feat: option for mobile smooth timeline scrubbing (#32552)

* feat(mobile): add smooth timeline scrubbing setting

* refactor: read smooth scrubbing setting where the scrubber is built

(cherry picked from commit 222d9276d31e890d3d9beb6dae5d96a6f6ab52f0)
This commit is contained in:
Tiago Deane
2026-10-22 05:21:00 +03:00
committed by Codex
parent 2d236024bc
commit 6aaebd167d
6 changed files with 20 additions and 1 deletions
@@ -75,6 +75,7 @@ abstract class AppConfig with _$AppConfig {
.timelineTilesPerRow => timeline.tilesPerRow,
.timelineGroupAssetsBy => timeline.groupAssetsBy,
.timelineStorageIndicator => timeline.storageIndicator,
.timelineSmoothScrubbing => timeline.smoothScrubbing,
.mapShowFavoriteOnly => map.favoritesOnly,
.mapRelativeDate => map.relativeDays,
.mapCustomFrom => map.customFrom,
@@ -131,6 +132,7 @@ abstract class AppConfig with _$AppConfig {
.timelineTilesPerRow => copyWith(timeline: timeline.copyWith(tilesPerRow: value as int)),
.timelineGroupAssetsBy => copyWith(timeline: timeline.copyWith(groupAssetsBy: value as GroupAssetsBy)),
.timelineStorageIndicator => copyWith(timeline: timeline.copyWith(storageIndicator: value as bool)),
.timelineSmoothScrubbing => copyWith(timeline: timeline.copyWith(smoothScrubbing: value as bool)),
.mapShowFavoriteOnly => copyWith(map: map.copyWith(favoritesOnly: value as bool)),
.mapRelativeDate => copyWith(map: map.copyWith(relativeDays: value as int)),
.mapCustomFrom => copyWith(map: map.copyWith(customFrom: .fromNullable(value as DateTime?))),
@@ -10,5 +10,6 @@ abstract class TimelineConfig with _$TimelineConfig {
@Default(4) int tilesPerRow,
@Default(GroupAssetsBy.day) GroupAssetsBy groupAssetsBy,
@Default(true) bool storageIndicator,
@Default(false) bool smoothScrubbing,
}) = _TimelineConfig;
}
@@ -48,6 +48,7 @@ enum SettingsKey<T> {
timelineTilesPerRow<int>(),
timelineGroupAssetsBy<GroupAssetsBy>(codec: EnumCodec(GroupAssetsBy.values)),
timelineStorageIndicator<bool>(),
timelineSmoothScrubbing<bool>(),
// Log
logLevel<LogLevel>(codec: EnumCodec(LogLevel.values)),
@@ -328,6 +328,8 @@ class _SliverTimelineState extends ConsumerState<_SliverTimeline> with WidgetsBi
final isMultiSelectStatusVisible = !isSelectionMode && isMultiSelectEnabled;
final isBottomWidgetVisible =
widget.bottomSheet != null && (isMultiSelectStatusVisible || widget.persistentBottomBar);
final smoothScrubbing = ref.watch(appConfigProvider.select((config) => config.timeline.smoothScrubbing));
final snapToMonth = widget.snapToMonth && !smoothScrubbing;
return PopScope(
canPop: !isMultiSelectEnabled,
@@ -409,7 +411,7 @@ class _SliverTimelineState extends ConsumerState<_SliverTimeline> with WidgetsBi
final Widget timeline;
if (widget.withScrubber) {
timeline = Scrubber(
snapToMonth: widget.snapToMonth,
snapToMonth: snapToMonth,
layoutSegments: segments,
timelineHeight: maxHeight,
topPadding: topPadding,
@@ -16,6 +16,7 @@ class AssetListSettings extends HookConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final storageIndicator = useValueNotifier(ref.watch(appConfigProvider.select((s) => s.timeline.storageIndicator)));
final smoothScrubbing = useValueNotifier(ref.watch(appConfigProvider.select((s) => s.timeline.smoothScrubbing)));
final assetListSetting = [
SettingsSwitchListTile(
@@ -27,6 +28,16 @@ class AssetListSettings extends HookConsumerWidget {
ref.invalidate(settingsProvider);
},
),
SettingsSwitchListTile(
valueNotifier: smoothScrubbing,
title: context.t.theme_setting_asset_list_smooth_scrubbing_title,
subtitle: context.t.theme_setting_asset_list_smooth_scrubbing_subtitle,
onChanged: (value) {
unawaited(ref.read(settingsProvider).write(.timelineSmoothScrubbing, value));
ref.invalidate(appSettingsServiceProvider);
ref.invalidate(settingsProvider);
},
),
const LayoutSettings(),
const GroupSettings(),
];