ui: Add a basic implementation of the video inline widget

This commit is contained in:
PapaTutuWawa 2022-04-01 13:37:38 +02:00
parent b4411ab4fb
commit 69f8f1b365
4 changed files with 97 additions and 21 deletions

View File

@ -31,6 +31,7 @@ import "package:moxxyv2/ui/bloc/profile_bloc.dart";
import "package:moxxyv2/ui/bloc/preferences_bloc.dart"; import "package:moxxyv2/ui/bloc/preferences_bloc.dart";
import "package:moxxyv2/ui/bloc/addcontact_bloc.dart"; import "package:moxxyv2/ui/bloc/addcontact_bloc.dart";
import "package:moxxyv2/ui/service/download.dart"; import "package:moxxyv2/ui/service/download.dart";
import "package:moxxyv2/ui/service/data.dart";
import "package:moxxyv2/service/service.dart"; import "package:moxxyv2/service/service.dart";
import "package:moxxyv2/shared/commands.dart"; import "package:moxxyv2/shared/commands.dart";
import "package:moxxyv2/shared/events.dart"; import "package:moxxyv2/shared/events.dart";
@ -51,8 +52,10 @@ void setupLogging() {
GetIt.I.registerSingleton<Logger>(Logger("MoxxyMain")); GetIt.I.registerSingleton<Logger>(Logger("MoxxyMain"));
} }
void setupUIServices() { Future<void> setupUIServices() async {
GetIt.I.registerSingleton<UIDownloadService>(UIDownloadService()); GetIt.I.registerSingleton<UIDownloadService>(UIDownloadService());
GetIt.I.registerSingleton<UIDataService>(UIDataService());
await GetIt.I.get<UIDataService>().init();
} }
void setupBlocs(GlobalKey<NavigatorState> navKey) { void setupBlocs(GlobalKey<NavigatorState> navKey) {
@ -71,7 +74,7 @@ void setupBlocs(GlobalKey<NavigatorState> navKey) {
// TODO: Theme the switches // TODO: Theme the switches
void main() async { void main() async {
setupLogging(); setupLogging();
setupUIServices(); await setupUIServices();
await initializeServiceIfNeeded(); await initializeServiceIfNeeded();
setupEventHandler(); setupEventHandler();

View File

@ -144,6 +144,7 @@ String? guessMimeTypeFromExtension(String ext) {
case "jpg": case "jpg":
case "jpeg": return "image/jpeg"; case "jpeg": return "image/jpeg";
case "webp": return "image/webp"; case "webp": return "image/webp";
case "mp4": return "video/mp4";
} }
return null; return null;

19
lib/ui/service/data.dart Normal file
View File

@ -0,0 +1,19 @@
import "package:flutter/material.dart";
import "package:external_path/external_path.dart";
import "package:path/path.dart" as pathlib;
class UIDataService {
late String _thumbnailBase;
UIDataService();
Future<void> init() async {
WidgetsFlutterBinding.ensureInitialized();
final base = await ExternalPath.getExternalStoragePublicDirectory(ExternalPath.DIRECTORY_PICTURES);
_thumbnailBase = pathlib.join(base, "Moxxy", ".thumbnail");
}
// The base path for thumbnails
String get thumbnailBase => _thumbnailBase;
}

View File

@ -1,15 +1,17 @@
import "dart:io"; import "dart:io";
import "package:moxxyv2/shared/models/message.dart"; import "package:moxxyv2/shared/models/message.dart";
import "package:moxxyv2/ui/service/data.dart";
import "package:moxxyv2/ui/widgets/chat/bottom.dart"; import "package:moxxyv2/ui/widgets/chat/bottom.dart";
import "package:moxxyv2/ui/widgets/chat/blurhash.dart"; import "package:moxxyv2/ui/widgets/chat/blurhash.dart";
import "package:moxxyv2/ui/widgets/chat/playbutton.dart"; import "package:moxxyv2/ui/widgets/chat/playbutton.dart";
import "package:moxxyv2/ui/widgets/chat/helpers.dart"; import "package:moxxyv2/ui/widgets/chat/helpers.dart";
import "package:moxxyv2/ui/widgets/chat/media/image.dart"; import "package:moxxyv2/ui/widgets/chat/media/image.dart";
import "package:moxxyv2/ui/widgets/chat/media/file.dart";
import "package:flutter/material.dart"; import "package:flutter/material.dart";
import "package:path/path.dart" as pathlib; import "package:path/path.dart" as pathlib;
import "package:external_path/external_path.dart"; import "package:get_it/get_it.dart";
import "package:video_compress/video_compress.dart"; import "package:video_compress/video_compress.dart";
import "package:open_file/open_file.dart"; import "package:open_file/open_file.dart";
@ -45,41 +47,92 @@ class _VideoChatWidgetState extends State<VideoChatWidget> {
final double maxWidth; final double maxWidth;
final Message message; final Message message;
String _thumbnailPath;
bool _hasThumbnail;
_VideoChatWidgetState( _VideoChatWidgetState(
this.message, this.message,
this.maxWidth, this.maxWidth,
this.timestamp, this.timestamp,
this.radius, this.radius,
) : _thumbnailPath = "", _hasThumbnail = true; );
Future<String> _getThumbnailPath() async { /// Returns the path of a possible thumbnail for the video. Does not imply that the file
final base = await ExternalPath.getExternalStoragePublicDirectory(ExternalPath.DIRECTORY_PICTURES); /// exists.
return pathlib.join(base, "Moxxy", ".thumbnail", message.conversationJid, pathlib.basename(message.mediaUrl!)); String _getThumbnailPath() {
final base = GetIt.I.get<UIDataService>().thumbnailBase;
return pathlib.join(base, message.conversationJid, pathlib.basename(message.mediaUrl!));
} }
/// Generate the thumbnail if needed.
Future<bool> _thumbnailFuture() async {
final thumbnailFile = File(_getThumbnailPath());
if (await thumbnailFile.exists()) {
return true;
}
// Thumbnail does not exist
final sourceFile = File(message.mediaUrl!);
if (await sourceFile.exists()) {
final bytes = await VideoCompress.getByteThumbnail(
sourceFile.path,
quality: 75
);
await thumbnailFile.writeAsBytes(bytes!);
return true;
}
// Source file also does not exist. Return "error".
return false;
}
Widget _buildNonDownloaded() { Widget _buildNonDownloaded() {
// TODO // TODO
return const SizedBox(); if (message.thumbnailData != null) {}
return FileChatWidget(
message,
timestamp,
extra: ElevatedButton(
// TODO
onPressed: () {},
child: const Text("Download")
)
);
} }
Widget _buildDownloading() { Widget _buildDownloading() {
// TODO // TODO
return const SizedBox(); if (message.thumbnailData != null) {}
return FileChatWidget(
message,
timestamp,
);
} }
Widget _buildVideo() { Widget _buildVideo() {
return ImageBaseChatWidget( return FutureBuilder<bool>(
message.mediaUrl!, future: _thumbnailFuture(),
radius, builder: (context, snapshot) {
Image.file(File(message.mediaUrl!)), if (snapshot.connectionState == ConnectionState.done) {
MessageBubbleBottom( if (snapshot.data!) {
message, return ImageBaseChatWidget(
timestamp: timestamp, message.mediaUrl!,
), radius,
extra: const PlayButton() Image.file(File(_getThumbnailPath())),
MessageBubbleBottom(
message,
timestamp: timestamp,
),
extra: const PlayButton()
);
} else {
// TODO: Error
return const Text("Error");
}
} else {
return const CircularProgressIndicator();
}
}
); );
} }