update onboarding; add missing safe areas

This commit is contained in:
Fabian Freund
2026-03-17 08:46:09 +01:00
parent 79b68f137e
commit 25f4d27f0d
49 changed files with 3938 additions and 2430 deletions
@@ -66,104 +66,109 @@ class ProfileBackupScreen extends HookConsumerWidget {
return Scaffold(
appBar: AppBar(title: const Text('Create Backup')),
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8),
child: Form(
key: formKey,
child: ListView(
children: [
FancyPasswordField(
controller: passwordTextController,
enabled: !disableInteraction,
passwordController: passwordController,
enableSuggestions: false,
autocorrect: false,
enableIMEPersonalizedLearning: false,
keyboardType: TextInputType.visiblePassword,
decoration: const InputDecoration(
labelText: 'Password',
floatingLabelBehavior: FloatingLabelBehavior.always,
),
validationRules: {MinCharactersValidationRule(5)},
validator: (value) {
//Make sure since onChange is sometimes unreliable
passwordController.onChange(value ?? '');
return passwordController.areAllRulesValidated
? null
: 'Not Validated';
},
),
const SizedBox(height: 16),
SwitchListTile(
contentPadding: EdgeInsets.zero,
value: integrityVerification.value,
onChanged: disableInteraction
? null
: (value) {
integrityVerification.value = value;
},
title: const Text('Verify Backup Integrity'),
subtitle: const Text(
'Automatically check that backups are complete and restorable',
),
),
ExpansionTile(
enabled: !disableInteraction,
childrenPadding: EdgeInsets.zero,
tilePadding: EdgeInsets.zero,
title: const Text('Advanced'),
children: [
SwitchListTile(
contentPadding: EdgeInsets.zero,
value: skipPasswordConfirmation.value,
onChanged: disableInteraction
? null
: (value) {
skipPasswordConfirmation.value = value;
},
title: const Text('Skip Password Confirmation Prompt'),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8),
child: Form(
key: formKey,
child: ListView(
children: [
FancyPasswordField(
controller: passwordTextController,
enabled: !disableInteraction,
passwordController: passwordController,
enableSuggestions: false,
autocorrect: false,
enableIMEPersonalizedLearning: false,
keyboardType: TextInputType.visiblePassword,
decoration: const InputDecoration(
labelText: 'Password',
floatingLabelBehavior: FloatingLabelBehavior.always,
),
],
),
const SizedBox(height: 16),
if (disableInteraction)
const Column(
children: [
LinearProgressIndicator(),
Text('Creating Backup'),
],
)
else
FilledButton.icon(
icon: const Icon(MdiIcons.safe),
onPressed: () async {
if (formKey.currentState?.validate() ?? false) {
if (!skipPasswordConfirmation.value) {
final confirmation =
await showPasswordConfirmationDialog(context);
validationRules: {MinCharactersValidationRule(5)},
validator: (value) {
//Make sure since onChange is sometimes unreliable
passwordController.onChange(value ?? '');
if (confirmation != passwordTextController.text) {
if (context.mounted) {
showErrorMessage(context, 'Passwords do not match');
}
return;
}
}
backupFuture.value = ref
.read(userBackupServiceProvider.notifier)
.createUserBackup(
profile,
password: passwordTextController.text,
integrityCheck: integrityVerification.value,
);
}
return passwordController.areAllRulesValidated
? null
: 'Not Validated';
},
label: const Text('Backup'),
),
],
const SizedBox(height: 16),
SwitchListTile(
contentPadding: EdgeInsets.zero,
value: integrityVerification.value,
onChanged: disableInteraction
? null
: (value) {
integrityVerification.value = value;
},
title: const Text('Verify Backup Integrity'),
subtitle: const Text(
'Automatically check that backups are complete and restorable',
),
),
ExpansionTile(
enabled: !disableInteraction,
childrenPadding: EdgeInsets.zero,
tilePadding: EdgeInsets.zero,
title: const Text('Advanced'),
children: [
SwitchListTile(
contentPadding: EdgeInsets.zero,
value: skipPasswordConfirmation.value,
onChanged: disableInteraction
? null
: (value) {
skipPasswordConfirmation.value = value;
},
title: const Text('Skip Password Confirmation Prompt'),
),
],
),
const SizedBox(height: 16),
if (disableInteraction)
const Column(
children: [
LinearProgressIndicator(),
Text('Creating Backup'),
],
)
else
FilledButton.icon(
icon: const Icon(MdiIcons.safe),
onPressed: () async {
if (formKey.currentState?.validate() ?? false) {
if (!skipPasswordConfirmation.value) {
final confirmation =
await showPasswordConfirmationDialog(context);
if (confirmation != passwordTextController.text) {
if (context.mounted) {
showErrorMessage(
context,
'Passwords do not match',
);
}
return;
}
}
backupFuture.value = ref
.read(userBackupServiceProvider.notifier)
.createUserBackup(
profile,
password: passwordTextController.text,
integrityCheck: integrityVerification.value,
);
}
},
label: const Text('Backup'),
),
],
),
),
),
),