import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:outbag_app/backend/request.dart'; import 'package:outbag_app/backend/themes.dart'; import 'package:outbag_app/backend/user.dart'; import 'package:outbag_app/screens/settings/dialogs/password.dart'; import 'package:outbag_app/tools/fetch_wrapper.dart'; import 'package:provider/provider.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class SettingsPage extends StatefulWidget { const SettingsPage({super.key}); @override State createState() => _SettingsPageState(); } class _SettingsPageState extends State { @override Widget build(BuildContext context) { final textTheme = Theme.of(context) .textTheme .apply(displayColor: Theme.of(context).colorScheme.onSurface); final user = context.watch(); final meta = context.watch(); return Scaffold( appBar: AppBar( title: Text(AppLocalizations.of(context)!.settings), ), body: SingleChildScrollView( child: Center( child: Column(children: [ // uswer information widget Padding( padding: const EdgeInsets.all(14), child: Card( child: Padding( padding: const EdgeInsets.all(8), child: Column( children: [ Padding( padding: const EdgeInsets.all(8), child: Text(user.humanReadable, style: textTheme.titleLarge)), ListTile( title: Text( AppLocalizations.of(context)!.limitRoomCount), subtitle: Text(AppLocalizations.of(context)! .limitRoomCountSubtitle), trailing: Text('${meta?.maxRoomCount ?? ""}'), ), ListTile( title: Text( AppLocalizations.of(context)!.limitRoomSize), subtitle: Text(AppLocalizations.of(context)! .limitRoomSizeSubtitle), trailing: Text('${meta?.maxRoomSize ?? ""}'), ), ListTile( title: Text(AppLocalizations.of(context)! .limitRoomMemberCount), subtitle: Text(AppLocalizations.of(context)! .limitRoomMemberCountSubtitle), trailing: Text('${meta?.maxRoomMemberCount ?? ""}')), ListTile( title: Text(AppLocalizations.of(context)! .userDiscoverable), subtitle: Text(AppLocalizations.of(context)! .userDiscoverableSubtitle), trailing: Checkbox( tristate: true, value: meta?.discoverable, onChanged: (_) { // TODO: implement changeVisibility }, )) ], )))), // change theme button ListTile( title: Text(AppLocalizations.of(context)!.changeThemeTitle), subtitle: Text(AppLocalizations.of(context)!.changeThemeSubtitle), trailing: const Icon(Icons.chevron_right), onTap: () { showDialog( context: context, builder: (context) => AlertDialog( title: Text( AppLocalizations.of(context)!.changeThemeTitle), content: SingleChildScrollView( child: Column(children: [ Padding( padding: const EdgeInsets.all(8), child: Text(AppLocalizations.of(context)! .changeThemeSubtitle), ), SegmentedButton( selected: {context.watch()}, selectedIcon: Icon(context.watch().icon), showSelectedIcon: true, multiSelectionEnabled: false, emptySelectionAllowed: false, segments: AppTheme.list().map((item) { return ButtonSegment( value: item, icon: Icon(item.icon), label: Text(item.name(context))); }).toList(), onSelectionChanged: (item) async { try { await item.first.toDisk(); } catch (_) {} }, ), ])), actions: [ FilledButton( child: Text(AppLocalizations.of(context)!.close), onPressed: () { context.pop(); }, ) ], )); }, ), // change password button ListTile( title: Text(AppLocalizations.of(context)!.changePasswordTitle), subtitle: Text(AppLocalizations.of(context)!.changePasswordSubtitle), onTap: () { showDialog( context: context, builder: (context) => const ChangePasswordDialog()); }, trailing: const Icon(Icons.chevron_right), ), // export account to json ListTile( title: Text(AppLocalizations.of(context)!.exportAccountTitle), subtitle: Text(AppLocalizations.of(context)!.exportAccountSubtitle), onTap: () { // TODO: show confirm dialog // NOTE: json dump the localstore // including users and rooms // NOTE: feature not confirmed }, trailing: const Icon(Icons.chevron_right), ), // delete account button ListTile( title: Text(AppLocalizations.of(context)!.deleteAccountTitle), subtitle: Text(AppLocalizations.of(context)!.deleteAccountSubtitle), onTap: () { // show confirm dialog // NOTE: same as logout // and performs a network request // but deletes account beforehand showDialog( context: context, builder: (ctx) => AlertDialog( title: Text( AppLocalizations.of(context)!.deleteAccountTitle), content: Text( AppLocalizations.of(context)!.deleteAccountConfirm), actions: [ TextButton( onPressed: () { // close popup Navigator.of(ctx).pop(); }, child: Text(AppLocalizations.of(context)!.cancel), ), FilledButton( onPressed: () async { // send request final scaffMgr = ScaffoldMessenger.of(ctx); final nav = Navigator.of(ctx); final router = GoRouter.of(ctx); doNetworkRequest(scaffMgr, req: () => postWithCreadentials( path: 'deleteAccount', target: user.server, body: {}, credentials: user), onOK: (_) async { // delete everything // delete user data (meta) try { await User.removeDisk(); } catch (_) {} // TODO: delete all rooms // go back home router.pushReplacementNamed('home'); }, after: () { // close popup nav.pop(); }); }, child: Text(AppLocalizations.of(context)!.yes), ) ], )); }, trailing: const Icon(Icons.chevron_right), ), // logout button Padding( padding: const EdgeInsets.all(8), child: FilledButton.tonal( child: Text(AppLocalizations.of(context)!.logOut), onPressed: () { // show confirm dialog showDialog( context: context, builder: (ctx) => AlertDialog( title: Text(AppLocalizations.of(context)!.logOut), content: Text( AppLocalizations.of(context)!.logOutConfirm), actions: [ TextButton( onPressed: () { // close popup Navigator.of(ctx).pop(); }, child: Text(AppLocalizations.of(context)!.cancel), ), FilledButton( onPressed: () async { // send request final router = GoRouter.of(ctx); // delete everything // delete user data (meta) try { await User.removeDisk(); } catch (_) {} // TODO: delete all rooms // go back home router.pushReplacementNamed('home'); }, child: Text(AppLocalizations.of(context)!.yes), ) ], )); }, )) ])))); } }