From 27abdda5a58ebadcba7c2ff84c35cf495ab19fa3 Mon Sep 17 00:00:00 2001 From: boyan <17426470+boyan01@users.noreply.github.com> Date: Fri, 28 Oct 2022 16:48:14 +0800 Subject: [PATCH 1/5] refactor toast --- lib/app.dart | 75 ++++++------ lib/ui/home/bloc/conversation_cubit.dart | 6 +- lib/ui/home/chat/chat_page.dart | 4 - lib/ui/home/chat/image_editor.dart | 4 +- lib/ui/home/chat/input_container.dart | 2 +- lib/ui/home/chat/selection_bottom_bar.dart | 5 +- .../home/chat/voice_recorder_bottom_bar.dart | 4 +- .../home/chat_slide_page/chat_info_page.dart | 48 +++----- .../chat_slide_page/circle_manager_page.dart | 3 - .../disappear_message_page.dart | 7 +- .../group_invite/group_invite_dialog.dart | 18 ++- .../group_participants_page.dart | 12 +- lib/ui/home/conversation/menu_wrapper.dart | 6 - lib/ui/home/conversation/search_list.dart | 5 +- lib/ui/home/home.dart | 9 +- lib/ui/home/slide_page.dart | 3 - lib/ui/landing/landing_mobile.dart | 21 ++-- lib/ui/setting/account_delete_page.dart | 7 +- lib/ui/setting/edit_profile_page.dart | 1 - lib/ui/setting/setting_page.dart | 1 - lib/ui/setting/storage_usage_detail_page.dart | 1 - lib/utils/uri_utils.dart | 15 ++- lib/utils/web_view/web_view_mobile.dart | 3 +- lib/widgets/actions/create_circle_action.dart | 1 - .../create_group_conversation_action.dart | 1 - .../conversation/conversation_dialog.dart | 3 +- lib/widgets/message/item/file_message.dart | 2 +- .../item/image/image_preview_page.dart | 6 +- .../message/item/stranger_message.dart | 1 - lib/widgets/message/message.dart | 14 +-- lib/widgets/message/message_bubble.dart | 9 +- .../send_message_dialog.dart | 1 - lib/widgets/search_bar.dart | 3 +- lib/widgets/toast.dart | 107 ++++++++---------- lib/widgets/user/captcha_web_view_dialog.dart | 1 - lib/widgets/user/change_number_dialog.dart | 6 +- lib/widgets/user/pin_verification_dialog.dart | 4 +- lib/widgets/user/user_dialog.dart | 7 +- lib/widgets/user/verification_dialog.dart | 11 +- pubspec.lock | 7 ++ pubspec.yaml | 1 + 41 files changed, 188 insertions(+), 257 deletions(-) diff --git a/lib/app.dart b/lib/app.dart index 883c28d8c4..37f9f26ee7 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart' hide AnimatedTheme; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:overlay_support/overlay_support.dart'; import 'package:provider/provider.dart'; import 'package:tuple/tuple.dart'; @@ -194,43 +195,45 @@ class _App extends StatelessWidget { @override Widget build(BuildContext context) => WindowShortcuts( child: GlobalMoveWindow( - child: MaterialApp( - title: 'Mixin', - navigatorObservers: [rootRouteObserver], - debugShowCheckedModeBanner: false, - localizationsDelegates: const [ - Localization.delegate, - GlobalMaterialLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - ], - supportedLocales: [ - ...Localization.delegate.supportedLocales, - ], - theme: ThemeData().withFallbackFonts(), - builder: (context, child) { - try { - context.accountServer.language = - Localizations.localeOf(context).languageCode; - } catch (_) {} - final mediaQueryData = MediaQuery.of(context); - // Different linux distro change the value, e.g. 1.2 - const textScaleFactor = 1.0; - return BrightnessObserver( - lightThemeData: lightBrightnessThemeData, - darkThemeData: darkBrightnessThemeData, - forceBrightness: context.watch().brightness, - child: MediaQuery( - data: mediaQueryData.copyWith( - textScaleFactor: Platform.isLinux - ? textScaleFactor - : mediaQueryData.textScaleFactor, + child: OverlaySupport.global( + child: MaterialApp( + title: 'Mixin', + navigatorObservers: [rootRouteObserver], + debugShowCheckedModeBanner: false, + localizationsDelegates: const [ + Localization.delegate, + GlobalMaterialLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + ], + supportedLocales: [ + ...Localization.delegate.supportedLocales, + ], + theme: ThemeData().withFallbackFonts(), + builder: (context, child) { + try { + context.accountServer.language = + Localizations.localeOf(context).languageCode; + } catch (_) {} + final mediaQueryData = MediaQuery.of(context); + // Different linux distro change the value, e.g. 1.2 + const textScaleFactor = 1.0; + return BrightnessObserver( + lightThemeData: lightBrightnessThemeData, + darkThemeData: darkBrightnessThemeData, + forceBrightness: context.watch().brightness, + child: MediaQuery( + data: mediaQueryData.copyWith( + textScaleFactor: Platform.isLinux + ? textScaleFactor + : mediaQueryData.textScaleFactor, + ), + child: SystemTrayWidget(child: child!), ), - child: SystemTrayWidget(child: child!), - ), - ); - }, - home: const _Home(), + ); + }, + home: const _Home(), + ), ), ), ); diff --git a/lib/ui/home/bloc/conversation_cubit.dart b/lib/ui/home/bloc/conversation_cubit.dart index 718fba1b0c..22f5c021ff 100644 --- a/lib/ui/home/bloc/conversation_cubit.dart +++ b/lib/ui/home/bloc/conversation_cubit.dart @@ -238,7 +238,7 @@ class ConversationCubit extends SimpleCubit await _conversationItem(context, conversationId); if (_conversation == null && sync) { - showToastLoading(context); + showToastLoading(); await context.accountServer.refreshConversation(conversationId); _conversation = await _conversationItem(context, conversationId); } @@ -246,7 +246,7 @@ class ConversationCubit extends SimpleCubit hasUnreadMessage ??= (_conversation?.unseenMessageCount ?? 0) > 0; if (_conversation == null) { - return showToastFailed(context, null); + return showToastFailed(null); } final _initIndexMessageId = initIndexMessageId ?? @@ -313,7 +313,7 @@ class ConversationCubit extends SimpleCubit user ?? await database.userDao.userById(userId).getSingleOrNull(); if (_user == null) { - return showToastFailed(context, ToastError(context.l10n.userNotFound)); + return showToastFailed(ToastError(context.l10n.userNotFound)); } final app = await database.appDao.findAppById(userId); diff --git a/lib/ui/home/chat/chat_page.dart b/lib/ui/home/chat/chat_page.dart index 52836a27ad..8616c60877 100644 --- a/lib/ui/home/chat/chat_page.dart +++ b/lib/ui/home/chat/chat_page.dart @@ -1168,7 +1168,6 @@ class _ConversationHandle extends ConversationMenuHandle { } final isGroupConversation = conversationState.isGroup == true; await runFutureWithToast( - context, context.accountServer.muteConversation( result, conversationId: isGroupConversation ? conversationId : null, @@ -1182,7 +1181,6 @@ class _ConversationHandle extends ConversationMenuHandle { @override void pin() { runFutureWithToast( - context, context.accountServer.pin(conversationId), ); } @@ -1206,7 +1204,6 @@ class _ConversationHandle extends ConversationMenuHandle { @override void unPin() { runFutureWithToast( - context, context.accountServer.unpin(conversationId), ); } @@ -1219,7 +1216,6 @@ class _ConversationHandle extends ConversationMenuHandle { } final isGroup = conversationState.isGroup == true; runFutureWithToast( - context, context.accountServer.unMuteConversation( conversationId: isGroup ? conversationId : null, userId: isGroup ? null : conversationState.conversation?.ownerId, diff --git a/lib/ui/home/chat/image_editor.dart b/lib/ui/home/chat/image_editor.dart index 1a59129a4a..a0809398f1 100644 --- a/lib/ui/home/chat/image_editor.dart +++ b/lib/ui/home/chat/image_editor.dart @@ -1500,11 +1500,11 @@ class _NormalOperationBar extends HookWidget { ), TextButton( onPressed: () async { - showToastLoading(context); + showToastLoading(); final snapshot = await context.read<_ImageEditorBloc>().takeSnapshot(); if (snapshot == null) { - await showToastFailed(context, null); + showToastFailed(null); return; } Toast.dismiss(); diff --git a/lib/ui/home/chat/input_container.dart b/lib/ui/home/chat/input_container.dart index d85ae74a9b..cbc2a846e4 100644 --- a/lib/ui/home/chat/input_container.dart +++ b/lib/ui/home/chat/input_container.dart @@ -359,7 +359,7 @@ class _AnimatedSendOrVoiceButton extends HookWidget { } void showMaxLengthReachedToast(BuildContext context) => - showToastFailed(context, ToastError(context.l10n.contentTooLong)); + showToastFailed(ToastError(context.l10n.contentTooLong)); void _sendPostMessage( BuildContext context, TextEditingController textEditingController) { diff --git a/lib/ui/home/chat/selection_bottom_bar.dart b/lib/ui/home/chat/selection_bottom_bar.dart index 637e64276a..c142fb1538 100644 --- a/lib/ui/home/chat/selection_bottom_bar.dart +++ b/lib/ui/home/chat/selection_bottom_bar.dart @@ -41,7 +41,6 @@ class SelectionBottomBar extends HookWidget { final messageIds = cubit.state.selectedMessageIds; await runWithLoading( - context, () => context.accountServer.sendTranscriptMessage( messageIds.toList(), result.first.encryptCategory!, @@ -68,7 +67,7 @@ class SelectionBottomBar extends HookWidget { final cubit = context.read(); final messageIds = cubit.state.selectedMessageIds; - await runWithLoading(context, () async { + await runWithLoading(() async { for (final id in messageIds) { await context.accountServer.forwardMessage( id, @@ -98,7 +97,7 @@ class SelectionBottomBar extends HookWidget { return; } d('messagesToDelete: $messagesToDelete'); - await runWithLoading(context, () async { + await runWithLoading(() async { for (final id in messagesToDelete) { await context.accountServer.deleteMessage(id); } diff --git a/lib/ui/home/chat/voice_recorder_bottom_bar.dart b/lib/ui/home/chat/voice_recorder_bottom_bar.dart index fdc35c775a..64231ff4d3 100644 --- a/lib/ui/home/chat/voice_recorder_bottom_bar.dart +++ b/lib/ui/home/chat/voice_recorder_bottom_bar.dart @@ -374,12 +374,12 @@ class VoiceRecorderBottomBar extends HookWidget { final audioFile = File(recordedResult.path); if (!audioFile.existsSync()) { e('audio file does not exist.'); - showToastFailed(context, null); + showToastFailed(null); return; } if (audioFile.lengthSync() == 0) { e('audio file is empty.'); - showToastFailed(context, null); + showToastFailed(null); return; } }, [recordedResult]); diff --git a/lib/ui/home/chat_slide_page/chat_info_page.dart b/lib/ui/home/chat_slide_page/chat_info_page.dart index 4980d3ea32..692fb02a1c 100644 --- a/lib/ui/home/chat_slide_page/chat_info_page.dart +++ b/lib/ui/home/chat_slide_page/chat_info_page.dart @@ -142,15 +142,13 @@ class ChatInfoPage extends HookWidget { if (result == null || result.isEmpty) return; final conversationId = result.first.conversationId; - await runFutureWithToast( - context, - accountServer.sendContactMessage( - conversation.userId!, - conversation.name, - result.first.encryptCategory!, - conversationId: conversationId, - recipientId: result.first.userId, - )); + await runFutureWithToast(accountServer.sendContactMessage( + conversation.userId!, + conversation.name, + result.first.encryptCategory!, + conversationId: conversationId, + recipientId: result.first.userId, + )); }, ), ), @@ -222,7 +220,6 @@ class ChatInfoPage extends HookWidget { if (result == null) return; await runFutureWithToast( - context, context.accountServer.editGroup( conversationId, announcement: result, @@ -256,7 +253,6 @@ class ChatInfoPage extends HookWidget { onTap: () async { if (muting) { await runFutureWithToast( - context, context.accountServer.unMuteConversation( conversationId: isGroupConversation ? conversationId : null, @@ -273,15 +269,13 @@ class ChatInfoPage extends HookWidget { if (result == null) return; await runFutureWithToast( - context, context.accountServer.muteConversation( - result, - conversationId: - isGroupConversation ? conversationId : null, - userId: isGroupConversation - ? null - : conversation.userId, - )); + result, + conversationId: + isGroupConversation ? conversationId : null, + userId: + isGroupConversation ? null : conversation.userId, + )); }, ), if (!isGroupConversation || @@ -302,7 +296,6 @@ class ChatInfoPage extends HookWidget { if (name?.isEmpty ?? true) return; await runFutureWithToast( - context, isGroupConversation ? accountServer.editGroup( conversation.conversationId, @@ -359,7 +352,6 @@ class ChatInfoPage extends HookWidget { if (!result) return; await runFutureWithToast( - context, accountServer.unblockUser(conversation.userId!), ); }, @@ -381,7 +373,6 @@ class ChatInfoPage extends HookWidget { if (!result) return; await runFutureWithToast( - context, accountServer.removeUser(conversation.userId!), ); }, @@ -400,7 +391,6 @@ class ChatInfoPage extends HookWidget { if (!result) return; await runFutureWithToast( - context, accountServer.blockUser(conversation.userId!), ); }, @@ -435,7 +425,6 @@ class ChatInfoPage extends HookWidget { if (!result) return; await runFutureWithToast( - context, accountServer.exitGroup(conversationId), ); @@ -491,7 +480,6 @@ class ChatInfoPage extends HookWidget { if (userId == null) return; await runFutureWithToast( - context, accountServer.report(userId), ); }, @@ -581,12 +569,10 @@ class _AddToContactsButton extends StatelessWidget { 'ContactsAdd: username should not be null.'); assert(conversation.isGroup != true, 'ContactsAdd conversation should not be a group.'); - runFutureWithToast( - context, - context.accountServer.addUser( - conversation.userId!, - username, - )); + runFutureWithToast(context.accountServer.addUser( + conversation.userId!, + username, + )); }, child: Text( conversation.isBot! diff --git a/lib/ui/home/chat_slide_page/circle_manager_page.dart b/lib/ui/home/chat_slide_page/circle_manager_page.dart index 678d93e010..b8e5c280a1 100644 --- a/lib/ui/home/chat_slide_page/circle_manager_page.dart +++ b/lib/ui/home/chat_slide_page/circle_manager_page.dart @@ -67,7 +67,6 @@ class CircleManagerPage extends HookWidget { ); await runFutureWithToast( - context, context.accountServer.createCircle(name!, [ CircleConversationRequest( action: CircleConversationAction.add, @@ -138,7 +137,6 @@ class _CircleManagerItem extends StatelessWidget { if (selected) { await runFutureWithToast( - context, context.accountServer.circleRemoveConversation( circleId, conversation!.conversationId), ); @@ -146,7 +144,6 @@ class _CircleManagerItem extends StatelessWidget { } await runFutureWithToast( - context, context.accountServer.editCircleConversation( circleId, [ diff --git a/lib/ui/home/chat_slide_page/disappear_message_page.dart b/lib/ui/home/chat_slide_page/disappear_message_page.dart index b187aeed17..4b5fef57ef 100644 --- a/lib/ui/home/chat_slide_page/disappear_message_page.dart +++ b/lib/ui/home/chat_slide_page/disappear_message_page.dart @@ -204,7 +204,7 @@ Future _updateConversationExpireDuration( ); } catch (error, stackTrace) { e('update conversation expire duration failed $error $stackTrace'); - await showToastFailed(context, error); + showToastFailed(error); } } @@ -330,8 +330,7 @@ class _CustomExpireTimeDialog extends HookWidget { return; } if (value > unit.value.maxValue) { - await showToastFailed( - context, + showToastFailed( ToastError(context.l10n.disappearingCustomTimeMaxWarning( unit.value .toDuration(unit.value.maxValue) @@ -340,7 +339,7 @@ class _CustomExpireTimeDialog extends HookWidget { ); return; } - showToastLoading(context); + showToastLoading(); await _updateConversationExpireDuration(context, duration: duration, conversationId: conversationId); Toast.dismiss(); diff --git a/lib/ui/home/chat_slide_page/group_invite/group_invite_dialog.dart b/lib/ui/home/chat_slide_page/group_invite/group_invite_dialog.dart index ca75cea0ce..7db68ea14c 100644 --- a/lib/ui/home/chat_slide_page/group_invite/group_invite_dialog.dart +++ b/lib/ui/home/chat_slide_page/group_invite/group_invite_dialog.dart @@ -157,14 +157,12 @@ class _ActionButtons extends StatelessWidget { onlyContact: false, ); if (result == null || result.isEmpty) return; - await runFutureWithToast( - context, - context.accountServer.sendTextMessage( - conversation.codeUrl!, - result.first.encryptCategory!, - conversationId: result.first.conversationId, - recipientId: result.first.userId, - )); + await runFutureWithToast(context.accountServer.sendTextMessage( + conversation.codeUrl!, + result.first.encryptCategory!, + conversationId: result.first.conversationId, + recipientId: result.first.userId, + )); }, ), _IconButton( @@ -173,14 +171,14 @@ class _ActionButtons extends StatelessWidget { onTap: () async { await Clipboard.setData( ClipboardData(text: conversation.codeUrl)); - showToastSuccessful(context); + showToastSuccessful(); }, ), _IconButton( label: context.l10n.resetLink, iconAssetName: Resources.assetsImagesInviteRefreshSvg, onTap: () { - runFutureWithToast(context, + runFutureWithToast( context.accountServer.rotate(conversation.conversationId)); }, ), diff --git a/lib/ui/home/chat_slide_page/group_participants_page.dart b/lib/ui/home/chat_slide_page/group_participants_page.dart index 060b894be3..08668a4bec 100644 --- a/lib/ui/home/chat_slide_page/group_participants_page.dart +++ b/lib/ui/home/chat_slide_page/group_participants_page.dart @@ -222,7 +222,6 @@ class _ParticipantMenuEntry extends StatelessWidget { icon: Resources.assetsImagesContextMenuUserEditSvg, title: context.l10n.makeGroupAdmin, onTap: () => runFutureWithToast( - context, context.accountServer.updateParticipantRole( context.read().state!.conversationId, participant.userId, @@ -233,9 +232,8 @@ class _ParticipantMenuEntry extends StatelessWidget { menus.add(ContextMenu( icon: Resources.assetsImagesContextMenuStopSvg, title: context.l10n.dismissAsAdmin, - onTap: () => runFutureWithToast( - context, - context.accountServer.updateParticipantRole( + onTap: () => runFutureWithToast(context.accountServer + .updateParticipantRole( context.read().state!.conversationId, participant.userId, null)), @@ -249,9 +247,8 @@ class _ParticipantMenuEntry extends StatelessWidget { icon: Resources.assetsImagesContextMenuDeleteSvg, isDestructiveAction: true, title: context.l10n.groupPopMenuRemove(participant.fullName ?? '?'), - onTap: () => runFutureWithToast( - context, - context.accountServer.removeParticipant( + onTap: () => runFutureWithToast(context.accountServer + .removeParticipant( context.read().state!.conversationId, participant.userId)), )); @@ -326,7 +323,6 @@ class _ActionAddParticipants extends StatelessWidget { context.read().state?.conversationId; assert(conversationId != null); await runFutureWithToast( - context, context.accountServer.addParticipant(conversationId!, userIds), ); }, diff --git a/lib/ui/home/conversation/menu_wrapper.dart b/lib/ui/home/conversation/menu_wrapper.dart index 6d72459487..bba196da72 100644 --- a/lib/ui/home/conversation/menu_wrapper.dart +++ b/lib/ui/home/conversation/menu_wrapper.dart @@ -47,7 +47,6 @@ class ConversationMenuWrapper extends StatelessWidget { icon: Resources.assetsImagesContextMenuUnpinSvg, title: context.l10n.unpin, onTap: () => runFutureWithToast( - context, context.accountServer.unpin(conversationId), ), ), @@ -56,7 +55,6 @@ class ConversationMenuWrapper extends StatelessWidget { icon: Resources.assetsImagesContextMenuPinSvg, title: context.l10n.pinTitle, onTap: () => runFutureWithToast( - context, context.accountServer.pin(conversationId), ), ), @@ -66,7 +64,6 @@ class ConversationMenuWrapper extends StatelessWidget { title: context.l10n.unmute, onTap: () async { await runFutureWithToast( - context, context.accountServer.unMuteConversation( conversationId: isGroupConversation ? conversationId : null, userId: isGroupConversation ? null : ownerId, @@ -84,7 +81,6 @@ class ConversationMenuWrapper extends StatelessWidget { context: context, child: const MuteDialog()); if (result == null) return; await runFutureWithToast( - context, context.accountServer.muteConversation( result, conversationId: isGroupConversation ? conversationId : null, @@ -110,7 +106,6 @@ class ConversationMenuWrapper extends StatelessWidget { title: e.name, onTap: () async { await runFutureWithToast( - context, () async { await context.accountServer .editCircleConversation( @@ -171,7 +166,6 @@ class ConversationMenuWrapper extends StatelessWidget { isDestructiveAction: true, onTap: () async { await runFutureWithToast( - context, context.accountServer.editCircleConversation( circleId!, [ diff --git a/lib/ui/home/conversation/search_list.dart b/lib/ui/home/conversation/search_list.dart index 95474cba0e..d191f27e0a 100644 --- a/lib/ui/home/conversation/search_list.dart +++ b/lib/ui/home/conversation/search_list.dart @@ -175,7 +175,7 @@ class SearchList extends HookWidget { keyword: keyword, maxLines: true, onTap: () async { - showToastLoading(context); + showToastLoading(); String? userId; @@ -187,8 +187,7 @@ class SearchList extends HookWidget { .insertSdkUser(mixinResponse.data); userId = mixinResponse.data.userId; } catch (error) { - await showToastFailed( - context, ToastError(context.l10n.userNotFound)); + showToastFailed(ToastError(context.l10n.userNotFound)); } Toast.dismiss(); diff --git a/lib/ui/home/home.dart b/lib/ui/home/home.dart index d1d8ebf470..904e7f05f2 100644 --- a/lib/ui/home/home.dart +++ b/lib/ui/home/home.dart @@ -140,23 +140,22 @@ class _SetupNameWidget extends HookWidget { MixinButton( disable: textEditingValue.text.trim().isEmpty, onTap: () async { - showToastLoading(context); + showToastLoading(); try { await context.accountServer.updateAccount( fullName: textEditingController.text.trim(), ); } on MixinApiError catch (error) { final mixinError = error.error as MixinError; - await showToastFailed( - context, + showToastFailed( ToastError(mixinError.toDisplayString(context)), ); return; } catch (error) { - await showToastFailed(context, null); + showToastFailed(null); return; } - showToastSuccessful(context); + showToastSuccessful(); }, child: Text(context.l10n.confirm), ), diff --git a/lib/ui/home/slide_page.dart b/lib/ui/home/slide_page.dart index 79f5f82ebc..f7afabe633 100644 --- a/lib/ui/home/slide_page.dart +++ b/lib/ui/home/slide_page.dart @@ -269,7 +269,6 @@ class _CircleList extends HookWidget { if (name?.isEmpty ?? true) return; await runFutureWithToast( - context, context.accountServer .updateCircle(circle.circleId, name!), ); @@ -302,7 +301,6 @@ class _CircleList extends HookWidget { if (result == null || result.isEmpty) return; await runFutureWithToast( - context, () async { final add = result.where((element) => !initSelected @@ -346,7 +344,6 @@ class _CircleList extends HookWidget { context.l10n.deleteTheCircle(circle.name)); if (!result) return; await runFutureWithToast( - context, () async { await context.accountServer .deleteCircle(circle.circleId); diff --git a/lib/ui/landing/landing_mobile.dart b/lib/ui/landing/landing_mobile.dart index 86dc52bf27..e009e7721e 100644 --- a/lib/ui/landing/landing_mobile.dart +++ b/lib/ui/landing/landing_mobile.dart @@ -83,7 +83,7 @@ class _PhoneNumberInputScene extends StatelessWidget { return; } - showToastLoading(context); + showToastLoading(); try { final response = await _requestVerificationCode( phone: phoneNumber, @@ -121,14 +121,13 @@ class _PhoneNumberInputScene extends StatelessWidget { } on MixinApiError catch (error) { e('Error requesting verification code: $error'); final mixinError = error.error as MixinError; - await showToastFailed( - context, + showToastFailed( ToastError(mixinError.toDisplayString(context)), ); return; } catch (error) { e('Error requesting verification code: $error'); - await showToastFailed(context, null); + showToastFailed(null); return; } }), @@ -158,7 +157,7 @@ class _CodeInputScene extends HookWidget { Future performLogin(String code) async { assert(code.length == 4, 'Invalid code length: $code'); - showToastLoading(context); + showToastLoading(); try { final registrationId = await SignalProtocol.initSignal(null); @@ -203,12 +202,11 @@ class _CodeInputScene extends HookWidget { e('login account error: $error'); if (error is MixinApiError) { final mixinError = error.error as MixinError; - await showToastFailed( - context, + showToastFailed( ToastError(mixinError.toDisplayString(context)), ); } else { - await showToastFailed(context, null); + showToastFailed(null); } return; } @@ -276,7 +274,7 @@ class _CodeInputScene extends HookWidget { const SizedBox(height: 0), ResendCodeWidget( onResend: () async { - showToastLoading(context); + showToastLoading(); try { final response = await _requestVerificationCode( phone: phoneNumber, @@ -288,14 +286,13 @@ class _CodeInputScene extends HookWidget { } on MixinApiError catch (error) { e('Error requesting verification code: $error'); final mixinError = error.error as MixinError; - await showToastFailed( - context, + showToastFailed( ToastError(mixinError.toDisplayString(context)), ); return false; } catch (error) { e('Error requesting verification code: $error'); - await showToastFailed(context, null); + showToastFailed(null); return false; } }, diff --git a/lib/ui/setting/account_delete_page.dart b/lib/ui/setting/account_delete_page.dart index 2288d0b785..2c90847e42 100644 --- a/lib/ui/setting/account_delete_page.dart +++ b/lib/ui/setting/account_delete_page.dart @@ -46,8 +46,7 @@ class AccountDeletePage extends StatelessWidget { color: context.theme.red, onTap: () async { if (!SessionKeyValue.instance.checkPinToken()) { - await showToastFailed( - context, + showToastFailed( ToastError(context.l10n.errorNoPinToken), ); return; @@ -77,7 +76,7 @@ class AccountDeletePage extends StatelessWidget { if (!confirmed) { return; } - showToastLoading(context); + showToastLoading(); VerificationResponse? verificationResponse; try { @@ -89,7 +88,7 @@ class AccountDeletePage extends StatelessWidget { Toast.dismiss(); } catch (error, stacktrace) { e('_requestVerificationCode $error, $stacktrace'); - await showToastFailed(context, error); + showToastFailed(error); return; } final verificationId = await showVerificationDialog( diff --git a/lib/ui/setting/edit_profile_page.dart b/lib/ui/setting/edit_profile_page.dart index dcd742bfad..0f4ee45fe0 100644 --- a/lib/ui/setting/edit_profile_page.dart +++ b/lib/ui/setting/edit_profile_page.dart @@ -43,7 +43,6 @@ class EditProfilePage extends HookWidget { MixinButton( onTap: () { runFutureWithToast( - context, context.accountServer.updateAccount( fullName: nameTextEditingController.text.trim(), biography: bioTextEditingController.text.trim(), diff --git a/lib/ui/setting/setting_page.dart b/lib/ui/setting/setting_page.dart index 221daffc9e..dadc353224 100644 --- a/lib/ui/setting/setting_page.dart +++ b/lib/ui/setting/setting_page.dart @@ -130,7 +130,6 @@ class SettingPage extends HookWidget { title: context.l10n.signOut, onTap: () async { final succeed = await runFutureWithToast( - context, context.accountServer.signOutAndClear(), ); if (!succeed) return; diff --git a/lib/ui/setting/storage_usage_detail_page.dart b/lib/ui/setting/storage_usage_detail_page.dart index e39a5f3b85..83398e7619 100644 --- a/lib/ui/setting/storage_usage_detail_page.dart +++ b/lib/ui/setting/storage_usage_detail_page.dart @@ -74,7 +74,6 @@ class StorageUsageDetailPage extends HookWidget { child: MixinButton( backgroundTransparent: true, onTap: () => runFutureWithToast( - context, () async { final accountServer = context.accountServer; if (selected.value.item1) { diff --git a/lib/utils/uri_utils.dart b/lib/utils/uri_utils.dart index 6f93e1e3a0..d7b719dc75 100644 --- a/lib/utils/uri_utils.dart +++ b/lib/utils/uri_utils.dart @@ -82,8 +82,7 @@ Future openUri( var homeUri = Uri.tryParse(app?.homeUri ?? ''); if (app == null || homeUri == null) { - await showToastFailed( - context, + showToastFailed( ToastError( context.l10n.botNotFound, ), @@ -117,7 +116,7 @@ Future openUri( } Future _showCodeDialog(BuildContext context, String code, Uri uri) async { - showToastLoading(context); + showToastLoading(); try { final mixinResponse = await context.accountServer.client.accountApi.code(code); @@ -135,7 +134,7 @@ Future _showCodeDialog(BuildContext context, String code, Uri uri) async { return false; } catch (error) { e('open code: $error'); - await showToastFailed(context, error); + showToastFailed(error); return false; } } @@ -143,7 +142,7 @@ Future _showCodeDialog(BuildContext context, String code, Uri uri) async { Future _showTransferDialog( BuildContext context, String snapshotTraceId) async { try { - showToastLoading(context); + showToastLoading(); final snapshotId = await context.database.snapshotDao .snapshotIdByTraceId(snapshotTraceId) @@ -163,7 +162,7 @@ Future _showTransferDialog( return true; } catch (error) { e('get snapshot by traceId: $error'); - await showToastFailed(context, error); + showToastFailed(error); return false; } } @@ -172,13 +171,13 @@ Future _selectConversation( Uri uri, BuildContext context, String conversationId) async { final userId = uri.queryParameters['user']; if (userId != null && userId.trim().isNotEmpty) { - showToastLoading(context); + showToastLoading(); await context.accountServer.refreshUsers([userId]); Toast.dismiss(); if (conversationId != generateConversationId(context.accountServer.userId, userId)) { - await showToastFailed(context, null); + showToastFailed(null); return false; } else { await ConversationCubit.selectUser(context, userId); diff --git a/lib/utils/web_view/web_view_mobile.dart b/lib/utils/web_view/web_view_mobile.dart index 1554b98645..76f1c0c5b3 100644 --- a/lib/utils/web_view/web_view_mobile.dart +++ b/lib/utils/web_view/web_view_mobile.dart @@ -256,8 +256,7 @@ class _ShareMenuItem extends StatelessWidget { onTap: () async { // can not share app if (appCardData?.shareable == false) { - await showToastFailed( - context, + showToastFailed( ToastError(context.l10n.appCardShareDisallow), ); } else { diff --git a/lib/widgets/actions/create_circle_action.dart b/lib/widgets/actions/create_circle_action.dart index 651d24cc9d..9210949d14 100644 --- a/lib/widgets/actions/create_circle_action.dart +++ b/lib/widgets/actions/create_circle_action.dart @@ -35,7 +35,6 @@ class CreateCircleAction extends Action { if (list == null) return; await runFutureWithToast( - context, context.accountServer.createCircle( name!, list diff --git a/lib/widgets/actions/create_group_conversation_action.dart b/lib/widgets/actions/create_group_conversation_action.dart index a3d70bee06..8b208f0d0d 100644 --- a/lib/widgets/actions/create_group_conversation_action.dart +++ b/lib/widgets/actions/create_group_conversation_action.dart @@ -42,7 +42,6 @@ class CreateGroupConversationAction if (name?.isEmpty ?? true) return; await runFutureWithToast( - context, context.accountServer.createGroupConversation(name!, userIds), ); } diff --git a/lib/widgets/conversation/conversation_dialog.dart b/lib/widgets/conversation/conversation_dialog.dart index 5a59033912..e9f7939c30 100644 --- a/lib/widgets/conversation/conversation_dialog.dart +++ b/lib/widgets/conversation/conversation_dialog.dart @@ -24,7 +24,7 @@ Future showConversationDialog(BuildContext context, final existed = conversationResponse.participants .any((element) => element.userId == context.multiAuthState.currentUserId); if (existed) { - await showToast(context, context.l10n.groupAlreadyIn); + showToast(context.l10n.groupAlreadyIn); await ConversationCubit.selectConversation( context, conversationResponse.conversationId, @@ -132,7 +132,6 @@ class _ConversationInfo extends HookWidget { const SizedBox(height: 8), DialogAddOrJoinButton( onTap: () => runFutureWithToast( - context, () async { await context.accountServer.joinGroup(code); await ConversationCubit.selectConversation( diff --git a/lib/widgets/message/item/file_message.dart b/lib/widgets/message/item/file_message.dart index a4d9e80211..1e9ad31b2a 100644 --- a/lib/widgets/message/item/file_message.dart +++ b/lib/widgets/message/item/file_message.dart @@ -85,7 +85,7 @@ class MessageFile extends HookWidget { final openResult = await OpenFile.open(path); if (openResult.type != ResultType.done) { i('open file result: $mediaName ${openResult.type} ${openResult.message}'); - await showToastFailed(context, + showToastFailed( ToastError(context.l10n.unableToOpenFile(mediaName))); } } else { diff --git a/lib/widgets/message/item/image/image_preview_page.dart b/lib/widgets/message/item/image/image_preview_page.dart index 70feec04f6..f5571747eb 100644 --- a/lib/widgets/message/item/image/image_preview_page.dart +++ b/lib/widgets/message/item/image/image_preview_page.dart @@ -580,15 +580,15 @@ class _Item extends HookWidget { Future _copyUrl(BuildContext context, String? filePath) async { if (filePath?.isEmpty ?? true) { - return showToastFailed(context, null); + return showToastFailed(null); } try { await Pasteboard.writeFiles([filePath!]); } catch (error) { - await showToastFailed(context, error); + showToastFailed(error); return; } - showToastSuccessful(context); + showToastSuccessful(); } class _CopyIntent extends Intent { diff --git a/lib/widgets/message/item/stranger_message.dart b/lib/widgets/message/item/stranger_message.dart index 6bea456943..3713c73c23 100644 --- a/lib/widgets/message/item/stranger_message.dart +++ b/lib/widgets/message/item/stranger_message.dart @@ -45,7 +45,6 @@ class StrangerMessage extends StatelessWidget { conversationId: message.conversationId); } else { await runFutureWithToast( - context, context.accountServer.blockUser(message.userId), ); } diff --git a/lib/widgets/message/message.dart b/lib/widgets/message/message.dart index 5265a823d0..320f9ffff5 100644 --- a/lib/widgets/message/message.dart +++ b/lib/widgets/message/message.dart @@ -493,7 +493,7 @@ class MessageItemWidget extends HookWidget { } Future _onAddSticker(BuildContext context) async { - showToastLoading(context); + showToastLoading(); try { final accountServer = context.accountServer; @@ -519,9 +519,9 @@ class MessageItemWidget extends HookWidget { )); }); } - showToastSuccessful(context); + showToastSuccessful(); } catch (_) { - await showToastFailed(context, ToastError(context.l10n.addStickerFailed)); + showToastFailed(ToastError(context.l10n.addStickerFailed)); } } } @@ -587,9 +587,9 @@ Future saveAs(BuildContext context, AccountServer accountServer, ? await GallerySaver.saveImage(path) : await GallerySaver.saveVideo(path); if (result != true) { - return showToastFailed(context, null); + return showToastFailed(null); } else { - showToastSuccessful(context); + showToastSuccessful(); return; } } else { @@ -602,9 +602,9 @@ Future saveAs(BuildContext context, AccountServer accountServer, path, suggestName: message.mediaName, ); - if (result) return showToastSuccessful(context); + if (result) return showToastSuccessful(); } catch (error) { - return showToastFailed(context, error); + return showToastFailed(error); } } } diff --git a/lib/widgets/message/message_bubble.dart b/lib/widgets/message/message_bubble.dart index 585bf1aae7..9f5ebea2d1 100644 --- a/lib/widgets/message/message_bubble.dart +++ b/lib/widgets/message/message_bubble.dart @@ -181,13 +181,8 @@ class MessageBubble extends HookWidget { .getMessageExpireAt([message.messageId]); final time = (expireAt[message.messageId] ?? 0) - DateTime.now().millisecondsSinceEpoch ~/ 1000; - await Toast.createView( - context: context, - child: ToastWidget( - barrierColor: Colors.transparent, - text: 'expire in: ${message.expireIn}. ' - 'will delete after: ${time < 0 ? 0 : time} seconds'), - ); + showToast('expire in: ${message.expireIn}. ' + 'will delete after: ${time < 0 ? 0 : time} seconds'); }, ); } diff --git a/lib/widgets/message/send_message_dialog/send_message_dialog.dart b/lib/widgets/message/send_message_dialog/send_message_dialog.dart index 8f13569568..35d0fdc637 100644 --- a/lib/widgets/message/send_message_dialog/send_message_dialog.dart +++ b/lib/widgets/message/send_message_dialog/send_message_dialog.dart @@ -267,7 +267,6 @@ Future _sendMessage(BuildContext context, String conversationId, if (category == _Category.image) { final sendImageData = data as SendImageData; await runWithLoading( - context, () => context.accountServer.sendImageMessageByUrl( encryptCategory, sendImageData.url, diff --git a/lib/widgets/search_bar.dart b/lib/widgets/search_bar.dart index f8f8cfcff8..a553ede6a6 100644 --- a/lib/widgets/search_bar.dart +++ b/lib/widgets/search_bar.dart @@ -166,8 +166,7 @@ class _SearchUserDialog extends HookWidget { await context.database.userDao.insertSdkUser(mixinResponse.data); resultUserId.value = mixinResponse.data.userId; } catch (e) { - unawaited( - showToastFailed(context, ToastError(context.l10n.userNotFound))); + showToastFailed(ToastError(context.l10n.userNotFound)); } loading.value = false; diff --git a/lib/widgets/toast.dart b/lib/widgets/toast.dart index 8bd00d3b63..6f057c6613 100644 --- a/lib/widgets/toast.dart +++ b/lib/widgets/toast.dart @@ -2,6 +2,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:mixin_bot_sdk_dart/mixin_bot_sdk_dart.dart'; +import 'package:overlay_support/overlay_support.dart'; + import '../constants/resources.dart'; import '../utils/extension/extension.dart'; import '../utils/logger.dart'; @@ -16,34 +18,26 @@ class Toast { static const shortDuration = Duration(seconds: 1); static const longDuration = Duration(seconds: 2); - static OverlayState? overlayState; - static OverlayEntry? _overlayEntry; - static bool _isVisible = false; + static OverlaySupportEntry? _lastLoadingEntry; - static Future createView({ - required BuildContext context, - required Widget child, + static void createView({ + required WidgetBuilder builder, Duration? duration = Toast.shortDuration, - }) async { - dismiss(); - _isVisible = true; - - overlayState = Overlay.of(context, rootOverlay: true); - - _overlayEntry = OverlayEntry(builder: (BuildContext context) => child); - overlayState!.insert(_overlayEntry!); - - if (duration == null) return; - await Future.delayed(duration); + }) { dismiss(); + showOverlay( + (context, progress) => Opacity( + opacity: progress, + child: builder(context), + ), + duration: duration ?? Duration.zero, + key: const ValueKey('toast'), + ); } static void dismiss() { - if (!_isVisible) { - return; - } - _isVisible = false; - _overlayEntry?.remove(); + _lastLoadingEntry?.dismiss(); + _lastLoadingEntry = null; } } @@ -100,9 +94,8 @@ class ToastWidget extends StatelessWidget { ); } -void showToastSuccessful(BuildContext context) => Toast.createView( - context: context, - child: ToastWidget( +void showToastSuccessful() => Toast.createView( + builder: (context) => ToastWidget( barrierColor: Colors.transparent, icon: const _Successful(), text: context.l10n.successful, @@ -118,37 +111,33 @@ class ToastError extends Error { static ToastError? fromError(Object? error) => null; } -Future showToastFailed(BuildContext context, Object? error) { - String? message; - if (error is ToastError) { - message = error.message; - } else if (error is MixinApiError) { - message = (error.error as MixinError).toDisplayString(context); - } else { - message = ToastError.fromError(error)?.message; - } - return Toast.createView( - context: context, - child: ToastWidget( - barrierColor: Colors.transparent, - icon: const _Failed(), - text: message ?? context.l10n.failed, - ), - ); -} +void showToastFailed(Object? error) => Toast.createView( + builder: (context) { + String? message; + if (error is ToastError) { + message = error.message; + } else if (error is MixinApiError) { + message = (error.error as MixinError).toDisplayString(context); + } else { + message = ToastError.fromError(error)?.message; + } + return ToastWidget( + barrierColor: Colors.transparent, + icon: const _Failed(), + text: message ?? context.l10n.failed, + ); + }, + ); -Future showToast(BuildContext context, String message) => - Toast.createView( - context: context, - child: ToastWidget( +void showToast(String message) => Toast.createView( + builder: (context) => ToastWidget( barrierColor: Colors.transparent, text: message, ), ); -void showToastLoading(BuildContext context) => Toast.createView( - context: context, - child: ToastWidget( +void showToastLoading() => Toast.createView( + builder: (context) => ToastWidget( icon: const _Loading(), text: context.l10n.loading, ), @@ -181,31 +170,27 @@ class _Successful extends StatelessWidget { SvgPicture.asset(Resources.assetsImagesSuccessfulSvg); } -Future runFutureWithToast( - BuildContext context, - Future future, -) async { - showToastLoading(context); +Future runFutureWithToast(Future future) async { + showToastLoading(); try { await future; } catch (error, s) { e("runFutureWithToast's error: $error, $s"); - await showToastFailed(context, error); + showToastFailed(error); return false; } - showToastSuccessful(context); + showToastSuccessful(); return true; } -Future runWithLoading( - BuildContext context, Future Function() function) async { - showToastLoading(context); +Future runWithLoading(Future Function() function) async { + showToastLoading(); try { await function(); Toast.dismiss(); } catch (error, s) { e("runWithLoading's error: $error, $s"); - await showToastFailed(context, error); + showToastFailed(error); } } diff --git a/lib/widgets/user/captcha_web_view_dialog.dart b/lib/widgets/user/captcha_web_view_dialog.dart index 4b6a8e64e7..22a0fc8a86 100644 --- a/lib/widgets/user/captcha_web_view_dialog.dart +++ b/lib/widgets/user/captcha_web_view_dialog.dart @@ -48,7 +48,6 @@ class CaptchaWebViewDialog extends HookWidget { } else { controllerRef.value!.loadUrl('about:blank'); showToastFailed( - context, ToastError(context.l10n.recaptchaTimeout), ); Navigator.pop(context); diff --git a/lib/widgets/user/change_number_dialog.dart b/lib/widgets/user/change_number_dialog.dart index c62f02ba54..e9c5ca0272 100644 --- a/lib/widgets/user/change_number_dialog.dart +++ b/lib/widgets/user/change_number_dialog.dart @@ -27,7 +27,7 @@ Future showChangeNumberDialog(BuildContext context) async { VerificationResponse? response; try { - showToastLoading(context); + showToastLoading(); response = await requestVerificationCode( phone: phoneNumber, context: context, @@ -36,7 +36,7 @@ Future showChangeNumberDialog(BuildContext context) async { Toast.dismiss(); } catch (error, stacktrace) { e('showChangeNumberDialog: $error $stacktrace'); - await showToastFailed(context, error); + showToastFailed(error); return; } @@ -72,7 +72,7 @@ Future showChangeNumberDialog(BuildContext context) async { return; } context.multiAuthCubit.updateAccount(account); - showToastSuccessful(context); + showToastSuccessful(); } Future _showPhoneNumberInputDialog(BuildContext context) => diff --git a/lib/widgets/user/pin_verification_dialog.dart b/lib/widgets/user/pin_verification_dialog.dart index c593de7132..dca7cdf88b 100644 --- a/lib/widgets/user/pin_verification_dialog.dart +++ b/lib/widgets/user/pin_verification_dialog.dart @@ -119,12 +119,12 @@ class _PinInputLayoutState extends State } _isVerifying = true; _closeInputConnection(); - showToastLoading(context); + showToastLoading(); try { await widget.doVerify(code); Toast.dismiss(); } catch (error, stacktrace) { - await showToastFailed(context, error); + showToastFailed(error); e('_verifyPinCode: $error $stacktrace'); _openInputConnection(); } finally { diff --git a/lib/widgets/user/user_dialog.dart b/lib/widgets/user/user_dialog.dart index c4b28ab518..2feec9c708 100644 --- a/lib/widgets/user/user_dialog.dart +++ b/lib/widgets/user/user_dialog.dart @@ -31,7 +31,7 @@ Future showUserDialog(BuildContext context, String? userId, return; } - showToastLoading(context); + showToastLoading(); User? user; if (_userId != null) { @@ -46,8 +46,7 @@ Future showUserDialog(BuildContext context, String? userId, } if (user == null) { - await showToastFailed( - context, + showToastFailed( ToastError( context.l10n.userNotFound, ), @@ -256,7 +255,6 @@ class _AddToContactsButton extends StatelessWidget { onTap: () { assert(user.fullName != null, ' username should not be null.'); runFutureWithToast( - context, context.accountServer.addUser( user.userId, user.fullName, @@ -296,7 +294,6 @@ class _UserProfileButtonBar extends StatelessWidget { final conversationId = result.first.conversationId; await runFutureWithToast( - context, context.accountServer.sendContactMessage( user.userId, user.fullName, diff --git a/lib/widgets/user/verification_dialog.dart b/lib/widgets/user/verification_dialog.dart index fdfb65162c..2411970739 100644 --- a/lib/widgets/user/verification_dialog.dart +++ b/lib/widgets/user/verification_dialog.dart @@ -65,7 +65,7 @@ class _VerificationCodeDialog extends StatelessWidget { initialVerificationResponse: initialVerificationResponse, reRequestVerification: reRequestVerification, onVerification: (code, response) async { - showToastLoading(context); + showToastLoading(); try { final result = await onVerification(code, response); d('_VerificationCodeDialog: result: $result'); @@ -73,7 +73,7 @@ class _VerificationCodeDialog extends StatelessWidget { Toast.dismiss(); } catch (error, stacktrace) { e('_VerificationCodeDialog error: $error $stacktrace'); - await showToastFailed(context, error); + showToastFailed(error); } }, ), @@ -196,7 +196,7 @@ class VerificationCodeInputLayout extends HookWidget { const SizedBox(height: 0), ResendCodeWidget( onResend: () async { - showToastLoading(context); + showToastLoading(); try { final response = await reRequestVerification(); Toast.dismiss(); @@ -205,14 +205,13 @@ class VerificationCodeInputLayout extends HookWidget { } on MixinApiError catch (error) { e('Error requesting verification code: $error'); final mixinError = error.error as MixinError; - await showToastFailed( - context, + showToastFailed( ToastError(mixinError.toDisplayString(context)), ); return false; } catch (error) { e('Error requesting verification code: $error'); - await showToastFailed(context, null); + showToastFailed(null); return false; } }, diff --git a/pubspec.lock b/pubspec.lock index ad667b0ab2..ba55ba0c36 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -921,6 +921,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "6.1.0+1" + overlay_support: + dependency: "direct main" + description: + name: overlay_support + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" package_config: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 836f6490d9..dcb28399a1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -74,6 +74,7 @@ dependencies: git: url: https://github.com/crazecoder/open_file.git ref: fbf68e4bb5cb3e262d8f8ebe10b2f8449ff8e030 + overlay_support: ^2.0.1 package_info_plus: ^3.0.1 pasteboard: git: From e5cf33e4903bd4159006d65df0713234edecc334 Mon Sep 17 00:00:00 2001 From: boyan <17426470+boyan01@users.noreply.github.com> Date: Fri, 28 Oct 2022 16:56:21 +0800 Subject: [PATCH 2/5] fix home page rebuild --- lib/app.dart | 75 +++++++++++++++++++++++++-------------------------- lib/main.dart | 3 ++- 2 files changed, 38 insertions(+), 40 deletions(-) diff --git a/lib/app.dart b/lib/app.dart index 37f9f26ee7..883c28d8c4 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -4,7 +4,6 @@ import 'package:flutter/material.dart' hide AnimatedTheme; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; -import 'package:overlay_support/overlay_support.dart'; import 'package:provider/provider.dart'; import 'package:tuple/tuple.dart'; @@ -195,45 +194,43 @@ class _App extends StatelessWidget { @override Widget build(BuildContext context) => WindowShortcuts( child: GlobalMoveWindow( - child: OverlaySupport.global( - child: MaterialApp( - title: 'Mixin', - navigatorObservers: [rootRouteObserver], - debugShowCheckedModeBanner: false, - localizationsDelegates: const [ - Localization.delegate, - GlobalMaterialLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - ], - supportedLocales: [ - ...Localization.delegate.supportedLocales, - ], - theme: ThemeData().withFallbackFonts(), - builder: (context, child) { - try { - context.accountServer.language = - Localizations.localeOf(context).languageCode; - } catch (_) {} - final mediaQueryData = MediaQuery.of(context); - // Different linux distro change the value, e.g. 1.2 - const textScaleFactor = 1.0; - return BrightnessObserver( - lightThemeData: lightBrightnessThemeData, - darkThemeData: darkBrightnessThemeData, - forceBrightness: context.watch().brightness, - child: MediaQuery( - data: mediaQueryData.copyWith( - textScaleFactor: Platform.isLinux - ? textScaleFactor - : mediaQueryData.textScaleFactor, - ), - child: SystemTrayWidget(child: child!), + child: MaterialApp( + title: 'Mixin', + navigatorObservers: [rootRouteObserver], + debugShowCheckedModeBanner: false, + localizationsDelegates: const [ + Localization.delegate, + GlobalMaterialLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + ], + supportedLocales: [ + ...Localization.delegate.supportedLocales, + ], + theme: ThemeData().withFallbackFonts(), + builder: (context, child) { + try { + context.accountServer.language = + Localizations.localeOf(context).languageCode; + } catch (_) {} + final mediaQueryData = MediaQuery.of(context); + // Different linux distro change the value, e.g. 1.2 + const textScaleFactor = 1.0; + return BrightnessObserver( + lightThemeData: lightBrightnessThemeData, + darkThemeData: darkBrightnessThemeData, + forceBrightness: context.watch().brightness, + child: MediaQuery( + data: mediaQueryData.copyWith( + textScaleFactor: Platform.isLinux + ? textScaleFactor + : mediaQueryData.textScaleFactor, ), - ); - }, - home: const _Home(), - ), + child: SystemTrayWidget(child: child!), + ), + ); + }, + home: const _Home(), ), ), ); diff --git a/lib/main.dart b/lib/main.dart index 0fd1780cdb..2eddcf7c90 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -9,6 +9,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:hydrated_bloc/hydrated_bloc.dart'; import 'package:isolate/isolate.dart'; +import 'package:overlay_support/overlay_support.dart'; import 'package:path/path.dart' as p; import 'package:protocol_handler/protocol_handler.dart'; import 'package:quick_breakpad/quick_breakpad.dart'; @@ -82,7 +83,7 @@ Future main(List args) async { }; HydratedBlocOverrides.runZoned( - () => runApp(const App()), + () => runApp(const OverlaySupport.global(child: App())), blocObserver: kDebugMode ? CustomBlocObserver() : null, storage: storage, ); From 8065dc7fcf6c46c2b1db7f8b6780ced505270c09 Mon Sep 17 00:00:00 2001 From: boyan <17426470+boyan01@users.noreply.github.com> Date: Fri, 28 Oct 2022 17:21:05 +0800 Subject: [PATCH 3/5] show toast error if failed to upload message attachment --- lib/generated/intl/messages_en.dart | 2 + lib/generated/intl/messages_zh.dart | 2 + lib/generated/l10n.dart | 10 +++++ lib/l10n/intl_en.arb | 1 + lib/l10n/intl_zh.arb | 1 + lib/utils/attachment/attachment_util.dart | 7 ++- lib/widgets/toast.dart | 53 ++++++++++++++--------- 7 files changed, 54 insertions(+), 22 deletions(-) diff --git a/lib/generated/intl/messages_en.dart b/lib/generated/intl/messages_en.dart index bbc5ea74da..a169aac2a3 100644 --- a/lib/generated/intl/messages_en.dart +++ b/lib/generated/intl/messages_en.dart @@ -391,6 +391,8 @@ class MessageLookup extends MessageLookupByLibrary { "Can\'t find an app able to open this media."), "errorUnknownWithCode": m21, "errorUnknownWithMessage": m22, + "errorUploadAttachmentFailed": MessageLookupByLibrary.simpleMessage( + "Failed to upload message attachment"), "errorUsedPhone": MessageLookupByLibrary.simpleMessage( "ERROR 20122: This phone number is already associated with another account."), "errorUserInvalidFormat": diff --git a/lib/generated/intl/messages_zh.dart b/lib/generated/intl/messages_zh.dart index 752740414f..f877346e3f 100644 --- a/lib/generated/intl/messages_zh.dart +++ b/lib/generated/intl/messages_zh.dart @@ -345,6 +345,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("无法找到能打开该媒体的应用"), "errorUnknownWithCode": m21, "errorUnknownWithMessage": m22, + "errorUploadAttachmentFailed": + MessageLookupByLibrary.simpleMessage("消息附件上传失败"), "errorUsedPhone": MessageLookupByLibrary.simpleMessage("错误 20122:电话号码已经被占用。"), "errorUserInvalidFormat": diff --git a/lib/generated/l10n.dart b/lib/generated/l10n.dart index 4fadafe9ac..eb741439f7 100644 --- a/lib/generated/l10n.dart +++ b/lib/generated/l10n.dart @@ -1728,6 +1728,16 @@ class Localization { ); } + /// `Failed to upload message attachment` + String get errorUploadAttachmentFailed { + return Intl.message( + 'Failed to upload message attachment', + name: 'errorUploadAttachmentFailed', + desc: '', + args: [], + ); + } + /// `ERROR 20122: This phone number is already associated with another account.` String get errorUsedPhone { return Intl.message( diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index bfc1f34c8c..7674037327 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -166,6 +166,7 @@ "errorUnableToOpenMedia" : "Can't find an app able to open this media.", "errorUnknownWithCode" : "ERROR: {arg0}", "errorUnknownWithMessage" : "ERROR: {arg0}", +"errorUploadAttachmentFailed" : "Failed to upload message attachment", "errorUsedPhone" : "ERROR 20122: This phone number is already associated with another account.", "errorUserInvalidFormat" : "Invalid user id", "errorWithdrawalMemoFormatIncorrect" : "ERROR 20131: Withdrawal memo format incorrect.", diff --git a/lib/l10n/intl_zh.arb b/lib/l10n/intl_zh.arb index 7ce3b04f9a..1464c90ff9 100644 --- a/lib/l10n/intl_zh.arb +++ b/lib/l10n/intl_zh.arb @@ -165,6 +165,7 @@ "errorUnableToOpenMedia" : "无法找到能打开该媒体的应用", "errorUnknownWithCode" : "错误:{arg0}", "errorUnknownWithMessage" : "错误:{arg0}", +"errorUploadAttachmentFailed" : "消息附件上传失败", "errorUsedPhone" : "错误 20122:电话号码已经被占用。", "errorUserInvalidFormat" : "用户数据不合法", "errorWithdrawalMemoFormatIncorrect" : "错误 20131:提现备注格式不正确", diff --git a/lib/utils/attachment/attachment_util.dart b/lib/utils/attachment/attachment_util.dart index a9e3b9e9b4..e1f3cb07c2 100644 --- a/lib/utils/attachment/attachment_util.dart +++ b/lib/utils/attachment/attachment_util.dart @@ -16,6 +16,7 @@ import '../../db/dao/transcript_message_dao.dart'; import '../../db/mixin_database.dart'; import '../../db/util/util.dart'; import '../../enum/media_status.dart'; +import '../../widgets/toast.dart'; import '../crypto_util.dart'; import '../extension/extension.dart'; import '../file.dart'; @@ -306,8 +307,10 @@ class AttachmentUtil extends ChangeNotifier { ? await base64EncodeWithIsolate(digest!) : null, response.data.createdAt); - } catch (e, s) { - w('upload failed error: $e, $s'); + } catch (error, s) { + w('upload failed error: $error, $s'); + showToastFailed(ToastError.builder( + (context) => context.l10n.errorUploadAttachmentFailed)); await _messageDao.updateMediaStatus(messageId, MediaStatus.canceled); return null; } finally { diff --git a/lib/widgets/toast.dart b/lib/widgets/toast.dart index 6f057c6613..eb1f1fb4b4 100644 --- a/lib/widgets/toast.dart +++ b/lib/widgets/toast.dart @@ -103,30 +103,43 @@ void showToastSuccessful() => Toast.createView( ); class ToastError extends Error { - ToastError(this.message); - - final String message; + factory ToastError(String message) => ToastError._internal(message: message); + + factory ToastError.builder(String Function(BuildContext context)? builder) => + ToastError._internal(messageBuilder: builder); + + ToastError._internal({this.message, this.messageBuilder}); + + static String errorToString(BuildContext context, Object? error) { + if (error is ToastError) { + if (error.message != null) { + return error.message!; + } else if (error.messageBuilder != null) { + return error.messageBuilder!(context); + } else { + return context.l10n.failed; + } + } else if (error is MixinApiError) { + return (error.error as MixinError).toDisplayString(context); + } else if (error is MixinError) { + return error.toDisplayString(context); + } else if (error is String) { + return error; + } else { + return error?.toString() ?? context.l10n.failed; + } + } - // ignore: avoid-unused-parameters - static ToastError? fromError(Object? error) => null; + final String? message; + final String Function(BuildContext)? messageBuilder; } void showToastFailed(Object? error) => Toast.createView( - builder: (context) { - String? message; - if (error is ToastError) { - message = error.message; - } else if (error is MixinApiError) { - message = (error.error as MixinError).toDisplayString(context); - } else { - message = ToastError.fromError(error)?.message; - } - return ToastWidget( - barrierColor: Colors.transparent, - icon: const _Failed(), - text: message ?? context.l10n.failed, - ); - }, + builder: (context) => ToastWidget( + barrierColor: Colors.transparent, + icon: const _Failed(), + text: ToastError.errorToString(context, error), + ), ); void showToast(String message) => Toast.createView( From 78fc44ec47e205df5d90cdedc5d05bf4683069b5 Mon Sep 17 00:00:00 2001 From: boyan <17426470+boyan01@users.noreply.github.com> Date: Fri, 28 Oct 2022 17:25:57 +0800 Subject: [PATCH 4/5] fix entry --- lib/widgets/toast.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/widgets/toast.dart b/lib/widgets/toast.dart index eb1f1fb4b4..5c98fc0e28 100644 --- a/lib/widgets/toast.dart +++ b/lib/widgets/toast.dart @@ -18,14 +18,14 @@ class Toast { static const shortDuration = Duration(seconds: 1); static const longDuration = Duration(seconds: 2); - static OverlaySupportEntry? _lastLoadingEntry; + static OverlaySupportEntry? _entry; static void createView({ required WidgetBuilder builder, Duration? duration = Toast.shortDuration, }) { dismiss(); - showOverlay( + _entry = showOverlay( (context, progress) => Opacity( opacity: progress, child: builder(context), @@ -36,8 +36,8 @@ class Toast { } static void dismiss() { - _lastLoadingEntry?.dismiss(); - _lastLoadingEntry = null; + _entry?.dismiss(); + _entry = null; } } From 91face28186e64ed8da54f116b94fbd1536dae52 Mon Sep 17 00:00:00 2001 From: boyan <17426470+boyan01@users.noreply.github.com> Date: Fri, 28 Oct 2022 17:30:21 +0800 Subject: [PATCH 5/5] fix analyze --- .../message/item/image/image_preview_page.dart | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/lib/widgets/message/item/image/image_preview_page.dart b/lib/widgets/message/item/image/image_preview_page.dart index f5571747eb..3f69d45f5f 100644 --- a/lib/widgets/message/item/image/image_preview_page.dart +++ b/lib/widgets/message/item/image/image_preview_page.dart @@ -200,10 +200,8 @@ class ImagePreviewPage extends HookWidget { }, actions: { _CopyIntent: CallbackAction( - onInvoke: (Intent intent) => _copyUrl( - context, - context.accountServer - .convertMessageAbsolutePath(current.value, isTranscriptPage)), + onInvoke: (Intent intent) => _copyUrl(context.accountServer + .convertMessageAbsolutePath(current.value, isTranscriptPage)), ), _PreviousImageIntent: CallbackAction( onInvoke: (intent) { @@ -402,10 +400,8 @@ class _Action extends StatelessWidget { ); } - Future copy() => _copyUrl( - context, - context.accountServer - .convertMessageAbsolutePath(message, isTranscriptPage)); + Future copy() => _copyUrl(context.accountServer + .convertMessageAbsolutePath(message, isTranscriptPage)); Future download() async { if (message.mediaUrl?.isEmpty ?? true) return; @@ -578,7 +574,7 @@ class _Item extends HookWidget { } } -Future _copyUrl(BuildContext context, String? filePath) async { +Future _copyUrl(String? filePath) async { if (filePath?.isEmpty ?? true) { return showToastFailed(null); }