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
+2
View File
@@ -2204,6 +2204,8 @@
"theme": "Theme", "theme": "Theme",
"theme_selection": "Theme selection", "theme_selection": "Theme selection",
"theme_selection_description": "Automatically set the theme to light or dark based on your browser's system preference", "theme_selection_description": "Automatically set the theme to light or dark based on your browser's system preference",
"theme_setting_asset_list_smooth_scrubbing_subtitle": "Scroll continuously when dragging the scrollbar instead of snapping to months",
"theme_setting_asset_list_smooth_scrubbing_title": "Smooth timeline scrubbing",
"theme_setting_asset_list_storage_indicator_title": "Show storage indicator on asset tiles", "theme_setting_asset_list_storage_indicator_title": "Show storage indicator on asset tiles",
"theme_setting_asset_list_tiles_per_row_title": "Number of assets per row ({count})", "theme_setting_asset_list_tiles_per_row_title": "Number of assets per row ({count})",
"theme_setting_colorful_interface_subtitle": "Apply primary color to background surfaces.", "theme_setting_colorful_interface_subtitle": "Apply primary color to background surfaces.",
@@ -75,6 +75,7 @@ abstract class AppConfig with _$AppConfig {
.timelineTilesPerRow => timeline.tilesPerRow, .timelineTilesPerRow => timeline.tilesPerRow,
.timelineGroupAssetsBy => timeline.groupAssetsBy, .timelineGroupAssetsBy => timeline.groupAssetsBy,
.timelineStorageIndicator => timeline.storageIndicator, .timelineStorageIndicator => timeline.storageIndicator,
.timelineSmoothScrubbing => timeline.smoothScrubbing,
.mapShowFavoriteOnly => map.favoritesOnly, .mapShowFavoriteOnly => map.favoritesOnly,
.mapRelativeDate => map.relativeDays, .mapRelativeDate => map.relativeDays,
.mapCustomFrom => map.customFrom, .mapCustomFrom => map.customFrom,
@@ -131,6 +132,7 @@ abstract class AppConfig with _$AppConfig {
.timelineTilesPerRow => copyWith(timeline: timeline.copyWith(tilesPerRow: value as int)), .timelineTilesPerRow => copyWith(timeline: timeline.copyWith(tilesPerRow: value as int)),
.timelineGroupAssetsBy => copyWith(timeline: timeline.copyWith(groupAssetsBy: value as GroupAssetsBy)), .timelineGroupAssetsBy => copyWith(timeline: timeline.copyWith(groupAssetsBy: value as GroupAssetsBy)),
.timelineStorageIndicator => copyWith(timeline: timeline.copyWith(storageIndicator: value as bool)), .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)), .mapShowFavoriteOnly => copyWith(map: map.copyWith(favoritesOnly: value as bool)),
.mapRelativeDate => copyWith(map: map.copyWith(relativeDays: value as int)), .mapRelativeDate => copyWith(map: map.copyWith(relativeDays: value as int)),
.mapCustomFrom => copyWith(map: map.copyWith(customFrom: .fromNullable(value as DateTime?))), .mapCustomFrom => copyWith(map: map.copyWith(customFrom: .fromNullable(value as DateTime?))),
@@ -10,5 +10,6 @@ abstract class TimelineConfig with _$TimelineConfig {
@Default(4) int tilesPerRow, @Default(4) int tilesPerRow,
@Default(GroupAssetsBy.day) GroupAssetsBy groupAssetsBy, @Default(GroupAssetsBy.day) GroupAssetsBy groupAssetsBy,
@Default(true) bool storageIndicator, @Default(true) bool storageIndicator,
@Default(false) bool smoothScrubbing,
}) = _TimelineConfig; }) = _TimelineConfig;
} }
@@ -48,6 +48,7 @@ enum SettingsKey<T> {
timelineTilesPerRow<int>(), timelineTilesPerRow<int>(),
timelineGroupAssetsBy<GroupAssetsBy>(codec: EnumCodec(GroupAssetsBy.values)), timelineGroupAssetsBy<GroupAssetsBy>(codec: EnumCodec(GroupAssetsBy.values)),
timelineStorageIndicator<bool>(), timelineStorageIndicator<bool>(),
timelineSmoothScrubbing<bool>(),
// Log // Log
logLevel<LogLevel>(codec: EnumCodec(LogLevel.values)), logLevel<LogLevel>(codec: EnumCodec(LogLevel.values)),
@@ -328,6 +328,8 @@ class _SliverTimelineState extends ConsumerState<_SliverTimeline> with WidgetsBi
final isMultiSelectStatusVisible = !isSelectionMode && isMultiSelectEnabled; final isMultiSelectStatusVisible = !isSelectionMode && isMultiSelectEnabled;
final isBottomWidgetVisible = final isBottomWidgetVisible =
widget.bottomSheet != null && (isMultiSelectStatusVisible || widget.persistentBottomBar); widget.bottomSheet != null && (isMultiSelectStatusVisible || widget.persistentBottomBar);
final smoothScrubbing = ref.watch(appConfigProvider.select((config) => config.timeline.smoothScrubbing));
final snapToMonth = widget.snapToMonth && !smoothScrubbing;
return PopScope( return PopScope(
canPop: !isMultiSelectEnabled, canPop: !isMultiSelectEnabled,
@@ -409,7 +411,7 @@ class _SliverTimelineState extends ConsumerState<_SliverTimeline> with WidgetsBi
final Widget timeline; final Widget timeline;
if (widget.withScrubber) { if (widget.withScrubber) {
timeline = Scrubber( timeline = Scrubber(
snapToMonth: widget.snapToMonth, snapToMonth: snapToMonth,
layoutSegments: segments, layoutSegments: segments,
timelineHeight: maxHeight, timelineHeight: maxHeight,
topPadding: topPadding, topPadding: topPadding,
@@ -16,6 +16,7 @@ class AssetListSettings extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final storageIndicator = useValueNotifier(ref.watch(appConfigProvider.select((s) => s.timeline.storageIndicator))); final storageIndicator = useValueNotifier(ref.watch(appConfigProvider.select((s) => s.timeline.storageIndicator)));
final smoothScrubbing = useValueNotifier(ref.watch(appConfigProvider.select((s) => s.timeline.smoothScrubbing)));
final assetListSetting = [ final assetListSetting = [
SettingsSwitchListTile( SettingsSwitchListTile(
@@ -27,6 +28,16 @@ class AssetListSettings extends HookConsumerWidget {
ref.invalidate(settingsProvider); 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 LayoutSettings(),
const GroupSettings(), const GroupSettings(),
]; ];