// SPDX-FileCopyrightText: 2019-Present Christian Kußowski // SPDX-FileCopyrightText: 2019-Present Contributors to FluffyChat // // SPDX-License-Identifier: AGPL-3.0-or-later import 'package:material_ui/material_ui.dart'; import 'package:matrix/matrix.dart'; import 'package:tatchat/l10n/l10n.dart'; import 'package:tatchat/utils/miniapp_store.dart'; /// ID of the built-in tasks example app. const String miniAppTasksId = 'tasks'; /// ID of the built-in account data explorer app. const String miniAppAccountDataId = 'accountdata'; /// Static registry of all built-in mini apps that ship with this build. A mini /// app only shows up in the "Apps" page once the user installs it (see /// [installedMiniApps]). Additionally to this list, users can import their own /// single-file HTML apps which are resolved through [resolveMiniAppConfig]. const List availableMiniApps = [ MiniAppConfig( id: miniAppTasksId, icon: Icons.checklist_rounded, color: Color(0xFF00D084), htmlAsset: 'assets/miniapps/tasks.html', ), MiniAppConfig( id: miniAppAccountDataId, icon: Icons.storage_rounded, color: Color(0xFF1F8EF1), htmlAsset: 'assets/miniapps/accountdata.html', ), ]; /// Declarative description of a mini app. The rendering is either a /// self-contained HTML document loaded from [htmlAsset] (built-in apps) or /// from [html] which is stored in the user's account data (imported apps). class MiniAppConfig { final String id; final IconData icon; final Color color; final String? name; final String? htmlAsset; final String? html; const MiniAppConfig({ required this.id, required this.icon, required this.color, this.name, this.htmlAsset, this.html, }); /// Config for a user-imported app whose HTML source is persisted in the /// account data store. MiniAppConfig.custom({ required String id, String? name, String? html, }) : this( id: id, icon: Icons.web_asset_rounded, color: const Color(0xFF9C27B0), name: name, html: html, ); bool get isCustom => html != null || htmlAsset == null; /// Resolves the HTML source that should be rendered for this app. Returns a /// bundled asset path for built-in apps or the raw HTML for imported apps. String? get htmlSource => html ?? htmlAsset; } /// Resolves the config of a single installed app, whether it is built-in or /// user-imported. Returns null if the app is not installed or not available. MiniAppConfig? resolveMiniAppConfig(Client client, String appId) { for (final app in availableMiniApps) { if (app.id == appId) return app; } if (client.isMiniAppInstalled(appId)) { final html = client.getMiniAppSource(appId); if (html != null) { return MiniAppConfig.custom( id: appId, name: client.getMiniAppName(appId), html: html, ); } } return null; } /// Returns the configs of all installed apps: built-in ones plus the /// user-imported ones. The visual order is: installed built-in apps first, /// then imported apps. List installedMiniAppConfigs(Client client) { final installed = client.installedMiniApps; return [ for (final app in availableMiniApps) if (installed.contains(app.id)) app, for (final id in installed) if (!availableMiniApps.any((app) => app.id == id)) if (client.getMiniAppSource(id) != null) MiniAppConfig.custom( id: id, name: client.getMiniAppName(id), html: client.getMiniAppSource(id), ), ]; } /// Resolves the localized display name of a mini app configuration. String miniAppName(BuildContext context, MiniAppConfig app) { final customName = app.name; if (customName != null && customName.isNotEmpty) return customName; switch (app.id) { case miniAppTasksId: return L10n.of(context).tasks; case miniAppAccountDataId: return L10n.of(context).accountDataEditor; default: return app.id; } }