178 lines
5.6 KiB
Dart
178 lines
5.6 KiB
Dart
|
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<StatefulWidget> createState() => _ChangePasswordDialogState();
|
||
|
}
|
||
|
|
||
|
class _ChangePasswordDialogState extends State<ChangePasswordDialog> {
|
||
|
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'),
|
||
|
)
|
||
|
],
|
||
|
);
|
||
|
}
|
||
|
}
|