fullscreen: fixed video init when deleting previous entry

This commit is contained in:
Thibault Deckers 2020-03-18 11:19:14 +09:00
parent 7fe8dbe13c
commit 1400ff7ecc

View file

@ -33,6 +33,7 @@ class FullscreenBody extends StatefulWidget {
} }
class FullscreenBodyState extends State<FullscreenBody> with SingleTickerProviderStateMixin { class FullscreenBodyState extends State<FullscreenBody> with SingleTickerProviderStateMixin {
ImageEntry _entry;
int _currentHorizontalPage; int _currentHorizontalPage;
ValueNotifier<int> _currentVerticalPage; ValueNotifier<int> _currentVerticalPage;
PageController _horizontalPager, _verticalPager; PageController _horizontalPager, _verticalPager;
@ -61,7 +62,8 @@ class FullscreenBodyState extends State<FullscreenBody> with SingleTickerProvide
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_currentHorizontalPage = max(0, entries.indexOf(widget.initialEntry)); _entry = widget.initialEntry;
_currentHorizontalPage = max(0, entries.indexOf(_entry));
_currentVerticalPage = ValueNotifier(imagePage); _currentVerticalPage = ValueNotifier(imagePage);
_horizontalPager = PageController(initialPage: _currentHorizontalPage); _horizontalPager = PageController(initialPage: _currentHorizontalPage);
_verticalPager = PageController(initialPage: _currentVerticalPage.value); _verticalPager = PageController(initialPage: _currentVerticalPage.value);
@ -90,13 +92,14 @@ class FullscreenBodyState extends State<FullscreenBody> with SingleTickerProvide
); );
_initVideoController(); _initVideoController();
_initOverlay(); _initOverlay();
_registerWidget(widget);
} }
Future<void> _initOverlay() async { @override
// wait for MaterialPageRoute.transitionDuration void didUpdateWidget(FullscreenBody oldWidget) {
// to show overlay after hero animation is complete super.didUpdateWidget(oldWidget);
await Future.delayed(Duration(milliseconds: (300 * timeDilation).toInt())); _unregisterWidget(oldWidget);
await _onOverlayVisibleChange(); _registerWidget(widget);
} }
@override @override
@ -104,12 +107,20 @@ class FullscreenBodyState extends State<FullscreenBody> with SingleTickerProvide
_overlayAnimationController.dispose(); _overlayAnimationController.dispose();
_overlayVisible.removeListener(_onOverlayVisibleChange); _overlayVisible.removeListener(_onOverlayVisibleChange);
_videoControllers.forEach((kv) => kv.item2.dispose()); _videoControllers.forEach((kv) => kv.item2.dispose());
_unregisterWidget(widget);
super.dispose(); super.dispose();
} }
void _registerWidget(FullscreenBody widget) {
widget.collection.addListener(_onCollectionChange);
}
void _unregisterWidget(FullscreenBody widget) {
widget.collection.removeListener(_onCollectionChange);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final entry = _currentHorizontalPage != null && _currentHorizontalPage < entries.length ? entries[_currentHorizontalPage] : null;
return WillPopScope( return WillPopScope(
onWillPop: () { onWillPop: () {
if (_currentVerticalPage.value == infoPage) { if (_currentVerticalPage.value == infoPage) {
@ -128,7 +139,7 @@ class FullscreenBodyState extends State<FullscreenBody> with SingleTickerProvide
children: [ children: [
FullscreenVerticalPageView( FullscreenVerticalPageView(
collection: collection, collection: collection,
entry: entry, entry: _entry,
videoControllers: _videoControllers, videoControllers: _videoControllers,
verticalPager: _verticalPager, verticalPager: _verticalPager,
horizontalPager: _horizontalPager, horizontalPager: _horizontalPager,
@ -140,7 +151,7 @@ class FullscreenBodyState extends State<FullscreenBody> with SingleTickerProvide
ValueListenableBuilder<int>( ValueListenableBuilder<int>(
valueListenable: _currentVerticalPage, valueListenable: _currentVerticalPage,
builder: (context, page, child) { builder: (context, page, child) {
final showOverlay = entry != null && page == imagePage; final showOverlay = _entry != null && page == imagePage;
return showOverlay return showOverlay
? FullscreenTopOverlay( ? FullscreenTopOverlay(
entries: entries, entries: entries,
@ -148,7 +159,7 @@ class FullscreenBodyState extends State<FullscreenBody> with SingleTickerProvide
scale: _topOverlayScale, scale: _topOverlayScale,
viewInsets: _frozenViewInsets, viewInsets: _frozenViewInsets,
viewPadding: _frozenViewPadding, viewPadding: _frozenViewPadding,
onActionSelected: (action) => _actionDelegate.onActionSelected(context, entry, action), onActionSelected: (action) => _actionDelegate.onActionSelected(context, _entry, action),
) )
: const SizedBox.shrink(); : const SizedBox.shrink();
}, },
@ -156,8 +167,8 @@ class FullscreenBodyState extends State<FullscreenBody> with SingleTickerProvide
ValueListenableBuilder<int>( ValueListenableBuilder<int>(
valueListenable: _currentVerticalPage, valueListenable: _currentVerticalPage,
builder: (context, page, child) { builder: (context, page, child) {
final showOverlay = entry != null && page == imagePage; final showOverlay = _entry != null && page == imagePage;
final videoController = showOverlay && entry.isVideo ? _videoControllers.firstWhere((kv) => kv.item1 == entry.uri, orElse: () => null)?.item2 : null; final videoController = showOverlay && _entry.isVideo ? _videoControllers.firstWhere((kv) => kv.item1 == _entry.uri, orElse: () => null)?.item2 : null;
return showOverlay return showOverlay
? Positioned( ? Positioned(
bottom: 0, bottom: 0,
@ -165,7 +176,7 @@ class FullscreenBodyState extends State<FullscreenBody> with SingleTickerProvide
children: [ children: [
if (videoController != null) if (videoController != null)
VideoControlOverlay( VideoControlOverlay(
entry: entry, entry: _entry,
controller: videoController, controller: videoController,
scale: _bottomOverlayScale, scale: _bottomOverlayScale,
viewInsets: _frozenViewInsets, viewInsets: _frozenViewInsets,
@ -208,12 +219,41 @@ class FullscreenBodyState extends State<FullscreenBody> with SingleTickerProvide
} }
} }
void _onHorizontalPageChanged(int page) {
_currentHorizontalPage = page;
_updateEntry();
}
void _onCollectionChange() {
_updateEntry();
}
void _updateEntry() {
final newEntry = _currentHorizontalPage != null && _currentHorizontalPage < entries.length ? entries[_currentHorizontalPage] : null;
if (_entry == newEntry) return;
_entry = newEntry;
_pauseVideoControllers();
_initVideoController();
setState(() {});
}
// system UI
void _onLeave() => _showSystemUI(); void _onLeave() => _showSystemUI();
void _showSystemUI() => SystemChrome.setEnabledSystemUIOverlays(SystemUiOverlay.values); void _showSystemUI() => SystemChrome.setEnabledSystemUIOverlays(SystemUiOverlay.values);
void _hideSystemUI() => SystemChrome.setEnabledSystemUIOverlays([]); void _hideSystemUI() => SystemChrome.setEnabledSystemUIOverlays([]);
// overlay
Future<void> _initOverlay() async {
// wait for MaterialPageRoute.transitionDuration
// to show overlay after hero animation is complete
await Future.delayed(Duration(milliseconds: (300 * timeDilation).toInt()));
await _onOverlayVisibleChange();
}
Future<void> _onOverlayVisibleChange() async { Future<void> _onOverlayVisibleChange() async {
if (_overlayVisible.value) { if (_overlayVisible.value) {
_showSystemUI(); _showSystemUI();
@ -231,20 +271,14 @@ class FullscreenBodyState extends State<FullscreenBody> with SingleTickerProvide
} }
} }
void _onHorizontalPageChanged(int page) { // video controller
_currentHorizontalPage = page;
_pauseVideoControllers();
_initVideoController();
setState(() {});
}
void _pauseVideoControllers() => _videoControllers.forEach((e) => e.item2.pause()); void _pauseVideoControllers() => _videoControllers.forEach((e) => e.item2.pause());
void _initVideoController() { void _initVideoController() {
final entry = _currentHorizontalPage != null && _currentHorizontalPage < entries.length ? entries[_currentHorizontalPage] : null; if (_entry == null || !_entry.isVideo) return;
if (entry == null || !entry.isVideo) return;
final uri = entry.uri; final uri = _entry.uri;
var controllerEntry = _videoControllers.firstWhere((kv) => kv.item1 == uri, orElse: () => null); var controllerEntry = _videoControllers.firstWhere((kv) => kv.item1 == uri, orElse: () => null);
if (controllerEntry != null) { if (controllerEntry != null) {
_videoControllers.remove(controllerEntry); _videoControllers.remove(controllerEntry);
@ -323,17 +357,6 @@ class _FullscreenVerticalPageViewState extends State<FullscreenVerticalPageView>
widget.entry.imageChangeNotifier.removeListener(_onImageChange); widget.entry.imageChangeNotifier.removeListener(_onImageChange);
} }
void _onVerticalPageControllerChange() {
_backgroundColorNotifier.value = _backgroundColorNotifier.value.withOpacity(min(1.0, widget.verticalPager.page));
}
void _onImageChange() async {
await UriImage(entry.uri).evict();
if (entry.path != null) await FileImage(File(entry.path)).evict();
// rebuild to refresh the Image inside ImagePage
setState(() {});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final onScaleChanged = (state) => setState(() => _isInitialScale = state == PhotoViewScaleState.initial); final onScaleChanged = (state) => setState(() => _isInitialScale = state == PhotoViewScaleState.initial);
@ -386,4 +409,15 @@ class _FullscreenVerticalPageViewState extends State<FullscreenVerticalPageView>
), ),
); );
} }
void _onVerticalPageControllerChange() {
_backgroundColorNotifier.value = _backgroundColorNotifier.value.withOpacity(min(1.0, widget.verticalPager.page));
}
void _onImageChange() async {
await UriImage(entry.uri).evict();
if (entry.path != null) await FileImage(File(entry.path)).evict();
// rebuild to refresh the Image inside ImagePage
setState(() {});
}
} }