TF-2919 Fix memory leak when attach files in composer
This commit is contained in:
@@ -2,7 +2,6 @@ import 'package:core/presentation/resources/image_paths.dart';
|
||||
import 'package:core/presentation/views/button/tmail_button_widget.dart';
|
||||
import 'package:core/utils/platform_info.dart';
|
||||
import 'package:extended_text/extended_text.dart';
|
||||
import 'package:filesize/filesize.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:get/get.dart';
|
||||
@@ -10,7 +9,7 @@ import 'package:tmail_ui_user/features/base/mixin/app_loader_mixin.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/styles/attachment_item_composer_widget_style.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/widgets/attachment_progress_loading_composer_widget.dart';
|
||||
import 'package:tmail_ui_user/features/upload/domain/model/upload_task_id.dart';
|
||||
import 'package:tmail_ui_user/features/upload/presentation/model/upload_file_state.dart';
|
||||
import 'package:tmail_ui_user/features/upload/presentation/model/upload_file_status.dart';
|
||||
|
||||
typedef OnDeleteAttachmentAction = void Function(UploadTaskId uploadTaskId);
|
||||
|
||||
@@ -18,7 +17,12 @@ class AttachmentItemComposerWidget extends StatelessWidget with AppLoaderMixin {
|
||||
|
||||
final _imagePaths = Get.find<ImagePaths>();
|
||||
|
||||
final UploadFileState fileState;
|
||||
final String fileIcon;
|
||||
final String fileName;
|
||||
final String fileSize;
|
||||
final UploadFileStatus uploadStatus;
|
||||
final double percentUploading;
|
||||
final UploadTaskId uploadTaskId;
|
||||
final double? maxWidth;
|
||||
final EdgeInsetsGeometry? itemMargin;
|
||||
final EdgeInsetsGeometry? itemPadding;
|
||||
@@ -27,7 +31,12 @@ class AttachmentItemComposerWidget extends StatelessWidget with AppLoaderMixin {
|
||||
|
||||
AttachmentItemComposerWidget({
|
||||
super.key,
|
||||
required this.fileState,
|
||||
required this.fileIcon,
|
||||
required this.fileName,
|
||||
required this.fileSize,
|
||||
required this.uploadStatus,
|
||||
required this.percentUploading,
|
||||
required this.uploadTaskId,
|
||||
this.maxWidth,
|
||||
this.itemMargin,
|
||||
this.itemPadding,
|
||||
@@ -55,7 +64,7 @@ class AttachmentItemComposerWidget extends StatelessWidget with AppLoaderMixin {
|
||||
Row(
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
fileState.getIcon(_imagePaths),
|
||||
fileIcon,
|
||||
width: AttachmentItemComposerWidgetStyle.iconSize,
|
||||
height: AttachmentItemComposerWidgetStyle.iconSize,
|
||||
fit: BoxFit.fill
|
||||
@@ -64,7 +73,7 @@ class AttachmentItemComposerWidget extends StatelessWidget with AppLoaderMixin {
|
||||
Expanded(
|
||||
child: PlatformInfo.isCanvasKit
|
||||
? ExtendedText(
|
||||
fileState.fileName,
|
||||
fileName,
|
||||
maxLines: 1,
|
||||
overflowWidget: const TextOverflowWidget(
|
||||
position: TextOverflowPosition.middle,
|
||||
@@ -76,7 +85,7 @@ class AttachmentItemComposerWidget extends StatelessWidget with AppLoaderMixin {
|
||||
style: AttachmentItemComposerWidgetStyle.labelTextStyle,
|
||||
)
|
||||
: Text(
|
||||
fileState.fileName,
|
||||
fileName,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: AttachmentItemComposerWidgetStyle.labelTextStyle,
|
||||
@@ -84,14 +93,14 @@ class AttachmentItemComposerWidget extends StatelessWidget with AppLoaderMixin {
|
||||
),
|
||||
const SizedBox(width: AttachmentItemComposerWidgetStyle.space),
|
||||
Text(
|
||||
filesize(fileState.fileSize),
|
||||
fileSize,
|
||||
style: AttachmentItemComposerWidgetStyle.sizeLabelTextStyle
|
||||
),
|
||||
],
|
||||
),
|
||||
AttachmentProgressLoadingComposerWidget(
|
||||
fileState: fileState,
|
||||
padding: AttachmentItemComposerWidgetStyle.progressLoadingPadding,
|
||||
uploadStatus: uploadStatus,
|
||||
percentUploading: percentUploading,
|
||||
)
|
||||
],
|
||||
),
|
||||
@@ -103,7 +112,7 @@ class AttachmentItemComposerWidget extends StatelessWidget with AppLoaderMixin {
|
||||
borderRadius: AttachmentItemComposerWidgetStyle.deleteIconRadius,
|
||||
padding: AttachmentItemComposerWidgetStyle.deleteIconPadding,
|
||||
iconColor: AttachmentItemComposerWidgetStyle.deleteIconColor,
|
||||
onTapActionCallback: () => onDeleteAttachmentAction?.call(fileState.uploadTaskId),
|
||||
onTapActionCallback: () => onDeleteAttachmentAction?.call(uploadTaskId),
|
||||
)
|
||||
],
|
||||
),
|
||||
|
||||
+12
-12
@@ -1,27 +1,27 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:percent_indicator/linear_percent_indicator.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/styles/attachment_item_composer_widget_style.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/styles/attachment_progress_loading_composer_widget_style.dart';
|
||||
import 'package:tmail_ui_user/features/upload/presentation/model/upload_file_state.dart';
|
||||
import 'package:tmail_ui_user/features/upload/presentation/model/upload_file_status.dart';
|
||||
|
||||
class AttachmentProgressLoadingComposerWidget extends StatelessWidget {
|
||||
|
||||
final UploadFileState fileState;
|
||||
final EdgeInsetsGeometry? padding;
|
||||
final UploadFileStatus uploadStatus;
|
||||
final double percentUploading;
|
||||
|
||||
const AttachmentProgressLoadingComposerWidget({
|
||||
super.key,
|
||||
required this.fileState,
|
||||
this.padding,
|
||||
required this.uploadStatus,
|
||||
required this.percentUploading,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
switch (fileState.uploadStatus) {
|
||||
switch (uploadStatus) {
|
||||
case UploadFileStatus.waiting:
|
||||
return Padding(
|
||||
padding: padding ?? EdgeInsets.zero,
|
||||
child: const LinearProgressIndicator(
|
||||
return const Padding(
|
||||
padding: AttachmentItemComposerWidgetStyle.progressLoadingPadding,
|
||||
child: LinearProgressIndicator(
|
||||
color: AttachmentProgressLoadingComposerWidgetStyle.progressColor,
|
||||
minHeight: AttachmentProgressLoadingComposerWidgetStyle.height,
|
||||
backgroundColor: AttachmentProgressLoadingComposerWidgetStyle.backgroundColor,
|
||||
@@ -29,13 +29,13 @@ class AttachmentProgressLoadingComposerWidget extends StatelessWidget {
|
||||
);
|
||||
case UploadFileStatus.uploading:
|
||||
return Padding(
|
||||
padding: padding ?? EdgeInsets.zero,
|
||||
padding: AttachmentItemComposerWidgetStyle.progressLoadingPadding,
|
||||
child: LinearPercentIndicator(
|
||||
padding: EdgeInsets.zero,
|
||||
lineHeight:AttachmentProgressLoadingComposerWidgetStyle.height,
|
||||
percent: fileState.percentUploading > 1.0
|
||||
percent: percentUploading > 1.0
|
||||
? 1.0
|
||||
: fileState.percentUploading,
|
||||
: percentUploading,
|
||||
barRadius: const Radius.circular(AttachmentProgressLoadingComposerWidgetStyle.radius),
|
||||
backgroundColor: AttachmentProgressLoadingComposerWidgetStyle.backgroundColor,
|
||||
progressColor: AttachmentProgressLoadingComposerWidgetStyle.progressColor,
|
||||
|
||||
+15
-2
@@ -3,6 +3,7 @@ import 'package:core/presentation/resources/image_paths.dart';
|
||||
import 'package:core/presentation/utils/responsive_utils.dart';
|
||||
import 'package:core/presentation/views/button/tmail_button_widget.dart';
|
||||
import 'package:core/presentation/views/list/sliver_grid_delegate_fixed_height.dart';
|
||||
import 'package:filesize/filesize.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/styles/attachment_item_composer_widget_style.dart';
|
||||
@@ -73,8 +74,14 @@ class _MobileAttachmentComposerWidgetState extends State<MobileAttachmentCompose
|
||||
primary: false,
|
||||
itemCount: _listFileDisplayed.length,
|
||||
itemBuilder: (context, index) {
|
||||
final file = _listFileDisplayed[index];
|
||||
return AttachmentItemComposerWidget(
|
||||
fileState: _listFileDisplayed[index],
|
||||
fileIcon: file.getIcon(_imagePaths),
|
||||
fileName: file.fileName,
|
||||
fileSize: filesize(file.fileSize),
|
||||
uploadStatus: file.uploadStatus,
|
||||
percentUploading: file.percentUploading,
|
||||
uploadTaskId: file.uploadTaskId,
|
||||
itemMargin: MobileAttachmentComposerWidgetStyle.itemMargin,
|
||||
onDeleteAttachmentAction: widget.onDeleteAttachmentAction
|
||||
);
|
||||
@@ -130,8 +137,14 @@ class _MobileAttachmentComposerWidgetState extends State<MobileAttachmentCompose
|
||||
crossAxisSpacing: MobileAttachmentComposerWidgetStyle.listItemSpace,
|
||||
),
|
||||
itemBuilder: (context, index) {
|
||||
final file = _listFileDisplayed[index];
|
||||
return AttachmentItemComposerWidget(
|
||||
fileState: _listFileDisplayed[index],
|
||||
fileIcon: file.getIcon(_imagePaths),
|
||||
fileName: file.fileName,
|
||||
fileSize: filesize(file.fileSize),
|
||||
uploadStatus: file.uploadStatus,
|
||||
percentUploading: file.percentUploading,
|
||||
uploadTaskId: file.uploadTaskId,
|
||||
itemMargin: MobileAttachmentComposerWidgetStyle.itemMargin,
|
||||
itemPadding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
onDeleteAttachmentAction: widget.onDeleteAttachmentAction
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
|
||||
import 'package:core/presentation/resources/image_paths.dart';
|
||||
import 'package:filesize/filesize.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/styles/web/attachment_composer_widget_style.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/widgets/attachment_item_composer_widget.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/widgets/attachment_header_composer_widget.dart';
|
||||
@@ -28,6 +31,7 @@ class AttachmentComposerWidget extends StatefulWidget {
|
||||
|
||||
class _AttachmentComposerWidgetState extends State<AttachmentComposerWidget> {
|
||||
|
||||
final ImagePaths _imagePaths = Get.find<ImagePaths>();
|
||||
bool _isCollapsed = false;
|
||||
|
||||
@override
|
||||
@@ -36,6 +40,12 @@ class _AttachmentComposerWidgetState extends State<AttachmentComposerWidget> {
|
||||
_isCollapsed = widget.isCollapsed;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_isCollapsed = false;
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
@@ -66,8 +76,13 @@ class _AttachmentComposerWidgetState extends State<AttachmentComposerWidget> {
|
||||
runSpacing: AttachmentComposerWidgetStyle.listItemSpace,
|
||||
children: widget.listFileUploaded
|
||||
.map((file) => AttachmentItemComposerWidget(
|
||||
fileState: file,
|
||||
onDeleteAttachmentAction: widget.onDeleteAttachmentAction
|
||||
fileIcon: file.getIcon(_imagePaths),
|
||||
fileName: file.fileName,
|
||||
fileSize: filesize(file.fileSize),
|
||||
uploadStatus: file.uploadStatus,
|
||||
percentUploading: file.percentUploading,
|
||||
uploadTaskId: file.uploadTaskId,
|
||||
onDeleteAttachmentAction: widget.onDeleteAttachmentAction,
|
||||
))
|
||||
.toList(),
|
||||
),
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:async/async.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:core/presentation/extensions/color_extension.dart';
|
||||
@@ -45,6 +47,9 @@ class UploadController extends BaseController {
|
||||
final StreamGroup<Either<Failure, Success>> _progressUploadInlineImageStateStreamGroup
|
||||
= StreamGroup<Either<Failure, Success>>.broadcast();
|
||||
|
||||
StreamSubscription? _uploadAttachmentStreamSubscription;
|
||||
StreamSubscription? _uploadInlineImageStreamSubscription;
|
||||
|
||||
final UploadFileStateList _uploadingStateFiles = UploadFileStateList();
|
||||
final UploadFileStateList _uploadingStateInlineFiles = UploadFileStateList();
|
||||
|
||||
@@ -58,17 +63,21 @@ class UploadController extends BaseController {
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
listUploadAttachments.clear();
|
||||
_uploadingStateFiles.clear();
|
||||
_progressUploadStateStreamGroup.close();
|
||||
_uploadingStateInlineFiles.clear();
|
||||
_progressUploadInlineImageStateStreamGroup.close();
|
||||
uploadInlineViewState.value = Right(UIClosedState());
|
||||
dispatchState(Right(UIClosedState()));
|
||||
_progressUploadStateStreamGroup.close();
|
||||
_progressUploadInlineImageStateStreamGroup.close();
|
||||
_uploadAttachmentStreamSubscription?.cancel();
|
||||
_uploadInlineImageStreamSubscription?.cancel();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
void _registerProgressUploadStateStream() {
|
||||
_progressUploadStateStreamGroup.stream.listen(_handleProgressUploadStateStream);
|
||||
_progressUploadInlineImageStateStreamGroup.stream.listen(_handleProgressUploadInlineImageStateStream);
|
||||
_uploadAttachmentStreamSubscription = _progressUploadStateStreamGroup.stream.listen(_handleProgressUploadStateStream);
|
||||
_uploadInlineImageStreamSubscription = _progressUploadInlineImageStateStreamGroup.stream.listen(_handleProgressUploadInlineImageStateStream);
|
||||
}
|
||||
|
||||
void _handleProgressUploadStateStream(Either<Failure, Success> uploadState) {
|
||||
|
||||
Reference in New Issue
Block a user