mirror of
https://github.com/immich-app/immich.git
synced 2026-02-28 01:29:04 +03:00
fix: bring back timeline args auto-scoping (#26219)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
This commit is contained in:
@@ -29,7 +29,38 @@ import 'package:immich_mobile/widgets/common/immich_sliver_app_bar.dart';
|
|||||||
import 'package:immich_mobile/widgets/common/mesmerizing_sliver_app_bar.dart';
|
import 'package:immich_mobile/widgets/common/mesmerizing_sliver_app_bar.dart';
|
||||||
import 'package:immich_mobile/widgets/common/selection_sliver_app_bar.dart';
|
import 'package:immich_mobile/widgets/common/selection_sliver_app_bar.dart';
|
||||||
|
|
||||||
class Timeline extends ConsumerWidget {
|
class _TimelineRestorationState extends ChangeNotifier {
|
||||||
|
int? _restoreAssetIndex;
|
||||||
|
bool _shouldRestoreAssetPosition = false;
|
||||||
|
|
||||||
|
int? get restoreAssetIndex => _restoreAssetIndex;
|
||||||
|
bool get shouldRestoreAssetPosition => _shouldRestoreAssetPosition;
|
||||||
|
|
||||||
|
void setRestoreAssetIndex(int? index) {
|
||||||
|
_restoreAssetIndex = index;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setShouldRestoreAssetPosition(bool should) {
|
||||||
|
_shouldRestoreAssetPosition = should;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearRestoreAssetIndex() {
|
||||||
|
_restoreAssetIndex = null;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TimelineRestorationProvider extends InheritedNotifier<_TimelineRestorationState> {
|
||||||
|
const _TimelineRestorationProvider({required super.notifier, required super.child});
|
||||||
|
|
||||||
|
static _TimelineRestorationState of(BuildContext context) {
|
||||||
|
return context.dependOnInheritedWidgetOfExactType<_TimelineRestorationProvider>()!.notifier!;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Timeline extends StatefulWidget {
|
||||||
const Timeline({
|
const Timeline({
|
||||||
super.key,
|
super.key,
|
||||||
this.topSliverWidget,
|
this.topSliverWidget,
|
||||||
@@ -58,36 +89,66 @@ class Timeline extends ConsumerWidget {
|
|||||||
final bool readOnly;
|
final bool readOnly;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
State<Timeline> createState() => _TimelineState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TimelineState extends State<Timeline> {
|
||||||
|
double? _lastWidth;
|
||||||
|
late final _TimelineRestorationState _restorationState;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_restorationState = _TimelineRestorationState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_restorationState.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
resizeToAvoidBottomInset: false,
|
resizeToAvoidBottomInset: false,
|
||||||
floatingActionButton: const DownloadStatusFloatingButton(),
|
floatingActionButton: const DownloadStatusFloatingButton(),
|
||||||
body: LayoutBuilder(
|
body: LayoutBuilder(
|
||||||
builder: (_, constraints) => ProviderScope(
|
builder: (_, constraints) {
|
||||||
|
if (_lastWidth != null && _lastWidth != constraints.maxWidth) {
|
||||||
|
_restorationState.setShouldRestoreAssetPosition(true);
|
||||||
|
}
|
||||||
|
_lastWidth = constraints.maxWidth;
|
||||||
|
return _TimelineRestorationProvider(
|
||||||
|
notifier: _restorationState,
|
||||||
|
child: ProviderScope(
|
||||||
|
key: ValueKey(_lastWidth),
|
||||||
overrides: [
|
overrides: [
|
||||||
timelineArgsProvider.overrideWithValue(
|
timelineArgsProvider.overrideWith(
|
||||||
TimelineArgs(
|
(ref) => TimelineArgs(
|
||||||
maxWidth: constraints.maxWidth,
|
maxWidth: constraints.maxWidth,
|
||||||
maxHeight: constraints.maxHeight,
|
maxHeight: constraints.maxHeight,
|
||||||
columnCount: ref.watch(settingsProvider.select((s) => s.get(Setting.tilesPerRow))),
|
columnCount: ref.watch(settingsProvider.select((s) => s.get(Setting.tilesPerRow))),
|
||||||
showStorageIndicator: showStorageIndicator,
|
showStorageIndicator: widget.showStorageIndicator,
|
||||||
withStack: withStack,
|
withStack: widget.withStack,
|
||||||
groupBy: groupBy,
|
groupBy: widget.groupBy,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (readOnly) readonlyModeProvider.overrideWith(() => _AlwaysReadOnlyNotifier()),
|
if (widget.readOnly) readonlyModeProvider.overrideWith(() => _AlwaysReadOnlyNotifier()),
|
||||||
],
|
],
|
||||||
child: _SliverTimeline(
|
child: _SliverTimeline(
|
||||||
key: const ValueKey('_sliver_timeline'),
|
key: const ValueKey('_sliver_timeline'),
|
||||||
topSliverWidget: topSliverWidget,
|
topSliverWidget: widget.topSliverWidget,
|
||||||
topSliverWidgetHeight: topSliverWidgetHeight,
|
topSliverWidgetHeight: widget.topSliverWidgetHeight,
|
||||||
appBar: appBar,
|
appBar: widget.appBar,
|
||||||
bottomSheet: bottomSheet,
|
bottomSheet: widget.bottomSheet,
|
||||||
withScrubber: withScrubber,
|
withScrubber: widget.withScrubber,
|
||||||
snapToMonth: snapToMonth,
|
snapToMonth: widget.snapToMonth,
|
||||||
initialScrollOffset: initialScrollOffset,
|
initialScrollOffset: widget.initialScrollOffset,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -141,7 +202,6 @@ class _SliverTimelineState extends ConsumerState<_SliverTimeline> {
|
|||||||
int _perRow = 4;
|
int _perRow = 4;
|
||||||
double _scaleFactor = 3.0;
|
double _scaleFactor = 3.0;
|
||||||
double _baseScaleFactor = 3.0;
|
double _baseScaleFactor = 3.0;
|
||||||
int? _restoreAssetIndex;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@@ -182,13 +242,16 @@ class _SliverTimelineState extends ConsumerState<_SliverTimeline> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _restoreAssetPosition(_) {
|
void _restoreAssetPosition(_) {
|
||||||
if (_restoreAssetIndex == null) return;
|
final restorationState = _TimelineRestorationProvider.of(context);
|
||||||
|
if (!restorationState.shouldRestoreAssetPosition || restorationState.restoreAssetIndex == null) return;
|
||||||
|
|
||||||
final asyncSegments = ref.read(timelineSegmentProvider);
|
final asyncSegments = ref.read(timelineSegmentProvider);
|
||||||
asyncSegments.whenData((segments) {
|
asyncSegments.whenData((segments) {
|
||||||
final targetSegment = segments.lastWhereOrNull((segment) => segment.firstAssetIndex <= _restoreAssetIndex!);
|
final targetSegment = segments.lastWhereOrNull(
|
||||||
|
(segment) => segment.firstAssetIndex <= restorationState.restoreAssetIndex!,
|
||||||
|
);
|
||||||
if (targetSegment != null) {
|
if (targetSegment != null) {
|
||||||
final assetIndexInSegment = _restoreAssetIndex! - targetSegment.firstAssetIndex;
|
final assetIndexInSegment = restorationState.restoreAssetIndex! - targetSegment.firstAssetIndex;
|
||||||
final newColumnCount = ref.read(timelineArgsProvider).columnCount;
|
final newColumnCount = ref.read(timelineArgsProvider).columnCount;
|
||||||
final rowIndexInSegment = (assetIndexInSegment / newColumnCount).floor();
|
final rowIndexInSegment = (assetIndexInSegment / newColumnCount).floor();
|
||||||
final targetRowIndex = targetSegment.firstIndex + 1 + rowIndexInSegment;
|
final targetRowIndex = targetSegment.firstIndex + 1 + rowIndexInSegment;
|
||||||
@@ -200,7 +263,7 @@ class _SliverTimelineState extends ConsumerState<_SliverTimeline> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
_restoreAssetIndex = null;
|
restorationState.clearRestoreAssetIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
int? _getCurrentAssetIndex(List<Segment> segments) {
|
int? _getCurrentAssetIndex(List<Segment> segments) {
|
||||||
@@ -411,7 +474,7 @@ class _SliverTimelineState extends ConsumerState<_SliverTimeline> {
|
|||||||
onNotification: (notification) {
|
onNotification: (notification) {
|
||||||
final currentIndex = _getCurrentAssetIndex(segments);
|
final currentIndex = _getCurrentAssetIndex(segments);
|
||||||
if (currentIndex != null && mounted) {
|
if (currentIndex != null && mounted) {
|
||||||
_restoreAssetIndex = currentIndex;
|
_TimelineRestorationProvider.of(context).setRestoreAssetIndex(currentIndex);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
@@ -430,12 +493,14 @@ class _SliverTimelineState extends ConsumerState<_SliverTimeline> {
|
|||||||
final targetAssetIndex = _getCurrentAssetIndex(segments);
|
final targetAssetIndex = _getCurrentAssetIndex(segments);
|
||||||
|
|
||||||
if (newPerRow != _perRow) {
|
if (newPerRow != _perRow) {
|
||||||
|
final restorationState = _TimelineRestorationProvider.of(context);
|
||||||
setState(() {
|
setState(() {
|
||||||
_scaleFactor = newScaleFactor;
|
_scaleFactor = newScaleFactor;
|
||||||
_perRow = newPerRow;
|
_perRow = newPerRow;
|
||||||
_restoreAssetIndex = targetAssetIndex;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
restorationState.setRestoreAssetIndex(targetAssetIndex);
|
||||||
|
restorationState.setShouldRestoreAssetPosition(true);
|
||||||
ref.read(settingsProvider.notifier).set(Setting.tilesPerRow, _perRow);
|
ref.read(settingsProvider.notifier).set(Setting.tilesPerRow, _perRow);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user