269 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Dart
		
	
	
	
			
		
		
	
	
			269 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Dart
		
	
	
	
| import 'package:flutter/material.dart';
 | |
| 
 | |
| import 'package:fluffychat/generated/l10n/l10n.dart';
 | |
| import 'package:go_router/go_router.dart';
 | |
| import 'package:matrix/matrix.dart';
 | |
| import 'package:url_launcher/url_launcher_string.dart';
 | |
| 
 | |
| import 'package:fluffychat/config/app_config.dart';
 | |
| import 'package:fluffychat/config/themes.dart';
 | |
| import 'package:fluffychat/utils/fluffy_share.dart';
 | |
| import 'package:fluffychat/utils/platform_infos.dart';
 | |
| import 'package:fluffychat/widgets/avatar.dart';
 | |
| import 'package:fluffychat/widgets/matrix.dart';
 | |
| import 'package:fluffychat/widgets/navigation_rail.dart';
 | |
| import '../../widgets/mxc_image_viewer.dart';
 | |
| import 'settings.dart';
 | |
| 
 | |
| class SettingsView extends StatelessWidget {
 | |
|   final SettingsController controller;
 | |
| 
 | |
|   const SettingsView(this.controller, {super.key});
 | |
| 
 | |
|   @override
 | |
|   Widget build(BuildContext context) {
 | |
|     final theme = Theme.of(context);
 | |
|     final showChatBackupBanner = controller.showChatBackupBanner;
 | |
|     final activeRoute =
 | |
|         GoRouter.of(context).routeInformationProvider.value.uri.path;
 | |
|     final accountManageUrl = Matrix.of(context)
 | |
|         .client
 | |
|         .wellKnown
 | |
|         ?.additionalProperties
 | |
|         .tryGetMap<String, Object?>('org.matrix.msc2965.authentication')
 | |
|         ?.tryGet<String>('account');
 | |
|     return Row(
 | |
|       children: [
 | |
|         if (FluffyThemes.isColumnMode(context)) ...[
 | |
|           SpacesNavigationRail(
 | |
|             activeSpaceId: null,
 | |
|             onGoToChats: () => context.go('/rooms'),
 | |
|             onGoToSpaceId: (spaceId) => context.go('/rooms?spaceId=$spaceId'),
 | |
|           ),
 | |
|           Container(
 | |
|             color: Theme.of(context).dividerColor,
 | |
|             width: 1,
 | |
|           ),
 | |
|         ],
 | |
|         Expanded(
 | |
|           child: Scaffold(
 | |
|             appBar: FluffyThemes.isColumnMode(context)
 | |
|                 ? null
 | |
|                 : AppBar(
 | |
|                     title: Text(L10n.of(context).settings),
 | |
|                     leading: Center(
 | |
|                       child: BackButton(
 | |
|                         onPressed: () => context.go('/rooms'),
 | |
|                       ),
 | |
|                     ),
 | |
|                   ),
 | |
|             body: ListTileTheme(
 | |
|               iconColor: theme.colorScheme.onSurface,
 | |
|               child: ListView(
 | |
|                 key: const Key('SettingsListViewContent'),
 | |
|                 children: <Widget>[
 | |
|                   FutureBuilder<Profile>(
 | |
|                     future: controller.profileFuture,
 | |
|                     builder: (context, snapshot) {
 | |
|                       final profile = snapshot.data;
 | |
|                       final avatar = profile?.avatarUrl;
 | |
|                       final mxid = Matrix.of(context).client.userID ??
 | |
|                           L10n.of(context).user;
 | |
|                       final displayname =
 | |
|                           profile?.displayName ?? mxid.localpart ?? mxid;
 | |
|                       return Row(
 | |
|                         children: [
 | |
|                           Padding(
 | |
|                             padding: const EdgeInsets.all(32.0),
 | |
|                             child: Stack(
 | |
|                               children: [
 | |
|                                 Avatar(
 | |
|                                   mxContent: avatar,
 | |
|                                   name: displayname,
 | |
|                                   size: Avatar.defaultSize * 2.5,
 | |
|                                   onTap: avatar != null
 | |
|                                       ? () => showDialog(
 | |
|                                             context: context,
 | |
|                                             builder: (_) =>
 | |
|                                                 MxcImageViewer(avatar),
 | |
|                                           )
 | |
|                                       : null,
 | |
|                                 ),
 | |
|                                 if (profile != null)
 | |
|                                   Positioned(
 | |
|                                     bottom: 0,
 | |
|                                     right: 0,
 | |
|                                     child: FloatingActionButton.small(
 | |
|                                       elevation: 2,
 | |
|                                       onPressed: controller.setAvatarAction,
 | |
|                                       heroTag: null,
 | |
|                                       child: const Icon(
 | |
|                                         Icons.camera_alt_outlined,
 | |
|                                       ),
 | |
|                                     ),
 | |
|                                   ),
 | |
|                               ],
 | |
|                             ),
 | |
|                           ),
 | |
|                           Expanded(
 | |
|                             child: Column(
 | |
|                               mainAxisAlignment: MainAxisAlignment.center,
 | |
|                               crossAxisAlignment: CrossAxisAlignment.start,
 | |
|                               children: [
 | |
|                                 TextButton.icon(
 | |
|                                   onPressed: controller.setDisplaynameAction,
 | |
|                                   icon: const Icon(
 | |
|                                     Icons.edit_outlined,
 | |
|                                     size: 16,
 | |
|                                   ),
 | |
|                                   style: TextButton.styleFrom(
 | |
|                                     foregroundColor:
 | |
|                                         theme.colorScheme.onSurface,
 | |
|                                     iconColor: theme.colorScheme.onSurface,
 | |
|                                   ),
 | |
|                                   label: Text(
 | |
|                                     displayname,
 | |
|                                     maxLines: 1,
 | |
|                                     overflow: TextOverflow.ellipsis,
 | |
|                                     style: const TextStyle(
 | |
|                                       fontSize: 18,
 | |
|                                     ),
 | |
|                                   ),
 | |
|                                 ),
 | |
|                                 TextButton.icon(
 | |
|                                   onPressed: () =>
 | |
|                                       FluffyShare.share(mxid, context),
 | |
|                                   icon: const Icon(
 | |
|                                     Icons.copy_outlined,
 | |
|                                     size: 14,
 | |
|                                   ),
 | |
|                                   style: TextButton.styleFrom(
 | |
|                                     foregroundColor:
 | |
|                                         theme.colorScheme.secondary,
 | |
|                                     iconColor: theme.colorScheme.secondary,
 | |
|                                   ),
 | |
|                                   label: Text(
 | |
|                                     mxid,
 | |
|                                     maxLines: 1,
 | |
|                                     overflow: TextOverflow.ellipsis,
 | |
|                                     //    style: const TextStyle(fontSize: 12),
 | |
|                                   ),
 | |
|                                 ),
 | |
|                               ],
 | |
|                             ),
 | |
|                           ),
 | |
|                         ],
 | |
|                       );
 | |
|                     },
 | |
|                   ),
 | |
|                   if (accountManageUrl != null)
 | |
|                     ListTile(
 | |
|                       leading: const Icon(Icons.account_circle_outlined),
 | |
|                       title: Text(L10n.of(context).manageAccount),
 | |
|                       trailing: const Icon(Icons.open_in_new_outlined),
 | |
|                       onTap: () => launchUrlString(
 | |
|                         accountManageUrl,
 | |
|                         mode: LaunchMode.inAppBrowserView,
 | |
|                       ),
 | |
|                     ),
 | |
|                   Divider(color: theme.dividerColor),
 | |
|                   if (showChatBackupBanner == null)
 | |
|                     ListTile(
 | |
|                       leading: const Icon(Icons.backup_outlined),
 | |
|                       title: Text(L10n.of(context).chatBackup),
 | |
|                       trailing: const CircularProgressIndicator.adaptive(),
 | |
|                     )
 | |
|                   else
 | |
|                     SwitchListTile.adaptive(
 | |
|                       controlAffinity: ListTileControlAffinity.trailing,
 | |
|                       value: controller.showChatBackupBanner == false,
 | |
|                       secondary: const Icon(Icons.backup_outlined),
 | |
|                       title: Text(L10n.of(context).chatBackup),
 | |
|                       onChanged: controller.firstRunBootstrapAction,
 | |
|                     ),
 | |
|                   Divider(
 | |
|                     color: theme.dividerColor,
 | |
|                   ),
 | |
|                   ListTile(
 | |
|                     leading: const Icon(Icons.format_paint_outlined),
 | |
|                     title: Text(L10n.of(context).changeTheme),
 | |
|                     tileColor: activeRoute.startsWith('/rooms/settings/style')
 | |
|                         ? theme.colorScheme.surfaceContainerHigh
 | |
|                         : null,
 | |
|                     onTap: () => context.go('/rooms/settings/style'),
 | |
|                   ),
 | |
|                   ListTile(
 | |
|                     leading: const Icon(Icons.notifications_outlined),
 | |
|                     title: Text(L10n.of(context).notifications),
 | |
|                     tileColor:
 | |
|                         activeRoute.startsWith('/rooms/settings/notifications')
 | |
|                             ? theme.colorScheme.surfaceContainerHigh
 | |
|                             : null,
 | |
|                     onTap: () => context.go('/rooms/settings/notifications'),
 | |
|                   ),
 | |
|                   ListTile(
 | |
|                     leading: const Icon(Icons.devices_outlined),
 | |
|                     title: Text(L10n.of(context).devices),
 | |
|                     onTap: () => context.go('/rooms/settings/devices'),
 | |
|                     tileColor: activeRoute.startsWith('/rooms/settings/devices')
 | |
|                         ? theme.colorScheme.surfaceContainerHigh
 | |
|                         : null,
 | |
|                   ),
 | |
|                   ListTile(
 | |
|                     leading: const Icon(Icons.forum_outlined),
 | |
|                     title: Text(L10n.of(context).chat),
 | |
|                     onTap: () => context.go('/rooms/settings/chat'),
 | |
|                     tileColor: activeRoute.startsWith('/rooms/settings/chat')
 | |
|                         ? theme.colorScheme.surfaceContainerHigh
 | |
|                         : null,
 | |
|                   ),
 | |
|                   ListTile(
 | |
|                     leading: const Icon(Icons.shield_outlined),
 | |
|                     title: Text(L10n.of(context).security),
 | |
|                     onTap: () => context.go('/rooms/settings/security'),
 | |
|                     tileColor:
 | |
|                         activeRoute.startsWith('/rooms/settings/security')
 | |
|                             ? theme.colorScheme.surfaceContainerHigh
 | |
|                             : null,
 | |
|                   ),
 | |
|                   Divider(color: theme.dividerColor),
 | |
|                   ListTile(
 | |
|                     leading: const Icon(Icons.dns_outlined),
 | |
|                     title: Text(
 | |
|                       L10n.of(context).aboutHomeserver(
 | |
|                         Matrix.of(context).client.userID?.domain ??
 | |
|                             'homeserver',
 | |
|                       ),
 | |
|                     ),
 | |
|                     onTap: () => context.go('/rooms/settings/homeserver'),
 | |
|                     tileColor:
 | |
|                         activeRoute.startsWith('/rooms/settings/homeserver')
 | |
|                             ? theme.colorScheme.surfaceContainerHigh
 | |
|                             : null,
 | |
|                   ),
 | |
|                   ListTile(
 | |
|                     leading: const Icon(Icons.privacy_tip_outlined),
 | |
|                     title: Text(L10n.of(context).privacy),
 | |
|                     onTap: () => launchUrlString(AppConfig.privacyUrl),
 | |
|                   ),
 | |
|                   ListTile(
 | |
|                     leading: const Icon(Icons.info_outline_rounded),
 | |
|                     title: Text(L10n.of(context).about),
 | |
|                     onTap: () => PlatformInfos.showDialog(context),
 | |
|                   ),
 | |
|                   Divider(color: theme.dividerColor),
 | |
|                   ListTile(
 | |
|                     leading: const Icon(Icons.logout_outlined),
 | |
|                     title: Text(L10n.of(context).logout),
 | |
|                     onTap: controller.logoutAction,
 | |
|                   ),
 | |
|                 ],
 | |
|               ),
 | |
|             ),
 | |
|           ),
 | |
|         ),
 | |
|       ],
 | |
|     );
 | |
|   }
 | |
| }
 |