8fffafde47
Translations are provided in *.arb* format. Some keys have descriptions (indicated by leading @-symbol). Descriptions should not be copied into the translation itself. Currently only English is supported (app_en.arb), but German is planned. Apparently weblate merged .arb support at some time, so it would be nice to enable community translations at some point.
146 lines
5.4 KiB
Dart
146 lines
5.4 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:flutter_gen/gen_l10n/app_localizations.dart';
|
|
import 'package:provider/provider.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();
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return AlertDialog(
|
|
title: Text(AppLocalizations.of(context)!.changeThemeTitle),
|
|
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: InputDecoration(
|
|
prefixIcon: const Icon(Icons.lock),
|
|
labelText: AppLocalizations.of(context)!.inputOldPasswordLabel,
|
|
hintText: AppLocalizations.of(context)!.inputOldPasswordHint,
|
|
helperText:AppLocalizations.of(context)!.inputOldPasswordHelp,
|
|
border: const OutlineInputBorder(),
|
|
),
|
|
),
|
|
),
|
|
Padding(
|
|
padding: const EdgeInsets.all(8),
|
|
child: TextField(
|
|
controller: _ctrNewPassword,
|
|
keyboardType: TextInputType.visiblePassword,
|
|
obscureText: true,
|
|
decoration: InputDecoration(
|
|
prefixIcon: const Icon(Icons.lock),
|
|
labelText: AppLocalizations.of(context)!.inputNewPasswordLabel,
|
|
hintText: AppLocalizations.of(context)!.inputNewPasswordHint,
|
|
helperText:AppLocalizations.of(context)!.inputNewPasswordHelp,
|
|
border: const OutlineInputBorder(),
|
|
),
|
|
),
|
|
),
|
|
Padding(
|
|
padding: const EdgeInsets.all(8),
|
|
child: TextField(
|
|
controller: _ctrNewPasswordRepeat,
|
|
keyboardType: TextInputType.visiblePassword,
|
|
obscureText: true,
|
|
decoration: InputDecoration(
|
|
prefixIcon: const Icon(Icons.lock),
|
|
labelText: AppLocalizations.of(context)!.inputNewPasswordRepeatLabel,
|
|
hintText: AppLocalizations.of(context)!.inputNewPasswordRepeatHint,
|
|
helperText:AppLocalizations.of(context)!.inputNewPasswordRepeatHelp,
|
|
border: const OutlineInputBorder(),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
)),
|
|
actions: [
|
|
TextButton(
|
|
onPressed: () {
|
|
// close popup
|
|
Navigator.of(context).pop();
|
|
},
|
|
child: Text(AppLocalizations.of(context)!.cancel),
|
|
),
|
|
FilledButton(
|
|
onPressed: () async {
|
|
final scaffMgr = ScaffoldMessenger.of(context);
|
|
final nav = Navigator.of(context);
|
|
final user = context.read<User>();
|
|
final trans = AppLocalizations.of(context);
|
|
|
|
// validate password
|
|
if (_ctrNewPassword.text.length < 6) {
|
|
// password has to be at least 6 characters long
|
|
showSimpleSnackbar(scaffMgr,
|
|
text: trans!.errorPasswordLength,
|
|
action: trans.dismiss);
|
|
|
|
_ctrNewPasswordRepeat.clear();
|
|
return;
|
|
}
|
|
if (_ctrNewPassword.text != _ctrNewPasswordRepeat.text) {
|
|
// new passwords do not match
|
|
showSimpleSnackbar(scaffMgr,
|
|
text: trans!.errorPasswordsDoNotMatch, action: trans.dismiss);
|
|
|
|
_ctrNewPasswordRepeat.clear();
|
|
return;
|
|
}
|
|
if (hashPassword(_ctrOldPassword.text) != user.password) {
|
|
// current password wrong
|
|
showSimpleSnackbar(scaffMgr,
|
|
text: trans!.errorOldPasswordWrong, action: trans.dismiss);
|
|
|
|
_ctrOldPassword.clear();
|
|
return;
|
|
}
|
|
|
|
final password = hashPassword(_ctrNewPassword.text);
|
|
|
|
// send request
|
|
doNetworkRequest(scaffMgr,
|
|
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: Text(AppLocalizations.of(context)!.changeThemeTitle),
|
|
)
|
|
],
|
|
);
|
|
}
|
|
}
|