Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[Release] 0.0.86 #226

Merged
merged 31 commits into from
Nov 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
20aabee
feat: add video compression args to ffmpeg command
Sep 21, 2023
77f2847
Merge branch 'develop' into feature/531525-video-compression
Sep 22, 2023
6ec3983
feat: add ffmpeg service class
Sep 22, 2023
cecdcf4
Merge branch 'develop' into feature/531525-video-compression
Sep 22, 2023
42b26bb
Merge branch 'develop' into feature/531525-video-compression
Sep 25, 2023
0d5b62e
Merge branch 'develop' into feature/531525-video-compression
Sep 25, 2023
ec9eb22
feat: add ffmpeg service to export
Sep 26, 2023
4045d59
feat: add merge audio method in ffmpeg service
Sep 27, 2023
a715442
feat: change video compression from 480p to 720p
Sep 27, 2023
83fdecb
feat: get media info in ffmpeg service
Sep 29, 2023
a9a495d
fix: toast layout when message is empty
Oct 13, 2023
c9de69d
Merge branch 'develop' into feature/531525-video-compression
Oct 16, 2023
69d3895
feat: use media info to decide if video should be compressed
Oct 17, 2023
4e971d4
feat: change video compression target resolution from 720 to 480
Oct 18, 2023
0ce0317
Merge branch 'develop' into feature/531525-video-compression
Oct 25, 2023
662bca3
feat: add hardware acceleration to video compression
Oct 25, 2023
2f5c990
fix: removed code
Oct 30, 2023
7dafa5c
feat: video compression general improvements
Oct 30, 2023
8b5d0f7
feat: delete input file after formatting video
Oct 31, 2023
a00611e
fix: remove deleteSync after video was downloaded
Oct 31, 2023
d133790
fix: download extension in DSFileService
Oct 31, 2023
21c66b9
fix: check audio source to download
Oct 31, 2023
5113861
Merge branch 'develop' into feature/531525-video-compression
Oct 31, 2023
c5429c6
chore: update pubspec.lock from sample
Nov 1, 2023
35b472b
refactor: rename service from DSFFMpegService to DSMediaFormatService
Nov 1, 2023
bdb764f
fix: get extension from mime type when returning cache path
Nov 1, 2023
f22ea13
fix: change extension from downloaded file only if it doesn't have an…
Nov 1, 2023
52d19a4
feat: add method to generate unique id in DSUtils
Nov 1, 2023
c8d5707
chore: upgrade app version from 0.0.85 to 0.0.86
Nov 1, 2023
9149e28
Merge pull request #225 from takenet/feature/531525-video-compression
mpamaro Nov 1, 2023
4e5b3fa
Merge branch 'develop' into release/0.0.86
Nov 1, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 0.0.86

- [DSMediaFormatService] Added service to format all kinds of media, like audios and videos.
- [DSAudioPlayer] Play audio from local storage when available.
- [DSFileService] Improved download method to get extension based on mime type.

## 0.0.85

- [DSVideoMessageBubble] Added a progressive loading
Expand Down
1 change: 1 addition & 0 deletions lib/blip_ds.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export 'src/services/ds_auth.service.dart' show DSAuthService;
export 'src/services/ds_bottom_sheet.service.dart' show DSBottomSheetService;
export 'src/services/ds_dialog.service.dart' show DSDialogService;
export 'src/services/ds_file.service.dart' show DSFileService;
export 'src/services/ds_media_format.service.dart' show DSMediaFormatService;
export 'src/services/ds_toast.service.dart' show DSToastService;
export 'src/themes/colors/ds_colors.theme.dart' show DSColors;
export 'src/themes/colors/ds_linear_gradient.theme.dart' show DSLinearGradient;
Expand Down
13 changes: 8 additions & 5 deletions lib/src/controllers/chat/ds_file_message_bubble.controller.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import 'package:filesize/filesize.dart';
import 'package:file_sizes/file_sizes.dart';
import 'package:get/get.dart';

import '../../services/ds_file.service.dart';
Expand All @@ -7,17 +7,20 @@ class DSFileMessageBubbleController extends GetxController {
final isDownloading = RxBool(false);

String getFileSize(final int size) {
return size > 0 ? filesize(size, 1) : '';
return size > 0
? FileSize.getSize(
size,
precision: PrecisionValue.One,
)
: '';
}

Future<void> openFile({
required final String filename,
required final String url,
final Map<String, String?>? httpHeaders,
}) =>
DSFileService.open(
filename,
url,
url: url,
onDownloadStateChange: (loading) => isDownloading.value = loading,
httpHeaders: httpHeaders,
);
Expand Down
14 changes: 6 additions & 8 deletions lib/src/controllers/chat/ds_image_message_bubble.controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import 'dart:io';

import 'package:crypto/crypto.dart';
import 'package:get/get.dart';
import 'package:path/path.dart' as path_utils;

import '../../services/ds_auth.service.dart';
import '../../services/ds_file.service.dart';
Expand Down Expand Up @@ -40,21 +39,20 @@ class DSImageMessageBubbleController extends GetxController {

final uri = Uri.parse(url);

final fullPath = await DSDirectoryFormatter.getPath(
final cachePath = await DSDirectoryFormatter.getCachePath(
type: mediaType!,
fileName: md5.convert(utf8.encode(uri.path)).toString(),
filename: md5.convert(utf8.encode(uri.path)).toString(),
);

if (await File(fullPath).exists()) {
localPath.value = fullPath;
if (File(cachePath).existsSync()) {
localPath.value = cachePath;
return;
}

try {
final savedFilePath = await DSFileService.download(
url,
path_utils.basename(fullPath),
path: path_utils.dirname(fullPath),
url: url,
path: cachePath,
onReceiveProgress: _onReceiveProgress,
httpHeaders: shouldAuthenticate ? DSAuthService.httpHeaders : null,
);
Expand Down
53 changes: 31 additions & 22 deletions lib/src/controllers/chat/ds_video_message_bubble.controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@ import 'dart:convert';
import 'dart:io';

import 'package:crypto/crypto.dart';
import 'package:ffmpeg_kit_flutter_full_gpl/ffmpeg_kit.dart';
import 'package:file_sizes/file_sizes.dart';
import 'package:get/get.dart';
import 'package:path/path.dart' as path_utils;

import '../../models/ds_toast_props.model.dart';
import '../../services/ds_file.service.dart';
import '../../services/ds_media_format.service.dart';
import '../../services/ds_toast.service.dart';
import '../../utils/ds_directory_formatter.util.dart';

Expand Down Expand Up @@ -48,19 +47,23 @@ class DSVideoMessageBubbleController {
try {
isLoadingThumbnail.value = true;
final fileName = md5.convert(utf8.encode(Uri.parse(url).path)).toString();
final fullPath = await DSDirectoryFormatter.getPath(

final fullPath = await DSDirectoryFormatter.getCachePath(
type: type,
fileName: fileName,
filename: fileName,
);
final fullThumbnailPath = await DSDirectoryFormatter.getPath(

final fullThumbnailPath = await DSDirectoryFormatter.getCachePath(
type: 'image/png',
fileName: '$fileName-thumbnail',
filename: '$fileName-thumbnail',
);

final file = File(fullPath);
final thumbnailfile = File(fullThumbnailPath);
if (await thumbnailfile.exists()) {

if (thumbnailfile.existsSync()) {
thumbnail.value = thumbnailfile.path;
} else if (await file.exists() && thumbnail.value.isEmpty) {
} else if (file.existsSync() && thumbnail.value.isEmpty) {
await _generateThumbnail(file.path);
}
} finally {
Expand All @@ -70,38 +73,43 @@ class DSVideoMessageBubbleController {

Future<String> getFullThumbnailPath() async {
final fileName = md5.convert(utf8.encode(Uri.parse(url).path)).toString();
final mediaPath = await DSDirectoryFormatter.getPath(

return DSDirectoryFormatter.getCachePath(
type: 'image/png',
fileName: '$fileName-thumbnail',
filename: '$fileName-thumbnail',
);
return mediaPath;
}

Future<void> downloadVideo() async {
final fileName = md5.convert(utf8.encode(Uri.parse(url).path)).toString();
isDownloading.value = true;

try {
final fullPath = await DSDirectoryFormatter.getPath(
final cachePath = await DSDirectoryFormatter.getCachePath(
type: 'video/mp4',
fileName: fileName,
filename: md5.convert(utf8.encode(Uri.parse(url).path)).toString(),
);
final outputFile = File(fullPath);

if (!await outputFile.exists()) {
final outputFile = File(cachePath);

if (!outputFile.existsSync()) {
final inputFilePath = await DSFileService.download(
url,
path_utils.basename(fullPath),
path: path_utils.dirname(fullPath),
url: url,
onReceiveProgress: (current, max) {
downloadProgress.value = current;
maximumProgress.value = max;
},
httpHeaders: httpHeaders,
);

_generateThumbnail(inputFilePath!);
final isSuccess = await DSMediaFormatService.formatVideo(
input: inputFilePath!,
output: cachePath,
);

hasError.value = !isSuccess;
}

_generateThumbnail(outputFile.path);
} catch (_) {
hasError.value = true;

Expand All @@ -120,8 +128,9 @@ class DSVideoMessageBubbleController {
Future<void> _generateThumbnail(String path) async {
final thumbnailPath = await getFullThumbnailPath();

await FFmpegKit.execute(
'-hide_banner -y -i "$path" -vframes 1 "$thumbnailPath"',
await DSMediaFormatService.getVideoThumbnail(
input: path,
output: thumbnailPath,
);

thumbnail.value = thumbnailPath;
Expand Down
3 changes: 0 additions & 3 deletions lib/src/controllers/ds_video_player.controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,7 @@ class DSVideoPlayerController extends GetxController {
Get.back();
Get.delete<DSVideoPlayerController>();

final filename = url.substring(url.lastIndexOf('/')).substring(1);

await DSVideoErrorDialog.show(
filename: filename,
url: url,
httpHeaders: shouldAuthenticate ? DSAuthService.httpHeaders : null,
);
Expand Down
3 changes: 2 additions & 1 deletion lib/src/extensions/ds_border_radius.extension.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:blip_ds/blip_ds.dart';
import 'package:flutter/material.dart';

import '../enums/ds_border_radius.enum.dart';

/// A Design System's extension that adds functionalities to [DSBorderRadius] enum.
extension DSBorderRadiusExtension on DSBorderRadius {
BorderRadius getCircularBorderRadius({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import 'package:blip_ds/blip_ds.dart';
import '../enums/ds_delivery_report_status.enum.dart';

extension DSDeliveryReportStatusExtension on DSDeliveryReportStatus {
DSDeliveryReportStatus getValue(String value) =>
Expand Down
3 changes: 2 additions & 1 deletion lib/src/models/ds_message_item.model.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:blip_ds/blip_ds.dart';
import '../enums/ds_align.enum.dart';
import '../enums/ds_delivery_report_status.enum.dart';

/// A Design System message model used with [DSGroupCard] to display grouped bubble
class DSMessageItemModel {
Expand Down
3 changes: 0 additions & 3 deletions lib/src/models/ds_select_option.model.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
import 'package:blip_ds/src/widgets/chat/ds_quick_reply.widget.dart';
import 'package:blip_ds/src/widgets/chat/ds_select_menu.widget.dart';

/// A Design System select options model used with [DSSelectMenu], [DSQuickReply] to display a options menu
class DSSelectOptionModel {
String text;
Expand Down
54 changes: 39 additions & 15 deletions lib/src/services/ds_file.service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,27 @@ import 'package:path/path.dart' as path_utils;
import 'package:path_provider/path_provider.dart';
import 'package:url_launcher/url_launcher_string.dart';

import '../utils/ds_utils.util.dart';

abstract class DSFileService {
static Future<void> open(
final String filename,
final String url, {
static Future<void> open({
required final String url,
final String? path,
final void Function(bool)? onDownloadStateChange,
final Map<String, String?>? httpHeaders,
}) async {
final path = await download(
url,
filename,
final filePath = await download(
url: url,
path: path,
onDownloadStateChange: onDownloadStateChange,
httpHeaders: httpHeaders,
);

if (path?.isEmpty ?? true) {
if (filePath?.isEmpty ?? true) {
return;
}

final result = await OpenFilex.open(path);
final result = await OpenFilex.open(filePath);

switch (result.type) {
case ResultType.done:
Expand All @@ -41,20 +43,23 @@ abstract class DSFileService {
}
}

static Future<String?> download(
final String url,
final String filename, {
static Future<String?> download({
required final String url,
final String? path,
final void Function(bool)? onDownloadStateChange,
final Map<String, String?>? httpHeaders,
final Function(int, int)? onReceiveProgress,
}) async {
try {
onDownloadStateChange?.call(true);
final savedFilePath = path_utils.join(
path ?? (await getTemporaryDirectory()).path, filename);

if (await File(savedFilePath).exists()) {
var savedFilePath = path ??
path_utils.join(
(await getTemporaryDirectory()).path,
DSUtils.generateUniqueID(),
);

if (File(savedFilePath).existsSync()) {
return savedFilePath;
}

Expand All @@ -70,7 +75,26 @@ abstract class DSFileService {
: null,
);

if (response.statusCode == 200) return savedFilePath;
if (response.statusCode == 200) {
final hasExtension = path_utils.extension(savedFilePath).isNotEmpty;

if (!hasExtension) {
final newExtension = getFileExtensionFromMime(
response.headers.map['content-type']?.first,
);

if (newExtension.isNotEmpty) {
final filename = savedFilePath.substring(0);

final newFilePath = '$filename.$newExtension';

File(savedFilePath).renameSync(newFilePath);
savedFilePath = newFilePath;
}
}

return savedFilePath;
}
} finally {
onDownloadStateChange?.call(false);
}
Expand Down
Loading