mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-01-22 08:46:18 +01:00
Support playing live photos taken with a Google Pixel
This commit is contained in:
parent
4dc2530c01
commit
654f6c0a43
14 changed files with 425 additions and 24 deletions
BIN
app/assets/2.0x/ic_motion_photos_play_24dp.png
Normal file
BIN
app/assets/2.0x/ic_motion_photos_play_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
BIN
app/assets/3.0x/ic_motion_photos_play_24dp.png
Normal file
BIN
app/assets/3.0x/ic_motion_photos_play_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.3 KiB |
BIN
app/assets/ic_motion_photos_play_24dp.png
Normal file
BIN
app/assets/ic_motion_photos_play_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 794 B |
|
@ -1,2 +1,3 @@
|
|||
const icAddCollectionsOutlined24 =
|
||||
"assets/ic_add_collections_outlined_24dp.png";
|
||||
const icMotionPhotosPlay24dp = "assets/ic_motion_photos_play_24dp.png";
|
||||
|
|
13
app/lib/live_photo_util.dart
Normal file
13
app/lib/live_photo_util.dart
Normal file
|
@ -0,0 +1,13 @@
|
|||
import 'package:nc_photos/entity/file_descriptor.dart';
|
||||
import 'package:video_player_platform_interface/video_player_platform_interface.dart';
|
||||
|
||||
LivePhotoType? getLivePhotoTypeFromFile(FileDescriptor file) {
|
||||
final filenameL = file.filename.toLowerCase();
|
||||
if (filenameL.startsWith("pxl_") && filenameL.endsWith(".mp.jpg")) {
|
||||
return LivePhotoType.googleMp;
|
||||
} else if (filenameL.startsWith("mvimg_") && filenameL.endsWith(".jpg")) {
|
||||
return LivePhotoType.googleMvimg;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -25,7 +25,7 @@ class HorizontalPageViewer extends StatefulWidget {
|
|||
final HorizontalPageViewerController controller;
|
||||
final double viewportFraction;
|
||||
final bool canSwitchPage;
|
||||
final ValueChanged<int>? onPageChanged;
|
||||
final void Function(int from, int to)? onPageChanged;
|
||||
}
|
||||
|
||||
class _HorizontalPageViewerState extends State<HorizontalPageViewer> {
|
||||
|
|
290
app/lib/widget/live_photo_viewer.dart
Normal file
290
app/lib/widget/live_photo_viewer.dart
Normal file
|
@ -0,0 +1,290 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:cached_network_image_platform_interface/cached_network_image_platform_interface.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:nc_photos/account.dart';
|
||||
import 'package:nc_photos/api/api_util.dart' as api_util;
|
||||
import 'package:nc_photos/cache_manager_util.dart';
|
||||
import 'package:nc_photos/entity/file_descriptor.dart';
|
||||
import 'package:nc_photos/exception_util.dart' as exception_util;
|
||||
import 'package:nc_photos/k.dart' as k;
|
||||
import 'package:nc_photos/np_api_util.dart';
|
||||
import 'package:nc_photos/snack_bar_manager.dart';
|
||||
import 'package:nc_photos/use_case/request_public_link.dart';
|
||||
import 'package:nc_photos/widget/cached_network_image_mod.dart' as mod;
|
||||
import 'package:np_codegen/np_codegen.dart';
|
||||
import 'package:np_platform_util/np_platform_util.dart';
|
||||
import 'package:video_player/video_player.dart';
|
||||
import 'package:video_player_platform_interface/video_player_platform_interface.dart';
|
||||
|
||||
part 'live_photo_viewer.g.dart';
|
||||
|
||||
class LivePhotoViewer extends StatefulWidget {
|
||||
const LivePhotoViewer({
|
||||
super.key,
|
||||
required this.account,
|
||||
required this.file,
|
||||
this.onLoaded,
|
||||
this.onLoadFailure,
|
||||
this.onHeightChanged,
|
||||
this.canPlay = true,
|
||||
this.livePhotoType,
|
||||
});
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _LivePhotoViewerState();
|
||||
|
||||
final Account account;
|
||||
final FileDescriptor file;
|
||||
final VoidCallback? onLoaded;
|
||||
final VoidCallback? onLoadFailure;
|
||||
final ValueChanged<double>? onHeightChanged;
|
||||
final bool canPlay;
|
||||
final LivePhotoType? livePhotoType;
|
||||
}
|
||||
|
||||
@npLog
|
||||
class _LivePhotoViewerState extends State<LivePhotoViewer> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_getVideoUrl().then((url) {
|
||||
if (mounted) {
|
||||
_initController(url);
|
||||
}
|
||||
}).onError((e, stacktrace) {
|
||||
_log.shout("[initState] Failed while _getVideoUrl", e, stacktrace);
|
||||
SnackBarManager().showSnackBar(SnackBar(
|
||||
content: Text(exception_util.toUserString(e)),
|
||||
duration: k.snackBarDurationNormal,
|
||||
));
|
||||
widget.onLoadFailure?.call();
|
||||
});
|
||||
|
||||
_lifecycleListener = AppLifecycleListener(onShow: () {
|
||||
if (_controller.value.isInitialized) {
|
||||
_controller.pause();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_lifecycleListener.dispose();
|
||||
_controller.removeListener(_onControllerChanged);
|
||||
_controllerValue?.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget content;
|
||||
if (_isControllerInitialized && _controller.value.isInitialized) {
|
||||
content = _buildPlayer(context);
|
||||
} else {
|
||||
content = _PlaceHolderView(
|
||||
account: widget.account,
|
||||
file: widget.file,
|
||||
);
|
||||
}
|
||||
|
||||
return Container(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
height: MediaQuery.of(context).size.height,
|
||||
alignment: Alignment.center,
|
||||
child: content,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _initController(String url) async {
|
||||
try {
|
||||
_controllerValue = VideoPlayerController.networkUrl(
|
||||
Uri.parse(url),
|
||||
httpHeaders: {
|
||||
"Authorization": AuthUtil.fromAccount(widget.account).toHeaderValue(),
|
||||
},
|
||||
livePhotoType: widget.livePhotoType,
|
||||
);
|
||||
await _controller.initialize();
|
||||
await _controller.setVolume(0);
|
||||
await _controller.setLooping(true);
|
||||
widget.onLoaded?.call();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (_key.currentContext != null) {
|
||||
widget.onHeightChanged?.call(_key.currentContext!.size!.height);
|
||||
}
|
||||
});
|
||||
_controller.addListener(_onControllerChanged);
|
||||
setState(() {
|
||||
_isControllerInitialized = true;
|
||||
});
|
||||
await _controller.play();
|
||||
} catch (e, stackTrace) {
|
||||
_log.shout("[_initController] Failed while initialize", e, stackTrace);
|
||||
SnackBarManager().showSnackBar(SnackBar(
|
||||
content: Text(exception_util.toUserString(e)),
|
||||
duration: k.snackBarDurationNormal,
|
||||
));
|
||||
widget.onLoadFailure?.call();
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildPlayer(BuildContext context) {
|
||||
if (_controller.value.isPlaying && !widget.canPlay) {
|
||||
_log.info("Pause playback");
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_controller.pause();
|
||||
});
|
||||
} else if (!_controller.value.isPlaying && widget.canPlay) {
|
||||
_log.info("Resume playback");
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_controller.play();
|
||||
});
|
||||
}
|
||||
return Center(
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
Center(
|
||||
child: AspectRatio(
|
||||
key: _key,
|
||||
aspectRatio: _controller.value.aspectRatio,
|
||||
child: IgnorePointer(
|
||||
child: VideoPlayer(_controller),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (!_isLoaded) ...[
|
||||
_PlaceHolderView(
|
||||
account: widget.account,
|
||||
file: widget.file,
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<String> _getVideoUrl() async {
|
||||
if (getRawPlatform() == NpPlatform.web) {
|
||||
return RequestPublicLink()(widget.account, widget.file);
|
||||
} else {
|
||||
return api_util.getFileUrl(widget.account, widget.file);
|
||||
}
|
||||
}
|
||||
|
||||
void _onControllerChanged() {
|
||||
if (!_controller.value.isInitialized) {
|
||||
return;
|
||||
}
|
||||
if (_controller.value.isPlaying != _isPlaying) {
|
||||
setState(() {
|
||||
_isPlaying = !_isPlaying;
|
||||
_isLoaded = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
VideoPlayerController get _controller => _controllerValue!;
|
||||
|
||||
final _key = GlobalKey();
|
||||
bool _isControllerInitialized = false;
|
||||
VideoPlayerController? _controllerValue;
|
||||
var _isPlaying = false;
|
||||
var _isLoaded = false;
|
||||
late final AppLifecycleListener _lifecycleListener;
|
||||
}
|
||||
|
||||
class _PlaceHolderView extends StatelessWidget {
|
||||
const _PlaceHolderView({
|
||||
required this.account,
|
||||
required this.file,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
mod.CachedNetworkImage(
|
||||
fit: BoxFit.contain,
|
||||
cacheManager: LargeImageCacheManager.inst,
|
||||
imageUrl: api_util.getFilePreviewUrl(
|
||||
account,
|
||||
file,
|
||||
width: k.photoLargeSize,
|
||||
height: k.photoLargeSize,
|
||||
isKeepAspectRatio: true,
|
||||
),
|
||||
httpHeaders: {
|
||||
"Authorization": AuthUtil.fromAccount(account).toHeaderValue(),
|
||||
},
|
||||
fadeInDuration: const Duration(),
|
||||
filterQuality: FilterQuality.high,
|
||||
imageRenderMethodForWeb: ImageRenderMethodForWeb.HttpGet,
|
||||
imageBuilder: (context, child, imageProvider) {
|
||||
const SizeChangedLayoutNotification().dispatch(context);
|
||||
return child;
|
||||
},
|
||||
),
|
||||
ColoredBox(color: Colors.black.withOpacity(.7)),
|
||||
const Center(child: _ProgressIndicator()),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
final Account account;
|
||||
final FileDescriptor file;
|
||||
}
|
||||
|
||||
class _ProgressIndicator extends StatefulWidget {
|
||||
const _ProgressIndicator();
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _ProgressIndicatorState();
|
||||
}
|
||||
|
||||
class _ProgressIndicatorState extends State<_ProgressIndicator>
|
||||
with TickerProviderStateMixin {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
animationController.repeat();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
animationController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
RotationTransition(
|
||||
turns: animationController
|
||||
.drive(CurveTween(curve: Curves.easeInOutCubic)),
|
||||
filterQuality: FilterQuality.high,
|
||||
child: Icon(
|
||||
Icons.motion_photos_on_outlined,
|
||||
size: 64,
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
),
|
||||
),
|
||||
Icon(
|
||||
Icons.play_arrow_rounded,
|
||||
size: 48,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
late final animationController = AnimationController(
|
||||
vsync: this,
|
||||
duration: const Duration(seconds: 1),
|
||||
);
|
||||
}
|
14
app/lib/widget/live_photo_viewer.g.dart
Normal file
14
app/lib/widget/live_photo_viewer.g.dart
Normal file
|
@ -0,0 +1,14 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'live_photo_viewer.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// NpLogGenerator
|
||||
// **************************************************************************
|
||||
|
||||
extension _$_LivePhotoViewerStateNpLog on _LivePhotoViewerState {
|
||||
// ignore: unused_element
|
||||
Logger get _log => log;
|
||||
|
||||
static final log = Logger("widget.live_photo_viewer._LivePhotoViewerState");
|
||||
}
|
|
@ -10,13 +10,13 @@ class PageChangedListener {
|
|||
if (pageController.hasClients) {
|
||||
final page = pageController.page!.round();
|
||||
if (page != _prevPage) {
|
||||
onPageChanged?.call(page);
|
||||
onPageChanged?.call(_prevPage, page);
|
||||
_prevPage = page;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final PageController pageController;
|
||||
final ValueChanged<int>? onPageChanged;
|
||||
final void Function(int from, int to)? onPageChanged;
|
||||
int _prevPage;
|
||||
}
|
||||
|
|
17
app/lib/widget/png_icon.dart
Normal file
17
app/lib/widget/png_icon.dart
Normal file
|
@ -0,0 +1,17 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class PngIcon extends StatelessWidget {
|
||||
const PngIcon(
|
||||
this.asset, {
|
||||
super.key,
|
||||
this.size = 24,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Image.asset(asset, width: size, height: size);
|
||||
}
|
||||
|
||||
final String asset;
|
||||
final double size;
|
||||
}
|
|
@ -110,8 +110,8 @@ class _VideoViewerState extends State<VideoViewer>
|
|||
|
||||
Future<void> _initController(String url) async {
|
||||
try {
|
||||
_controllerValue = VideoPlayerController.network(
|
||||
url,
|
||||
_controllerValue = VideoPlayerController.networkUrl(
|
||||
Uri.parse(url),
|
||||
httpHeaders: {
|
||||
"Authorization": AuthUtil.fromAccount(widget.account).toHeaderValue(),
|
||||
},
|
||||
|
|
|
@ -11,6 +11,7 @@ import 'package:kiwi/kiwi.dart';
|
|||
import 'package:logging/logging.dart';
|
||||
import 'package:nc_photos/account.dart';
|
||||
import 'package:nc_photos/app_localizations.dart';
|
||||
import 'package:nc_photos/asset.dart';
|
||||
import 'package:nc_photos/controller/account_controller.dart';
|
||||
import 'package:nc_photos/controller/collection_items_controller.dart';
|
||||
import 'package:nc_photos/di_container.dart';
|
||||
|
@ -23,6 +24,7 @@ import 'package:nc_photos/entity/file_util.dart' as file_util;
|
|||
import 'package:nc_photos/entity/pref.dart';
|
||||
import 'package:nc_photos/flutter_util.dart';
|
||||
import 'package:nc_photos/k.dart' as k;
|
||||
import 'package:nc_photos/live_photo_util.dart';
|
||||
import 'package:nc_photos/object_extension.dart';
|
||||
import 'package:nc_photos/platform/features.dart' as features;
|
||||
import 'package:nc_photos/share_handler.dart';
|
||||
|
@ -34,6 +36,8 @@ import 'package:nc_photos/widget/horizontal_page_viewer.dart';
|
|||
import 'package:nc_photos/widget/image_editor.dart';
|
||||
import 'package:nc_photos/widget/image_enhancer.dart';
|
||||
import 'package:nc_photos/widget/image_viewer.dart';
|
||||
import 'package:nc_photos/widget/live_photo_viewer.dart';
|
||||
import 'package:nc_photos/widget/png_icon.dart';
|
||||
import 'package:nc_photos/widget/slideshow_dialog.dart';
|
||||
import 'package:nc_photos/widget/slideshow_viewer.dart';
|
||||
import 'package:nc_photos/widget/video_viewer.dart';
|
||||
|
@ -43,6 +47,7 @@ import 'package:nc_photos/widget/viewer_mixin.dart';
|
|||
import 'package:np_codegen/np_codegen.dart';
|
||||
import 'package:np_common/or_null.dart';
|
||||
import 'package:np_platform_util/np_platform_util.dart';
|
||||
import 'package:video_player_platform_interface/video_player_platform_interface.dart';
|
||||
|
||||
part 'viewer.g.dart';
|
||||
|
||||
|
@ -164,8 +169,10 @@ class _ViewerState extends State<Viewer>
|
|||
controller: _viewerController,
|
||||
viewportFraction: _viewportFraction,
|
||||
canSwitchPage: _canSwitchPage(),
|
||||
onPageChanged: (_) {
|
||||
setState(() {});
|
||||
onPageChanged: (from, to) {
|
||||
setState(() {
|
||||
_pageStates[from]?.shouldPlayLivePhoto = false;
|
||||
});
|
||||
},
|
||||
),
|
||||
if (_isShowAppBar)
|
||||
|
@ -206,6 +213,17 @@ class _ViewerState extends State<Viewer>
|
|||
centerTitle: isCentered,
|
||||
actions: [
|
||||
if (!_isDetailPaneActive && _canOpenDetailPane()) ...[
|
||||
if (getLivePhotoTypeFromFile(file) != null)
|
||||
if (_pageStates[index]?.shouldPlayLivePhoto ?? false)
|
||||
IconButton(
|
||||
icon: const Icon(Icons.motion_photos_pause_outlined),
|
||||
onPressed: () => _onPauseMotionPhotosPressed(index),
|
||||
)
|
||||
else
|
||||
IconButton(
|
||||
icon: const PngIcon(icMotionPhotosPlay24dp),
|
||||
onPressed: () => _onPlayMotionPhotosPressed(index),
|
||||
),
|
||||
(_pageStates[index]?.favoriteOverride ?? file.fdIsFavorite) == true
|
||||
? IconButton(
|
||||
icon: const Icon(Icons.star),
|
||||
|
@ -361,6 +379,15 @@ class _ViewerState extends State<Viewer>
|
|||
Widget _buildItemView(BuildContext context, int index) {
|
||||
final file = _streamFilesView[index];
|
||||
if (file_util.isSupportedImageFormat(file)) {
|
||||
final shouldPlayLivePhoto = _pageStates[index]!.shouldPlayLivePhoto;
|
||||
if (shouldPlayLivePhoto) {
|
||||
final livePhotoType = getLivePhotoTypeFromFile(file);
|
||||
if (livePhotoType != null) {
|
||||
return _buildLivePhotoView(context, index, livePhotoType);
|
||||
} else {
|
||||
_log.warning("[_buildItemView] Not a live photo");
|
||||
}
|
||||
}
|
||||
return _buildImageView(context, index);
|
||||
} else if (file_util.isSupportedVideoFormat(file)) {
|
||||
return _buildVideoView(context, index);
|
||||
|
@ -404,6 +431,25 @@ class _ViewerState extends State<Viewer>
|
|||
);
|
||||
}
|
||||
|
||||
Widget _buildLivePhotoView(
|
||||
BuildContext context, int index, LivePhotoType livePhotoType) {
|
||||
return LivePhotoViewer(
|
||||
account: widget.account,
|
||||
file: _streamFilesView[index],
|
||||
onLoaded: () => _onVideoLoaded(index),
|
||||
onHeightChanged: (height) => _updateItemHeight(index, height),
|
||||
canPlay: !_isDetailPaneActive,
|
||||
livePhotoType: livePhotoType,
|
||||
onLoadFailure: () {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_pageStates[index]!.shouldPlayLivePhoto = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
bool _onPageContentScrolled(ScrollNotification notification, int index) {
|
||||
if (!_canOpenDetailPane()) {
|
||||
return false;
|
||||
|
@ -538,6 +584,18 @@ class _ViewerState extends State<Viewer>
|
|||
}
|
||||
}
|
||||
|
||||
void _onPlayMotionPhotosPressed(int index) {
|
||||
setState(() {
|
||||
_pageStates[index]!.shouldPlayLivePhoto = true;
|
||||
});
|
||||
}
|
||||
|
||||
void _onPauseMotionPhotosPressed(int index) {
|
||||
setState(() {
|
||||
_pageStates[index]!.shouldPlayLivePhoto = false;
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _onFavoritePressed(int index) async {
|
||||
if (_pageStates[index]!.isProcessingFavorite) {
|
||||
_log.fine("[_onFavoritePressed] Process ongoing, ignored");
|
||||
|
@ -931,6 +989,7 @@ class _PageState {
|
|||
|
||||
bool isProcessingFavorite = false;
|
||||
bool? favoriteOverride;
|
||||
bool shouldPlayLivePhoto = false;
|
||||
}
|
||||
|
||||
class _AppBarTitle extends StatelessWidget {
|
||||
|
|
|
@ -1776,36 +1776,37 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
path: "packages/video_player/video_player"
|
||||
ref: "video_player-v2.4.5-nc-photos-2"
|
||||
resolved-ref: b5c28c21f29f09b623900d5a8cc88a70da29de3a
|
||||
ref: "video_player-v2.8.6-nc-photos-1"
|
||||
resolved-ref: ea754fd61b8bb3c431bd33d1a07709b6f501345c
|
||||
url: "https://gitlab.com/nc-photos/flutter-plugins"
|
||||
source: git
|
||||
version: "2.4.5"
|
||||
version: "2.8.6"
|
||||
video_player_android:
|
||||
dependency: "direct overridden"
|
||||
description:
|
||||
path: "packages/video_player/video_player_android"
|
||||
ref: "video_player-v2.4.5-nc-photos-2"
|
||||
resolved-ref: b5c28c21f29f09b623900d5a8cc88a70da29de3a
|
||||
ref: "video_player-v2.8.6-nc-photos-1"
|
||||
resolved-ref: ea754fd61b8bb3c431bd33d1a07709b6f501345c
|
||||
url: "https://gitlab.com/nc-photos/flutter-plugins"
|
||||
source: git
|
||||
version: "2.3.6"
|
||||
version: "2.4.12"
|
||||
video_player_avfoundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: video_player_avfoundation
|
||||
sha256: "90468226c8687adf7b567d9bb42c25588783c4d30509af1fbd663b2dd049f700"
|
||||
sha256: d1e9a824f2b324000dc8fb2dcb2a3285b6c1c7c487521c63306cc5b394f68a7c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.2"
|
||||
version: "2.6.1"
|
||||
video_player_platform_interface:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: video_player_platform_interface
|
||||
sha256: "318a6d20577e1c78cf0bf40670883cc571ea860c72a4f7426d7dacce4bdd4343"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.1.4"
|
||||
path: "packages/video_player/video_player_platform_interface"
|
||||
ref: "video_player-v2.8.6-nc-photos-1"
|
||||
resolved-ref: ea754fd61b8bb3c431bd33d1a07709b6f501345c
|
||||
url: "https://gitlab.com/nc-photos/flutter-plugins"
|
||||
source: git
|
||||
version: "6.2.2"
|
||||
video_player_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -153,7 +153,8 @@ dependencies:
|
|||
tuple: ^2.0.2
|
||||
url_launcher: ^6.2.6
|
||||
uuid: ^3.0.7
|
||||
video_player: 2.4.5
|
||||
video_player:
|
||||
video_player_platform_interface:
|
||||
visibility_detector: ^0.4.0+2
|
||||
wakelock_plus: ^1.1.1
|
||||
woozy_search: ^2.0.3
|
||||
|
@ -162,13 +163,18 @@ dependency_overrides:
|
|||
video_player:
|
||||
git:
|
||||
url: https://gitlab.com/nc-photos/flutter-plugins
|
||||
ref: video_player-v2.4.5-nc-photos-2
|
||||
ref: video_player-v2.8.6-nc-photos-1
|
||||
path: packages/video_player/video_player
|
||||
video_player_android:
|
||||
git:
|
||||
url: https://gitlab.com/nc-photos/flutter-plugins
|
||||
ref: video_player-v2.4.5-nc-photos-2
|
||||
ref: video_player-v2.8.6-nc-photos-1
|
||||
path: packages/video_player/video_player_android
|
||||
video_player_platform_interface:
|
||||
git:
|
||||
url: https://gitlab.com/nc-photos/flutter-plugins
|
||||
ref: video_player-v2.8.6-nc-photos-1
|
||||
path: packages/video_player/video_player_platform_interface
|
||||
|
||||
dev_dependencies:
|
||||
test: ^1.22.1
|
||||
|
|
Loading…
Reference in a new issue