Reduce worker_manager memory allocation (#4435)
This commit is contained in:
@@ -120,16 +120,6 @@
|
|||||||
android:exported="false"
|
android:exported="false"
|
||||||
tools:node="remove"/>
|
tools:node="remove"/>
|
||||||
|
|
||||||
<provider
|
|
||||||
android:name="vn.hunghd.flutterdownloader.DownloadedFileProvider"
|
|
||||||
android:authorities="${applicationId}.flutter_downloader.provider"
|
|
||||||
android:exported="false"
|
|
||||||
android:grantUriPermissions="true">
|
|
||||||
<meta-data
|
|
||||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
|
||||||
android:resource="@xml/provider_paths"/>
|
|
||||||
</provider>
|
|
||||||
|
|
||||||
<!-- Don't delete the meta-data below.
|
<!-- Don't delete the meta-data below.
|
||||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||||
<meta-data
|
<meta-data
|
||||||
|
|||||||
@@ -1,9 +1,3 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">Twake Mail</string>
|
<string name="app_name">Twake Mail</string>
|
||||||
<string name="flutter_downloader_notification_started">Started</string>
|
|
||||||
<string name="flutter_downloader_notification_in_progress">In Progress</string>
|
|
||||||
<string name="flutter_downloader_notification_canceled">Canceled</string>
|
|
||||||
<string name="flutter_downloader_notification_failed">Failed</string>
|
|
||||||
<string name="flutter_downloader_notification_complete">Completed</string>
|
|
||||||
<string name="flutter_downloader_notification_paused">Paused</string>
|
|
||||||
</resources>
|
</resources>
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
# 0079 - Reduce Twake Mail mobile memory usage
|
||||||
|
|
||||||
|
Date: 2026-04-09
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Accepted
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
Twake Mail is allocating a lot of memory on mobile.
|
||||||
|
- ~375 MB on Android (Oneplus 8T)
|
||||||
|
|
||||||
|
<img src="../images/android-before-4435.png">
|
||||||
|
|
||||||
|
- ~297 MB on iOS (iPhone 11 Pro)
|
||||||
|
|
||||||
|
<img src="../images/ios-before-4435.png">
|
||||||
|
|
||||||
|
## Findings
|
||||||
|
|
||||||
|
### `worker_manager` library's inefficient memory allocation (Android & iOS)
|
||||||
|
- Version `5.0.3` counts the number of processors (x) on the device, create forever-live x - 1 isolates
|
||||||
|
- Version `7.2.7` adds an ability to create isolate on-demand, and dispose when done. However, it still leaks 1 isolate when init.
|
||||||
|
### `firebase_messaging` library's eager background Dart isolate (Android)
|
||||||
|
- FirebaseMessaging.onBackgroundMessage() creates a forever-live isolate even when the app is in foreground.
|
||||||
|
- Related: https://github.com/firebase/flutterfire/issues/17163
|
||||||
|
### Unused `flutter_downloader` library's worker (iOS)
|
||||||
|
- The only usage was deleted in https://github.com/linagora/tmail-flutter/commit/be8eaf625818b17e60ca65846053cb8c26a71a15#diff-451741ba5146e6ad711c77e4c2fe34958a36595e4926cd43c2ddb97586ef6d88, but the library and initialization process remained, causing 1 forever-live isolate.
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
### `worker_manager`
|
||||||
|
- Upgrade to `7.2.7`
|
||||||
|
- Create an upstream fix for init's isolate leak
|
||||||
|
### `firebase_messaging`
|
||||||
|
- Wait for https://github.com/firebase/flutterfire/pull/18122, update when merged
|
||||||
|
### `flutter_downloader`
|
||||||
|
- Remove the library
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
- Android: ~118 MB
|
||||||
|
|
||||||
|
<img src="../images/android-after-4435.png">
|
||||||
|
|
||||||
|
- iOS: ~78 MB
|
||||||
|
|
||||||
|
<img src="../images/ios-after-4435.png">
|
||||||
|
|
||||||
|
- No changes for web
|
||||||
|
|
||||||
|
| Before | After |
|
||||||
|
| :--- | :--- |
|
||||||
|
| <img src="../images/web-before-4435.png"> | <img src="../images/web-after-4435.png"> |
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 927 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.0 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.1 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 1012 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 585 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 593 KiB |
+8
-20
@@ -97,8 +97,6 @@ PODS:
|
|||||||
- Flutter
|
- Flutter
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- UniversalDetector2 (= 2.0.1)
|
- UniversalDetector2 (= 2.0.1)
|
||||||
- flutter_downloader (0.0.1):
|
|
||||||
- Flutter
|
|
||||||
- flutter_file_dialog (0.0.1):
|
- flutter_file_dialog (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- flutter_image_compress_common (1.0.0):
|
- flutter_image_compress_common (1.0.0):
|
||||||
@@ -164,7 +162,7 @@ PODS:
|
|||||||
- libwebp/sharpyuv (1.5.0)
|
- libwebp/sharpyuv (1.5.0)
|
||||||
- libwebp/webp (1.5.0):
|
- libwebp/webp (1.5.0):
|
||||||
- libwebp/sharpyuv
|
- libwebp/sharpyuv
|
||||||
- lottie-ios (4.4.1)
|
- lottie-ios (4.4.3)
|
||||||
- lottie_native (0.0.1):
|
- lottie_native (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- lottie-ios (~> 4.4.1)
|
- lottie-ios (~> 4.4.1)
|
||||||
@@ -206,10 +204,10 @@ PODS:
|
|||||||
- ReachabilitySwift (5.2.4)
|
- ReachabilitySwift (5.2.4)
|
||||||
- receive_sharing_intent (1.8.1):
|
- receive_sharing_intent (1.8.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- SDWebImage (5.21.1):
|
- SDWebImage (5.21.7):
|
||||||
- SDWebImage/Core (= 5.21.1)
|
- SDWebImage/Core (= 5.21.7)
|
||||||
- SDWebImage/Core (5.21.1)
|
- SDWebImage/Core (5.21.7)
|
||||||
- SDWebImageWebPCoder (0.14.6):
|
- SDWebImageWebPCoder (0.15.0):
|
||||||
- libwebp (~> 1.0)
|
- libwebp (~> 1.0)
|
||||||
- SDWebImage/Core (~> 5.17)
|
- SDWebImage/Core (~> 5.17)
|
||||||
- Sentry/HybridSDK (8.56.2)
|
- Sentry/HybridSDK (8.56.2)
|
||||||
@@ -228,8 +226,6 @@ PODS:
|
|||||||
- UniversalDetector2 (2.0.1)
|
- UniversalDetector2 (2.0.1)
|
||||||
- url_launcher_ios (0.0.1):
|
- url_launcher_ios (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- workmanager_apple (0.0.1):
|
|
||||||
- Flutter
|
|
||||||
|
|
||||||
DEPENDENCIES:
|
DEPENDENCIES:
|
||||||
- app_links (from `.symlinks/plugins/app_links/ios`)
|
- app_links (from `.symlinks/plugins/app_links/ios`)
|
||||||
@@ -246,7 +242,6 @@ DEPENDENCIES:
|
|||||||
- Flutter (from `Flutter`)
|
- Flutter (from `Flutter`)
|
||||||
- flutter_appauth (from `.symlinks/plugins/flutter_appauth/ios`)
|
- flutter_appauth (from `.symlinks/plugins/flutter_appauth/ios`)
|
||||||
- flutter_charset_detector_darwin (from `.symlinks/plugins/flutter_charset_detector_darwin/darwin`)
|
- flutter_charset_detector_darwin (from `.symlinks/plugins/flutter_charset_detector_darwin/darwin`)
|
||||||
- flutter_downloader (from `.symlinks/plugins/flutter_downloader/ios`)
|
|
||||||
- flutter_file_dialog (from `.symlinks/plugins/flutter_file_dialog/ios`)
|
- flutter_file_dialog (from `.symlinks/plugins/flutter_file_dialog/ios`)
|
||||||
- flutter_image_compress_common (from `.symlinks/plugins/flutter_image_compress_common/ios`)
|
- flutter_image_compress_common (from `.symlinks/plugins/flutter_image_compress_common/ios`)
|
||||||
- flutter_inappwebview_ios (from `.symlinks/plugins/flutter_inappwebview_ios/ios`)
|
- flutter_inappwebview_ios (from `.symlinks/plugins/flutter_inappwebview_ios/ios`)
|
||||||
@@ -272,7 +267,6 @@ DEPENDENCIES:
|
|||||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||||
- super_dns_client (from `.symlinks/plugins/super_dns_client/ios`)
|
- super_dns_client (from `.symlinks/plugins/super_dns_client/ios`)
|
||||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||||
- workmanager_apple (from `.symlinks/plugins/workmanager_apple/ios`)
|
|
||||||
|
|
||||||
SPEC REPOS:
|
SPEC REPOS:
|
||||||
trunk:
|
trunk:
|
||||||
@@ -329,8 +323,6 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/flutter_appauth/ios"
|
:path: ".symlinks/plugins/flutter_appauth/ios"
|
||||||
flutter_charset_detector_darwin:
|
flutter_charset_detector_darwin:
|
||||||
:path: ".symlinks/plugins/flutter_charset_detector_darwin/darwin"
|
:path: ".symlinks/plugins/flutter_charset_detector_darwin/darwin"
|
||||||
flutter_downloader:
|
|
||||||
:path: ".symlinks/plugins/flutter_downloader/ios"
|
|
||||||
flutter_file_dialog:
|
flutter_file_dialog:
|
||||||
:path: ".symlinks/plugins/flutter_file_dialog/ios"
|
:path: ".symlinks/plugins/flutter_file_dialog/ios"
|
||||||
flutter_image_compress_common:
|
flutter_image_compress_common:
|
||||||
@@ -381,8 +373,6 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/super_dns_client/ios"
|
:path: ".symlinks/plugins/super_dns_client/ios"
|
||||||
url_launcher_ios:
|
url_launcher_ios:
|
||||||
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
||||||
workmanager_apple:
|
|
||||||
:path: ".symlinks/plugins/workmanager_apple/ios"
|
|
||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
app_links: 3da4c36b46cac3bf24eb897f1a6ce80bda109874
|
app_links: 3da4c36b46cac3bf24eb897f1a6ce80bda109874
|
||||||
@@ -408,7 +398,6 @@ SPEC CHECKSUMS:
|
|||||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||||
flutter_appauth: d4abcf54856e5d8ba82ed7646ffc83245d4aa448
|
flutter_appauth: d4abcf54856e5d8ba82ed7646ffc83245d4aa448
|
||||||
flutter_charset_detector_darwin: 14f055ebeed6896144cc96b046749df51127a0a3
|
flutter_charset_detector_darwin: 14f055ebeed6896144cc96b046749df51127a0a3
|
||||||
flutter_downloader: 78da0da1084e709cbfd3b723c7ea349c71681f09
|
|
||||||
flutter_file_dialog: ca8d7fbd1772d4f0c2777b4ab20a7787ef4e7dd8
|
flutter_file_dialog: ca8d7fbd1772d4f0c2777b4ab20a7787ef4e7dd8
|
||||||
flutter_image_compress_common: 1697a328fd72bfb335507c6bca1a65fa5ad87df1
|
flutter_image_compress_common: 1697a328fd72bfb335507c6bca1a65fa5ad87df1
|
||||||
flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99
|
flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99
|
||||||
@@ -420,7 +409,7 @@ SPEC CHECKSUMS:
|
|||||||
GoogleDataTransport: 6c09b596d841063d76d4288cc2d2f42cc36e1e2a
|
GoogleDataTransport: 6c09b596d841063d76d4288cc2d2f42cc36e1e2a
|
||||||
GoogleUtilities: ea963c370a38a8069cc5f7ba4ca849a60b6d7d15
|
GoogleUtilities: ea963c370a38a8069cc5f7ba4ca849a60b6d7d15
|
||||||
libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8
|
libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8
|
||||||
lottie-ios: e047b1d2e6239b787cc5e9755b988869cf190494
|
lottie-ios: fcb5e73e17ba4c983140b7d21095c834b3087418
|
||||||
lottie_native: c2e590a297861fc32a0188cf8dab39aa97f86d81
|
lottie_native: c2e590a297861fc32a0188cf8dab39aa97f86d81
|
||||||
Mantle: c5aa8794a29a022dfbbfc9799af95f477a69b62d
|
Mantle: c5aa8794a29a022dfbbfc9799af95f477a69b62d
|
||||||
nanopb: d4d75c12cd1316f4a64e3c6963f879ecd4b5e0d5
|
nanopb: d4d75c12cd1316f4a64e3c6963f879ecd4b5e0d5
|
||||||
@@ -438,8 +427,8 @@ SPEC CHECKSUMS:
|
|||||||
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
||||||
ReachabilitySwift: 32793e867593cfc1177f5d16491e3a197d2fccda
|
ReachabilitySwift: 32793e867593cfc1177f5d16491e3a197d2fccda
|
||||||
receive_sharing_intent: 222384f00ffe7e952bbfabaa9e3967cb87e5fe00
|
receive_sharing_intent: 222384f00ffe7e952bbfabaa9e3967cb87e5fe00
|
||||||
SDWebImage: f29024626962457f3470184232766516dee8dfea
|
SDWebImage: e9fc87c1aab89a8ab1bbd74eba378c6f53be8abf
|
||||||
SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380
|
SDWebImageWebPCoder: 0e06e365080397465cc73a7a9b472d8a3bd0f377
|
||||||
Sentry: b53951377b78e21a734f5dc8318e333dbfc682d7
|
Sentry: b53951377b78e21a734f5dc8318e333dbfc682d7
|
||||||
sentry_flutter: 4c33648b7e83310aa1fdb1b10c5491027d9643f0
|
sentry_flutter: 4c33648b7e83310aa1fdb1b10c5491027d9643f0
|
||||||
share_plus: de6030e33b4e106470e09322d87cf2a4258d2d1d
|
share_plus: de6030e33b4e106470e09322d87cf2a4258d2d1d
|
||||||
@@ -448,7 +437,6 @@ SPEC CHECKSUMS:
|
|||||||
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
|
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
|
||||||
UniversalDetector2: 7c9ffd935cf050eeb19edf7e90f6febe3743a1af
|
UniversalDetector2: 7c9ffd935cf050eeb19edf7e90f6febe3743a1af
|
||||||
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
|
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
|
||||||
workmanager_apple: 904529ae31e97fc5be632cf628507652294a0778
|
|
||||||
|
|
||||||
PODFILE CHECKSUM: 40b12ce0bc437886ee4f4050970375d7d253708d
|
PODFILE CHECKSUM: 40b12ce0bc437886ee4f4050970375d7d253708d
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import UIKit
|
import UIKit
|
||||||
import Flutter
|
import Flutter
|
||||||
import flutter_downloader
|
|
||||||
import receive_sharing_intent
|
import receive_sharing_intent
|
||||||
import flutter_local_notifications
|
import flutter_local_notifications
|
||||||
|
|
||||||
@@ -34,12 +33,6 @@ import flutter_local_notifications
|
|||||||
GeneratedPluginRegistrant.register(with: registry)
|
GeneratedPluginRegistrant.register(with: registry)
|
||||||
}
|
}
|
||||||
|
|
||||||
FlutterDownloaderPlugin.setPluginRegistrantCallback { registry in
|
|
||||||
if (!registry.hasPlugin("FlutterDownloaderPlugin")) {
|
|
||||||
FlutterDownloaderPlugin.register(with: registry.registrar(forPlugin: "FlutterDownloaderPlugin")!)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let sharingIntent = SwiftReceiveSharingIntentPlugin.instance
|
let sharingIntent = SwiftReceiveSharingIntentPlugin.instance
|
||||||
if let url = launchOptions?[UIApplication.LaunchOptionsKey.url] as? URL {
|
if let url = launchOptions?[UIApplication.LaunchOptionsKey.url] as? URL {
|
||||||
if url.scheme == "mailto" {
|
if url.scheme == "mailto" {
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import 'package:core/presentation/state/failure.dart';
|
|||||||
import 'package:core/presentation/state/success.dart';
|
import 'package:core/presentation/state/success.dart';
|
||||||
import 'package:core/utils/app_logger.dart';
|
import 'package:core/utils/app_logger.dart';
|
||||||
import 'package:core/utils/platform_info.dart';
|
import 'package:core/utils/platform_info.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:flutter_downloader/flutter_downloader.dart';
|
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:jmap_dart_client/jmap/core/session/session.dart';
|
import 'package:jmap_dart_client/jmap/core/session/session.dart';
|
||||||
import 'package:model/account/personal_account.dart';
|
import 'package:model/account/personal_account.dart';
|
||||||
@@ -68,7 +66,6 @@ class HomeController extends ReloadableController {
|
|||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
if (PlatformInfo.isMobile) {
|
if (PlatformInfo.isMobile) {
|
||||||
_initFlutterDownloader();
|
|
||||||
_registerReceivingFileSharing();
|
_registerReceivingFileSharing();
|
||||||
_registerDeepLinks();
|
_registerDeepLinks();
|
||||||
}
|
}
|
||||||
@@ -96,14 +93,6 @@ class HomeController extends ReloadableController {
|
|||||||
clearDataAndGoToLoginPage();
|
clearDataAndGoToLoginPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _initFlutterDownloader() {
|
|
||||||
FlutterDownloader
|
|
||||||
.initialize(debug: kDebugMode)
|
|
||||||
.then((_) => FlutterDownloader.registerCallback(downloadCallback));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void downloadCallback(String id, int status, int progress) {}
|
|
||||||
|
|
||||||
Future<void> _handleNavigateToScreen() async {
|
Future<void> _handleNavigateToScreen() async {
|
||||||
await Future.delayed(2.seconds);
|
await Future.delayed(2.seconds);
|
||||||
final arguments = Get.arguments;
|
final arguments = Get.arguments;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:core/presentation/state/failure.dart';
|
import 'package:core/presentation/state/failure.dart';
|
||||||
import 'package:core/presentation/state/success.dart';
|
import 'package:core/presentation/state/success.dart';
|
||||||
@@ -172,7 +173,7 @@ class MailboxDataSourceImpl extends MailboxDataSource {
|
|||||||
StreamController<dartz.Either<Failure, Success>>? onProgressController,
|
StreamController<dartz.Either<Failure, Success>>? onProgressController,
|
||||||
}) {
|
}) {
|
||||||
return Future.sync(() async {
|
return Future.sync(() async {
|
||||||
if (PlatformInfo.isWeb) {
|
if (PlatformInfo.isWeb || Platform.numberOfProcessors == 1) {
|
||||||
return await mailboxAPI.moveFolderContent(
|
return await mailboxAPI.moveFolderContent(
|
||||||
session: session,
|
session: session,
|
||||||
accountId: accountId,
|
accountId: accountId,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:core/presentation/state/failure.dart';
|
import 'package:core/presentation/state/failure.dart';
|
||||||
import 'package:core/presentation/state/success.dart';
|
import 'package:core/presentation/state/success.dart';
|
||||||
@@ -39,9 +40,8 @@ class MailboxIsolateWorker {
|
|||||||
|
|
||||||
final ThreadAPI _threadApi;
|
final ThreadAPI _threadApi;
|
||||||
final EmailAPI _emailApi;
|
final EmailAPI _emailApi;
|
||||||
final Executor _isolateExecutor;
|
|
||||||
|
|
||||||
MailboxIsolateWorker(this._threadApi, this._emailApi, this._isolateExecutor);
|
MailboxIsolateWorker(this._threadApi, this._emailApi);
|
||||||
|
|
||||||
Future<List<EmailId>> markAsMailboxRead(
|
Future<List<EmailId>> markAsMailboxRead(
|
||||||
Session session,
|
Session session,
|
||||||
@@ -50,8 +50,8 @@ class MailboxIsolateWorker {
|
|||||||
int totalEmailUnread,
|
int totalEmailUnread,
|
||||||
StreamController<Either<Failure, Success>> onProgressController
|
StreamController<Either<Failure, Success>> onProgressController
|
||||||
) async {
|
) async {
|
||||||
if (PlatformInfo.isWeb) {
|
if (PlatformInfo.isWeb || Platform.numberOfProcessors == 1) {
|
||||||
return _handleMarkAsMailboxReadActionOnWeb(
|
return await _handleMarkAsMailboxReadActionOnMainIsolate(
|
||||||
session,
|
session,
|
||||||
accountId,
|
accountId,
|
||||||
mailboxId,
|
mailboxId,
|
||||||
@@ -63,108 +63,87 @@ class MailboxIsolateWorker {
|
|||||||
throw const CanNotGetRootIsolateToken();
|
throw const CanNotGetRootIsolateToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
final result = await _isolateExecutor.execute(
|
final args = MailboxMarkAsReadArguments(
|
||||||
arg1: MailboxMarkAsReadArguments(
|
session,
|
||||||
session,
|
_threadApi,
|
||||||
_threadApi,
|
_emailApi,
|
||||||
_emailApi,
|
accountId,
|
||||||
accountId,
|
mailboxId,
|
||||||
mailboxId,
|
rootIsolateToken,
|
||||||
rootIsolateToken
|
);
|
||||||
),
|
return await workerManager.executeWithPort<List<EmailId>, int>(
|
||||||
fun1: _handleMarkAsMailboxReadAction,
|
_buildMarkAsReadClosure(args),
|
||||||
notification: (value) {
|
onMessage: (countRead) {
|
||||||
if (value is List<EmailId>) {
|
log('MailboxIsolateWorker::markAsMailboxRead(): onUpdateProgress: PERCENT ${countRead / totalEmailUnread}');
|
||||||
log('MailboxIsolateWorker::markAsMailboxRead(): onUpdateProgress: PERCENT ${value.length / totalEmailUnread}');
|
onProgressController.add(Right(UpdatingMarkAsMailboxReadState(
|
||||||
onProgressController.add(Right(UpdatingMarkAsMailboxReadState(
|
mailboxId: mailboxId,
|
||||||
mailboxId: mailboxId,
|
totalUnread: totalEmailUnread,
|
||||||
totalUnread: totalEmailUnread,
|
countRead: countRead)));
|
||||||
countRead: value.length)));
|
},
|
||||||
}
|
);
|
||||||
});
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<List<EmailId>> _handleMarkAsMailboxReadAction(
|
static Future<List<EmailId>> _handleMarkAsMailboxReadAction(
|
||||||
MailboxMarkAsReadArguments args,
|
MailboxMarkAsReadArguments args,
|
||||||
TypeSendPort sendPort
|
SendPort sendPort,
|
||||||
) async {
|
) async {
|
||||||
final rootIsolateToken = args.isolateToken;
|
final rootIsolateToken = args.isolateToken;
|
||||||
BackgroundIsolateBinaryMessenger.ensureInitialized(rootIsolateToken);
|
BackgroundIsolateBinaryMessenger.ensureInitialized(rootIsolateToken);
|
||||||
await HiveCacheConfig.instance.setUp();
|
await HiveCacheConfig.instance.setUp();
|
||||||
|
|
||||||
List<EmailId> emailIdsCompleted = List.empty(growable: true);
|
final emailIdsCompleted = await _executeMarkAsMailboxRead(
|
||||||
bool mailboxHasEmails = true;
|
threadAPI: args.threadAPI,
|
||||||
UTCDate? lastReceivedDate;
|
emailAPI: args.emailAPI,
|
||||||
EmailId? lastEmailId;
|
session: args.session,
|
||||||
|
accountId: args.accountId,
|
||||||
while (mailboxHasEmails) {
|
mailboxId: args.mailboxId,
|
||||||
final emailResponse = await args.threadAPI
|
onProgress: sendPort.send,
|
||||||
.getAllEmail(
|
);
|
||||||
args.session,
|
|
||||||
args.accountId,
|
|
||||||
limit: UnsignedInt(30),
|
|
||||||
filter: EmailFilterCondition(
|
|
||||||
inMailbox: args.mailboxId,
|
|
||||||
notKeyword: KeyWordIdentifier.emailSeen.value,
|
|
||||||
before: lastReceivedDate),
|
|
||||||
sort: <Comparator>{}..add(
|
|
||||||
EmailComparator(EmailComparatorProperty.receivedAt)
|
|
||||||
..setIsAscending(false)),
|
|
||||||
properties: Properties({
|
|
||||||
EmailProperty.id,
|
|
||||||
EmailProperty.keywords,
|
|
||||||
EmailProperty.receivedAt,
|
|
||||||
}))
|
|
||||||
.then((response) {
|
|
||||||
var listEmails = response.emailList;
|
|
||||||
if (listEmails != null && listEmails.isNotEmpty && lastEmailId != null) {
|
|
||||||
listEmails = listEmails
|
|
||||||
.where((email) => email.id != lastEmailId)
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
return EmailsResponse(emailList: listEmails, state: response.state);
|
|
||||||
});
|
|
||||||
final listEmailUnread = emailResponse.emailList;
|
|
||||||
|
|
||||||
log('MailboxIsolateWorker::_handleMarkAsMailboxRead(): listEmailUnread: ${listEmailUnread?.length}');
|
|
||||||
|
|
||||||
if (listEmailUnread == null || listEmailUnread.isEmpty) {
|
|
||||||
mailboxHasEmails = false;
|
|
||||||
} else {
|
|
||||||
lastEmailId = listEmailUnread.last.id;
|
|
||||||
lastReceivedDate = listEmailUnread.last.receivedAt;
|
|
||||||
|
|
||||||
final result = await args.emailAPI.markAsRead(
|
|
||||||
args.session,
|
|
||||||
args.accountId,
|
|
||||||
listEmailUnread.listEmailIds,
|
|
||||||
ReadActions.markAsRead);
|
|
||||||
|
|
||||||
log('MailboxIsolateWorker::_handleMarkAsMailboxRead(): MARK_READ: ${result.emailIdsSuccess.length}');
|
|
||||||
emailIdsCompleted.addAll(result.emailIdsSuccess);
|
|
||||||
sendPort.send(emailIdsCompleted);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log('MailboxIsolateWorker::_handleMarkAsMailboxRead(): TOTAL_READ: ${emailIdsCompleted.length}');
|
log('MailboxIsolateWorker::_handleMarkAsMailboxRead(): TOTAL_READ: ${emailIdsCompleted.length}');
|
||||||
return emailIdsCompleted;
|
return emailIdsCompleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<EmailId>> _handleMarkAsMailboxReadActionOnWeb(
|
Future<List<EmailId>> _handleMarkAsMailboxReadActionOnMainIsolate(
|
||||||
Session session,
|
Session session,
|
||||||
AccountId accountId,
|
AccountId accountId,
|
||||||
MailboxId mailboxId,
|
MailboxId mailboxId,
|
||||||
int totalEmailUnread,
|
int totalEmailUnread,
|
||||||
StreamController<Either<Failure, Success>> onProgressController
|
StreamController<Either<Failure, Success>> onProgressController,
|
||||||
) async {
|
) async {
|
||||||
|
final result = await _executeMarkAsMailboxRead(
|
||||||
|
threadAPI: _threadApi,
|
||||||
|
emailAPI: _emailApi,
|
||||||
|
session: session,
|
||||||
|
accountId: accountId,
|
||||||
|
mailboxId: mailboxId,
|
||||||
|
onProgress: (countRead) => onProgressController.add(Right(
|
||||||
|
UpdatingMarkAsMailboxReadState(
|
||||||
|
mailboxId: mailboxId,
|
||||||
|
totalUnread: totalEmailUnread,
|
||||||
|
countRead: countRead,
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
log('MailboxIsolateWorker::_handleMarkAsMailboxReadActionOnMainIsolate(): TOTAL_READ: ${result.length}');
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<List<EmailId>> _executeMarkAsMailboxRead({
|
||||||
|
required ThreadAPI threadAPI,
|
||||||
|
required EmailAPI emailAPI,
|
||||||
|
required Session session,
|
||||||
|
required AccountId accountId,
|
||||||
|
required MailboxId mailboxId,
|
||||||
|
required void Function(int countRead) onProgress,
|
||||||
|
}) async {
|
||||||
List<EmailId> emailIdsCompleted = List.empty(growable: true);
|
List<EmailId> emailIdsCompleted = List.empty(growable: true);
|
||||||
bool mailboxHasEmails = true;
|
bool mailboxHasEmails = true;
|
||||||
UTCDate? lastReceivedDate;
|
UTCDate? lastReceivedDate;
|
||||||
EmailId? lastEmailId;
|
EmailId? lastEmailId;
|
||||||
|
|
||||||
while (mailboxHasEmails) {
|
while (mailboxHasEmails) {
|
||||||
final emailResponse = await _threadApi
|
final emailResponse = await threadAPI
|
||||||
.getAllEmail(
|
.getAllEmail(
|
||||||
session,
|
session,
|
||||||
accountId,
|
accountId,
|
||||||
@@ -192,7 +171,7 @@ class MailboxIsolateWorker {
|
|||||||
});
|
});
|
||||||
final listEmailUnread = emailResponse.emailList;
|
final listEmailUnread = emailResponse.emailList;
|
||||||
|
|
||||||
log('MailboxIsolateWorker::_handleMarkAsMailboxReadActionOnWeb(): listEmailUnread: ${listEmailUnread?.length}');
|
log('MailboxIsolateWorker::_executeMarkAsMailboxRead(): listEmailUnread: ${listEmailUnread?.length}');
|
||||||
|
|
||||||
if (listEmailUnread == null || listEmailUnread.isEmpty) {
|
if (listEmailUnread == null || listEmailUnread.isEmpty) {
|
||||||
mailboxHasEmails = false;
|
mailboxHasEmails = false;
|
||||||
@@ -200,22 +179,19 @@ class MailboxIsolateWorker {
|
|||||||
lastEmailId = listEmailUnread.last.id;
|
lastEmailId = listEmailUnread.last.id;
|
||||||
lastReceivedDate = listEmailUnread.last.receivedAt;
|
lastReceivedDate = listEmailUnread.last.receivedAt;
|
||||||
|
|
||||||
final result = await _emailApi.markAsRead(
|
final result = await emailAPI.markAsRead(
|
||||||
session,
|
session,
|
||||||
accountId,
|
accountId,
|
||||||
listEmailUnread.listEmailIds,
|
listEmailUnread.listEmailIds,
|
||||||
ReadActions.markAsRead,
|
ReadActions.markAsRead,
|
||||||
);
|
);
|
||||||
log('MailboxIsolateWorker::_handleMarkAsMailboxReadActionOnWeb(): MARK_READ: ${result.emailIdsSuccess.length}');
|
log('MailboxIsolateWorker::_executeMarkAsMailboxRead(): MARK_READ: ${result.emailIdsSuccess.length}');
|
||||||
emailIdsCompleted.addAll(result.emailIdsSuccess);
|
emailIdsCompleted.addAll(result.emailIdsSuccess);
|
||||||
|
|
||||||
onProgressController.add(Right(UpdatingMarkAsMailboxReadState(
|
onProgress(emailIdsCompleted.length);
|
||||||
mailboxId: mailboxId,
|
|
||||||
totalUnread: totalEmailUnread,
|
|
||||||
countRead: emailIdsCompleted.length)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log('MailboxIsolateWorker::_handleMarkAsMailboxReadActionOnWeb(): TOTAL_READ: ${emailIdsCompleted.length}');
|
log('MailboxIsolateWorker::_executeMarkAsMailboxRead(): TOTAL_READ: ${emailIdsCompleted.length}');
|
||||||
return emailIdsCompleted;
|
return emailIdsCompleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,29 +206,27 @@ class MailboxIsolateWorker {
|
|||||||
throw const CanNotGetRootIsolateToken();
|
throw const CanNotGetRootIsolateToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
final countEmailsCompleted = await _isolateExecutor.execute(
|
final args = MoveFolderContentIsolateArguments(
|
||||||
arg1: MoveFolderContentIsolateArguments(
|
session: session,
|
||||||
session: session,
|
accountId: accountId,
|
||||||
accountId: accountId,
|
threadAPI: _threadApi,
|
||||||
threadAPI: _threadApi,
|
emailAPI: _emailApi,
|
||||||
emailAPI: _emailApi,
|
currentMailboxId: request.mailboxId,
|
||||||
currentMailboxId: request.mailboxId,
|
destinationMailboxId: request.destinationMailboxId,
|
||||||
destinationMailboxId: request.destinationMailboxId,
|
isolateToken: rootIsolateToken,
|
||||||
isolateToken: rootIsolateToken,
|
markAsRead: request.markAsRead,
|
||||||
markAsRead: request.markAsRead,
|
);
|
||||||
),
|
final countEmailsCompleted = await workerManager.executeWithPort<int, int>(
|
||||||
fun1: _moveFolderContentIsolateMethod,
|
_buildMoveFolderClosure(args),
|
||||||
notification: (value) {
|
onMessage: (value) {
|
||||||
if (value is int) {
|
log('$runtimeType::moveFolderContent(): Progress percent is ${value / request.totalEmails}');
|
||||||
log('$runtimeType::moveFolderContent(): Progress percent is ${value / request.totalEmails}');
|
onProgressController?.add(
|
||||||
onProgressController?.add(
|
Right<Failure, Success>(MoveFolderContentProgressState(
|
||||||
Right<Failure, Success>(MoveFolderContentProgressState(
|
request.mailboxId,
|
||||||
request.mailboxId,
|
value,
|
||||||
value,
|
request.totalEmails,
|
||||||
request.totalEmails,
|
)),
|
||||||
)),
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -263,9 +237,17 @@ class MailboxIsolateWorker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Future<List<EmailId>> Function(SendPort) _buildMarkAsReadClosure(
|
||||||
|
MailboxMarkAsReadArguments args,
|
||||||
|
) => (sendPort) => _handleMarkAsMailboxReadAction(args, sendPort);
|
||||||
|
|
||||||
|
static Future<int> Function(SendPort) _buildMoveFolderClosure(
|
||||||
|
MoveFolderContentIsolateArguments args,
|
||||||
|
) => (sendPort) => _moveFolderContentIsolateMethod(args, sendPort);
|
||||||
|
|
||||||
static Future<int> _moveFolderContentIsolateMethod(
|
static Future<int> _moveFolderContentIsolateMethod(
|
||||||
MoveFolderContentIsolateArguments args,
|
MoveFolderContentIsolateArguments args,
|
||||||
TypeSendPort sendPort,
|
SendPort sendPort,
|
||||||
) async {
|
) async {
|
||||||
final rootIsolateToken = args.isolateToken;
|
final rootIsolateToken = args.isolateToken;
|
||||||
BackgroundIsolateBinaryMessenger.ensureInitialized(rootIsolateToken);
|
BackgroundIsolateBinaryMessenger.ensureInitialized(rootIsolateToken);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:core/presentation/state/failure.dart';
|
import 'package:core/presentation/state/failure.dart';
|
||||||
import 'package:core/presentation/state/success.dart';
|
import 'package:core/presentation/state/success.dart';
|
||||||
@@ -30,9 +31,8 @@ import 'package:worker_manager/worker_manager.dart';
|
|||||||
class ThreadIsolateWorker {
|
class ThreadIsolateWorker {
|
||||||
final ThreadAPI _threadAPI;
|
final ThreadAPI _threadAPI;
|
||||||
final EmailAPI _emailAPI;
|
final EmailAPI _emailAPI;
|
||||||
final Executor _isolateExecutor;
|
|
||||||
|
|
||||||
ThreadIsolateWorker(this._threadAPI, this._emailAPI, this._isolateExecutor);
|
ThreadIsolateWorker(this._threadAPI, this._emailAPI);
|
||||||
|
|
||||||
Future<List<EmailId>> emptyMailboxFolder(
|
Future<List<EmailId>> emptyMailboxFolder(
|
||||||
Session session,
|
Session session,
|
||||||
@@ -41,31 +41,29 @@ class ThreadIsolateWorker {
|
|||||||
int totalEmails,
|
int totalEmails,
|
||||||
StreamController<dartz.Either<Failure, Success>> onProgressController
|
StreamController<dartz.Either<Failure, Success>> onProgressController
|
||||||
) async {
|
) async {
|
||||||
if (PlatformInfo.isWeb) {
|
if (PlatformInfo.isWeb || Platform.numberOfProcessors == 1) {
|
||||||
return _emptyMailboxFolderOnWeb(session, accountId, mailboxId, totalEmails, onProgressController);
|
return _emptyMailboxFolderOnMainIsolate(session, accountId, mailboxId, totalEmails, onProgressController);
|
||||||
} else {
|
} else {
|
||||||
final rootIsolateToken = RootIsolateToken.instance;
|
final rootIsolateToken = RootIsolateToken.instance;
|
||||||
if (rootIsolateToken == null) {
|
if (rootIsolateToken == null) {
|
||||||
throw const CanNotGetRootIsolateToken();
|
throw const CanNotGetRootIsolateToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
final result = await _isolateExecutor.execute(
|
final args = EmptyMailboxFolderArguments(
|
||||||
arg1: EmptyMailboxFolderArguments(
|
session,
|
||||||
session,
|
_threadAPI,
|
||||||
_threadAPI,
|
_emailAPI,
|
||||||
_emailAPI,
|
accountId,
|
||||||
accountId,
|
mailboxId,
|
||||||
mailboxId,
|
rootIsolateToken,
|
||||||
rootIsolateToken
|
);
|
||||||
),
|
final result = await workerManager.executeWithPort<List<EmailId>, int>(
|
||||||
fun1: _emptyMailboxFolderAction,
|
_buildEmptyMailboxClosure(args),
|
||||||
notification: (value) {
|
onMessage: (processedCount) {
|
||||||
if (value is List<EmailId>) {
|
log('ThreadIsolateWorker::emptyMailboxFolder(): processed $processedCount - totalEmails $totalEmails');
|
||||||
log('ThreadIsolateWorker::emptyMailboxFolder(): processed ${value.length} - totalEmails $totalEmails');
|
onProgressController.add(Right<Failure, Success>(EmptyingFolderState(
|
||||||
onProgressController.add(Right<Failure, Success>(EmptyingFolderState(
|
mailboxId, processedCount, totalEmails
|
||||||
mailboxId, value.length, totalEmails
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -77,9 +75,13 @@ class ThreadIsolateWorker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Future<List<EmailId>> Function(SendPort) _buildEmptyMailboxClosure(
|
||||||
|
EmptyMailboxFolderArguments args,
|
||||||
|
) => (sendPort) => _emptyMailboxFolderAction(args, sendPort);
|
||||||
|
|
||||||
static Future<List<EmailId>> _emptyMailboxFolderAction(
|
static Future<List<EmailId>> _emptyMailboxFolderAction(
|
||||||
EmptyMailboxFolderArguments args,
|
EmptyMailboxFolderArguments args,
|
||||||
TypeSendPort sendPort
|
SendPort sendPort,
|
||||||
) async {
|
) async {
|
||||||
final rootIsolateToken = args.isolateToken;
|
final rootIsolateToken = args.isolateToken;
|
||||||
BackgroundIsolateBinaryMessenger.ensureInitialized(rootIsolateToken);
|
BackgroundIsolateBinaryMessenger.ensureInitialized(rootIsolateToken);
|
||||||
@@ -119,7 +121,7 @@ class ThreadIsolateWorker {
|
|||||||
args.accountId,
|
args.accountId,
|
||||||
newEmailList.listEmailIds);
|
newEmailList.listEmailIds);
|
||||||
emailListCompleted.addAll(listEmailIdDeleted.emailIdsSuccess);
|
emailListCompleted.addAll(listEmailIdDeleted.emailIdsSuccess);
|
||||||
sendPort.send(emailListCompleted);
|
sendPort.send(emailListCompleted.length);
|
||||||
} else {
|
} else {
|
||||||
hasEmails = false;
|
hasEmails = false;
|
||||||
}
|
}
|
||||||
@@ -128,7 +130,7 @@ class ThreadIsolateWorker {
|
|||||||
return emailListCompleted;
|
return emailListCompleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<EmailId>> _emptyMailboxFolderOnWeb(
|
Future<List<EmailId>> _emptyMailboxFolderOnMainIsolate(
|
||||||
Session session,
|
Session session,
|
||||||
AccountId accountId,
|
AccountId accountId,
|
||||||
MailboxId mailboxId,
|
MailboxId mailboxId,
|
||||||
@@ -158,7 +160,7 @@ class ThreadIsolateWorker {
|
|||||||
newEmailList = newEmailList.where((email) => email.id != lastEmail!.id).toList();
|
newEmailList = newEmailList.where((email) => email.id != lastEmail!.id).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
log('ThreadIsolateWorker::_emptyMailboxFolderOnWeb(): ${newEmailList.length}');
|
log('ThreadIsolateWorker::_emptyMailboxFolderOnMainIsolate(): ${newEmailList.length}');
|
||||||
|
|
||||||
if (newEmailList.isNotEmpty) {
|
if (newEmailList.isNotEmpty) {
|
||||||
lastEmail = newEmailList.last;
|
lastEmail = newEmailList.last;
|
||||||
@@ -176,7 +178,7 @@ class ThreadIsolateWorker {
|
|||||||
hasEmails = false;
|
hasEmails = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log('ThreadIsolateWorker::_emptyMailboxFolderOnWeb(): TOTAL_REMOVE: ${emailListCompleted.length}');
|
log('ThreadIsolateWorker::_emptyMailboxFolderOnMainIsolate(): TOTAL_REMOVE: ${emailListCompleted.length}');
|
||||||
return emailListCompleted;
|
return emailListCompleted;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,12 +31,10 @@ class FileUploader {
|
|||||||
static const String filePathExtraKey = 'path';
|
static const String filePathExtraKey = 'path';
|
||||||
|
|
||||||
final DioClient _dioClient;
|
final DioClient _dioClient;
|
||||||
final worker.Executor _isolateExecutor;
|
|
||||||
final FileUtils _fileUtils;
|
final FileUtils _fileUtils;
|
||||||
|
|
||||||
FileUploader(
|
FileUploader(
|
||||||
this._dioClient,
|
this._dioClient,
|
||||||
this._isolateExecutor,
|
|
||||||
this._fileUtils,
|
this._fileUtils,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -49,8 +47,8 @@ class FileUploader {
|
|||||||
StreamController<Either<Failure, Success>>? onSendController,
|
StreamController<Either<Failure, Success>>? onSendController,
|
||||||
}
|
}
|
||||||
) async {
|
) async {
|
||||||
if (PlatformInfo.isWeb) {
|
if (PlatformInfo.isWeb || Platform.numberOfProcessors == 1) {
|
||||||
return _handleUploadAttachmentActionOnWeb(
|
return _handleUploadAttachmentActionOnMainIsolate(
|
||||||
uploadId,
|
uploadId,
|
||||||
fileInfo,
|
fileInfo,
|
||||||
uploadUri,
|
uploadUri,
|
||||||
@@ -63,31 +61,33 @@ class FileUploader {
|
|||||||
throw const CanNotGetRootIsolateToken();
|
throw const CanNotGetRootIsolateToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
return await _isolateExecutor.execute(
|
final args = UploadFileArguments(
|
||||||
arg1: UploadFileArguments(
|
_dioClient,
|
||||||
_dioClient,
|
_fileUtils,
|
||||||
_fileUtils,
|
uploadId,
|
||||||
uploadId,
|
fileInfo,
|
||||||
fileInfo,
|
uploadUri,
|
||||||
uploadUri,
|
rootIsolateToken,
|
||||||
rootIsolateToken,
|
);
|
||||||
),
|
return await worker.workerManager.executeWithPort<Attachment, Success>(
|
||||||
fun1: _handleUploadAttachmentAction,
|
_buildUploadClosure(args),
|
||||||
notification: (value) {
|
onMessage: (value) {
|
||||||
if (value is Success) {
|
log('FileUploader::uploadAttachment(): onUpdateProgress: $value');
|
||||||
log('FileUploader::uploadAttachment(): onUpdateProgress: $value');
|
onSendController?.add(Right(value));
|
||||||
onSendController?.add(Right(value));
|
},
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
.then((value) => value)
|
.then((value) => value)
|
||||||
.catchError((error) => throw error);
|
.catchError((error) => throw error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Future<Attachment> Function(worker.SendPort) _buildUploadClosure(
|
||||||
|
UploadFileArguments args,
|
||||||
|
) => (sendPort) => _handleUploadAttachmentAction(args, sendPort);
|
||||||
|
|
||||||
static Future<Attachment> _handleUploadAttachmentAction(
|
static Future<Attachment> _handleUploadAttachmentAction(
|
||||||
UploadFileArguments argsUpload,
|
UploadFileArguments argsUpload,
|
||||||
worker.TypeSendPort sendPort
|
worker.SendPort sendPort,
|
||||||
) async {
|
) async {
|
||||||
try {
|
try {
|
||||||
final rootIsolateToken = argsUpload.isolateToken;
|
final rootIsolateToken = argsUpload.isolateToken;
|
||||||
@@ -159,7 +159,7 @@ class FileUploader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Attachment> _handleUploadAttachmentActionOnWeb(
|
Future<Attachment> _handleUploadAttachmentActionOnMainIsolate(
|
||||||
UploadTaskId uploadId,
|
UploadTaskId uploadId,
|
||||||
FileInfo fileInfo,
|
FileInfo fileInfo,
|
||||||
Uri uploadUri,
|
Uri uploadUri,
|
||||||
@@ -188,7 +188,7 @@ class FileUploader {
|
|||||||
data: BodyBytesStream.fromBytes(fileInfo.bytes!),
|
data: BodyBytesStream.fromBytes(fileInfo.bytes!),
|
||||||
cancelToken: cancelToken,
|
cancelToken: cancelToken,
|
||||||
onSendProgress: (count, total) {
|
onSendProgress: (count, total) {
|
||||||
log('FileUploader::_handleUploadAttachmentActionOnWeb():onSendProgress: FILE[${uploadId.id}] : { PROGRESS = $count | TOTAL = $total}');
|
log('FileUploader::_handleUploadAttachmentActionOnMainIsolate():onSendProgress: FILE[${uploadId.id}] : { PROGRESS = $count | TOTAL = $total}');
|
||||||
onSendController?.add(
|
onSendController?.add(
|
||||||
Right(UploadingAttachmentUploadState(
|
Right(UploadingAttachmentUploadState(
|
||||||
uploadId,
|
uploadId,
|
||||||
@@ -198,7 +198,7 @@ class FileUploader {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
log('FileUploader::_handleUploadAttachmentActionOnWeb(): RESULT_JSON = $resultJson');
|
log('FileUploader::_handleUploadAttachmentActionOnMainIsolate(): RESULT_JSON = $resultJson');
|
||||||
if (fileInfo.mimeType == FileUtils.TEXT_PLAIN_MIME_TYPE) {
|
if (fileInfo.mimeType == FileUtils.TEXT_PLAIN_MIME_TYPE) {
|
||||||
final fileCharset = await _fileUtils.getCharsetFromBytes(fileInfo.bytes!);
|
final fileCharset = await _fileUtils.getCharsetFromBytes(fileInfo.bytes!);
|
||||||
return _parsingResponse(
|
return _parsingResponse(
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ import 'package:tmail_ui_user/main/exceptions/thrower/remote_exception_thrower.d
|
|||||||
import 'package:tmail_ui_user/main/exceptions/thrower/send_email_exception_thrower.dart';
|
import 'package:tmail_ui_user/main/exceptions/thrower/send_email_exception_thrower.dart';
|
||||||
import 'package:tmail_ui_user/main/utils/ios_sharing_manager.dart';
|
import 'package:tmail_ui_user/main/utils/ios_sharing_manager.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
import 'package:worker_manager/worker_manager.dart';
|
|
||||||
|
|
||||||
class NetworkBindings extends Bindings {
|
class NetworkBindings extends Bindings {
|
||||||
|
|
||||||
@@ -85,7 +84,6 @@ class NetworkBindings extends Bindings {
|
|||||||
Get.find<OIDCHttpClient>(),
|
Get.find<OIDCHttpClient>(),
|
||||||
Get.find<MailboxCacheManager>(),
|
Get.find<MailboxCacheManager>(),
|
||||||
));
|
));
|
||||||
Get.put(Executor());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _bindingInterceptors() {
|
void _bindingInterceptors() {
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import 'package:tmail_ui_user/features/upload/data/network/file_uploader.dart';
|
|||||||
import 'package:tmail_ui_user/main/bindings/network/binding_tag.dart';
|
import 'package:tmail_ui_user/main/bindings/network/binding_tag.dart';
|
||||||
import 'package:tmail_ui_user/main/utils/ios_sharing_manager.dart';
|
import 'package:tmail_ui_user/main/utils/ios_sharing_manager.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
import 'package:worker_manager/worker_manager.dart';
|
|
||||||
|
|
||||||
class NetworkIsolateBindings extends Bindings {
|
class NetworkIsolateBindings extends Bindings {
|
||||||
|
|
||||||
@@ -96,16 +95,13 @@ class NetworkIsolateBindings extends Bindings {
|
|||||||
Get.put(ThreadIsolateWorker(
|
Get.put(ThreadIsolateWorker(
|
||||||
Get.find<ThreadAPI>(tag: PlatformInfo.isMobile ? BindingTag.isolateTag : null),
|
Get.find<ThreadAPI>(tag: PlatformInfo.isMobile ? BindingTag.isolateTag : null),
|
||||||
Get.find<EmailAPI>(tag: PlatformInfo.isMobile ? BindingTag.isolateTag : null),
|
Get.find<EmailAPI>(tag: PlatformInfo.isMobile ? BindingTag.isolateTag : null),
|
||||||
Get.find<Executor>(),
|
|
||||||
));
|
));
|
||||||
Get.put(MailboxIsolateWorker(
|
Get.put(MailboxIsolateWorker(
|
||||||
Get.find<ThreadAPI>(tag: PlatformInfo.isMobile ? BindingTag.isolateTag : null),
|
Get.find<ThreadAPI>(tag: PlatformInfo.isMobile ? BindingTag.isolateTag : null),
|
||||||
Get.find<EmailAPI>(tag: PlatformInfo.isMobile ? BindingTag.isolateTag : null),
|
Get.find<EmailAPI>(tag: PlatformInfo.isMobile ? BindingTag.isolateTag : null),
|
||||||
Get.find<Executor>(),
|
|
||||||
));
|
));
|
||||||
Get.put(FileUploader(
|
Get.put(FileUploader(
|
||||||
Get.find<DioClient>(tag: PlatformInfo.isMobile ? BindingTag.isolateTag : null),
|
Get.find<DioClient>(tag: PlatformInfo.isMobile ? BindingTag.isolateTag : null),
|
||||||
Get.find<Executor>(),
|
|
||||||
Get.find<FileUtils>(),
|
Get.find<FileUtils>(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import 'package:core/presentation/utils/theme_utils.dart';
|
|||||||
import 'package:core/utils/build_utils.dart';
|
import 'package:core/utils/build_utils.dart';
|
||||||
import 'package:core/utils/platform_info.dart';
|
import 'package:core/utils/platform_info.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:get/get.dart';
|
|
||||||
import 'package:tmail_ui_user/features/caching/config/hive_cache_config.dart';
|
import 'package:tmail_ui_user/features/caching/config/hive_cache_config.dart';
|
||||||
import 'package:tmail_ui_user/main.dart';
|
import 'package:tmail_ui_user/main.dart';
|
||||||
import 'package:tmail_ui_user/main/bindings/main_bindings.dart';
|
import 'package:tmail_ui_user/main/bindings/main_bindings.dart';
|
||||||
@@ -25,7 +24,10 @@ Future<void> runTmailPreload() async {
|
|||||||
if (PlatformInfo.isWeb) AssetPreloader.preloadHtmlEditorAssets(),
|
if (PlatformInfo.isWeb) AssetPreloader.preloadHtmlEditorAssets(),
|
||||||
], eagerError: false);
|
], eagerError: false);
|
||||||
|
|
||||||
await Get.find<Executor>().warmUp(log: BuildUtils.isDebugMode);
|
if (PlatformInfo.isMobile) {
|
||||||
|
await workerManager.init(dynamicSpawning: true);
|
||||||
|
workerManager.log = BuildUtils.isDebugMode;
|
||||||
|
}
|
||||||
await CozyIntegration.integrateCozy();
|
await CozyIntegration.integrateCozy();
|
||||||
await HiveCacheConfig.instance.initializeEncryptionKey();
|
await HiveCacheConfig.instance.initializeEncryptionKey();
|
||||||
|
|
||||||
|
|||||||
+6
-45
@@ -773,14 +773,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.0.2"
|
version: "5.0.2"
|
||||||
flutter_downloader:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: flutter_downloader
|
|
||||||
sha256: "93a9ddbd561f8a3f5483b4189453fba145a0a1014a88143c96a966296b78a118"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.12.0"
|
|
||||||
flutter_file_dialog:
|
flutter_file_dialog:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -2583,43 +2575,12 @@ packages:
|
|||||||
worker_manager:
|
worker_manager:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: worker_manager
|
path: "."
|
||||||
sha256: "42501e49ee0acad9eeda562984e3dcfe6fe3d26f2d8dc410bd76308a86447eb5"
|
ref: "hotfix/worker-init-memory-leak"
|
||||||
url: "https://pub.dev"
|
resolved-ref: dd04544217c9fcc08b2a32634583f38d22cc2309
|
||||||
source: hosted
|
url: "https://github.com/linagora/worker_manager.git"
|
||||||
version: "5.0.3"
|
source: git
|
||||||
workmanager:
|
version: "7.2.7"
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: workmanager
|
|
||||||
sha256: "065673b2a465865183093806925419d311a9a5e0995aa74ccf8920fd695e2d10"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.9.0+3"
|
|
||||||
workmanager_android:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: workmanager_android
|
|
||||||
sha256: "9ae744db4ef891f5fcd2fb8671fccc712f4f96489a487a1411e0c8675e5e8cb7"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.9.0+2"
|
|
||||||
workmanager_apple:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: workmanager_apple
|
|
||||||
sha256: "1cc12ae3cbf5535e72f7ba4fde0c12dd11b757caf493a28e22d684052701f2ca"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.9.1+2"
|
|
||||||
workmanager_platform_interface:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: workmanager_platform_interface
|
|
||||||
sha256: f40422f10b970c67abb84230b44da22b075147637532ac501729256fcea10a47
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.9.1+1"
|
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
+5
-5
@@ -143,8 +143,6 @@ dependencies:
|
|||||||
|
|
||||||
uuid: 3.0.7
|
uuid: 3.0.7
|
||||||
|
|
||||||
flutter_downloader: 1.12.0
|
|
||||||
|
|
||||||
external_path: 2.2.0
|
external_path: 2.2.0
|
||||||
|
|
||||||
path_provider: 2.1.5
|
path_provider: 2.1.5
|
||||||
@@ -177,7 +175,11 @@ dependencies:
|
|||||||
|
|
||||||
percent_indicator: 4.2.2
|
percent_indicator: 4.2.2
|
||||||
|
|
||||||
worker_manager: 5.0.3
|
# TODO: Replace with upstream when https://github.com/dsrenesanse/worker_manager/pull/123 is merged
|
||||||
|
worker_manager:
|
||||||
|
git:
|
||||||
|
url: https://github.com/linagora/worker_manager.git
|
||||||
|
ref: hotfix/worker-init-memory-leak
|
||||||
|
|
||||||
async: 2.13.0
|
async: 2.13.0
|
||||||
|
|
||||||
@@ -211,8 +213,6 @@ dependencies:
|
|||||||
|
|
||||||
intl: 0.20.2
|
intl: 0.20.2
|
||||||
|
|
||||||
workmanager: 0.9.0+3
|
|
||||||
|
|
||||||
flutter_typeahead: 5.0.2
|
flutter_typeahead: 5.0.2
|
||||||
|
|
||||||
flutter_keyboard_visibility: 6.0.0
|
flutter_keyboard_visibility: 6.0.0
|
||||||
|
|||||||
@@ -52,7 +52,6 @@ import 'package:tmail_ui_user/main/universal_import/html_stub.dart';
|
|||||||
import 'package:tmail_ui_user/main/utils/toast_manager.dart';
|
import 'package:tmail_ui_user/main/utils/toast_manager.dart';
|
||||||
import 'package:tmail_ui_user/main/utils/twake_app_manager.dart';
|
import 'package:tmail_ui_user/main/utils/twake_app_manager.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
import 'package:worker_manager/worker_manager.dart';
|
|
||||||
|
|
||||||
import 'identity_creator_controller_test.mocks.dart';
|
import 'identity_creator_controller_test.mocks.dart';
|
||||||
|
|
||||||
@@ -76,7 +75,6 @@ import 'identity_creator_controller_test.mocks.dart';
|
|||||||
MockSpec<GetAllIdentitiesInteractor>(),
|
MockSpec<GetAllIdentitiesInteractor>(),
|
||||||
MockSpec<IdentityUtils>(),
|
MockSpec<IdentityUtils>(),
|
||||||
MockSpec<DioClient>(),
|
MockSpec<DioClient>(),
|
||||||
MockSpec<Executor>(),
|
|
||||||
MockSpec<FileUtils>(),
|
MockSpec<FileUtils>(),
|
||||||
MockSpec<FileUploader>(),
|
MockSpec<FileUploader>(),
|
||||||
MockSpec<RemoteExceptionThrower>(),
|
MockSpec<RemoteExceptionThrower>(),
|
||||||
@@ -159,7 +157,6 @@ void main() {
|
|||||||
mockSaveIdentityCacheOnWebInteractor = MockSaveIdentityCacheOnWebInteractor();
|
mockSaveIdentityCacheOnWebInteractor = MockSaveIdentityCacheOnWebInteractor();
|
||||||
|
|
||||||
Get.put<DioClient>(MockDioClient(), tag: BindingTag.isolateTag);
|
Get.put<DioClient>(MockDioClient(), tag: BindingTag.isolateTag);
|
||||||
Get.put<Executor>(MockExecutor());
|
|
||||||
Get.put<FileUtils>(MockFileUtils());
|
Get.put<FileUtils>(MockFileUtils());
|
||||||
Get.put<FileUploader>(MockFileUploader());
|
Get.put<FileUploader>(MockFileUploader());
|
||||||
Get.put<RemoteExceptionThrower>(MockRemoteExceptionThrower());
|
Get.put<RemoteExceptionThrower>(MockRemoteExceptionThrower());
|
||||||
|
|||||||
Reference in New Issue
Block a user