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:
parent
8f3ed8ba8e
commit
5145c33ed4
@ -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",
|
||||
|
@ -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(
|
||||
|
@ -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 =
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
},
|
||||
|
@ -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(
|
||||
|
@ -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(
|
||||
|
@ -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()],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -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(),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
@ -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),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user