feat: tela de apps com logos/menu de exclusao, correcao de tema nas mini apps e sidebar de navegacao
This commit is contained in:
109
lib/utils/miniapp_meta.dart
Normal file
109
lib/utils/miniapp_meta.dart
Normal file
@@ -0,0 +1,109 @@
|
||||
// SPDX-FileCopyrightText: 2026 TatuChat
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
/// Names of the `<meta>` tags a mini app document must declare to be
|
||||
/// installable. They act as the mini app's manifest.
|
||||
const String miniAppMetaIdTag = 'mini-app-id';
|
||||
const String miniAppMetaNameTag = 'mini-app-name';
|
||||
const String miniAppMetaCategoryTag = 'mini-app-category';
|
||||
const String miniAppMetaDescriptionTag = 'mini-app-description';
|
||||
const String miniAppMetaLogoTag = 'mini-app-logo';
|
||||
const String miniAppMetaInChatTag = 'mini-app-in-chat';
|
||||
|
||||
const List<String> miniAppMetaTags = [
|
||||
miniAppMetaIdTag,
|
||||
miniAppMetaNameTag,
|
||||
miniAppMetaCategoryTag,
|
||||
miniAppMetaDescriptionTag,
|
||||
miniAppMetaLogoTag,
|
||||
miniAppMetaInChatTag,
|
||||
];
|
||||
|
||||
/// Manifest of a mini app, extracted from its `<meta>` tags.
|
||||
///
|
||||
/// [id] is mandatory and non-empty. It is used as the account data key under
|
||||
/// which the app's store and HTML source are persisted
|
||||
/// (`im.tatuchat.miniapps.data.<id>` / `im.tatuchat.miniapps.source.<id>`).
|
||||
class MiniAppMeta {
|
||||
final String id;
|
||||
final String name;
|
||||
final String category;
|
||||
final String description;
|
||||
final String logo;
|
||||
|
||||
/// Whether the mini app can run inside a chat room. `false` by default.
|
||||
final bool inChat;
|
||||
|
||||
const MiniAppMeta({
|
||||
required this.id,
|
||||
required this.name,
|
||||
this.category = '',
|
||||
this.description = '',
|
||||
this.logo = '',
|
||||
this.inChat = false,
|
||||
});
|
||||
}
|
||||
|
||||
/// Extracts the meta tags of an HTML document into a `name -> content` map
|
||||
/// (names normalized to lower case). Attribute order and quoting style are
|
||||
/// irrelevant.
|
||||
Map<String, String> extractMetaTags(String html) {
|
||||
final result = <String, String>{};
|
||||
final metaRegex = RegExp(r'<meta\b[^>]*>', caseSensitive: false);
|
||||
final attrRegex = RegExp(
|
||||
r"""(name|content)\s*=\s*["']([^"']*)["']""",
|
||||
caseSensitive: false,
|
||||
);
|
||||
for (final match in metaRegex.allMatches(html)) {
|
||||
final attributes = <String, String>{};
|
||||
for (final attr in attrRegex.allMatches(match.group(0)!)) {
|
||||
attributes[attr.group(1)!.toLowerCase()] = attr.group(2)!;
|
||||
}
|
||||
final name = attributes['name'];
|
||||
final content = attributes['content'];
|
||||
if (name != null && content != null) {
|
||||
result[name.toLowerCase()] = content;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Parses the mini app manifest out of the `<meta>` tags of [html].
|
||||
///
|
||||
/// All [miniAppMetaTags] must be present (their content may be empty), except
|
||||
/// `mini-app-id` and `mini-app-name`, which must also be non-empty. Throws a
|
||||
/// [FormatException] with a human readable reason otherwise.
|
||||
MiniAppMeta parseMiniAppMeta(String html) {
|
||||
final tags = extractMetaTags(html);
|
||||
final missing = [
|
||||
for (final tag in miniAppMetaTags)
|
||||
if (!tags.containsKey(tag)) tag,
|
||||
];
|
||||
if (missing.isNotEmpty) {
|
||||
throw FormatException(
|
||||
'This document is missing the required meta tag(s): '
|
||||
'${missing.join(', ')}',
|
||||
);
|
||||
}
|
||||
final id = tags[miniAppMetaIdTag]!.trim();
|
||||
final name = tags[miniAppMetaNameTag]!.trim();
|
||||
if (id.isEmpty) {
|
||||
throw FormatException(
|
||||
'The meta tag "$miniAppMetaIdTag" must not be empty',
|
||||
);
|
||||
}
|
||||
if (name.isEmpty) {
|
||||
throw FormatException(
|
||||
'The meta tag "$miniAppMetaNameTag" must not be empty',
|
||||
);
|
||||
}
|
||||
return MiniAppMeta(
|
||||
id: id,
|
||||
name: name,
|
||||
category: tags[miniAppMetaCategoryTag]!.trim(),
|
||||
description: tags[miniAppMetaDescriptionTag]!.trim(),
|
||||
logo: tags[miniAppMetaLogoTag]!.trim(),
|
||||
inChat: tags[miniAppMetaInChatTag]!.trim().toLowerCase() == 'true',
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user