diff --git a/lib/pods/userinfo.dart b/lib/pods/userinfo.dart index 2bdc8a45..beb4e7d5 100644 --- a/lib/pods/userinfo.dart +++ b/lib/pods/userinfo.dart @@ -5,7 +5,8 @@ import 'package:dio/dio.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:firebase_analytics/firebase_analytics.dart'; import 'package:flutter/foundation.dart'; -import 'package:flutter_platform_alert/flutter_platform_alert.dart'; +import 'package:flutter/material.dart'; +import 'package:island/widgets/alert.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:island/models/account.dart'; @@ -36,41 +37,65 @@ class UserInfoNotifier extends StateNotifier> { } catch (error, stackTrace) { if (!kIsWeb) { if (error is DioException) { - FlutterPlatformAlert.showCustomAlert( - windowTitle: 'failedToLoadUserInfo'.tr(), - text: [ - (error.response?.statusCode == 401 - ? 'failedToLoadUserInfoUnauthorized' - : 'failedToLoadUserInfoNetwork') - .tr() - .trim(), - '', - '${error.response?.statusCode ?? 'Network Error'}', - if (error.response?.headers != null) error.response?.headers, - if (error.response?.data != null) - jsonEncode(error.response?.data), - ].join('\n'), - iconStyle: IconStyle.error, - neutralButtonTitle: 'retry'.tr(), - negativeButtonTitle: 'okay'.tr(), + showOverlayDialog( + builder: + (context, close) => AlertDialog( + title: Text('failedToLoadUserInfo'.tr()), + content: Text( + [ + (error.response?.statusCode == 401 + ? 'failedToLoadUserInfoUnauthorized' + : 'failedToLoadUserInfoNetwork') + .tr() + .trim(), + '', + '${error.response?.statusCode ?? 'Network Error'}', + if (error.response?.headers != null) + error.response?.headers, + if (error.response?.data != null) + jsonEncode(error.response?.data), + ].join('\n'), + ), + actions: [ + TextButton( + onPressed: () => close(false), + child: Text('okay'.tr()), + ), + TextButton( + onPressed: () => close(true), + child: Text('retry'.tr()), + ), + ], + ), ).then((value) { - if (value == CustomButton.neutralButton) { + if (value == true) { fetchUser(); } }); } - FlutterPlatformAlert.showCustomAlert( - windowTitle: 'failedToLoadUserInfo'.tr(), - text: - [ - 'failedToLoadUserInfoNetwork'.tr(), - error.toString(), - ].join('\n\n').trim(), - iconStyle: IconStyle.error, - neutralButtonTitle: 'retry'.tr(), - negativeButtonTitle: 'okay'.tr(), + showOverlayDialog( + builder: + (context, close) => AlertDialog( + title: Text('failedToLoadUserInfo'.tr()), + content: Text( + [ + 'failedToLoadUserInfoNetwork'.tr(), + error.toString(), + ].join('\n\n').trim(), + ), + actions: [ + TextButton( + onPressed: () => close(false), + child: Text('okay'.tr()), + ), + TextButton( + onPressed: () => close(true), + child: Text('retry'.tr()), + ), + ], + ), ).then((value) { - if (value == CustomButton.neutralButton) { + if (value == true) { fetchUser(); } }); diff --git a/lib/widgets/alert.dart b/lib/widgets/alert.dart index 757a53fe..57d47940 100644 --- a/lib/widgets/alert.dart +++ b/lib/widgets/alert.dart @@ -1,13 +1,14 @@ +import 'dart:async'; + +import 'package:dio/dio.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:gap/gap.dart'; import 'package:island/main.dart'; +import 'package:island/talker.dart'; import 'package:styled_widget/styled_widget.dart'; import 'package:top_snackbar_flutter/top_snack_bar.dart'; -export 'content/alert.native.dart' - if (dart.library.html) 'content/alert.web.dart'; - void showSnackBar(String message, {SnackBarAction? action}) { final context = globalOverlay.currentState!.context; final screenWidth = MediaQuery.of(context).size.width; @@ -56,6 +57,11 @@ class _FadeOverlayState extends State<_FadeOverlay> { }); } + Future animateOut() async { + setState(() => _visible = false); + await Future.delayed(const Duration(milliseconds: 200)); + } + @override Widget build(BuildContext context) { return AnimatedOpacity( @@ -106,10 +112,138 @@ void hideLoadingModal(BuildContext context) async { final state = entry.mounted ? _loadingOverlayKey.currentState : null; if (state != null) { - // ignore: invalid_use_of_protected_member - state.setState(() => state._visible = false); - await Future.delayed(const Duration(milliseconds: 200)); + await state.animateOut(); } entry.remove(); } + +String _parseRemoteError(DioException err) { + String? message; + if (err.response?.data is String) { + message = err.response?.data; + } else if (err.response?.data?['message'] != null) { + message = [ + err.response?.data?['message']?.toString(), + err.response?.data?['detail']?.toString(), + ].where((e) => e != null).cast().map((e) => e.trim()).join('\n'); + } else if (err.response?.data?['errors'] != null) { + final errors = err.response?.data['errors'] as Map; + message = errors.values + .map( + (ele) => + (ele as List).map((ele) => ele.toString()).join('\n'), + ) + .join('\n'); + } + if (message == null || message.isEmpty) message = err.response?.statusMessage; + message ??= err.message; + return message ?? err.toString(); +} + +Future showOverlayDialog({ + required Widget Function(BuildContext context, void Function(T? result) close) + builder, + bool barrierDismissible = true, +}) { + final completer = Completer(); + final key = GlobalKey<_FadeOverlayState>(); + late OverlayEntry entry; + + void close(T? result) async { + if (completer.isCompleted) return; + + final state = key.currentState; + if (state != null) { + await state.animateOut(); + } + + entry.remove(); + completer.complete(result); + } + + entry = OverlayEntry( + builder: + (context) => _FadeOverlay( + key: key, + child: Stack( + children: [ + Positioned.fill( + child: GestureDetector( + onTap: barrierDismissible ? () => close(null) : null, + behavior: HitTestBehavior.opaque, + child: const ColoredBox(color: Colors.black54), + ), + ), + Center(child: builder(context, close)), + ], + ), + ), + ); + + globalOverlay.currentState!.insert(entry); + return completer.future; +} + +void showErrorAlert(dynamic err) { + if (err is Error) { + talker.error('Something went wrong...', err, err.stackTrace); + } + final text = switch (err) { + String _ => err, + DioException _ => _parseRemoteError(err), + Exception _ => err.toString(), + _ => err.toString(), + }; + + showOverlayDialog( + builder: + (context, close) => AlertDialog( + title: Text('somethingWentWrong'.tr()), + content: Text(text), + actions: [ + TextButton( + onPressed: () => close(null), + child: Text(MaterialLocalizations.of(context).okButtonLabel), + ), + ], + ), + ); +} + +void showInfoAlert(String message, String title) { + showOverlayDialog( + builder: + (context, close) => AlertDialog( + title: Text(title), + content: Text(message), + actions: [ + TextButton( + onPressed: () => close(null), + child: Text(MaterialLocalizations.of(context).okButtonLabel), + ), + ], + ), + ); +} + +Future showConfirmAlert(String message, String title) async { + final result = await showOverlayDialog( + builder: + (context, close) => AlertDialog( + title: Text(title), + content: Text(message), + actions: [ + TextButton( + onPressed: () => close(false), + child: Text(MaterialLocalizations.of(context).cancelButtonLabel), + ), + TextButton( + onPressed: () => close(true), + child: Text(MaterialLocalizations.of(context).okButtonLabel), + ), + ], + ), + ); + return result ?? false; +} diff --git a/lib/widgets/content/alert.native.dart b/lib/widgets/content/alert.native.dart deleted file mode 100644 index fb536b9b..00000000 --- a/lib/widgets/content/alert.native.dart +++ /dev/null @@ -1,64 +0,0 @@ -import 'package:dio/dio.dart'; -import 'package:easy_localization/easy_localization.dart'; -import 'package:flutter_platform_alert/flutter_platform_alert.dart'; -import 'package:island/talker.dart'; - -String _parseRemoteError(DioException err) { - String? message; - if (err.response?.data is String) { - message = err.response?.data; - } else if (err.response?.data?['message'] != null) { - message = [ - err.response?.data?['message']?.toString(), - err.response?.data?['detail']?.toString(), - ].where((e) => e != null).cast().map((e) => e.trim()).join('\n'); - } else if (err.response?.data?['errors'] != null) { - final errors = err.response?.data['errors'] as Map; - message = errors.values - .map( - (ele) => - (ele as List).map((ele) => ele.toString()).join('\n'), - ) - .join('\n'); - } - if (message == null || message.isEmpty) message = err.response?.statusMessage; - message ??= err.message; - return message ?? err.toString(); -} - -void showErrorAlert(dynamic err) async { - if (err is Error) { - talker.error('Something went wrong...', err, err.stackTrace); - } - final text = switch (err) { - String _ => err, - DioException _ => _parseRemoteError(err), - Exception _ => err.toString(), - _ => err.toString(), - }; - FlutterPlatformAlert.showAlert( - windowTitle: 'somethingWentWrong'.tr(), - text: text, - alertStyle: AlertButtonStyle.ok, - iconStyle: IconStyle.error, - ); -} - -void showInfoAlert(String message, String title) async { - FlutterPlatformAlert.showAlert( - windowTitle: title, - text: message, - alertStyle: AlertButtonStyle.ok, - iconStyle: IconStyle.information, - ); -} - -Future showConfirmAlert(String message, String title) async { - final result = await FlutterPlatformAlert.showAlert( - windowTitle: title, - text: message, - alertStyle: AlertButtonStyle.okCancel, - iconStyle: IconStyle.question, - ); - return result == AlertButton.okButton; -} diff --git a/lib/widgets/content/alert.web.dart b/lib/widgets/content/alert.web.dart deleted file mode 100644 index 397e719f..00000000 --- a/lib/widgets/content/alert.web.dart +++ /dev/null @@ -1,53 +0,0 @@ -// ignore_for_file: avoid_web_libraries_in_flutter - -import 'dart:js' as js; - -import 'package:dio/dio.dart'; -import 'package:easy_localization/easy_localization.dart'; - -String _parseRemoteError(DioException err) { - String? message; - if (err.response?.data is String) { - message = err.response?.data; - } else if (err.response?.data?['message'] != null) { - message = [ - err.response?.data?['message']?.toString(), - err.response?.data?['detail']?.toString(), - ].where((e) => e != null).cast().map((e) => e.trim()).join('\n'); - } else if (err.response?.data?['errors'] != null) { - final errors = err.response?.data['errors'] as Map; - message = errors.values - .map( - (ele) => - (ele as List).map((ele) => ele.toString()).join('\n'), - ) - .join('\n'); - } - if (message == null || message.isEmpty) message = err.response?.statusMessage; - message ??= err.message; - return message ?? err.toString(); -} - -void showErrorAlert(dynamic err) async { - final text = switch (err) { - String _ => err, - DioException _ => _parseRemoteError(err), - Exception _ => err.toString(), - _ => err.toString(), - }; - js.context.callMethod('swal', ['somethingWentWrong'.tr(), text, 'error']); -} - -void showInfoAlert(String message, String title) async { - js.context.callMethod('swal', [title, message, 'info']); -} - -Future showConfirmAlert(String message, String title) async { - final result = await js.context.callMethod('swal', [ - title, - message, - 'question', - {'buttons': true}, - ]); - return result == true; -} diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index 9b02d871..c3ed320d 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -38,9 +37,6 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); file_selector_plugin_register_with_registrar(file_selector_linux_registrar); - g_autoptr(FlPluginRegistrar) flutter_platform_alert_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterPlatformAlertPlugin"); - flutter_platform_alert_plugin_register_with_registrar(flutter_platform_alert_registrar); g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin"); flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 6c94e197..02828327 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -6,7 +6,6 @@ list(APPEND FLUTTER_PLUGIN_LIST desktop_drop file_saver file_selector_linux - flutter_platform_alert flutter_secure_storage_linux flutter_timezone flutter_udid diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 82470806..a5164a11 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -17,7 +17,6 @@ import firebase_crashlytics import firebase_messaging import flutter_inappwebview_macos import flutter_local_notifications -import flutter_platform_alert import flutter_secure_storage_macos import flutter_timezone import flutter_udid @@ -59,7 +58,6 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin")) InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin")) FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin")) - FlutterPlatformAlertPlugin.register(with: registry.registrar(forPlugin: "FlutterPlatformAlertPlugin")) FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin")) FlutterTimezonePlugin.register(with: registry.registrar(forPlugin: "FlutterTimezonePlugin")) FlutterUdidPlugin.register(with: registry.registrar(forPlugin: "FlutterUdidPlugin")) diff --git a/pubspec.lock b/pubspec.lock index c453868e..d3c5c736 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1019,14 +1019,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.1+1" - flutter_platform_alert: - dependency: "direct main" - description: - name: flutter_platform_alert - sha256: "70f4979a617388cd890ec32e9acc1a6a425bcdf3d8b444eb976be1834e79dc0c" - url: "https://pub.dev" - source: hosted - version: "0.8.0" flutter_plugin_android_lifecycle: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 5ac2c3c5..0a39cbed 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -61,7 +61,7 @@ dependencies: media_kit_video: ^2.0.0 media_kit_libs_video: ^1.0.7 flutter_cache_manager: ^3.4.1 - flutter_platform_alert: ^0.8.0 + email_validator: ^3.0.0 easy_localization: ^3.0.8 flutter_inappwebview: ^6.1.5 diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index f807b086..ef809211 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -52,8 +51,6 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("FirebaseCorePluginCApi")); FlutterInappwebviewWindowsPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("FlutterInappwebviewWindowsPluginCApi")); - FlutterPlatformAlertPluginRegisterWithRegistrar( - registry->GetRegistrarForPlugin("FlutterPlatformAlertPlugin")); FlutterSecureStorageWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin")); FlutterTimezonePluginCApiRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 30676e7f..912dc878 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -10,7 +10,6 @@ list(APPEND FLUTTER_PLUGIN_LIST file_selector_windows firebase_core flutter_inappwebview_windows - flutter_platform_alert flutter_secure_storage_windows flutter_timezone flutter_udid