refactor(mobile): migrate all Hive boxes to Isar database (#2036)

This commit is contained in:
Fynn Petersen-Frey
2023-03-23 02:36:44 +01:00
committed by GitHub
parent 0616a66b05
commit eccde8fa07
33 changed files with 1540 additions and 383 deletions

View File

@@ -265,7 +265,7 @@ class AlbumService {
Future<bool> deleteAlbum(Album album) async {
try {
final userId = Store.get<User>(StoreKey.currentUser)!.isarId;
final userId = Store.get(StoreKey.currentUser).isarId;
if (album.owner.value?.isarId == userId) {
await _apiService.albumApi.deleteAlbum(album.remoteId!);
}

View File

@@ -2,10 +2,9 @@ import 'package:auto_route/auto_route.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:immich_mobile/constants/hive_box.dart';
import 'package:immich_mobile/routing/router.dart';
import 'package:immich_mobile/shared/models/album.dart';
import 'package:immich_mobile/shared/models/store.dart';
import 'package:immich_mobile/utils/image_url_builder.dart';
import 'package:openapi/api.dart';
@@ -21,7 +20,6 @@ class AlbumThumbnailListTile extends StatelessWidget {
@override
Widget build(BuildContext context) {
var box = Hive.box(userInfoBox);
var cardSize = 68.0;
var isDarkMode = Theme.of(context).brightness == Brightness.dark;
@@ -50,7 +48,9 @@ class AlbumThumbnailListTile extends StatelessWidget {
album,
type: ThumbnailFormat.JPEG,
),
httpHeaders: {"Authorization": "Bearer ${box.get(accessTokenKey)}"},
httpHeaders: {
"Authorization": "Bearer ${Store.get(StoreKey.accessToken)}"
},
cacheKey: getAlbumThumbNailCacheKey(album, type: ThumbnailFormat.JPEG),
errorWidget: (context, url, error) =>
const Icon(Icons.image_not_supported_outlined),

View File

@@ -4,16 +4,15 @@ import 'package:auto_route/auto_route.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hive/hive.dart';
import 'package:flutter_hooks/flutter_hooks.dart' hide Store;
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/hive_box.dart';
import 'package:immich_mobile/modules/album/ui/add_to_album_bottom_sheet.dart';
import 'package:immich_mobile/modules/asset_viewer/providers/image_viewer_page_state.provider.dart';
import 'package:immich_mobile/modules/asset_viewer/ui/exif_bottom_sheet.dart';
import 'package:immich_mobile/modules/asset_viewer/ui/top_control_app_bar.dart';
import 'package:immich_mobile/modules/asset_viewer/views/video_viewer_page.dart';
import 'package:immich_mobile/modules/favorite/providers/favorite_provider.dart';
import 'package:immich_mobile/shared/models/store.dart';
import 'package:immich_mobile/shared/services/asset.service.dart';
import 'package:immich_mobile/modules/home/ui/delete_dialog.dart';
import 'package:immich_mobile/modules/settings/providers/app_settings.provider.dart';
@@ -47,7 +46,6 @@ class GalleryViewerPage extends HookConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final Box<dynamic> box = Hive.box(userInfoBox);
final settings = ref.watch(appSettingsServiceProvider);
final isLoadPreview = useState(AppSettingsEnum.loadPreview.defaultValue);
final isLoadOriginal = useState(AppSettingsEnum.loadOriginal.defaultValue);
@@ -57,7 +55,7 @@ class GalleryViewerPage extends HookConsumerWidget {
final isPlayingMotionVideo = useState(false);
final isPlayingVideo = useState(false);
late Offset localPosition;
final authToken = 'Bearer ${box.get(accessTokenKey)}';
final authToken = 'Bearer ${Store.get(StoreKey.accessToken)}';
showAppBar.addListener(() {
// Change to and from immersive mode, hiding navigation and app bar

View File

@@ -1,13 +1,12 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/hive_box.dart';
import 'package:chewie/chewie.dart';
import 'package:immich_mobile/modules/asset_viewer/models/image_viewer_page_state.model.dart';
import 'package:immich_mobile/modules/asset_viewer/providers/image_viewer_page_state.provider.dart';
import 'package:immich_mobile/shared/models/asset.dart';
import 'package:immich_mobile/shared/models/store.dart';
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
import 'package:photo_manager/photo_manager.dart';
import 'package:video_player/video_player.dart';
@@ -54,17 +53,15 @@ class VideoViewerPage extends HookConsumerWidget {
}
final downloadAssetStatus =
ref.watch(imageViewerStateProvider).downloadAssetStatus;
final box = Hive.box(userInfoBox);
final String jwtToken = box.get(accessTokenKey);
final String videoUrl = isMotionVideo
? '${box.get(serverEndpointKey)}/asset/file/${asset.livePhotoVideoId}'
: '${box.get(serverEndpointKey)}/asset/file/${asset.remoteId}';
? '${Store.get(StoreKey.serverEndpoint)}/asset/file/${asset.livePhotoVideoId}'
: '${Store.get(StoreKey.serverEndpoint)}/asset/file/${asset.remoteId}';
return Stack(
children: [
VideoThumbnailPlayer(
url: videoUrl,
jwtToken: jwtToken,
jwtToken: Store.get(StoreKey.accessToken),
isMotionVideo: isMotionVideo,
onVideoEnded: onVideoEnded,
onPaused: onPaused,

View File

@@ -8,16 +8,13 @@ import 'package:collection/collection.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/hive_box.dart';
import 'package:immich_mobile/main.dart';
import 'package:immich_mobile/modules/backup/background_service/localization.dart';
import 'package:immich_mobile/modules/backup/models/backup_album.model.dart';
import 'package:immich_mobile/modules/backup/models/current_upload_asset.model.dart';
import 'package:immich_mobile/modules/backup/models/error_upload_asset.model.dart';
import 'package:immich_mobile/modules/backup/services/backup.service.dart';
import 'package:immich_mobile/modules/login/models/hive_saved_login_info.model.dart';
import 'package:immich_mobile/modules/settings/services/app_settings.service.dart';
import 'package:immich_mobile/shared/models/store.dart';
import 'package:immich_mobile/shared/services/api.service.dart';
@@ -317,7 +314,6 @@ class BackgroundService {
debugPrint(error.toString());
return false;
} finally {
await Hive.close();
releaseLock();
}
case "systemStop":
@@ -332,17 +328,9 @@ class BackgroundService {
Future<bool> _onAssetsChanged() async {
final Isar db = await loadDb();
await Hive.initFlutter();
Hive.registerAdapter(HiveSavedLoginInfoAdapter());
await Future.wait([
Hive.openBox(userInfoBox),
Hive.openBox<HiveSavedLoginInfo>(hiveLoginInfoBox),
Hive.openBox(userSettingInfoBox),
]);
ApiService apiService = ApiService();
apiService.setAccessToken(Hive.box(userInfoBox).get(accessTokenKey));
apiService.setAccessToken(Store.get(StoreKey.accessToken));
BackupService backupService = BackupService(apiService, db);
AppSettingsService settingsService = AppSettingsService();
@@ -387,7 +375,7 @@ class BackgroundService {
db.backupAlbums.deleteAllSync(toDelete);
db.backupAlbums.putAllSync(toUpsert);
});
} else if (Store.get(StoreKey.backupFailedSince) == null) {
} else if (Store.tryGet(StoreKey.backupFailedSince) == null) {
Store.put(StoreKey.backupFailedSince, DateTime.now());
return false;
}
@@ -529,7 +517,7 @@ class BackgroundService {
} else if (value == 5) {
return false;
}
final DateTime? failedSince = Store.get(StoreKey.backupFailedSince);
final DateTime? failedSince = Store.tryGet(StoreKey.backupFailedSince);
if (failedSince == null) {
return false;
}

View File

@@ -1,9 +1,7 @@
import 'package:cancellation_token_http/http.dart';
import 'package:collection/collection.dart';
import 'package:flutter/widgets.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/hive_box.dart';
import 'package:immich_mobile/modules/backup/models/available_album.model.dart';
import 'package:immich_mobile/modules/backup/models/backup_album.model.dart';
import 'package:immich_mobile/modules/backup/models/backup_state.model.dart';
@@ -42,9 +40,10 @@ class BackupNotifier extends StateNotifier<BackUpState> {
progressInPercentage: 0,
cancelToken: CancellationToken(),
backgroundBackup: false,
backupRequireWifi: true,
backupRequireCharging: false,
backupTriggerDelay: 5000,
backupRequireWifi: Store.get(StoreKey.backupRequireWifi, true),
backupRequireCharging:
Store.get(StoreKey.backupRequireCharging, false),
backupTriggerDelay: Store.get(StoreKey.backupTriggerDelay, 5000),
serverInfo: ServerInfoResponseDto(
diskAvailable: "0",
diskAvailableRaw: 0,
@@ -163,14 +162,12 @@ class BackupNotifier extends StateNotifier<BackUpState> {
triggerMaxDelay: state.backupTriggerDelay * 10,
);
if (success) {
await Future.wait([
Store.put(StoreKey.backupRequireWifi, state.backupRequireWifi),
Store.put(
StoreKey.backupRequireCharging,
state.backupRequireCharging,
),
Store.put(StoreKey.backupTriggerDelay, state.backupTriggerDelay),
]);
await Store.put(StoreKey.backupRequireWifi, state.backupRequireWifi);
await Store.put(
StoreKey.backupRequireCharging,
state.backupRequireCharging,
);
await Store.put(StoreKey.backupTriggerDelay, state.backupTriggerDelay);
} else {
state = state.copyWith(
backgroundBackup: wasEnabled,
@@ -544,7 +541,7 @@ class BackupNotifier extends StateNotifier<BackUpState> {
Future<void> _resumeBackup() async {
// Check if user is login
final accessKey = Hive.box(userInfoBox).get(accessTokenKey);
final accessKey = Store.tryGet(StoreKey.accessToken);
// User has been logged out return
if (accessKey == null || !_authState.isAuthenticated) {
@@ -603,9 +600,6 @@ class BackupNotifier extends StateNotifier<BackUpState> {
backupProgress: BackUpProgressEnum.inBackground,
selectedBackupAlbums: selectedAlbums,
excludedBackupAlbums: excludedAlbums,
backupRequireWifi: Store.get(StoreKey.backupRequireWifi),
backupRequireCharging: Store.get(StoreKey.backupRequireCharging),
backupTriggerDelay: Store.get(StoreKey.backupTriggerDelay),
);
// assumes the background service is currently running
// if true, waits until it has stopped to start the backup

View File

@@ -5,13 +5,12 @@ import 'dart:io';
import 'package:cancellation_token_http/http.dart';
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/hive_box.dart';
import 'package:immich_mobile/modules/backup/models/backup_album.model.dart';
import 'package:immich_mobile/modules/backup/models/current_upload_asset.model.dart';
import 'package:immich_mobile/modules/backup/models/duplicated_asset.model.dart';
import 'package:immich_mobile/modules/backup/models/error_upload_asset.model.dart';
import 'package:immich_mobile/shared/models/store.dart';
import 'package:immich_mobile/shared/providers/api.provider.dart';
import 'package:immich_mobile/shared/providers/db.provider.dart';
import 'package:immich_mobile/shared/services/api.service.dart';
@@ -38,7 +37,7 @@ class BackupService {
BackupService(this._apiService, this._db);
Future<List<String>?> getDeviceBackupAsset() async {
String deviceId = Hive.box(userInfoBox).get(deviceIdKey);
final String deviceId = Store.get(StoreKey.deviceId);
try {
return await _apiService.assetApi.getUserAssetsByDeviceId(deviceId);
@@ -173,7 +172,7 @@ class BackupService {
}
final Set<String> existing = {};
try {
final String deviceId = Hive.box(userInfoBox).get(deviceIdKey);
final String deviceId = Store.get(StoreKey.deviceId);
final CheckExistingAssetsResponseDto? duplicates =
await _apiService.assetApi.checkExistingAssets(
CheckExistingAssetsDto(
@@ -204,8 +203,8 @@ class BackupService {
Function(CurrentUploadAsset) setCurrentUploadAssetCb,
Function(ErrorUploadAsset) errorCb,
) async {
String deviceId = Hive.box(userInfoBox).get(deviceIdKey);
String savedEndpoint = Hive.box(userInfoBox).get(serverEndpointKey);
final String deviceId = Store.get(StoreKey.deviceId);
final String savedEndpoint = Store.get(StoreKey.serverEndpoint);
File? file;
bool anyErrors = false;
final List<String> duplicatedAssetIds = [];
@@ -236,15 +235,14 @@ class BackupService {
),
);
var box = Hive.box(userInfoBox);
var req = MultipartRequest(
'POST',
Uri.parse('$savedEndpoint/asset/upload'),
onProgress: ((bytes, totalBytes) =>
uploadProgressCb(bytes, totalBytes)),
);
req.headers["Authorization"] = "Bearer ${box.get(accessTokenKey)}";
req.headers["Authorization"] =
"Bearer ${Store.get(StoreKey.accessToken)}";
req.fields['deviceAssetId'] = entity.id;
req.fields['deviceId'] = deviceId;

View File

@@ -2,9 +2,7 @@ import 'dart:math';
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/hive_box.dart';
import 'package:immich_mobile/modules/login/models/authentication_state.model.dart';
import 'package:immich_mobile/modules/login/providers/authentication.provider.dart';
@@ -12,6 +10,7 @@ import 'package:immich_mobile/routing/router.dart';
import 'package:immich_mobile/modules/backup/models/backup_state.model.dart';
import 'package:immich_mobile/shared/models/server_info_state.model.dart';
import 'package:immich_mobile/modules/backup/providers/backup.provider.dart';
import 'package:immich_mobile/shared/models/store.dart';
import 'package:immich_mobile/shared/providers/server_info.provider.dart';
import 'package:immich_mobile/shared/ui/transparent_image.dart';
@@ -47,7 +46,7 @@ class HomePageAppBar extends ConsumerWidget with PreferredSizeWidget {
},
);
} else {
String endpoint = Hive.box(userInfoBox).get(serverEndpointKey);
final String? endpoint = Store.get(StoreKey.serverEndpoint);
var dummy = Random().nextInt(1024);
return InkWell(
onTap: () {

View File

@@ -1,14 +1,13 @@
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:flutter_hooks/flutter_hooks.dart' hide Store;
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:image_picker/image_picker.dart';
import 'package:immich_mobile/constants/hive_box.dart';
import 'package:immich_mobile/modules/home/providers/upload_profile_image.provider.dart';
import 'package:immich_mobile/modules/login/models/authentication_state.model.dart';
import 'package:immich_mobile/modules/login/providers/authentication.provider.dart';
import 'package:immich_mobile/shared/models/store.dart';
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
import 'package:immich_mobile/shared/ui/transparent_image.dart';
@@ -19,7 +18,7 @@ class ProfileDrawerHeader extends HookConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
String endpoint = Hive.box(userInfoBox).get(serverEndpointKey);
final String endpoint = Store.get(StoreKey.serverEndpoint);
AuthenticationState authState = ref.watch(authenticationProvider);
final uploadProfileImageStatus =
ref.watch(uploadProfileImageProvider).status;

View File

@@ -2,12 +2,9 @@ import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:hive/hive.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/hive_box.dart';
import 'package:immich_mobile/shared/models/store.dart';
import 'package:immich_mobile/modules/login/models/authentication_state.model.dart';
import 'package:immich_mobile/modules/login/models/hive_saved_login_info.model.dart';
import 'package:immich_mobile/modules/backup/services/backup.service.dart';
import 'package:immich_mobile/shared/models/user.dart';
import 'package:immich_mobile/shared/providers/api.provider.dart';
@@ -91,11 +88,10 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> {
try {
await Future.wait([
_apiService.authenticationApi.logout(),
Hive.box(userInfoBox).delete(accessTokenKey),
Store.delete(StoreKey.assetETag),
Store.delete(StoreKey.userRemoteId),
Store.delete(StoreKey.currentUser),
Hive.box<HiveSavedLoginInfo>(hiveLoginInfoBox).delete(savedLoginInfoKey)
Store.delete(StoreKey.accessToken),
]);
state = state.copyWith(isAuthenticated: false);
@@ -157,14 +153,13 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> {
}
if (userResponseDto != null) {
var userInfoHiveBox = await Hive.openBox(userInfoBox);
var deviceInfo = await _deviceInfoService.getDeviceInfo();
userInfoHiveBox.put(deviceIdKey, deviceInfo["deviceId"]);
userInfoHiveBox.put(accessTokenKey, accessToken);
Store.put(StoreKey.deviceId, deviceInfo["deviceId"]);
Store.put(StoreKey.deviceIdHash, fastHash(deviceInfo["deviceId"]));
Store.put(StoreKey.userRemoteId, userResponseDto.id);
Store.put(StoreKey.currentUser, User.fromDto(userResponseDto));
Store.put(StoreKey.serverUrl, serverUrl);
Store.put(StoreKey.accessToken, accessToken);
state = state.copyWith(
isAuthenticated: true,
@@ -178,17 +173,6 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> {
deviceId: deviceInfo["deviceId"],
deviceType: deviceInfo["deviceType"],
);
// Save login info to local storage
Hive.box<HiveSavedLoginInfo>(hiveLoginInfoBox).put(
savedLoginInfoKey,
HiveSavedLoginInfo(
email: "",
password: "",
serverUrl: serverUrl,
accessToken: accessToken,
),
);
}
// Register device info

View File

@@ -1,14 +1,12 @@
import 'package:auto_route/auto_route.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hive/hive.dart';
import 'package:flutter_hooks/flutter_hooks.dart' hide Store;
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/hive_box.dart';
import 'package:immich_mobile/modules/login/models/hive_saved_login_info.model.dart';
import 'package:immich_mobile/modules/login/providers/oauth.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/models/store.dart';
import 'package:immich_mobile/shared/providers/api.provider.dart';
import 'package:immich_mobile/shared/providers/asset.provider.dart';
import 'package:immich_mobile/modules/login/providers/authentication.provider.dart';
@@ -63,8 +61,7 @@ class LoginForm extends HookConsumerWidget {
try {
isLoadingServer.value = true;
final endpoint =
await apiService.resolveAndSetEndpoint(serverUrl);
final endpoint = await apiService.resolveAndSetEndpoint(serverUrl);
final loginConfig = await apiService.oAuthApi.generateConfig(
OAuthConfigDto(redirectUri: serverUrl),
@@ -104,15 +101,10 @@ class LoginForm extends HookConsumerWidget {
useEffect(
() {
var loginInfo = Hive.box<HiveSavedLoginInfo>(hiveLoginInfoBox)
.get(savedLoginInfoKey);
if (loginInfo != null) {
usernameController.text = loginInfo.email;
passwordController.text = loginInfo.password;
serverEndpointController.text = loginInfo.serverUrl;
final serverUrl = Store.tryGet(StoreKey.serverUrl);
if (serverUrl != null) {
serverEndpointController.text = serverUrl;
}
return null;
},
[],
@@ -133,11 +125,11 @@ class LoginForm extends HookConsumerWidget {
try {
final isAuthenticated =
await ref.read(authenticationProvider.notifier).login(
usernameController.text,
passwordController.text,
serverEndpointController.text.trim(),
);
await ref.read(authenticationProvider.notifier).login(
usernameController.text,
passwordController.text,
serverEndpointController.text.trim(),
);
if (isAuthenticated) {
// Resume backup (if enable) then navigate
if (ref.read(authenticationProvider).shouldChangePassword &&
@@ -283,61 +275,61 @@ class LoginForm extends HookConsumerWidget {
onSubmit: login,
),
// Note: This used to have an AnimatedSwitcher, but was removed
// because of https://github.com/flutter/flutter/issues/120874
isLoading.value
? const Padding(
padding: EdgeInsets.only(top: 18.0),
child: SizedBox(
width: 24,
height: 24,
child: FittedBox(
child: CircularProgressIndicator(
strokeWidth: 2,
// Note: This used to have an AnimatedSwitcher, but was removed
// because of https://github.com/flutter/flutter/issues/120874
isLoading.value
? const Padding(
padding: EdgeInsets.only(top: 18.0),
child: SizedBox(
width: 24,
height: 24,
child: FittedBox(
child: CircularProgressIndicator(
strokeWidth: 2,
),
),
),
),
)
: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(height: 18),
LoginButton(onPressed: login),
if (isOauthEnable.value) ...[
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16.0,
)
: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(height: 18),
LoginButton(onPressed: login),
if (isOauthEnable.value) ...[
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16.0,
),
child: Divider(
color:
Brightness.dark == Theme.of(context).brightness
? Colors.white
: Colors.black,
),
),
child: Divider(
color:
Brightness.dark == Theme.of(context).brightness
? Colors.white
: Colors.black,
OAuthLoginButton(
serverEndpointController: serverEndpointController,
buttonLabel: oAuthButtonLabel.value,
isLoading: isLoading,
onPressed: oAuthLogin,
),
),
OAuthLoginButton(
serverEndpointController: serverEndpointController,
buttonLabel: oAuthButtonLabel.value,
isLoading: isLoading,
onPressed: oAuthLogin,
),
],
],
],
),
const SizedBox(height: 12),
TextButton.icon(
icon: const Icon(Icons.arrow_back),
onPressed: () => serverEndpoint.value = null,
label: const Text('Back'),
),
),
const SizedBox(height: 12),
TextButton.icon(
icon: const Icon(Icons.arrow_back),
onPressed: () => serverEndpoint.value = null,
label: const Text('Back'),
),
],
),
);
}
final serverSelectionOrLogin = serverEndpoint.value == null
? buildSelectServer()
: buildLogin();
final serverSelectionOrLogin =
serverEndpoint.value == null ? buildSelectServer() : buildLogin();
return LayoutBuilder(
builder: (context, constraints) {
@@ -545,7 +537,6 @@ class OAuthLoginButton extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
return ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: Theme.of(context).primaryColor.withAlpha(230),

View File

@@ -1,7 +1,6 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:immich_mobile/constants/hive_box.dart';
import 'package:immich_mobile/shared/models/store.dart';
class ThumbnailWithInfo extends StatelessWidget {
const ThumbnailWithInfo({
@@ -19,7 +18,6 @@ class ThumbnailWithInfo extends StatelessWidget {
@override
Widget build(BuildContext context) {
var box = Hive.box(userInfoBox);
var isDarkMode = Theme.of(context).brightness == Brightness.dark;
var textAndIconColor = isDarkMode ? Colors.grey[100] : Colors.grey[700];
return GestureDetector(
@@ -51,7 +49,8 @@ class ThumbnailWithInfo extends StatelessWidget {
fit: BoxFit.cover,
imageUrl: imageUrl!,
httpHeaders: {
"Authorization": "Bearer ${box.get(accessTokenKey)}"
"Authorization":
"Bearer ${Store.get(StoreKey.accessToken)}"
},
errorWidget: (context, url, error) =>
const Icon(Icons.image_not_supported_outlined),

View File

@@ -1,15 +1,14 @@
import 'package:auto_route/auto_route.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:flutter_hooks/flutter_hooks.dart' hide Store;
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/hive_box.dart';
import 'package:immich_mobile/modules/search/providers/search_page_state.provider.dart';
import 'package:immich_mobile/modules/search/ui/search_bar.dart';
import 'package:immich_mobile/modules/search/ui/search_suggestion_list.dart';
import 'package:immich_mobile/modules/search/ui/thumbnail_with_info.dart';
import 'package:immich_mobile/routing/router.dart';
import 'package:immich_mobile/shared/models/store.dart';
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
import 'package:immich_mobile/utils/capitalize_first_letter.dart';
import 'package:openapi/api.dart';
@@ -22,7 +21,6 @@ class SearchPage extends HookConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
var box = Hive.box(userInfoBox);
final isSearchEnabled = ref.watch(searchPageStateProvider).isSearchEnabled;
AsyncValue<List<CuratedLocationsResponseDto>> curatedLocation =
ref.watch(getCuratedLocationProvider);
@@ -64,7 +62,7 @@ class SearchPage extends HookConsumerWidget {
itemBuilder: ((context, index) {
var locationInfo = curatedLocations[index];
var thumbnailRequestUrl =
'${box.get(serverEndpointKey)}/asset/thumbnail/${locationInfo.id}';
'${Store.get(StoreKey.serverEndpoint)}/asset/thumbnail/${locationInfo.id}';
return ThumbnailWithInfo(
imageUrl: thumbnailRequestUrl,
textInfo: locationInfo.city,
@@ -113,7 +111,7 @@ class SearchPage extends HookConsumerWidget {
itemBuilder: ((context, index) {
var curatedObjectInfo = objects[index];
var thumbnailRequestUrl =
'${box.get(serverEndpointKey)}/asset/thumbnail/${curatedObjectInfo.id}';
'${Store.get(StoreKey.serverEndpoint)}/asset/thumbnail/${curatedObjectInfo.id}';
return ThumbnailWithInfo(
imageUrl: thumbnailRequestUrl,

View File

@@ -1,59 +1,63 @@
import 'package:hive_flutter/hive_flutter.dart';
import 'package:immich_mobile/constants/hive_box.dart';
import 'package:immich_mobile/shared/models/store.dart';
enum AppSettingsEnum<T> {
loadPreview<bool>("loadPreview", true),
loadOriginal<bool>("loadOriginal", false),
themeMode<String>("themeMode", "system"), // "light","dark","system"
tilesPerRow<int>("tilesPerRow", 4),
dynamicLayout<bool>("dynamicLayout", false),
groupAssetsBy<int>("groupBy", 0),
loadPreview<bool>(StoreKey.loadPreview, "loadPreview", true),
loadOriginal<bool>(StoreKey.loadOriginal, "loadOriginal", false),
themeMode<String>(
StoreKey.themeMode,
"themeMode",
"system",
), // "light","dark","system"
tilesPerRow<int>(StoreKey.tilesPerRow, "tilesPerRow", 4),
dynamicLayout<bool>(StoreKey.dynamicLayout, "dynamicLayout", false),
groupAssetsBy<int>(StoreKey.groupAssetsBy, "groupBy", 0),
uploadErrorNotificationGracePeriod<int>(
StoreKey.uploadErrorNotificationGracePeriod,
"uploadErrorNotificationGracePeriod",
2,
),
backgroundBackupTotalProgress<bool>("backgroundBackupTotalProgress", true),
backgroundBackupSingleProgress<bool>("backgroundBackupSingleProgress", false),
storageIndicator<bool>("storageIndicator", true),
thumbnailCacheSize<int>("thumbnailCacheSize", 10000),
imageCacheSize<int>("imageCacheSize", 350),
albumThumbnailCacheSize<int>("albumThumbnailCacheSize", 200),
useExperimentalAssetGrid<bool>("useExperimentalAssetGrid", false),
selectedAlbumSortOrder<int>("selectedAlbumSortOrder", 0);
backgroundBackupTotalProgress<bool>(
StoreKey.backgroundBackupTotalProgress,
"backgroundBackupTotalProgress",
true,
),
backgroundBackupSingleProgress<bool>(
StoreKey.backgroundBackupSingleProgress,
"backgroundBackupSingleProgress",
false,
),
storageIndicator<bool>(StoreKey.storageIndicator, "storageIndicator", true),
thumbnailCacheSize<int>(
StoreKey.thumbnailCacheSize,
"thumbnailCacheSize",
10000,
),
imageCacheSize<int>(StoreKey.imageCacheSize, "imageCacheSize", 350),
albumThumbnailCacheSize<int>(
StoreKey.albumThumbnailCacheSize,
"albumThumbnailCacheSize",
200,
),
selectedAlbumSortOrder<int>(
StoreKey.selectedAlbumSortOrder,
"selectedAlbumSortOrder",
0,
),
;
const AppSettingsEnum(this.hiveKey, this.defaultValue);
const AppSettingsEnum(this.storeKey, this.hiveKey, this.defaultValue);
final StoreKey<T> storeKey;
final String hiveKey;
final T defaultValue;
}
class AppSettingsService {
late final Box hiveBox;
AppSettingsService() {
hiveBox = Hive.box(userSettingInfoBox);
T getSetting<T>(AppSettingsEnum<T> setting) {
return Store.get(setting.storeKey, setting.defaultValue);
}
T getSetting<T>(AppSettingsEnum<T> settingType) {
if (!hiveBox.containsKey(settingType.hiveKey)) {
return _setDefault(settingType);
}
var result = hiveBox.get(settingType.hiveKey);
if (result is! T) {
return _setDefault(settingType);
}
return result;
}
setSetting<T>(AppSettingsEnum<T> settingType, T value) {
hiveBox.put(settingType.hiveKey, value);
}
T _setDefault<T>(AppSettingsEnum<T> settingType) {
hiveBox.put(settingType.hiveKey, settingType.defaultValue);
return settingType.defaultValue;
void setSetting<T>(AppSettingsEnum<T> setting, T value) {
Store.put(setting.storeKey, value);
}
}