import 'package:flutter/material.dart'; import 'package:outbag_app/backend/crypto.dart'; import 'package:outbag_app/backend/request.dart'; import 'package:outbag_app/backend/user.dart'; import 'package:outbag_app/tools/fetch_wrapper.dart'; import 'package:outbag_app/tools/snackbar.dart'; import 'package:routemaster/routemaster.dart'; class ChangePasswordDialog extends StatefulWidget { const ChangePasswordDialog({super.key}); @override State createState() => _ChangePasswordDialogState(); } class _ChangePasswordDialogState extends State { final TextEditingController _ctrOldPassword = TextEditingController(); final TextEditingController _ctrNewPassword = TextEditingController(); final TextEditingController _ctrNewPasswordRepeat = TextEditingController(); User? user; void loadUser() async { final rmaster = Routemaster.of(context); try { final u = await User.fromDisk(); setState(() { user = u; }); } catch (_) { // logout user await User.removeDisk(); // move to welcome screen rmaster.replace('/'); } } @override void initState() { super.initState(); User.listen((data) async { try { final u = await User.fromDisk(); setState(() { user = u; }); } catch (_) {} }); } @override Widget build(BuildContext context) { return AlertDialog( title: const Text('Change Password'), icon: const Icon(Icons.password), content: SingleChildScrollView( child: Column( children: [ Padding( padding: const EdgeInsets.all(8), child: TextField( controller: _ctrOldPassword, keyboardType: TextInputType.visiblePassword, obscureText: true, decoration: const InputDecoration( prefixIcon: Icon(Icons.lock), labelText: 'Old Password', hintText: 'Your current password', helperText: 'For safety, you have to type your current passwort', border: OutlineInputBorder(), ), ), ), Padding( padding: const EdgeInsets.all(8), child: TextField( controller: _ctrNewPassword, keyboardType: TextInputType.visiblePassword, obscureText: true, decoration: const InputDecoration( prefixIcon: Icon(Icons.lock), labelText: 'New Password', hintText: 'Your new password', helperText: 'Password have to be at least six characters long', border: OutlineInputBorder(), ), ), ), Padding( padding: const EdgeInsets.all(8), child: TextField( controller: _ctrNewPasswordRepeat, keyboardType: TextInputType.visiblePassword, obscureText: true, decoration: const InputDecoration( prefixIcon: Icon(Icons.lock), labelText: 'Repeat new Password', hintText: 'Type your new password again', helperText: 'Type your new password again, to make sure you know it', border: OutlineInputBorder(), ), ), ), ], )), actions: [ TextButton( onPressed: () { // close popup Navigator.of(context).pop(); }, child: const Text('Cancel'), ), FilledButton( onPressed: () async { final scaffMgr = ScaffoldMessenger.of(context); final nav = Navigator.of(context); // validate password if (_ctrNewPassword.text.length < 6) { // password has to be at least 6 characters long showSimpleSnackbar(scaffMgr, text: 'Password has to be at least 6 characters longs', action: 'Dismiss'); _ctrNewPasswordRepeat.clear(); return; } if (_ctrNewPassword.text != _ctrNewPasswordRepeat.text) { // new passwords do not match showSimpleSnackbar(scaffMgr, text: 'New passwords do not match', action: 'Dismiss'); _ctrNewPasswordRepeat.clear(); return; } if (hashPassword(_ctrOldPassword.text) != user?.password) { // current password wrong showSimpleSnackbar(scaffMgr, text: 'Old password is wrong', action: 'Dismiss'); _ctrOldPassword.clear(); return; } final password = hashPassword(_ctrNewPassword.text); // send request doNetworkRequest(scaffMgr, needUser: false, req: (_) => postWithCreadentials( path: 'changePassword', target: (user?.server)!, body: {'accountKey': password}, credentials: user!), onOK: (_) async { // update local user struct final updatedUser = User( username: (user?.username)!, password: password, server: (user?.server)!); await updatedUser.toDisk(); }, after: () { // close popup nav.pop(); }); }, child: const Text('Change password'), ) ], ); } }