style: New settings design
This commit is contained in:
parent
5940ad5054
commit
5d53a37e2e
10 changed files with 401 additions and 458 deletions
|
|
@ -1,10 +1,16 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:adaptive_dialog/adaptive_dialog.dart';
|
||||
import 'package:file_picker_cross/file_picker_cross.dart';
|
||||
import 'package:flutter_app_lock/flutter_app_lock.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:future_loading_dialog/future_loading_dialog.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
import 'package:fluffychat/config/setting_keys.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
|
@ -93,12 +99,102 @@ class SettingsSecurityController extends State<SettingsSecurity> {
|
|||
}
|
||||
}
|
||||
|
||||
void deleteAccountAction() async {
|
||||
if (await showOkCancelAlertDialog(
|
||||
useRootNavigator: false,
|
||||
context: context,
|
||||
title: L10n.of(context)!.warning,
|
||||
message: L10n.of(context)!.deactivateAccountWarning,
|
||||
okLabel: L10n.of(context)!.ok,
|
||||
cancelLabel: L10n.of(context)!.cancel,
|
||||
) ==
|
||||
OkCancelResult.cancel) {
|
||||
return;
|
||||
}
|
||||
final supposedMxid = Matrix.of(context).client.userID!;
|
||||
final mxids = await showTextInputDialog(
|
||||
useRootNavigator: false,
|
||||
context: context,
|
||||
title: L10n.of(context)!.confirmMatrixId,
|
||||
textFields: [
|
||||
DialogTextField(
|
||||
validator: (text) => text == supposedMxid
|
||||
? null
|
||||
: L10n.of(context)!.supposedMxid(supposedMxid),
|
||||
),
|
||||
],
|
||||
okLabel: L10n.of(context)!.delete,
|
||||
cancelLabel: L10n.of(context)!.cancel,
|
||||
);
|
||||
if (mxids == null || mxids.length != 1 || mxids.single != supposedMxid) {
|
||||
return;
|
||||
}
|
||||
final input = await showTextInputDialog(
|
||||
useRootNavigator: false,
|
||||
context: context,
|
||||
title: L10n.of(context)!.pleaseEnterYourPassword,
|
||||
okLabel: L10n.of(context)!.ok,
|
||||
cancelLabel: L10n.of(context)!.cancel,
|
||||
textFields: [
|
||||
const DialogTextField(
|
||||
obscureText: true,
|
||||
hintText: '******',
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
)
|
||||
],
|
||||
);
|
||||
if (input == null) return;
|
||||
await showFutureLoadingDialog(
|
||||
context: context,
|
||||
future: () => Matrix.of(context).client.deactivateAccount(
|
||||
auth: AuthenticationPassword(
|
||||
password: input.single,
|
||||
identifier: AuthenticationUserIdentifier(
|
||||
user: Matrix.of(context).client.userID!),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void showBootstrapDialog(BuildContext context) async {
|
||||
await BootstrapDialog(
|
||||
client: Matrix.of(context).client,
|
||||
).show(context);
|
||||
}
|
||||
|
||||
Future<void> dehydrateAction() => dehydrateDevice(context);
|
||||
|
||||
static Future<void> dehydrateDevice(BuildContext context) async {
|
||||
final response = await showOkCancelAlertDialog(
|
||||
context: context,
|
||||
isDestructiveAction: true,
|
||||
title: L10n.of(context)!.dehydrate,
|
||||
message: L10n.of(context)!.dehydrateWarning,
|
||||
);
|
||||
if (response != OkCancelResult.ok) {
|
||||
return;
|
||||
}
|
||||
await showFutureLoadingDialog(
|
||||
context: context,
|
||||
future: () async {
|
||||
try {
|
||||
final export = await Matrix.of(context).client.exportDump();
|
||||
final filePickerCross = FilePickerCross(
|
||||
Uint8List.fromList(const Utf8Codec().encode(export!)),
|
||||
path:
|
||||
'/fluffychat-export-${DateFormat(DateFormat.YEAR_MONTH_DAY).format(DateTime.now())}.fluffybackup',
|
||||
fileExtension: 'fluffybackup');
|
||||
await filePickerCross.exportToStorage(
|
||||
subject: L10n.of(context)!.dehydrateShare,
|
||||
);
|
||||
} catch (e, s) {
|
||||
Logs().e('Export error', e, s);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => SettingsSecurityView(this);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,30 +19,34 @@ class SettingsSecurityView extends StatelessWidget {
|
|||
return Scaffold(
|
||||
appBar: AppBar(title: Text(L10n.of(context)!.security)),
|
||||
body: ListTileTheme(
|
||||
iconColor: Theme.of(context).textTheme.bodyLarge!.color,
|
||||
iconColor: Theme.of(context).colorScheme.onBackground,
|
||||
child: MaxWidthBody(
|
||||
withScrolling: true,
|
||||
child: Column(
|
||||
children: [
|
||||
ListTile(
|
||||
trailing: const Icon(Icons.panorama_fish_eye),
|
||||
leading: const Icon(Icons.panorama_fish_eye),
|
||||
trailing: const Icon(Icons.chevron_right_outlined),
|
||||
title: Text(L10n.of(context)!.whoCanSeeMyStories),
|
||||
onTap: () => VRouter.of(context).to('stories'),
|
||||
),
|
||||
ListTile(
|
||||
trailing: const Icon(Icons.close),
|
||||
leading: const Icon(Icons.close),
|
||||
trailing: const Icon(Icons.chevron_right_outlined),
|
||||
title: Text(L10n.of(context)!.ignoredUsers),
|
||||
onTap: () => VRouter.of(context).to('ignorelist'),
|
||||
),
|
||||
ListTile(
|
||||
trailing: const Icon(Icons.vpn_key_outlined),
|
||||
leading: const Icon(Icons.password_outlined),
|
||||
trailing: const Icon(Icons.chevron_right_outlined),
|
||||
title: Text(
|
||||
L10n.of(context)!.changePassword,
|
||||
),
|
||||
onTap: controller.changePasswordAccountAction,
|
||||
),
|
||||
ListTile(
|
||||
trailing: const Icon(Icons.mail_outlined),
|
||||
leading: const Icon(Icons.mail_outlined),
|
||||
trailing: const Icon(Icons.chevron_right_outlined),
|
||||
title: Text(L10n.of(context)!.passwordRecovery),
|
||||
onTap: () => VRouter.of(context).to('3pid'),
|
||||
),
|
||||
|
|
@ -50,7 +54,8 @@ class SettingsSecurityView extends StatelessWidget {
|
|||
const Divider(thickness: 1),
|
||||
if (PlatformInfos.isMobile)
|
||||
ListTile(
|
||||
trailing: const Icon(Icons.lock_outlined),
|
||||
leading: const Icon(Icons.lock_outlined),
|
||||
trailing: const Icon(Icons.chevron_right_outlined),
|
||||
title: Text(L10n.of(context)!.appLock),
|
||||
onTap: controller.setAppLockAction,
|
||||
),
|
||||
|
|
@ -64,48 +69,32 @@ class SettingsSecurityView extends StatelessWidget {
|
|||
Matrix.of(context).client.fingerprintKey.beautified,
|
||||
okLabel: L10n.of(context)!.ok,
|
||||
),
|
||||
trailing: const Icon(Icons.vpn_key_outlined),
|
||||
),
|
||||
if (!Matrix.of(context).client.encryption!.crossSigning.enabled)
|
||||
ListTile(
|
||||
title: Text(L10n.of(context)!.crossSigningEnabled),
|
||||
trailing: const Icon(Icons.error, color: Colors.red),
|
||||
onTap: () => controller.showBootstrapDialog(context),
|
||||
subtitle: Text(
|
||||
Matrix.of(context).client.fingerprintKey.beautified,
|
||||
style: const TextStyle(fontFamily: 'monospace'),
|
||||
),
|
||||
if (!Matrix.of(context).client.encryption!.keyManager.enabled)
|
||||
ListTile(
|
||||
title: Text(L10n.of(context)!.onlineKeyBackupEnabled),
|
||||
trailing: const Icon(Icons.error, color: Colors.red),
|
||||
onTap: () => controller.showBootstrapDialog(context),
|
||||
),
|
||||
if (Matrix.of(context).client.isUnknownSession)
|
||||
ListTile(
|
||||
title: const Text('Session verified'),
|
||||
trailing: const Icon(Icons.error, color: Colors.red),
|
||||
onTap: () => controller.showBootstrapDialog(context),
|
||||
),
|
||||
FutureBuilder(
|
||||
future: () async {
|
||||
return (await Matrix.of(context)
|
||||
.client
|
||||
.encryption!
|
||||
.keyManager
|
||||
.isCached()) &&
|
||||
(await Matrix.of(context)
|
||||
.client
|
||||
.encryption!
|
||||
.crossSigning
|
||||
.isCached());
|
||||
}(),
|
||||
builder: (context, snapshot) => snapshot.data == true
|
||||
? Container()
|
||||
: ListTile(
|
||||
title: Text(L10n.of(context)!.keysCached),
|
||||
trailing: const Icon(Icons.error, color: Colors.red),
|
||||
onTap: () => controller.showBootstrapDialog(context),
|
||||
),
|
||||
leading: const Icon(Icons.vpn_key_outlined),
|
||||
),
|
||||
},
|
||||
const Divider(height: 1),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.tap_and_play),
|
||||
trailing: const Icon(Icons.chevron_right_outlined),
|
||||
title: Text(
|
||||
L10n.of(context)!.dehydrate,
|
||||
style: const TextStyle(color: Colors.red),
|
||||
),
|
||||
onTap: controller.dehydrateAction,
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.delete_outlined),
|
||||
trailing: const Icon(Icons.chevron_right_outlined),
|
||||
title: Text(
|
||||
L10n.of(context)!.deleteAccount,
|
||||
style: const TextStyle(color: Colors.red),
|
||||
),
|
||||
onTap: controller.deleteAccountAction,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue