Ver Fonte

Added video player page

Alex Tran há 3 anos atrás
pai
commit
00830f8a05

+ 1 - 0
mobile/android/app/src/main/AndroidManifest.xml

@@ -3,6 +3,7 @@
     <application
             android:label="Immich"
             android:name="${applicationName}"
+            android:usesCleartextTraffic="true"
             android:icon="@mipmap/ic_launcher">
         <activity
                 android:name=".MainActivity"

+ 0 - 53
mobile/lib/modules/home/ui/image_grid.dart

@@ -51,56 +51,3 @@ class ImageGrid extends ConsumerWidget {
     );
   }
 }
-
-// class VideoThumbnailPlayer extends StatefulWidget {
-//   ImmichAsset videoAsset;
-
-//   VideoThumbnailPlayer({Key? key, required this.videoAsset}) : super(key: key);
-
-//   @override
-//   State<VideoThumbnailPlayer> createState() => _VideoThumbnailPlayerState();
-// }
-
-// class _VideoThumbnailPlayerState extends State<VideoThumbnailPlayer> {
-//   late VideoPlayerController videoPlayerController;
-//   ChewieController? chewieController;
-
-//   @override
-//   void initState() {
-//     super.initState();
-//     initializePlayer();
-//   }
-
-//   Future<void> initializePlayer() async {
-//     videoPlayerController =
-//         VideoPlayerController.network('https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4');
-
-//     await Future.wait([
-//       videoPlayerController.initialize(),
-//     ]);
-//     _createChewieController();
-//     setState(() {});
-//   }
-
-//   _createChewieController() {
-//     chewieController = ChewieController(
-//       showControlsOnInitialize: false,
-//       videoPlayerController: videoPlayerController,
-//       autoPlay: true,
-//       looping: true,
-//     );
-//   }
-
-//   @override
-//   Widget build(BuildContext context) {
-//     return chewieController != null && chewieController!.videoPlayerController.value.isInitialized
-//         ? SizedBox(
-//             height: 300,
-//             width: 300,
-//             child: Chewie(
-//               controller: chewieController!,
-//             ),
-//           )
-//         : const Text("Loading Video");
-//   }
-// }

+ 19 - 9
mobile/lib/modules/home/ui/thumbnail_image.dart

@@ -21,14 +21,24 @@ class ThumbnailImage extends HookWidget {
         '${box.get(serverEndpointKey)}/asset/file?aid=${asset.deviceAssetId}&did=${asset.deviceId}&isThumb=true';
     return GestureDetector(
       onTap: () {
-        AutoRouter.of(context).push(
-          ImageViewerRoute(
-            imageUrl:
-                '${box.get(serverEndpointKey)}/asset/file?aid=${asset.deviceAssetId}&did=${asset.deviceId}&isThumb=false',
-            heroTag: asset.id,
-            thumbnailUrl: thumbnailRequestUrl,
-          ),
-        );
+        if (asset.type == 'IMAGE') {
+          AutoRouter.of(context).push(
+            ImageViewerRoute(
+              imageUrl:
+                  '${box.get(serverEndpointKey)}/asset/file?aid=${asset.deviceAssetId}&did=${asset.deviceId}&isThumb=false',
+              heroTag: asset.id,
+              thumbnailUrl: thumbnailRequestUrl,
+            ),
+          );
+        } else {
+          debugPrint("Navigate to video player");
+
+          AutoRouter.of(context).push(
+            VideoViewerRoute(
+              videoUrl: '${box.get(serverEndpointKey)}/asset/file?aid=${asset.deviceAssetId}&did=${asset.deviceId}',
+            ),
+          );
+        }
       },
       onLongPress: () {},
       child: Hero(
@@ -37,7 +47,7 @@ class ThumbnailImage extends HookWidget {
           cacheKey: "${asset.id}-${cacheKey.value}",
           width: 300,
           height: 300,
-          memCacheHeight: 250,
+          memCacheHeight: asset.type == 'IMAGE' ? 250 : 500,
           fit: BoxFit.cover,
           imageUrl: thumbnailRequestUrl,
           httpHeaders: {"Authorization": "Bearer ${box.get(accessTokenKey)}"},

+ 2 - 0
mobile/lib/routing/router.dart

@@ -5,6 +5,7 @@ import 'package:immich_mobile/modules/home/views/home_page.dart';
 import 'package:immich_mobile/routing/auth_guard.dart';
 import 'package:immich_mobile/shared/views/backup_controller_page.dart';
 import 'package:immich_mobile/shared/views/image_viewer_page.dart';
+import 'package:immich_mobile/shared/views/video_viewer_page.dart';
 
 part 'router.gr.dart';
 
@@ -15,6 +16,7 @@ part 'router.gr.dart';
     AutoRoute(page: HomePage, guards: [AuthGuard]),
     AutoRoute(page: BackupControllerPage, guards: [AuthGuard]),
     AutoRoute(page: ImageViewerPage, guards: [AuthGuard]),
+    AutoRoute(page: VideoViewerPage, guards: [AuthGuard]),
   ],
 )
 class AppRouter extends _$AppRouter {

+ 33 - 1
mobile/lib/routing/router.gr.dart

@@ -42,6 +42,12 @@ class _$AppRouter extends RootStackRouter {
               imageUrl: args.imageUrl,
               heroTag: args.heroTag,
               thumbnailUrl: args.thumbnailUrl));
+    },
+    VideoViewerRoute.name: (routeData) {
+      final args = routeData.argsAs<VideoViewerRouteArgs>();
+      return MaterialPageX<dynamic>(
+          routeData: routeData,
+          child: VideoViewerPage(key: args.key, videoUrl: args.videoUrl));
     }
   };
 
@@ -52,7 +58,9 @@ class _$AppRouter extends RootStackRouter {
         RouteConfig(BackupControllerRoute.name,
             path: '/backup-controller-page', guards: [authGuard]),
         RouteConfig(ImageViewerRoute.name,
-            path: '/image-viewer-page', guards: [authGuard])
+            path: '/image-viewer-page', guards: [authGuard]),
+        RouteConfig(VideoViewerRoute.name,
+            path: '/video-viewer-page', guards: [authGuard])
       ];
 }
 
@@ -120,3 +128,27 @@ class ImageViewerRouteArgs {
     return 'ImageViewerRouteArgs{key: $key, imageUrl: $imageUrl, heroTag: $heroTag, thumbnailUrl: $thumbnailUrl}';
   }
 }
+
+/// generated route for
+/// [VideoViewerPage]
+class VideoViewerRoute extends PageRouteInfo<VideoViewerRouteArgs> {
+  VideoViewerRoute({Key? key, required String videoUrl})
+      : super(VideoViewerRoute.name,
+            path: '/video-viewer-page',
+            args: VideoViewerRouteArgs(key: key, videoUrl: videoUrl));
+
+  static const String name = 'VideoViewerRoute';
+}
+
+class VideoViewerRouteArgs {
+  const VideoViewerRouteArgs({this.key, required this.videoUrl});
+
+  final Key? key;
+
+  final String videoUrl;
+
+  @override
+  String toString() {
+    return 'VideoViewerRouteArgs{key: $key, videoUrl: $videoUrl}';
+  }
+}

+ 101 - 0
mobile/lib/shared/views/video_viewer_page.dart

@@ -0,0 +1,101 @@
+import 'package:auto_route/auto_route.dart';
+import 'package:flutter/material.dart';
+import 'package:hive/hive.dart';
+import 'package:immich_mobile/constants/hive_box.dart';
+import 'package:chewie/chewie.dart';
+import 'package:video_player/video_player.dart';
+
+class VideoViewerPage extends StatelessWidget {
+  final String videoUrl;
+
+  const VideoViewerPage({Key? key, required this.videoUrl}) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    String jwtToken = Hive.box(userInfoBox).get(accessTokenKey);
+
+    return Scaffold(
+      backgroundColor: Colors.black,
+      appBar: AppBar(
+        backgroundColor: Colors.black,
+        leading: IconButton(
+            onPressed: () {
+              AutoRouter.of(context).pop();
+            },
+            icon: const Icon(Icons.arrow_back_ios)),
+      ),
+      body: Center(
+        child: VideoThumbnailPlayer(
+          url: videoUrl,
+          jwtToken: jwtToken,
+        ),
+      ),
+    );
+  }
+}
+
+class VideoThumbnailPlayer extends StatefulWidget {
+  final String url;
+  final String? jwtToken;
+
+  const VideoThumbnailPlayer({Key? key, required this.url, this.jwtToken}) : super(key: key);
+
+  @override
+  State<VideoThumbnailPlayer> createState() => _VideoThumbnailPlayerState();
+}
+
+class _VideoThumbnailPlayerState extends State<VideoThumbnailPlayer> {
+  late VideoPlayerController videoPlayerController;
+  ChewieController? chewieController;
+
+  @override
+  void initState() {
+    super.initState();
+    initializePlayer();
+  }
+
+  Future<void> initializePlayer() async {
+    videoPlayerController =
+        VideoPlayerController.network(widget.url, httpHeaders: {"Authorization": "Bearer ${widget.jwtToken}"});
+
+    await Future.wait([
+      videoPlayerController.initialize(),
+    ]);
+    _createChewieController();
+    setState(() {});
+  }
+
+  _createChewieController() {
+    chewieController = ChewieController(
+      showOptions: true,
+      showControlsOnInitialize: false,
+      videoPlayerController: videoPlayerController,
+      autoPlay: true,
+      autoInitialize: false,
+    );
+  }
+
+  @override
+  void dispose() {
+    super.dispose();
+    videoPlayerController.pause();
+    videoPlayerController.dispose();
+    chewieController!.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return chewieController != null && chewieController!.videoPlayerController.value.isInitialized
+        ? SizedBox(
+            child: Chewie(
+              controller: chewieController!,
+            ),
+          )
+        : const SizedBox(
+            width: 75,
+            height: 75,
+            child: CircularProgressIndicator.adaptive(
+              strokeWidth: 2,
+            ));
+  }
+}