viewer: collapse motion photo pages in button row

This commit is contained in:
Thibault Deckers 2022-03-06 12:27:05 +09:00
parent db5b971a81
commit e92cee781c
4 changed files with 54 additions and 17 deletions

View file

@ -15,7 +15,7 @@ class ThumbnailScroller extends StatefulWidget {
final ValueNotifier<int?> indexNotifier;
final void Function(int index)? onTap;
final Object? Function(AvesEntry entry)? heroTagger;
final bool highlightable, showLocation;
final bool scrollable, highlightable, showLocation;
const ThumbnailScroller({
Key? key,
@ -27,6 +27,7 @@ class ThumbnailScroller extends StatefulWidget {
this.heroTagger,
this.highlightable = false,
this.showLocation = true,
this.scrollable = true,
}) : super(key: key);
@override
@ -46,6 +47,10 @@ class _ThumbnailScrollerState extends State<ThumbnailScroller> {
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
void initState() {
super.initState();
@ -84,13 +89,14 @@ class _ThumbnailScrollerState extends State<ThumbnailScroller> {
@override
Widget build(BuildContext context) {
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(
extent: thumbnailExtent,
showLocation: widget.showLocation && settings.showThumbnailLocation,
showTrash: false,
child: SizedBox(
width: scrollable ? null : widthFor(entryCount),
height: thumbnailExtent,
child: ListView.builder(
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`
// and `FixedExtentScrollPhysics` can only be used with Scrollables that uses the `FixedExtentScrollController`
// so we use `KnownExtentScrollPhysics`, adapted from `FixedExtentScrollPhysics` without the constraints
physics: KnownExtentScrollPhysics(
indexToScrollOffset: indexToScrollOffset,
scrollOffsetToIndex: scrollOffsetToIndex,
),
physics: scrollable
? KnownExtentScrollPhysics(
indexToScrollOffset: indexToScrollOffset,
scrollOffsetToIndex: scrollOffsetToIndex,
)
: const NeverScrollableScrollPhysics(),
padding: padding,
itemExtent: itemExtent,
itemBuilder: (context, index) => _buildThumbnail(index),
@ -152,6 +160,8 @@ class _ThumbnailScrollerState extends State<ThumbnailScroller> {
}
Future<void> _goTo(int index) async {
if (!scrollable) return;
final targetOffset = indexToScrollOffset(index);
final offsetDelta = (targetOffset - _scrollController.offset).abs();

View file

@ -136,13 +136,23 @@ class _BottomOverlayContentState extends State<_BottomOverlayContent> {
return Selector<MediaQueryData, double>(
selector: (context, mq) => mq.size.width,
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(
width: mqWidth,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (mainEntry.isMultiPage && multiPageController != null)
if (showMultiPageOverlay && !collapsedPageScroller)
Padding(
padding: const EdgeInsets.only(bottom: 8),
child: FadeTransition(
@ -150,15 +160,30 @@ class _BottomOverlayContentState extends State<_BottomOverlayContent> {
child: MultiPageOverlay(
controller: multiPageController,
availableWidth: mqWidth,
scrollable: true,
),
),
),
ViewerButtonRow(
mainEntry: mainEntry,
pageEntry: pageEntry,
scale: _buttonScale,
canToggleFavourite: widget.hasCollection,
),
(showMultiPageOverlay && collapsedPageScroller)
? Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
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)
FadeTransition(
opacity: _thumbnailOpacity,

View file

@ -8,11 +8,13 @@ import 'package:provider/provider.dart';
class MultiPageOverlay extends StatefulWidget {
final MultiPageController controller;
final double availableWidth;
final bool scrollable;
const MultiPageOverlay({
Key? key,
required this.controller,
required this.availableWidth,
required this.scrollable,
}) : super(key: key);
@override
@ -66,6 +68,7 @@ class _MultiPageOverlayState extends State<MultiPageOverlay> {
entryCount: multiPageInfo?.pageCount ?? 0,
entryBuilder: (page) => multiPageInfo?.getPageEntryByIndex(page),
indexNotifier: controller.pageNotifier,
scrollable: widget.scrollable,
);
},
);

View file

@ -105,11 +105,10 @@ class ViewerButtonRow extends StatelessWidget {
return SafeArea(
top: false,
bottom: false,
child: Selector<MediaQueryData, double>(
selector: (context, mq) => mq.size.width - mq.padding.horizontal,
builder: (context, mqWidth, child) {
child: LayoutBuilder(
builder: (context, constraints) {
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>(
selector: (context, s) => s.isRotationLocked,
builder: (context, s, child) {