diff --git a/lib/widgets/viewer/overlay/minimap.dart b/lib/widgets/viewer/overlay/minimap.dart index 42a5617ab..dad6232ae 100644 --- a/lib/widgets/viewer/overlay/minimap.dart +++ b/lib/widgets/viewer/overlay/minimap.dart @@ -1,75 +1,53 @@ import 'dart:math'; -import 'package:aves/model/entry.dart'; -import 'package:aves/widgets/viewer/video/conductor.dart'; import 'package:aves/widgets/viewer/visual/state.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; class Minimap extends StatelessWidget { - final AvesEntry entry; final ValueNotifier viewStateNotifier; - final Size size; - static const defaultSize = Size(96, 96); + static const Size minimapSize = Size(96, 96); const Minimap({ Key? key, - required this.entry, required this.viewStateNotifier, - this.size = defaultSize, }) : super(key: key); @override Widget build(BuildContext context) { return IgnorePointer( child: ValueListenableBuilder( - valueListenable: viewStateNotifier, - builder: (context, viewState, child) { - final viewportSize = viewState.viewportSize; - if (viewportSize == null) return const SizedBox.shrink(); - return AnimatedBuilder( - animation: entry.imageChangeNotifier, - builder: (context, child) { - Widget _builder(Size displaySize) => CustomPaint( - painter: MinimapPainter( - viewportSize: viewportSize, - entrySize: displaySize, - viewCenterOffset: viewState.position, - viewScale: viewState.scale!, - minimapBorderColor: Colors.white30, - ), - size: size, - ); - - if (entry.isVideo) { - final videoController = context.read().getController(entry); - if (videoController == null) return const SizedBox(); - return ValueListenableBuilder( - valueListenable: videoController.sarNotifier, - builder: (context, sar, child) { - return _builder(entry.videoDisplaySize(sar)); - }, - ); - } - return _builder(entry.displaySize); - }, - ); - }), + valueListenable: viewStateNotifier, + builder: (context, viewState, child) { + final viewportSize = viewState.viewportSize; + final contentSize = viewState.contentSize; + if (viewportSize == null || contentSize == null) return const SizedBox(); + return CustomPaint( + painter: MinimapPainter( + viewportSize: viewportSize, + contentSize: contentSize, + viewCenterOffset: viewState.position, + viewScale: viewState.scale!, + minimapBorderColor: Colors.white30, + ), + size: minimapSize, + ); + }, + ), ); } } class MinimapPainter extends CustomPainter { - final Size entrySize, viewportSize; + final Size contentSize, viewportSize; final Offset viewCenterOffset; final double viewScale; final Color minimapBorderColor, viewportBorderColor; const MinimapPainter({ required this.viewportSize, - required this.entrySize, + required this.contentSize, required this.viewCenterOffset, required this.viewScale, this.minimapBorderColor = Colors.white, @@ -78,30 +56,30 @@ class MinimapPainter extends CustomPainter { @override void paint(Canvas canvas, Size size) { - if (entrySize.width <= 0 || entrySize.height <= 0) return; + if (contentSize.width <= 0 || contentSize.height <= 0) return; - final viewSize = entrySize * viewScale; + final viewSize = contentSize * viewScale; if (viewSize.isEmpty) return; // hide minimap when image is in full view if (viewportSize + const Offset(precisionErrorTolerance, precisionErrorTolerance) >= viewSize) return; final canvasScale = size.longestSide / viewSize.longestSide; - final scaledEntrySize = viewSize * canvasScale; + final scaledContentSize = viewSize * canvasScale; final scaledViewportSize = viewportSize * canvasScale; - final entryRect = Rect.fromCenter( + final contentRect = Rect.fromCenter( center: size.center(Offset.zero), - width: scaledEntrySize.width, - height: scaledEntrySize.height, + width: scaledContentSize.width, + height: scaledContentSize.height, ); final viewportRect = Rect.fromCenter( center: size.center(Offset.zero) - viewCenterOffset * canvasScale, - width: min(scaledEntrySize.width, scaledViewportSize.width), - height: min(scaledEntrySize.height, scaledViewportSize.height), + width: min(scaledContentSize.width, scaledViewportSize.width), + height: min(scaledContentSize.height, scaledViewportSize.height), ); - canvas.translate((entryRect.width - size.width) / 2, (entryRect.height - size.height) / 2); + canvas.translate((contentRect.width - size.width) / 2, (contentRect.height - size.height) / 2); final fill = Paint() ..style = PaintingStyle.fill @@ -114,8 +92,8 @@ class MinimapPainter extends CustomPainter { ..color = viewportBorderColor; canvas.drawRect(viewportRect, fill); - canvas.drawRect(entryRect, fill); - canvas.drawRect(entryRect, minimapStroke); + canvas.drawRect(contentRect, fill); + canvas.drawRect(contentRect, minimapStroke); canvas.drawRect(viewportRect, viewportStroke); } diff --git a/lib/widgets/viewer/overlay/top.dart b/lib/widgets/viewer/overlay/top.dart index dcd2d774a..b1ce4e443 100644 --- a/lib/widgets/viewer/overlay/top.dart +++ b/lib/widgets/viewer/overlay/top.dart @@ -145,7 +145,6 @@ class ViewerTopOverlay extends StatelessWidget { FadeTransition( opacity: scale, child: Minimap( - entry: pageEntry, viewStateNotifier: viewStateNotifier, ), ) diff --git a/lib/widgets/viewer/visual/conductor.dart b/lib/widgets/viewer/visual/conductor.dart index 043bc62cd..c66004bf4 100644 --- a/lib/widgets/viewer/visual/conductor.dart +++ b/lib/widgets/viewer/visual/conductor.dart @@ -29,15 +29,16 @@ class ViewStateConductor { // try to initialize the view state to match magnifier initial state const initialScale = ScaleLevel(ref: ScaleReference.contained); final initialValue = ViewState( - Offset.zero, - ScaleBoundaries( + position: Offset.zero, + scale: ScaleBoundaries( minScale: initialScale, maxScale: initialScale, initialScale: initialScale, viewportSize: _viewportSize, childSize: entry.displaySize, ).initialScale, - _viewportSize, + viewportSize: _viewportSize, + contentSize: entry.displaySize, ); controller = Tuple2(entry.uri, ValueNotifier(initialValue)); } diff --git a/lib/widgets/viewer/visual/entry_page_view.dart b/lib/widgets/viewer/visual/entry_page_view.dart index 20ad5e563..eb35be268 100644 --- a/lib/widgets/viewer/visual/entry_page_view.dart +++ b/lib/widgets/viewer/visual/entry_page_view.dart @@ -305,15 +305,17 @@ class _EntryPageViewState extends State { void _onTap() => const ToggleOverlayNotification().dispatch(context); void _onViewStateChanged(MagnifierState v) { - final current = _viewStateNotifier.value; - final viewState = ViewState(v.position, v.scale, current.viewportSize); - _viewStateNotifier.value = viewState; + _viewStateNotifier.value = _viewStateNotifier.value.copyWith( + position: v.position, + scale: v.scale, + ); } void _onViewScaleBoundariesChanged(ScaleBoundaries v) { - final current = _viewStateNotifier.value; - final viewState = ViewState(current.position, current.scale, v.viewportSize); - _viewStateNotifier.value = viewState; + _viewStateNotifier.value = _viewStateNotifier.value.copyWith( + viewportSize: v.viewportSize, + contentSize: v.childSize, + ); } static ScaleState _vectorScaleStateCycle(ScaleState actual) { diff --git a/lib/widgets/viewer/visual/state.dart b/lib/widgets/viewer/visual/state.dart index 416400db2..a523d7eb5 100644 --- a/lib/widgets/viewer/visual/state.dart +++ b/lib/widgets/viewer/visual/state.dart @@ -5,12 +5,36 @@ import 'package:flutter/widgets.dart'; class ViewState extends Equatable { final Offset position; final double? scale; - final Size? viewportSize; + final Size? viewportSize, contentSize; - static const ViewState zero = ViewState(Offset.zero, 0, null); + static const ViewState zero = ViewState( + position: Offset.zero, + scale: 0, + viewportSize: null, + contentSize: null, + ); @override - List get props => [position, scale, viewportSize]; + List get props => [position, scale, viewportSize, contentSize]; - const ViewState(this.position, this.scale, this.viewportSize); + const ViewState({ + required this.position, + required this.scale, + required this.viewportSize, + required this.contentSize, + }); + + ViewState copyWith({ + Offset? position, + double? scale, + Size? viewportSize, + Size? contentSize, + }) { + return ViewState( + position: position ?? this.position, + scale: scale ?? this.scale, + viewportSize: viewportSize ?? this.viewportSize, + contentSize: contentSize ?? this.contentSize, + ); + } }