viewer: collapse motion photo pages in button row
This commit is contained in:
parent
db5b971a81
commit
e92cee781c
4 changed files with 54 additions and 17 deletions
|
@ -15,7 +15,7 @@ class ThumbnailScroller extends StatefulWidget {
|
||||||
final ValueNotifier<int?> indexNotifier;
|
final ValueNotifier<int?> indexNotifier;
|
||||||
final void Function(int index)? onTap;
|
final void Function(int index)? onTap;
|
||||||
final Object? Function(AvesEntry entry)? heroTagger;
|
final Object? Function(AvesEntry entry)? heroTagger;
|
||||||
final bool highlightable, showLocation;
|
final bool scrollable, highlightable, showLocation;
|
||||||
|
|
||||||
const ThumbnailScroller({
|
const ThumbnailScroller({
|
||||||
Key? key,
|
Key? key,
|
||||||
|
@ -27,6 +27,7 @@ class ThumbnailScroller extends StatefulWidget {
|
||||||
this.heroTagger,
|
this.heroTagger,
|
||||||
this.highlightable = false,
|
this.highlightable = false,
|
||||||
this.showLocation = true,
|
this.showLocation = true,
|
||||||
|
this.scrollable = true,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -46,6 +47,10 @@ class _ThumbnailScrollerState extends State<ThumbnailScroller> {
|
||||||
|
|
||||||
ValueNotifier<int?> get indexNotifier => widget.indexNotifier;
|
ValueNotifier<int?> get indexNotifier => widget.indexNotifier;
|
||||||
|
|
||||||
|
bool get scrollable => widget.scrollable;
|
||||||
|
|
||||||
|
static double widthFor(int pageCount) => pageCount == 0 ? 0 : pageCount * thumbnailExtent + (pageCount - 1) * separatorWidth;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
@ -84,13 +89,14 @@ class _ThumbnailScrollerState extends State<ThumbnailScroller> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final marginWidth = max(0.0, (widget.availableWidth - thumbnailExtent) / 2 - separatorWidth);
|
final marginWidth = max(0.0, (widget.availableWidth - thumbnailExtent) / 2 - separatorWidth);
|
||||||
final padding = EdgeInsets.only(left: marginWidth + separatorWidth, right: marginWidth);
|
final padding = scrollable ? EdgeInsets.only(left: marginWidth + separatorWidth, right: marginWidth) : EdgeInsets.zero;
|
||||||
|
|
||||||
return GridTheme(
|
return GridTheme(
|
||||||
extent: thumbnailExtent,
|
extent: thumbnailExtent,
|
||||||
showLocation: widget.showLocation && settings.showThumbnailLocation,
|
showLocation: widget.showLocation && settings.showThumbnailLocation,
|
||||||
showTrash: false,
|
showTrash: false,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
|
width: scrollable ? null : widthFor(entryCount),
|
||||||
height: thumbnailExtent,
|
height: thumbnailExtent,
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
|
@ -98,10 +104,12 @@ class _ThumbnailScrollerState extends State<ThumbnailScroller> {
|
||||||
// as of Flutter v2.10.2, `FixedExtentScrollController` can only be used with `ListWheelScrollView`
|
// as of Flutter v2.10.2, `FixedExtentScrollController` can only be used with `ListWheelScrollView`
|
||||||
// and `FixedExtentScrollPhysics` can only be used with Scrollables that uses the `FixedExtentScrollController`
|
// and `FixedExtentScrollPhysics` can only be used with Scrollables that uses the `FixedExtentScrollController`
|
||||||
// so we use `KnownExtentScrollPhysics`, adapted from `FixedExtentScrollPhysics` without the constraints
|
// so we use `KnownExtentScrollPhysics`, adapted from `FixedExtentScrollPhysics` without the constraints
|
||||||
physics: KnownExtentScrollPhysics(
|
physics: scrollable
|
||||||
|
? KnownExtentScrollPhysics(
|
||||||
indexToScrollOffset: indexToScrollOffset,
|
indexToScrollOffset: indexToScrollOffset,
|
||||||
scrollOffsetToIndex: scrollOffsetToIndex,
|
scrollOffsetToIndex: scrollOffsetToIndex,
|
||||||
),
|
)
|
||||||
|
: const NeverScrollableScrollPhysics(),
|
||||||
padding: padding,
|
padding: padding,
|
||||||
itemExtent: itemExtent,
|
itemExtent: itemExtent,
|
||||||
itemBuilder: (context, index) => _buildThumbnail(index),
|
itemBuilder: (context, index) => _buildThumbnail(index),
|
||||||
|
@ -152,6 +160,8 @@ class _ThumbnailScrollerState extends State<ThumbnailScroller> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _goTo(int index) async {
|
Future<void> _goTo(int index) async {
|
||||||
|
if (!scrollable) return;
|
||||||
|
|
||||||
final targetOffset = indexToScrollOffset(index);
|
final targetOffset = indexToScrollOffset(index);
|
||||||
final offsetDelta = (targetOffset - _scrollController.offset).abs();
|
final offsetDelta = (targetOffset - _scrollController.offset).abs();
|
||||||
|
|
||||||
|
|
|
@ -136,13 +136,23 @@ class _BottomOverlayContentState extends State<_BottomOverlayContent> {
|
||||||
return Selector<MediaQueryData, double>(
|
return Selector<MediaQueryData, double>(
|
||||||
selector: (context, mq) => mq.size.width,
|
selector: (context, mq) => mq.size.width,
|
||||||
builder: (context, mqWidth, child) {
|
builder: (context, mqWidth, child) {
|
||||||
|
final viewerButtonRow = ViewerButtonRow(
|
||||||
|
mainEntry: mainEntry,
|
||||||
|
pageEntry: pageEntry,
|
||||||
|
scale: _buttonScale,
|
||||||
|
canToggleFavourite: widget.hasCollection,
|
||||||
|
);
|
||||||
|
|
||||||
|
final showMultiPageOverlay = mainEntry.isMultiPage && multiPageController != null;
|
||||||
|
final collapsedPageScroller = mainEntry.isMotionPhoto;
|
||||||
|
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: mqWidth,
|
width: mqWidth,
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
if (mainEntry.isMultiPage && multiPageController != null)
|
if (showMultiPageOverlay && !collapsedPageScroller)
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 8),
|
padding: const EdgeInsets.only(bottom: 8),
|
||||||
child: FadeTransition(
|
child: FadeTransition(
|
||||||
|
@ -150,15 +160,30 @@ class _BottomOverlayContentState extends State<_BottomOverlayContent> {
|
||||||
child: MultiPageOverlay(
|
child: MultiPageOverlay(
|
||||||
controller: multiPageController,
|
controller: multiPageController,
|
||||||
availableWidth: mqWidth,
|
availableWidth: mqWidth,
|
||||||
|
scrollable: true,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
ViewerButtonRow(
|
(showMultiPageOverlay && collapsedPageScroller)
|
||||||
mainEntry: mainEntry,
|
? Row(
|
||||||
pageEntry: pageEntry,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
scale: _buttonScale,
|
children: [
|
||||||
canToggleFavourite: widget.hasCollection,
|
SafeArea(
|
||||||
|
top: false,
|
||||||
|
bottom: false,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 8),
|
||||||
|
child: MultiPageOverlay(
|
||||||
|
controller: multiPageController,
|
||||||
|
availableWidth: mqWidth,
|
||||||
|
scrollable: false,
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(child: viewerButtonRow),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
: viewerButtonRow,
|
||||||
if (settings.showOverlayThumbnailPreview)
|
if (settings.showOverlayThumbnailPreview)
|
||||||
FadeTransition(
|
FadeTransition(
|
||||||
opacity: _thumbnailOpacity,
|
opacity: _thumbnailOpacity,
|
||||||
|
|
|
@ -8,11 +8,13 @@ import 'package:provider/provider.dart';
|
||||||
class MultiPageOverlay extends StatefulWidget {
|
class MultiPageOverlay extends StatefulWidget {
|
||||||
final MultiPageController controller;
|
final MultiPageController controller;
|
||||||
final double availableWidth;
|
final double availableWidth;
|
||||||
|
final bool scrollable;
|
||||||
|
|
||||||
const MultiPageOverlay({
|
const MultiPageOverlay({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.controller,
|
required this.controller,
|
||||||
required this.availableWidth,
|
required this.availableWidth,
|
||||||
|
required this.scrollable,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -66,6 +68,7 @@ class _MultiPageOverlayState extends State<MultiPageOverlay> {
|
||||||
entryCount: multiPageInfo?.pageCount ?? 0,
|
entryCount: multiPageInfo?.pageCount ?? 0,
|
||||||
entryBuilder: (page) => multiPageInfo?.getPageEntryByIndex(page),
|
entryBuilder: (page) => multiPageInfo?.getPageEntryByIndex(page),
|
||||||
indexNotifier: controller.pageNotifier,
|
indexNotifier: controller.pageNotifier,
|
||||||
|
scrollable: widget.scrollable,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -105,11 +105,10 @@ class ViewerButtonRow extends StatelessWidget {
|
||||||
return SafeArea(
|
return SafeArea(
|
||||||
top: false,
|
top: false,
|
||||||
bottom: false,
|
bottom: false,
|
||||||
child: Selector<MediaQueryData, double>(
|
child: LayoutBuilder(
|
||||||
selector: (context, mq) => mq.size.width - mq.padding.horizontal,
|
builder: (context, constraints) {
|
||||||
builder: (context, mqWidth, child) {
|
|
||||||
final buttonWidth = OverlayButton.getSize(context);
|
final buttonWidth = OverlayButton.getSize(context);
|
||||||
final availableCount = ((mqWidth - outerPadding * 2) / (buttonWidth + innerPadding)).floor();
|
final availableCount = ((constraints.maxWidth - outerPadding * 2) / (buttonWidth + innerPadding)).floor();
|
||||||
return Selector<Settings, bool>(
|
return Selector<Settings, bool>(
|
||||||
selector: (context, s) => s.isRotationLocked,
|
selector: (context, s) => s.isRotationLocked,
|
||||||
builder: (context, s, child) {
|
builder: (context, s, child) {
|
||||||
|
|
Loading…
Reference in a new issue