ui: Add a basic implementation of the video inline widget
This commit is contained in:
parent
b4411ab4fb
commit
69f8f1b365
@ -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();
|
||||||
|
@ -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
19
lib/ui/service/data.dart
Normal 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;
|
||||||
|
}
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user