diff --git a/assets/images/ic_not_connection.svg b/assets/images/ic_not_connection.svg new file mode 100644 index 000000000..3b806bfe1 --- /dev/null +++ b/assets/images/ic_not_connection.svg @@ -0,0 +1,3 @@ + + + diff --git a/core/lib/presentation/resources/image_paths.dart b/core/lib/presentation/resources/image_paths.dart index 73ca23672..cd78ffc17 100644 --- a/core/lib/presentation/resources/image_paths.dart +++ b/core/lib/presentation/resources/image_paths.dart @@ -86,6 +86,7 @@ class ImagePaths { String get icClose => _getImagePath('ic_close.svg'); String get icSendToastError => _getImagePath('ic_send_toast_error.svg'); String get icEmpty => _getImagePath('ic_empty.svg'); + String get icNotConnection => _getImagePath('ic_not_connection.svg'); String _getImagePath(String imageName) { return AssetsPaths.images + imageName; diff --git a/lib/features/base/base_controller.dart b/lib/features/base/base_controller.dart index fd7b0ad5b..df240ac34 100644 --- a/lib/features/base/base_controller.dart +++ b/lib/features/base/base_controller.dart @@ -1,9 +1,11 @@ +import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:core/core.dart'; import 'package:dartz/dartz.dart'; import 'package:get/get.dart'; abstract class BaseController extends GetxController { final viewState = Rx>(Right(UIState.idle)); + final connectivityResult = Rxn(); void consumeState(Stream> newStateStream) async { log('BaseController::consumeState():'); @@ -18,6 +20,14 @@ abstract class BaseController extends GetxController { viewState.value = newState; } + void setNetworkConnectivityState(ConnectivityResult newConnectivityResult) { + connectivityResult.value = newConnectivityResult; + } + + bool isNetworkConnectionAvailable() { + return connectivityResult.value != ConnectivityResult.none; + } + void getState(Future> newStateStream) async { final state = await newStateStream; state.fold( diff --git a/lib/features/base/mixin/network_connection_mixin.dart b/lib/features/base/mixin/network_connection_mixin.dart new file mode 100644 index 000000000..09441068a --- /dev/null +++ b/lib/features/base/mixin/network_connection_mixin.dart @@ -0,0 +1,33 @@ + +import 'package:core/core.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:get/get.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; + +mixin NetworkConnectionMixin { + + final _imagePaths = Get.find(); + + Widget buildNetworkConnectionWidget(BuildContext context) { + return Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16)), + width: 320, + margin: EdgeInsets.only(bottom: 100), + child: Material( + elevation: 8, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(16.0)), + ), + child: ListTile( + leading: SvgPicture.asset(_imagePaths.icNotConnection), + title: Text( + AppLocalizations.of(context).no_internet_connection, + style: TextStyle(fontSize: 15, color: Colors.black)), + ) + ) + ); + } +} \ No newline at end of file diff --git a/lib/features/email/presentation/email_view.dart b/lib/features/email/presentation/email_view.dart index 9d6d96277..cca7cb462 100644 --- a/lib/features/email/presentation/email_view.dart +++ b/lib/features/email/presentation/email_view.dart @@ -8,6 +8,7 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; import 'package:model/model.dart'; +import 'package:tmail_ui_user/features/base/mixin/network_connection_mixin.dart'; import 'package:tmail_ui_user/features/composer/presentation/extensions/prefix_email_address_extension.dart'; import 'package:tmail_ui_user/features/email/presentation/email_controller.dart'; import 'package:tmail_ui_user/features/email/presentation/widgets/app_bar_mail_widget_builder.dart'; @@ -20,7 +21,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/user_setti import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:filesize/filesize.dart'; -class EmailView extends GetView with UserSettingPopupMenuMixin { +class EmailView extends GetView with UserSettingPopupMenuMixin, NetworkConnectionMixin { final emailController = Get.find(); final responsiveUtils = Get.find(); @@ -37,28 +38,33 @@ class EmailView extends GetView with UserSettingPopupMenuMixin { }, child: Scaffold( backgroundColor: responsiveUtils.isDesktop(context) ? AppColor.colorBgDesktop : Colors.white, - body: Container( - padding: EdgeInsets.zero, - margin: EdgeInsets.zero, - decoration: responsiveUtils.isTabletLarge(context) - ? BoxDecoration(border: Border(left: BorderSide(color: AppColor.colorLineLeftEmailView, width: 1.0))) - : null, - child: SafeArea( - right: responsiveUtils.isMobileDevice(context) && responsiveUtils.isLandscape(context), - left: responsiveUtils.isMobileDevice(context) && responsiveUtils.isLandscape(context), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - if (responsiveUtils.isDesktop(context)) - Container( - color: Colors.white, - padding: EdgeInsets.only(right: 10, top: 16, bottom: 10), - child: _buildHeader(context)), - Expanded(child: _buildBody(context)), - ] - ) + body: Stack(children: [ + Container( + padding: EdgeInsets.zero, + margin: EdgeInsets.zero, + decoration: responsiveUtils.isTabletLarge(context) + ? BoxDecoration(border: Border(left: BorderSide(color: AppColor.colorLineLeftEmailView, width: 1.0))) + : null, + child: SafeArea( + right: responsiveUtils.isMobileDevice(context) && responsiveUtils.isLandscape(context), + left: responsiveUtils.isMobileDevice(context) && responsiveUtils.isLandscape(context), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (responsiveUtils.isDesktop(context)) + Container( + color: Colors.white, + padding: EdgeInsets.only(right: 10, top: 16, bottom: 10), + child: _buildHeader(context)), + Expanded(child: _buildBody(context)), + ] + ) + ), ), - ) + Obx(() => !emailController.mailboxDashBoardController.isNetworkConnectionAvailable() && (responsiveUtils.isMobile(context) || responsiveUtils.isTablet(context)) + ? Align(alignment: Alignment.bottomCenter, child: buildNetworkConnectionWidget(context)) + : SizedBox.shrink()), + ]) ) ); } diff --git a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart index 3e71a6324..69fcaba95 100644 --- a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart @@ -1,3 +1,6 @@ +import 'dart:async'; + +import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:core/core.dart'; import 'package:dartz/dartz.dart'; import 'package:flutter/foundation.dart'; @@ -47,6 +50,7 @@ class MailboxDashBoardController extends ReloadableController { final RemoveEmailDraftsInteractor _removeEmailDraftsInteractor = Get.find(); final DeleteCredentialInteractor _deleteCredentialInteractor = Get.find(); final CachingManager _cachingManager = Get.find(); + final Connectivity _connectivity = Get.find(); final MoveToTrashInteractor _moveToTrashInteractor; final MoveToMailboxInteractor _moveToMailboxInteractor; @@ -68,12 +72,19 @@ class MailboxDashBoardController extends ReloadableController { TextEditingController searchInputController = TextEditingController(); FocusNode searchFocus = FocusNode(); RouterArguments? routerArguments; + late StreamSubscription _connectivityStreamSubscription; MailboxDashBoardController( this._moveToTrashInteractor, this._moveToMailboxInteractor, ); + @override + void onInit() { + super.onInit(); + _registerNetworkConnectivityState(); + } + @override void onReady() { super.onReady(); @@ -144,7 +155,17 @@ class MailboxDashBoardController extends ReloadableController { } @override - void onError(error) { + void onError(error) {} + + void _registerNetworkConnectivityState() async { + setNetworkConnectivityState(await _connectivity.checkConnectivity()); + _connectivityStreamSubscription = _connectivity.onConnectivityChanged.listen((ConnectivityResult result) { + log('MailboxDashBoardController::_registerNetworkConnectivityState(): ConnectivityResult: ${result.name}'); + setNetworkConnectivityState(result); + if (userProfile.value == null && result != ConnectivityResult.none) { + _getUserProfile(); + } + }); } void _getUserProfile() async { @@ -354,6 +375,7 @@ class MailboxDashBoardController extends ReloadableController { @override void onClose() { + _connectivityStreamSubscription.cancel(); searchInputController.dispose(); searchFocus.dispose(); super.onClose(); diff --git a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view.dart b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view.dart index 59d30e03e..0f4175c6d 100644 --- a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view.dart +++ b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view.dart @@ -1,6 +1,7 @@ import 'package:core/core.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:tmail_ui_user/features/base/mixin/network_connection_mixin.dart'; import 'package:tmail_ui_user/features/composer/presentation/composer_view.dart' if (dart.library.html) 'package:tmail_ui_user/features/composer/presentation/composer_view_web.dart'; import 'package:tmail_ui_user/features/email/presentation/email_view.dart'; @@ -12,7 +13,7 @@ import 'package:tmail_ui_user/features/setting/presentation/model/reading_pane.d import 'package:tmail_ui_user/features/thread/presentation/thread_view.dart'; import 'package:tmail_ui_user/main/routes/app_routes.dart'; -class MailboxDashBoardView extends GetWidget { +class MailboxDashBoardView extends GetWidget with NetworkConnectionMixin { final _responsiveUtils = Get.find(); @@ -40,6 +41,9 @@ class MailboxDashBoardView extends GetWidget { Obx(() => controller.dashBoardAction == DashBoardAction.compose ? ComposerView() : SizedBox.shrink()), + Obx(() => controller.isNetworkConnectionAvailable() + ? SizedBox.shrink() + : Align(alignment: Alignment.bottomCenter, child: buildNetworkConnectionWidget(context))), ]), ); } diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index 91cbc3d6d..eb1d2b667 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2022-03-31T09:03:00.853808", + "@@last_modified": "2022-03-31T12:07:59.313834", "initializing_data": "Initializing data...", "@initializing_data": { "type": "text", @@ -911,5 +911,11 @@ "type": "text", "placeholders_order": [], "placeholders": {} + }, + "no_internet_connection": "No internet connection", + "@no_internet_connection": { + "type": "text", + "placeholders_order": [], + "placeholders": {} } } \ No newline at end of file diff --git a/lib/main/bindings/network/network_bindings.dart b/lib/main/bindings/network/network_bindings.dart index ff9cb78d7..8b671e117 100644 --- a/lib/main/bindings/network/network_bindings.dart +++ b/lib/main/bindings/network/network_bindings.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:core/core.dart'; import 'package:dio/dio.dart'; import 'package:flutter/foundation.dart'; @@ -17,6 +18,7 @@ class NetworkBindings extends Bindings { void dependencies() { _bindingDio(); _bindingApi(); + _bindingConnection(); } void _bindingBaseOption() { @@ -56,4 +58,8 @@ class NetworkBindings extends Bindings { Get.find())); Get.put(ComposerAPI(Get.find())); } + + void _bindingConnection() { + Get.put(Connectivity()); + } } \ No newline at end of file diff --git a/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart index d331b4da1..b6dc36586 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -970,4 +970,11 @@ class AppLocalizations { name: 'moved_to_trash' ); } + + String get no_internet_connection { + return Intl.message( + 'No internet connection', + name: 'no_internet_connection' + ); + } } \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index c6bcb1cb4..80fd3efac 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -137,6 +137,8 @@ dependencies: rxdart: 0.27.3 + connectivity_plus: 2.2.1 + dev_dependencies: flutter_test: sdk: flutter