Skip to content

Commit

Permalink
TW-1586: update the view of downloading file: process, cancel and mul…
Browse files Browse the repository at this point in the history
…tiple downloading
  • Loading branch information
sherlockvn authored and hoangdat committed Mar 25, 2024
1 parent 9b9c944 commit cd95d8a
Show file tree
Hide file tree
Showing 7 changed files with 444 additions and 52 deletions.
12 changes: 0 additions & 12 deletions lib/pages/chat/events/message_content.dart
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,6 @@ class MessageContent extends StatelessWidget
}
return MessageDownloadContent(
event,
onFileTapped: (event) => onFileTapped(
context: context,
event: event,
),
);
case MessageTypes.Video:
if (event.isVideoAvailable) {
Expand All @@ -105,10 +101,6 @@ class MessageContent extends StatelessWidget
children: [
MessageDownloadContent(
event,
onFileTapped: (event) => onFileTapped(
context: context,
event: event,
),
),
Padding(
padding: MessageContentStyle.endOfBubbleWidgetPadding,
Expand All @@ -124,10 +116,6 @@ class MessageContent extends StatelessWidget
children: [
MessageDownloadContent(
event,
onFileTapped: (event) => onFileTapped(
context: context,
event: event,
),
),
Padding(
padding: MessageContentStyle.endOfBubbleWidgetPadding,
Expand Down
192 changes: 169 additions & 23 deletions lib/pages/chat/events/message_download_content.dart
Original file line number Diff line number Diff line change
@@ -1,45 +1,191 @@
import 'dart:async';
import 'dart:io';

import 'package:dartz/dartz.dart' hide State, OpenFile;
import 'package:fluffychat/app_state/failure.dart';
import 'package:fluffychat/app_state/success.dart';
import 'package:fluffychat/di/global/get_it_initializer.dart';
import 'package:fluffychat/presentation/model/chat/downloading_state_presentation_model.dart';
import 'package:fluffychat/utils/manager/download_manager/download_file_state.dart';
import 'package:fluffychat/utils/manager/download_manager/download_manager.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/download_file_extension.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/event_extension.dart';
import 'package:fluffychat/utils/platform_infos.dart';
import 'package:fluffychat/widgets/file_widget/download_file_tile_widget.dart';
import 'package:fluffychat/widgets/file_widget/file_tile_widget.dart';
import 'package:fluffychat/widgets/file_widget/message_file_tile_style.dart';
import 'package:fluffychat/widgets/mixins/handle_download_and_preview_file_mixin.dart';
import 'package:flutter/material.dart';
import 'package:matrix/matrix.dart';

class MessageDownloadContent extends StatelessWidget {
class MessageDownloadContent extends StatefulWidget {
final Event event;
final void Function(Event event)? onFileTapped;

final String? highlightText;

const MessageDownloadContent(
this.event, {
Key? key,
this.onFileTapped,
this.highlightText,
}) : super(key: key);

@override
Widget build(BuildContext context) {
final filename = event.filename;
final filetype = event.fileType;
final sizeString = event.sizeString;
State<MessageDownloadContent> createState() => _MessageDownloadContentState();
}

class _MessageDownloadContentState extends State<MessageDownloadContent>
with HandleDownloadAndPreviewFileMixin {
final downloadManager = getIt.get<DownloadManager>();

final downloadFileStateNotifier = ValueNotifier<DownloadPresentationState>(
const NotDownloadPresentationState(),
);

StreamSubscription<Either<Failure, Success>>? streamSubscription;

@override
void initState() {
super.initState();
checkDownloadFileState();
}

void checkDownloadFileState() async {
if (!PlatformInfos.isWeb) {
final filePath = await widget.event.getFileNameInAppDownload();
final file = File(filePath);
if (await file.exists() &&
await file.length() == widget.event.getFileSize()) {
downloadFileStateNotifier.value = DownloadedPresentationState(
filePath: filePath,
);
return;
}
}
setupListeningForStreamSubcription();
if (streamSubscription != null) {
downloadFileStateNotifier.value = const DownloadingPresentationState();
}
}

Logs().i(
'filename: $filename, filetype: $filetype, sizeString: $sizeString, content: ${event.content}',
void setupListeningForStreamSubcription() {
streamSubscription = downloadManager
.getDownloadStateStream(widget.event.eventId)
?.listen(setupDownloadingProcess);
}

void setupDownloadingProcess(Either<Failure, Success> event) {
event.fold(
(failure) {
Logs().e('MessageDownloadContent::onDownloadingProcess(): $failure');
downloadFileStateNotifier.value = const NotDownloadPresentationState();
},
(success) {
if (success is DownloadingFileState) {
if (success.total != 0) {
downloadFileStateNotifier.value = DownloadingPresentationState(
receive: success.receive,
total: success.total,
);
}
} else if (success is DownloadNativeFileSuccessState) {
downloadFileStateNotifier.value = DownloadedPresentationState(
filePath: success.filePath,
);
} else if (success is DownloadMatrixFileSuccessState) {
downloadFileStateNotifier.value = FileWebDownloadedPresentationState(
matrixFile: success.matrixFile,
);
}
},
);
return InkWell(
onTap: onFileTapped != null
? () {
onFileTapped?.call(event);
}
: null,
child: FileTileWidget(
mimeType: event.mimeType,
fileType: filetype,
filename: filename,
highlightText: highlightText,
sizeString: sizeString,
style: MessageFileTileStyle(),
),
}

@override
void dispose() {
streamSubscription?.cancel();
downloadFileStateNotifier.dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
final filename = widget.event.filename;
final filetype = widget.event.fileType;
final sizeString = widget.event.sizeString;
return ValueListenableBuilder(
valueListenable: downloadFileStateNotifier,
builder: (context, DownloadPresentationState state, child) {
if (state is DownloadedPresentationState) {
return InkWell(
onTap: () async {
openDownloadedFileForPreview(
filePath: state.filePath,
mimeType: widget.event.mimeType,
);
},
child: FileTileWidget(
mimeType: widget.event.mimeType,
fileType: filetype,
filename: filename,
highlightText: widget.highlightText,
sizeString: sizeString,
style: const MessageFileTileStyle(),
),
);
} else if (state is DownloadingPresentationState) {
return DownloadFileTileWidget(
mimeType: widget.event.mimeType,
fileType: filetype,
filename: filename,
highlightText: widget.highlightText,
sizeString: sizeString,
style: const MessageFileTileStyle(),
downloadFileStateNotifier: downloadFileStateNotifier,
onCancelDownload: () {
downloadFileStateNotifier.value =
const NotDownloadPresentationState();
downloadManager.cancelDownload(widget.event.eventId);
},
);
} else if (state is FileWebDownloadedPresentationState) {
return InkWell(
onTap: () {
handlePreviewWeb(
event: widget.event,
context: context,
);
},
child: FileTileWidget(
mimeType: widget.event.mimeType,
fileType: filetype,
filename: filename,
highlightText: widget.highlightText,
sizeString: sizeString,
style: const MessageFileTileStyle(),
),
);
}

return InkWell(
onTap: () {
downloadFileStateNotifier.value =
const DownloadingPresentationState();
downloadManager.download(
event: widget.event,
);
setupListeningForStreamSubcription();
},
child: DownloadFileTileWidget(
mimeType: widget.event.mimeType,
fileType: filetype,
filename: filename,
highlightText: widget.highlightText,
sizeString: sizeString,
downloadFileStateNotifier: downloadFileStateNotifier,
style: const MessageFileTileStyle(),
),
);
},
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import 'package:equatable/equatable.dart';
import 'package:matrix/matrix.dart';

abstract class DownloadPresentationState with EquatableMixin {
const DownloadPresentationState();

@override
List<Object?> get props => [];
}

class NotDownloadPresentationState extends DownloadPresentationState {
const NotDownloadPresentationState() : super();
}

class DownloadedPresentationState extends DownloadPresentationState {
final String filePath;

const DownloadedPresentationState({required this.filePath}) : super();

@override
List<Object?> get props => [filePath];
}

class FileWebDownloadedPresentationState extends DownloadPresentationState {
final MatrixFile matrixFile;

const FileWebDownloadedPresentationState({required this.matrixFile})
: super();

@override
List<Object?> get props => [matrixFile];
}

class DownloadingPresentationState extends DownloadPresentationState {
final int? receive;

final int? total;

const DownloadingPresentationState({
this.receive,
this.total,
});

@override
List<Object?> get props => [receive, total];
}
12 changes: 9 additions & 3 deletions lib/utils/matrix_sdk_extensions/int_extension.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
extension DoubleExtension on int {
String bytesToMB() {
return (this / (1024 * 1024)).toString();
extension IntExtension on int {
String bytesToMB({int? placeDecimal}) {
return (this / (1024 * 1024)).toStringAsFixed(placeDecimal ?? 0);
}

String bytesToKB({int? placeDecimal}) {
return (this / 1024).toStringAsFixed(placeDecimal ?? 0);
}

static const oneKB = 1024 * 1024;
}
Loading

0 comments on commit cd95d8a

Please sign in to comment.