diff --git a/android/app/build.gradle b/android/app/build.gradle index 66b1ade..232ec3b 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -47,7 +47,7 @@ android { applicationId "social.myportal.flutter_portal" // You can update the following values to match your application needs. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration. - minSdkVersion 19 + minSdkVersion 21 targetSdkVersion flutter.targetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName diff --git a/lib/controls/media_attachment_viewer_control.dart b/lib/controls/media_attachment_viewer_control.dart new file mode 100644 index 0000000..cb43d92 --- /dev/null +++ b/lib/controls/media_attachment_viewer_control.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; +import 'package:url_launcher/url_launcher.dart'; + +import '../models/attachment_media_type_enum.dart'; +import '../models/media_attachment.dart'; +import '../screens/image_viewer_screen.dart'; +import '../utils/snackbar_builder.dart'; +import 'image_control.dart'; + +class MediaAttachmentViewerControl extends StatefulWidget { + final MediaAttachment attachment; + + const MediaAttachmentViewerControl({super.key, required this.attachment}); + + @override + State createState() => + _MediaAttachmentViewerControlState(); +} + +class _MediaAttachmentViewerControlState + extends State { + @override + Widget build(BuildContext context) { + final item = widget.attachment; + if (item.explicitType == AttachmentMediaType.video) { + return ElevatedButton( + onPressed: () async { + if (await canLaunchUrl(item.uri)) { + buildSnackbar( + context, + 'Attempting to launch video: ${item.uri}', + ); + await launchUrl(item.uri); + } else { + buildSnackbar(context, 'Unable to launch video: ${item.uri}'); + } + }, + child: + Text(item.description.isNotEmpty ? item.description : 'Video')); + } + if (item.explicitType != AttachmentMediaType.image) { + return Text('${item.explicitType}: ${item.uri}'); + } + + return ImageControl( + width: 250.0, + height: 250.0, + imageUrl: item.thumbnailUri.toString(), + altText: item.description, + onTap: () async { + Navigator.push(context, MaterialPageRoute(builder: (context) { + return ImageViewerScreen(attachment: item); + })); + }, + ); + } +} diff --git a/lib/controls/timeline/status_control.dart b/lib/controls/timeline/status_control.dart index 082dae6..ba87fb5 100644 --- a/lib/controls/timeline/status_control.dart +++ b/lib/controls/timeline/status_control.dart @@ -2,16 +2,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart'; import 'package:logging/logging.dart'; import 'package:provider/provider.dart'; -import 'package:url_launcher/url_launcher.dart'; -import '../../models/attachment_media_type_enum.dart'; import '../../models/entry_tree_item.dart'; import '../../models/timeline_entry.dart'; -import '../../screens/image_viewer_screen.dart'; import '../../services/timeline_manager.dart'; -import '../../utils/snackbar_builder.dart'; import '../../utils/url_opening_utils.dart'; -import '../image_control.dart'; +import '../media_attachment_viewer_control.dart'; import '../padding.dart'; import 'interactions_bar_control.dart'; import 'status_header_control.dart'; @@ -142,42 +138,7 @@ class _StatusControlState extends State { child: ListView.separated( scrollDirection: Axis.horizontal, itemBuilder: (context, index) { - final item = items[index]; - - if (item.explicitType == AttachmentMediaType.video) { - return ElevatedButton( - onPressed: () async { - if (await canLaunchUrl(item.uri)) { - buildSnackbar( - context, - 'Attempting to launch video: ${item.uri}', - ); - await launchUrl(item.uri); - } else { - buildSnackbar( - context, 'Unable to launch video: ${item.uri}'); - } - }, - child: Text(item.description.isNotEmpty - ? item.description - : 'Video')); - } - if (item.explicitType != AttachmentMediaType.image) { - return Text('${item.explicitType}: ${item.uri}'); - } - - return ImageControl( - width: 250.0, - height: 250.0, - imageUrl: item.thumbnailUri.toString(), - altText: item.description, - onTap: () async { - Navigator.push(context, MaterialPageRoute(builder: (context) { - return ImageViewerScreen(attachment: item); - })); - }, - ); - // return Text(item.toString()); + return MediaAttachmentViewerControl(attachment: items[index]); }, separatorBuilder: (context, index) { return HorizontalPadding(); diff --git a/lib/globals.dart b/lib/globals.dart index cb8fc8c..170c1e7 100644 --- a/lib/globals.dart +++ b/lib/globals.dart @@ -13,6 +13,8 @@ final platformHasCamera = Platform.isIOS || Platform.isAndroid; final useImagePicker = kIsWeb || Platform.isAndroid || Platform.isIOS; +final useVideoPlayer = kIsWeb || Platform.isAndroid || Platform.isIOS; + Future showConfirmDialog(BuildContext context, String caption) { return showDialog( context: context, diff --git a/pubspec.lock b/pubspec.lock index 7875cc1..d9675d4 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -777,6 +777,41 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.2" + video_player: + dependency: "direct main" + description: + name: video_player + url: "https://pub.dartlang.org" + source: hosted + version: "2.4.10" + video_player_android: + dependency: transitive + description: + name: video_player_android + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.10" + video_player_avfoundation: + dependency: transitive + description: + name: video_player_avfoundation + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.8" + video_player_platform_interface: + dependency: transitive + description: + name: video_player_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "6.0.1" + video_player_web: + dependency: transitive + description: + name: video_player_web + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.13" win32: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index a778f9a..dc3caa4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -36,6 +36,7 @@ dependencies: image: ^3.2.2 flutter_file_dialog: ^2.3.2 multi_trigger_autocomplete: ^0.1.1 + video_player: ^2.4.10 dev_dependencies: flutter_test: