1
0
mirror of https://github.com/immich-app/immich.git synced 2024-12-25 10:43:13 +02:00

feat(mobile): use app without storage permission (#5014)

* feat(mobile): use app without storage permission

* address review feedback
This commit is contained in:
Fynn Petersen-Frey 2023-11-14 21:30:27 +01:00 committed by GitHub
parent 8f3ed8ba8e
commit 5145c33ed4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 134 additions and 232 deletions

View File

@ -80,7 +80,6 @@
"backup_controller_page_failed": "Failed ({})",
"backup_controller_page_filename": "File name: {} [{}]",
"backup_controller_page_id": "ID: {}",
"backup_controller_page_info": "Backup Information",
"backup_controller_page_none_selected": "None selected",
"backup_controller_page_remainder": "Remainder",
"backup_controller_page_remainder_sub": "Remaining photos and videos to back up from selection",
@ -96,7 +95,6 @@
"backup_controller_page_turn_off": "Turn off foreground backup",
"backup_controller_page_turn_on": "Turn on foreground backup",
"backup_controller_page_uploading_file_info": "Uploading file info",
"backup_err_only_album": "Cannot remove the only album",
"backup_info_card_assets": "assets",
"backup_manual_cancelled": "Cancelled",
"backup_manual_failed": "Failed",
@ -253,11 +251,11 @@
"permission_onboarding_get_started": "Get started",
"permission_onboarding_go_to_settings": "Go to settings",
"permission_onboarding_grant_permission": "Grant permission",
"permission_onboarding_log_out": "Log out",
"permission_onboarding_back": "Back",
"permission_onboarding_permission_denied": "Permission denied. To use Immich, grant photo and video permissions in Settings.",
"permission_onboarding_permission_granted": "Permission granted! You are all set.",
"permission_onboarding_permission_limited": "Permission limited. To let Immich backup and manage your entire gallery collection, grant photo and video permissions in Settings.",
"permission_onboarding_request": "Immich requires permission to view your photos and videos.",
"permission_onboarding_request": "Immich requires permission to access your photos and videos.",
"profile_drawer_app_logs": "Logs",
"profile_drawer_client_server_up_to_date": "Client and Server are up-to-date",
"profile_drawer_documentation": "Documentation",

View File

@ -25,6 +25,8 @@ class AlbumNotifier extends StateNotifier<List<Album>> {
_albumService.refreshRemoteAlbums(isShared: false),
]);
Future<void> getDeviceAlbums() => _albumService.refreshDeviceAlbums();
Future<bool> deleteAlbum(Album album) => _albumService.deleteAlbum(album);
Future<Album?> createAlbum(

View File

@ -67,6 +67,10 @@ class AlbumService {
final List<String> selectedIds =
await _backupService.selectedAlbumsQuery().idProperty().findAll();
if (selectedIds.isEmpty) {
final numLocal = await _db.albums.where().localIdIsNotNull().count();
if (numLocal > 0) {
_syncService.removeAllLocalAlbumsAndAssets();
}
return false;
}
final List<AssetPathEntity> onDevice =

View File

@ -89,7 +89,6 @@ class BackupNotifier extends StateNotifier<BackUpState> {
state = state
.copyWith(selectedBackupAlbums: {...state.selectedBackupAlbums, album});
_updateBackupAssetCount();
}
void addExcludedAlbumForBackup(AvailableAlbum album) {
@ -98,7 +97,6 @@ class BackupNotifier extends StateNotifier<BackUpState> {
}
state = state
.copyWith(excludedBackupAlbums: {...state.excludedBackupAlbums, album});
_updateBackupAssetCount();
}
void removeAlbumForBackup(AvailableAlbum album) {
@ -107,7 +105,6 @@ class BackupNotifier extends StateNotifier<BackUpState> {
currentSelectedAlbums.removeWhere((a) => a == album);
state = state.copyWith(selectedBackupAlbums: currentSelectedAlbums);
_updateBackupAssetCount();
}
void removeExcludedAlbumForBackup(AvailableAlbum album) {
@ -116,7 +113,20 @@ class BackupNotifier extends StateNotifier<BackUpState> {
currentExcludedAlbums.removeWhere((a) => a == album);
state = state.copyWith(excludedBackupAlbums: currentExcludedAlbums);
_updateBackupAssetCount();
}
Future<void> backupAlbumSelectionDone() {
if (state.selectedBackupAlbums.isEmpty) {
// disable any backup
cancelBackup();
setAutoBackup(false);
configureBackgroundBackup(
enabled: false,
onError: (msg) {},
onBatteryInfo: () {},
);
}
return _updateBackupAssetCount();
}
void setAutoBackup(bool enabled) {
@ -249,30 +259,6 @@ class BackupNotifier extends StateNotifier<BackUpState> {
final List<BackupAlbum> selectedBackupAlbums =
await _backupService.selectedAlbumsQuery().findAll();
// First time backup - set isAll album is the default one for backup.
if (selectedBackupAlbums.isEmpty) {
log.info("First time backup; setup 'Recent(s)' album as default");
// Get album that contains all assets
final list = await PhotoManager.getAssetPathList(
hasAll: true,
onlyAll: true,
type: RequestType.common,
);
if (list.isEmpty) {
return;
}
AssetPathEntity albumHasAllAssets = list.first;
final ba = BackupAlbum(
albumHasAllAssets.id,
DateTime.fromMillisecondsSinceEpoch(0),
BackupSelection.select,
);
await _db.writeTxn(() => _db.backupAlbums.put(ba));
}
// Generate AssetPathEntity from id to add to local state
final Set<AvailableAlbum> selectedAlbums = {};
for (final BackupAlbum ba in selectedBackupAlbums) {
@ -362,7 +348,6 @@ class BackupNotifier extends StateNotifier<BackUpState> {
allUniqueAssets: {},
selectedAlbumsBackupAssetsIds: selectedAlbumsBackupAssets,
);
return;
} else {
state = state.copyWith(
allAssetsInDatabase: allAssetsInDatabase,
@ -373,8 +358,6 @@ class BackupNotifier extends StateNotifier<BackUpState> {
// Save to persistent storage
await _updatePersistentAlbumsSelection();
return;
}
/// Get all necessary information for calculating the available albums,

View File

@ -82,19 +82,9 @@ class AlbumInfoCard extends HookConsumerWidget {
HapticFeedback.selectionClick();
if (isSelected) {
if (ref.watch(backupProvider).selectedBackupAlbums.length == 1) {
ImmichToast.show(
context: context,
msg: "backup_err_only_album".tr(),
toastType: ToastType.error,
gravity: ToastGravity.BOTTOM,
);
return;
}
ref.watch(backupProvider.notifier).removeAlbumForBackup(albumInfo);
ref.read(backupProvider.notifier).removeAlbumForBackup(albumInfo);
} else {
ref.watch(backupProvider.notifier).addAlbumForBackup(albumInfo);
ref.read(backupProvider.notifier).addAlbumForBackup(albumInfo);
}
},
onDoubleTap: () {
@ -103,23 +93,10 @@ class AlbumInfoCard extends HookConsumerWidget {
if (isExcluded) {
// Remove from exclude album list
ref
.watch(backupProvider.notifier)
.read(backupProvider.notifier)
.removeExcludedAlbumForBackup(albumInfo);
} else {
// Add to exclude album list
if (ref.watch(backupProvider).selectedBackupAlbums.length == 1 &&
ref
.watch(backupProvider)
.selectedBackupAlbums
.contains(albumInfo)) {
ImmichToast.show(
context: context,
msg: "backup_err_only_album".tr(),
toastType: ToastType.error,
gravity: ToastGravity.BOTTOM,
);
return;
}
if (albumInfo.id == 'isAll' || albumInfo.name == 'Recents') {
ImmichToast.show(
@ -132,7 +109,7 @@ class AlbumInfoCard extends HookConsumerWidget {
}
ref
.watch(backupProvider.notifier)
.read(backupProvider.notifier)
.addExcludedAlbumForBackup(albumInfo);
}
},

View File

@ -1,4 +1,3 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
@ -74,23 +73,10 @@ class AlbumInfoListTile extends HookConsumerWidget {
if (isExcluded) {
// Remove from exclude album list
ref
.watch(backupProvider.notifier)
.read(backupProvider.notifier)
.removeExcludedAlbumForBackup(albumInfo);
} else {
// Add to exclude album list
if (ref.watch(backupProvider).selectedBackupAlbums.length == 1 &&
ref
.watch(backupProvider)
.selectedBackupAlbums
.contains(albumInfo)) {
ImmichToast.show(
context: context,
msg: "backup_err_only_album".tr(),
toastType: ToastType.error,
gravity: ToastGravity.BOTTOM,
);
return;
}
if (albumInfo.id == 'isAll' || albumInfo.name == 'Recents') {
ImmichToast.show(
@ -103,7 +89,7 @@ class AlbumInfoListTile extends HookConsumerWidget {
}
ref
.watch(backupProvider.notifier)
.read(backupProvider.notifier)
.addExcludedAlbumForBackup(albumInfo);
}
},
@ -113,19 +99,9 @@ class AlbumInfoListTile extends HookConsumerWidget {
onTap: () {
HapticFeedback.selectionClick();
if (isSelected) {
if (ref.watch(backupProvider).selectedBackupAlbums.length == 1) {
ImmichToast.show(
context: context,
msg: "backup_err_only_album".tr(),
toastType: ToastType.error,
gravity: ToastGravity.BOTTOM,
);
return;
}
ref.watch(backupProvider.notifier).removeAlbumForBackup(albumInfo);
ref.read(backupProvider.notifier).removeAlbumForBackup(albumInfo);
} else {
ref.watch(backupProvider.notifier).addAlbumForBackup(albumInfo);
ref.read(backupProvider.notifier).addAlbumForBackup(albumInfo);
}
},
leading: ClipRRect(

View File

@ -1,7 +1,6 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/immich_colors.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
@ -9,7 +8,6 @@ import 'package:immich_mobile/modules/backup/providers/backup.provider.dart';
import 'package:immich_mobile/modules/backup/ui/album_info_card.dart';
import 'package:immich_mobile/modules/backup/ui/album_info_list_tile.dart';
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
import 'package:immich_mobile/shared/ui/immich_toast.dart';
class BackupAlbumSelectionPage extends HookConsumerWidget {
const BackupAlbumSelectionPage({Key? key}) : super(key: key);
@ -91,19 +89,8 @@ class BackupAlbumSelectionPage extends HookConsumerWidget {
buildSelectedAlbumNameChip() {
return selectedBackupAlbums.map((album) {
void removeSelection() {
if (ref.watch(backupProvider).selectedBackupAlbums.length == 1) {
ImmichToast.show(
context: context,
msg: "backup_err_only_album".tr(),
toastType: ToastType.error,
gravity: ToastGravity.BOTTOM,
);
return;
}
ref.watch(backupProvider.notifier).removeAlbumForBackup(album);
}
void removeSelection() =>
ref.read(backupProvider.notifier).removeAlbumForBackup(album);
return Padding(
padding: const EdgeInsets.only(right: 8.0),
@ -252,47 +239,6 @@ class BackupAlbumSelectionPage extends HookConsumerWidget {
),
),
Padding(
padding:
const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8),
child: Card(
margin: const EdgeInsets.all(0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
side: BorderSide(
color: isDarkTheme
? const Color.fromARGB(255, 0, 0, 0)
: const Color.fromARGB(255, 235, 235, 235),
width: 1,
),
),
elevation: 0,
borderOnForeground: false,
child: Column(
children: [
ListTile(
visualDensity: VisualDensity.compact,
title: const Text(
"backup_album_selection_page_total_assets",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14,
),
).tr(),
trailing: Text(
ref
.watch(backupProvider)
.allUniqueAssets
.length
.toString(),
style: const TextStyle(fontWeight: FontWeight.bold),
),
),
],
),
),
),
ListTile(
title: Text(
"backup_album_selection_page_albums_device".tr(

View File

@ -6,6 +6,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/modules/album/providers/album.provider.dart';
import 'package:immich_mobile/modules/backup/background_service/background.service.dart';
import 'package:immich_mobile/modules/backup/providers/error_backup_list.provider.dart';
import 'package:immich_mobile/modules/backup/providers/ios_background_settings.provider.dart';
@ -38,6 +39,7 @@ class BackupControllerPage extends HookConsumerWidget {
final settingsService = ref.watch(appSettingsServiceProvider);
final showBackupFix = Platform.isAndroid &&
settingsService.getSetting(AppSettingsEnum.advancedTroubleshooting);
final hasAnyAlbum = backupState.selectedBackupAlbums.isNotEmpty;
final appRefreshDisabled =
Platform.isIOS && settings?.appRefreshEnabled != true;
@ -590,8 +592,14 @@ class BackupControllerPage extends HookConsumerWidget {
),
),
trailing: ElevatedButton(
onPressed: () {
context.autoPush(const BackupAlbumSelectionRoute());
onPressed: () async {
await context.autoPush(const BackupAlbumSelectionRoute());
// waited until returning from selection
await ref
.read(backupProvider.notifier)
.backupAlbumSelectionDone();
// waited until backup albums are stored in DB
ref.read(albumProvider.notifier).getDeviceAlbums();
},
child: const Text(
"backup_controller_page_select",
@ -689,55 +697,50 @@ class BackupControllerPage extends HookConsumerWidget {
padding: const EdgeInsets.only(left: 16.0, right: 16, bottom: 32),
child: ListView(
// crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: const Text(
"backup_controller_page_info",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
).tr(),
),
buildFolderSelectionTile(),
BackupInfoCard(
title: "backup_controller_page_total".tr(),
subtitle: "backup_controller_page_total_sub".tr(),
info: ref.watch(backupProvider).availableAlbums.isEmpty
? "..."
: "${backupState.allUniqueAssets.length}",
),
BackupInfoCard(
title: "backup_controller_page_backup".tr(),
subtitle: "backup_controller_page_backup_sub".tr(),
info: ref.watch(backupProvider).availableAlbums.isEmpty
? "..."
: "${backupState.selectedAlbumsBackupAssetsIds.length}",
),
BackupInfoCard(
title: "backup_controller_page_remainder".tr(),
subtitle: "backup_controller_page_remainder_sub".tr(),
info: ref.watch(backupProvider).availableAlbums.isEmpty
? "..."
: "${backupState.allUniqueAssets.length - backupState.selectedAlbumsBackupAssetsIds.length}",
),
const Divider(),
buildAutoBackupController(),
const Divider(),
AnimatedSwitcher(
duration: const Duration(milliseconds: 500),
child: Platform.isIOS
? (appRefreshDisabled
? buildBackgroundAppRefreshWarning()
: buildBackgroundBackupController())
: buildBackgroundBackupController(),
),
if (showBackupFix) const Divider(),
if (showBackupFix) buildCheckCorruptBackups(),
const Divider(),
const Divider(),
const CurrentUploadingAssetInfoBox(),
if (!hasExclusiveAccess) buildBackgroundBackupInfo(),
buildBackupButton(),
],
children: hasAnyAlbum
? [
buildFolderSelectionTile(),
BackupInfoCard(
title: "backup_controller_page_total".tr(),
subtitle: "backup_controller_page_total_sub".tr(),
info: ref.watch(backupProvider).availableAlbums.isEmpty
? "..."
: "${backupState.allUniqueAssets.length}",
),
BackupInfoCard(
title: "backup_controller_page_backup".tr(),
subtitle: "backup_controller_page_backup_sub".tr(),
info: ref.watch(backupProvider).availableAlbums.isEmpty
? "..."
: "${backupState.selectedAlbumsBackupAssetsIds.length}",
),
BackupInfoCard(
title: "backup_controller_page_remainder".tr(),
subtitle: "backup_controller_page_remainder_sub".tr(),
info: ref.watch(backupProvider).availableAlbums.isEmpty
? "..."
: "${backupState.allUniqueAssets.length - backupState.selectedAlbumsBackupAssetsIds.length}",
),
const Divider(),
buildAutoBackupController(),
const Divider(),
AnimatedSwitcher(
duration: const Duration(milliseconds: 500),
child: Platform.isIOS
? (appRefreshDisabled
? buildBackgroundAppRefreshWarning()
: buildBackgroundBackupController())
: buildBackgroundBackupController(),
),
if (showBackupFix) const Divider(),
if (showBackupFix) buildCheckCorruptBackups(),
const Divider(),
const Divider(),
const CurrentUploadingAssetInfoBox(),
if (!hasExclusiveAccess) buildBackgroundBackupInfo(),
buildBackupButton(),
]
: [buildFolderSelectionTile()],
),
),
);

View File

@ -2,8 +2,6 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/modules/backup/providers/backup.provider.dart';
import 'package:immich_mobile/modules/login/providers/authentication.provider.dart';
import 'package:immich_mobile/modules/onboarding/providers/gallery_permission.provider.dart';
import 'package:immich_mobile/routing/router.dart';
import 'package:immich_mobile/shared/ui/immich_logo.dart';
@ -18,13 +16,7 @@ class PermissionOnboardingPage extends HookConsumerWidget {
final PermissionStatus permission = ref.watch(galleryPermissionNotifier);
// Navigate to the main Tab Controller when permission is granted
void goToHome() {
// Resume backup (if enable) then navigate
ref.watch(backupProvider.notifier).resumeBackup().catchError((error) {
debugPrint('PermissionOnboardingPage error: $error');
});
context.autoReplace(const TabControllerRoute());
}
void goToBackup() => context.autoReplace(const BackupControllerRoute());
// When the permission is denied, we show a request permission page
buildRequestPermission() {
@ -46,7 +38,7 @@ class PermissionOnboardingPage extends HookConsumerWidget {
if (permission.isGranted) {
// If permission is limited, we will show the limited
// permission page
goToHome();
goToBackup();
}
}),
child: const Text(
@ -71,7 +63,7 @@ class PermissionOnboardingPage extends HookConsumerWidget {
).tr(),
const SizedBox(height: 18),
ElevatedButton(
onPressed: () => goToHome(),
onPressed: () => goToBackup(),
child: const Text('permission_onboarding_get_started').tr(),
),
],
@ -106,7 +98,7 @@ class PermissionOnboardingPage extends HookConsumerWidget {
),
const SizedBox(height: 8.0),
TextButton(
onPressed: () => goToHome(),
onPressed: () => goToBackup(),
child: const Text(
'permission_onboarding_continue_anyway',
).tr(),
@ -181,11 +173,8 @@ class PermissionOnboardingPage extends HookConsumerWidget {
),
),
TextButton(
child: const Text('permission_onboarding_log_out').tr(),
onPressed: () {
ref.read(authenticationProvider.notifier).logout();
context.autoReplace(const LoginRoute());
},
child: const Text('permission_onboarding_back').tr(),
onPressed: () => context.autoPop(),
),
],
),

View File

@ -2,10 +2,10 @@ import 'package:auto_route/auto_route.dart';
import 'package:immich_mobile/modules/onboarding/providers/gallery_permission.provider.dart';
import 'package:immich_mobile/routing/router.dart';
class GalleryPermissionGuard extends AutoRouteGuard {
class BackupPermissionGuard extends AutoRouteGuard {
final GalleryPermissionNotifier _permission;
GalleryPermissionGuard(this._permission);
BackupPermissionGuard(this._permission);
@override
void onNavigation(NavigationResolver resolver, StackRouter router) async {
@ -13,7 +13,7 @@ class GalleryPermissionGuard extends AutoRouteGuard {
if (p) {
resolver.next(true);
} else {
router.replaceAll([const PermissionOnboardingRoute()]);
router.push(const PermissionOnboardingRoute());
}
}
}

View File

@ -44,7 +44,7 @@ import 'package:immich_mobile/modules/search/views/search_result_page.dart';
import 'package:immich_mobile/modules/settings/views/settings_page.dart';
import 'package:immich_mobile/routing/auth_guard.dart';
import 'package:immich_mobile/routing/duplicate_guard.dart';
import 'package:immich_mobile/routing/gallery_permission_guard.dart';
import 'package:immich_mobile/routing/backup_permission_guard.dart';
import 'package:immich_mobile/shared/models/asset.dart';
import 'package:immich_mobile/shared/models/album.dart';
import 'package:immich_mobile/shared/models/logger_message.model.dart';
@ -77,7 +77,7 @@ part 'router.gr.dart';
AutoRoute(page: ChangePasswordPage),
CustomRoute(
page: TabControllerPage,
guards: [AuthGuard, DuplicateGuard, GalleryPermissionGuard],
guards: [AuthGuard, DuplicateGuard],
children: [
AutoRoute(page: HomePage, guards: [AuthGuard, DuplicateGuard]),
AutoRoute(page: SearchPage, guards: [AuthGuard, DuplicateGuard]),
@ -88,10 +88,13 @@ part 'router.gr.dart';
),
AutoRoute(
page: GalleryViewerPage,
guards: [AuthGuard, DuplicateGuard, GalleryPermissionGuard],
guards: [AuthGuard, DuplicateGuard],
),
AutoRoute(page: VideoViewerPage, guards: [AuthGuard, DuplicateGuard]),
AutoRoute(page: BackupControllerPage, guards: [AuthGuard, DuplicateGuard]),
AutoRoute(
page: BackupControllerPage,
guards: [AuthGuard, DuplicateGuard, BackupPermissionGuard],
),
AutoRoute(page: SearchResultPage, guards: [AuthGuard, DuplicateGuard]),
AutoRoute(page: CuratedLocationPage, guards: [AuthGuard, DuplicateGuard]),
AutoRoute(page: CreateAlbumPage, guards: [AuthGuard, DuplicateGuard]),
@ -179,8 +182,8 @@ class AppRouter extends _$AppRouter {
) : super(
authGuard: AuthGuard(_apiService),
duplicateGuard: DuplicateGuard(),
galleryPermissionGuard:
GalleryPermissionGuard(galleryPermissionNotifier),
backupPermissionGuard:
BackupPermissionGuard(galleryPermissionNotifier),
);
}

View File

@ -17,14 +17,14 @@ class _$AppRouter extends RootStackRouter {
GlobalKey<NavigatorState>? navigatorKey,
required this.authGuard,
required this.duplicateGuard,
required this.galleryPermissionGuard,
required this.backupPermissionGuard,
}) : super(navigatorKey);
final AuthGuard authGuard;
final DuplicateGuard duplicateGuard;
final GalleryPermissionGuard galleryPermissionGuard;
final BackupPermissionGuard backupPermissionGuard;
@override
final Map<String, PageFactory> pagesMap = {
@ -414,7 +414,6 @@ class _$AppRouter extends RootStackRouter {
guards: [
authGuard,
duplicateGuard,
galleryPermissionGuard,
],
children: [
RouteConfig(
@ -461,7 +460,6 @@ class _$AppRouter extends RootStackRouter {
guards: [
authGuard,
duplicateGuard,
galleryPermissionGuard,
],
),
RouteConfig(
@ -478,6 +476,7 @@ class _$AppRouter extends RootStackRouter {
guards: [
authGuard,
duplicateGuard,
backupPermissionGuard,
],
),
RouteConfig(

View File

@ -45,12 +45,14 @@ class AppStateNotiifer extends StateNotifier<AppStateEnum> {
_wasPaused = false;
final isAuthenticated = _ref.read(authenticationProvider).isAuthenticated;
final permission = _ref.read(galleryPermissionNotifier);
// Needs to be logged in and have gallery permissions
if (isAuthenticated && (permission.isGranted || permission.isLimited)) {
_ref.read(backupProvider.notifier).resumeBackup();
_ref.read(backgroundServiceProvider).resumeServiceIfEnabled();
// Needs to be logged in
if (isAuthenticated) {
final permission = _ref.watch(galleryPermissionNotifier);
if (permission.isGranted || permission.isLimited) {
_ref.read(backupProvider.notifier).resumeBackup();
_ref.read(backgroundServiceProvider).resumeServiceIfEnabled();
}
_ref.read(serverInfoProvider.notifier).getServerVersion();
switch (_ref.read(tabProvider)) {
case TabEnum.home:

View File

@ -90,6 +90,9 @@ class SyncService {
Future<bool> syncNewAssetToDb(Asset newAsset) =>
_lock.run(() => _syncNewAssetToDb(newAsset));
Future<bool> removeAllLocalAlbumsAndAssets() =>
_lock.run(_removeAllLocalAlbumsAndAssets);
// private methods:
/// Syncs users from the server to the local database
@ -756,6 +759,23 @@ class SyncService {
await a.assetCountAsync !=
(await _db.eTags.getById(a.eTagKeyAssetCount))?.assetCount;
}
Future<bool> _removeAllLocalAlbumsAndAssets() async {
try {
final assets = await _db.assets.where().localIdIsNotNull().findAll();
final (toDelete, toUpdate) =
_handleAssetRemoval(assets, [], remote: false);
await _db.writeTxn(() async {
await _db.assets.deleteAll(toDelete);
await _db.assets.putAll(toUpdate);
await _db.albums.where().localIdIsNotNull().deleteAll();
});
return true;
} catch (e) {
_log.severe("Failed to remove all local albums and assets: $e");
return false;
}
}
}
/// Returns a triple(toAdd, toUpdate, toRemove)