mirror of
https://gitlab.com/comunic/comunicmobile
synced 2024-11-26 06:49:22 +00:00
Generate video thumbnails
This commit is contained in:
parent
8f7ca14586
commit
b84eba59e3
@ -312,6 +312,9 @@ class ConversationsHelper {
|
|||||||
// Check for file
|
// Check for file
|
||||||
if (message.hasFile) request.addBytesFile("file", message.file);
|
if (message.hasFile) request.addBytesFile("file", message.file);
|
||||||
|
|
||||||
|
if (message.hasThumbnail)
|
||||||
|
request.addBytesFile("thumbnail", message.thumbnail);
|
||||||
|
|
||||||
//Send the message
|
//Send the message
|
||||||
APIResponse response;
|
APIResponse response;
|
||||||
if (!message.hasFile)
|
if (!message.hasFile)
|
||||||
|
@ -54,10 +54,16 @@ class ServerConfigurationHelper {
|
|||||||
conversationsPolicy: ConversationsPolicy(
|
conversationsPolicy: ConversationsPolicy(
|
||||||
minMessageLen: conversationsPolicy["min_message_len"],
|
minMessageLen: conversationsPolicy["min_message_len"],
|
||||||
maxMessageLen: conversationsPolicy["max_message_len"],
|
maxMessageLen: conversationsPolicy["max_message_len"],
|
||||||
allowedFilesType: conversationsPolicy["allowed_files_type"].cast<String>(),
|
allowedFilesType:
|
||||||
|
conversationsPolicy["allowed_files_type"].cast<String>(),
|
||||||
filesMaxSize: conversationsPolicy["files_max_size"],
|
filesMaxSize: conversationsPolicy["files_max_size"],
|
||||||
writingEventInterval: conversationsPolicy["writing_event_interval"],
|
writingEventInterval: conversationsPolicy["writing_event_interval"],
|
||||||
writingEventLifetime: conversationsPolicy["writing_event_lifetime"],
|
writingEventLifetime: conversationsPolicy["writing_event_lifetime"],
|
||||||
|
maxMessageImageWidth: conversationsPolicy["max_message_image_width"],
|
||||||
|
maxMessageImageHeight:
|
||||||
|
conversationsPolicy["max_message_image_height"],
|
||||||
|
maxThumbnailWidth: conversationsPolicy["max_thumbnail_width"],
|
||||||
|
maxThumbnailHeight: conversationsPolicy["max_thumbnail_height"],
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,15 +11,19 @@ class NewConversationMessage {
|
|||||||
final int conversationID;
|
final int conversationID;
|
||||||
final String message;
|
final String message;
|
||||||
final BytesFile file;
|
final BytesFile file;
|
||||||
|
final BytesFile thumbnail;
|
||||||
|
|
||||||
NewConversationMessage({
|
NewConversationMessage({
|
||||||
@required this.conversationID,
|
@required this.conversationID,
|
||||||
@required this.message,
|
@required this.message,
|
||||||
this.file,
|
this.file,
|
||||||
|
this.thumbnail,
|
||||||
}) : assert(conversationID != null),
|
}) : assert(conversationID != null),
|
||||||
assert(file != null || message != null);
|
assert(file != null || message != null);
|
||||||
|
|
||||||
bool get hasMessage => message != null;
|
bool get hasMessage => message != null;
|
||||||
|
|
||||||
bool get hasFile => file != null;
|
bool get hasFile => file != null;
|
||||||
|
|
||||||
|
bool get hasThumbnail => thumbnail != null;
|
||||||
}
|
}
|
||||||
|
@ -64,6 +64,10 @@ class ConversationsPolicy {
|
|||||||
final int filesMaxSize;
|
final int filesMaxSize;
|
||||||
final int writingEventInterval;
|
final int writingEventInterval;
|
||||||
final int writingEventLifetime;
|
final int writingEventLifetime;
|
||||||
|
final int maxMessageImageWidth;
|
||||||
|
final int maxMessageImageHeight;
|
||||||
|
final int maxThumbnailWidth;
|
||||||
|
final int maxThumbnailHeight;
|
||||||
|
|
||||||
const ConversationsPolicy({
|
const ConversationsPolicy({
|
||||||
@required this.minMessageLen,
|
@required this.minMessageLen,
|
||||||
@ -72,12 +76,20 @@ class ConversationsPolicy {
|
|||||||
@required this.filesMaxSize,
|
@required this.filesMaxSize,
|
||||||
@required this.writingEventInterval,
|
@required this.writingEventInterval,
|
||||||
@required this.writingEventLifetime,
|
@required this.writingEventLifetime,
|
||||||
|
@required this.maxMessageImageWidth,
|
||||||
|
@required this.maxMessageImageHeight,
|
||||||
|
@required this.maxThumbnailWidth,
|
||||||
|
@required this.maxThumbnailHeight,
|
||||||
}) : assert(minMessageLen != null),
|
}) : assert(minMessageLen != null),
|
||||||
assert(maxMessageLen != null),
|
assert(maxMessageLen != null),
|
||||||
assert(allowedFilesType != null),
|
assert(allowedFilesType != null),
|
||||||
assert(filesMaxSize != null),
|
assert(filesMaxSize != null),
|
||||||
assert(writingEventInterval != null),
|
assert(writingEventInterval != null),
|
||||||
assert(writingEventLifetime != null);
|
assert(writingEventLifetime != null),
|
||||||
|
assert(maxMessageImageWidth != null),
|
||||||
|
assert(maxMessageImageHeight != null),
|
||||||
|
assert(maxThumbnailWidth != null),
|
||||||
|
assert(maxThumbnailHeight != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
class ServerConfig {
|
class ServerConfig {
|
||||||
|
@ -77,8 +77,8 @@ Future<BytesFile> showPickFileDialog({
|
|||||||
@required BuildContext context,
|
@required BuildContext context,
|
||||||
int maxFileSize,
|
int maxFileSize,
|
||||||
List<String> allowedMimeTypes,
|
List<String> allowedMimeTypes,
|
||||||
double imageMaxWidth,
|
int imageMaxWidth,
|
||||||
double imageMaxHeight,
|
int imageMaxHeight,
|
||||||
}) async {
|
}) async {
|
||||||
assert(allowedMimeTypes != null);
|
assert(allowedMimeTypes != null);
|
||||||
|
|
||||||
@ -113,8 +113,8 @@ Future<BytesFile> showPickFileDialog({
|
|||||||
source: choice == _FileChoices.PICK_IMAGE
|
source: choice == _FileChoices.PICK_IMAGE
|
||||||
? ImageSource.gallery
|
? ImageSource.gallery
|
||||||
: ImageSource.camera,
|
: ImageSource.camera,
|
||||||
maxWidth: imageMaxWidth,
|
maxWidth: imageMaxWidth.toDouble(),
|
||||||
maxHeight: imageMaxHeight,
|
maxHeight: imageMaxHeight.toDouble(),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (image == null) return null;
|
if (image == null) return null;
|
||||||
|
@ -6,6 +6,7 @@ import 'package:comunic/helpers/server_config_helper.dart';
|
|||||||
import 'package:comunic/helpers/users_helper.dart';
|
import 'package:comunic/helpers/users_helper.dart';
|
||||||
import 'package:comunic/lists/conversation_messages_list.dart';
|
import 'package:comunic/lists/conversation_messages_list.dart';
|
||||||
import 'package:comunic/lists/users_list.dart';
|
import 'package:comunic/lists/users_list.dart';
|
||||||
|
import 'package:comunic/models/api_request.dart';
|
||||||
import 'package:comunic/models/conversation.dart';
|
import 'package:comunic/models/conversation.dart';
|
||||||
import 'package:comunic/models/conversation_message.dart';
|
import 'package:comunic/models/conversation_message.dart';
|
||||||
import 'package:comunic/models/new_conversation_message.dart';
|
import 'package:comunic/models/new_conversation_message.dart';
|
||||||
@ -15,11 +16,14 @@ import 'package:comunic/ui/tiles/conversation_message_tile.dart';
|
|||||||
import 'package:comunic/ui/tiles/server_conversation_message_tile.dart';
|
import 'package:comunic/ui/tiles/server_conversation_message_tile.dart';
|
||||||
import 'package:comunic/ui/widgets/safe_state.dart';
|
import 'package:comunic/ui/widgets/safe_state.dart';
|
||||||
import 'package:comunic/ui/widgets/scroll_watcher.dart';
|
import 'package:comunic/ui/widgets/scroll_watcher.dart';
|
||||||
|
import 'package:comunic/utils/files_utils.dart';
|
||||||
import 'package:comunic/utils/intl_utils.dart';
|
import 'package:comunic/utils/intl_utils.dart';
|
||||||
import 'package:comunic/utils/list_utils.dart';
|
import 'package:comunic/utils/list_utils.dart';
|
||||||
import 'package:comunic/utils/log_utils.dart';
|
import 'package:comunic/utils/log_utils.dart';
|
||||||
import 'package:comunic/utils/ui_utils.dart';
|
import 'package:comunic/utils/ui_utils.dart';
|
||||||
|
import 'package:comunic/utils/video_utils.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:mime/mime.dart';
|
||||||
|
|
||||||
/// Conversation screen
|
/// Conversation screen
|
||||||
///
|
///
|
||||||
@ -227,16 +231,23 @@ class _ConversationScreenState extends SafeState<ConversationScreen> {
|
|||||||
context: context,
|
context: context,
|
||||||
maxFileSize: srvConfig.conversationsPolicy.filesMaxSize,
|
maxFileSize: srvConfig.conversationsPolicy.filesMaxSize,
|
||||||
allowedMimeTypes: srvConfig.conversationsPolicy.allowedFilesType,
|
allowedMimeTypes: srvConfig.conversationsPolicy.allowedFilesType,
|
||||||
|
imageMaxWidth: srvConfig.conversationsPolicy.maxMessageImageWidth,
|
||||||
|
imageMaxHeight: srvConfig.conversationsPolicy.maxMessageImageHeight,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (file == null) return;
|
if (file == null) return;
|
||||||
|
|
||||||
|
BytesFile thumbnail;
|
||||||
|
|
||||||
|
if (isVideo(lookupMimeType(file.filename)))
|
||||||
|
thumbnail = await generateVideoThumbnail(videoFile: file);
|
||||||
|
|
||||||
await _submitMessage(
|
await _submitMessage(
|
||||||
NewConversationMessage(
|
NewConversationMessage(
|
||||||
conversationID: widget.conversationID,
|
conversationID: widget.conversationID,
|
||||||
message: null,
|
message: null,
|
||||||
file: file,
|
file: file,
|
||||||
),
|
thumbnail: thumbnail),
|
||||||
);
|
);
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
logError(e, s);
|
logError(e, s);
|
||||||
|
@ -90,7 +90,9 @@ class ConversationMessageTile extends StatelessWidget {
|
|||||||
|
|
||||||
// Update message content
|
// Update message content
|
||||||
PopupMenuItem(
|
PopupMenuItem(
|
||||||
enabled: message.isOwner,
|
enabled: message.isOwner &&
|
||||||
|
message.message != null &&
|
||||||
|
message.message.content.isNotEmpty,
|
||||||
value: _MenuChoices.REQUEST_UPDATE_CONTENT,
|
value: _MenuChoices.REQUEST_UPDATE_CONTENT,
|
||||||
child: Text(tr("Update")),
|
child: Text(tr("Update")),
|
||||||
),
|
),
|
||||||
|
40
lib/utils/video_utils.dart
Normal file
40
lib/utils/video_utils.dart
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:comunic/models/api_request.dart';
|
||||||
|
import 'package:comunic/utils/log_utils.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:path/path.dart' as path;
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
import 'package:random_string/random_string.dart';
|
||||||
|
import 'package:video_thumbnail/video_thumbnail.dart';
|
||||||
|
|
||||||
|
/// Video utilities
|
||||||
|
///
|
||||||
|
/// @author Pierre Hubert
|
||||||
|
|
||||||
|
/// Generate a thumbnail for a video. In case of failure, return null
|
||||||
|
Future<BytesFile> generateVideoThumbnail({
|
||||||
|
@required BytesFile videoFile,
|
||||||
|
int maxWidth,
|
||||||
|
}) async {
|
||||||
|
File file;
|
||||||
|
|
||||||
|
try {
|
||||||
|
final tempDir = await getTemporaryDirectory();
|
||||||
|
if (tempDir == null) return null;
|
||||||
|
file = File(path.join(tempDir.path, randomString(15, from: 65, to: 90)));
|
||||||
|
|
||||||
|
await file.writeAsBytes(videoFile.bytes);
|
||||||
|
|
||||||
|
return BytesFile(
|
||||||
|
"thumb.png",
|
||||||
|
await VideoThumbnail.thumbnailData(
|
||||||
|
video: file.absolute.path, maxWidth: maxWidth),
|
||||||
|
);
|
||||||
|
} catch (e, s) {
|
||||||
|
logError(e, s);
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
if (file != null && await file.exists()) await file.delete();
|
||||||
|
}
|
||||||
|
}
|
@ -686,6 +686,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.1.4+1"
|
version: "0.1.4+1"
|
||||||
|
video_thumbnail:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: video_thumbnail
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.5+1"
|
||||||
wakelock:
|
wakelock:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -109,6 +109,9 @@ dependencies:
|
|||||||
# Determine file mime type
|
# Determine file mime type
|
||||||
mime: ^0.9.7
|
mime: ^0.9.7
|
||||||
|
|
||||||
|
# Create video thumbnails
|
||||||
|
video_thumbnail: ^0.2.5+1
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
Loading…
Reference in New Issue
Block a user