thumb zoom prep

This commit is contained in:
Thibault Deckers 2023-03-08 14:24:56 +01:00
parent 655d251890
commit 09cf4fef3e
20 changed files with 271 additions and 219 deletions

View file

@ -125,6 +125,7 @@ class AIcons {
static const IconData setCover = MdiIcons.imageEditOutline; static const IconData setCover = MdiIcons.imageEditOutline;
static const IconData share = Icons.share_outlined; static const IconData share = Icons.share_outlined;
static const IconData show = Icons.visibility_outlined; static const IconData show = Icons.visibility_outlined;
static const IconData showFullscreen = MdiIcons.arrowExpand;
static const IconData slideshow = Icons.slideshow_outlined; static const IconData slideshow = Icons.slideshow_outlined;
static const IconData speed = Icons.speed_outlined; static const IconData speed = Icons.speed_outlined;
static const IconData stats = Icons.donut_small_outlined; static const IconData stats = Icons.donut_small_outlined;

View file

@ -5,6 +5,7 @@ import 'package:aves/model/entry.dart';
import 'package:aves/model/favourites.dart'; import 'package:aves/model/favourites.dart';
import 'package:aves/model/filters/favourite.dart'; import 'package:aves/model/filters/favourite.dart';
import 'package:aves/model/filters/mime.dart'; import 'package:aves/model/filters/mime.dart';
import 'package:aves/model/selection.dart';
import 'package:aves/model/settings/settings.dart'; import 'package:aves/model/settings/settings.dart';
import 'package:aves/model/source/collection_lens.dart'; import 'package:aves/model/source/collection_lens.dart';
import 'package:aves/model/source/collection_source.dart'; import 'package:aves/model/source/collection_source.dart';
@ -21,6 +22,7 @@ import 'package:aves/widgets/collection/grid/section_layout.dart';
import 'package:aves/widgets/collection/grid/tile.dart'; import 'package:aves/widgets/collection/grid/tile.dart';
import 'package:aves/widgets/common/basic/draggable_scrollbar/scrollbar.dart'; import 'package:aves/widgets/common/basic/draggable_scrollbar/scrollbar.dart';
import 'package:aves/widgets/common/basic/insets.dart'; import 'package:aves/widgets/common/basic/insets.dart';
import 'package:aves/widgets/common/behaviour/routes.dart';
import 'package:aves/widgets/common/behaviour/sloppy_scroll_physics.dart'; import 'package:aves/widgets/common/behaviour/sloppy_scroll_physics.dart';
import 'package:aves/widgets/common/extensions/build_context.dart'; import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/common/extensions/media_query.dart'; import 'package:aves/widgets/common/extensions/media_query.dart';
@ -39,8 +41,10 @@ import 'package:aves/widgets/common/identity/scroll_thumb.dart';
import 'package:aves/widgets/common/providers/tile_extent_controller_provider.dart'; import 'package:aves/widgets/common/providers/tile_extent_controller_provider.dart';
import 'package:aves/widgets/common/thumbnail/decorated.dart'; import 'package:aves/widgets/common/thumbnail/decorated.dart';
import 'package:aves/widgets/common/thumbnail/image.dart'; import 'package:aves/widgets/common/thumbnail/image.dart';
import 'package:aves/widgets/common/thumbnail/notifications.dart';
import 'package:aves/widgets/common/tile_extent_controller.dart'; import 'package:aves/widgets/common/tile_extent_controller.dart';
import 'package:aves/widgets/navigation/nav_bar/nav_bar.dart'; import 'package:aves/widgets/navigation/nav_bar/nav_bar.dart';
import 'package:aves/widgets/viewer/entry_viewer_page.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
@ -152,58 +156,64 @@ class _CollectionGridContentState extends State<_CollectionGridContent> {
tileAnimationDelay = Duration.zero; tileAnimationDelay = Duration.zero;
} }
return StreamBuilder( return NotificationListener<OpenViewerNotification>(
stream: source.eventBus.on<AspectRatioChangedEvent>(), onNotification: (notification) {
builder: (context, snapshot) => SectionedEntryListLayoutProvider( _goToViewer(collection, notification.entry);
collection: collection, return true;
selectable: selectable, },
scrollableWidth: scrollableWidth, child: StreamBuilder(
tileLayout: tileLayout, stream: source.eventBus.on<AspectRatioChangedEvent>(),
columnCount: columnCount, builder: (context, snapshot) => SectionedEntryListLayoutProvider(
spacing: tileSpacing, collection: collection,
horizontalPadding: horizontalPadding, selectable: selectable,
tileExtent: thumbnailExtent, scrollableWidth: scrollableWidth,
tileBuilder: (entry, tileSize) { tileLayout: tileLayout,
final extent = tileSize.shortestSide; columnCount: columnCount,
return AnimatedBuilder( spacing: tileSpacing,
animation: favourites, horizontalPadding: horizontalPadding,
builder: (context, child) { tileExtent: thumbnailExtent,
Widget tile = InteractiveTile( tileBuilder: (entry, tileSize) {
key: ValueKey(entry.id), final extent = tileSize.shortestSide;
collection: collection, return AnimatedBuilder(
entry: entry, animation: favourites,
thumbnailExtent: extent, builder: (context, child) {
tileLayout: tileLayout, Widget tile = InteractiveTile(
isScrollingNotifier: _isScrollingNotifier, key: ValueKey(entry.id),
); collection: collection,
if (!settings.useTvLayout) return tile; entry: entry,
thumbnailExtent: extent,
tileLayout: tileLayout,
isScrollingNotifier: _isScrollingNotifier,
);
if (!settings.useTvLayout) return tile;
return Focus( return Focus(
onFocusChange: (focused) { onFocusChange: (focused) {
if (focused) { if (focused) {
_focusedItemNotifier.value = entry; _focusedItemNotifier.value = entry;
} else if (_focusedItemNotifier.value == entry) { } else if (_focusedItemNotifier.value == entry) {
_focusedItemNotifier.value = null; _focusedItemNotifier.value = null;
} }
},
child: ValueListenableBuilder<AvesEntry?>(
valueListenable: _focusedItemNotifier,
builder: (context, focusedItem, child) {
return AnimatedScale(
scale: focusedItem == entry ? 1 : .9,
curve: Curves.fastOutSlowIn,
duration: context.select<DurationsData, Duration>((v) => v.tvImageFocusAnimation),
child: child!,
);
}, },
child: tile, child: ValueListenableBuilder<AvesEntry?>(
), valueListenable: _focusedItemNotifier,
); builder: (context, focusedItem, child) {
}, return AnimatedScale(
); scale: focusedItem == entry ? 1 : .9,
}, curve: Curves.fastOutSlowIn,
tileAnimationDelay: tileAnimationDelay, duration: context.select<DurationsData, Duration>((v) => v.tvImageFocusAnimation),
child: child!, child: child!,
);
},
child: tile,
),
);
},
);
},
tileAnimationDelay: tileAnimationDelay,
child: child!,
),
), ),
); );
}, },
@ -227,6 +237,34 @@ class _CollectionGridContentState extends State<_CollectionGridContent> {
}, },
); );
} }
void _goToViewer(CollectionLens collection, AvesEntry entry) {
final selection = context.read<Selection<AvesEntry>>();
Navigator.maybeOf(context)?.push(
TransparentMaterialPageRoute(
settings: const RouteSettings(name: EntryViewerPage.routeName),
pageBuilder: (context, a, sa) {
final viewerCollection = collection.copyWith(
listenToSource: false,
);
assert(viewerCollection.sortedEntries.map((entry) => entry.id).contains(entry.id));
Widget child = EntryViewerPage(
collection: viewerCollection,
initialEntry: entry,
);
if (selection.isSelecting) {
child = ChangeNotifierProvider<Selection<AvesEntry>>.value(
value: selection,
child: child,
);
}
return child;
},
),
);
}
} }
class _CollectionSectionedContent extends StatefulWidget { class _CollectionSectionedContent extends StatefulWidget {

View file

@ -6,10 +6,9 @@ import 'package:aves/model/source/enums/enums.dart';
import 'package:aves/services/intent_service.dart'; import 'package:aves/services/intent_service.dart';
import 'package:aves/widgets/collection/grid/list_details.dart'; import 'package:aves/widgets/collection/grid/list_details.dart';
import 'package:aves/widgets/collection/grid/list_details_theme.dart'; import 'package:aves/widgets/collection/grid/list_details_theme.dart';
import 'package:aves/widgets/common/behaviour/routes.dart';
import 'package:aves/widgets/common/grid/scaling.dart'; import 'package:aves/widgets/common/grid/scaling.dart';
import 'package:aves/widgets/common/thumbnail/decorated.dart'; import 'package:aves/widgets/common/thumbnail/decorated.dart';
import 'package:aves/widgets/viewer/entry_viewer_page.dart'; import 'package:aves/widgets/common/thumbnail/notifications.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -40,7 +39,7 @@ class InteractiveTile extends StatelessWidget {
if (selection.isSelecting) { if (selection.isSelecting) {
selection.toggleSelection(entry); selection.toggleSelection(entry);
} else { } else {
_goToViewer(context); OpenViewerNotification(entry).dispatch(context);
} }
break; break;
case AppMode.pickSingleMediaExternal: case AppMode.pickSingleMediaExternal:
@ -79,24 +78,6 @@ class InteractiveTile extends StatelessWidget {
), ),
); );
} }
void _goToViewer(BuildContext context) {
Navigator.maybeOf(context)?.push(
TransparentMaterialPageRoute(
settings: const RouteSettings(name: EntryViewerPage.routeName),
pageBuilder: (context, a, sa) {
final viewerCollection = collection.copyWith(
listenToSource: false,
);
assert(viewerCollection.sortedEntries.map((entry) => entry.id).contains(entry.id));
return EntryViewerPage(
collection: viewerCollection,
initialEntry: entry,
);
},
),
);
}
} }
class Tile extends StatelessWidget { class Tile extends StatelessWidget {

View file

@ -22,44 +22,38 @@ class GridItemSelectionOverlay<T> extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final isSelecting = context.select<Selection<T>, bool>((selection) => selection.isSelecting); final isSelecting = context.select<Selection<T>, bool>((selection) => selection.isSelecting);
final child = isSelecting return AnimatedSwitcher(
? Selector<Selection<T>, bool>( duration: duration,
selector: (context, selection) => selection.isSelected([item]), child: isSelecting
builder: (context, isSelected, child) { ? Selector<Selection<T>, bool>(
var child = isSelecting selector: (context, selection) => selection.isSelected([item]),
? OverlayIcon( builder: (context, isSelected, child) {
return AnimatedContainer(
alignment: AlignmentDirectional.topEnd,
padding: padding,
decoration: BoxDecoration(
color: isSelected ? Theme.of(context).colorScheme.secondary.withOpacity(.6) : Colors.transparent,
borderRadius: borderRadius,
),
duration: duration,
child: AnimatedSwitcher(
duration: duration,
switchInCurve: Curves.easeOutBack,
switchOutCurve: Curves.easeOutBack,
transitionBuilder: (child, animation) => ScaleTransition(
scale: animation,
child: child,
),
child: OverlayIcon(
key: ValueKey(isSelected), key: ValueKey(isSelected),
icon: isSelected ? AIcons.selected : AIcons.unselected, icon: isSelected ? AIcons.selected : AIcons.unselected,
margin: EdgeInsets.zero, margin: EdgeInsets.zero,
) ),
: const SizedBox(); ),
child = AnimatedSwitcher( );
duration: duration, },
switchInCurve: Curves.easeOutBack, )
switchOutCurve: Curves.easeOutBack, : const SizedBox(),
transitionBuilder: (child, animation) => ScaleTransition(
scale: animation,
child: child,
),
child: child,
);
child = AnimatedContainer(
alignment: AlignmentDirectional.topEnd,
padding: padding,
decoration: BoxDecoration(
color: isSelected ? Theme.of(context).colorScheme.secondary.withOpacity(.6) : Colors.transparent,
borderRadius: borderRadius,
),
duration: duration,
child: child,
);
return child;
},
)
: const SizedBox();
return AnimatedSwitcher(
duration: duration,
child: child,
); );
} }
} }

View file

@ -30,10 +30,12 @@ class GridTheme extends StatelessWidget {
final fontSize = (iconSize * .7).floorToDouble(); final fontSize = (iconSize * .7).floorToDouble();
iconSize *= mq.textScaleFactor; iconSize *= mq.textScaleFactor;
final highlightBorderWidth = extent * .1; final highlightBorderWidth = extent * .1;
final interactiveDimension = min(iconSize * 2, kMinInteractiveDimension);
return GridThemeData( return GridThemeData(
iconSize: iconSize, iconSize: iconSize,
fontSize: fontSize, fontSize: fontSize,
highlightBorderWidth: highlightBorderWidth, highlightBorderWidth: highlightBorderWidth,
interactiveDimension: interactiveDimension,
showFavourite: settings.showThumbnailFavourite, showFavourite: settings.showThumbnailFavourite,
locationIcon: showLocation ? settings.thumbnailLocationIcon : ThumbnailOverlayLocationIcon.none, locationIcon: showLocation ? settings.thumbnailLocationIcon : ThumbnailOverlayLocationIcon.none,
tagIcon: settings.thumbnailTagIcon, tagIcon: settings.thumbnailTagIcon,
@ -52,7 +54,7 @@ class GridTheme extends StatelessWidget {
typedef GridThemeIconBuilder = List<Widget> Function(BuildContext context, AvesEntry entry); typedef GridThemeIconBuilder = List<Widget> Function(BuildContext context, AvesEntry entry);
class GridThemeData { class GridThemeData {
final double iconSize, fontSize, highlightBorderWidth; final double iconSize, fontSize, highlightBorderWidth, interactiveDimension;
final bool showFavourite, showMotionPhoto, showRating, showRaw, showTrash, showVideoDuration; final bool showFavourite, showMotionPhoto, showRating, showRaw, showTrash, showVideoDuration;
final bool showLocated, showUnlocated, showTagged, showUntagged; final bool showLocated, showUnlocated, showTagged, showUntagged;
late final GridThemeIconBuilder iconBuilder; late final GridThemeIconBuilder iconBuilder;
@ -61,6 +63,7 @@ class GridThemeData {
required this.iconSize, required this.iconSize,
required this.fontSize, required this.fontSize,
required this.highlightBorderWidth, required this.highlightBorderWidth,
required this.interactiveDimension,
required this.showFavourite, required this.showFavourite,
required ThumbnailOverlayLocationIcon locationIcon, required ThumbnailOverlayLocationIcon locationIcon,
required ThumbnailOverlayTagIcon tagIcon, required ThumbnailOverlayTagIcon tagIcon,

View file

@ -0,0 +1,9 @@
import 'package:aves/model/entry.dart';
import 'package:flutter/widgets.dart';
@immutable
class OpenViewerNotification extends Notification {
final AvesEntry entry;
const OpenViewerNotification(this.entry);
}

View file

@ -2,6 +2,9 @@ import 'dart:math';
import 'package:aves/model/entry.dart'; import 'package:aves/model/entry.dart';
import 'package:aves/model/highlight.dart'; import 'package:aves/model/highlight.dart';
import 'package:aves/model/selection.dart';
import 'package:aves/theme/durations.dart';
import 'package:aves/theme/icons.dart';
import 'package:aves/widgets/common/fx/sweeper.dart'; import 'package:aves/widgets/common/fx/sweeper.dart';
import 'package:aves/widgets/common/grid/theme.dart'; import 'package:aves/widgets/common/grid/theme.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -70,3 +73,43 @@ class _ThumbnailHighlightOverlayState extends State<ThumbnailHighlightOverlay> {
); );
} }
} }
class ThumbnailZoomOverlay extends StatelessWidget {
final VoidCallback? onZoom;
const ThumbnailZoomOverlay({
super.key,
this.onZoom,
});
static const alignment = AlignmentDirectional.bottomEnd;
static const duration = Durations.thumbnailOverlayAnimation;
@override
Widget build(BuildContext context) {
final isSelecting = context.select<Selection<AvesEntry>, bool>((selection) => selection.isSelecting);
final interactiveDimension = context.select<GridThemeData, double>((t) => t.interactiveDimension);
return AnimatedSwitcher(
duration: duration,
child: isSelecting
? Align(
alignment: alignment,
child: GestureDetector(
onTap: onZoom,
child: Container(
alignment: alignment,
padding: const EdgeInsets.symmetric(vertical: 1, horizontal: 2),
width: interactiveDimension,
height: interactiveDimension,
child: Icon(
AIcons.showFullscreen,
size: context.select<GridThemeData, double>((t) => t.iconSize),
color: Colors.white70,
),
),
),
)
: const SizedBox(),
);
}
}

View file

@ -1,5 +1,5 @@
import 'package:aves/theme/durations.dart'; import 'package:aves/theme/durations.dart';
import 'package:aves/widgets/common/basic/reselectable_radio_list_tile.dart'; import 'package:aves/widgets/common/basic/list_tiles/reselectable_radio.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart'; import 'package:flutter/scheduler.dart';

View file

@ -10,7 +10,7 @@ import 'package:aves/model/source/collection_lens.dart';
import 'package:aves/model/source/collection_source.dart'; import 'package:aves/model/source/collection_source.dart';
import 'package:aves/theme/icons.dart'; import 'package:aves/theme/icons.dart';
import 'package:aves/utils/constants.dart'; import 'package:aves/utils/constants.dart';
import 'package:aves/widgets/common/basic/color_list_tile.dart'; import 'package:aves/widgets/common/basic/list_tiles/color.dart';
import 'package:aves/widgets/common/extensions/build_context.dart'; import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/common/fx/borders.dart'; import 'package:aves/widgets/common/fx/borders.dart';
import 'package:aves/widgets/dialogs/aves_dialog.dart'; import 'package:aves/widgets/dialogs/aves_dialog.dart';

View file

@ -2,8 +2,8 @@ import 'package:aves/image_providers/app_icon_image_provider.dart';
import 'package:aves/model/settings/settings.dart'; import 'package:aves/model/settings/settings.dart';
import 'package:aves/services/common/services.dart'; import 'package:aves/services/common/services.dart';
import 'package:aves/utils/android_file_utils.dart'; import 'package:aves/utils/android_file_utils.dart';
import 'package:aves/widgets/common/basic/list_tiles/reselectable_radio.dart';
import 'package:aves/widgets/common/basic/query_bar.dart'; import 'package:aves/widgets/common/basic/query_bar.dart';
import 'package:aves/widgets/common/basic/reselectable_radio_list_tile.dart';
import 'package:aves/widgets/common/basic/scaffold.dart'; import 'package:aves/widgets/common/basic/scaffold.dart';
import 'package:aves/widgets/common/extensions/build_context.dart'; import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';

View file

@ -2,8 +2,8 @@ import 'dart:collection';
import 'package:aves/model/settings/settings.dart'; import 'package:aves/model/settings/settings.dart';
import 'package:aves/widgets/aves_app.dart'; import 'package:aves/widgets/aves_app.dart';
import 'package:aves/widgets/common/basic/list_tiles/reselectable_radio.dart';
import 'package:aves/widgets/common/basic/query_bar.dart'; import 'package:aves/widgets/common/basic/query_bar.dart';
import 'package:aves/widgets/common/basic/reselectable_radio_list_tile.dart';
import 'package:aves/widgets/common/basic/scaffold.dart'; import 'package:aves/widgets/common/basic/scaffold.dart';
import 'package:aves/widgets/common/extensions/build_context.dart'; import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/settings/language/locale_tile.dart'; import 'package:aves/widgets/settings/language/locale_tile.dart';

View file

@ -1,9 +1,9 @@
import 'package:aves/model/settings/enums/enums.dart'; import 'package:aves/model/settings/enums/enums.dart';
import 'package:aves/model/settings/enums/subtitle_position.dart'; import 'package:aves/model/settings/enums/subtitle_position.dart';
import 'package:aves/model/settings/settings.dart'; import 'package:aves/model/settings/settings.dart';
import 'package:aves/widgets/common/basic/color_list_tile.dart'; import 'package:aves/widgets/common/basic/list_tiles/color.dart';
import 'package:aves/widgets/common/basic/list_tiles/slider.dart';
import 'package:aves/widgets/common/basic/scaffold.dart'; import 'package:aves/widgets/common/basic/scaffold.dart';
import 'package:aves/widgets/common/basic/slider_list_tile.dart';
import 'package:aves/widgets/common/extensions/build_context.dart'; import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/settings/common/tiles.dart'; import 'package:aves/widgets/settings/common/tiles.dart';
import 'package:aves/widgets/settings/video/subtitle_sample.dart'; import 'package:aves/widgets/settings/video/subtitle_sample.dart';

View file

@ -3,10 +3,8 @@ import 'package:aves/model/source/collection_lens.dart';
import 'package:aves/widgets/common/basic/scaffold.dart'; import 'package:aves/widgets/common/basic/scaffold.dart';
import 'package:aves/widgets/viewer/controller.dart'; import 'package:aves/widgets/viewer/controller.dart';
import 'package:aves/widgets/viewer/entry_viewer_stack.dart'; import 'package:aves/widgets/viewer/entry_viewer_stack.dart';
import 'package:aves/widgets/viewer/multipage/conductor.dart';
import 'package:aves/widgets/viewer/overlay/bottom.dart'; import 'package:aves/widgets/viewer/overlay/bottom.dart';
import 'package:aves/widgets/viewer/video/conductor.dart'; import 'package:aves/widgets/viewer/providers.dart';
import 'package:aves/widgets/viewer/visual/conductor.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -43,16 +41,16 @@ class _EntryViewerPageState extends State<EntryViewerPage> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final collection = widget.collection; final collection = widget.collection;
return AvesScaffold( return AvesScaffold(
body: ViewStateConductorProvider( body: MultiProvider(
child: VideoConductorProvider( providers: [
ViewStateConductorProvider(),
VideoConductorProvider(collection: collection),
MultiPageConductorProvider(),
],
child: EntryViewerStack(
collection: collection, collection: collection,
child: MultiPageConductorProvider( initialEntry: widget.initialEntry,
child: EntryViewerStack( viewerController: _viewerController,
collection: collection,
initialEntry: widget.initialEntry,
viewerController: _viewerController,
),
),
), ),
), ),
backgroundColor: Navigator.canPop(context) backgroundColor: Navigator.canPop(context)
@ -64,63 +62,3 @@ class _EntryViewerPageState extends State<EntryViewerPage> {
); );
} }
} }
class ViewStateConductorProvider extends StatelessWidget {
final Widget? child;
const ViewStateConductorProvider({
super.key,
this.child,
});
@override
Widget build(BuildContext context) {
return ProxyProvider<MediaQueryData, ViewStateConductor>(
create: (context) => ViewStateConductor(),
update: (context, mq, value) {
value!.viewportSize = mq.size;
return value;
},
dispose: (context, value) => value.dispose(),
child: child,
);
}
}
class VideoConductorProvider extends StatelessWidget {
final CollectionLens? collection;
final Widget? child;
const VideoConductorProvider({
super.key,
this.collection,
required this.child,
});
@override
Widget build(BuildContext context) {
return Provider<VideoConductor>(
create: (context) => VideoConductor(collection: collection),
dispose: (context, value) => value.dispose(),
child: child,
);
}
}
class MultiPageConductorProvider extends StatelessWidget {
final Widget? child;
const MultiPageConductorProvider({
super.key,
required this.child,
});
@override
Widget build(BuildContext context) {
return Provider<MultiPageConductor>(
create: (context) => MultiPageConductor(),
dispose: (context, value) => value.dispose(),
child: child,
);
}
}

View file

@ -0,0 +1,41 @@
import 'package:aves/model/source/collection_lens.dart';
import 'package:aves/widgets/viewer/multipage/conductor.dart';
import 'package:aves/widgets/viewer/video/conductor.dart';
import 'package:aves/widgets/viewer/visual/conductor.dart';
import 'package:flutter/widgets.dart';
import 'package:provider/provider.dart';
class ViewStateConductorProvider extends ProxyProvider<MediaQueryData, ViewStateConductor> {
ViewStateConductorProvider({
super.key,
super.child,
}) : super(
create: (context) => ViewStateConductor(),
update: (context, mq, value) {
value!.viewportSize = mq.size;
return value;
},
dispose: (context, value) => value.dispose(),
);
}
class VideoConductorProvider extends Provider<VideoConductor> {
VideoConductorProvider({
super.key,
CollectionLens? collection,
super.child,
}) : super(
create: (context) => VideoConductor(collection: collection),
dispose: (context, value) => value.dispose(),
);
}
class MultiPageConductorProvider extends Provider<MultiPageConductor> {
MultiPageConductorProvider({
super.key,
super.child,
}) : super(
create: (context) => MultiPageConductor(),
dispose: (context, value) => value.dispose(),
);
}

View file

@ -8,10 +8,11 @@ import 'package:aves/widgets/common/basic/scaffold.dart';
import 'package:aves/widgets/common/extensions/build_context.dart'; import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/common/identity/empty.dart'; import 'package:aves/widgets/common/identity/empty.dart';
import 'package:aves/widgets/viewer/controller.dart'; import 'package:aves/widgets/viewer/controller.dart';
import 'package:aves/widgets/viewer/entry_viewer_page.dart';
import 'package:aves/widgets/viewer/entry_viewer_stack.dart'; import 'package:aves/widgets/viewer/entry_viewer_stack.dart';
import 'package:aves/widgets/viewer/providers.dart';
import 'package:aves_magnifier/aves_magnifier.dart'; import 'package:aves_magnifier/aves_magnifier.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class ScreenSaverPage extends StatefulWidget { class ScreenSaverPage extends StatefulWidget {
static const routeName = '/screen_saver'; static const routeName = '/screen_saver';
@ -80,15 +81,16 @@ class _ScreenSaverPageState extends State<ScreenSaverPage> with WidgetsBindingOb
alignment: Alignment.center, alignment: Alignment.center,
); );
} else { } else {
child = ViewStateConductorProvider( child = MultiProvider(
child: VideoConductorProvider( providers: [
child: MultiPageConductorProvider( ViewStateConductorProvider(),
child: EntryViewerStack( VideoConductorProvider(),
collection: collection, MultiPageConductorProvider(),
initialEntry: entries.first, ],
viewerController: _viewerController, child: EntryViewerStack(
), collection: collection,
), initialEntry: entries.first,
viewerController: _viewerController,
), ),
); );
} }

View file

@ -14,8 +14,8 @@ import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/common/identity/empty.dart'; import 'package:aves/widgets/common/identity/empty.dart';
import 'package:aves/widgets/settings/viewer/slideshow.dart'; import 'package:aves/widgets/settings/viewer/slideshow.dart';
import 'package:aves/widgets/viewer/controller.dart'; import 'package:aves/widgets/viewer/controller.dart';
import 'package:aves/widgets/viewer/entry_viewer_page.dart';
import 'package:aves/widgets/viewer/entry_viewer_stack.dart'; import 'package:aves/widgets/viewer/entry_viewer_stack.dart';
import 'package:aves/widgets/viewer/providers.dart';
import 'package:aves_magnifier/aves_magnifier.dart'; import 'package:aves_magnifier/aves_magnifier.dart';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -69,21 +69,22 @@ class _SlideshowPageState extends State<SlideshowPage> {
text: context.l10n.collectionEmptyImages, text: context.l10n.collectionEmptyImages,
alignment: Alignment.center, alignment: Alignment.center,
) )
: ViewStateConductorProvider( : MultiProvider(
child: VideoConductorProvider( providers: [
child: MultiPageConductorProvider( ViewStateConductorProvider(),
child: NotificationListener<SlideshowActionNotification>( VideoConductorProvider(),
onNotification: (notification) { MultiPageConductorProvider(),
_onActionSelected(notification.action); ],
return true; child: NotificationListener<SlideshowActionNotification>(
}, onNotification: (notification) {
child: EntryViewerStack( _onActionSelected(notification.action);
key: ValueKey(_viewerController), return true;
collection: _slideshowCollection, },
initialEntry: initialEntry, child: EntryViewerStack(
viewerController: _viewerController, key: ValueKey(_viewerController),
), collection: _slideshowCollection,
), initialEntry: initialEntry,
viewerController: _viewerController,
), ),
), ),
), ),

View file

@ -8,12 +8,12 @@ import 'package:aves/widgets/common/basic/insets.dart';
import 'package:aves/widgets/common/basic/scaffold.dart'; import 'package:aves/widgets/common/basic/scaffold.dart';
import 'package:aves/widgets/viewer/controller.dart'; import 'package:aves/widgets/viewer/controller.dart';
import 'package:aves/widgets/viewer/entry_horizontal_pager.dart'; import 'package:aves/widgets/viewer/entry_horizontal_pager.dart';
import 'package:aves/widgets/viewer/entry_viewer_page.dart';
import 'package:aves/widgets/viewer/multipage/conductor.dart'; import 'package:aves/widgets/viewer/multipage/conductor.dart';
import 'package:aves/widgets/viewer/notifications.dart'; import 'package:aves/widgets/viewer/notifications.dart';
import 'package:aves/widgets/viewer/overlay/bottom.dart'; import 'package:aves/widgets/viewer/overlay/bottom.dart';
import 'package:aves/widgets/viewer/overlay/video/video.dart'; import 'package:aves/widgets/viewer/overlay/video/video.dart';
import 'package:aves/widgets/viewer/page_entry_builder.dart'; import 'package:aves/widgets/viewer/page_entry_builder.dart';
import 'package:aves/widgets/viewer/providers.dart';
import 'package:aves/widgets/viewer/video/conductor.dart'; import 'package:aves/widgets/viewer/video/conductor.dart';
import 'package:aves/widgets/viewer/video/controller.dart'; import 'package:aves/widgets/viewer/video/controller.dart';
import 'package:aves/widgets/viewer/video_action_delegate.dart'; import 'package:aves/widgets/viewer/video_action_delegate.dart';
@ -37,13 +37,14 @@ class WallpaperPage extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return AvesScaffold( return AvesScaffold(
body: entry != null body: entry != null
? ViewStateConductorProvider( ? MultiProvider(
child: VideoConductorProvider( providers: [
child: MultiPageConductorProvider( ViewStateConductorProvider(),
child: EntryEditor( VideoConductorProvider(),
entry: entry!, MultiPageConductorProvider(),
), ],
), child: EntryEditor(
entry: entry!,
), ),
) )
: const SizedBox(), : const SizedBox(),