// SPDX-FileCopyrightText: 2019-Present Christian Kußowski // SPDX-FileCopyrightText: 2019-Present Contributors to FluffyChat // // SPDX-License-Identifier: AGPL-3.0-or-later import 'package:async/async.dart'; import 'package:go_router/go_router.dart'; import 'package:material_ui/material_ui.dart'; import 'package:matrix/matrix.dart' hide Result; import 'package:tatchat/config/themes.dart'; import 'package:tatchat/l10n/l10n.dart'; import 'package:tatchat/utils/tatu_share.dart'; import 'package:tatchat/widgets/avatar.dart'; import 'package:tatchat/widgets/matrix.dart'; import 'package:url_launcher/url_launcher_string.dart'; import 'chat_list.dart'; class ClientChooserButton extends StatelessWidget { final ChatListController controller; const ClientChooserButton(this.controller, {super.key}); List> _bundleMenuItems(BuildContext context) { final matrix = Matrix.of(context); final bundles = matrix.accountBundles.keys.toList() ..sort( (a, b) => a!.isValidMatrixIdStrict() == b!.isValidMatrixIdStrict() ? 0 : a.isValidMatrixIdStrict() && !b.isValidMatrixIdStrict() ? -1 : 1, ); if (FluffyThemes.isColumnMode(context)) { // In column mode the settings/actions live in the navigation sidebar, // so the avatar popup only offers the account switcher. return >[ ..._bundleEntries(context, matrix, bundles), PopupMenuItem( value: SettingsAction.addAccount, child: Row( children: [ const Icon(Icons.person_add_outlined), const SizedBox(width: 18), Text(L10n.of(context).addAccount), ], ), ), ]; } return >[ PopupMenuItem( value: SettingsAction.newGroup, child: Row( children: [ const Icon(Icons.group_add_outlined), const SizedBox(width: 18), Text(L10n.of(context).createGroup), ], ), ), PopupMenuItem( value: SettingsAction.setStatus, child: Row( children: [ const Icon(Icons.edit_outlined), const SizedBox(width: 18), Text(L10n.of(context).setStatus), ], ), ), PopupMenuItem( value: SettingsAction.invite, child: Row( children: [ Icon(Icons.adaptive.share_outlined), const SizedBox(width: 18), Text(L10n.of(context).inviteContact), ], ), ), PopupMenuItem( value: SettingsAction.archive, child: Row( children: [ const Icon(Icons.archive_outlined), const SizedBox(width: 18), Text(L10n.of(context).archive), ], ), ), PopupMenuItem( value: SettingsAction.apps, child: Row( children: [ const Icon(Icons.apps_outlined), const SizedBox(width: 18), Text(L10n.of(context).apps), ], ), ), PopupMenuItem( value: SettingsAction.settings, child: Row( children: [ const Icon(Icons.settings_outlined), const SizedBox(width: 18), Text(L10n.of(context).settings), ], ), ), PopupMenuItem( value: SettingsAction.support, child: Row( children: [ Icon(Icons.favorite, color: Colors.red), const SizedBox(width: 18), Text(L10n.of(context).supportFluffyChat), ], ), ), const PopupMenuDivider(), ..._bundleEntries(context, matrix, bundles), PopupMenuItem( value: SettingsAction.addAccount, child: Row( children: [ const Icon(Icons.person_add_outlined), const SizedBox(width: 18), Text(L10n.of(context).addAccount), ], ), ), ]; } List> _bundleEntries( BuildContext context, MatrixState matrix, List bundles, ) { return >[ for (final bundle in bundles) ...[ if (matrix.accountBundles[bundle]!.length != 1 || matrix.accountBundles[bundle]!.single!.userID != bundle) PopupMenuItem( value: null, child: Column( crossAxisAlignment: .start, mainAxisSize: .min, children: [ Text( bundle!, style: TextStyle( color: Theme.of(context).textTheme.titleMedium!.color, fontSize: 14, ), ), const Divider(height: 1), ], ), ), ...matrix.accountBundles[bundle]! .whereType() .where((client) => client.isLogged()) .map( (client) => PopupMenuItem( value: client, child: FutureBuilder( future: client.fetchOwnProfile(), builder: (context, snapshot) { final displayname = snapshot.data?.displayName ?? client.userID!.localpart!; return Row( key: ValueKey('switch_account_$displayname'), children: [ Avatar( mxContent: snapshot.data?.avatarUrl, name: displayname, size: 32, ), const SizedBox(width: 12), Expanded( child: Text( displayname, overflow: TextOverflow.ellipsis, ), ), const SizedBox(width: 12), IconButton( icon: const Icon(Icons.edit_outlined), onPressed: () => controller.editBundlesForAccount( client.userID, bundle, ), ), ], ); }, ), ), ), ], ]; } @override Widget build(BuildContext context) { final matrix = Matrix.of(context); final client = Result(() => matrix.client).asValue?.value; var clientCount = 0; matrix.accountBundles.forEach((key, value) => clientCount += value.length); return FutureBuilder( future: client?.isLogged() == true ? client?.fetchOwnProfile() : null, builder: (context, snapshot) => Material( clipBehavior: Clip.hardEdge, borderRadius: BorderRadius.circular(99), color: Colors.transparent, child: PopupMenuButton( key: Key('accounts_and_settings_buttons'), tooltip: L10n.of(context).accountsAndSettings, onSelected: (o) => _clientSelected(o, context), itemBuilder: _bundleMenuItems, icon: Avatar( mxContent: snapshot.data?.avatarUrl, name: snapshot.data?.displayName ?? client?.userID?.localpart, size: 32, ), ), ), ); } Future _clientSelected(Object object, BuildContext context) async { if (object is Client) { controller.setActiveClient(object); } else if (object is String) { controller.setActiveBundle(object); } else if (object is SettingsAction) { switch (object) { case SettingsAction.addAccount: if (!context.mounted) return; context.go('/rooms/settings/addaccount'); break; case SettingsAction.newGroup: context.go('/rooms/newgroup'); break; case SettingsAction.invite: TatuShare.shareInviteLink(context); break; case SettingsAction.support: launchUrlString( 'https://ko-fi.com/post/How-can-I-support-FluffyChat-J2G325WE6I', ); break; case SettingsAction.settings: context.go('/rooms/settings'); break; case SettingsAction.archive: context.go('/rooms/archive'); break; case SettingsAction.apps: context.go('/rooms/apps'); break; case SettingsAction.setStatus: controller.setStatus(); break; } } } } enum SettingsAction { addAccount, newGroup, setStatus, invite, support, settings, archive, apps, }