From 9ea7afc4f2c3e4ebd206d1e03ef453594b5edce5 Mon Sep 17 00:00:00 2001 From: Christian Pauly Date: Sat, 14 Nov 2020 10:08:13 +0100 Subject: [PATCH] chore: Switch to adaptive dialogs --- lib/components/chat_settings_popup_menu.dart | 8 +- lib/components/dialogs/simple_dialogs.dart | 139 ------------ lib/components/encryption_button.dart | 12 +- lib/components/list_items/chat_list_item.dart | 8 +- lib/components/matrix.dart | 28 ++- lib/components/user_bottom_sheet.dart | 17 +- lib/l10n/intl_en.arb | 5 + lib/utils/sentry_controller.dart | 20 +- lib/utils/url_launcher.dart | 15 +- lib/views/chat.dart | 25 +- lib/views/chat_details.dart | 64 +++--- lib/views/chat_encryption_settings.dart | 13 +- lib/views/chat_list.dart | 24 +- lib/views/homeserver_picker.dart | 19 +- lib/views/key_verification.dart | 34 +-- lib/views/settings.dart | 214 +++++++++++------- lib/views/settings_devices.dart | 37 ++- lib/views/settings_emotes.dart | 27 ++- pubspec.lock | 14 ++ pubspec.yaml | 1 + 20 files changed, 361 insertions(+), 363 deletions(-) diff --git a/lib/components/chat_settings_popup_menu.dart b/lib/components/chat_settings_popup_menu.dart index 4bc12903..22d848a4 100644 --- a/lib/components/chat_settings_popup_menu.dart +++ b/lib/components/chat_settings_popup_menu.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:famedlysdk/famedlysdk.dart'; import 'package:fluffychat/utils/app_route.dart'; import 'package:fluffychat/views/chat_details.dart'; @@ -84,8 +85,11 @@ class _ChatSettingsPopupMenuState extends State { onSelected: (String choice) async { switch (choice) { case 'leave': - var confirmed = await SimpleDialogs(context).askConfirmation(); - if (confirmed) { + var confirmed = await showOkCancelAlertDialog( + context: context, + title: L10n.of(context).areYouSure, + ); + if (confirmed == OkCancelResult.ok) { final success = await SimpleDialogs(context) .tryRequestWithLoadingDialog(widget.room.leave()); if (success != false) { diff --git a/lib/components/dialogs/simple_dialogs.dart b/lib/components/dialogs/simple_dialogs.dart index 476fbaa0..b1481cd9 100644 --- a/lib/components/dialogs/simple_dialogs.dart +++ b/lib/components/dialogs/simple_dialogs.dart @@ -2,140 +2,12 @@ import 'package:flushbar/flushbar_helper.dart'; import 'package:famedlysdk/famedlysdk.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; -import 'package:matrix_link_text/link_text.dart'; class SimpleDialogs { final BuildContext context; const SimpleDialogs(this.context); - Future enterText( - {String titleText, - String confirmText, - String cancelText, - String hintText, - String labelText, - String prefixText, - String suffixText, - bool password = false, - bool multiLine = false, - TextInputType keyboardType}) async { - var textEditingController = TextEditingController(); - final controller = textEditingController; - String input; - await showDialog( - context: context, - builder: (c) => AlertDialog( - title: Text(titleText ?? 'Please enter a text'), - content: TextField( - controller: controller, - autofocus: true, - autocorrect: false, - onSubmitted: (s) { - input = s; - Navigator.of(c).pop(); - }, - minLines: multiLine ? 3 : 1, - maxLines: multiLine ? 3 : 1, - obscureText: password, - textInputAction: multiLine ? TextInputAction.newline : null, - keyboardType: keyboardType, - decoration: InputDecoration( - hintText: hintText, - labelText: labelText, - prefixText: prefixText, - suffixText: suffixText, - prefixStyle: TextStyle(color: Theme.of(context).primaryColor), - suffixStyle: TextStyle(color: Theme.of(context).primaryColor), - border: OutlineInputBorder(), - ), - ), - actions: [ - FlatButton( - child: Text( - cancelText?.toUpperCase() ?? - L10n.of(context).close.toUpperCase(), - style: TextStyle(color: Colors.blueGrey)), - onPressed: () => Navigator.of(c).pop(), - ), - FlatButton( - child: Text( - confirmText?.toUpperCase() ?? - L10n.of(context).confirm.toUpperCase(), - ), - onPressed: () { - input = controller.text; - Navigator.of(c).pop(); - }, - ), - ], - ), - ); - return input; - } - - Future askConfirmation({ - String titleText, - String contentText, - String confirmText, - String cancelText, - bool dangerous = false, - }) async { - var confirmed = false; - await showDialog( - context: context, - builder: (c) => AlertDialog( - title: Text(titleText ?? L10n.of(context).areYouSure), - content: contentText != null ? LinkText(text: contentText) : null, - actions: [ - FlatButton( - child: Text( - cancelText?.toUpperCase() ?? - L10n.of(context).close.toUpperCase(), - style: TextStyle(color: Colors.blueGrey)), - onPressed: () => Navigator.of(c).pop(), - ), - FlatButton( - child: Text( - confirmText?.toUpperCase() ?? - L10n.of(context).confirm.toUpperCase(), - style: TextStyle(color: dangerous ? Colors.red : null), - ), - onPressed: () { - confirmed = true; - Navigator.of(c).pop(); - }, - ), - ], - ), - ); - return confirmed; - } - - Future inform({ - String titleText, - String contentText, - String okText, - }) async { - await showDialog( - context: context, - builder: (c) => AlertDialog( - title: titleText != null ? Text(titleText) : null, - content: contentText != null ? Text(contentText) : null, - actions: [ - FlatButton( - child: Text( - okText ?? L10n.of(context).ok.toUpperCase(), - ), - onPressed: () { - Navigator.of(c).pop(); - }, - ), - ], - ), - ); - } - Future tryRequestWithLoadingDialog(Future request, {Function(MatrixException) onAdditionalAuth}) async { var completed = false; @@ -178,15 +50,4 @@ class SimpleDialogs { return false; } } - - void showLoadingDialog(BuildContext context) async { - await showDialog( - context: context, - barrierDismissible: false, - builder: (BuildContext context) => AlertDialog( - title: Text(L10n.of(context).loadingPleaseWait), - content: LinearProgressIndicator(), - ), - ); - } } diff --git a/lib/components/encryption_button.dart b/lib/components/encryption_button.dart index ca8d2fee..bd9f47dd 100644 --- a/lib/components/encryption_button.dart +++ b/lib/components/encryption_button.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:flushbar/flushbar_helper.dart'; import 'package:famedlysdk/famedlysdk.dart'; import 'package:fluffychat/utils/app_route.dart'; @@ -36,14 +37,15 @@ class _EncryptionButtonState extends State { .show(context); return; } - if (await SimpleDialogs(context).askConfirmation( - titleText: L10n.of(context).enableEncryptionWarning, - contentText: widget.room.client.encryptionEnabled + if (await showOkCancelAlertDialog( + context: context, + title: L10n.of(context).enableEncryptionWarning, + message: widget.room.client.encryptionEnabled ? L10n.of(context).warningEncryptionInBeta : L10n.of(context).needPantalaimonWarning, - confirmText: L10n.of(context).yes, + okLabel: L10n.of(context).yes, ) == - true) { + OkCancelResult.ok) { await SimpleDialogs(context).tryRequestWithLoadingDialog( widget.room.enableEncryption(), ); diff --git a/lib/components/list_items/chat_list_item.dart b/lib/components/list_items/chat_list_item.dart index d2c8415d..0a788eb1 100644 --- a/lib/components/list_items/chat_list_item.dart +++ b/lib/components/list_items/chat_list_item.dart @@ -1,3 +1,4 @@ +import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:flushbar/flushbar_helper.dart'; import 'package:circular_check_box/circular_check_box.dart'; import 'package:famedlysdk/famedlysdk.dart'; @@ -117,8 +118,11 @@ class ChatListItem extends StatelessWidget { } return success; } - final confirmed = await SimpleDialogs(context).askConfirmation(); - if (!confirmed) return; + final confirmed = await showOkCancelAlertDialog( + context: context, + title: L10n.of(context).areYouSure, + ); + if (confirmed == OkCancelResult.cancel) return; await SimpleDialogs(context).tryRequestWithLoadingDialog(room.leave()); return; } diff --git a/lib/components/matrix.dart b/lib/components/matrix.dart index c895daa1..0b02989b 100644 --- a/lib/components/matrix.dart +++ b/lib/components/matrix.dart @@ -1,9 +1,9 @@ import 'dart:async'; import 'dart:io'; +import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:famedlysdk/encryption.dart'; import 'package:famedlysdk/famedlysdk.dart'; -import 'package:fluffychat/components/dialogs/simple_dialogs.dart'; import 'package:fluffychat/utils/firebase_controller.dart'; import 'package:fluffychat/utils/matrix_locals.dart'; import 'package:fluffychat/utils/platform_infos.dart'; @@ -258,13 +258,15 @@ class MatrixState extends State { return; // ignore share requests by others } final sender = room.getUserByMXIDSync(request.sender); - if (await SimpleDialogs(context).askConfirmation( - titleText: L10n.of(context).requestToReadOlderMessages, - contentText: - '${sender.id}\n\n${L10n.of(context).device}:\n${request.requestingDevice.deviceId}\n\n${L10n.of(context).identity}:\n${request.requestingDevice.curve25519Key.beautified}', - confirmText: L10n.of(context).verify, - cancelText: L10n.of(context).deny, - )) { + if (await showOkCancelAlertDialog( + context: context, + title: L10n.of(context).requestToReadOlderMessages, + message: + '${sender.id}\n\n${L10n.of(context).device}:\n${request.requestingDevice.deviceId}\n\n${L10n.of(context).identity}:\n${request.requestingDevice.curve25519Key.beautified}', + okLabel: L10n.of(context).verify, + cancelLabel: L10n.of(context).deny, + ) == + OkCancelResult.ok) { await request.forwardKey(); } }); @@ -279,10 +281,12 @@ class MatrixState extends State { } hidPopup = true; }; - if (await SimpleDialogs(context).askConfirmation( - titleText: L10n.of(context).newVerificationRequest, - contentText: L10n.of(context).askVerificationRequest(request.userId), - )) { + if (await showOkCancelAlertDialog( + context: context, + title: L10n.of(context).newVerificationRequest, + message: L10n.of(context).askVerificationRequest(request.userId), + ) == + OkCancelResult.ok) { request.onUpdate = null; hidPopup = true; await request.acceptVerification(); diff --git a/lib/components/user_bottom_sheet.dart b/lib/components/user_bottom_sheet.dart index 0d1c91d0..3a0dece6 100644 --- a/lib/components/user_bottom_sheet.dart +++ b/lib/components/user_bottom_sheet.dart @@ -1,5 +1,6 @@ import 'dart:math'; +import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:famedlysdk/famedlysdk.dart'; import 'package:fluffychat/components/adaptive_page_layout.dart'; import 'package:fluffychat/utils/app_route.dart'; @@ -23,41 +24,45 @@ class UserBottomSheet extends StatelessWidget { : super(key: key); void participantAction(BuildContext context, String action) async { + final Function _askConfirmation = () async => + (await showOkCancelAlertDialog( + context: context, title: L10n.of(context).areYouSure) == + OkCancelResult.ok); switch (action) { case 'mention': Navigator.of(context).pop(); onMention(); break; case 'ban': - if (await SimpleDialogs(context).askConfirmation()) { + if (await _askConfirmation()) { await SimpleDialogs(context).tryRequestWithLoadingDialog(user.ban()); } break; case 'unban': - if (await SimpleDialogs(context).askConfirmation()) { + if (await _askConfirmation()) { await SimpleDialogs(context) .tryRequestWithLoadingDialog(user.unban()); } break; case 'kick': - if (await SimpleDialogs(context).askConfirmation()) { + if (await _askConfirmation()) { await SimpleDialogs(context).tryRequestWithLoadingDialog(user.kick()); } break; case 'admin': - if (await SimpleDialogs(context).askConfirmation()) { + if (await _askConfirmation()) { await SimpleDialogs(context) .tryRequestWithLoadingDialog(user.setPower(100)); } break; case 'moderator': - if (await SimpleDialogs(context).askConfirmation()) { + if (await _askConfirmation()) { await SimpleDialogs(context) .tryRequestWithLoadingDialog(user.setPower(50)); } break; case 'user': - if (await SimpleDialogs(context).askConfirmation()) { + if (await _askConfirmation()) { await SimpleDialogs(context) .tryRequestWithLoadingDialog(user.setPower(0)); } diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index 46f8aa0d..c81bddbd 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -283,6 +283,11 @@ "type": "text", "placeholders": {} }, + "changePassword": "Change password", + "@changePassword": { + "type": "text", + "placeholders": {} + }, "changeWallpaper": "Change wallpaper", "@changeWallpaper": { "type": "text", diff --git a/lib/utils/sentry_controller.dart b/lib/utils/sentry_controller.dart index e50833cb..32f633a7 100644 --- a/lib/utils/sentry_controller.dart +++ b/lib/utils/sentry_controller.dart @@ -1,5 +1,5 @@ +import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:flushbar/flushbar_helper.dart'; -import 'package:fluffychat/components/dialogs/simple_dialogs.dart'; import 'package:fluffychat/config/app_config.dart'; import 'package:flutter/material.dart'; import 'package:flutter/foundation.dart'; @@ -11,16 +11,18 @@ import '../config/setting_keys.dart'; abstract class SentryController { static Future toggleSentryAction(BuildContext context) async { - final enableSentry = await SimpleDialogs(context).askConfirmation( - titleText: L10n.of(context).sendBugReports, - contentText: L10n.of(context).sentryInfo, - confirmText: L10n.of(context).ok, - cancelText: L10n.of(context).no, - ); + final enableSentry = await showOkCancelAlertDialog( + context: context, + title: L10n.of(context).sendBugReports, + message: L10n.of(context).sentryInfo, + okLabel: L10n.of(context).ok, + cancelLabel: L10n.of(context).no, + ) == + OkCancelResult.ok; final storage = Store(); await storage.setItem(SettingKeys.sentry, enableSentry.toString()); - await FlushbarHelper.createSuccess( - message: L10n.of(context).changesHaveBeenSaved) + // ignore: unawaited_futures + FlushbarHelper.createSuccess(message: L10n.of(context).changesHaveBeenSaved) .show(context); return; } diff --git a/lib/utils/url_launcher.dart b/lib/utils/url_launcher.dart index 1f99d657..7ca7c34f 100644 --- a/lib/utils/url_launcher.dart +++ b/lib/utils/url_launcher.dart @@ -1,3 +1,4 @@ +import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:famedlysdk/famedlysdk.dart'; import 'package:fluffychat/components/dialogs/simple_dialogs.dart'; import 'package:fluffychat/components/matrix.dart'; @@ -79,8 +80,11 @@ class UrlLauncher { if (roomIdOrAlias[0] == '!') { roomId = roomIdOrAlias; } - if (await SimpleDialogs(context) - .askConfirmation(titleText: 'Join room $roomIdOrAlias')) { + if (await showOkCancelAlertDialog( + context: context, + title: 'Join room $roomIdOrAlias', + ) == + OkCancelResult.ok) { final response = await SimpleDialogs(context).tryRequestWithLoadingDialog( matrix.client.joinRoomOrAlias( @@ -114,8 +118,11 @@ class UrlLauncher { return; } - if (await SimpleDialogs(context) - .askConfirmation(titleText: 'Message user $identifier')) { + if (await showOkCancelAlertDialog( + context: context, + title: 'Message user $identifier', + ) == + OkCancelResult.ok) { roomId = await SimpleDialogs(context) .tryRequestWithLoadingDialog(user.startDirectChat()); Navigator.of(context).pop(); diff --git a/lib/views/chat.dart b/lib/views/chat.dart index 3b106963..a77049ea 100644 --- a/lib/views/chat.dart +++ b/lib/views/chat.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:io'; import 'dart:math'; +import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:famedlysdk/famedlysdk.dart'; import 'package:file_picker_cross/file_picker_cross.dart'; @@ -303,10 +304,12 @@ class _ChatState extends State<_Chat> { } void redactEventsAction(BuildContext context) async { - var confirmed = await SimpleDialogs(context).askConfirmation( - titleText: L10n.of(context).messageWillBeRemovedWarning, - confirmText: L10n.of(context).remove, - ); + var confirmed = await showOkCancelAlertDialog( + context: context, + title: L10n.of(context).messageWillBeRemovedWarning, + okLabel: L10n.of(context).remove, + ) == + OkCancelResult.ok; if (!confirmed) return; for (var event in selectedEvents) { await SimpleDialogs(context).tryRequestWithLoadingDialog( @@ -363,10 +366,7 @@ class _ChatState extends State<_Chat> { if (eventIndex == -1) { // event id not found...maybe we can fetch it? // the try...finally is here to start and close the loading dialog reliably - try { - if (context != null) { - SimpleDialogs(context).showLoadingDialog(context); - } + final task = Future.microtask(() async { // okay, we first have to fetch if the event is in the room try { final event = await timeline.getEventById(eventId); @@ -399,10 +399,11 @@ class _ChatState extends State<_Chat> { eventIndex = getFilteredEvents().indexWhere((e) => e.eventId == eventId); } - } finally { - if (context != null) { - Navigator.of(context)?.pop(); - } + }); + if (context != null) { + await SimpleDialogs(context).tryRequestWithLoadingDialog(task); + } else { + await task; } } await _scrollController.scrollToIndex(eventIndex, diff --git a/lib/views/chat_details.dart b/lib/views/chat_details.dart index c43a224d..3b190ee9 100644 --- a/lib/views/chat_details.dart +++ b/lib/views/chat_details.dart @@ -1,3 +1,4 @@ +import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:flushbar/flushbar_helper.dart'; import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/matrix_api.dart'; @@ -36,16 +37,22 @@ class ChatDetails extends StatefulWidget { class _ChatDetailsState extends State { List members; void setDisplaynameAction(BuildContext context) async { - var enterText = SimpleDialogs(context).enterText( - titleText: L10n.of(context).changeTheNameOfTheGroup, - labelText: L10n.of(context).changeTheNameOfTheGroup, - hintText: - widget.room.getLocalizedDisplayname(MatrixLocals(L10n.of(context))), + final input = await showTextInputDialog( + context: context, + title: L10n.of(context).changeTheNameOfTheGroup, + textFields: [ + DialogTextField( + initialText: widget.room.getLocalizedDisplayname( + MatrixLocals( + L10n.of(context), + ), + ), + ) + ], ); - final displayname = await enterText; - if (displayname == null) return; + if (input == null) return; final success = await SimpleDialogs(context).tryRequestWithLoadingDialog( - widget.room.setName(displayname), + widget.room.setName(input.single), ); if (success != false) { await FlushbarHelper.createSuccess( @@ -55,16 +62,19 @@ class _ChatDetailsState extends State { } void setCanonicalAliasAction(context) async { - final s = await SimpleDialogs(context).enterText( - titleText: L10n.of(context).setInvitationLink, - labelText: L10n.of(context).setInvitationLink, - hintText: L10n.of(context).alias.toLowerCase(), - prefixText: '#', - suffixText: ':' + widget.room.client.userID.domain, + final input = await showTextInputDialog( + context: context, + title: L10n.of(context).setInvitationLink, + textFields: [ + DialogTextField( + hintText: '#localpart:domain', + initialText: L10n.of(context).alias.toLowerCase(), + ) + ], ); - if (s == null) return; + if (input == null) return; final domain = widget.room.client.userID.domain; - final canonicalAlias = '%23' + s + '%3A' + domain; + final canonicalAlias = '%23' + input.single + '%3A' + domain; final aliasEvent = widget.room.getState('m.room.aliases', domain); final aliases = aliasEvent != null ? aliasEvent.content['aliases'] ?? [] : []; @@ -84,23 +94,25 @@ class _ChatDetailsState extends State { } await SimpleDialogs(context).tryRequestWithLoadingDialog( widget.room.client.sendState(widget.room.id, 'm.room.canonical_alias', { - 'alias': '#$s:$domain', + 'alias': input.single, }), ); } void setTopicAction(BuildContext context) async { - final displayname = await SimpleDialogs(context).enterText( - titleText: L10n.of(context).setGroupDescription, - labelText: L10n.of(context).setGroupDescription, - hintText: (widget.room.topic?.isNotEmpty ?? false) - ? widget.room.topic - : L10n.of(context).addGroupDescription, - multiLine: true, + final input = await showTextInputDialog( + context: context, + title: L10n.of(context).setGroupDescription, + textFields: [ + DialogTextField( + hintText: L10n.of(context).setGroupDescription, + initialText: widget.room.topic, + ) + ], ); - if (displayname == null) return; + if (input == null) return; final success = await SimpleDialogs(context).tryRequestWithLoadingDialog( - widget.room.setDescription(displayname), + widget.room.setDescription(input.single), ); if (success != false) { await FlushbarHelper.createSuccess( diff --git a/lib/views/chat_encryption_settings.dart b/lib/views/chat_encryption_settings.dart index 571a7eda..cad4da96 100644 --- a/lib/views/chat_encryption_settings.dart +++ b/lib/views/chat_encryption_settings.dart @@ -1,3 +1,4 @@ +import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:famedlysdk/encryption.dart'; import 'package:famedlysdk/famedlysdk.dart'; import 'package:fluffychat/components/adaptive_page_layout.dart'; @@ -8,8 +9,6 @@ import 'package:fluffychat/views/chat_list.dart'; import 'package:flushbar/flushbar_helper.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; - -import '../components/dialogs/simple_dialogs.dart'; import '../utils/app_route.dart'; import 'key_verification.dart'; @@ -64,10 +63,12 @@ class _ChatEncryptionSettingsState extends State { ); break; case 'verify_manual': - if (await SimpleDialogs(context).askConfirmation( - titleText: L10n.of(context).isDeviceKeyCorrect, - contentText: key.ed25519Key.beautified, - )) { + if (await showOkCancelAlertDialog( + context: context, + title: L10n.of(context).isDeviceKeyCorrect, + message: key.ed25519Key.beautified, + ) == + OkCancelResult.ok) { await unblock(); await key.setVerified(true); setState(() => null); diff --git a/lib/views/chat_list.dart b/lib/views/chat_list.dart index e1f63af0..95801b73 100644 --- a/lib/views/chat_list.dart +++ b/lib/views/chat_list.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'dart:io'; +import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/matrix_api.dart'; import 'package:fluffychat/components/connection_status_header.dart'; @@ -197,19 +198,22 @@ class _ChatListState extends State { void _setStatus(BuildContext context) async { Navigator.of(context).pop(); - final statusMsg = await SimpleDialogs(context).enterText( - titleText: L10n.of(context).setStatus, - labelText: L10n.of(context).setStatus, - hintText: L10n.of(context).statusExampleMessage, - multiLine: true, + final input = await showTextInputDialog( + title: L10n.of(context).setStatus, + context: context, + textFields: [ + DialogTextField( + hintText: L10n.of(context).statusExampleMessage, + ) + ], ); - if (statusMsg?.isEmpty ?? true) return; + if (input == null || input.single.isEmpty) return; final client = Matrix.of(context).client; await SimpleDialogs(context).tryRequestWithLoadingDialog( client.sendPresence( client.userID, PresenceType.online, - statusMsg: statusMsg, + statusMsg: input.single, ), ); return; @@ -242,7 +246,11 @@ class _ChatListState extends State { } Future _archiveAction(BuildContext context) async { - final confirmed = await SimpleDialogs(context).askConfirmation(); + final confirmed = await showOkCancelAlertDialog( + context: context, + title: L10n.of(context).areYouSure, + ) == + OkCancelResult.ok; if (!confirmed) return; await SimpleDialogs(context) .tryRequestWithLoadingDialog(_archiveSelectedRooms(context)); diff --git a/lib/views/homeserver_picker.dart b/lib/views/homeserver_picker.dart index 8d6fbcfe..a9127d0c 100644 --- a/lib/views/homeserver_picker.dart +++ b/lib/views/homeserver_picker.dart @@ -1,5 +1,6 @@ import 'dart:math'; +import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:famedlysdk/famedlysdk.dart'; import 'package:fluffychat/components/dialogs/simple_dialogs.dart'; import 'package:fluffychat/components/matrix.dart'; @@ -13,13 +14,17 @@ import 'package:url_launcher/url_launcher.dart'; class HomeserverPicker extends StatelessWidget { Future _setHomeserverAction(BuildContext context) async { - final homeserver = await SimpleDialogs(context).enterText( - titleText: L10n.of(context).enterYourHomeserver, - hintText: AppConfig.defaultHomeserver, - prefixText: 'https://', - keyboardType: TextInputType.url); - if (homeserver?.isEmpty ?? true) return; - _checkHomeserverAction(homeserver, context); + final homeserver = await showTextInputDialog( + title: L10n.of(context).enterYourHomeserver, + context: context, + textFields: [ + DialogTextField( + hintText: AppConfig.defaultHomeserver, + ) + ], + ); + if (homeserver?.single?.isEmpty ?? true) return; + _checkHomeserverAction(homeserver.single, context); } void _checkHomeserverAction(String homeserver, BuildContext context) async { diff --git a/lib/views/key_verification.dart b/lib/views/key_verification.dart index 59585cd5..f3e24621 100644 --- a/lib/views/key_verification.dart +++ b/lib/views/key_verification.dart @@ -1,3 +1,4 @@ +import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:famedlysdk/encryption.dart'; import 'package:famedlysdk/matrix_api.dart'; import 'package:flutter/material.dart'; @@ -77,25 +78,28 @@ class _KeyVerificationPageState extends State { if (input == null) { return; } - SimpleDialogs(context).showLoadingDialog(context); - // make sure the loading spinner shows before we test the keys - await Future.delayed(Duration(milliseconds: 100)); - var valid = false; - try { - await widget.request.openSSSS(recoveryKey: input); - valid = true; - } catch (_) { + final valid = await SimpleDialogs(context) + .tryRequestWithLoadingDialog(Future.microtask(() async { + // make sure the loading spinner shows before we test the keys + await Future.delayed(Duration(milliseconds: 100)); + var valid = false; try { - await widget.request.openSSSS(passphrase: input); + await widget.request.openSSSS(recoveryKey: input); valid = true; } catch (_) { - valid = false; + try { + await widget.request.openSSSS(passphrase: input); + valid = true; + } catch (_) { + valid = false; + } } - } - await Navigator.of(context)?.pop(); - if (!valid) { - await SimpleDialogs(context).inform( - contentText: L10n.of(context).incorrectPassphraseOrKey, + return valid; + })); + if (valid == false) { + await showOkAlertDialog( + context: context, + message: L10n.of(context).incorrectPassphraseOrKey, ); } }; diff --git a/lib/views/settings.dart b/lib/views/settings.dart index 6308a774..5036510e 100644 --- a/lib/views/settings.dart +++ b/lib/views/settings.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:flushbar/flushbar_helper.dart'; import 'package:famedlysdk/famedlysdk.dart'; import 'package:file_picker_cross/file_picker_cross.dart'; @@ -52,7 +53,11 @@ class _SettingsState extends State { bool megolmBackupCached; void logoutAction(BuildContext context) async { - if (await SimpleDialogs(context).askConfirmation() == false) { + if (await showOkCancelAlertDialog( + context: context, + title: L10n.of(context).areYouSure, + ) == + OkCancelResult.cancel) { return; } var matrix = Matrix.of(context); @@ -61,20 +66,25 @@ class _SettingsState extends State { } void _changePasswordAccountAction(BuildContext context) async { - final oldPassword = await SimpleDialogs(context).enterText( - password: true, - titleText: L10n.of(context).pleaseEnterYourPassword, + final input = await showTextInputDialog( + context: context, + title: L10n.of(context).changePassword, + textFields: [ + DialogTextField( + hintText: L10n.of(context).pleaseEnterYourPassword, + obscureText: true, + ), + DialogTextField( + hintText: L10n.of(context).chooseAStrongPassword, + obscureText: true, + ), + ], ); - if (oldPassword == null) return; - final newPassword = await SimpleDialogs(context).enterText( - password: true, - titleText: L10n.of(context).chooseAStrongPassword, - ); - if (newPassword == null) return; + if (input == null) return; await SimpleDialogs(context).tryRequestWithLoadingDialog( Matrix.of(context) .client - .changePassword(newPassword, oldPassword: oldPassword), + .changePassword(input.last, oldPassword: input.first), ); await FlushbarHelper.createSuccess( message: L10n.of(context).passwordHasBeenChanged) @@ -82,39 +92,44 @@ class _SettingsState extends State { } void _deleteAccountAction(BuildContext context) async { - if (await SimpleDialogs(context).askConfirmation( - titleText: L10n.of(context).warning, - contentText: L10n.of(context).deactivateAccountWarning, - dangerous: true, + if (await showOkCancelAlertDialog( + context: context, + title: L10n.of(context).warning, + message: L10n.of(context).deactivateAccountWarning, ) == - false) { + OkCancelResult.cancel) { return; } - if (await SimpleDialogs(context).askConfirmation(dangerous: true) == - false) { + if (await showOkCancelAlertDialog( + context: context, title: L10n.of(context).areYouSure) == + OkCancelResult.cancel) { return; } - final password = await SimpleDialogs(context).enterText( - password: true, - titleText: L10n.of(context).pleaseEnterYourPassword, + final input = await showTextInputDialog( + context: context, + title: L10n.of(context).pleaseEnterYourPassword, + textFields: [DialogTextField(obscureText: true, hintText: '******')], ); - if (password == null) return; + if (input == null) return; await SimpleDialogs(context).tryRequestWithLoadingDialog( Matrix.of(context).client.deactivateAccount(auth: { 'type': 'm.login.password', 'user': Matrix.of(context).client.userID, - 'password': password, + 'password': input.single, }), ); } void setJitsiInstanceAction(BuildContext context) async { - var jitsi = await SimpleDialogs(context).enterText( - titleText: L10n.of(context).editJitsiInstance, - hintText: Matrix.of(context).jitsiInstance, - labelText: L10n.of(context).editJitsiInstance, + var input = await showTextInputDialog( + context: context, + title: L10n.of(context).editJitsiInstance, + textFields: [ + DialogTextField(initialText: Matrix.of(context).jitsiInstance), + ], ); - if (jitsi == null) return; + if (input == null) return; + var jitsi = input.single; if (!jitsi.endsWith('/')) { jitsi += '/'; } @@ -124,16 +139,20 @@ class _SettingsState extends State { } void setDisplaynameAction(BuildContext context) async { - final displayname = await SimpleDialogs(context).enterText( - titleText: L10n.of(context).editDisplayname, - hintText: - profile?.displayname ?? Matrix.of(context).client.userID.localpart, - labelText: L10n.of(context).enterAUsername, + final input = await showTextInputDialog( + context: context, + title: L10n.of(context).editDisplayname, + textFields: [ + DialogTextField( + initialText: profile?.displayname ?? + Matrix.of(context).client.userID.localpart, + ) + ], ); - if (displayname == null) return; + if (input == null) return; final matrix = Matrix.of(context); final success = await SimpleDialogs(context).tryRequestWithLoadingDialog( - matrix.client.setDisplayname(matrix.client.userID, displayname), + matrix.client.setDisplayname(matrix.client.userID, input.single), ); if (success != false) { setState(() { @@ -195,36 +214,43 @@ class _SettingsState extends State { Future requestSSSSCache(BuildContext context) async { final handle = Matrix.of(context).client.encryption.ssss.open(); - final str = await SimpleDialogs(context).enterText( - titleText: L10n.of(context).askSSSSCache, - hintText: L10n.of(context).passphraseOrKey, - password: true, + final input = await showTextInputDialog( + context: context, + title: L10n.of(context).askSSSSCache, + textFields: [ + DialogTextField( + hintText: L10n.of(context).passphraseOrKey, obscureText: true) + ], ); - if (str != null) { - SimpleDialogs(context).showLoadingDialog(context); - // make sure the loading spinner shows before we test the keys - await Future.delayed(Duration(milliseconds: 100)); - var valid = false; - try { - handle.unlock(recoveryKey: str); - valid = true; - } catch (e, s) { - debugPrint('Couldn\'t use recovery key: ' + e.toString()); - debugPrint(s.toString()); + if (input != null) { + final valid = await SimpleDialogs(context) + .tryRequestWithLoadingDialog(Future.microtask(() async { + // make sure the loading spinner shows before we test the keys + await Future.delayed(Duration(milliseconds: 100)); + var valid = false; try { - handle.unlock(passphrase: str); + handle.unlock(recoveryKey: input.single); valid = true; } catch (e, s) { - debugPrint('Couldn\'t use recovery passphrase: ' + e.toString()); + debugPrint('Couldn\'t use recovery key: ' + e.toString()); debugPrint(s.toString()); - valid = false; + try { + handle.unlock(passphrase: input.single); + valid = true; + } catch (e, s) { + debugPrint('Couldn\'t use recovery passphrase: ' + e.toString()); + debugPrint(s.toString()); + valid = false; + } } - } - await Navigator.of(context)?.pop(); - if (valid) { + return valid; + })); + + if (valid == true) { await handle.maybeCacheAll(); - await SimpleDialogs(context).inform( - contentText: L10n.of(context).cachedKeys, + await showOkAlertDialog( + context: context, + message: L10n.of(context).cachedKeys, ); setState(() { crossSigningCachedFuture = null; @@ -233,8 +259,9 @@ class _SettingsState extends State { megolmBackupCached = null; }); } else { - await SimpleDialogs(context).inform( - contentText: L10n.of(context).incorrectPassphraseOrKey, + await showOkAlertDialog( + context: context, + message: L10n.of(context).incorrectPassphraseOrKey, ); } } @@ -452,7 +479,7 @@ class _SettingsState extends State { ListTile( trailing: Icon(Icons.vpn_key), title: Text( - 'Change password', + L10n.of(context).changePassword, ), onTap: () => _changePasswordAccountAction(context), ), @@ -497,39 +524,48 @@ class _SettingsState extends State { : null, onTap: () async { if (!client.encryption.crossSigning.enabled) { - await SimpleDialogs(context).inform( - contentText: L10n.of(context).noCrossSignBootstrap, + await showOkAlertDialog( + context: context, + message: L10n.of(context).noCrossSignBootstrap, ); return; } if (client.isUnknownSession) { - final str = await SimpleDialogs(context).enterText( - titleText: L10n.of(context).askSSSSVerify, - hintText: L10n.of(context).passphraseOrKey, - password: true, + final input = await showTextInputDialog( + context: context, + title: L10n.of(context).askSSSSVerify, + textFields: [ + DialogTextField( + hintText: L10n.of(context).passphraseOrKey, + obscureText: true) + ], ); - if (str != null) { - SimpleDialogs(context).showLoadingDialog(context); - // make sure the loading spinner shows before we test the keys - await Future.delayed(Duration(milliseconds: 100)); - var valid = false; - try { - await client.encryption.crossSigning - .selfSign(recoveryKey: str); - valid = true; - } catch (_) { + if (input != null) { + final valid = await SimpleDialogs(context) + .tryRequestWithLoadingDialog(Future.microtask(() async { + // make sure the loading spinner shows before we test the keys + await Future.delayed(Duration(milliseconds: 100)); + var valid = false; try { await client.encryption.crossSigning - .selfSign(passphrase: str); + .selfSign(recoveryKey: input.single); valid = true; } catch (_) { - valid = false; + try { + await client.encryption.crossSigning + .selfSign(passphrase: input.single); + valid = true; + } catch (_) { + valid = false; + } } - } - await Navigator.of(context)?.pop(); - if (valid) { - await SimpleDialogs(context).inform( - contentText: L10n.of(context).verifiedSession, + return valid; + })); + + if (valid == true) { + await showOkAlertDialog( + context: context, + message: L10n.of(context).verifiedSession, ); setState(() { crossSigningCachedFuture = null; @@ -538,8 +574,9 @@ class _SettingsState extends State { megolmBackupCached = null; }); } else { - await SimpleDialogs(context).inform( - contentText: L10n.of(context).incorrectPassphraseOrKey, + await showOkAlertDialog( + context: context, + message: L10n.of(context).incorrectPassphraseOrKey, ); } } @@ -563,8 +600,9 @@ class _SettingsState extends State { : null, onTap: () async { if (!client.encryption.keyManager.enabled) { - await SimpleDialogs(context).inform( - contentText: L10n.of(context).noMegolmBootstrap, + await showOkAlertDialog( + context: context, + message: L10n.of(context).noMegolmBootstrap, ); return; } diff --git a/lib/views/settings_devices.dart b/lib/views/settings_devices.dart index 76c2ed76..ea8f70b5 100644 --- a/lib/views/settings_devices.dart +++ b/lib/views/settings_devices.dart @@ -1,3 +1,4 @@ +import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:famedlysdk/famedlysdk.dart'; import 'package:fluffychat/components/dialogs/simple_dialogs.dart'; import 'package:flutter/material.dart'; @@ -35,37 +36,51 @@ class DevicesSettingsState extends State { void reload() => setState(() => devices = null); void _removeDevicesAction(BuildContext context, List devices) async { - if (await SimpleDialogs(context).askConfirmation() == false) return; + if (await showOkCancelAlertDialog( + context: context, + title: L10n.of(context).areYouSure, + ) == + OkCancelResult.cancel) return; var matrix = Matrix.of(context); var deviceIds = []; for (var userDevice in devices) { deviceIds.add(userDevice.deviceId); } - final password = await SimpleDialogs(context).enterText( - titleText: L10n.of(context).pleaseEnterYourPassword, - labelText: L10n.of(context).pleaseEnterYourPassword, - hintText: '******', - password: true); + final password = await showTextInputDialog( + title: L10n.of(context).pleaseEnterYourPassword, + context: context, + textFields: [ + DialogTextField( + hintText: '******', + obscureText: true, + ) + ], + ); if (password == null) return; final success = await SimpleDialogs(context).tryRequestWithLoadingDialog( matrix.client.deleteDevices(deviceIds, - auth: matrix.getAuthByPassword(password))); + auth: matrix.getAuthByPassword(password.single))); if (success != false) { reload(); } } void _renameDeviceAction(BuildContext context, Device device) async { - final displayName = await SimpleDialogs(context).enterText( - hintText: device.displayName, - labelText: L10n.of(context).changeDeviceName, + final displayName = await showTextInputDialog( + context: context, + title: L10n.of(context).changeDeviceName, + textFields: [ + DialogTextField( + hintText: device.displayName, + ) + ], ); if (displayName == null) return; final success = await SimpleDialogs(context).tryRequestWithLoadingDialog( Matrix.of(context) .client - .setDeviceMetadata(device.deviceId, displayName: displayName), + .setDeviceMetadata(device.deviceId, displayName: displayName.single), ); if (success != false) { reload(); diff --git a/lib/views/settings_emotes.dart b/lib/views/settings_emotes.dart index cdf6ae2c..631554d0 100644 --- a/lib/views/settings_emotes.dart +++ b/lib/views/settings_emotes.dart @@ -1,3 +1,4 @@ +import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:flushbar/flushbar_helper.dart'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:famedlysdk/famedlysdk.dart'; @@ -247,9 +248,9 @@ class _EmotesSettingsState extends State { newEmoteController.text.isEmpty || newMxcController.text == null || newMxcController.text.isEmpty) { - await SimpleDialogs(context).inform( - contentText: - L10n.of(context).emoteWarnNeedToPick); + await showOkAlertDialog( + context: context, + message: L10n.of(context).emoteWarnNeedToPick); return; } final emoteCode = ':${newEmoteController.text}:'; @@ -257,13 +258,15 @@ class _EmotesSettingsState extends State { if (emotes.indexWhere((e) => e.emote == emoteCode && e.mxc != mxc) != -1) { - await SimpleDialogs(context).inform( - contentText: L10n.of(context).emoteExists); + await showOkAlertDialog( + context: context, + message: L10n.of(context).emoteExists); return; } if (!RegExp(r'^:[-\w]+:$').hasMatch(emoteCode)) { - await SimpleDialogs(context).inform( - contentText: L10n.of(context).emoteInvalid); + await showOkAlertDialog( + context: context, + message: L10n.of(context).emoteInvalid); return; } emotes.add(_EmoteEntry(emote: emoteCode, mxc: mxc)); @@ -357,16 +360,18 @@ class _EmotesSettingsState extends State { e.mxc != emote.mxc) != -1) { controller.text = emote.emoteClean; - SimpleDialogs(context).inform( - contentText: + showOkAlertDialog( + context: context, + message: L10n.of(context).emoteExists); return; } if (!RegExp(r'^:[-\w]+:$') .hasMatch(emoteCode)) { controller.text = emote.emoteClean; - SimpleDialogs(context).inform( - contentText: + showOkAlertDialog( + context: context, + message: L10n.of(context).emoteInvalid); return; } diff --git a/pubspec.lock b/pubspec.lock index a8962f8b..0c02df54 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -8,6 +8,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "7.0.0" + adaptive_dialog: + dependency: "direct main" + description: + name: adaptive_dialog + url: "https://pub.dartlang.org" + source: hosted + version: "0.9.0+1" analyzer: dependency: transitive description: @@ -15,6 +22,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.39.17" + animations: + dependency: transitive + description: + name: animations + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.2" ansicolor: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 9507b1fe..94cc93af 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -49,6 +49,7 @@ dependencies: open_file: ^3.0.3 mime_type: ^0.3.2 flushbar: ^1.10.4 + adaptive_dialog: ^0.9.0+1 flutter_matrix_html: ^0.1.10 moor: ^3.4.0 sqlite3_flutter_libs: ^0.2.0