1
0
Fork 0
mirror of https://github.com/immich-app/immich.git synced 2025-03-01 15:11:21 +01:00

remove video_player

This commit is contained in:
mertalev 2024-11-21 20:24:34 -05:00
parent 2ece3d3822
commit fa3156e6ee
No known key found for this signature in database
GPG key ID: CA85EF6600C9E8AD
8 changed files with 7 additions and 616 deletions

View file

@ -93,6 +93,7 @@ class Asset {
@ignore @ignore
bool _didUpdateLocal = false; bool _didUpdateLocal = false;
@ignore
Future<AssetEntity> get localAsync async { Future<AssetEntity> get localAsync async {
final local = this.local; final local = this.local;
if (local == null) { if (local == null) {

View file

@ -1,167 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/entities/asset.entity.dart';
import 'package:immich_mobile/providers/asset_viewer/show_controls.provider.dart';
import 'package:immich_mobile/providers/asset_viewer/video_player_controller_provider.dart';
import 'package:immich_mobile/providers/asset_viewer/video_player_controls_provider.dart';
import 'package:immich_mobile/providers/asset_viewer/video_player_value_provider.dart';
import 'package:immich_mobile/widgets/asset_viewer/video_player.dart';
import 'package:immich_mobile/widgets/common/delayed_loading_indicator.dart';
import 'package:wakelock_plus/wakelock_plus.dart';
class VideoViewerPage extends HookConsumerWidget {
final Asset asset;
final bool isMotionVideo;
final Widget? placeholder;
final Duration hideControlsTimer;
final bool showControls;
final bool showDownloadingIndicator;
final bool loopVideo;
const VideoViewerPage({
super.key,
required this.asset,
this.isMotionVideo = false,
this.placeholder,
this.showControls = true,
this.hideControlsTimer = const Duration(seconds: 5),
this.showDownloadingIndicator = true,
this.loopVideo = false,
});
@override
build(BuildContext context, WidgetRef ref) {
final controller =
ref.watch(videoPlayerControllerProvider(asset: asset)).value;
// The last volume of the video used when mute is toggled
final lastVolume = useState(0.5);
// When the volume changes, set the volume
ref.listen(videoPlayerControlsProvider.select((value) => value.mute),
(_, mute) {
if (mute) {
controller?.setVolume(0.0);
} else {
controller?.setVolume(lastVolume.value);
}
});
// When the position changes, seek to the position
ref.listen(videoPlayerControlsProvider.select((value) => value.position),
(_, position) {
if (controller == null) {
// No seeeking if there is no video
return;
}
// Find the position to seek to
final Duration seek = controller.value.duration * (position / 100.0);
controller.seekTo(seek);
});
// When the custom video controls paus or plays
ref.listen(videoPlayerControlsProvider.select((value) => value.pause),
(lastPause, pause) {
if (pause) {
controller?.pause();
} else {
controller?.play();
}
});
// Updates the [videoPlaybackValueProvider] with the current
// position and duration of the video from the Chewie [controller]
// Also sets the error if there is an error in the playback
void updateVideoPlayback() {
final videoPlayback = VideoPlaybackValue.fromController(controller);
ref.read(videoPlaybackValueProvider.notifier).value = videoPlayback;
final state = videoPlayback.state;
// Enable the WakeLock while the video is playing
if (state == VideoPlaybackState.playing) {
// Sync with the controls playing
WakelockPlus.enable();
} else {
// Sync with the controls pause
WakelockPlus.disable();
}
}
// Adds and removes the listener to the video player
useEffect(
() {
Future.microtask(
() => ref.read(videoPlayerControlsProvider.notifier).reset(),
);
// Guard no controller
if (controller == null) {
return null;
}
// Hide the controls
// Done in a microtask to avoid setting the state while the is building
if (!isMotionVideo) {
Future.microtask(() {
ref.read(showControlsProvider.notifier).show = false;
});
}
// Subscribes to listener
Future.microtask(() {
controller.addListener(updateVideoPlayback);
});
return () {
// Removes listener when we dispose
controller.removeListener(updateVideoPlayback);
controller.pause();
};
},
[controller],
);
final size = MediaQuery.sizeOf(context);
return PopScope(
onPopInvokedWithResult: (didPop, _) {
ref.read(videoPlaybackValueProvider.notifier).reset();
},
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 400),
child: Stack(
children: [
Visibility(
visible: controller == null,
child: Stack(
children: [
if (placeholder != null) placeholder!,
const Positioned.fill(
child: Center(
child: DelayedLoadingIndicator(
fadeInDuration: Duration(milliseconds: 500),
),
),
),
],
),
),
if (controller != null)
SizedBox(
height: size.height,
width: size.width,
child: VideoPlayerViewer(
controller: controller,
isMotionVideo: isMotionVideo,
placeholder: placeholder,
hideControlsTimer: hideControlsTimer,
showControls: showControls,
showDownloadingIndicator: showDownloadingIndicator,
loopVideo: loopVideo,
),
),
],
),
),
);
}
}

View file

@ -1,46 +0,0 @@
import 'package:immich_mobile/entities/asset.entity.dart';
import 'package:immich_mobile/entities/store.entity.dart';
import 'package:immich_mobile/services/api.service.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:video_player/video_player.dart';
part 'video_player_controller_provider.g.dart';
@riverpod
Future<VideoPlayerController> videoPlayerController(
VideoPlayerControllerRef ref, {
required Asset asset,
}) async {
late VideoPlayerController controller;
if (asset.isLocal && asset.livePhotoVideoId == null) {
// Use a local file for the video player controller
final file = await asset.local!.file;
if (file == null) {
throw Exception('No file found for the video');
}
controller = VideoPlayerController.file(file);
} else {
// Use a network URL for the video player controller
final serverEndpoint = Store.get(StoreKey.serverEndpoint);
final String videoUrl = asset.livePhotoVideoId != null
? '$serverEndpoint/assets/${asset.livePhotoVideoId}/video/playback'
: '$serverEndpoint/assets/${asset.remoteId}/video/playback';
final url = Uri.parse(videoUrl);
controller = VideoPlayerController.networkUrl(
url,
httpHeaders: ApiService.getRequestHeaders(),
videoPlayerOptions: asset.livePhotoVideoId != null
? VideoPlayerOptions(mixWithOthers: true)
: VideoPlayerOptions(mixWithOthers: false),
);
}
await controller.initialize();
ref.onDispose(() {
controller.dispose();
});
return controller;
}

View file

@ -1,164 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'video_player_controller_provider.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$videoPlayerControllerHash() =>
r'84b2961cc2aeaf9d03255dbf9b9484619d0c24f5';
/// Copied from Dart SDK
class _SystemHash {
_SystemHash._();
static int combine(int hash, int value) {
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + value);
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
return hash ^ (hash >> 6);
}
static int finish(int hash) {
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
// ignore: parameter_assignments
hash = hash ^ (hash >> 11);
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
}
}
/// See also [videoPlayerController].
@ProviderFor(videoPlayerController)
const videoPlayerControllerProvider = VideoPlayerControllerFamily();
/// See also [videoPlayerController].
class VideoPlayerControllerFamily
extends Family<AsyncValue<VideoPlayerController>> {
/// See also [videoPlayerController].
const VideoPlayerControllerFamily();
/// See also [videoPlayerController].
VideoPlayerControllerProvider call({
required Asset asset,
}) {
return VideoPlayerControllerProvider(
asset: asset,
);
}
@override
VideoPlayerControllerProvider getProviderOverride(
covariant VideoPlayerControllerProvider provider,
) {
return call(
asset: provider.asset,
);
}
static const Iterable<ProviderOrFamily>? _dependencies = null;
@override
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
@override
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
_allTransitiveDependencies;
@override
String? get name => r'videoPlayerControllerProvider';
}
/// See also [videoPlayerController].
class VideoPlayerControllerProvider
extends AutoDisposeFutureProvider<VideoPlayerController> {
/// See also [videoPlayerController].
VideoPlayerControllerProvider({
required Asset asset,
}) : this._internal(
(ref) => videoPlayerController(
ref as VideoPlayerControllerRef,
asset: asset,
),
from: videoPlayerControllerProvider,
name: r'videoPlayerControllerProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$videoPlayerControllerHash,
dependencies: VideoPlayerControllerFamily._dependencies,
allTransitiveDependencies:
VideoPlayerControllerFamily._allTransitiveDependencies,
asset: asset,
);
VideoPlayerControllerProvider._internal(
super._createNotifier, {
required super.name,
required super.dependencies,
required super.allTransitiveDependencies,
required super.debugGetCreateSourceHash,
required super.from,
required this.asset,
}) : super.internal();
final Asset asset;
@override
Override overrideWith(
FutureOr<VideoPlayerController> Function(VideoPlayerControllerRef provider)
create,
) {
return ProviderOverride(
origin: this,
override: VideoPlayerControllerProvider._internal(
(ref) => create(ref as VideoPlayerControllerRef),
from: from,
name: null,
dependencies: null,
allTransitiveDependencies: null,
debugGetCreateSourceHash: null,
asset: asset,
),
);
}
@override
AutoDisposeFutureProviderElement<VideoPlayerController> createElement() {
return _VideoPlayerControllerProviderElement(this);
}
@override
bool operator ==(Object other) {
return other is VideoPlayerControllerProvider && other.asset == asset;
}
@override
int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, asset.hashCode);
return _SystemHash.finish(hash);
}
}
mixin VideoPlayerControllerRef
on AutoDisposeFutureProviderRef<VideoPlayerController> {
/// The parameter `asset` of this provider.
Asset get asset;
}
class _VideoPlayerControllerProviderElement
extends AutoDisposeFutureProviderElement<VideoPlayerController>
with VideoPlayerControllerRef {
_VideoPlayerControllerProviderElement(super.provider);
@override
Asset get asset => (origin as VideoPlayerControllerProvider).asset;
}
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member

View file

@ -1,6 +1,5 @@
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:native_video_player/native_video_player.dart'; import 'package:native_video_player/native_video_player.dart';
import 'package:video_player/video_player.dart';
enum VideoPlaybackState { enum VideoPlaybackState {
initializing, initializing,
@ -54,29 +53,6 @@ class VideoPlaybackValue {
); );
} }
factory VideoPlaybackValue.fromController(VideoPlayerController? controller) {
final video = controller?.value;
late VideoPlaybackState s;
if (video == null) {
s = VideoPlaybackState.initializing;
} else if (video.isCompleted) {
s = VideoPlaybackState.completed;
} else if (video.isPlaying) {
s = VideoPlaybackState.playing;
} else if (video.isBuffering) {
s = VideoPlaybackState.buffering;
} else {
s = VideoPlaybackState.paused;
}
return VideoPlaybackValue(
position: video?.position ?? Duration.zero,
duration: video?.duration ?? Duration.zero,
state: s,
volume: video?.volume ?? 0.0,
);
}
VideoPlaybackValue copyWith({ VideoPlaybackValue copyWith({
Duration? position, Duration? position,
Duration? duration, Duration? duration,

View file

@ -1085,7 +1085,7 @@ class NativeVideoViewerRoute extends PageRouteInfo<NativeVideoViewerRouteArgs> {
NativeVideoViewerRoute({ NativeVideoViewerRoute({
Key? key, Key? key,
required Asset asset, required Asset asset,
required Widget placeholder, required Widget image,
bool showControls = true, bool showControls = true,
List<PageRouteInfo>? children, List<PageRouteInfo>? children,
}) : super( }) : super(
@ -1093,7 +1093,7 @@ class NativeVideoViewerRoute extends PageRouteInfo<NativeVideoViewerRouteArgs> {
args: NativeVideoViewerRouteArgs( args: NativeVideoViewerRouteArgs(
key: key, key: key,
asset: asset, asset: asset,
placeholder: placeholder, image: image,
showControls: showControls, showControls: showControls,
), ),
initialChildren: children, initialChildren: children,
@ -1108,7 +1108,7 @@ class NativeVideoViewerRoute extends PageRouteInfo<NativeVideoViewerRouteArgs> {
return NativeVideoViewerPage( return NativeVideoViewerPage(
key: args.key, key: args.key,
asset: args.asset, asset: args.asset,
image: args.placeholder, image: args.image,
showControls: args.showControls, showControls: args.showControls,
); );
}, },
@ -1119,7 +1119,7 @@ class NativeVideoViewerRouteArgs {
const NativeVideoViewerRouteArgs({ const NativeVideoViewerRouteArgs({
this.key, this.key,
required this.asset, required this.asset,
required this.placeholder, required this.image,
this.showControls = true, this.showControls = true,
}); });
@ -1127,13 +1127,13 @@ class NativeVideoViewerRouteArgs {
final Asset asset; final Asset asset;
final Widget placeholder; final Widget image;
final bool showControls; final bool showControls;
@override @override
String toString() { String toString() {
return 'NativeVideoViewerRouteArgs{key: $key, asset: $asset, placeholder: $placeholder, showControls: $showControls}'; return 'NativeVideoViewerRouteArgs{key: $key, asset: $asset, image: $image, showControls: $showControls}';
} }
} }

View file

@ -1,161 +0,0 @@
import 'package:chewie/chewie.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:video_player/video_player.dart';
/// Provides the initialized video player controller
/// If the asset is local, use the local file
/// Otherwise, use a video player with a URL
ChewieController useChewieController({
required VideoPlayerController controller,
EdgeInsets controlsSafeAreaMinimum = const EdgeInsets.only(
bottom: 100,
),
bool showOptions = true,
bool showControlsOnInitialize = false,
bool autoPlay = true,
bool allowFullScreen = false,
bool allowedScreenSleep = false,
bool showControls = true,
bool loopVideo = false,
Widget? customControls,
Widget? placeholder,
Duration hideControlsTimer = const Duration(seconds: 1),
VoidCallback? onPlaying,
VoidCallback? onPaused,
VoidCallback? onVideoEnded,
}) {
return use(
_ChewieControllerHook(
controller: controller,
placeholder: placeholder,
showOptions: showOptions,
controlsSafeAreaMinimum: controlsSafeAreaMinimum,
autoPlay: autoPlay,
allowFullScreen: allowFullScreen,
customControls: customControls,
hideControlsTimer: hideControlsTimer,
showControlsOnInitialize: showControlsOnInitialize,
showControls: showControls,
loopVideo: loopVideo,
allowedScreenSleep: allowedScreenSleep,
onPlaying: onPlaying,
onPaused: onPaused,
onVideoEnded: onVideoEnded,
),
);
}
class _ChewieControllerHook extends Hook<ChewieController> {
final VideoPlayerController controller;
final EdgeInsets controlsSafeAreaMinimum;
final bool showOptions;
final bool showControlsOnInitialize;
final bool autoPlay;
final bool allowFullScreen;
final bool allowedScreenSleep;
final bool showControls;
final bool loopVideo;
final Widget? customControls;
final Widget? placeholder;
final Duration hideControlsTimer;
final VoidCallback? onPlaying;
final VoidCallback? onPaused;
final VoidCallback? onVideoEnded;
const _ChewieControllerHook({
required this.controller,
this.controlsSafeAreaMinimum = const EdgeInsets.only(
bottom: 100,
),
this.showOptions = true,
this.showControlsOnInitialize = false,
this.autoPlay = true,
this.allowFullScreen = false,
this.allowedScreenSleep = false,
this.showControls = true,
this.loopVideo = false,
this.customControls,
this.placeholder,
this.hideControlsTimer = const Duration(seconds: 3),
this.onPlaying,
this.onPaused,
this.onVideoEnded,
});
@override
createState() => _ChewieControllerHookState();
}
class _ChewieControllerHookState
extends HookState<ChewieController, _ChewieControllerHook> {
late ChewieController chewieController = ChewieController(
videoPlayerController: hook.controller,
controlsSafeAreaMinimum: hook.controlsSafeAreaMinimum,
showOptions: hook.showOptions,
showControlsOnInitialize: hook.showControlsOnInitialize,
autoPlay: hook.autoPlay,
allowFullScreen: hook.allowFullScreen,
allowedScreenSleep: hook.allowedScreenSleep,
showControls: hook.showControls,
looping: hook.loopVideo,
customControls: hook.customControls,
placeholder: hook.placeholder,
hideControlsTimer: hook.hideControlsTimer,
);
@override
void dispose() {
chewieController.dispose();
super.dispose();
}
@override
ChewieController build(BuildContext context) {
return chewieController;
}
/*
/// Initializes the chewie controller and video player controller
Future<void> _initialize() async {
if (hook.asset.isLocal && hook.asset.livePhotoVideoId == null) {
// Use a local file for the video player controller
final file = await hook.asset.local!.file;
if (file == null) {
throw Exception('No file found for the video');
}
videoPlayerController = VideoPlayerController.file(file);
} else {
// Use a network URL for the video player controller
final serverEndpoint = store.Store.get(store.StoreKey.serverEndpoint);
final String videoUrl = hook.asset.livePhotoVideoId != null
? '$serverEndpoint/assets/${hook.asset.livePhotoVideoId}/video/playback'
: '$serverEndpoint/assets/${hook.asset.remoteId}/video/playback';
final url = Uri.parse(videoUrl);
final accessToken = store.Store.get(StoreKey.accessToken);
videoPlayerController = VideoPlayerController.networkUrl(
url,
httpHeaders: {"x-immich-user-token": accessToken},
);
}
await videoPlayerController!.initialize();
chewieController = ChewieController(
videoPlayerController: videoPlayerController!,
controlsSafeAreaMinimum: hook.controlsSafeAreaMinimum,
showOptions: hook.showOptions,
showControlsOnInitialize: hook.showControlsOnInitialize,
autoPlay: hook.autoPlay,
allowFullScreen: hook.allowFullScreen,
allowedScreenSleep: hook.allowedScreenSleep,
showControls: hook.showControls,
customControls: hook.customControls,
placeholder: hook.placeholder,
hideControlsTimer: hook.hideControlsTimer,
);
}
*/
}

View file

@ -1,48 +0,0 @@
import 'package:chewie/chewie.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/utils/hooks/chewiew_controller_hook.dart';
import 'package:immich_mobile/widgets/asset_viewer/custom_video_player_controls.dart';
import 'package:video_player/video_player.dart';
class VideoPlayerViewer extends HookConsumerWidget {
final VideoPlayerController controller;
final bool isMotionVideo;
final Widget? placeholder;
final Duration hideControlsTimer;
final bool showControls;
final bool showDownloadingIndicator;
final bool loopVideo;
const VideoPlayerViewer({
super.key,
required this.controller,
required this.isMotionVideo,
this.placeholder,
required this.hideControlsTimer,
required this.showControls,
required this.showDownloadingIndicator,
required this.loopVideo,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
final chewie = useChewieController(
controller: controller,
controlsSafeAreaMinimum: const EdgeInsets.only(
bottom: 100,
),
placeholder: SizedBox.expand(child: placeholder),
customControls: CustomVideoPlayerControls(
hideTimerDuration: hideControlsTimer,
),
showControls: showControls && !isMotionVideo,
hideControlsTimer: hideControlsTimer,
loopVideo: loopVideo,
);
return Chewie(
controller: chewie,
);
}
}