import 'package:flutter/material.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:routemaster/routemaster.dart'; class SettingsPage extends StatefulWidget { const SettingsPage({super.key}); @override State createState() => _SettingsPageState(); } class _SettingsPageState extends State { User? user; AccountMeta? meta; void fetchMeta() { doNetworkRequest(ScaffoldMessenger.of(context), req: (user) { setState(() { this.user = user; }); return postWithCreadentials( path: 'getMyAccount', credentials: user!, target: user.server, body: {}); }, onOK: (body) { final meta = AccountMeta.fromJSON(body['data']); setState(() { this.meta = meta; }); }); } @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) => fetchMeta()); } @override Widget build(BuildContext context) { final textTheme = Theme.of(context) .textTheme .apply(displayColor: Theme.of(context).colorScheme.onSurface); return Scaffold( appBar: AppBar( title: const Text('Settings'), leading: IconButton( onPressed: () { // go back Navigator.of(context).pop(); }, icon: const Icon(Icons.arrow_back), tooltip: "Go back", ), ), 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: const Text('Room count limit:'), subtitle: const Text( 'How many rooms you are allowed to own'), trailing: Text('${meta?.maxRoomCount ?? ""}'), ), ListTile( title: const Text('Room size limit:'), subtitle: const Text( 'How many items/products/categories each room may contain'), trailing: Text('${meta?.maxRoomSize ?? ""}'), ), ListTile( title: const Text('Room member limit:'), subtitle: const Text( 'How many members each of your rooms may have'), trailing: Text('${meta?.maxRoomMemberCount ?? ""}')), ListTile( title: const Text('Discoverable'), subtitle: const Text( 'Determines if your account can be discovered by users from other servers'), trailing: Checkbox( tristate: true, value: meta?.discoverable, onChanged: (_) {}, )) ], )))), // change theme button ListTile( title: const Text('Change Theme'), subtitle: const Text( 'You can change between a light theme, a dark theme and automatic theme selection'), // NOTE: have the trailing item be a value select widget trailing: 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)); }).toList(), onSelectionChanged: (item) async { try { await item.first.toDisk(); } catch(_) {} }, ), ), // change password button ListTile( title: const Text('Change password'), subtitle: const Text('Choose a new password for your account'), onTap: () { // TODO: show confirm dialog // NOTE: needs an input field for the current password // NOTE: might want to show a message explaining, // that there is no way to reset the password showDialog( context: context, builder: (context) => const ChangePasswordDialog()); }, trailing: const Icon(Icons.chevron_right), ), // export account to json ListTile( title: const Text('Export account'), subtitle: const Text('Export account data'), 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: const Text('Delete account'), subtitle: const Text('Delete your account from your homeserver'), onTap: () { // show confirm dialog // NOTE: same as logout // and performs a network request // but deletes account beforehand showDialog( context: context, builder: (ctx) => AlertDialog( title: const Text('Delete account'), content: const Text( 'Do you really want to delete your account?'), actions: [ TextButton( onPressed: () { // close popup Navigator.of(ctx).pop(); }, child: const Text('Cancel'), ), FilledButton( onPressed: () async { // send request final scaffMgr = ScaffoldMessenger.of(ctx); final nav = Navigator.of(ctx); final rmaster = Routemaster.of(ctx); doNetworkRequest(scaffMgr, req: (user) => 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 rmaster.replace('/'); }, after: () { // close popup nav.pop(); }); }, child: const Text('Delete Account'), ) ], )); }, trailing: const Icon(Icons.chevron_right), ), // logout button Padding( padding: const EdgeInsets.all(8), child: FilledButton.tonal( child: const Text('Log out'), onPressed: () { // show confirm dialog showDialog( context: context, builder: (ctx) => AlertDialog( title: const Text('Log out'), content: const Text('Do you really want to log out?'), actions: [ TextButton( onPressed: () { // close popup Navigator.of(ctx).pop(); }, child: const Text('Cancel'), ), FilledButton( onPressed: () async { // send request final rmaster = Routemaster.of(ctx); // delete everything // delete user data (meta) try { await User.removeDisk(); } catch (_) {} // TODO: delete all rooms // go back home rmaster.replace('/'); }, child: const Text('Log out'), ) ], )); }, )) ])))); } }