Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TF-2177 Download attachment file is not working #2283

Merged
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 1 addition & 22 deletions lib/features/base/mixin/app_loader_mixin.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@

import 'package:core/core.dart';
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:percent_indicator/circular_percent_indicator.dart';
import 'package:percent_indicator/linear_percent_indicator.dart';

mixin AppLoaderMixin {
Expand All @@ -22,18 +21,6 @@ mixin AppLoaderMixin {
backgroundColor: AppColor.colorBgMailboxSelected));
}

Widget circularPercentLoadingWidget(double percent) {
return Center(
child: CircularPercentIndicator(
percent: percent > 1.0 ? 1.0 : percent,
backgroundColor: AppColor.colorBgMailboxSelected,
progressColor: AppColor.primaryColor,
lineWidth: 3,
radius: 14,
)
);
}

Widget horizontalPercentLoadingWidget(double percent) {
return Center(
child: LinearPercentIndicator(
Expand All @@ -44,12 +31,4 @@ mixin AppLoaderMixin {
progressColor: AppColor.primaryColor,
));
}

Widget loadingWidgetWithSizeColor({double? size, Color? color}) {
return Center(child: SizedBox(
width: size ?? 24,
height: size ?? 24,
child: CircularProgressIndicator(
color: color ?? AppColor.colorLoading)));
}
}
3 changes: 3 additions & 0 deletions lib/features/caching/caching_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ class CachingManager {
Future<void> onUpgradeCache(int oldVersion, int newVersion) async {
log('CachingManager::onUpgradeCache():oldVersion $oldVersion | newVersion: $newVersion');
await clearData();
if (oldVersion > 0 && oldVersion < newVersion && newVersion == 7) {
await clearAll();
}
await storeCacheVersion(newVersion);
}

Expand Down
2 changes: 1 addition & 1 deletion lib/features/caching/config/cache_version.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@

class CacheVersion {
static const int hiveDBVersion = 6;
static const int hiveDBVersion = 7;
}
6 changes: 5 additions & 1 deletion lib/features/email/data/network/email_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,11 @@ class EmailAPI with HandleSetErrorMixin {
headers: headerParam,
responseType: ResponseType.bytes),
onReceiveProgress: (downloaded, total) {
final progress = (downloaded / total) * 100;
log('DownloadClient::downloadFileForWeb(): downloaded = $downloaded | total: $total');
double progress = 0;
if (downloaded > 0 && total > downloaded) {
progress = (downloaded / total) * 100;
}
log('DownloadClient::downloadFileForWeb(): progress = ${progress.round()}%');
onReceiveController.add(Right(DownloadingAttachmentForWeb(
taskId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,11 @@ class DownloadAttachmentForWebSuccess extends UIState {

class DownloadAttachmentForWebFailure extends FeatureFailure {

final DownloadTaskId taskId;
final DownloadTaskId? taskId;

DownloadAttachmentForWebFailure(this.taskId, dynamic exception) : super(exception: exception);
DownloadAttachmentForWebFailure({
this.taskId, dynamic exception
}) : super(exception: exception);

@override
List<Object?> get props => [taskId, ...super.props];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,39 +45,38 @@ class DownloadAttachmentForWebInteractor {

if (currentAccount.authenticationType == AuthenticationType.oidc) {
final tokenOidc = await _authenticationOIDCRepository.getStoredTokenOIDC(currentAccount.id);
accountRequest = AccountRequest(
token: tokenOidc.toToken(),
authenticationType: AuthenticationType.oidc);
accountRequest = AccountRequest.withOidc(token: tokenOidc.toToken());
} else {
final authenticationInfoCache = await credentialRepository.getAuthenticationInfoStored();
if (authenticationInfoCache != null) {
accountRequest = AccountRequest(
userName: UserName(authenticationInfoCache.username),
password: Password(authenticationInfoCache.password),
authenticationType: AuthenticationType.basic);
}
accountRequest = AccountRequest.withBasic(
userName: UserName(authenticationInfoCache.username),
password: Password(authenticationInfoCache.password),
);
}

if (accountRequest != null) {
final bytesDownloaded = await emailRepository.downloadAttachmentForWeb(
taskId,
attachment,
accountId,
baseDownloadUrl,
accountRequest,
onReceiveController);
final bytesDownloaded = await emailRepository.downloadAttachmentForWeb(
taskId,
attachment,
accountId,
baseDownloadUrl,
accountRequest,
onReceiveController
);

yield Right<Failure, Success>(DownloadAttachmentForWebSuccess(
taskId,
attachment,
bytesDownloaded));
} else {
yield Left<Failure, Success>(DownloadAttachmentForWebFailure(taskId, null));
}
} catch (exception) {
yield Left<Failure, Success>(DownloadAttachmentForWebFailure(
yield Right<Failure, Success>(
DownloadAttachmentForWebSuccess(
taskId,
exception));
attachment,
bytesDownloaded
)
);
} catch (exception) {
yield Left<Failure, Success>(
DownloadAttachmentForWebFailure(
taskId: taskId,
exception: exception
)
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,32 +46,25 @@ class DownloadAttachmentsInteractor {

if (currentAccount.authenticationType == AuthenticationType.oidc) {
final tokenOidc = await _authenticationOIDCRepository.getStoredTokenOIDC(currentAccount.id);
accountRequest = AccountRequest(
token: tokenOidc.toToken(),
authenticationType: AuthenticationType.oidc);
accountRequest = AccountRequest.withOidc(token: tokenOidc.toToken());
} else {
final authenticationInfoCache = await credentialRepository.getAuthenticationInfoStored();
if (authenticationInfoCache != null) {
accountRequest = AccountRequest(
userName: UserName(authenticationInfoCache.username),
password: Password(authenticationInfoCache.password),
authenticationType: AuthenticationType.basic);
}
accountRequest = AccountRequest.withBasic(
userName: UserName(authenticationInfoCache.username),
password: Password(authenticationInfoCache.password),
);
}

if (accountRequest != null) {
final taskIds = await emailRepository.downloadAttachments(
attachments,
accountId,
baseDownloadUrl,
accountRequest);
final taskIds = await emailRepository.downloadAttachments(
attachments,
accountId,
baseDownloadUrl,
accountRequest
);

yield Right<Failure, Success>(DownloadAttachmentsSuccess(taskIds));
} else {
yield Left<Failure, Success>(DownloadAttachmentsFailure(null));
}
yield Right<Failure, Success>(DownloadAttachmentsSuccess(taskIds));
} catch (exception) {
log('DownloadAttachmentsInteractor::execute(): $exception');
logError('DownloadAttachmentsInteractor::execute(): $exception');
if (exception is DownloadAttachmentHasTokenExpiredException &&
exception.refreshToken.isNotEmpty) {
yield* _retryDownloadAttachments(
Expand Down Expand Up @@ -101,9 +94,10 @@ class DownloadAttachmentsInteractor {
oidcConfig.scopes,
refreshToken);

await _accountRepository.deleteCurrentAccount(accountCurrent.id);

await Future.wait([
_authenticationOIDCRepository.persistTokenOIDC(newTokenOIDC),
_accountRepository.deleteCurrentAccount(accountCurrent.id),
_accountRepository.setCurrentAccount(PersonalAccount(
newTokenOIDC.tokenIdHash,
AuthenticationType.oidc,
Expand All @@ -117,9 +111,7 @@ class DownloadAttachmentsInteractor {
newToken: newTokenOIDC.toToken(),
newConfig: oidcConfig);

final accountRequest = AccountRequest(
token: newTokenOIDC.toToken(),
authenticationType: AuthenticationType.oidc);
final accountRequest = AccountRequest.withOidc(token: newTokenOIDC.toToken());

final taskIds = await emailRepository.downloadAttachments(
attachments,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,31 +38,24 @@ class ExportAttachmentInteractor {

if (currentAccount.authenticationType == AuthenticationType.oidc) {
final tokenOidc = await _authenticationOIDCRepository.getStoredTokenOIDC(currentAccount.id);
accountRequest = AccountRequest(
token: tokenOidc.toToken(),
authenticationType: AuthenticationType.oidc);
accountRequest = AccountRequest.withOidc(token: tokenOidc.toToken());
} else {
final authenticationInfoCache = await credentialRepository.getAuthenticationInfoStored();
if (authenticationInfoCache != null) {
accountRequest = AccountRequest(
userName: UserName(authenticationInfoCache.username),
password: Password(authenticationInfoCache.password),
authenticationType: AuthenticationType.basic);
}
accountRequest = AccountRequest.withBasic(
userName: UserName(authenticationInfoCache.username),
password: Password(authenticationInfoCache.password),
);
}

if (accountRequest != null) {
final downloadedResponse = await emailRepository.exportAttachment(
attachment,
accountId,
baseDownloadUrl,
accountRequest,
cancelToken);
final downloadedResponse = await emailRepository.exportAttachment(
attachment,
accountId,
baseDownloadUrl,
accountRequest,
cancelToken
);

yield Right<Failure, Success>(ExportAttachmentSuccess(downloadedResponse));
} else {
yield Left<Failure, Success>(ExportAttachmentFailure(null));
}
yield Right<Failure, Success>(ExportAttachmentSuccess(downloadedResponse));
} catch (exception) {
log('ExportAttachmentInteractor::execute(): exception: $exception');
yield Left<Failure, Success>(ExportAttachmentFailure(exception));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ import 'package:tmail_ui_user/features/manage_account/domain/usecases/create_new
import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_all_identities_interactor.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/extensions/datetime_extension.dart';
import 'package:tmail_ui_user/features/rules_filter_creator/presentation/model/rules_filter_creator_arguments.dart';
import 'package:tmail_ui_user/features/session/data/exceptions/session_exceptions.dart';
import 'package:tmail_ui_user/features/thread/domain/constants/thread_constants.dart';
import 'package:tmail_ui_user/features/thread/presentation/model/delete_action_type.dart';
import 'package:tmail_ui_user/main/error/capability_validator.dart';
Expand Down Expand Up @@ -698,15 +699,20 @@ class SingleEmailController extends BaseController with AppLoaderMixin {

void _downloadAttachmentForWebAction(BuildContext context, Attachment attachment) async {
final accountId = mailboxDashBoardController.accountId.value;
if (accountId != null && mailboxDashBoardController.sessionCurrent != null) {
final baseDownloadUrl = mailboxDashBoardController.sessionCurrent!.getDownloadUrl(jmapUrl: _dynamicUrlInterceptors.jmapUrl);
final session = mailboxDashBoardController.sessionCurrent;
if (accountId != null && session != null) {
final baseDownloadUrl = session.getDownloadUrl(jmapUrl: _dynamicUrlInterceptors.jmapUrl);
final generateTaskId = DownloadTaskId(_uuid.v4());
consumeState(_downloadAttachmentForWebInteractor.execute(
generateTaskId,
attachment,
accountId,
baseDownloadUrl,
_downloadProgressStateController));
} else {
consumeState(Stream.value(
Left(DownloadAttachmentForWebFailure(exception: NotFoundSessionException()))
));
}
}

Expand All @@ -721,7 +727,9 @@ class SingleEmailController extends BaseController with AppLoaderMixin {

void _downloadAttachmentForWebFailureAction(DownloadAttachmentForWebFailure failure) {
log('SingleEmailController::_downloadAttachmentForWebFailureAction(): $failure');
mailboxDashBoardController.deleteDownloadTask(failure.taskId);
if (failure.taskId != null) {
mailboxDashBoardController.deleteDownloadTask(failure.taskId!);
}

if (currentOverlayContext != null && currentContext != null) {
_appToast.showToastErrorMessage(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,21 @@ class HiveAccountDatasourceImpl extends AccountDatasource {
@override
Future<PersonalAccount> getCurrentAccount() {
return Future.sync(() async {
return await _accountCacheManager.getSelectedAccount();
return await _accountCacheManager.getCurrentAccount();
}).catchError(_exceptionThrower.throwException);
}

@override
Future<void> setCurrentAccount(PersonalAccount newCurrentAccount) {
return Future.sync(() async {
return await _accountCacheManager.setSelectedAccount(newCurrentAccount);
return await _accountCacheManager.setCurrentAccount(newCurrentAccount);
}).catchError(_exceptionThrower.throwException);
}

@override
Future<void> deleteCurrentAccount(String accountId) {
return Future.sync(() async {
return await _accountCacheManager.deleteSelectedAccount(accountId);
return await _accountCacheManager.deleteCurrentAccount(accountId);
}).catchError(_exceptionThrower.throwException);
}
}
22 changes: 22 additions & 0 deletions lib/features/login/data/extensions/account_cache_extensions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,26 @@ extension AccountCacheExtension on AccountCache {
apiUrl: apiUrl,
userName: userName != null ? UserName(userName!) : null);
}

AccountCache unselected() {
return AccountCache(
id,
authenticationType,
isSelected: false,
accountId: accountId,
apiUrl: apiUrl,
userName: userName
);
}

AccountCache emptyId() {
return AccountCache(
'',
authenticationType,
isSelected: false,
accountId: accountId,
apiUrl: apiUrl,
userName: userName
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import 'package:collection/collection.dart';
import 'package:core/utils/app_logger.dart';
import 'package:tmail_ui_user/features/login/data/extensions/account_cache_extensions.dart';
import 'package:tmail_ui_user/features/login/data/model/account_cache.dart';

extension ListAccountCacheExtension on List<AccountCache> {
List<AccountCache> unselected() => map((account) => account.unselected()).toList();

List<AccountCache> removeDuplicated() {
final listAccountId = map((account) => account.accountId).whereNotNull().toSet();
hoangdat marked this conversation as resolved.
Show resolved Hide resolved
log('ListAccountCacheExtension::removeDuplicated:listAccountId: $listAccountId');
retainWhere((account) => listAccountId.remove(account.accountId));
log('ListAccountCacheExtension::removeDuplicated:listAccount: $this');
return this;
}

Map<String, AccountCache> toMap() {
return {
for (var account in this)
account.id: account
};
}
}
Loading
Loading