From 43bf0b24325d7ae2100abe017f5cb38ec2e97d03 Mon Sep 17 00:00:00 2001 From: RaulRodrigo06 Date: Mon, 2 Oct 2023 09:52:38 -0300 Subject: [PATCH 01/18] feat: adding fileName field on controller and bubble --- .../ds_video_message_bubble.controller.dart | 31 ++++++++++++++----- .../video/ds_video_message_bubble.widget.dart | 5 +++ lib/src/widgets/utils/ds_card.widget.dart | 1 + 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/lib/src/controllers/chat/ds_video_message_bubble.controller.dart b/lib/src/controllers/chat/ds_video_message_bubble.controller.dart index e4dad29b..79e8872e 100644 --- a/lib/src/controllers/chat/ds_video_message_bubble.controller.dart +++ b/lib/src/controllers/chat/ds_video_message_bubble.controller.dart @@ -16,11 +16,13 @@ class DSVideoMessageBubbleController { final String url; final int mediaSize; final Map? httpHeaders; + final String fileName; DSVideoMessageBubbleController({ required this.uniqueId, required this.url, required this.mediaSize, + required this.fileName, this.httpHeaders, }) { setThumbnail(); @@ -44,6 +46,17 @@ class DSVideoMessageBubbleController { final thumbnailFile = File(await getFullThumbnailPath()); if (await thumbnailFile.exists()) { thumbnail.value = thumbnailFile.path; + } else { + getVideoAndSetThumbnail(); + } + } + + Future getVideoAndSetThumbnail() async { + final temporaryPath = (await getTemporaryDirectory()).path; + final localPath = temporaryPath.replaceAll('cache', 'files'); + final file = File('$localPath/$fileName'); + if (await file.exists()) { + _generateThumbnail(file.path); } } @@ -89,13 +102,7 @@ class DSVideoMessageBubbleController { } } - final thumbnailPath = await getFullThumbnailPath(); - - await FFmpegKit.execute( - '-hide_banner -y -i "${outputFile.path}" -vframes 1 "$thumbnailPath"', - ); - - thumbnail.value = thumbnailPath; + _generateThumbnail(outputFile.path); } catch (_) { hasError.value = true; @@ -110,4 +117,14 @@ class DSVideoMessageBubbleController { isDownloading.value = false; } } + + Future _generateThumbnail(String path) async { + final thumbnailPath = await getFullThumbnailPath(); + + await FFmpegKit.execute( + '-hide_banner -y -i "$path" -vframes 1 "$thumbnailPath"', + ); + + thumbnail.value = thumbnailPath; + } } diff --git a/lib/src/widgets/chat/video/ds_video_message_bubble.widget.dart b/lib/src/widgets/chat/video/ds_video_message_bubble.widget.dart index 24129f8c..d7e5b8bf 100644 --- a/lib/src/widgets/chat/video/ds_video_message_bubble.widget.dart +++ b/lib/src/widgets/chat/video/ds_video_message_bubble.widget.dart @@ -48,6 +48,9 @@ class DSVideoMessageBubble extends StatefulWidget { /// Indicates if the HTTP Requests should be authenticated or not. final bool shouldAuthenticate; + /// The title of the video + final String? title; + /// Card for the purpose of triggering a video to play. /// /// This widget is intended to display a video card from a url passed in the [url] parameter. @@ -60,6 +63,7 @@ class DSVideoMessageBubble extends StatefulWidget { required this.appBarText, required this.uniqueId, required this.mediaSize, + this.title, this.appBarPhotoUri, this.text, this.borderRadius = const [DSBorderRadius.all], @@ -83,6 +87,7 @@ class _DSVideoMessageBubbleState extends State url: widget.url, mediaSize: widget.mediaSize, httpHeaders: widget.shouldAuthenticate ? DSAuthService.httpHeaders : null, + fileName: widget.title ?? '', ); } diff --git a/lib/src/widgets/utils/ds_card.widget.dart b/lib/src/widgets/utils/ds_card.widget.dart index 6898ecb6..540d868f 100644 --- a/lib/src/widgets/utils/ds_card.widget.dart +++ b/lib/src/widgets/utils/ds_card.widget.dart @@ -271,6 +271,7 @@ class DSCard extends StatelessWidget { text: media.text, borderRadius: borderRadius, style: style, + title: media.title ?? '', uniqueId: messageId ?? DateTime.now().toIso8601String(), mediaSize: size, shouldAuthenticate: shouldAuthenticate, From 75566452b96fbdb8027a0decde978d68af0e1c48 Mon Sep 17 00:00:00 2001 From: RaulRodrigo06 Date: Tue, 3 Oct 2023 12:27:32 -0300 Subject: [PATCH 02/18] feat: adding a directory formatter to unify media storage --- lib/blip_ds.dart | 10 +++-- .../ds_video_message_bubble.controller.dart | 19 ++++++---- lib/src/enums/ds_file_type.enum.dart | 5 +++ .../utils/ds_directory_formatter.util.dart | 38 +++++++++++++++++++ 4 files changed, 60 insertions(+), 12 deletions(-) create mode 100644 lib/src/enums/ds_file_type.enum.dart create mode 100644 lib/src/utils/ds_directory_formatter.util.dart diff --git a/lib/blip_ds.dart b/lib/blip_ds.dart index da2c6a89..ebd3ccf8 100644 --- a/lib/blip_ds.dart +++ b/lib/blip_ds.dart @@ -4,6 +4,7 @@ export 'src/enums/ds_align.enum.dart' show DSAlign; export 'src/enums/ds_border_radius.enum.dart' show DSBorderRadius; export 'src/enums/ds_delivery_report_status.enum.dart' show DSDeliveryReportStatus; +export 'src/enums/ds_file_type.enum.dart' show DSFileType; export 'src/enums/ds_input_container_shape.enum.dart' show DSInputContainerShape; export 'src/enums/ds_survey_scale.enum.dart' show DSSurveyScale; @@ -50,6 +51,7 @@ export 'src/themes/texts/styles/ds_headline_small_text_style.theme.dart' export 'src/themes/texts/utils/ds_font_families.theme.dart' show DSFontFamilies; export 'src/themes/texts/utils/ds_font_weights.theme.dart' show DSFontWeights; export 'src/utils/ds_animate.util.dart' show DSAnimate; +export 'src/utils/ds_directory_formatter.util.dart' show DSDirectoryFormatter; export 'src/utils/ds_linkify.util.dart' show DSLinkify; export 'src/utils/ds_utils.util.dart' show DSUtils; export 'src/widgets/animations/ds_animated_size.widget.dart' @@ -77,10 +79,10 @@ export 'src/widgets/buttons/ds_icon_button.widget.dart' show DSIconButton; export 'src/widgets/buttons/ds_pause_button.widget.dart' show DSPauseButton; export 'src/widgets/buttons/ds_play_button.widget.dart' show DSPlayButton; export 'src/widgets/buttons/ds_primary_button.widget.dart' show DSPrimaryButton; -export 'src/widgets/buttons/ds_secondary_button.widget.dart' - show DSSecondaryButton; export 'src/widgets/buttons/ds_request_location_button.widget.dart' show DSRequestLocationButton; +export 'src/widgets/buttons/ds_secondary_button.widget.dart' + show DSSecondaryButton; export 'src/widgets/buttons/ds_send_button.widget.dart' show DSSendButton; export 'src/widgets/buttons/ds_tertiary_button.widget.dart' show DSTertiaryButton; @@ -101,6 +103,8 @@ export 'src/widgets/chat/ds_location_message_bubble.widget.dart' export 'src/widgets/chat/ds_message_bubble.widget.dart' show DSMessageBubble; export 'src/widgets/chat/ds_message_bubble_detail.widget.dart' show DSMessageBubbleDetail; +export 'src/widgets/chat/ds_request_location_bubble.widget.dart' + show DSRequestLocationBubble; export 'src/widgets/chat/ds_survey_message_bubble.widget.dart' show DSSurveyMessageBubble; export 'src/widgets/chat/ds_text_message_bubble.widget.dart' @@ -155,5 +159,3 @@ export 'src/widgets/utils/ds_group_card.widget.dart' show DSGroupCard; export 'src/widgets/utils/ds_header.widget.dart' show DSHeader; export 'src/widgets/utils/ds_progress_bar.widget.dart' show DSProgressBar; export 'src/widgets/utils/ds_user_avatar.widget.dart' show DSUserAvatar; -export 'src/widgets/chat/ds_request_location_bubble.widget.dart' - show DSRequestLocationBubble; diff --git a/lib/src/controllers/chat/ds_video_message_bubble.controller.dart b/lib/src/controllers/chat/ds_video_message_bubble.controller.dart index 79e8872e..5ad98bc6 100644 --- a/lib/src/controllers/chat/ds_video_message_bubble.controller.dart +++ b/lib/src/controllers/chat/ds_video_message_bubble.controller.dart @@ -4,11 +4,12 @@ import 'package:ffmpeg_kit_flutter_full_gpl/ffmpeg_kit.dart'; import 'package:ffmpeg_kit_flutter_full_gpl/return_code.dart'; import 'package:file_sizes/file_sizes.dart'; import 'package:get/get.dart'; -import 'package:path_provider/path_provider.dart'; +import '../../enums/ds_file_type.enum.dart'; import '../../models/ds_toast_props.model.dart'; import '../../services/ds_file.service.dart'; import '../../services/ds_toast.service.dart'; +import '../../utils/ds_directory_formatter.util.dart'; import '../../widgets/chat/video/ds_video_error.dialog.dart'; class DSVideoMessageBubbleController { @@ -52,17 +53,18 @@ class DSVideoMessageBubbleController { } Future getVideoAndSetThumbnail() async { - final temporaryPath = (await getTemporaryDirectory()).path; - final localPath = temporaryPath.replaceAll('cache', 'files'); - final file = File('$localPath/$fileName'); + final mediaPath = + await DSDirectoryFormatter.getPath(type: DSFileType.videos); + final file = File('$mediaPath/$fileName'); if (await file.exists()) { _generateThumbnail(file.path); } } Future getFullThumbnailPath() async { - final temporaryPath = (await getTemporaryDirectory()).path; - return "$temporaryPath/VIDEO-Thumbnail-$uniqueId.png"; + final mediaPath = + await DSDirectoryFormatter.getPath(type: DSFileType.videos); + return "$mediaPath/VIDEO-Thumbnail-$uniqueId.png"; } Future downloadVideo() async { @@ -77,8 +79,9 @@ class DSVideoMessageBubbleController { fileName = DateTime.now().toIso8601String(); } - final temporaryPath = (await getTemporaryDirectory()).path; - final outputFile = File('$temporaryPath/VIDEO-$uniqueId.mp4'); + final mediaPath = + await DSDirectoryFormatter.getPath(type: DSFileType.videos); + final outputFile = File('$mediaPath/VIDEO-$uniqueId.mp4'); if (!await outputFile.exists()) { final inputFilePath = await DSFileService.download( diff --git a/lib/src/enums/ds_file_type.enum.dart b/lib/src/enums/ds_file_type.enum.dart new file mode 100644 index 00000000..7db4f696 --- /dev/null +++ b/lib/src/enums/ds_file_type.enum.dart @@ -0,0 +1,5 @@ +enum DSFileType { + videos, + documents, + images, +} diff --git a/lib/src/utils/ds_directory_formatter.util.dart b/lib/src/utils/ds_directory_formatter.util.dart new file mode 100644 index 00000000..867d79ca --- /dev/null +++ b/lib/src/utils/ds_directory_formatter.util.dart @@ -0,0 +1,38 @@ +import 'dart:io'; + +import 'package:get/get.dart'; +import 'package:path/path.dart' as path; +import 'package:path_provider/path_provider.dart'; + +import '../enums/ds_file_type.enum.dart'; + +abstract class DSDirectoryFormatter { + static Future formatMediaDirectory({ + required String filePath, + required DSFileType type, + required String fileName, + }) async { + String dir = path.dirname(filePath); + final String formattedDir = _formatDir(type: type, dir: dir); + final dirExists = await Directory(formattedDir).exists(); + if (!dirExists) { + await Directory(formattedDir).create(recursive: true); + } + String newName = path.join(formattedDir, fileName); + await File(filePath).rename(newName); + return newName; + } + + static Future getPath({required DSFileType type}) async { + final temporaryPath = (await getTemporaryDirectory()).path; + final mediaPath = _formatDir(type: type, dir: temporaryPath); + return mediaPath; + } + + static String _formatDir({required DSFileType type, required String dir}) { + return dir.replaceAll( + dir.split('/').last, + 'BlipDesk/Media/${type.name.capitalizeFirst}', + ); + } +} From 2429e829829a134827bbea8f6a7f730da0b1a4d0 Mon Sep 17 00:00:00 2001 From: RaulRodrigo06 Date: Tue, 3 Oct 2023 12:36:42 -0300 Subject: [PATCH 03/18] fix: fixing dir creation --- lib/src/utils/ds_directory_formatter.util.dart | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/src/utils/ds_directory_formatter.util.dart b/lib/src/utils/ds_directory_formatter.util.dart index 867d79ca..0c7ca84c 100644 --- a/lib/src/utils/ds_directory_formatter.util.dart +++ b/lib/src/utils/ds_directory_formatter.util.dart @@ -13,11 +13,7 @@ abstract class DSDirectoryFormatter { required String fileName, }) async { String dir = path.dirname(filePath); - final String formattedDir = _formatDir(type: type, dir: dir); - final dirExists = await Directory(formattedDir).exists(); - if (!dirExists) { - await Directory(formattedDir).create(recursive: true); - } + final String formattedDir = await _formatDir(type: type, dir: dir); String newName = path.join(formattedDir, fileName); await File(filePath).rename(newName); return newName; @@ -29,10 +25,16 @@ abstract class DSDirectoryFormatter { return mediaPath; } - static String _formatDir({required DSFileType type, required String dir}) { - return dir.replaceAll( + static Future _formatDir( + {required DSFileType type, required String dir}) async { + final formattedDir = dir.replaceAll( dir.split('/').last, 'BlipDesk/Media/${type.name.capitalizeFirst}', ); + final dirExists = await Directory(formattedDir).exists(); + if (!dirExists) { + await Directory(formattedDir).create(recursive: true); + } + return formattedDir; } } From fe086a18a5ea129b533c4a729c170d18a42df48f Mon Sep 17 00:00:00 2001 From: RaulRodrigo06 Date: Tue, 3 Oct 2023 14:36:01 -0300 Subject: [PATCH 04/18] fix: set media path on download --- lib/src/controllers/chat/ds_video_message_bubble.controller.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/controllers/chat/ds_video_message_bubble.controller.dart b/lib/src/controllers/chat/ds_video_message_bubble.controller.dart index 5ad98bc6..1d9af3c6 100644 --- a/lib/src/controllers/chat/ds_video_message_bubble.controller.dart +++ b/lib/src/controllers/chat/ds_video_message_bubble.controller.dart @@ -87,6 +87,7 @@ class DSVideoMessageBubbleController { final inputFilePath = await DSFileService.download( url, fileName, + path: mediaPath, httpHeaders: httpHeaders, ); From 4b1f1b0df17714c033aa9b2b5a362633aaefcb32 Mon Sep 17 00:00:00 2001 From: RaulRodrigo06 Date: Tue, 3 Oct 2023 15:57:56 -0300 Subject: [PATCH 05/18] feat: deleting output fle --- .../chat/ds_video_message_bubble.controller.dart | 3 ++- .../widgets/chat/video/ds_video_player.widget.dart | 14 +++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/src/controllers/chat/ds_video_message_bubble.controller.dart b/lib/src/controllers/chat/ds_video_message_bubble.controller.dart index 1d9af3c6..ec9b65a5 100644 --- a/lib/src/controllers/chat/ds_video_message_bubble.controller.dart +++ b/lib/src/controllers/chat/ds_video_message_bubble.controller.dart @@ -87,13 +87,14 @@ class DSVideoMessageBubbleController { final inputFilePath = await DSFileService.download( url, fileName, - path: mediaPath, httpHeaders: httpHeaders, ); final session = await FFmpegKit.execute( '-hide_banner -y -i "$inputFilePath" "${outputFile.path}"'); + File(inputFilePath!).delete(); + final returnCode = await session.getReturnCode(); if (!ReturnCode.isSuccess(returnCode)) { diff --git a/lib/src/widgets/chat/video/ds_video_player.widget.dart b/lib/src/widgets/chat/video/ds_video_player.widget.dart index e251ab32..6270c36a 100644 --- a/lib/src/widgets/chat/video/ds_video_player.widget.dart +++ b/lib/src/widgets/chat/video/ds_video_player.widget.dart @@ -4,6 +4,8 @@ import 'package:flutter/services.dart'; import 'package:get/get.dart'; import '../../../controllers/ds_video_player.controller.dart'; +import '../../../themes/colors/ds_colors.theme.dart'; +import '../../../themes/icons/ds_icons.dart'; import '../../../themes/system_overlay/ds_system_overlay.style.dart'; import '../../utils/ds_header.widget.dart'; @@ -73,9 +75,15 @@ class DSVideoPlayer extends StatelessWidget { 8.0, 8.0 + MediaQuery.of(context).padding.bottom, ), - child: Chewie( - controller: controller.chewieController!, - ), + child: controller.chewieController == null + ? const Icon( + DSIcons.video_broken_outline, + size: 80.0, + color: DSColors.neutralDarkRooftop, + ) + : Chewie( + controller: controller.chewieController!, + ), ), ), ), From 2f3270ac0c36f7a8407a7724c96eac392f270a62 Mon Sep 17 00:00:00 2001 From: RaulRodrigo06 Date: Wed, 4 Oct 2023 11:43:44 -0300 Subject: [PATCH 06/18] chore: renaming vars --- .../utils/ds_directory_formatter.util.dart | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/src/utils/ds_directory_formatter.util.dart b/lib/src/utils/ds_directory_formatter.util.dart index 0c7ca84c..cbde46c3 100644 --- a/lib/src/utils/ds_directory_formatter.util.dart +++ b/lib/src/utils/ds_directory_formatter.util.dart @@ -12,8 +12,8 @@ abstract class DSDirectoryFormatter { required DSFileType type, required String fileName, }) async { - String dir = path.dirname(filePath); - final String formattedDir = await _formatDir(type: type, dir: dir); + String directory = path.dirname(filePath); + final String formattedDir = await _formatDirectory(type: type, directory: directory); String newName = path.join(formattedDir, fileName); await File(filePath).rename(newName); return newName; @@ -21,20 +21,20 @@ abstract class DSDirectoryFormatter { static Future getPath({required DSFileType type}) async { final temporaryPath = (await getTemporaryDirectory()).path; - final mediaPath = _formatDir(type: type, dir: temporaryPath); + final mediaPath = _formatDirectory(type: type, directory: temporaryPath); return mediaPath; } - static Future _formatDir( - {required DSFileType type, required String dir}) async { - final formattedDir = dir.replaceAll( - dir.split('/').last, + static Future _formatDirectory( + {required DSFileType type, required String directory}) async { + final formattedDirectory = directory.replaceAll( + directory.split('/').last, 'BlipDesk/Media/${type.name.capitalizeFirst}', ); - final dirExists = await Directory(formattedDir).exists(); + final dirExists = await Directory(formattedDirectory).exists(); if (!dirExists) { - await Directory(formattedDir).create(recursive: true); + await Directory(formattedDirectory).create(recursive: true); } - return formattedDir; + return formattedDirectory; } } From c7f7cdae02a7f08ad0a13afd8cc40ba8ab751850 Mon Sep 17 00:00:00 2001 From: RaulRodrigo06 Date: Wed, 4 Oct 2023 14:17:49 -0300 Subject: [PATCH 07/18] chore: renaming var and folder name --- lib/src/utils/ds_directory_formatter.util.dart | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/src/utils/ds_directory_formatter.util.dart b/lib/src/utils/ds_directory_formatter.util.dart index cbde46c3..fd0bf2f7 100644 --- a/lib/src/utils/ds_directory_formatter.util.dart +++ b/lib/src/utils/ds_directory_formatter.util.dart @@ -13,7 +13,8 @@ abstract class DSDirectoryFormatter { required String fileName, }) async { String directory = path.dirname(filePath); - final String formattedDir = await _formatDirectory(type: type, directory: directory); + final String formattedDir = + await _formatDirectory(type: type, directory: directory); String newName = path.join(formattedDir, fileName); await File(filePath).rename(newName); return newName; @@ -29,10 +30,10 @@ abstract class DSDirectoryFormatter { {required DSFileType type, required String directory}) async { final formattedDirectory = directory.replaceAll( directory.split('/').last, - 'BlipDesk/Media/${type.name.capitalizeFirst}', + 'Blip Desk/Media/${type.name.capitalizeFirst}', ); - final dirExists = await Directory(formattedDirectory).exists(); - if (!dirExists) { + final directoryExists = await Directory(formattedDirectory).exists(); + if (!directoryExists) { await Directory(formattedDirectory).create(recursive: true); } return formattedDirectory; From f47a7ba381ba2191e3e8723f905ab187636e4e39 Mon Sep 17 00:00:00 2001 From: RaulRodrigo06 Date: Thu, 5 Oct 2023 12:08:23 -0300 Subject: [PATCH 08/18] fix: using uniqueId --- .../ds_video_message_bubble.controller.dart | 29 ++++--------------- .../utils/ds_directory_formatter.util.dart | 3 +- .../video/ds_video_message_bubble.widget.dart | 7 +---- lib/src/widgets/utils/ds_card.widget.dart | 1 - 4 files changed, 9 insertions(+), 31 deletions(-) diff --git a/lib/src/controllers/chat/ds_video_message_bubble.controller.dart b/lib/src/controllers/chat/ds_video_message_bubble.controller.dart index ec9b65a5..b5e7e165 100644 --- a/lib/src/controllers/chat/ds_video_message_bubble.controller.dart +++ b/lib/src/controllers/chat/ds_video_message_bubble.controller.dart @@ -17,16 +17,14 @@ class DSVideoMessageBubbleController { final String url; final int mediaSize; final Map? httpHeaders; - final String fileName; DSVideoMessageBubbleController({ required this.uniqueId, required this.url, required this.mediaSize, - required this.fileName, this.httpHeaders, }) { - setThumbnail(); + getVideoAndSetThumbnail(); } final isDownloading = RxBool(false); @@ -43,19 +41,10 @@ class DSVideoMessageBubbleController { : 'Download'; } - Future setThumbnail() async { - final thumbnailFile = File(await getFullThumbnailPath()); - if (await thumbnailFile.exists()) { - thumbnail.value = thumbnailFile.path; - } else { - getVideoAndSetThumbnail(); - } - } - Future getVideoAndSetThumbnail() async { final mediaPath = await DSDirectoryFormatter.getPath(type: DSFileType.videos); - final file = File('$mediaPath/$fileName'); + final file = File('$mediaPath/VID_$uniqueId.mp4'); if (await file.exists()) { _generateThumbnail(file.path); } @@ -64,24 +53,18 @@ class DSVideoMessageBubbleController { Future getFullThumbnailPath() async { final mediaPath = await DSDirectoryFormatter.getPath(type: DSFileType.videos); - return "$mediaPath/VIDEO-Thumbnail-$uniqueId.png"; + return "$mediaPath/VID_$uniqueId.png"; } Future downloadVideo() async { isDownloading.value = true; try { - final path = Uri.parse(url).path; - - var fileName = path.substring(path.lastIndexOf('/')).substring(1); - - if (fileName.isEmpty) { - fileName = DateTime.now().toIso8601String(); - } + final fileName = DateTime.now().toIso8601String(); final mediaPath = await DSDirectoryFormatter.getPath(type: DSFileType.videos); - final outputFile = File('$mediaPath/VIDEO-$uniqueId.mp4'); + final outputFile = File('$mediaPath/VID_$uniqueId.mp4'); if (!await outputFile.exists()) { final inputFilePath = await DSFileService.download( @@ -93,7 +76,7 @@ class DSVideoMessageBubbleController { final session = await FFmpegKit.execute( '-hide_banner -y -i "$inputFilePath" "${outputFile.path}"'); - File(inputFilePath!).delete(); + File(inputFilePath!).delete(); final returnCode = await session.getReturnCode(); diff --git a/lib/src/utils/ds_directory_formatter.util.dart b/lib/src/utils/ds_directory_formatter.util.dart index fd0bf2f7..c33ea010 100644 --- a/lib/src/utils/ds_directory_formatter.util.dart +++ b/lib/src/utils/ds_directory_formatter.util.dart @@ -15,7 +15,8 @@ abstract class DSDirectoryFormatter { String directory = path.dirname(filePath); final String formattedDir = await _formatDirectory(type: type, directory: directory); - String newName = path.join(formattedDir, fileName); + String newName = + '${path.join(formattedDir, fileName)}.${filePath.split('.').last}'; await File(filePath).rename(newName); return newName; } diff --git a/lib/src/widgets/chat/video/ds_video_message_bubble.widget.dart b/lib/src/widgets/chat/video/ds_video_message_bubble.widget.dart index d7e5b8bf..1e5bd962 100644 --- a/lib/src/widgets/chat/video/ds_video_message_bubble.widget.dart +++ b/lib/src/widgets/chat/video/ds_video_message_bubble.widget.dart @@ -48,9 +48,6 @@ class DSVideoMessageBubble extends StatefulWidget { /// Indicates if the HTTP Requests should be authenticated or not. final bool shouldAuthenticate; - /// The title of the video - final String? title; - /// Card for the purpose of triggering a video to play. /// /// This widget is intended to display a video card from a url passed in the [url] parameter. @@ -63,7 +60,6 @@ class DSVideoMessageBubble extends StatefulWidget { required this.appBarText, required this.uniqueId, required this.mediaSize, - this.title, this.appBarPhotoUri, this.text, this.borderRadius = const [DSBorderRadius.all], @@ -83,11 +79,10 @@ class _DSVideoMessageBubbleState extends State void initState() { super.initState(); _controller = DSVideoMessageBubbleController( - uniqueId: widget.uniqueId, url: widget.url, mediaSize: widget.mediaSize, httpHeaders: widget.shouldAuthenticate ? DSAuthService.httpHeaders : null, - fileName: widget.title ?? '', + uniqueId: widget.uniqueId, ); } diff --git a/lib/src/widgets/utils/ds_card.widget.dart b/lib/src/widgets/utils/ds_card.widget.dart index 540d868f..6898ecb6 100644 --- a/lib/src/widgets/utils/ds_card.widget.dart +++ b/lib/src/widgets/utils/ds_card.widget.dart @@ -271,7 +271,6 @@ class DSCard extends StatelessWidget { text: media.text, borderRadius: borderRadius, style: style, - title: media.title ?? '', uniqueId: messageId ?? DateTime.now().toIso8601String(), mediaSize: size, shouldAuthenticate: shouldAuthenticate, From 45eb2bc89af67df1a963c1fba5974db23313601c Mon Sep 17 00:00:00 2001 From: RaulRodrigo06 Date: Fri, 6 Oct 2023 17:16:09 -0300 Subject: [PATCH 09/18] refactor: video storage refactor --- .../ds_video_message_bubble.controller.dart | 18 +++++++---- .../ds_video_player.controller.dart | 3 -- .../utils/ds_directory_formatter.util.dart | 31 +++++++++++++++++-- .../chat/video/ds_video_body.widget.dart | 3 -- .../video/ds_video_message_bubble.widget.dart | 10 +++--- .../chat/video/ds_video_player.widget.dart | 4 --- lib/src/widgets/utils/ds_card.widget.dart | 3 +- .../sample_message_bubble.showcase.dart | 8 ++--- 8 files changed, 51 insertions(+), 29 deletions(-) diff --git a/lib/src/controllers/chat/ds_video_message_bubble.controller.dart b/lib/src/controllers/chat/ds_video_message_bubble.controller.dart index b5e7e165..15e5779c 100644 --- a/lib/src/controllers/chat/ds_video_message_bubble.controller.dart +++ b/lib/src/controllers/chat/ds_video_message_bubble.controller.dart @@ -13,13 +13,13 @@ import '../../utils/ds_directory_formatter.util.dart'; import '../../widgets/chat/video/ds_video_error.dialog.dart'; class DSVideoMessageBubbleController { - final String uniqueId; + final String fileName; final String url; final int mediaSize; final Map? httpHeaders; DSVideoMessageBubbleController({ - required this.uniqueId, + required this.fileName, required this.url, required this.mediaSize, this.httpHeaders, @@ -30,6 +30,7 @@ class DSVideoMessageBubbleController { final isDownloading = RxBool(false); final thumbnail = RxString(''); final hasError = RxBool(false); + final loadingThumbnail = RxBool(true); String size() { return mediaSize > 0 @@ -42,18 +43,23 @@ class DSVideoMessageBubbleController { } Future getVideoAndSetThumbnail() async { + loadingThumbnail.value = true; final mediaPath = await DSDirectoryFormatter.getPath(type: DSFileType.videos); - final file = File('$mediaPath/VID_$uniqueId.mp4'); + final bool containsVid = fileName.contains('VID'); + final file = containsVid + ? File('$mediaPath/$fileName.mp4') + : File('$mediaPath/VID-$fileName.mp4'); if (await file.exists()) { - _generateThumbnail(file.path); + await _generateThumbnail(file.path); } + loadingThumbnail.value = false; } Future getFullThumbnailPath() async { final mediaPath = await DSDirectoryFormatter.getPath(type: DSFileType.videos); - return "$mediaPath/VID_$uniqueId.png"; + return "$mediaPath/VID-$fileName.png"; } Future downloadVideo() async { @@ -64,7 +70,7 @@ class DSVideoMessageBubbleController { final mediaPath = await DSDirectoryFormatter.getPath(type: DSFileType.videos); - final outputFile = File('$mediaPath/VID_$uniqueId.mp4'); + final outputFile = File('$mediaPath/VID-$fileName.mp4'); if (!await outputFile.exists()) { final inputFilePath = await DSFileService.download( diff --git a/lib/src/controllers/ds_video_player.controller.dart b/lib/src/controllers/ds_video_player.controller.dart index e8a3a0d4..00f50711 100644 --- a/lib/src/controllers/ds_video_player.controller.dart +++ b/lib/src/controllers/ds_video_player.controller.dart @@ -13,15 +13,12 @@ class DSVideoPlayerController extends GetxController { /// the management of video controls. DSVideoPlayerController({ required this.url, - required this.uniqueId, this.shouldAuthenticate = false, }); // External URL containing the video to be played final String url; - final String uniqueId; - /// Indicates if the HTTP Requests should be authenticated or not. final bool shouldAuthenticate; diff --git a/lib/src/utils/ds_directory_formatter.util.dart b/lib/src/utils/ds_directory_formatter.util.dart index c33ea010..2bdddada 100644 --- a/lib/src/utils/ds_directory_formatter.util.dart +++ b/lib/src/utils/ds_directory_formatter.util.dart @@ -13,10 +13,13 @@ abstract class DSDirectoryFormatter { required String fileName, }) async { String directory = path.dirname(filePath); - final String formattedDir = + final String formattedDirectory = await _formatDirectory(type: type, directory: directory); - String newName = - '${path.join(formattedDir, fileName)}.${filePath.split('.').last}'; + final String newName = await _formatNewName( + formattedDirectory: formattedDirectory, + fileName: fileName, + filePath: filePath, + ); await File(filePath).rename(newName); return newName; } @@ -39,4 +42,26 @@ abstract class DSDirectoryFormatter { } return formattedDirectory; } + + static Future _formatNewName({ + required String formattedDirectory, + required String fileName, + required String filePath, + }) async { + int numberOfFiles = 0; + final String extension = filePath.split('.').last; + final directory = Directory(formattedDirectory).listSync(); + + for (FileSystemEntity files in directory) { + if (files.path.contains(fileName) && + (files.path.split('.').last == extension)) { + numberOfFiles++; + } + } + + String newName = + '${path.join(formattedDirectory, fileName)}-BA$numberOfFiles.$extension'; + + return newName; + } } diff --git a/lib/src/widgets/chat/video/ds_video_body.widget.dart b/lib/src/widgets/chat/video/ds_video_body.widget.dart index d4ffdcbe..63fb81cb 100644 --- a/lib/src/widgets/chat/video/ds_video_body.widget.dart +++ b/lib/src/widgets/chat/video/ds_video_body.widget.dart @@ -10,7 +10,6 @@ class DSVideoBody extends StatelessWidget { required this.appBarText, required this.appBarPhotoUri, required this.url, - required this.uniqueId, required this.thumbnail, this.shouldAuthenticate = false, }); @@ -19,7 +18,6 @@ class DSVideoBody extends StatelessWidget { final String appBarText; final Uri? appBarPhotoUri; final String url; - final String uniqueId; final Widget thumbnail; final bool shouldAuthenticate; @@ -43,7 +41,6 @@ class DSVideoBody extends StatelessWidget { appBarText: appBarText, appBarPhotoUri: appBarPhotoUri, url: url, - uniqueId: uniqueId, shouldAuthenticate: shouldAuthenticate, ), ); diff --git a/lib/src/widgets/chat/video/ds_video_message_bubble.widget.dart b/lib/src/widgets/chat/video/ds_video_message_bubble.widget.dart index 1e5bd962..5ea157bc 100644 --- a/lib/src/widgets/chat/video/ds_video_message_bubble.widget.dart +++ b/lib/src/widgets/chat/video/ds_video_message_bubble.widget.dart @@ -40,7 +40,7 @@ class DSVideoMessageBubble extends StatefulWidget { final DSMessageBubbleStyle style; // Unique id to message bubble - final String uniqueId; + final String fileName; /// The video size final int mediaSize; @@ -58,7 +58,7 @@ class DSVideoMessageBubble extends StatefulWidget { required this.align, required this.url, required this.appBarText, - required this.uniqueId, + required this.fileName, required this.mediaSize, this.appBarPhotoUri, this.text, @@ -82,7 +82,7 @@ class _DSVideoMessageBubbleState extends State url: widget.url, mediaSize: widget.mediaSize, httpHeaders: widget.shouldAuthenticate ? DSAuthService.httpHeaders : null, - uniqueId: widget.uniqueId, + fileName: widget.fileName, ); } @@ -135,7 +135,8 @@ class _DSVideoMessageBubbleState extends State size: 80.0, color: DSColors.neutralDarkRooftop, ) - : _controller.isDownloading.value + : (_controller.isDownloading.value || + _controller.loadingThumbnail.value) ? Center( child: Container( height: 50.0, @@ -169,7 +170,6 @@ class _DSVideoMessageBubbleState extends State align: widget.align, appBarPhotoUri: widget.appBarPhotoUri, appBarText: widget.appBarText, - uniqueId: widget.uniqueId, url: widget.url, shouldAuthenticate: widget.shouldAuthenticate, thumbnail: Center( diff --git a/lib/src/widgets/chat/video/ds_video_player.widget.dart b/lib/src/widgets/chat/video/ds_video_player.widget.dart index 6270c36a..264855a0 100644 --- a/lib/src/widgets/chat/video/ds_video_player.widget.dart +++ b/lib/src/widgets/chat/video/ds_video_player.widget.dart @@ -18,8 +18,6 @@ class DSVideoPlayer extends StatelessWidget { /// Avatar to be displayed in the appBarr final Uri? appBarPhotoUri; - final String uniqueId; - /// Indicates if the HTTP Requests should be authenticated or not. final bool shouldAuthenticate; @@ -31,13 +29,11 @@ class DSVideoPlayer extends StatelessWidget { Key? key, required this.appBarText, required String url, - required this.uniqueId, this.appBarPhotoUri, this.shouldAuthenticate = false, }) : controller = Get.put( DSVideoPlayerController( url: url, - uniqueId: uniqueId, ), ), super(key: key); diff --git a/lib/src/widgets/utils/ds_card.widget.dart b/lib/src/widgets/utils/ds_card.widget.dart index 6898ecb6..a33d53b6 100644 --- a/lib/src/widgets/utils/ds_card.widget.dart +++ b/lib/src/widgets/utils/ds_card.widget.dart @@ -258,6 +258,7 @@ class DSCard extends StatelessWidget { shouldAuthenticate: shouldAuthenticate, ); } else if (media.type.contains('video')) { + final fileName = media.title?.split('.').first; return DSVideoMessageBubble( url: media.uri, align: align, @@ -271,7 +272,7 @@ class DSCard extends StatelessWidget { text: media.text, borderRadius: borderRadius, style: style, - uniqueId: messageId ?? DateTime.now().toIso8601String(), + fileName: fileName ?? messageId ?? DateTime.now().toIso8601String(), mediaSize: size, shouldAuthenticate: shouldAuthenticate, ); diff --git a/sample/lib/widgets/showcase/sample_message_bubble.showcase.dart b/sample/lib/widgets/showcase/sample_message_bubble.showcase.dart index 62b571ab..f63af8dd 100644 --- a/sample/lib/widgets/showcase/sample_message_bubble.showcase.dart +++ b/sample/lib/widgets/showcase/sample_message_bubble.showcase.dart @@ -250,7 +250,7 @@ class SampleMessageBubbleShowcase extends StatelessWidget { url: _srcsVideo[0], text: '.mov', appBarText: 'Unknown User', - uniqueId: 'video1', + fileName: 'video1', mediaSize: 10000, ), DSVideoMessageBubble( @@ -258,7 +258,7 @@ class SampleMessageBubbleShowcase extends StatelessWidget { url: _srcsVideo[1], text: '.avi!', appBarText: 'Unknown User', - uniqueId: 'video2', + fileName: 'video2', mediaSize: 10000, ), DSVideoMessageBubble( @@ -266,7 +266,7 @@ class SampleMessageBubbleShowcase extends StatelessWidget { url: _srcsVideo[2], text: '.mpeg', appBarText: 'Unknown User', - uniqueId: 'video3', + fileName: 'video3', mediaSize: 10000, ), DSVideoMessageBubble( @@ -274,7 +274,7 @@ class SampleMessageBubbleShowcase extends StatelessWidget { url: _srcsVideo[3], text: '.mpg', appBarText: 'Unknown User', - uniqueId: 'video4', + fileName: 'video4', mediaSize: 10000, ), DSContactMessageBubble( From a99a51a3abff3661a1b5361bed61e6ec12f1fc5f Mon Sep 17 00:00:00 2001 From: RaulRodrigo06 Date: Mon, 9 Oct 2023 11:10:38 -0300 Subject: [PATCH 10/18] fix: removing fileName not used --- .../controllers/chat/ds_video_message_bubble.controller.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/src/controllers/chat/ds_video_message_bubble.controller.dart b/lib/src/controllers/chat/ds_video_message_bubble.controller.dart index 15e5779c..9d6730ef 100644 --- a/lib/src/controllers/chat/ds_video_message_bubble.controller.dart +++ b/lib/src/controllers/chat/ds_video_message_bubble.controller.dart @@ -66,8 +66,6 @@ class DSVideoMessageBubbleController { isDownloading.value = true; try { - final fileName = DateTime.now().toIso8601String(); - final mediaPath = await DSDirectoryFormatter.getPath(type: DSFileType.videos); final outputFile = File('$mediaPath/VID-$fileName.mp4'); From 562ca550bf9d1d81a36c1c912514ae10acd5d977 Mon Sep 17 00:00:00 2001 From: RaulRodrigo06 Date: Fri, 13 Oct 2023 10:16:00 -0300 Subject: [PATCH 11/18] feat: adding md5 converter --- .../ds_video_message_bubble.controller.dart | 30 +++++----- .../utils/ds_directory_formatter.util.dart | 58 +++++-------------- .../video/ds_video_message_bubble.widget.dart | 5 ++ lib/src/widgets/utils/ds_card.widget.dart | 17 +++++- pubspec.yaml | 1 + 5 files changed, 51 insertions(+), 60 deletions(-) diff --git a/lib/src/controllers/chat/ds_video_message_bubble.controller.dart b/lib/src/controllers/chat/ds_video_message_bubble.controller.dart index 9d6730ef..094b8697 100644 --- a/lib/src/controllers/chat/ds_video_message_bubble.controller.dart +++ b/lib/src/controllers/chat/ds_video_message_bubble.controller.dart @@ -5,7 +5,6 @@ import 'package:ffmpeg_kit_flutter_full_gpl/return_code.dart'; import 'package:file_sizes/file_sizes.dart'; import 'package:get/get.dart'; -import '../../enums/ds_file_type.enum.dart'; import '../../models/ds_toast_props.model.dart'; import '../../services/ds_file.service.dart'; import '../../services/ds_toast.service.dart'; @@ -17,11 +16,13 @@ class DSVideoMessageBubbleController { final String url; final int mediaSize; final Map? httpHeaders; + final String type; DSVideoMessageBubbleController({ required this.fileName, required this.url, required this.mediaSize, + required this.type, this.httpHeaders, }) { getVideoAndSetThumbnail(); @@ -44,12 +45,11 @@ class DSVideoMessageBubbleController { Future getVideoAndSetThumbnail() async { loadingThumbnail.value = true; - final mediaPath = - await DSDirectoryFormatter.getPath(type: DSFileType.videos); - final bool containsVid = fileName.contains('VID'); - final file = containsVid - ? File('$mediaPath/$fileName.mp4') - : File('$mediaPath/VID-$fileName.mp4'); + final fullPath = await DSDirectoryFormatter.getPath( + type: type, + fileName: fileName, + ); + final file = File(fullPath); if (await file.exists()) { await _generateThumbnail(file.path); } @@ -57,18 +57,22 @@ class DSVideoMessageBubbleController { } Future getFullThumbnailPath() async { - final mediaPath = - await DSDirectoryFormatter.getPath(type: DSFileType.videos); - return "$mediaPath/VID-$fileName.png"; + final mediaPath = await DSDirectoryFormatter.getPath( + type: 'image/png', + fileName: '$fileName-thumbnail', + ); + return mediaPath; } Future downloadVideo() async { isDownloading.value = true; try { - final mediaPath = - await DSDirectoryFormatter.getPath(type: DSFileType.videos); - final outputFile = File('$mediaPath/VID-$fileName.mp4'); + final fullPath = await DSDirectoryFormatter.getPath( + type: 'video/mp4', + fileName: fileName, + ); + final outputFile = File(fullPath); if (!await outputFile.exists()) { final inputFilePath = await DSFileService.download( diff --git a/lib/src/utils/ds_directory_formatter.util.dart b/lib/src/utils/ds_directory_formatter.util.dart index 2bdddada..7508236a 100644 --- a/lib/src/utils/ds_directory_formatter.util.dart +++ b/lib/src/utils/ds_directory_formatter.util.dart @@ -1,40 +1,30 @@ import 'dart:io'; import 'package:get/get.dart'; -import 'package:path/path.dart' as path; import 'package:path_provider/path_provider.dart'; -import '../enums/ds_file_type.enum.dart'; - abstract class DSDirectoryFormatter { - static Future formatMediaDirectory({ - required String filePath, - required DSFileType type, + static Future getPath({ + required String type, required String fileName, }) async { - String directory = path.dirname(filePath); - final String formattedDirectory = - await _formatDirectory(type: type, directory: directory); - final String newName = await _formatNewName( - formattedDirectory: formattedDirectory, - fileName: fileName, - filePath: filePath, - ); - await File(filePath).rename(newName); - return newName; - } - - static Future getPath({required DSFileType type}) async { final temporaryPath = (await getTemporaryDirectory()).path; - final mediaPath = _formatDirectory(type: type, directory: temporaryPath); - return mediaPath; + final typeName = '${type.split('/').first.capitalizeFirst}'; + final prefix = fileName.contains(typeName.substring(0, 3).toUpperCase()) + ? '' + : '${typeName.substring(0, 3).toUpperCase()}-'; + final extension = type.split('/').last; + final path = + await _formatDirectory(typeName: typeName, directory: temporaryPath); + final fullPath = '$path/$prefix$fileName.$extension'; + return fullPath; } static Future _formatDirectory( - {required DSFileType type, required String directory}) async { + {required String typeName, required String directory}) async { final formattedDirectory = directory.replaceAll( directory.split('/').last, - 'Blip Desk/Media/${type.name.capitalizeFirst}', + 'Blip Desk/Media/$typeName', ); final directoryExists = await Directory(formattedDirectory).exists(); if (!directoryExists) { @@ -42,26 +32,4 @@ abstract class DSDirectoryFormatter { } return formattedDirectory; } - - static Future _formatNewName({ - required String formattedDirectory, - required String fileName, - required String filePath, - }) async { - int numberOfFiles = 0; - final String extension = filePath.split('.').last; - final directory = Directory(formattedDirectory).listSync(); - - for (FileSystemEntity files in directory) { - if (files.path.contains(fileName) && - (files.path.split('.').last == extension)) { - numberOfFiles++; - } - } - - String newName = - '${path.join(formattedDirectory, fileName)}-BA$numberOfFiles.$extension'; - - return newName; - } } diff --git a/lib/src/widgets/chat/video/ds_video_message_bubble.widget.dart b/lib/src/widgets/chat/video/ds_video_message_bubble.widget.dart index 5ea157bc..267777b4 100644 --- a/lib/src/widgets/chat/video/ds_video_message_bubble.widget.dart +++ b/lib/src/widgets/chat/video/ds_video_message_bubble.widget.dart @@ -45,6 +45,9 @@ class DSVideoMessageBubble extends StatefulWidget { /// The video size final int mediaSize; + /// The video type + final String type; + /// Indicates if the HTTP Requests should be authenticated or not. final bool shouldAuthenticate; @@ -61,6 +64,7 @@ class DSVideoMessageBubble extends StatefulWidget { required this.fileName, required this.mediaSize, this.appBarPhotoUri, + this.type = 'video/mp4', this.text, this.borderRadius = const [DSBorderRadius.all], this.shouldAuthenticate = false, @@ -83,6 +87,7 @@ class _DSVideoMessageBubbleState extends State mediaSize: widget.mediaSize, httpHeaders: widget.shouldAuthenticate ? DSAuthService.httpHeaders : null, fileName: widget.fileName, + type: widget.type, ); } diff --git a/lib/src/widgets/utils/ds_card.widget.dart b/lib/src/widgets/utils/ds_card.widget.dart index a33d53b6..6fe88f00 100644 --- a/lib/src/widgets/utils/ds_card.widget.dart +++ b/lib/src/widgets/utils/ds_card.widget.dart @@ -1,3 +1,6 @@ +import 'dart:convert'; + +import 'package:crypto/crypto.dart'; import 'package:flutter/material.dart'; import '../../enums/ds_align.enum.dart'; @@ -258,7 +261,6 @@ class DSCard extends StatelessWidget { shouldAuthenticate: shouldAuthenticate, ); } else if (media.type.contains('video')) { - final fileName = media.title?.split('.').first; return DSVideoMessageBubble( url: media.uri, align: align, @@ -272,7 +274,7 @@ class DSCard extends StatelessWidget { text: media.text, borderRadius: borderRadius, style: style, - fileName: fileName ?? messageId ?? DateTime.now().toIso8601String(), + fileName: _formatFileName(media: media), mediaSize: size, shouldAuthenticate: shouldAuthenticate, ); @@ -290,6 +292,17 @@ class DSCard extends StatelessWidget { } } + String _formatFileName({required DSMediaLink media}) { + final fileName = media.title?.split('.').first; + + if (fileName != null) { + return fileName; + } else if (messageId != null) { + return md5.convert(utf8.encode(messageId!)).toString(); + } + return DateTime.now().toIso8601String(); + } + Widget _buildRequestLocation() { final label = content['label']; final type = label['type']; diff --git a/pubspec.yaml b/pubspec.yaml index 2dd99891..b1d845bd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -39,6 +39,7 @@ dependencies: dotted_border: ^2.0.0+3 map_launcher: ^2.5.0+1 mime: ^1.0.4 + crypto: ^3.0.2 dev_dependencies: flutter_test: From bc969d940682382258ba82ff42a5a821463cd6ee Mon Sep 17 00:00:00 2001 From: Marcelo Amaro Date: Mon, 16 Oct 2023 15:10:39 -0300 Subject: [PATCH 12/18] fix: fix filename prefix check in DSDirectoryFormatter --- .../utils/ds_directory_formatter.util.dart | 37 ++++++++++++------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/lib/src/utils/ds_directory_formatter.util.dart b/lib/src/utils/ds_directory_formatter.util.dart index 7508236a..860fda36 100644 --- a/lib/src/utils/ds_directory_formatter.util.dart +++ b/lib/src/utils/ds_directory_formatter.util.dart @@ -5,31 +5,42 @@ import 'package:path_provider/path_provider.dart'; abstract class DSDirectoryFormatter { static Future getPath({ - required String type, - required String fileName, + required final String type, + required final String fileName, }) async { final temporaryPath = (await getTemporaryDirectory()).path; - final typeName = '${type.split('/').first.capitalizeFirst}'; - final prefix = fileName.contains(typeName.substring(0, 3).toUpperCase()) - ? '' - : '${typeName.substring(0, 3).toUpperCase()}-'; + + final typeFolder = '${type.split('/').first.capitalizeFirst}'; final extension = type.split('/').last; - final path = - await _formatDirectory(typeName: typeName, directory: temporaryPath); - final fullPath = '$path/$prefix$fileName.$extension'; - return fullPath; + + final typePrefix = '${typeFolder.substring(0, 3).toUpperCase()}-'; + + final newFileName = + '${!fileName.startsWith(typePrefix) ? typePrefix : ''}$fileName'; + + final path = await _formatDirectory( + type: typeFolder, + directory: temporaryPath, + ); + + return '$path/$newFileName.$extension'; } - static Future _formatDirectory( - {required String typeName, required String directory}) async { + static Future _formatDirectory({ + required final String type, + required final String directory, + }) async { final formattedDirectory = directory.replaceAll( directory.split('/').last, - 'Blip Desk/Media/$typeName', + 'Blip Desk/Media/$type', ); + final directoryExists = await Directory(formattedDirectory).exists(); + if (!directoryExists) { await Directory(formattedDirectory).create(recursive: true); } + return formattedDirectory; } } From 4cf55fbd297e324d6dcda6fb350837440ef10963 Mon Sep 17 00:00:00 2001 From: RaulRodrigo06 Date: Tue, 17 Oct 2023 11:31:12 -0300 Subject: [PATCH 13/18] fix: fixing directory --- .../utils/ds_directory_formatter.util.dart | 36 +++++++------------ lib/src/widgets/utils/ds_card.widget.dart | 9 +---- pubspec.yaml | 1 + 3 files changed, 14 insertions(+), 32 deletions(-) diff --git a/lib/src/utils/ds_directory_formatter.util.dart b/lib/src/utils/ds_directory_formatter.util.dart index 860fda36..643bce8c 100644 --- a/lib/src/utils/ds_directory_formatter.util.dart +++ b/lib/src/utils/ds_directory_formatter.util.dart @@ -8,33 +8,21 @@ abstract class DSDirectoryFormatter { required final String type, required final String fileName, }) async { - final temporaryPath = (await getTemporaryDirectory()).path; - - final typeFolder = '${type.split('/').first.capitalizeFirst}'; + final temporaryPath = (await getExternalCacheDirectories())?.first.path; + final typeName = '${type.split('/').first.capitalizeFirst}'; + final prefix = fileName.contains(typeName.substring(0, 3).toUpperCase()) + ? '' + : '${typeName.substring(0, 3).toUpperCase()}-'; final extension = type.split('/').last; - - final typePrefix = '${typeFolder.substring(0, 3).toUpperCase()}-'; - - final newFileName = - '${!fileName.startsWith(typePrefix) ? typePrefix : ''}$fileName'; - - final path = await _formatDirectory( - type: typeFolder, - directory: temporaryPath, - ); - - return '$path/$newFileName.$extension'; + final path = + await _formatDirectory(typeName: typeName, directory: temporaryPath!); + final fullPath = '$path/$prefix$fileName.$extension'; + return fullPath; } - static Future _formatDirectory({ - required final String type, - required final String directory, - }) async { - final formattedDirectory = directory.replaceAll( - directory.split('/').last, - 'Blip Desk/Media/$type', - ); - + static Future _formatDirectory( + {required String typeName, required String directory}) async { + final formattedDirectory = '$directory/$typeName'; final directoryExists = await Directory(formattedDirectory).exists(); if (!directoryExists) { diff --git a/lib/src/widgets/utils/ds_card.widget.dart b/lib/src/widgets/utils/ds_card.widget.dart index 6fe88f00..94c07234 100644 --- a/lib/src/widgets/utils/ds_card.widget.dart +++ b/lib/src/widgets/utils/ds_card.widget.dart @@ -293,14 +293,7 @@ class DSCard extends StatelessWidget { } String _formatFileName({required DSMediaLink media}) { - final fileName = media.title?.split('.').first; - - if (fileName != null) { - return fileName; - } else if (messageId != null) { - return md5.convert(utf8.encode(messageId!)).toString(); - } - return DateTime.now().toIso8601String(); + return md5.convert(utf8.encode(Uri.parse(media.uri).path)).toString(); } Widget _buildRequestLocation() { diff --git a/pubspec.yaml b/pubspec.yaml index b1d845bd..6aa39707 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -40,6 +40,7 @@ dependencies: map_launcher: ^2.5.0+1 mime: ^1.0.4 crypto: ^3.0.2 + permission_handler: ^10.2.0 dev_dependencies: flutter_test: From 59a981a72cb3ed3606448a115dfd54abe7c964d8 Mon Sep 17 00:00:00 2001 From: RaulRodrigo06 Date: Tue, 17 Oct 2023 12:41:58 -0300 Subject: [PATCH 14/18] fix: removing logic from dscard --- .../chat/ds_video_message_bubble.controller.dart | 7 +++++-- .../chat/video/ds_video_message_bubble.widget.dart | 5 ----- lib/src/widgets/utils/ds_card.widget.dart | 8 -------- .../widgets/showcase/sample_message_bubble.showcase.dart | 4 ---- 4 files changed, 5 insertions(+), 19 deletions(-) diff --git a/lib/src/controllers/chat/ds_video_message_bubble.controller.dart b/lib/src/controllers/chat/ds_video_message_bubble.controller.dart index 094b8697..781afc6e 100644 --- a/lib/src/controllers/chat/ds_video_message_bubble.controller.dart +++ b/lib/src/controllers/chat/ds_video_message_bubble.controller.dart @@ -1,5 +1,7 @@ +import 'dart:convert'; import 'dart:io'; +import 'package:crypto/crypto.dart'; import 'package:ffmpeg_kit_flutter_full_gpl/ffmpeg_kit.dart'; import 'package:ffmpeg_kit_flutter_full_gpl/return_code.dart'; import 'package:file_sizes/file_sizes.dart'; @@ -12,14 +14,12 @@ import '../../utils/ds_directory_formatter.util.dart'; import '../../widgets/chat/video/ds_video_error.dialog.dart'; class DSVideoMessageBubbleController { - final String fileName; final String url; final int mediaSize; final Map? httpHeaders; final String type; DSVideoMessageBubbleController({ - required this.fileName, required this.url, required this.mediaSize, required this.type, @@ -44,6 +44,7 @@ class DSVideoMessageBubbleController { } Future getVideoAndSetThumbnail() async { + final fileName = md5.convert(utf8.encode(Uri.parse(url).path)).toString(); loadingThumbnail.value = true; final fullPath = await DSDirectoryFormatter.getPath( type: type, @@ -57,6 +58,7 @@ class DSVideoMessageBubbleController { } Future getFullThumbnailPath() async { + final fileName = md5.convert(utf8.encode(Uri.parse(url).path)).toString(); final mediaPath = await DSDirectoryFormatter.getPath( type: 'image/png', fileName: '$fileName-thumbnail', @@ -65,6 +67,7 @@ class DSVideoMessageBubbleController { } Future downloadVideo() async { + final fileName = md5.convert(utf8.encode(Uri.parse(url).path)).toString(); isDownloading.value = true; try { diff --git a/lib/src/widgets/chat/video/ds_video_message_bubble.widget.dart b/lib/src/widgets/chat/video/ds_video_message_bubble.widget.dart index 267777b4..3d6dd687 100644 --- a/lib/src/widgets/chat/video/ds_video_message_bubble.widget.dart +++ b/lib/src/widgets/chat/video/ds_video_message_bubble.widget.dart @@ -39,9 +39,6 @@ class DSVideoMessageBubble extends StatefulWidget { /// Style for bubble final DSMessageBubbleStyle style; - // Unique id to message bubble - final String fileName; - /// The video size final int mediaSize; @@ -61,7 +58,6 @@ class DSVideoMessageBubble extends StatefulWidget { required this.align, required this.url, required this.appBarText, - required this.fileName, required this.mediaSize, this.appBarPhotoUri, this.type = 'video/mp4', @@ -86,7 +82,6 @@ class _DSVideoMessageBubbleState extends State url: widget.url, mediaSize: widget.mediaSize, httpHeaders: widget.shouldAuthenticate ? DSAuthService.httpHeaders : null, - fileName: widget.fileName, type: widget.type, ); } diff --git a/lib/src/widgets/utils/ds_card.widget.dart b/lib/src/widgets/utils/ds_card.widget.dart index 94c07234..a71d1217 100644 --- a/lib/src/widgets/utils/ds_card.widget.dart +++ b/lib/src/widgets/utils/ds_card.widget.dart @@ -1,6 +1,3 @@ -import 'dart:convert'; - -import 'package:crypto/crypto.dart'; import 'package:flutter/material.dart'; import '../../enums/ds_align.enum.dart'; @@ -274,7 +271,6 @@ class DSCard extends StatelessWidget { text: media.text, borderRadius: borderRadius, style: style, - fileName: _formatFileName(media: media), mediaSize: size, shouldAuthenticate: shouldAuthenticate, ); @@ -292,10 +288,6 @@ class DSCard extends StatelessWidget { } } - String _formatFileName({required DSMediaLink media}) { - return md5.convert(utf8.encode(Uri.parse(media.uri).path)).toString(); - } - Widget _buildRequestLocation() { final label = content['label']; final type = label['type']; diff --git a/sample/lib/widgets/showcase/sample_message_bubble.showcase.dart b/sample/lib/widgets/showcase/sample_message_bubble.showcase.dart index f63af8dd..a0f33e2a 100644 --- a/sample/lib/widgets/showcase/sample_message_bubble.showcase.dart +++ b/sample/lib/widgets/showcase/sample_message_bubble.showcase.dart @@ -250,7 +250,6 @@ class SampleMessageBubbleShowcase extends StatelessWidget { url: _srcsVideo[0], text: '.mov', appBarText: 'Unknown User', - fileName: 'video1', mediaSize: 10000, ), DSVideoMessageBubble( @@ -258,7 +257,6 @@ class SampleMessageBubbleShowcase extends StatelessWidget { url: _srcsVideo[1], text: '.avi!', appBarText: 'Unknown User', - fileName: 'video2', mediaSize: 10000, ), DSVideoMessageBubble( @@ -266,7 +264,6 @@ class SampleMessageBubbleShowcase extends StatelessWidget { url: _srcsVideo[2], text: '.mpeg', appBarText: 'Unknown User', - fileName: 'video3', mediaSize: 10000, ), DSVideoMessageBubble( @@ -274,7 +271,6 @@ class SampleMessageBubbleShowcase extends StatelessWidget { url: _srcsVideo[3], text: '.mpg', appBarText: 'Unknown User', - fileName: 'video4', mediaSize: 10000, ), DSContactMessageBubble( From 1f646d29325860016292e5cdf2542f8e5ef9271e Mon Sep 17 00:00:00 2001 From: RaulRodrigo06 Date: Tue, 17 Oct 2023 15:36:06 -0300 Subject: [PATCH 15/18] fix: showing file on gallery --- lib/src/utils/ds_directory_formatter.util.dart | 4 +++- pubspec.yaml | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/src/utils/ds_directory_formatter.util.dart b/lib/src/utils/ds_directory_formatter.util.dart index 643bce8c..16ae7070 100644 --- a/lib/src/utils/ds_directory_formatter.util.dart +++ b/lib/src/utils/ds_directory_formatter.util.dart @@ -8,7 +8,9 @@ abstract class DSDirectoryFormatter { required final String type, required final String fileName, }) async { - final temporaryPath = (await getExternalCacheDirectories())?.first.path; + final String? temporaryPath = Platform.isAndroid + ? (await getExternalCacheDirectories())?.first.path + : (await getApplicationCacheDirectory()).path; final typeName = '${type.split('/').first.capitalizeFirst}'; final prefix = fileName.contains(typeName.substring(0, 3).toUpperCase()) ? '' diff --git a/pubspec.yaml b/pubspec.yaml index 6aa39707..6a16ad8f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -18,7 +18,7 @@ dependencies: get: ^4.6.5 filesize: ^2.0.1 open_filex: ^4.3.2 - path_provider: ^2.0.11 + path_provider: ^2.1.1 dio: ^5.2.1+1 url_launcher: ^6.1.5 path: ^1.8.1 From 2184eff4954b20b984928c752065b5de474fd5e6 Mon Sep 17 00:00:00 2001 From: Marcelo Amaro Date: Thu, 19 Oct 2023 17:40:04 -0300 Subject: [PATCH 16/18] feat: change DSDirectoryFormatter path getter to always return Application Cache folder --- .../utils/ds_directory_formatter.util.dart | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/lib/src/utils/ds_directory_formatter.util.dart b/lib/src/utils/ds_directory_formatter.util.dart index 16ae7070..49fb68c0 100644 --- a/lib/src/utils/ds_directory_formatter.util.dart +++ b/lib/src/utils/ds_directory_formatter.util.dart @@ -8,23 +8,29 @@ abstract class DSDirectoryFormatter { required final String type, required final String fileName, }) async { - final String? temporaryPath = Platform.isAndroid - ? (await getExternalCacheDirectories())?.first.path - : (await getApplicationCacheDirectory()).path; - final typeName = '${type.split('/').first.capitalizeFirst}'; - final prefix = fileName.contains(typeName.substring(0, 3).toUpperCase()) - ? '' - : '${typeName.substring(0, 3).toUpperCase()}-'; + final cachePath = (await getApplicationCacheDirectory()).path; + + final typeFolder = '${type.split('/').first.capitalizeFirst}'; final extension = type.split('/').last; - final path = - await _formatDirectory(typeName: typeName, directory: temporaryPath!); - final fullPath = '$path/$prefix$fileName.$extension'; - return fullPath; + + final typePrefix = '${typeFolder.substring(0, 3).toUpperCase()}-'; + + final newFileName = + '${!fileName.startsWith(typePrefix) ? typePrefix : ''}$fileName'; + + final path = await _formatDirectory( + type: typeFolder, + directory: cachePath, + ); + + return '$path/$newFileName.$extension'; } - static Future _formatDirectory( - {required String typeName, required String directory}) async { - final formattedDirectory = '$directory/$typeName'; + static Future _formatDirectory({ + required final String type, + required final String directory, + }) async { + final formattedDirectory = '$directory/$type'; final directoryExists = await Directory(formattedDirectory).exists(); if (!directoryExists) { From 4eedd06f2f4e83d43e042b5a273829e6975448eb Mon Sep 17 00:00:00 2001 From: RaulRodrigo06 Date: Thu, 19 Oct 2023 19:51:28 -0300 Subject: [PATCH 17/18] refactor: code improvement --- lib/blip_ds.dart | 1 - .../ds_video_message_bubble.controller.dart | 36 ++++++++++++------- lib/src/enums/ds_file_type.enum.dart | 5 --- .../video/ds_video_message_bubble.widget.dart | 7 ++-- pubspec.yaml | 2 -- 5 files changed, 27 insertions(+), 24 deletions(-) delete mode 100644 lib/src/enums/ds_file_type.enum.dart diff --git a/lib/blip_ds.dart b/lib/blip_ds.dart index ebd3ccf8..7f2b52e5 100644 --- a/lib/blip_ds.dart +++ b/lib/blip_ds.dart @@ -4,7 +4,6 @@ export 'src/enums/ds_align.enum.dart' show DSAlign; export 'src/enums/ds_border_radius.enum.dart' show DSBorderRadius; export 'src/enums/ds_delivery_report_status.enum.dart' show DSDeliveryReportStatus; -export 'src/enums/ds_file_type.enum.dart' show DSFileType; export 'src/enums/ds_input_container_shape.enum.dart' show DSInputContainerShape; export 'src/enums/ds_survey_scale.enum.dart' show DSSurveyScale; diff --git a/lib/src/controllers/chat/ds_video_message_bubble.controller.dart b/lib/src/controllers/chat/ds_video_message_bubble.controller.dart index 781afc6e..9a73ee87 100644 --- a/lib/src/controllers/chat/ds_video_message_bubble.controller.dart +++ b/lib/src/controllers/chat/ds_video_message_bubble.controller.dart @@ -25,13 +25,13 @@ class DSVideoMessageBubbleController { required this.type, this.httpHeaders, }) { - getVideoAndSetThumbnail(); + getStoredVideo(); } final isDownloading = RxBool(false); final thumbnail = RxString(''); final hasError = RxBool(false); - final loadingThumbnail = RxBool(true); + final isLoadingThumbnail = RxBool(false); String size() { return mediaSize > 0 @@ -43,18 +43,28 @@ class DSVideoMessageBubbleController { : 'Download'; } - Future getVideoAndSetThumbnail() async { - final fileName = md5.convert(utf8.encode(Uri.parse(url).path)).toString(); - loadingThumbnail.value = true; - final fullPath = await DSDirectoryFormatter.getPath( - type: type, - fileName: fileName, - ); - final file = File(fullPath); - if (await file.exists()) { - await _generateThumbnail(file.path); + Future getStoredVideo() async { + try { + isLoadingThumbnail.value = true; + final fileName = md5.convert(utf8.encode(Uri.parse(url).path)).toString(); + final fullPath = await DSDirectoryFormatter.getPath( + type: type, + fileName: fileName, + ); + final fullThumbnailPath = await DSDirectoryFormatter.getPath( + type: 'image/png', + fileName: '$fileName-thumbnail', + ); + final file = File(fullPath); + final thumbnailfile = File(fullThumbnailPath); + if (await thumbnailfile.exists()) { + thumbnail.value = thumbnailfile.path; + } else if (await file.exists() && thumbnail.value.isEmpty) { + await _generateThumbnail(file.path); + } + } finally { + isLoadingThumbnail.value = false; } - loadingThumbnail.value = false; } Future getFullThumbnailPath() async { diff --git a/lib/src/enums/ds_file_type.enum.dart b/lib/src/enums/ds_file_type.enum.dart deleted file mode 100644 index 7db4f696..00000000 --- a/lib/src/enums/ds_file_type.enum.dart +++ /dev/null @@ -1,5 +0,0 @@ -enum DSFileType { - videos, - documents, - images, -} diff --git a/lib/src/widgets/chat/video/ds_video_message_bubble.widget.dart b/lib/src/widgets/chat/video/ds_video_message_bubble.widget.dart index 3d6dd687..33a3916b 100644 --- a/lib/src/widgets/chat/video/ds_video_message_bubble.widget.dart +++ b/lib/src/widgets/chat/video/ds_video_message_bubble.widget.dart @@ -136,13 +136,14 @@ class _DSVideoMessageBubbleState extends State color: DSColors.neutralDarkRooftop, ) : (_controller.isDownloading.value || - _controller.loadingThumbnail.value) + _controller.isLoadingThumbnail.value) ? Center( child: Container( height: 50.0, decoration: BoxDecoration( - shape: BoxShape.circle, - color: foregroundColor), + shape: BoxShape.circle, + color: foregroundColor, + ), child: DSFadingCircleLoading( color: backgroundLoadingColor, size: 45.0, diff --git a/pubspec.yaml b/pubspec.yaml index 6a16ad8f..3a6bb5cd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -39,8 +39,6 @@ dependencies: dotted_border: ^2.0.0+3 map_launcher: ^2.5.0+1 mime: ^1.0.4 - crypto: ^3.0.2 - permission_handler: ^10.2.0 dev_dependencies: flutter_test: From d6fa47ad42ef05a891bde5fc8085b0bd1e2d5094 Mon Sep 17 00:00:00 2001 From: Marcelo Amaro Date: Fri, 20 Oct 2023 14:31:18 -0300 Subject: [PATCH 18/18] chore: get dependencies from sample --- pubspec.yaml | 1 + sample/pubspec.lock | 30 +++++++++++++++--------------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/pubspec.yaml b/pubspec.yaml index 3a6bb5cd..46241f6c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -39,6 +39,7 @@ dependencies: dotted_border: ^2.0.0+3 map_launcher: ^2.5.0+1 mime: ^1.0.4 + crypto: ^3.0.3 dev_dependencies: flutter_test: diff --git a/sample/pubspec.lock b/sample/pubspec.lock index 5735e40c..67d875ba 100644 --- a/sample/pubspec.lock +++ b/sample/pubspec.lock @@ -108,10 +108,10 @@ packages: dependency: transitive description: name: crypto - sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.3" csslib: dependency: transitive description: @@ -499,50 +499,50 @@ packages: dependency: transitive description: name: path_provider - sha256: dcea5feb97d8abf90cab9e9030b497fb7c3cbf26b7a1fe9e3ef7dcb0a1ddec95 + sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa url: "https://pub.dev" source: hosted - version: "2.0.12" + version: "2.1.1" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: a776c088d671b27f6e3aa8881d64b87b3e80201c64e8869b811325de7a76c15e + sha256: "6b8b19bd80da4f11ce91b2d1fb931f3006911477cec227cce23d3253d80df3f1" url: "https://pub.dev" source: hosted - version: "2.0.22" + version: "2.2.0" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "62a68e7e1c6c459f9289859e2fae58290c981ce21d1697faf54910fe1faa4c74" + sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.3.1" path_provider_linux: dependency: transitive description: name: path_provider_linux - sha256: ab0987bf95bc591da42dffb38c77398fc43309f0b9b894dcc5d6f40c4b26c379 + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 url: "https://pub.dev" source: hosted - version: "2.1.7" + version: "2.2.1" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface - sha256: f0abc8ebd7253741f05488b4813d936b4d07c6bae3e86148a09e342ee4b08e76 + sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c" url: "https://pub.dev" source: hosted - version: "2.0.5" + version: "2.1.1" path_provider_windows: dependency: transitive description: name: path_provider_windows - sha256: bcabbe399d4042b8ee687e17548d5d3f527255253b4a639f5f8d2094a9c2b45c + sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.2.1" pedantic: dependency: transitive description: @@ -974,4 +974,4 @@ packages: version: "6.3.0" sdks: dart: ">=3.1.0-185.0.dev <4.0.0" - flutter: ">=3.7.0-0" + flutter: ">=3.7.0"