aves/lib/widgets/viewer/entry_vertical_pager.dart
2021-01-25 12:43:04 +09:00

165 lines
5.6 KiB
Dart

import 'dart:math';
import 'package:aves/model/entry.dart';
import 'package:aves/model/source/collection_lens.dart';
import 'package:aves/widgets/common/magnifier/pan/scroll_physics.dart';
import 'package:aves/widgets/viewer/entry_horizontal_pager.dart';
import 'package:aves/widgets/viewer/info/info_page.dart';
import 'package:aves/widgets/viewer/info/notifications.dart';
import 'package:aves/widgets/viewer/multipage.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_ijkplayer/flutter_ijkplayer.dart';
import 'package:tuple/tuple.dart';
class ViewerVerticalPageView extends StatefulWidget {
final CollectionLens collection;
final ValueNotifier<AvesEntry> entryNotifier;
final List<Tuple2<String, IjkMediaController>> videoControllers;
final List<Tuple2<String, MultiPageController>> multiPageControllers;
final PageController horizontalPager, verticalPager;
final void Function(int page) onVerticalPageChanged, onHorizontalPageChanged;
final VoidCallback onImageTap, onImagePageRequested;
final void Function(String uri) onViewDisposed;
const ViewerVerticalPageView({
@required this.collection,
@required this.entryNotifier,
@required this.videoControllers,
@required this.multiPageControllers,
@required this.verticalPager,
@required this.horizontalPager,
@required this.onVerticalPageChanged,
@required this.onHorizontalPageChanged,
@required this.onImageTap,
@required this.onImagePageRequested,
@required this.onViewDisposed,
});
@override
_ViewerVerticalPageViewState createState() => _ViewerVerticalPageViewState();
}
class _ViewerVerticalPageViewState extends State<ViewerVerticalPageView> {
final ValueNotifier<Color> _backgroundColorNotifier = ValueNotifier(Colors.black);
final ValueNotifier<bool> _infoPageVisibleNotifier = ValueNotifier(false);
AvesEntry _oldEntry;
CollectionLens get collection => widget.collection;
bool get hasCollection => collection != null;
AvesEntry get entry => widget.entryNotifier.value;
@override
void initState() {
super.initState();
_registerWidget(widget);
}
@override
void didUpdateWidget(covariant ViewerVerticalPageView oldWidget) {
super.didUpdateWidget(oldWidget);
_unregisterWidget(oldWidget);
_registerWidget(widget);
}
@override
void dispose() {
_unregisterWidget(widget);
super.dispose();
}
void _registerWidget(ViewerVerticalPageView widget) {
widget.verticalPager.addListener(_onVerticalPageControllerChanged);
widget.entryNotifier.addListener(_onEntryChanged);
if (_oldEntry != entry) _onEntryChanged();
}
void _unregisterWidget(ViewerVerticalPageView widget) {
widget.verticalPager.removeListener(_onVerticalPageControllerChanged);
widget.entryNotifier.removeListener(_onEntryChanged);
_oldEntry?.imageChangeNotifier?.removeListener(_onImageChanged);
}
@override
Widget build(BuildContext context) {
final pages = [
// fake page for opacity transition between collection and viewer
SizedBox(),
hasCollection
? MultiEntryScroller(
collection: collection,
pageController: widget.horizontalPager,
onTap: widget.onImageTap,
onPageChanged: widget.onHorizontalPageChanged,
videoControllers: widget.videoControllers,
multiPageControllers: widget.multiPageControllers,
onViewDisposed: widget.onViewDisposed,
)
: SingleEntryScroller(
entry: entry,
onTap: widget.onImageTap,
videoControllers: widget.videoControllers,
multiPageControllers: widget.multiPageControllers,
),
NotificationListener(
onNotification: (notification) {
if (notification is BackUpNotification) widget.onImagePageRequested();
return false;
},
child: InfoPage(
collection: collection,
entryNotifier: widget.entryNotifier,
visibleNotifier: _infoPageVisibleNotifier,
),
),
];
return ValueListenableBuilder<Color>(
valueListenable: _backgroundColorNotifier,
builder: (context, backgroundColor, child) => Container(
color: backgroundColor,
child: child,
),
child: PageView(
key: Key('vertical-pageview'),
scrollDirection: Axis.vertical,
controller: widget.verticalPager,
physics: MagnifierScrollerPhysics(parent: PageScrollPhysics()),
onPageChanged: (page) {
widget.onVerticalPageChanged(page);
_infoPageVisibleNotifier.value = page == pages.length - 1;
},
children: pages,
),
);
}
void _onVerticalPageControllerChanged() {
final opacity = min(1.0, widget.verticalPager.page);
_backgroundColorNotifier.value = _backgroundColorNotifier.value.withOpacity(opacity * opacity);
}
// when the entry changed (e.g. by scrolling through the PageView, or if the entry got deleted)
void _onEntryChanged() {
_oldEntry?.imageChangeNotifier?.removeListener(_onImageChanged);
_oldEntry = entry;
if (entry != null) {
entry.imageChangeNotifier.addListener(_onImageChanged);
// make sure to locate the entry,
// so that we can display the address instead of coordinates
// even when background locating has not reached this entry yet
entry.locate();
} else {
Navigator.pop(context);
}
}
// when the entry image itself changed (e.g. after rotation)
void _onImageChanged() async {
// rebuild to refresh the Image inside ImagePage
setState(() {});
}
}