diff --git a/assets/images/ic_send_toast.svg b/assets/images/ic_send_toast.svg
new file mode 100644
index 000000000..34a878c9c
--- /dev/null
+++ b/assets/images/ic_send_toast.svg
@@ -0,0 +1,4 @@
+
diff --git a/core/lib/data/utils/device_manager.dart b/core/lib/data/utils/device_manager.dart
index bfc666408..5462b20fa 100644
--- a/core/lib/data/utils/device_manager.dart
+++ b/core/lib/data/utils/device_manager.dart
@@ -1,6 +1,7 @@
import 'dart:core';
-import 'package:device_info/device_info.dart';
+import 'package:device_info_plus/device_info_plus.dart';
+
class DeviceManager {
final DeviceInfoPlugin _deviceInfoPlugin;
@@ -9,6 +10,10 @@ class DeviceManager {
Future isNeedRequestStoragePermissionOnAndroid() async {
final androidInfo = await _deviceInfoPlugin.androidInfo;
- return androidInfo.version.sdkInt <= 28;
+ final sdkInt = androidInfo.version.sdkInt;
+ if (sdkInt != null) {
+ return sdkInt <= 28;
+ }
+ return false;
}
}
\ No newline at end of file
diff --git a/core/lib/presentation/resources/image_paths.dart b/core/lib/presentation/resources/image_paths.dart
index 289306ae1..392313734 100644
--- a/core/lib/presentation/resources/image_paths.dart
+++ b/core/lib/presentation/resources/image_paths.dart
@@ -79,6 +79,7 @@ class ImagePaths {
String get icFilterMessageAll => _getImagePath('ic_filter_message_all.svg');
String get icFilterMessageAttachments => _getImagePath('ic_filter_message_attachments.svg');
String get icLogoTMailV2 => _getImagePath('logo_tmail_v2.png');
+ String get icSendToast => _getImagePath('ic_send_toast.svg');
String _getImagePath(String imageName) {
return AssetsPaths.images + imageName;
diff --git a/core/lib/presentation/utils/app_toast.dart b/core/lib/presentation/utils/app_toast.dart
index 5a2c2e8df..6365d0463 100644
--- a/core/lib/presentation/utils/app_toast.dart
+++ b/core/lib/presentation/utils/app_toast.dart
@@ -61,7 +61,8 @@ class AppToast {
}
void showToastWithIcon(BuildContext context,
- {String? message, String? icon, Color? bgColor, double? radius, EdgeInsets? padding, TextStyle? textStyle}) {
+ {String? message, String? icon, Color? bgColor,
+ Color? textColor, double? radius, EdgeInsets? padding, TextStyle? textStyle}) {
final toast = Material(
color: bgColor ?? Colors.white,
elevation: 10,
@@ -71,7 +72,7 @@ class AppToast {
padding: padding ?? EdgeInsets.symmetric(horizontal: 12.0, vertical: 14),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(radius ?? 10.0),
- color: Colors.white,
+ color: bgColor ?? Colors.white,
),
width: 320,
child: Row(
@@ -81,7 +82,7 @@ class AppToast {
SizedBox(width: 10.0),
Expanded(child: Text(
message ?? '',
- style: textStyle ?? TextStyle(fontSize: 15, color: Colors.black))),
+ style: textStyle ?? TextStyle(fontSize: 15, color: textColor ?? Colors.black))),
],
),
),
diff --git a/core/pubspec.yaml b/core/pubspec.yaml
index ddb5c6eea..8cf69db04 100644
--- a/core/pubspec.yaml
+++ b/core/pubspec.yaml
@@ -55,8 +55,8 @@ dependencies:
# GetX
get: 4.1.4
- # device_info
- device_info: 2.0.2
+ # device_info_plus
+ device_info_plus: 3.2.2
# getwidget
getwidget: 2.0.4
diff --git a/lib/features/composer/presentation/composer_bindings.dart b/lib/features/composer/presentation/composer_bindings.dart
index da75a9993..bd872bf03 100644
--- a/lib/features/composer/presentation/composer_bindings.dart
+++ b/lib/features/composer/presentation/composer_bindings.dart
@@ -1,4 +1,5 @@
import 'package:core/core.dart';
+import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/cupertino.dart';
import 'package:get/get.dart';
import 'package:tmail_ui_user/features/composer/data/datasource/autocomplete_datasource.dart';
@@ -70,7 +71,9 @@ class ComposerBindings extends Bindings {
Get.find(),
Get.find(),
Get.find(),
+ Get.find(),
Get.find(),
+ Get.find(),
Get.find(),
Get.find(),
Get.find()));
diff --git a/lib/features/composer/presentation/composer_controller.dart b/lib/features/composer/presentation/composer_controller.dart
index 5e2311a47..0d58427b6 100644
--- a/lib/features/composer/presentation/composer_controller.dart
+++ b/lib/features/composer/presentation/composer_controller.dart
@@ -3,13 +3,15 @@ import 'dart:async';
import 'package:core/core.dart';
import 'package:dartz/dartz.dart';
+import 'package:device_info_plus/device_info_plus.dart';
import 'package:enough_html_editor/enough_html_editor.dart';
import 'package:file_picker/file_picker.dart';
import 'package:fk_user_agent/fk_user_agent.dart';
import 'package:flutter/cupertino.dart';
-import 'package:flutter/services.dart';
+import 'package:flutter/foundation.dart';
import 'package:flutter_chips_input/flutter_chips_input.dart';
import 'package:get/get.dart';
+import 'package:html_editor_enhanced/html_editor.dart' as HtmlEditorBrowser;
import 'package:http_parser/http_parser.dart';
import 'package:jmap_dart_client/jmap/core/id.dart';
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
@@ -39,7 +41,6 @@ import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
import 'package:tmail_ui_user/main/utils/app_logger.dart';
import 'package:uuid/uuid.dart';
-import 'dart:developer' as developer;
class ComposerController extends BaseController {
@@ -55,10 +56,12 @@ class ComposerController extends BaseController {
final GetAutoCompleteInteractor _getAutoCompleteInteractor;
final GetAutoCompleteWithDeviceContactInteractor _getAutoCompleteWithDeviceContactInteractor;
final AppToast _appToast;
+ final ImagePaths _imagePaths;
final Uuid _uuid;
final TextEditingController subjectEmailInputController;
final LocalFilePickerInteractor _localFilePickerInteractor;
final UploadMultipleAttachmentInteractor _uploadMultipleAttachmentInteractor;
+ final DeviceInfoPlugin _deviceInfoPlugin;
List listToEmailAddress = [];
List listCcEmailAddress = [];
@@ -66,19 +69,30 @@ class ComposerController extends BaseController {
String? _subjectEmail;
ContactSuggestionSource _contactSuggestionSource = ContactSuggestionSource.localContact;
HtmlEditorApi? htmlEditorApi;
+ final HtmlEditorBrowser.HtmlEditorController htmlControllerBrowser = HtmlEditorBrowser.HtmlEditorController();
final keyToEmailAddress = GlobalKey();
final keyCcEmailAddress = GlobalKey();
final keyBccEmailAddress = GlobalKey();
void setSubjectEmail(String subject) => _subjectEmail = subject;
+ Future _getEmailBodyText() async {
+ if (kIsWeb) {
+ return await htmlControllerBrowser.getText();
+ } else {
+ return (await htmlEditorApi?.getFullHtml()) ?? '';
+ }
+ }
+
ComposerController(
this._sendEmailInteractor,
this._saveEmailAddressInteractor,
this._getAutoCompleteInteractor,
this._getAutoCompleteWithDeviceContactInteractor,
this._appToast,
+ this._imagePaths,
this._uuid,
+ this._deviceInfoPlugin,
this.subjectEmailInputController,
this._localFilePickerInteractor,
this._uploadMultipleAttachmentInteractor,
@@ -124,7 +138,13 @@ class ComposerController extends BaseController {
@override
void onError(error) {
- _appToast.showErrorToast(AppLocalizations.of(Get.context!).error_message_sent);
+ if (Get.overlayContext != null && Get.context != null) {
+ _appToast.showToastWithIcon(
+ Get.overlayContext!,
+ textColor: AppColor.toastErrorBackgroundColor,
+ message: AppLocalizations.of(Get.context!).message_has_been_sent_failure,
+ icon: _imagePaths.icSendToast);
+ }
popBack();
}
@@ -261,7 +281,8 @@ class ComposerController extends BaseController {
final generatePartId = PartId(_uuid.v1());
final generateBlobId = Id(_uuid.v1());
- final emailBodyText = (await htmlEditorApi?.getFullHtml()) ?? '';
+ final emailBodyText = await _getEmailBodyText();
+ final userAgent = await userAgentPlatform;
return Email(
generateEmailId,
@@ -280,17 +301,22 @@ class ComposerController extends BaseController {
bodyValues: {
generatePartId: EmailBodyValue(emailBodyText, false, false)
},
- headerUserAgent: {IndividualHeaderIdentifier.headerUserAgent : userAgentPlatform},
+ headerUserAgent: {IndividualHeaderIdentifier.headerUserAgent : userAgent},
attachments: attachments.isNotEmpty ? _generateAttachments() : null,
);
}
- String get userAgentPlatform {
+ Future get userAgentPlatform async {
String userAgent;
try {
- userAgent = FkUserAgent.userAgent ?? '';
+ if (kIsWeb) {
+ final webBrowserInfo = await _deviceInfoPlugin.webBrowserInfo;
+ userAgent = webBrowserInfo.userAgent ?? '';
+ } else {
+ userAgent = FkUserAgent.userAgent ?? '';
+ }
log('ComposerController - userAgentPlatform(): userAgent: $userAgent');
- } on PlatformException {
+ } on Exception {
userAgent = '';
}
return userAgent;
diff --git a/lib/features/composer/presentation/composer_view.dart b/lib/features/composer/presentation/composer_view.dart
index 532625108..889030ce3 100644
--- a/lib/features/composer/presentation/composer_view.dart
+++ b/lib/features/composer/presentation/composer_view.dart
@@ -1,6 +1,8 @@
import 'package:core/core.dart';
import 'package:enough_html_editor/enough_html_editor.dart';
+import 'package:html_editor_enhanced/html_editor.dart' as HtmlEditorBrowser;
import 'package:file_picker/file_picker.dart';
+import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';
@@ -22,8 +24,7 @@ class ComposerView extends GetWidget {
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
- FocusManager.instance.primaryFocus?.unfocus();
- controller.htmlEditorApi?.unfocus();
+ controller.htmlEditorApi?.unfocus(context);
},
child: Scaffold(
backgroundColor: AppColor.primaryLightColor,
@@ -225,28 +226,36 @@ class ComposerView extends GetWidget {
Widget _buildComposerEditor(BuildContext context) {
return Obx(() {
- if (controller.composerArguments.value?.emailActionType == EmailActionType.compose) {
- return HtmlEditor(
+ if (kIsWeb) {
+ return HtmlEditorBrowser.HtmlEditor(
key: Key('composer_editor'),
- minHeight: 100,
- supportZoom: true,
- disableHorizontalScroll: false,
- disableVerticalScroll: false,
- onCreated: (editorApi) => controller.htmlEditorApi = editorApi,
+ controller: controller.htmlControllerBrowser,
+ htmlEditorOptions: HtmlEditorBrowser.HtmlEditorOptions(
+ shouldEnsureVisible: true,
+ initialText: controller.getContentEmail(),
+ autoAdjustHeight: controller.getContentEmail().isNotEmpty,
+ ),
+ htmlToolbarOptions: HtmlEditorBrowser.HtmlToolbarOptions(
+ toolbarPosition: HtmlEditorBrowser.ToolbarPosition.custom
+ ),
+ otherOptions: HtmlEditorBrowser.OtherOptions(height: 550),
);
} else {
- final message = controller.getContentEmail();
- return message.isNotEmpty
- ? HtmlEditor(
+ if (controller.composerArguments.value?.emailActionType == EmailActionType.compose) {
+ return HtmlEditor(
key: Key('composer_editor'),
minHeight: 100,
- supportZoom: true,
- disableHorizontalScroll: false,
- disableVerticalScroll: false,
- onCreated: (editorApi) => controller.htmlEditorApi = editorApi,
- initialContent: message,
- )
- : SizedBox.shrink();
+ onCreated: (editorApi) => controller.htmlEditorApi = editorApi);
+ } else {
+ final message = controller.getContentEmail();
+ return message.isNotEmpty
+ ? HtmlEditor(
+ key: Key('composer_editor'),
+ minHeight: 100,
+ onCreated: (editorApi) => controller.htmlEditorApi = editorApi,
+ initialContent: message)
+ : SizedBox.shrink();
+ }
}
});
}
diff --git a/lib/features/email/presentation/email_view.dart b/lib/features/email/presentation/email_view.dart
index a5f707aa8..8b48cc546 100644
--- a/lib/features/email/presentation/email_view.dart
+++ b/lib/features/email/presentation/email_view.dart
@@ -61,13 +61,13 @@ class EmailView extends GetView {
Widget _buildBottomBar(BuildContext context) {
return Padding(
padding: EdgeInsets.only(left: 6, top: 6, right: 6, bottom: 6),
- child: (BottomBarMailWidgetBuilder(
+ child: Obx(() => (BottomBarMailWidgetBuilder(
context,
imagePaths,
responsiveUtils,
emailController.mailboxDashBoardController.selectedEmail.value)
..addOnPressEmailAction((emailActionType) => emailController.pressEmailAction(emailActionType)))
- .build());
+ .build()));
}
Widget _buildEmailBody(BuildContext context) {
diff --git a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_bindings.dart b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_bindings.dart
index 47865d54a..fbf0843db 100644
--- a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_bindings.dart
+++ b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_bindings.dart
@@ -16,11 +16,12 @@ class MailboxDashBoardBindings extends Bindings {
Get.lazyPut(() => CredentialRepositoryImpl(Get.find()));
Get.lazyPut(() => Get.find());
Get.lazyPut(() => GetUserProfileInteractor(Get.find()));
- Get.lazyPut(() => AppToast());
Get.put(MailboxDashBoardController(
Get.find(),
- Get.find()));
+ Get.find(),
+ Get.find(),
+ ));
MailboxBindings().dependencies();
ThreadBindings().dependencies();
diff --git a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart
index a7db55ec6..77685321b 100644
--- a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart
+++ b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart
@@ -21,6 +21,7 @@ class MailboxDashBoardController extends BaseController {
final GetUserProfileInteractor _getUserProfileInteractor;
final AppToast _appToast;
+ final ImagePaths _imagePaths;
final scaffoldKey = GlobalKey();
final selectedMailbox = Rxn();
@@ -37,7 +38,11 @@ class MailboxDashBoardController extends BaseController {
Map mapDefaultMailboxId = Map();
Map mapMailbox = Map();
- MailboxDashBoardController(this._getUserProfileInteractor, this._appToast);
+ MailboxDashBoardController(
+ this._getUserProfileInteractor,
+ this._appToast,
+ this._imagePaths,
+ );
@override
void onReady() {
@@ -51,8 +56,11 @@ class MailboxDashBoardController extends BaseController {
super.onData(newState);
viewState.value.map((success) {
if (success is SendingEmailState) {
- if (Get.context != null) {
- _appToast.showToast(AppLocalizations.of(Get.context!).your_email_being_sent);
+ if (Get.overlayContext != null && Get.context != null) {
+ _appToast.showToastWithIcon(
+ Get.overlayContext!,
+ message: AppLocalizations.of(Get.context!).your_email_being_sent,
+ icon: _imagePaths.icSendToast);
}
}
});
@@ -63,20 +71,28 @@ class MailboxDashBoardController extends BaseController {
viewState.value.fold(
(failure) {
if (failure is SendEmailFailure) {
- if (Get.context != null) {
- _appToast.showErrorToast(AppLocalizations.of(Get.context!).error_message_sent);
- clearState();
+ if (Get.overlayContext != null && Get.context != null) {
+ _appToast.showToastWithIcon(
+ Get.overlayContext!,
+ textColor: AppColor.toastErrorBackgroundColor,
+ message: AppLocalizations.of(Get.context!).message_has_been_sent_failure,
+ icon: _imagePaths.icSendToast);
}
+ clearState();
}
},
(success) {
if (success is GetUserProfileSuccess) {
userProfile.value = success.userProfile;
} else if (success is SendEmailSuccess) {
- if (Get.context != null) {
- _appToast.showSuccessToast(AppLocalizations.of(Get.context!).message_sent);
- clearState();
+ if (Get.overlayContext != null && Get.context != null) {
+ _appToast.showToastWithIcon(
+ Get.overlayContext!,
+ textColor: AppColor.toastSuccessBackgroundColor,
+ message: AppLocalizations.of(Get.context!).message_has_been_sent_successfully,
+ icon: _imagePaths.icSendToast);
}
+ clearState();
}
}
);
diff --git a/lib/main/bindings/core/core_bindings.dart b/lib/main/bindings/core/core_bindings.dart
index f569cdd71..0712989ca 100644
--- a/lib/main/bindings/core/core_bindings.dart
+++ b/lib/main/bindings/core/core_bindings.dart
@@ -1,5 +1,5 @@
import 'package:core/core.dart';
-import 'package:device_info/device_info.dart';
+import 'package:device_info_plus/device_info_plus.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:get/get.dart';
import 'package:shared_preferences/shared_preferences.dart';
diff --git a/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart
index f71d6b1b9..12983df9b 100644
--- a/lib/main/localizations/app_localizations.dart
+++ b/lib/main/localizations/app_localizations.dart
@@ -214,20 +214,6 @@ class AppLocalizations {
);
}
- String get message_sent {
- return Intl.message(
- 'Message sent',
- name: 'message_sent',
- );
- }
-
- String get error_message_sent {
- return Intl.message(
- 'Error message sent',
- name: 'error_message_sent',
- );
- }
-
String count_email_selected(int count) {
return Intl.message(
'$count selected',
@@ -585,4 +571,18 @@ class AppLocalizations {
'With Starred',
name: 'with_starred');
}
+
+ String get message_has_been_sent_successfully {
+ return Intl.message(
+ 'Message has been sent successfully',
+ name: 'message_has_been_sent_successfully',
+ );
+ }
+
+ String get message_has_been_sent_failure {
+ return Intl.message(
+ 'Message has been sent failure',
+ name: 'message_has_been_sent_failure',
+ );
+ }
}
\ No newline at end of file
diff --git a/pubspec.yaml b/pubspec.yaml
index d4bd6816f..b3ea7d9b7 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -95,8 +95,8 @@ dependencies:
# path_provider
path_provider: 2.0.3
- # device_info
- device_info: 2.0.2
+ # device_info_plus
+ device_info_plus: 3.2.2
# permission_handler
permission_handler: 8.1.6
@@ -111,16 +111,18 @@ dependencies:
ref: master
# file_picker
- file_picker: 3.0.2+2
+ file_picker: 4.2.0
# hive
hive: 2.0.4
- # enough_html_editor
+ # enough_html_editor: Compose email for Mobile & Tablet
enough_html_editor:
git:
- url: https://github.com/dab246/enough_html_editor.git
- ref: fix_bug_enough_platform_widgets
+ url: https://github.com/Enough-Software/enough_html_editor.git
+
+ # html_editor_enhanced: Compose email for Web Browser
+ html_editor_enhanced: 2.4.0+1
# fk_user_agent
fk_user_agent: 2.1.0