TF-3488 Add hide download taskbar feature
This commit is contained in:
@@ -11,32 +11,22 @@ class CircleLoadingWidget extends StatelessWidget {
|
|||||||
super.key,
|
super.key,
|
||||||
this.size,
|
this.size,
|
||||||
this.padding,
|
this.padding,
|
||||||
this.strokeWidth
|
this.strokeWidth,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (padding != null) {
|
final loadingSize = size ?? CircleLoadingWidgetStyles.size;
|
||||||
return Padding(
|
final loadingStrokeWidth = strokeWidth ?? CircleLoadingWidgetStyles.width;
|
||||||
padding: padding!,
|
|
||||||
child: SizedBox(
|
return Container(
|
||||||
width: size ?? CircleLoadingWidgetStyles.size,
|
padding: padding,
|
||||||
height: size ?? CircleLoadingWidgetStyles.size,
|
width: loadingSize,
|
||||||
child: CircularProgressIndicator(
|
height: loadingSize,
|
||||||
color: CircleLoadingWidgetStyles.progressColor,
|
child: CircularProgressIndicator(
|
||||||
strokeWidth: strokeWidth ?? CircleLoadingWidgetStyles.width,
|
color: CircleLoadingWidgetStyles.progressColor,
|
||||||
)
|
strokeWidth: loadingStrokeWidth,
|
||||||
),
|
)
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
return SizedBox(
|
|
||||||
width: size ?? CircleLoadingWidgetStyles.size,
|
|
||||||
height: size ?? CircleLoadingWidgetStyles.size,
|
|
||||||
child: CircularProgressIndicator(
|
|
||||||
color: CircleLoadingWidgetStyles.progressColor,
|
|
||||||
strokeWidth: strokeWidth ?? CircleLoadingWidgetStyles.width,
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
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';
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
import 'package:model/download/download_task_id.dart';
|
import 'package:model/download/download_task_id.dart';
|
||||||
import 'package:model/email/attachment.dart';
|
import 'package:model/email/attachment.dart';
|
||||||
|
|
||||||
@@ -10,11 +11,12 @@ class StartDownloadAttachmentForWeb extends UIState {
|
|||||||
|
|
||||||
final DownloadTaskId taskId;
|
final DownloadTaskId taskId;
|
||||||
final Attachment attachment;
|
final Attachment attachment;
|
||||||
|
final CancelToken? cancelToken;
|
||||||
|
|
||||||
StartDownloadAttachmentForWeb(this.taskId, this.attachment);
|
StartDownloadAttachmentForWeb(this.taskId, this.attachment, [this.cancelToken]);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object> get props => [taskId, attachment];
|
List<Object?> get props => [taskId, attachment, cancelToken];
|
||||||
}
|
}
|
||||||
|
|
||||||
class DownloadingAttachmentForWeb extends UIState {
|
class DownloadingAttachmentForWeb extends UIState {
|
||||||
@@ -59,13 +61,15 @@ class DownloadAttachmentForWebFailure extends FeatureFailure {
|
|||||||
|
|
||||||
final DownloadTaskId? taskId;
|
final DownloadTaskId? taskId;
|
||||||
final Attachment? attachment;
|
final Attachment? attachment;
|
||||||
|
final CancelToken? cancelToken;
|
||||||
|
|
||||||
DownloadAttachmentForWebFailure({
|
DownloadAttachmentForWebFailure({
|
||||||
this.attachment,
|
this.attachment,
|
||||||
this.taskId,
|
this.taskId,
|
||||||
dynamic exception
|
this.cancelToken,
|
||||||
}) : super(exception: exception);
|
super.exception
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [attachment, taskId, ...super.props];
|
List<Object?> get props => [attachment, taskId, cancelToken, ...super.props];
|
||||||
}
|
}
|
||||||
@@ -38,8 +38,8 @@ class DownloadAttachmentForWebInteractor {
|
|||||||
{CancelToken? cancelToken}
|
{CancelToken? cancelToken}
|
||||||
) async* {
|
) async* {
|
||||||
try {
|
try {
|
||||||
yield Right<Failure, Success>(StartDownloadAttachmentForWeb(taskId, attachment));
|
yield Right<Failure, Success>(StartDownloadAttachmentForWeb(taskId, attachment, cancelToken));
|
||||||
onReceiveController.add(Right(StartDownloadAttachmentForWeb(taskId, attachment)));
|
onReceiveController.add(Right(StartDownloadAttachmentForWeb(taskId, attachment, cancelToken)));
|
||||||
|
|
||||||
final currentAccount = await _accountRepository.getCurrentAccount();
|
final currentAccount = await _accountRepository.getCurrentAccount();
|
||||||
AccountRequest? accountRequest;
|
AccountRequest? accountRequest;
|
||||||
@@ -77,7 +77,8 @@ class DownloadAttachmentForWebInteractor {
|
|||||||
DownloadAttachmentForWebFailure(
|
DownloadAttachmentForWebFailure(
|
||||||
attachment: attachment,
|
attachment: attachment,
|
||||||
taskId: taskId,
|
taskId: taskId,
|
||||||
exception: exception
|
exception: exception,
|
||||||
|
cancelToken: cancelToken,
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -426,9 +426,12 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
|||||||
(success) {
|
(success) {
|
||||||
if (success is StartDownloadAttachmentForWeb) {
|
if (success is StartDownloadAttachmentForWeb) {
|
||||||
emailSupervisorController.mailboxDashBoardController.addDownloadTask(
|
emailSupervisorController.mailboxDashBoardController.addDownloadTask(
|
||||||
DownloadTaskState(
|
DownloadTaskState(
|
||||||
taskId: success.taskId,
|
taskId: success.taskId,
|
||||||
attachment: success.attachment));
|
attachment: success.attachment,
|
||||||
|
onCancel: () => success.cancelToken?.cancel(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
if (currentOverlayContext != null && currentContext != null) {
|
if (currentOverlayContext != null && currentContext != null) {
|
||||||
appToast.showToastMessage(
|
appToast.showToastMessage(
|
||||||
@@ -896,12 +899,15 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
|||||||
final baseDownloadUrl = session!.getDownloadUrl(
|
final baseDownloadUrl = session!.getDownloadUrl(
|
||||||
jmapUrl: dynamicUrlInterceptors.jmapUrl,
|
jmapUrl: dynamicUrlInterceptors.jmapUrl,
|
||||||
);
|
);
|
||||||
|
final cancelToken = CancelToken();
|
||||||
consumeState(_downloadAttachmentForWebInteractor.execute(
|
consumeState(_downloadAttachmentForWebInteractor.execute(
|
||||||
generateTaskId,
|
generateTaskId,
|
||||||
attachment,
|
attachment,
|
||||||
accountId!,
|
accountId!,
|
||||||
baseDownloadUrl,
|
baseDownloadUrl,
|
||||||
_downloadProgressStateController));
|
_downloadProgressStateController,
|
||||||
|
cancelToken: cancelToken,
|
||||||
|
));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logError('SingleEmailController::downloadAttachmentForWeb(): $e');
|
logError('SingleEmailController::downloadAttachmentForWeb(): $e');
|
||||||
consumeState(Stream.value(Left(DownloadAttachmentForWebFailure(attachment: attachment, taskId: generateTaskId, exception: e))));
|
consumeState(Stream.value(Left(DownloadAttachmentForWebFailure(attachment: attachment, taskId: generateTaskId, exception: e))));
|
||||||
@@ -945,13 +951,16 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
|||||||
_updateAttachmentsViewState(failure.attachment?.blobId, Left(failure));
|
_updateAttachmentsViewState(failure.attachment?.blobId, Left(failure));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentOverlayContext != null && currentContext != null) {
|
if (currentOverlayContext == null || currentContext == null) return;
|
||||||
appToast.showToastErrorMessage(
|
|
||||||
currentOverlayContext!,
|
String message = AppLocalizations.of(currentContext!).attachment_download_failed;
|
||||||
failure.attachment is EMLAttachment
|
if (failure.attachment is EMLAttachment) {
|
||||||
? AppLocalizations.of(currentContext!).downloadMessageAsEMLFailed
|
message = AppLocalizations.of(currentContext!).downloadMessageAsEMLFailed;
|
||||||
: AppLocalizations.of(currentContext!).attachment_download_failed);
|
} else if (failure.cancelToken?.isCancelled == true) {
|
||||||
|
message = AppLocalizations.of(currentContext!).downloadAttachmentHasBeenCancelled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
appToast.showToastErrorMessage(currentOverlayContext!, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _updateAttachmentsViewState(
|
void _updateAttachmentsViewState(
|
||||||
|
|||||||
+5
@@ -9,12 +9,14 @@ typedef UpdateDownloadTaskStateCallback = DownloadTaskState Function(DownloadTas
|
|||||||
class DownloadController extends GetxController {
|
class DownloadController extends GetxController {
|
||||||
|
|
||||||
final listDownloadTaskState = RxList<DownloadTaskState>();
|
final listDownloadTaskState = RxList<DownloadTaskState>();
|
||||||
|
final hideDownloadTaskbar = RxBool(false);
|
||||||
|
|
||||||
bool get notEmptyListDownloadTask => listDownloadTaskState.isNotEmpty;
|
bool get notEmptyListDownloadTask => listDownloadTaskState.isNotEmpty;
|
||||||
|
|
||||||
void addDownloadTask(DownloadTaskState task) {
|
void addDownloadTask(DownloadTaskState task) {
|
||||||
log('DownloadController::addDownloadTask(): ${task.taskId}');
|
log('DownloadController::addDownloadTask(): ${task.taskId}');
|
||||||
listDownloadTaskState.add(task);
|
listDownloadTaskState.add(task);
|
||||||
|
hideDownloadTaskbar.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateDownloadTaskByTaskId(
|
void updateDownloadTaskByTaskId(
|
||||||
@@ -37,5 +39,8 @@ class DownloadController extends GetxController {
|
|||||||
listDownloadTaskState.removeAt(matchIndex);
|
listDownloadTaskState.removeAt(matchIndex);
|
||||||
listDownloadTaskState.refresh();
|
listDownloadTaskState.refresh();
|
||||||
}
|
}
|
||||||
|
if (listDownloadTaskState.isEmpty) {
|
||||||
|
hideDownloadTaskbar.value = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -202,7 +202,7 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView {
|
|||||||
? const SearchMailboxView()
|
? const SearchMailboxView()
|
||||||
: const SizedBox.shrink()
|
: const SizedBox.shrink()
|
||||||
),
|
),
|
||||||
_buildDownloadTaskStateWidget(),
|
_buildDownloadTaskStateWidget(AppLocalizations.of(context)),
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -413,30 +413,50 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView {
|
|||||||
controller.dispatchAction(FilterMessageAction(FilterMessageOption.all));
|
controller.dispatchAction(FilterMessageAction(FilterMessageOption.all));
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildDownloadTaskStateWidget() {
|
Widget _buildDownloadTaskStateWidget(AppLocalizations appLocalizations) {
|
||||||
return Obx(() {
|
return Obx(() {
|
||||||
final listDownloadTasks = controller.downloadController.listDownloadTaskState;
|
final listDownloadTasks = controller.downloadController.listDownloadTaskState;
|
||||||
if (listDownloadTasks.isNotEmpty) {
|
final hideDownloadTaskbar = controller.downloadController.hideDownloadTaskbar;
|
||||||
|
if (listDownloadTasks.isNotEmpty && !hideDownloadTaskbar.value) {
|
||||||
return Align(
|
return Align(
|
||||||
alignment: Alignment.bottomCenter,
|
alignment: Alignment.bottomCenter,
|
||||||
child: Container(
|
child: Container(
|
||||||
color: AppColor.colorBackgroundSnackBar,
|
color: AppColor.colorBackgroundSnackBar,
|
||||||
height: 60,
|
height: 60,
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
child: ListView.separated(
|
child: Row(
|
||||||
scrollDirection: Axis.horizontal,
|
children: [
|
||||||
padding: EdgeInsets.zero,
|
Expanded(
|
||||||
itemCount: listDownloadTasks.length,
|
child: ListView.separated(
|
||||||
separatorBuilder: (context, index) =>
|
scrollDirection: Axis.horizontal,
|
||||||
const Padding(
|
padding: EdgeInsets.zero,
|
||||||
padding: EdgeInsets.symmetric(vertical: 5),
|
itemCount: listDownloadTasks.length,
|
||||||
child: VerticalDivider(
|
separatorBuilder: (context, index) =>
|
||||||
color: Colors.grey,
|
const Padding(
|
||||||
width: 2.5,
|
padding: EdgeInsets.symmetric(vertical: 5),
|
||||||
thickness: 0.2),
|
child: VerticalDivider(
|
||||||
|
color: Colors.grey,
|
||||||
|
width: 2.5,
|
||||||
|
thickness: 0.2),
|
||||||
|
),
|
||||||
|
itemBuilder: (context, index) =>
|
||||||
|
DownloadTaskItemWidget(listDownloadTasks[index])
|
||||||
),
|
),
|
||||||
itemBuilder: (context, index) =>
|
),
|
||||||
DownloadTaskItemWidget(listDownloadTasks[index])
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
|
child: TMailButtonWidget.fromText(
|
||||||
|
text: appLocalizations.hide,
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
textStyle: const TextStyle(
|
||||||
|
color: AppColor.colorCancelButton,
|
||||||
|
),
|
||||||
|
onTapActionCallback: () {
|
||||||
|
controller.downloadController.hideDownloadTaskbar.value = true;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
|
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:model/download/download_task_id.dart';
|
import 'package:model/download/download_task_id.dart';
|
||||||
import 'package:model/email/attachment.dart';
|
import 'package:model/email/attachment.dart';
|
||||||
|
|
||||||
@@ -9,13 +10,15 @@ class DownloadTaskState with EquatableMixin {
|
|||||||
final double progress;
|
final double progress;
|
||||||
final int downloaded;
|
final int downloaded;
|
||||||
final int total;
|
final int total;
|
||||||
|
final VoidCallback? onCancel;
|
||||||
|
|
||||||
DownloadTaskState({
|
DownloadTaskState({
|
||||||
required this.taskId,
|
required this.taskId,
|
||||||
required this.attachment,
|
required this.attachment,
|
||||||
this.progress = 0,
|
this.progress = 0,
|
||||||
this.downloaded = 0,
|
this.downloaded = 0,
|
||||||
this.total = 0
|
this.total = 0,
|
||||||
|
this.onCancel,
|
||||||
});
|
});
|
||||||
|
|
||||||
DownloadTaskState copyWith({
|
DownloadTaskState copyWith({
|
||||||
@@ -23,14 +26,16 @@ class DownloadTaskState with EquatableMixin {
|
|||||||
Attachment? attachment,
|
Attachment? attachment,
|
||||||
double? progress,
|
double? progress,
|
||||||
int? downloaded,
|
int? downloaded,
|
||||||
int? total
|
int? total,
|
||||||
|
VoidCallback? onCancel
|
||||||
}) {
|
}) {
|
||||||
return DownloadTaskState(
|
return DownloadTaskState(
|
||||||
taskId: taskId ?? this.taskId,
|
taskId: taskId ?? this.taskId,
|
||||||
attachment: attachment ?? this.attachment,
|
attachment: attachment ?? this.attachment,
|
||||||
progress: progress ?? this.progress,
|
progress: progress ?? this.progress,
|
||||||
downloaded: downloaded ?? this.downloaded,
|
downloaded: downloaded ?? this.downloaded,
|
||||||
total: total ?? this.total
|
total: total ?? this.total,
|
||||||
|
onCancel: onCancel ?? this.onCancel,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,5 +51,5 @@ class DownloadTaskState with EquatableMixin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [taskId, attachment, progress, downloaded, total];
|
List<Object?> get props => [taskId, attachment, progress, downloaded, total, onCancel];
|
||||||
}
|
}
|
||||||
+10
-2
@@ -3,10 +3,12 @@ import 'package:byte_converter/byte_converter.dart';
|
|||||||
import 'package:core/presentation/extensions/color_extension.dart';
|
import 'package:core/presentation/extensions/color_extension.dart';
|
||||||
import 'package:core/presentation/resources/image_paths.dart';
|
import 'package:core/presentation/resources/image_paths.dart';
|
||||||
import 'package:core/presentation/utils/style_utils.dart';
|
import 'package:core/presentation/utils/style_utils.dart';
|
||||||
|
import 'package:core/presentation/views/button/tmail_button_widget.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:percent_indicator/circular_percent_indicator.dart';
|
import 'package:percent_indicator/circular_percent_indicator.dart';
|
||||||
|
import 'package:tmail_ui_user/features/base/widget/circle_loading_widget.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/extensions/attachment_extension.dart';
|
import 'package:tmail_ui_user/features/email/presentation/extensions/attachment_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/download/download_task_state.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/download/download_task_state.dart';
|
||||||
|
|
||||||
@@ -43,7 +45,7 @@ class DownloadTaskItemWidget extends StatelessWidget {
|
|||||||
fit: BoxFit.fill),
|
fit: BoxFit.fill),
|
||||||
Center(
|
Center(
|
||||||
child: taskState.percentDownloading == 0
|
child: taskState.percentDownloading == 0
|
||||||
? const CircularProgressIndicator(color: AppColor.primaryColor, strokeWidth: 3)
|
? const CircleLoadingWidget(strokeWidth: 3)
|
||||||
: CircularPercentIndicator(
|
: CircularPercentIndicator(
|
||||||
percent: taskState.percentDownloading,
|
percent: taskState.percentDownloading,
|
||||||
backgroundColor: AppColor.colorBgMailboxSelected,
|
backgroundColor: AppColor.colorBgMailboxSelected,
|
||||||
@@ -83,7 +85,13 @@ class DownloadTaskItemWidget extends StatelessWidget {
|
|||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
|
if (taskState.onCancel != null)
|
||||||
|
TMailButtonWidget.fromIcon(
|
||||||
|
icon: imagePaths.icClose,
|
||||||
|
onTapActionCallback: taskState.onCancel,
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -4211,5 +4211,11 @@
|
|||||||
"type": "text",
|
"type": "text",
|
||||||
"placeholders_order": [],
|
"placeholders_order": [],
|
||||||
"placeholders": {}
|
"placeholders": {}
|
||||||
|
},
|
||||||
|
"downloadAttachmentHasBeenCancelled": "Download attachment has been cancelled",
|
||||||
|
"@downloadAttachmentHasBeenCancelled": {
|
||||||
|
"type": "text",
|
||||||
|
"placeholders_order": [],
|
||||||
|
"placeholders": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4419,4 +4419,11 @@ class AppLocalizations {
|
|||||||
name: 'thisHtmlAttachmentCannotBePreviewed',
|
name: 'thisHtmlAttachmentCannotBePreviewed',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String get downloadAttachmentHasBeenCancelled {
|
||||||
|
return Intl.message(
|
||||||
|
'Download attachment has been cancelled',
|
||||||
|
name: 'downloadAttachmentHasBeenCancelled',
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user