feat: Better verification design

This commit is contained in:
Christian Pauly 2021-02-20 10:28:04 +01:00
parent 7403ac784b
commit 9bcd6b2609
4 changed files with 101 additions and 50 deletions

View File

@ -8,6 +8,7 @@ import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'adaptive_flat_button.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart';
import '../../utils/string_color.dart';
import '../../utils/beautify_string_extension.dart';
class KeyVerificationDialog extends StatefulWidget {
Future<void> show(BuildContext context) => PlatformInfos.isCupertinoStyle
@ -168,6 +169,26 @@ class _KeyVerificationPageState extends State<KeyVerificationDialog> {
],
mainAxisSize: MainAxisSize.min,
);
final key = widget.request.client.userDeviceKeys[widget.request.userId]
.deviceKeys[widget.request.deviceId];
if (key != null) {
buttons.add(AdaptiveFlatButton(
child: Text(widget.l10n.verifyManual),
onPressed: () async {
final result = await showOkCancelAlertDialog(
context: context,
title: widget.l10n.verifyManual,
message: key.ed25519Key.beautified,
);
if (result == OkCancelResult.ok) {
await key.setVerified(true);
}
await widget.request.cancel();
Navigator.of(context).pop();
},
));
}
break;
case KeyVerificationState.askSas:
TextSpan compareWidget;

View File

@ -0,0 +1,33 @@
import 'package:famedlysdk/famedlysdk.dart';
import 'package:flutter/material.dart';
extension DeviceExtension on Device {
String get displayname =>
(displayName?.isNotEmpty ?? false) ? displayName : 'Unknown device';
IconData get icon => displayname.toLowerCase().contains('android')
? Icons.phone_android_outlined
: displayname.toLowerCase().contains('ios')
? Icons.phone_iphone_outlined
: displayname.toLowerCase().contains('web')
? Icons.web_outlined
: displayname.toLowerCase().contains('desktop')
? Icons.desktop_mac_outlined
: Icons.device_unknown_outlined;
}
extension DeviceKeysExtension on DeviceKeys {
String get displayname => (deviceDisplayName?.isNotEmpty ?? false)
? deviceDisplayName
: 'Unknown device';
IconData get icon => displayname.toLowerCase().contains('android')
? Icons.phone_android_outlined
: displayname.toLowerCase().contains('ios')
? Icons.phone_iphone_outlined
: displayname.toLowerCase().contains('web')
? Icons.web_outlined
: displayname.toLowerCase().contains('desktop')
? Icons.desktop_mac_outlined
: Icons.device_unknown_outlined;
}

View File

@ -1,13 +1,12 @@
import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:famedlysdk/encryption.dart';
import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/components/avatar.dart';
import 'package:fluffychat/components/matrix.dart';
import 'package:fluffychat/utils/beautify_string_extension.dart';
import 'package:flushbar/flushbar_helper.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import '../components/dialogs/key_verification_dialog.dart';
import '../utils/device_extension.dart';
class ChatEncryptionSettings extends StatefulWidget {
final String id;
@ -41,20 +40,6 @@ class _ChatEncryptionSettingsState extends State<ChatEncryptionSettings> {
l10n: L10n.of(context),
).show(context);
break;
case 'verify_manual':
if (await showOkCancelAlertDialog(
context: context,
title: L10n.of(context).isDeviceKeyCorrect,
message: key.ed25519Key.beautified,
okLabel: L10n.of(context).ok,
cancelLabel: L10n.of(context).cancel,
) ==
OkCancelResult.ok) {
await unblock();
await key.setVerified(true);
setState(() => null);
}
break;
case 'verify_user':
await unblock();
final req =
@ -170,20 +155,11 @@ class _ChatEncryptionSettingsState extends State<ChatEncryptionSettings> {
var items = <PopupMenuEntry<String>>[];
if (deviceKeys[i].blocked ||
!deviceKeys[i].verified) {
if (deviceKeys[i].userId == room.client.userID) {
items.add(PopupMenuItem(
child: Text(L10n.of(context).verifyStart),
value: 'verify',
));
} else {
items.add(PopupMenuItem(
child: Text(L10n.of(context).verifyUser),
value: 'verify_user',
));
}
items.add(PopupMenuItem(
child: Text(L10n.of(context).verifyManual),
value: 'verify_manual',
child: Text(L10n.of(context).verifyStart),
value: deviceKeys[i].userId == room.client.userID
? 'verify'
: 'verify_user',
));
}
if (deviceKeys[i].blocked) {
@ -201,8 +177,15 @@ class _ChatEncryptionSettingsState extends State<ChatEncryptionSettings> {
return items;
},
child: ListTile(
leading: CircleAvatar(
foregroundColor:
Theme.of(context).textTheme.bodyText1.color,
backgroundColor:
Theme.of(context).secondaryHeaderColor,
child: Icon(deviceKeys[i].icon),
),
title: Text(
'${deviceKeys[i].deviceDisplayName ?? L10n.of(context).unknownDevice}',
deviceKeys[i].displayname,
style: TextStyle(
color: deviceKeys[i].blocked
? Colors.red

View File

@ -8,6 +8,7 @@ import 'package:flutter_gen/gen_l10n/l10n.dart';
import '../components/matrix.dart';
import '../utils/date_time_extension.dart';
import '../utils/device_extension.dart';
class DevicesSettings extends StatefulWidget {
@override
@ -113,6 +114,15 @@ class DevicesSettingsState extends State<DevicesSettings> {
setState(() => null);
}
void _unblockDeviceAction(BuildContext context, Device device) async {
final key = Matrix.of(context)
.client
.userDeviceKeys[Matrix.of(context).client.userID]
.deviceKeys[device.deviceId];
await key.setBlocked(false);
setState(() => null);
}
@override
Widget build(BuildContext context) {
return Scaffold(
@ -152,6 +162,7 @@ class DevicesSettingsState extends State<DevicesSettings> {
remove: (d) => _removeDevicesAction(context, [d]),
verify: (d) => _verifyDeviceAction(context, d),
block: (d) => _blockDeviceAction(context, d),
unblock: (d) => _unblockDeviceAction(context, d),
),
Divider(height: 1),
if (devices.isNotEmpty)
@ -189,6 +200,7 @@ class DevicesSettingsState extends State<DevicesSettings> {
remove: (d) => _removeDevicesAction(context, [d]),
verify: (d) => _verifyDeviceAction(context, d),
block: (d) => _blockDeviceAction(context, d),
unblock: (d) => _unblockDeviceAction(context, d),
),
),
),
@ -205,6 +217,7 @@ enum UserDeviceListItemAction {
remove,
verify,
block,
unblock,
}
class UserDeviceListItem extends StatelessWidget {
@ -213,6 +226,7 @@ class UserDeviceListItem extends StatelessWidget {
final void Function(Device) rename;
final void Function(Device) verify;
final void Function(Device) block;
final void Function(Device) unblock;
const UserDeviceListItem(
this.userDevice, {
@ -220,6 +234,7 @@ class UserDeviceListItem extends StatelessWidget {
@required this.rename,
@required this.verify,
@required this.block,
@required this.unblock,
Key key,
}) : super(key: key);
@ -229,9 +244,6 @@ class UserDeviceListItem extends StatelessWidget {
.client
.userDeviceKeys[Matrix.of(context).client.userID]
?.deviceKeys[userDevice.deviceId];
final displayname = (userDevice.displayName?.isNotEmpty ?? false)
? userDevice.displayName
: L10n.of(context).unknownDevice;
return ListTile(
onTap: () async {
@ -244,16 +256,23 @@ class UserDeviceListItem extends StatelessWidget {
),
SheetAction(
key: UserDeviceListItemAction.verify,
label: L10n.of(context).verify,
label: L10n.of(context).verifyStart,
),
if (keys != null) ...{
if (!keys.blocked)
SheetAction(
key: UserDeviceListItemAction.block,
label: L10n.of(context).blockDevice,
isDestructiveAction: true,
),
if (keys.blocked)
SheetAction(
key: UserDeviceListItemAction.unblock,
label: L10n.of(context).unblockDevice,
isDestructiveAction: true,
),
SheetAction(
key: UserDeviceListItemAction.block,
label: L10n.of(context).blockDevice,
isDestructiveAction: true,
),
SheetAction(
key: UserDeviceListItemAction.block,
key: UserDeviceListItemAction.remove,
label: L10n.of(context).delete,
isDestructiveAction: true,
),
@ -273,25 +292,20 @@ class UserDeviceListItem extends StatelessWidget {
case UserDeviceListItemAction.block:
block(userDevice);
break;
case UserDeviceListItemAction.unblock:
unblock(userDevice);
break;
}
},
leading: CircleAvatar(
foregroundColor: Theme.of(context).textTheme.bodyText1.color,
backgroundColor: Theme.of(context).secondaryHeaderColor,
child: Icon(displayname.toLowerCase().contains('android')
? Icons.phone_android_outlined
: displayname.toLowerCase().contains('ios')
? Icons.phone_iphone_outlined
: displayname.toLowerCase().contains('web')
? Icons.web_outlined
: displayname.toLowerCase().contains('desktop')
? Icons.desktop_mac_outlined
: Icons.device_unknown_outlined),
child: Icon(userDevice.icon),
),
title: Row(
children: <Widget>[
Text(
displayname,
userDevice.displayname,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),