@ -1,14 +1,19 @@
import ' dart:async ' ;
import ' package:easy_localization/easy_localization.dart ' ;
import ' package:flutter/material.dart ' ;
import ' package:hooks_riverpod/hooks_riverpod.dart ' ;
import ' package:immich_mobile/domain/models/album/local_album.model.dart ' ;
import ' package:immich_mobile/domain/models/store.model.dart ' ;
import ' package:immich_mobile/domain/services/sync_linked_album.service.dart ' ;
import ' package:immich_mobile/entities/store.entity.dart ' ;
import ' package:immich_mobile/extensions/build_context_extensions.dart ' ;
import ' package:immich_mobile/extensions/platform_extensions.dart ' ;
import ' package:immich_mobile/extensions/translate_extensions.dart ' ;
import ' package:immich_mobile/providers/app_settings.provider.dart ' ;
import ' package:immich_mobile/domain/services/sync_linked_album.service.dart ' ;
import ' package:immich_mobile/providers/background_sync.provider.dart ' ;
import ' package:immich_mobile/providers/backup/backup_album.provider.dart ' ;
import ' package:immich_mobile/providers/infrastructure/platform.provider.dart ' ;
import ' package:immich_mobile/providers/user.provider.dart ' ;
import ' package:immich_mobile/services/app_settings.service.dart ' ;
import ' package:immich_mobile/widgets/settings/settings_sub_page_scaffold.dart ' ;
@ -18,12 +23,40 @@ class DriftBackupSettings extends ConsumerWidget {
@ override
Widget build ( BuildContext context , WidgetRef ref ) {
return const SettingsSubPageScaffold (
return SettingsSubPageScaffold (
settings: [
_UseWifiForUploadVideosButton ( ) ,
_UseWifiForUploadPhotosButton ( ) ,
Divider ( indent: 16 , endIndent: 16 ) ,
_AlbumSyncActionButton ( ) ,
Padding (
padding: const EdgeInsets . only ( left: 16.0 ) ,
child: Text (
" network_requirements " . t ( context: context ) . toUpperCase ( ) ,
style: context . textTheme . labelSmall ? . copyWith ( color: context . colorScheme . onSurface . withValues ( alpha: 0.7 ) ) ,
) ,
) ,
const _UseWifiForUploadVideosButton ( ) ,
const _UseWifiForUploadPhotosButton ( ) ,
if ( CurrentPlatform . isAndroid ) . . . [
const Divider ( ) ,
Padding (
padding: const EdgeInsets . only ( left: 16.0 ) ,
child: Text (
" background_options " . t ( context: context ) . toUpperCase ( ) ,
style: context . textTheme . labelSmall ? . copyWith (
color: context . colorScheme . onSurface . withValues ( alpha: 0.7 ) ,
) ,
) ,
) ,
const _BackupOnlyWhenChargingButton ( ) ,
const _BackupDelaySlider ( ) ,
] ,
const Divider ( ) ,
Padding (
padding: const EdgeInsets . only ( left: 16.0 ) ,
child: Text (
" backup_albums_sync " . t ( context: context ) . toUpperCase ( ) ,
style: context . textTheme . labelSmall ? . copyWith ( color: context . colorScheme . onSurface . withValues ( alpha: 0.7 ) ) ,
) ,
) ,
const _AlbumSyncActionButton ( ) ,
] ,
) ;
}
@ -151,30 +184,59 @@ class _AlbumSyncActionButtonState extends ConsumerState<_AlbumSyncActionButton>
}
}
class _UseWifiForUploadVideosButton extends ConsumerWidget {
const _UseWifiForUploadVideosButton ( ) ;
class _SettingsSwitchTile extends ConsumerStatefulWidget {
final AppSettingsEnum < bool > appSettingsEnum ;
final String titleKey ;
final String subtitleKey ;
final void Function ( bool ? ) ? onChanged ;
const _SettingsSwitchTile ( {
required this . appSettingsEnum ,
required this . titleKey ,
required this . subtitleKey ,
this . onChanged ,
} ) ;
@ override
Widget build ( BuildContext context , WidgetRef ref ) {
final valueStream = Store . watch ( StoreKey . useWifiForUploadVideos ) ;
ConsumerState createState ( ) = > _SettingsSwitchTileState ( ) ;
}
class _SettingsSwitchTileState extends ConsumerState < _SettingsSwitchTile > {
late final Stream < bool ? > valueStream ;
late final StreamSubscription < bool ? > subscription ;
@ override
void initState ( ) {
super . initState ( ) ;
valueStream = Store . watch ( widget . appSettingsEnum . storeKey ) . asBroadcastStream ( ) ;
subscription = valueStream . listen ( ( value ) {
widget . onChanged ? . call ( value ) ;
} ) ;
}
@ override
void dispose ( ) {
subscription . cancel ( ) ;
super . dispose ( ) ;
}
@ override
Widget build ( BuildContext context ) {
return ListTile (
title: Text (
" videos " . t ( context: context ) ,
widget . titleKey . t ( context: context ) ,
style: context . textTheme . titleMedium ? . copyWith ( color: context . primaryColor ) ,
) ,
subtitle: Text ( " network_requirement_videos_upload " . t ( context: context ) , style: context . textTheme . labelLarge ) ,
subtitle: Text ( widget . subtitleKey . t ( context: context ) , style: context . textTheme . labelLarge ) ,
trailing: StreamBuilder (
stream: valueStream ,
initialData: Store . tryGet ( StoreKey . useWifiForUploadVideos ) ? ? false ,
initialData: Store . tryGet ( widget. appSettingsEnum . storeKey ) ? ? widget . appSettingsEnum . defaultValu e,
builder: ( context , snapshot ) {
final value = snapshot . data ? ? false ;
return Switch (
value: value ,
onChanged: ( bool newValue ) async {
await ref
. read ( appSettingsServiceProvider )
. setSetting ( AppSettingsEnum . useCellularForUploadVideos , newValue ) ;
await ref . read ( appSettingsServiceProvider ) . setSetting ( widget . appSettingsEnum , newValue ) ;
} ,
) ;
} ,
@ -183,34 +245,135 @@ class _UseWifiForUploadVideosButton extends ConsumerWidget {
}
}
class _UseWifiForUploadVideosButton extends ConsumerWidget {
const _UseWifiForUploadVideosButton ( ) ;
@ override
Widget build ( BuildContext context , WidgetRef ref ) {
return const _SettingsSwitchTile (
appSettingsEnum: AppSettingsEnum . useCellularForUploadVideos ,
titleKey: " videos " ,
subtitleKey: " network_requirement_videos_upload " ,
) ;
}
}
class _UseWifiForUploadPhotosButton extends ConsumerWidget {
const _UseWifiForUploadPhotosButton ( ) ;
@ override
Widget build ( BuildContext context , WidgetRef ref ) {
final valueStream = Store . watch ( StoreKey . useWifiForUploadPhotos ) ;
return const _SettingsSwitchTile (
appSettingsEnum: AppSettingsEnum . useCellularForUploadPhotos ,
titleKey: " photos " ,
subtitleKey: " network_requirement_photos_upload " ,
) ;
}
}
return ListTile (
title: Text (
" photos " . t ( context: context ) ,
style: context . textTheme . titleMedium ? . copyWith ( color: context . primaryColor ) ,
) ,
subtitle: Text ( " network_requirement_photos_upload " . t ( context: context ) , style: context . textTheme . labelLarge ) ,
trailing: StreamBuilder (
stream: valueStream ,
initialData: Store . tryGet ( StoreKey . useWifiForUploadPhotos ) ? ? false ,
builder: ( context , snapshot ) {
final value = snapshot . data ? ? false ;
return Switch (
value: value ,
onChanged: ( bool newValue ) async {
await ref
. read ( appSettingsServiceProvider )
. setSetting ( AppSettingsEnum . useCellularForUploadPhotos , newValue ) ;
} ,
) ;
} ,
) ,
class _BackupOnlyWhenChargingButton extends ConsumerWidget {
const _BackupOnlyWhenChargingButton ( ) ;
@ override
Widget build ( BuildContext context , WidgetRef ref ) {
return _SettingsSwitchTile (
appSettingsEnum: AppSettingsEnum . backupRequireCharging ,
titleKey: " charging " ,
subtitleKey: " charging_requirement_mobile_backup " ,
onChanged: ( value ) {
ref . read ( backgroundWorkerFgServiceProvider ) . configure ( requireCharging: value ? ? false ) ;
} ,
) ;
}
}
class _BackupDelaySlider extends ConsumerStatefulWidget {
const _BackupDelaySlider ( ) ;
@ override
ConsumerState < _BackupDelaySlider > createState ( ) = > _BackupDelaySliderState ( ) ;
}
class _BackupDelaySliderState extends ConsumerState < _BackupDelaySlider > {
late final Stream < int ? > valueStream ;
late final StreamSubscription < int ? > subscription ;
late int currentValue ;
static int backupDelayToSliderValue ( int ms ) = > switch ( ms ) {
5 = > 0 ,
30 = > 1 ,
120 = > 2 ,
_ = > 3 ,
} ;
static int backupDelayToSeconds ( int v ) = > switch ( v ) {
0 = > 5 ,
1 = > 30 ,
2 = > 120 ,
_ = > 600 ,
} ;
static String formatBackupDelaySliderValue ( int v ) = > switch ( v ) {
0 = > ' setting_notifications_notify_seconds ' . tr ( namedArgs: { ' count ' : ' 5 ' } ) ,
1 = > ' setting_notifications_notify_seconds ' . tr ( namedArgs: { ' count ' : ' 30 ' } ) ,
2 = > ' setting_notifications_notify_minutes ' . tr ( namedArgs: { ' count ' : ' 2 ' } ) ,
_ = > ' setting_notifications_notify_minutes ' . tr ( namedArgs: { ' count ' : ' 10 ' } ) ,
} ;
@ override
void initState ( ) {
super . initState ( ) ;
final initialValue =
Store . tryGet ( AppSettingsEnum . backupTriggerDelay . storeKey ) ? ? AppSettingsEnum . backupTriggerDelay . defaultValue ;
currentValue = backupDelayToSliderValue ( initialValue ) ;
valueStream = Store . watch ( AppSettingsEnum . backupTriggerDelay . storeKey ) . asBroadcastStream ( ) ;
subscription = valueStream . listen ( ( value ) {
if ( mounted & & value ! = null ) {
setState ( ( ) {
currentValue = backupDelayToSliderValue ( value ) ;
} ) ;
}
} ) ;
}
@ override
void dispose ( ) {
subscription . cancel ( ) ;
super . dispose ( ) ;
}
@ override
Widget build ( BuildContext context ) {
return Column (
crossAxisAlignment: CrossAxisAlignment . start ,
children: [
Padding (
padding: const EdgeInsets . only ( left: 16.0 , top: 8.0 ) ,
child: Text (
' backup_controller_page_background_delay ' . tr (
namedArgs: { ' duration ' : formatBackupDelaySliderValue ( currentValue ) } ,
) ,
style: context . textTheme . titleMedium ? . copyWith ( color: context . primaryColor ) ,
) ,
) ,
Slider (
value: currentValue . toDouble ( ) ,
onChanged: ( double v ) {
setState ( ( ) {
currentValue = v . toInt ( ) ;
} ) ;
} ,
onChangeEnd: ( double v ) async {
final milliseconds = backupDelayToSeconds ( v . toInt ( ) ) ;
await ref . read ( appSettingsServiceProvider ) . setSetting ( AppSettingsEnum . backupTriggerDelay , milliseconds ) ;
} ,
max: 3.0 ,
min: 0.0 ,
divisions: 3 ,
label: formatBackupDelaySliderValue ( currentValue ) ,
) ,
] ,
) ;
}
}