fix: Bootstrap hint

This commit is contained in:
Christian Pauly 2021-02-27 09:10:08 +01:00
parent 55803d1d3f
commit 8651b37d81
6 changed files with 102 additions and 61 deletions

View File

@ -91,6 +91,7 @@ class _BootstrapDialogState extends State<BootstrapDialog> {
style: TextStyle( style: TextStyle(
fontSize: 18, fontSize: 18,
wordSpacing: 38, wordSpacing: 38,
fontFamily: 'monospace',
), ),
), ),
); );
@ -129,8 +130,8 @@ class _BootstrapDialogState extends State<BootstrapDialog> {
_recoveryKeyInputError ?? L10n.of(context).pleaseEnterSecurityKey; _recoveryKeyInputError ?? L10n.of(context).pleaseEnterSecurityKey;
body = PlatformInfos.isCupertinoStyle body = PlatformInfos.isCupertinoStyle
? CupertinoTextField( ? CupertinoTextField(
minLines: 2, minLines: 1,
maxLines: 2, maxLines: 1,
autofocus: true, autofocus: true,
autocorrect: false, autocorrect: false,
autofillHints: _recoveryKeyInputLoading autofillHints: _recoveryKeyInputLoading
@ -139,46 +140,22 @@ class _BootstrapDialogState extends State<BootstrapDialog> {
controller: _recoveryKeyTextEditingController, controller: _recoveryKeyTextEditingController,
) )
: TextField( : TextField(
minLines: 2, minLines: 1,
maxLines: 2, maxLines: 1,
autofocus: true, autofocus: true,
autocorrect: false, autocorrect: false,
autofillHints: _recoveryKeyInputLoading autofillHints: _recoveryKeyInputLoading
? null ? null
: [AutofillHints.password], : [AutofillHints.password],
controller: _recoveryKeyTextEditingController, controller: _recoveryKeyTextEditingController,
decoration: InputDecoration(
border: UnderlineInputBorder(),
filled: false,
hintText: L10n.of(context).securityKey,
),
); );
buttons.add(AdaptiveFlatButton( buttons.add(AdaptiveFlatButton(
textColor: Colors.red, label: L10n.of(context).unlockChatBackup,
label: 'Lost security key',
onPressed: () async {
if (OkCancelResult.ok ==
await showOkCancelAlertDialog(
context: context,
useRootNavigator: false,
title: L10n.of(context).securityKeyLost,
message: L10n.of(context).wipeChatBackup,
okLabel: L10n.of(context).ok,
cancelLabel: L10n.of(context).cancel,
isDestructiveAction: true,
)) {
_createBootstrap(true);
}
},
));
buttons.add(AdaptiveFlatButton(
label: L10n.of(context).transferFromAnotherDevice,
onPressed: () async {
final req = await Matrix.of(context)
.client
.userDeviceKeys[Matrix.of(context).client.userID]
.startVerification();
await KeyVerificationDialog(request: req).show(context);
Navigator.of(context, rootNavigator: false).pop();
},
));
buttons.add(AdaptiveFlatButton(
label: L10n.of(context).next,
onPressed: () async { onPressed: () async {
setState(() { setState(() {
_recoveryKeyInputError = null; _recoveryKeyInputError = null;
@ -197,6 +174,35 @@ class _BootstrapDialogState extends State<BootstrapDialog> {
setState(() => _recoveryKeyInputLoading = false); setState(() => _recoveryKeyInputLoading = false);
} }
})); }));
buttons.add(AdaptiveFlatButton(
label: L10n.of(context).transferFromAnotherDevice,
onPressed: () async {
final req = await Matrix.of(context)
.client
.userDeviceKeys[Matrix.of(context).client.userID]
.startVerification();
await KeyVerificationDialog(request: req).show(context);
Navigator.of(context, rootNavigator: false).pop();
},
));
buttons.add(AdaptiveFlatButton(
textColor: Colors.red,
label: L10n.of(context).securityKeyLost,
onPressed: () async {
if (OkCancelResult.ok ==
await showOkCancelAlertDialog(
context: context,
useRootNavigator: false,
title: L10n.of(context).securityKeyLost,
message: L10n.of(context).wipeChatBackup,
okLabel: L10n.of(context).ok,
cancelLabel: L10n.of(context).cancel,
isDestructiveAction: true,
)) {
_createBootstrap(true);
}
},
));
break; break;
case BootstrapState.askWipeCrossSigning: case BootstrapState.askWipeCrossSigning:
WidgetsBinding.instance.addPostFrameCallback( WidgetsBinding.instance.addPostFrameCallback(

View File

@ -98,33 +98,44 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
StreamSubscription<html.Event> onFocusSub; StreamSubscription<html.Event> onFocusSub;
StreamSubscription<html.Event> onBlurSub; StreamSubscription<html.Event> onBlurSub;
String _cachedPassword;
String get cachedPassword {
final tmp = _cachedPassword;
_cachedPassword = null;
return tmp;
}
set cachedPassword(String p) => _cachedPassword = p;
void _onUiaRequest(UiaRequest uiaRequest) async { void _onUiaRequest(UiaRequest uiaRequest) async {
if (uiaRequest.state != UiaRequestState.waitForUser || if (uiaRequest.state != UiaRequestState.waitForUser ||
uiaRequest.nextStages.isEmpty) return; uiaRequest.nextStages.isEmpty) return;
final stage = uiaRequest.nextStages.first; final stage = uiaRequest.nextStages.first;
switch (stage) { switch (stage) {
case AuthenticationTypes.password: case AuthenticationTypes.password:
final input = await showTextInputDialog( final input = cachedPassword ??
context: context, (await showTextInputDialog(
title: L10n.of(context).pleaseEnterYourPassword, context: context,
okLabel: L10n.of(context).ok, title: L10n.of(context).pleaseEnterYourPassword,
cancelLabel: L10n.of(context).cancel, okLabel: L10n.of(context).ok,
useRootNavigator: false, cancelLabel: L10n.of(context).cancel,
textFields: [ useRootNavigator: false,
DialogTextField( textFields: [
minLines: 1, DialogTextField(
maxLines: 1, minLines: 1,
obscureText: true, maxLines: 1,
hintText: '******', obscureText: true,
) hintText: '******',
], )
); ],
))
?.single;
if (input?.isEmpty ?? true) return; if (input?.isEmpty ?? true) return;
return uiaRequest.completeStage( return uiaRequest.completeStage(
AuthenticationPassword( AuthenticationPassword(
session: uiaRequest.session, session: uiaRequest.session,
user: client.userID, user: client.userID,
password: input.single, password: input,
identifier: AuthenticationUserIdentifier(user: client.userID), identifier: AuthenticationUserIdentifier(user: client.userID),
), ),
); );

View File

@ -498,7 +498,7 @@
"type": "text", "type": "text",
"placeholders": {} "placeholders": {}
}, },
"pleaseEnterSecurityKey": "Please enter your security key", "pleaseEnterSecurityKey": "Please enter your security key:",
"@pleaseEnterSecurityKey": { "@pleaseEnterSecurityKey": {
"type": "text", "type": "text",
"placeholders": {} "placeholders": {}
@ -2006,6 +2006,11 @@
"unreadChats": {} "unreadChats": {}
} }
}, },
"unlockChatBackup": "Unlock chat backup",
"@unlockChatBackup": {
"type": "text",
"placeholders": {}
},
"yourPublicKey": "Your public key", "yourPublicKey": "Your public key",
"@yourPublicKey": { "@yourPublicKey": {
"type": "text", "type": "text",

View File

@ -174,12 +174,8 @@ class _ChatListState extends State<ChatList> {
final GlobalKey<DefaultAppBarSearchFieldState> _searchFieldKey = GlobalKey(); final GlobalKey<DefaultAppBarSearchFieldState> _searchFieldKey = GlobalKey();
Future<List<ThirdPartyIdentifier>> _thirdPartyIdentifierFuture;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
_thirdPartyIdentifierFuture ??=
Matrix.of(context).client.requestThirdPartyIdentifiers();
return StreamBuilder<Object>( return StreamBuilder<Object>(
stream: Matrix.of(context).onShareContentChanged.stream, stream: Matrix.of(context).onShareContentChanged.stream,
builder: (_, __) { builder: (_, __) {

View File

@ -140,12 +140,7 @@ class _ContactsState extends State<Contacts> {
color: Colors.grey, color: Colors.grey,
), ),
Center( Center(
child: RaisedButton( child: OutlinedButton(
elevation: 7,
color: Theme.of(context).scaffoldBackgroundColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6),
),
child: Text( child: Text(
L10n.of(context).inviteContact, L10n.of(context).inviteContact,
style: TextStyle( style: TextStyle(

View File

@ -378,6 +378,34 @@ class _SettingsState extends State<Settings> {
.textTheme .textTheme
.headline6 .headline6
.color)), .color)),
actions: [
FutureBuilder(
future: crossSigningCachedFuture,
builder: (context, snapshot) {
final needsBootstrap = Matrix.of(context)
.client
.encryption
.crossSigning
.enabled ==
false ||
snapshot.data == false;
final isUnknownSession =
Matrix.of(context).client.isUnknownSession;
final displayHeader = needsBootstrap || isUnknownSession;
if (!displayHeader) return Container();
return TextButton.icon(
icon: Icon(Icons.cloud, color: Colors.red),
label: Text(
L10n.of(context).chatBackup,
style: TextStyle(color: Colors.red),
),
onPressed: () async {
await BootstrapDialog().show(context);
AdaptivePageLayout.of(context).popUntilIsFirst();
},
);
}),
],
backgroundColor: Theme.of(context).appBarTheme.color, backgroundColor: Theme.of(context).appBarTheme.color,
flexibleSpace: FlexibleSpaceBar( flexibleSpace: FlexibleSpaceBar(
background: ContentBanner(profile?.avatarUrl, background: ContentBanner(profile?.avatarUrl,