diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index 15451886..0ea69f2b 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -3106,6 +3106,42 @@ abstract class AppLocalizations { /// **'Show when searching for existing tracks'** String get libraryShowDuplicateIndicatorSubtitle; + /// Setting for automatic library scanning + /// + /// In en, this message translates to: + /// **'Auto Scan'** + String get libraryAutoScan; + + /// Subtitle for auto scan setting + /// + /// In en, this message translates to: + /// **'Automatically scan your library for new files'** + String get libraryAutoScanSubtitle; + + /// Auto scan disabled + /// + /// In en, this message translates to: + /// **'Off'** + String get libraryAutoScanOff; + + /// Auto scan when app opens + /// + /// In en, this message translates to: + /// **'Every app open'** + String get libraryAutoScanOnOpen; + + /// Auto scan once per day + /// + /// In en, this message translates to: + /// **'Daily'** + String get libraryAutoScanDaily; + + /// Auto scan once per week + /// + /// In en, this message translates to: + /// **'Weekly'** + String get libraryAutoScanWeekly; + /// Section header for library actions /// /// In en, this message translates to: diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index f0137de1..7ad45e21 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -1719,6 +1719,25 @@ class AppLocalizationsDe extends AppLocalizations { String get libraryShowDuplicateIndicatorSubtitle => 'Bei der Suche nach vorhandenen Titeln anzeigen'; + @override + String get libraryAutoScan => 'Auto Scan'; + + @override + String get libraryAutoScanSubtitle => + 'Automatically scan your library for new files'; + + @override + String get libraryAutoScanOff => 'Off'; + + @override + String get libraryAutoScanOnOpen => 'Every app open'; + + @override + String get libraryAutoScanDaily => 'Daily'; + + @override + String get libraryAutoScanWeekly => 'Weekly'; + @override String get libraryActions => 'Aktionen'; diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 041c5bd1..13208d5b 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -1695,6 +1695,25 @@ class AppLocalizationsEn extends AppLocalizations { String get libraryShowDuplicateIndicatorSubtitle => 'Show when searching for existing tracks'; + @override + String get libraryAutoScan => 'Auto Scan'; + + @override + String get libraryAutoScanSubtitle => + 'Automatically scan your library for new files'; + + @override + String get libraryAutoScanOff => 'Off'; + + @override + String get libraryAutoScanOnOpen => 'Every app open'; + + @override + String get libraryAutoScanDaily => 'Daily'; + + @override + String get libraryAutoScanWeekly => 'Weekly'; + @override String get libraryActions => 'Actions'; diff --git a/lib/l10n/app_localizations_es.dart b/lib/l10n/app_localizations_es.dart index 99849885..113c08f1 100644 --- a/lib/l10n/app_localizations_es.dart +++ b/lib/l10n/app_localizations_es.dart @@ -1695,6 +1695,25 @@ class AppLocalizationsEs extends AppLocalizations { String get libraryShowDuplicateIndicatorSubtitle => 'Show when searching for existing tracks'; + @override + String get libraryAutoScan => 'Auto Scan'; + + @override + String get libraryAutoScanSubtitle => + 'Automatically scan your library for new files'; + + @override + String get libraryAutoScanOff => 'Off'; + + @override + String get libraryAutoScanOnOpen => 'Every app open'; + + @override + String get libraryAutoScanDaily => 'Daily'; + + @override + String get libraryAutoScanWeekly => 'Weekly'; + @override String get libraryActions => 'Actions'; diff --git a/lib/l10n/app_localizations_fr.dart b/lib/l10n/app_localizations_fr.dart index cec6eae9..6521f755 100644 --- a/lib/l10n/app_localizations_fr.dart +++ b/lib/l10n/app_localizations_fr.dart @@ -1697,6 +1697,25 @@ class AppLocalizationsFr extends AppLocalizations { String get libraryShowDuplicateIndicatorSubtitle => 'Show when searching for existing tracks'; + @override + String get libraryAutoScan => 'Auto Scan'; + + @override + String get libraryAutoScanSubtitle => + 'Automatically scan your library for new files'; + + @override + String get libraryAutoScanOff => 'Off'; + + @override + String get libraryAutoScanOnOpen => 'Every app open'; + + @override + String get libraryAutoScanDaily => 'Daily'; + + @override + String get libraryAutoScanWeekly => 'Weekly'; + @override String get libraryActions => 'Actions'; diff --git a/lib/l10n/app_localizations_hi.dart b/lib/l10n/app_localizations_hi.dart index 9a9ad518..04227142 100644 --- a/lib/l10n/app_localizations_hi.dart +++ b/lib/l10n/app_localizations_hi.dart @@ -1695,6 +1695,25 @@ class AppLocalizationsHi extends AppLocalizations { String get libraryShowDuplicateIndicatorSubtitle => 'Show when searching for existing tracks'; + @override + String get libraryAutoScan => 'Auto Scan'; + + @override + String get libraryAutoScanSubtitle => + 'Automatically scan your library for new files'; + + @override + String get libraryAutoScanOff => 'Off'; + + @override + String get libraryAutoScanOnOpen => 'Every app open'; + + @override + String get libraryAutoScanDaily => 'Daily'; + + @override + String get libraryAutoScanWeekly => 'Weekly'; + @override String get libraryActions => 'Actions'; diff --git a/lib/l10n/app_localizations_id.dart b/lib/l10n/app_localizations_id.dart index 902d49cd..b23768e3 100644 --- a/lib/l10n/app_localizations_id.dart +++ b/lib/l10n/app_localizations_id.dart @@ -1702,6 +1702,25 @@ class AppLocalizationsId extends AppLocalizations { String get libraryShowDuplicateIndicatorSubtitle => 'Show when searching for existing tracks'; + @override + String get libraryAutoScan => 'Auto Scan'; + + @override + String get libraryAutoScanSubtitle => + 'Automatically scan your library for new files'; + + @override + String get libraryAutoScanOff => 'Off'; + + @override + String get libraryAutoScanOnOpen => 'Every app open'; + + @override + String get libraryAutoScanDaily => 'Daily'; + + @override + String get libraryAutoScanWeekly => 'Weekly'; + @override String get libraryActions => 'Actions'; diff --git a/lib/l10n/app_localizations_ja.dart b/lib/l10n/app_localizations_ja.dart index 31270670..caf7d16e 100644 --- a/lib/l10n/app_localizations_ja.dart +++ b/lib/l10n/app_localizations_ja.dart @@ -1682,6 +1682,25 @@ class AppLocalizationsJa extends AppLocalizations { String get libraryShowDuplicateIndicatorSubtitle => 'Show when searching for existing tracks'; + @override + String get libraryAutoScan => 'Auto Scan'; + + @override + String get libraryAutoScanSubtitle => + 'Automatically scan your library for new files'; + + @override + String get libraryAutoScanOff => 'Off'; + + @override + String get libraryAutoScanOnOpen => 'Every app open'; + + @override + String get libraryAutoScanDaily => 'Daily'; + + @override + String get libraryAutoScanWeekly => 'Weekly'; + @override String get libraryActions => 'アクション'; diff --git a/lib/l10n/app_localizations_ko.dart b/lib/l10n/app_localizations_ko.dart index 76f1b737..1cac05e7 100644 --- a/lib/l10n/app_localizations_ko.dart +++ b/lib/l10n/app_localizations_ko.dart @@ -1675,6 +1675,25 @@ class AppLocalizationsKo extends AppLocalizations { String get libraryShowDuplicateIndicatorSubtitle => 'Show when searching for existing tracks'; + @override + String get libraryAutoScan => 'Auto Scan'; + + @override + String get libraryAutoScanSubtitle => + 'Automatically scan your library for new files'; + + @override + String get libraryAutoScanOff => 'Off'; + + @override + String get libraryAutoScanOnOpen => 'Every app open'; + + @override + String get libraryAutoScanDaily => 'Daily'; + + @override + String get libraryAutoScanWeekly => 'Weekly'; + @override String get libraryActions => 'Actions'; diff --git a/lib/l10n/app_localizations_nl.dart b/lib/l10n/app_localizations_nl.dart index d509e1e7..ac2c8b57 100644 --- a/lib/l10n/app_localizations_nl.dart +++ b/lib/l10n/app_localizations_nl.dart @@ -1695,6 +1695,25 @@ class AppLocalizationsNl extends AppLocalizations { String get libraryShowDuplicateIndicatorSubtitle => 'Show when searching for existing tracks'; + @override + String get libraryAutoScan => 'Auto Scan'; + + @override + String get libraryAutoScanSubtitle => + 'Automatically scan your library for new files'; + + @override + String get libraryAutoScanOff => 'Off'; + + @override + String get libraryAutoScanOnOpen => 'Every app open'; + + @override + String get libraryAutoScanDaily => 'Daily'; + + @override + String get libraryAutoScanWeekly => 'Weekly'; + @override String get libraryActions => 'Actions'; diff --git a/lib/l10n/app_localizations_pt.dart b/lib/l10n/app_localizations_pt.dart index ef87eca7..3c5c8896 100644 --- a/lib/l10n/app_localizations_pt.dart +++ b/lib/l10n/app_localizations_pt.dart @@ -1695,6 +1695,25 @@ class AppLocalizationsPt extends AppLocalizations { String get libraryShowDuplicateIndicatorSubtitle => 'Show when searching for existing tracks'; + @override + String get libraryAutoScan => 'Auto Scan'; + + @override + String get libraryAutoScanSubtitle => + 'Automatically scan your library for new files'; + + @override + String get libraryAutoScanOff => 'Off'; + + @override + String get libraryAutoScanOnOpen => 'Every app open'; + + @override + String get libraryAutoScanDaily => 'Daily'; + + @override + String get libraryAutoScanWeekly => 'Weekly'; + @override String get libraryActions => 'Actions'; diff --git a/lib/l10n/app_localizations_ru.dart b/lib/l10n/app_localizations_ru.dart index 8bbb8a74..31a1a1dc 100644 --- a/lib/l10n/app_localizations_ru.dart +++ b/lib/l10n/app_localizations_ru.dart @@ -1731,6 +1731,25 @@ class AppLocalizationsRu extends AppLocalizations { String get libraryShowDuplicateIndicatorSubtitle => 'Показать при поиске существующих треков'; + @override + String get libraryAutoScan => 'Auto Scan'; + + @override + String get libraryAutoScanSubtitle => + 'Automatically scan your library for new files'; + + @override + String get libraryAutoScanOff => 'Off'; + + @override + String get libraryAutoScanOnOpen => 'Every app open'; + + @override + String get libraryAutoScanDaily => 'Daily'; + + @override + String get libraryAutoScanWeekly => 'Weekly'; + @override String get libraryActions => 'Действия'; diff --git a/lib/l10n/app_localizations_tr.dart b/lib/l10n/app_localizations_tr.dart index bbf6ef14..518bcf77 100644 --- a/lib/l10n/app_localizations_tr.dart +++ b/lib/l10n/app_localizations_tr.dart @@ -1707,6 +1707,25 @@ class AppLocalizationsTr extends AppLocalizations { String get libraryShowDuplicateIndicatorSubtitle => 'Show when searching for existing tracks'; + @override + String get libraryAutoScan => 'Auto Scan'; + + @override + String get libraryAutoScanSubtitle => + 'Automatically scan your library for new files'; + + @override + String get libraryAutoScanOff => 'Off'; + + @override + String get libraryAutoScanOnOpen => 'Every app open'; + + @override + String get libraryAutoScanDaily => 'Daily'; + + @override + String get libraryAutoScanWeekly => 'Weekly'; + @override String get libraryActions => 'Actions'; diff --git a/lib/l10n/app_localizations_zh.dart b/lib/l10n/app_localizations_zh.dart index 465f196c..d36cf154 100644 --- a/lib/l10n/app_localizations_zh.dart +++ b/lib/l10n/app_localizations_zh.dart @@ -1695,6 +1695,25 @@ class AppLocalizationsZh extends AppLocalizations { String get libraryShowDuplicateIndicatorSubtitle => 'Show when searching for existing tracks'; + @override + String get libraryAutoScan => 'Auto Scan'; + + @override + String get libraryAutoScanSubtitle => + 'Automatically scan your library for new files'; + + @override + String get libraryAutoScanOff => 'Off'; + + @override + String get libraryAutoScanOnOpen => 'Every app open'; + + @override + String get libraryAutoScanDaily => 'Daily'; + + @override + String get libraryAutoScanWeekly => 'Weekly'; + @override String get libraryActions => 'Actions'; diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 7f4e1acb..7055840d 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -2242,6 +2242,30 @@ "@libraryShowDuplicateIndicatorSubtitle": { "description": "Subtitle for duplicate indicator toggle" }, + "libraryAutoScan": "Auto Scan", + "@libraryAutoScan": { + "description": "Setting for automatic library scanning" + }, + "libraryAutoScanSubtitle": "Automatically scan your library for new files", + "@libraryAutoScanSubtitle": { + "description": "Subtitle for auto scan setting" + }, + "libraryAutoScanOff": "Off", + "@libraryAutoScanOff": { + "description": "Auto scan disabled" + }, + "libraryAutoScanOnOpen": "Every app open", + "@libraryAutoScanOnOpen": { + "description": "Auto scan when app opens" + }, + "libraryAutoScanDaily": "Daily", + "@libraryAutoScanDaily": { + "description": "Auto scan once per day" + }, + "libraryAutoScanWeekly": "Weekly", + "@libraryAutoScanWeekly": { + "description": "Auto scan once per week" + }, "libraryActions": "Actions", "@libraryActions": { "description": "Section header for library actions" diff --git a/lib/main.dart b/lib/main.dart index 63d74d3a..7ead4a81 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -4,6 +4,7 @@ import 'package:device_info_plus/device_info_plus.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:path_provider/path_provider.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import 'package:spotiflac_android/app.dart'; import 'package:spotiflac_android/providers/download_queue_provider.dart'; import 'package:spotiflac_android/providers/extension_provider.dart'; @@ -90,16 +91,21 @@ class _EagerInitialization extends ConsumerStatefulWidget { _EagerInitializationState(); } -class _EagerInitializationState extends ConsumerState<_EagerInitialization> { +class _EagerInitializationState extends ConsumerState<_EagerInitialization> + with WidgetsBindingObserver { ProviderSubscription? _localLibraryEnabledSub; Timer? _downloadHistoryWarmupTimer; Timer? _libraryCollectionsWarmupTimer; Timer? _localLibraryWarmupTimer; bool _localLibraryWarmupScheduled = false; + bool _autoScanTriggeredOnLaunch = false; + + static const _lastScannedAtKey = 'local_library_last_scanned_at'; @override void initState() { super.initState(); + WidgetsBinding.instance.addObserver(this); WidgetsBinding.instance.addPostFrameCallback((_) { if (!mounted) return; _initializeAppServices(); @@ -110,6 +116,7 @@ class _EagerInitializationState extends ConsumerState<_EagerInitialization> { @override void dispose() { + WidgetsBinding.instance.removeObserver(this); _localLibraryEnabledSub?.close(); _downloadHistoryWarmupTimer?.cancel(); _libraryCollectionsWarmupTimer?.cancel(); @@ -117,6 +124,13 @@ class _EagerInitializationState extends ConsumerState<_EagerInitialization> { super.dispose(); } + @override + void didChangeAppLifecycleState(AppLifecycleState state) { + if (state == AppLifecycleState.resumed) { + _maybeAutoScanLocalLibrary(); + } + } + void _initializeDeferredProviders() { _downloadHistoryWarmupTimer = _scheduleProviderWarmup( const Duration(milliseconds: 400), @@ -155,7 +169,64 @@ class _EagerInitializationState extends ConsumerState<_EagerInitialization> { _localLibraryWarmupScheduled = true; _localLibraryWarmupTimer = _scheduleProviderWarmup( const Duration(milliseconds: 1600), - () => ref.read(localLibraryProvider), + () { + ref.read(localLibraryProvider); + // Trigger auto-scan after initial warmup on first app launch. + if (!_autoScanTriggeredOnLaunch) { + _autoScanTriggeredOnLaunch = true; + // Give the provider a moment to load existing data before scanning. + Future.delayed(const Duration(milliseconds: 500), () { + if (mounted) _maybeAutoScanLocalLibrary(); + }); + } + }, + ); + } + + /// Checks whether an automatic incremental scan should be triggered based on + /// the user's auto-scan preference and the time since the last scan. + Future _maybeAutoScanLocalLibrary() async { + if (!mounted) return; + + final settings = ref.read(settingsProvider); + if (!settings.localLibraryEnabled) return; + if (settings.localLibraryPath.isEmpty) return; + if (settings.localLibraryAutoScan == 'off') return; + + // Don't start a scan if one is already running. + final libraryState = ref.read(localLibraryProvider); + if (libraryState.isScanning) return; + + // Determine cooldown based on auto-scan mode. + final now = DateTime.now(); + final prefs = await SharedPreferences.getInstance(); + final lastScannedMs = prefs.getInt(_lastScannedAtKey); + + if (lastScannedMs != null) { + final lastScanned = DateTime.fromMillisecondsSinceEpoch(lastScannedMs); + final elapsed = now.difference(lastScanned); + + switch (settings.localLibraryAutoScan) { + case 'on_open': + // Cooldown of 10 minutes to prevent rapid re-scans. + if (elapsed.inMinutes < 10) return; + break; + case 'daily': + if (elapsed.inHours < 24) return; + break; + case 'weekly': + if (elapsed.inDays < 7) return; + break; + default: + return; + } + } + + // All checks passed -- start an incremental scan. + final iosBookmark = settings.localLibraryBookmark; + ref.read(localLibraryProvider.notifier).startScan( + settings.localLibraryPath, + iosBookmark: iosBookmark.isNotEmpty ? iosBookmark : null, ); } diff --git a/lib/models/settings.dart b/lib/models/settings.dart index 9bf2ee10..87c31e1b 100644 --- a/lib/models/settings.dart +++ b/lib/models/settings.dart @@ -59,6 +59,8 @@ class AppSettings { localLibraryBookmark; // Base64-encoded iOS security-scoped bookmark final bool localLibraryShowDuplicates; // Show indicator when searching for existing tracks + final String + localLibraryAutoScan; // Auto-scan mode: 'off', 'on_open', 'daily', 'weekly' final bool hasCompletedTutorial; // Track if user has completed the app tutorial @@ -123,6 +125,7 @@ class AppSettings { this.localLibraryPath = '', this.localLibraryBookmark = '', this.localLibraryShowDuplicates = true, + this.localLibraryAutoScan = 'off', this.hasCompletedTutorial = false, this.lyricsProviders = const [ 'lrclib', @@ -186,6 +189,7 @@ class AppSettings { String? localLibraryPath, String? localLibraryBookmark, bool? localLibraryShowDuplicates, + String? localLibraryAutoScan, bool? hasCompletedTutorial, List? lyricsProviders, bool? lyricsIncludeTranslationNetease, @@ -251,6 +255,8 @@ class AppSettings { localLibraryBookmark: localLibraryBookmark ?? this.localLibraryBookmark, localLibraryShowDuplicates: localLibraryShowDuplicates ?? this.localLibraryShowDuplicates, + localLibraryAutoScan: + localLibraryAutoScan ?? this.localLibraryAutoScan, hasCompletedTutorial: hasCompletedTutorial ?? this.hasCompletedTutorial, lyricsProviders: lyricsProviders ?? this.lyricsProviders, lyricsIncludeTranslationNetease: diff --git a/lib/models/settings.g.dart b/lib/models/settings.g.dart index 99a5114d..2b6a35cf 100644 --- a/lib/models/settings.g.dart +++ b/lib/models/settings.g.dart @@ -57,6 +57,7 @@ AppSettings _$AppSettingsFromJson(Map json) => AppSettings( localLibraryBookmark: json['localLibraryBookmark'] as String? ?? '', localLibraryShowDuplicates: json['localLibraryShowDuplicates'] as bool? ?? true, + localLibraryAutoScan: json['localLibraryAutoScan'] as String? ?? 'off', hasCompletedTutorial: json['hasCompletedTutorial'] as bool? ?? false, lyricsProviders: (json['lyricsProviders'] as List?) @@ -129,6 +130,7 @@ Map _$AppSettingsToJson( 'localLibraryPath': instance.localLibraryPath, 'localLibraryBookmark': instance.localLibraryBookmark, 'localLibraryShowDuplicates': instance.localLibraryShowDuplicates, + 'localLibraryAutoScan': instance.localLibraryAutoScan, 'hasCompletedTutorial': instance.hasCompletedTutorial, 'lyricsProviders': instance.lyricsProviders, 'lyricsIncludeTranslationNetease': instance.lyricsIncludeTranslationNetease, diff --git a/lib/providers/settings_provider.dart b/lib/providers/settings_provider.dart index e98a70e0..33706c57 100644 --- a/lib/providers/settings_provider.dart +++ b/lib/providers/settings_provider.dart @@ -518,6 +518,11 @@ class SettingsNotifier extends Notifier { _saveSettings(); } + void setLocalLibraryAutoScan(String mode) { + state = state.copyWith(localLibraryAutoScan: mode); + _saveSettings(); + } + void setTutorialComplete() { state = state.copyWith(hasCompletedTutorial: true); _saveSettings(); diff --git a/lib/screens/settings/library_settings_page.dart b/lib/screens/settings/library_settings_page.dart index e71c1046..608eb4bf 100644 --- a/lib/screens/settings/library_settings_page.dart +++ b/lib/screens/settings/library_settings_page.dart @@ -241,6 +241,99 @@ class _LibrarySettingsPageState extends ConsumerState { } } + String _getAutoScanLabel(BuildContext context, String mode) { + switch (mode) { + case 'on_open': + return context.l10n.libraryAutoScanOnOpen; + case 'daily': + return context.l10n.libraryAutoScanDaily; + case 'weekly': + return context.l10n.libraryAutoScanWeekly; + default: + return context.l10n.libraryAutoScanOff; + } + } + + void _showAutoScanPicker(BuildContext context, String current) { + final colorScheme = Theme.of(context).colorScheme; + showModalBottomSheet( + context: context, + useRootNavigator: true, + backgroundColor: colorScheme.surfaceContainerHigh, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical(top: Radius.circular(28)), + ), + builder: (context) => SafeArea( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.fromLTRB(24, 24, 24, 8), + child: Text( + context.l10n.libraryAutoScan, + style: Theme.of(context) + .textTheme + .titleLarge + ?.copyWith(fontWeight: FontWeight.bold), + ), + ), + Padding( + padding: const EdgeInsets.fromLTRB(24, 0, 24, 16), + child: Text( + context.l10n.libraryAutoScanSubtitle, + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + color: colorScheme.onSurfaceVariant, + ), + ), + ), + _AutoScanOption( + icon: Icons.block, + title: context.l10n.libraryAutoScanOff, + selected: current == 'off', + colorScheme: colorScheme, + onTap: () { + ref.read(settingsProvider.notifier).setLocalLibraryAutoScan('off'); + Navigator.pop(context); + }, + ), + _AutoScanOption( + icon: Icons.open_in_new, + title: context.l10n.libraryAutoScanOnOpen, + selected: current == 'on_open', + colorScheme: colorScheme, + onTap: () { + ref.read(settingsProvider.notifier).setLocalLibraryAutoScan('on_open'); + Navigator.pop(context); + }, + ), + _AutoScanOption( + icon: Icons.today, + title: context.l10n.libraryAutoScanDaily, + selected: current == 'daily', + colorScheme: colorScheme, + onTap: () { + ref.read(settingsProvider.notifier).setLocalLibraryAutoScan('daily'); + Navigator.pop(context); + }, + ), + _AutoScanOption( + icon: Icons.date_range, + title: context.l10n.libraryAutoScanWeekly, + selected: current == 'weekly', + colorScheme: colorScheme, + onTap: () { + ref.read(settingsProvider.notifier).setLocalLibraryAutoScan('weekly'); + Navigator.pop(context); + }, + ), + const SizedBox(height: 16), + ], + ), + ), + ); + } + @override Widget build(BuildContext context) { final settings = ref.watch(settingsProvider); @@ -344,7 +437,18 @@ class _LibrarySettingsPageState extends ConsumerState { onChanged: (value) => ref .read(settingsProvider.notifier) .setLocalLibraryShowDuplicates(value), - showDivider: false, + ), + Opacity( + opacity: settings.localLibraryEnabled ? 1.0 : 0.5, + child: SettingsItem( + icon: Icons.autorenew_rounded, + title: context.l10n.libraryAutoScan, + subtitle: _getAutoScanLabel(context, settings.localLibraryAutoScan), + onTap: settings.localLibraryEnabled + ? () => _showAutoScanPicker(context, settings.localLibraryAutoScan) + : null, + showDivider: false, + ), ), ], ), @@ -825,3 +929,31 @@ class _ScanProgressTile extends StatelessWidget { ); } } + +class _AutoScanOption extends StatelessWidget { + final IconData icon; + final String title; + final bool selected; + final ColorScheme colorScheme; + final VoidCallback onTap; + + const _AutoScanOption({ + required this.icon, + required this.title, + required this.selected, + required this.colorScheme, + required this.onTap, + }); + + @override + Widget build(BuildContext context) { + return ListTile( + leading: Icon(icon), + title: Text(title), + trailing: selected + ? Icon(Icons.check, color: colorScheme.primary) + : null, + onTap: onTap, + ); + } +}