chore: bump dart sdk to 3.8 (#20355)
* chore: bump dart sdk to 3.8 * chore: make build * make pigeon * chore: format files --------- Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
This commit is contained in:
@@ -36,12 +36,9 @@ class AlbumActivity extends _$AlbumActivity {
|
||||
}
|
||||
|
||||
Future<void> addComment(String comment) async {
|
||||
final activity = await ref.watch(activityServiceProvider).addActivity(
|
||||
albumId,
|
||||
ActivityType.comment,
|
||||
assetId: assetId,
|
||||
comment: comment,
|
||||
);
|
||||
final activity = await ref
|
||||
.watch(activityServiceProvider)
|
||||
.addActivity(albumId, ActivityType.comment, assetId: assetId, comment: comment);
|
||||
|
||||
if (activity.hasValue) {
|
||||
final activities = state.valueOrNull ?? [];
|
||||
|
||||
+30
-47
@@ -34,10 +34,7 @@ abstract class _$AlbumActivity
|
||||
late final String albumId;
|
||||
late final String? assetId;
|
||||
|
||||
FutureOr<List<Activity>> build(
|
||||
String albumId, [
|
||||
String? assetId,
|
||||
]);
|
||||
FutureOr<List<Activity>> build(String albumId, [String? assetId]);
|
||||
}
|
||||
|
||||
/// Maintains the current list of all activities for <share-album-id, asset>
|
||||
@@ -58,24 +55,15 @@ class AlbumActivityFamily extends Family<AsyncValue<List<Activity>>> {
|
||||
/// Maintains the current list of all activities for <share-album-id, asset>
|
||||
///
|
||||
/// Copied from [AlbumActivity].
|
||||
AlbumActivityProvider call(
|
||||
String albumId, [
|
||||
String? assetId,
|
||||
]) {
|
||||
return AlbumActivityProvider(
|
||||
albumId,
|
||||
assetId,
|
||||
);
|
||||
AlbumActivityProvider call(String albumId, [String? assetId]) {
|
||||
return AlbumActivityProvider(albumId, assetId);
|
||||
}
|
||||
|
||||
@override
|
||||
AlbumActivityProvider getProviderOverride(
|
||||
covariant AlbumActivityProvider provider,
|
||||
) {
|
||||
return call(
|
||||
provider.albumId,
|
||||
provider.assetId,
|
||||
);
|
||||
return call(provider.albumId, provider.assetId);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
@@ -96,30 +84,28 @@ class AlbumActivityFamily extends Family<AsyncValue<List<Activity>>> {
|
||||
/// Maintains the current list of all activities for <share-album-id, asset>
|
||||
///
|
||||
/// Copied from [AlbumActivity].
|
||||
class AlbumActivityProvider extends AutoDisposeAsyncNotifierProviderImpl<
|
||||
AlbumActivity, List<Activity>> {
|
||||
class AlbumActivityProvider
|
||||
extends
|
||||
AutoDisposeAsyncNotifierProviderImpl<AlbumActivity, List<Activity>> {
|
||||
/// Maintains the current list of all activities for <share-album-id, asset>
|
||||
///
|
||||
/// Copied from [AlbumActivity].
|
||||
AlbumActivityProvider(
|
||||
String albumId, [
|
||||
String? assetId,
|
||||
]) : this._internal(
|
||||
() => AlbumActivity()
|
||||
..albumId = albumId
|
||||
..assetId = assetId,
|
||||
from: albumActivityProvider,
|
||||
name: r'albumActivityProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$albumActivityHash,
|
||||
dependencies: AlbumActivityFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
AlbumActivityFamily._allTransitiveDependencies,
|
||||
albumId: albumId,
|
||||
assetId: assetId,
|
||||
);
|
||||
AlbumActivityProvider(String albumId, [String? assetId])
|
||||
: this._internal(
|
||||
() => AlbumActivity()
|
||||
..albumId = albumId
|
||||
..assetId = assetId,
|
||||
from: albumActivityProvider,
|
||||
name: r'albumActivityProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$albumActivityHash,
|
||||
dependencies: AlbumActivityFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
AlbumActivityFamily._allTransitiveDependencies,
|
||||
albumId: albumId,
|
||||
assetId: assetId,
|
||||
);
|
||||
|
||||
AlbumActivityProvider._internal(
|
||||
super._createNotifier, {
|
||||
@@ -136,13 +122,8 @@ class AlbumActivityProvider extends AutoDisposeAsyncNotifierProviderImpl<
|
||||
final String? assetId;
|
||||
|
||||
@override
|
||||
FutureOr<List<Activity>> runNotifierBuild(
|
||||
covariant AlbumActivity notifier,
|
||||
) {
|
||||
return notifier.build(
|
||||
albumId,
|
||||
assetId,
|
||||
);
|
||||
FutureOr<List<Activity>> runNotifierBuild(covariant AlbumActivity notifier) {
|
||||
return notifier.build(albumId, assetId);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -166,7 +147,7 @@ class AlbumActivityProvider extends AutoDisposeAsyncNotifierProviderImpl<
|
||||
|
||||
@override
|
||||
AutoDisposeAsyncNotifierProviderElement<AlbumActivity, List<Activity>>
|
||||
createElement() {
|
||||
createElement() {
|
||||
return _AlbumActivityProviderElement(this);
|
||||
}
|
||||
|
||||
@@ -198,8 +179,9 @@ mixin AlbumActivityRef on AutoDisposeAsyncNotifierProviderRef<List<Activity>> {
|
||||
}
|
||||
|
||||
class _AlbumActivityProviderElement
|
||||
extends AutoDisposeAsyncNotifierProviderElement<AlbumActivity,
|
||||
List<Activity>> with AlbumActivityRef {
|
||||
extends
|
||||
AutoDisposeAsyncNotifierProviderElement<AlbumActivity, List<Activity>>
|
||||
with AlbumActivityRef {
|
||||
_AlbumActivityProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
@@ -207,5 +189,6 @@ class _AlbumActivityProviderElement
|
||||
@override
|
||||
String? get assetId => (origin as AlbumActivityProvider).assetId;
|
||||
}
|
||||
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
|
||||
+23
-42
@@ -34,10 +34,7 @@ abstract class _$ActivityStatistics extends BuildlessAutoDisposeNotifier<int> {
|
||||
late final String albumId;
|
||||
late final String? assetId;
|
||||
|
||||
int build(
|
||||
String albumId, [
|
||||
String? assetId,
|
||||
]);
|
||||
int build(String albumId, [String? assetId]);
|
||||
}
|
||||
|
||||
/// Maintains the current number of comments by <shared-album, asset>
|
||||
@@ -58,24 +55,15 @@ class ActivityStatisticsFamily extends Family<int> {
|
||||
/// Maintains the current number of comments by <shared-album, asset>
|
||||
///
|
||||
/// Copied from [ActivityStatistics].
|
||||
ActivityStatisticsProvider call(
|
||||
String albumId, [
|
||||
String? assetId,
|
||||
]) {
|
||||
return ActivityStatisticsProvider(
|
||||
albumId,
|
||||
assetId,
|
||||
);
|
||||
ActivityStatisticsProvider call(String albumId, [String? assetId]) {
|
||||
return ActivityStatisticsProvider(albumId, assetId);
|
||||
}
|
||||
|
||||
@override
|
||||
ActivityStatisticsProvider getProviderOverride(
|
||||
covariant ActivityStatisticsProvider provider,
|
||||
) {
|
||||
return call(
|
||||
provider.albumId,
|
||||
provider.assetId,
|
||||
);
|
||||
return call(provider.albumId, provider.assetId);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
@@ -101,25 +89,22 @@ class ActivityStatisticsProvider
|
||||
/// Maintains the current number of comments by <shared-album, asset>
|
||||
///
|
||||
/// Copied from [ActivityStatistics].
|
||||
ActivityStatisticsProvider(
|
||||
String albumId, [
|
||||
String? assetId,
|
||||
]) : this._internal(
|
||||
() => ActivityStatistics()
|
||||
..albumId = albumId
|
||||
..assetId = assetId,
|
||||
from: activityStatisticsProvider,
|
||||
name: r'activityStatisticsProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$activityStatisticsHash,
|
||||
dependencies: ActivityStatisticsFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
ActivityStatisticsFamily._allTransitiveDependencies,
|
||||
albumId: albumId,
|
||||
assetId: assetId,
|
||||
);
|
||||
ActivityStatisticsProvider(String albumId, [String? assetId])
|
||||
: this._internal(
|
||||
() => ActivityStatistics()
|
||||
..albumId = albumId
|
||||
..assetId = assetId,
|
||||
from: activityStatisticsProvider,
|
||||
name: r'activityStatisticsProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$activityStatisticsHash,
|
||||
dependencies: ActivityStatisticsFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
ActivityStatisticsFamily._allTransitiveDependencies,
|
||||
albumId: albumId,
|
||||
assetId: assetId,
|
||||
);
|
||||
|
||||
ActivityStatisticsProvider._internal(
|
||||
super._createNotifier, {
|
||||
@@ -136,13 +121,8 @@ class ActivityStatisticsProvider
|
||||
final String? assetId;
|
||||
|
||||
@override
|
||||
int runNotifierBuild(
|
||||
covariant ActivityStatistics notifier,
|
||||
) {
|
||||
return notifier.build(
|
||||
albumId,
|
||||
assetId,
|
||||
);
|
||||
int runNotifierBuild(covariant ActivityStatistics notifier) {
|
||||
return notifier.build(albumId, assetId);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -206,5 +186,6 @@ class _ActivityStatisticsProviderElement
|
||||
@override
|
||||
String? get assetId => (origin as ActivityStatisticsProvider).assetId;
|
||||
}
|
||||
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
|
||||
@@ -35,31 +35,15 @@ class AlbumNotifier extends StateNotifier<List<Album>> {
|
||||
|
||||
Future<bool> deleteAlbum(Album album) => albumService.deleteAlbum(album);
|
||||
|
||||
Future<Album?> createAlbum(
|
||||
String albumTitle,
|
||||
Set<Asset> assets,
|
||||
) =>
|
||||
albumService.createAlbum(albumTitle, assets, []);
|
||||
Future<Album?> createAlbum(String albumTitle, Set<Asset> assets) => albumService.createAlbum(albumTitle, assets, []);
|
||||
|
||||
Future<Album?> getAlbumByName(
|
||||
String albumName, {
|
||||
bool? remote,
|
||||
bool? shared,
|
||||
bool? owner,
|
||||
}) =>
|
||||
albumService.getAlbumByName(
|
||||
albumName,
|
||||
remote: remote,
|
||||
shared: shared,
|
||||
owner: owner,
|
||||
);
|
||||
Future<Album?> getAlbumByName(String albumName, {bool? remote, bool? shared, bool? owner}) =>
|
||||
albumService.getAlbumByName(albumName, remote: remote, shared: shared, owner: owner);
|
||||
|
||||
/// Create an album on the server with the same name as the selected album for backup
|
||||
/// First this will check if the album already exists on the server with name
|
||||
/// If it does not exist, it will create the album on the server
|
||||
Future<void> createSyncAlbum(
|
||||
String albumName,
|
||||
) async {
|
||||
Future<void> createSyncAlbum(String albumName) async {
|
||||
final album = await getAlbumByName(albumName, remote: true, owner: true);
|
||||
if (album != null) {
|
||||
return;
|
||||
@@ -105,10 +89,7 @@ class AlbumNotifier extends StateNotifier<List<Album>> {
|
||||
return await albumService.removeAsset(album, assets);
|
||||
}
|
||||
|
||||
Future<bool> setActivitystatus(
|
||||
Album album,
|
||||
bool enabled,
|
||||
) {
|
||||
Future<bool> setActivitystatus(Album album, bool enabled) {
|
||||
return albumService.setActivityStatus(album, enabled);
|
||||
}
|
||||
|
||||
@@ -126,10 +107,7 @@ class AlbumNotifier extends StateNotifier<List<Album>> {
|
||||
}
|
||||
|
||||
final albumProvider = StateNotifierProvider.autoDispose<AlbumNotifier, List<Album>>((ref) {
|
||||
return AlbumNotifier(
|
||||
ref.watch(albumServiceProvider),
|
||||
ref,
|
||||
);
|
||||
return AlbumNotifier(ref.watch(albumServiceProvider), ref);
|
||||
});
|
||||
|
||||
final albumWatcher = StreamProvider.autoDispose.family<Album, int>((ref, id) async* {
|
||||
|
||||
@@ -75,22 +75,10 @@ class _AlbumSortHandlers {
|
||||
enum AlbumSortMode {
|
||||
title(1, "library_page_sort_title", _AlbumSortHandlers.title),
|
||||
assetCount(4, "library_page_sort_asset_count", _AlbumSortHandlers.assetCount),
|
||||
lastModified(
|
||||
3,
|
||||
"library_page_sort_last_modified",
|
||||
_AlbumSortHandlers.lastModified,
|
||||
),
|
||||
lastModified(3, "library_page_sort_last_modified", _AlbumSortHandlers.lastModified),
|
||||
created(0, "library_page_sort_created", _AlbumSortHandlers.created),
|
||||
mostRecent(
|
||||
2,
|
||||
"sort_recent",
|
||||
_AlbumSortHandlers.mostRecent,
|
||||
),
|
||||
mostOldest(
|
||||
5,
|
||||
"sort_oldest",
|
||||
_AlbumSortHandlers.mostOldest,
|
||||
);
|
||||
mostRecent(2, "sort_recent", _AlbumSortHandlers.mostRecent),
|
||||
mostOldest(5, "sort_oldest", _AlbumSortHandlers.mostOldest);
|
||||
|
||||
final int storeIndex;
|
||||
final String label;
|
||||
@@ -104,18 +92,12 @@ class AlbumSortByOptions extends _$AlbumSortByOptions {
|
||||
@override
|
||||
AlbumSortMode build() {
|
||||
final sortOpt = ref.watch(appSettingsServiceProvider).getSetting(AppSettingsEnum.selectedAlbumSortOrder);
|
||||
return AlbumSortMode.values.firstWhere(
|
||||
(e) => e.storeIndex == sortOpt,
|
||||
orElse: () => AlbumSortMode.title,
|
||||
);
|
||||
return AlbumSortMode.values.firstWhere((e) => e.storeIndex == sortOpt, orElse: () => AlbumSortMode.title);
|
||||
}
|
||||
|
||||
void changeSortMode(AlbumSortMode sortOption) {
|
||||
state = sortOption;
|
||||
ref.watch(appSettingsServiceProvider).setSetting(
|
||||
AppSettingsEnum.selectedAlbumSortOrder,
|
||||
sortOption.storeIndex,
|
||||
);
|
||||
ref.watch(appSettingsServiceProvider).setSetting(AppSettingsEnum.selectedAlbumSortOrder, sortOption.storeIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+16
-16
@@ -13,14 +13,14 @@ String _$albumSortByOptionsHash() =>
|
||||
@ProviderFor(AlbumSortByOptions)
|
||||
final albumSortByOptionsProvider =
|
||||
AutoDisposeNotifierProvider<AlbumSortByOptions, AlbumSortMode>.internal(
|
||||
AlbumSortByOptions.new,
|
||||
name: r'albumSortByOptionsProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$albumSortByOptionsHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
AlbumSortByOptions.new,
|
||||
name: r'albumSortByOptionsProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$albumSortByOptionsHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$AlbumSortByOptions = AutoDisposeNotifier<AlbumSortMode>;
|
||||
String _$albumSortOrderHash() => r'573dea45b4519e69386fc7104c72522e35713440';
|
||||
@@ -29,14 +29,14 @@ String _$albumSortOrderHash() => r'573dea45b4519e69386fc7104c72522e35713440';
|
||||
@ProviderFor(AlbumSortOrder)
|
||||
final albumSortOrderProvider =
|
||||
AutoDisposeNotifierProvider<AlbumSortOrder, bool>.internal(
|
||||
AlbumSortOrder.new,
|
||||
name: r'albumSortOrderProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$albumSortOrderHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
AlbumSortOrder.new,
|
||||
name: r'albumSortOrderProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$albumSortOrderHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$AlbumSortOrder = AutoDisposeNotifier<bool>;
|
||||
// ignore_for_file: type=lint
|
||||
|
||||
@@ -12,6 +12,4 @@ class AlbumTitleNotifier extends StateNotifier<String> {
|
||||
}
|
||||
}
|
||||
|
||||
final albumTitleProvider = StateNotifierProvider<AlbumTitleNotifier, String>(
|
||||
(ref) => AlbumTitleNotifier(),
|
||||
);
|
||||
final albumTitleProvider = StateNotifierProvider<AlbumTitleNotifier, String>((ref) => AlbumTitleNotifier());
|
||||
|
||||
@@ -5,13 +5,7 @@ import 'package:immich_mobile/services/album.service.dart';
|
||||
|
||||
class AlbumViewerNotifier extends StateNotifier<AlbumViewerPageState> {
|
||||
AlbumViewerNotifier(this.ref)
|
||||
: super(
|
||||
const AlbumViewerPageState(
|
||||
editTitleText: "",
|
||||
isEditAlbum: false,
|
||||
editDescriptionText: "",
|
||||
),
|
||||
);
|
||||
: super(const AlbumViewerPageState(editTitleText: "", isEditAlbum: false, editDescriptionText: ""));
|
||||
|
||||
final Ref ref;
|
||||
|
||||
@@ -40,17 +34,10 @@ class AlbumViewerNotifier extends StateNotifier<AlbumViewerPageState> {
|
||||
}
|
||||
|
||||
void resetState() {
|
||||
state = state.copyWith(
|
||||
editTitleText: "",
|
||||
isEditAlbum: false,
|
||||
editDescriptionText: "",
|
||||
);
|
||||
state = state.copyWith(editTitleText: "", isEditAlbum: false, editDescriptionText: "");
|
||||
}
|
||||
|
||||
Future<bool> changeAlbumTitle(
|
||||
Album album,
|
||||
String newAlbumTitle,
|
||||
) async {
|
||||
Future<bool> changeAlbumTitle(Album album, String newAlbumTitle) async {
|
||||
AlbumService service = ref.watch(albumServiceProvider);
|
||||
|
||||
bool isSuccess = await service.changeTitleAlbum(album, newAlbumTitle);
|
||||
@@ -65,16 +52,10 @@ class AlbumViewerNotifier extends StateNotifier<AlbumViewerPageState> {
|
||||
return false;
|
||||
}
|
||||
|
||||
Future<bool> changeAlbumDescription(
|
||||
Album album,
|
||||
String newAlbumDescription,
|
||||
) async {
|
||||
Future<bool> changeAlbumDescription(Album album, String newAlbumDescription) async {
|
||||
AlbumService service = ref.watch(albumServiceProvider);
|
||||
|
||||
bool isSuccess = await service.changeDescriptionAlbum(
|
||||
album,
|
||||
newAlbumDescription,
|
||||
);
|
||||
bool isSuccess = await service.changeDescriptionAlbum(album, newAlbumDescription);
|
||||
|
||||
if (isSuccess) {
|
||||
state = state.copyWith(editDescriptionText: "", isEditAlbum: false);
|
||||
|
||||
+8
-7
@@ -12,13 +12,14 @@ String _$currentAlbumHash() => r'61f00273d6b69da45add1532cc3d3a076ee55110';
|
||||
@ProviderFor(CurrentAlbum)
|
||||
final currentAlbumProvider =
|
||||
AutoDisposeNotifierProvider<CurrentAlbum, Album?>.internal(
|
||||
CurrentAlbum.new,
|
||||
name: r'currentAlbumProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product') ? null : _$currentAlbumHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
CurrentAlbum.new,
|
||||
name: r'currentAlbumProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$currentAlbumHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$CurrentAlbum = AutoDisposeNotifier<Album?>;
|
||||
// ignore_for_file: type=lint
|
||||
|
||||
Generated
+3
-2
@@ -13,8 +13,9 @@ String _$apiServiceHash() => r'187a7de59b064fab1104c23717f18ce0ae3e426c';
|
||||
final apiServiceProvider = Provider<ApiService>.internal(
|
||||
apiService,
|
||||
name: r'apiServiceProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product') ? null : _$apiServiceHash,
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$apiServiceHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@@ -27,14 +27,7 @@ import 'package:isar/isar.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
|
||||
enum AppLifeCycleEnum {
|
||||
active,
|
||||
inactive,
|
||||
paused,
|
||||
resumed,
|
||||
detached,
|
||||
hidden,
|
||||
}
|
||||
enum AppLifeCycleEnum { active, inactive, paused, resumed, detached, hidden }
|
||||
|
||||
class AppLifeCycleNotifier extends StateNotifier<AppLifeCycleEnum> {
|
||||
final Ref _ref;
|
||||
@@ -93,15 +86,13 @@ class AppLifeCycleNotifier extends StateNotifier<AppLifeCycleEnum> {
|
||||
// Ensure proper cleanup before starting new background tasks
|
||||
try {
|
||||
await Future.wait([
|
||||
backgroundManager.syncLocal().then(
|
||||
(_) {
|
||||
Logger("AppLifeCycleNotifier").fine("Hashing assets after syncLocal");
|
||||
// Check if app is still active before hashing
|
||||
if (state == AppLifeCycleEnum.resumed) {
|
||||
backgroundManager.hashAssets();
|
||||
}
|
||||
},
|
||||
),
|
||||
backgroundManager.syncLocal().then((_) {
|
||||
Logger("AppLifeCycleNotifier").fine("Hashing assets after syncLocal");
|
||||
// Check if app is still active before hashing
|
||||
if (state == AppLifeCycleEnum.resumed) {
|
||||
backgroundManager.hashAssets();
|
||||
}
|
||||
}),
|
||||
backgroundManager.syncRemote(),
|
||||
]).then((_) async {
|
||||
final isEnableBackup = _ref.read(appSettingsServiceProvider).getSetting(AppSettingsEnum.enableBackup);
|
||||
@@ -116,11 +107,7 @@ class AppLifeCycleNotifier extends StateNotifier<AppLifeCycleEnum> {
|
||||
}
|
||||
});
|
||||
} catch (e, stackTrace) {
|
||||
Logger("AppLifeCycleNotifier").severe(
|
||||
"Error during background sync",
|
||||
e,
|
||||
stackTrace,
|
||||
);
|
||||
Logger("AppLifeCycleNotifier").severe("Error during background sync", e, stackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -68,9 +68,7 @@ class AssetNotifier extends StateNotifier<bool> {
|
||||
}
|
||||
final bool newRemote = await _assetService.refreshRemoteAssets();
|
||||
final bool newLocal = await _albumService.refreshDeviceAlbums();
|
||||
debugPrint(
|
||||
"changedUsers: $changedUsers, newRemote: $newRemote, newLocal: $newLocal",
|
||||
);
|
||||
debugPrint("changedUsers: $changedUsers, newRemote: $newRemote, newLocal: $newLocal");
|
||||
if (newRemote) {
|
||||
_ref.invalidate(memoryFutureProvider);
|
||||
}
|
||||
@@ -122,17 +120,11 @@ class AssetNotifier extends StateNotifier<bool> {
|
||||
/// Delete remote asset only
|
||||
///
|
||||
/// Default behavior is trashing the asset
|
||||
Future<bool> deleteRemoteAssets(
|
||||
Iterable<Asset> deleteAssets, {
|
||||
bool shouldDeletePermanently = false,
|
||||
}) async {
|
||||
Future<bool> deleteRemoteAssets(Iterable<Asset> deleteAssets, {bool shouldDeletePermanently = false}) async {
|
||||
_deleteInProgress = true;
|
||||
state = true;
|
||||
try {
|
||||
await _assetService.deleteRemoteAssets(
|
||||
deleteAssets,
|
||||
shouldDeletePermanently: shouldDeletePermanently,
|
||||
);
|
||||
await _assetService.deleteRemoteAssets(deleteAssets, shouldDeletePermanently: shouldDeletePermanently);
|
||||
return true;
|
||||
} catch (error) {
|
||||
log.severe("Failed to delete remote assets", error);
|
||||
@@ -143,17 +135,11 @@ class AssetNotifier extends StateNotifier<bool> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> deleteAssets(
|
||||
Iterable<Asset> deleteAssets, {
|
||||
bool force = false,
|
||||
}) async {
|
||||
Future<bool> deleteAssets(Iterable<Asset> deleteAssets, {bool force = false}) async {
|
||||
_deleteInProgress = true;
|
||||
state = true;
|
||||
try {
|
||||
await _assetService.deleteAssets(
|
||||
deleteAssets,
|
||||
shouldDeletePermanently: force,
|
||||
);
|
||||
await _assetService.deleteAssets(deleteAssets, shouldDeletePermanently: force);
|
||||
return true;
|
||||
} catch (error) {
|
||||
log.severe("Failed to delete assets", error);
|
||||
@@ -174,10 +160,7 @@ class AssetNotifier extends StateNotifier<bool> {
|
||||
return _assetService.changeArchiveStatus(assets, status);
|
||||
}
|
||||
|
||||
Future<void> setLockedView(
|
||||
List<Asset> selection,
|
||||
AssetVisibilityEnum visibility,
|
||||
) {
|
||||
Future<void> setLockedView(List<Asset> selection, AssetVisibilityEnum visibility) {
|
||||
return _assetService.setVisibility(selection, visibility);
|
||||
}
|
||||
}
|
||||
|
||||
+39
-38
@@ -30,13 +30,12 @@ class _SystemHash {
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _$AssetPeopleNotifier extends BuildlessAutoDisposeAsyncNotifier<
|
||||
List<PersonWithFacesResponseDto>> {
|
||||
abstract class _$AssetPeopleNotifier
|
||||
extends
|
||||
BuildlessAutoDisposeAsyncNotifier<List<PersonWithFacesResponseDto>> {
|
||||
late final Asset asset;
|
||||
|
||||
FutureOr<List<PersonWithFacesResponseDto>> build(
|
||||
Asset asset,
|
||||
);
|
||||
FutureOr<List<PersonWithFacesResponseDto>> build(Asset asset);
|
||||
}
|
||||
|
||||
/// Maintains the list of people for an asset.
|
||||
@@ -58,21 +57,15 @@ class AssetPeopleNotifierFamily
|
||||
/// Maintains the list of people for an asset.
|
||||
///
|
||||
/// Copied from [AssetPeopleNotifier].
|
||||
AssetPeopleNotifierProvider call(
|
||||
Asset asset,
|
||||
) {
|
||||
return AssetPeopleNotifierProvider(
|
||||
asset,
|
||||
);
|
||||
AssetPeopleNotifierProvider call(Asset asset) {
|
||||
return AssetPeopleNotifierProvider(asset);
|
||||
}
|
||||
|
||||
@override
|
||||
AssetPeopleNotifierProvider getProviderOverride(
|
||||
covariant AssetPeopleNotifierProvider provider,
|
||||
) {
|
||||
return call(
|
||||
provider.asset,
|
||||
);
|
||||
return call(provider.asset);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
@@ -93,26 +86,28 @@ class AssetPeopleNotifierFamily
|
||||
/// Maintains the list of people for an asset.
|
||||
///
|
||||
/// Copied from [AssetPeopleNotifier].
|
||||
class AssetPeopleNotifierProvider extends AutoDisposeAsyncNotifierProviderImpl<
|
||||
AssetPeopleNotifier, List<PersonWithFacesResponseDto>> {
|
||||
class AssetPeopleNotifierProvider
|
||||
extends
|
||||
AutoDisposeAsyncNotifierProviderImpl<
|
||||
AssetPeopleNotifier,
|
||||
List<PersonWithFacesResponseDto>
|
||||
> {
|
||||
/// Maintains the list of people for an asset.
|
||||
///
|
||||
/// Copied from [AssetPeopleNotifier].
|
||||
AssetPeopleNotifierProvider(
|
||||
Asset asset,
|
||||
) : this._internal(
|
||||
() => AssetPeopleNotifier()..asset = asset,
|
||||
from: assetPeopleNotifierProvider,
|
||||
name: r'assetPeopleNotifierProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$assetPeopleNotifierHash,
|
||||
dependencies: AssetPeopleNotifierFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
AssetPeopleNotifierFamily._allTransitiveDependencies,
|
||||
asset: asset,
|
||||
);
|
||||
AssetPeopleNotifierProvider(Asset asset)
|
||||
: this._internal(
|
||||
() => AssetPeopleNotifier()..asset = asset,
|
||||
from: assetPeopleNotifierProvider,
|
||||
name: r'assetPeopleNotifierProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$assetPeopleNotifierHash,
|
||||
dependencies: AssetPeopleNotifierFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
AssetPeopleNotifierFamily._allTransitiveDependencies,
|
||||
asset: asset,
|
||||
);
|
||||
|
||||
AssetPeopleNotifierProvider._internal(
|
||||
super._createNotifier, {
|
||||
@@ -130,9 +125,7 @@ class AssetPeopleNotifierProvider extends AutoDisposeAsyncNotifierProviderImpl<
|
||||
FutureOr<List<PersonWithFacesResponseDto>> runNotifierBuild(
|
||||
covariant AssetPeopleNotifier notifier,
|
||||
) {
|
||||
return notifier.build(
|
||||
asset,
|
||||
);
|
||||
return notifier.build(asset);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -152,8 +145,11 @@ class AssetPeopleNotifierProvider extends AutoDisposeAsyncNotifierProviderImpl<
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeAsyncNotifierProviderElement<AssetPeopleNotifier,
|
||||
List<PersonWithFacesResponseDto>> createElement() {
|
||||
AutoDisposeAsyncNotifierProviderElement<
|
||||
AssetPeopleNotifier,
|
||||
List<PersonWithFacesResponseDto>
|
||||
>
|
||||
createElement() {
|
||||
return _AssetPeopleNotifierProviderElement(this);
|
||||
}
|
||||
|
||||
@@ -180,12 +176,17 @@ mixin AssetPeopleNotifierRef
|
||||
}
|
||||
|
||||
class _AssetPeopleNotifierProviderElement
|
||||
extends AutoDisposeAsyncNotifierProviderElement<AssetPeopleNotifier,
|
||||
List<PersonWithFacesResponseDto>> with AssetPeopleNotifierRef {
|
||||
extends
|
||||
AutoDisposeAsyncNotifierProviderElement<
|
||||
AssetPeopleNotifier,
|
||||
List<PersonWithFacesResponseDto>
|
||||
>
|
||||
with AssetPeopleNotifierRef {
|
||||
_AssetPeopleNotifierProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
Asset get asset => (origin as AssetPeopleNotifierProvider).asset;
|
||||
}
|
||||
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
|
||||
@@ -12,13 +12,14 @@ String _$currentAssetHash() => r'2def10ea594152c984ae2974d687ab6856d7bdd0';
|
||||
@ProviderFor(CurrentAsset)
|
||||
final currentAssetProvider =
|
||||
AutoDisposeNotifierProvider<CurrentAsset, Asset?>.internal(
|
||||
CurrentAsset.new,
|
||||
name: r'currentAssetProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product') ? null : _$currentAssetHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
CurrentAsset.new,
|
||||
name: r'currentAssetProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$currentAssetHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$CurrentAsset = AutoDisposeNotifier<Asset?>;
|
||||
// ignore_for_file: type=lint
|
||||
|
||||
@@ -18,17 +18,14 @@ class DownloadStateNotifier extends StateNotifier<DownloadState> {
|
||||
final ShareService _shareService;
|
||||
final AlbumService _albumService;
|
||||
|
||||
DownloadStateNotifier(
|
||||
this._downloadService,
|
||||
this._shareService,
|
||||
this._albumService,
|
||||
) : super(
|
||||
const DownloadState(
|
||||
downloadStatus: TaskStatus.complete,
|
||||
showProgress: false,
|
||||
taskProgress: <String, DownloadInfo>{},
|
||||
),
|
||||
) {
|
||||
DownloadStateNotifier(this._downloadService, this._shareService, this._albumService)
|
||||
: super(
|
||||
const DownloadState(
|
||||
downloadStatus: TaskStatus.complete,
|
||||
showProgress: false,
|
||||
taskProgress: <String, DownloadInfo>{},
|
||||
),
|
||||
) {
|
||||
_downloadService.onImageDownloadStatus = _downloadImageCallback;
|
||||
_downloadService.onVideoDownloadStatus = _downloadVideoCallback;
|
||||
_downloadService.onLivePhotoDownloadStatus = _downloadLivePhotoCallback;
|
||||
@@ -131,9 +128,7 @@ class DownloadStateNotifier extends StateNotifier<DownloadState> {
|
||||
);
|
||||
|
||||
if (state.taskProgress.isEmpty) {
|
||||
state = state.copyWith(
|
||||
showProgress: false,
|
||||
);
|
||||
state = state.copyWith(showProgress: false);
|
||||
}
|
||||
_albumService.refreshDeviceAlbums();
|
||||
});
|
||||
@@ -159,9 +154,7 @@ class DownloadStateNotifier extends StateNotifier<DownloadState> {
|
||||
}
|
||||
|
||||
if (state.taskProgress.isEmpty) {
|
||||
state = state.copyWith(
|
||||
showProgress: false,
|
||||
);
|
||||
state = state.copyWith(showProgress: false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,19 +162,17 @@ class DownloadStateNotifier extends StateNotifier<DownloadState> {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext buildContext) {
|
||||
_shareService.shareAsset(asset, context).then(
|
||||
(bool status) {
|
||||
if (!status) {
|
||||
ImmichToast.show(
|
||||
context: context,
|
||||
msg: 'image_viewer_page_state_provider_share_error'.tr(),
|
||||
toastType: ToastType.error,
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
}
|
||||
buildContext.pop();
|
||||
},
|
||||
);
|
||||
_shareService.shareAsset(asset, context).then((bool status) {
|
||||
if (!status) {
|
||||
ImmichToast.show(
|
||||
context: context,
|
||||
msg: 'image_viewer_page_state_provider_share_error'.tr(),
|
||||
toastType: ToastType.error,
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
}
|
||||
buildContext.pop();
|
||||
});
|
||||
return const ShareDialog();
|
||||
},
|
||||
barrierDismissible: false,
|
||||
@@ -192,8 +183,8 @@ class DownloadStateNotifier extends StateNotifier<DownloadState> {
|
||||
|
||||
final downloadStateProvider = StateNotifierProvider<DownloadStateNotifier, DownloadState>(
|
||||
((ref) => DownloadStateNotifier(
|
||||
ref.watch(downloadServiceProvider),
|
||||
ref.watch(shareServiceProvider),
|
||||
ref.watch(albumServiceProvider),
|
||||
)),
|
||||
ref.watch(downloadServiceProvider),
|
||||
ref.watch(shareServiceProvider),
|
||||
ref.watch(albumServiceProvider),
|
||||
)),
|
||||
);
|
||||
|
||||
@@ -15,10 +15,10 @@ import 'package:path/path.dart';
|
||||
|
||||
final shareIntentUploadProvider = StateNotifierProvider<ShareIntentUploadStateNotifier, List<ShareIntentAttachment>>(
|
||||
((ref) => ShareIntentUploadStateNotifier(
|
||||
ref.watch(appRouterProvider),
|
||||
ref.watch(uploadServiceProvider),
|
||||
ref.watch(shareIntentServiceProvider),
|
||||
)),
|
||||
ref.watch(appRouterProvider),
|
||||
ref.watch(uploadServiceProvider),
|
||||
ref.watch(shareIntentServiceProvider),
|
||||
)),
|
||||
);
|
||||
|
||||
class ShareIntentUploadStateNotifier extends StateNotifier<List<ShareIntentAttachment>> {
|
||||
@@ -26,11 +26,7 @@ class ShareIntentUploadStateNotifier extends StateNotifier<List<ShareIntentAttac
|
||||
final UploadService _uploadService;
|
||||
final ShareIntentService _shareIntentService;
|
||||
|
||||
ShareIntentUploadStateNotifier(
|
||||
this.router,
|
||||
this._uploadService,
|
||||
this._shareIntentService,
|
||||
) : super([]) {
|
||||
ShareIntentUploadStateNotifier(this.router, this._uploadService, this._shareIntentService) : super([]) {
|
||||
_uploadService.taskStatusStream.listen(_updateUploadStatus);
|
||||
_uploadService.taskProgressStream.listen(_taskProgressCallback);
|
||||
}
|
||||
@@ -83,7 +79,7 @@ class ShareIntentUploadStateNotifier extends StateNotifier<List<ShareIntentAttac
|
||||
TaskStatus.running => UploadStatus.running,
|
||||
TaskStatus.paused => UploadStatus.paused,
|
||||
TaskStatus.notFound => UploadStatus.notFound,
|
||||
TaskStatus.waitingToRetry => UploadStatus.waitingToRetry
|
||||
TaskStatus.waitingToRetry => UploadStatus.waitingToRetry,
|
||||
};
|
||||
|
||||
state = [
|
||||
@@ -106,19 +102,12 @@ class ShareIntentUploadStateNotifier extends StateNotifier<List<ShareIntentAttac
|
||||
}
|
||||
|
||||
Future<void> upload(File file) async {
|
||||
final task = await _buildUploadTask(
|
||||
hash(file.path).toString(),
|
||||
file,
|
||||
);
|
||||
final task = await _buildUploadTask(hash(file.path).toString(), file);
|
||||
|
||||
_uploadService.enqueueTasks([task]);
|
||||
}
|
||||
|
||||
Future<UploadTask> _buildUploadTask(
|
||||
String id,
|
||||
File file, {
|
||||
Map<String, String>? fields,
|
||||
}) async {
|
||||
Future<UploadTask> _buildUploadTask(String id, File file, {Map<String, String>? fields}) async {
|
||||
final serverEndpoint = Store.get(StoreKey.serverEndpoint);
|
||||
final url = Uri.parse('$serverEndpoint/assets').toString();
|
||||
final headers = ApiService.getRequestHeaders();
|
||||
|
||||
@@ -2,11 +2,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/providers/asset_viewer/video_player_value_provider.dart';
|
||||
|
||||
class VideoPlaybackControls {
|
||||
const VideoPlaybackControls({
|
||||
required this.position,
|
||||
required this.pause,
|
||||
this.restarted = false,
|
||||
});
|
||||
const VideoPlaybackControls({required this.position, required this.pause, this.restarted = false});
|
||||
|
||||
final double position;
|
||||
final bool pause;
|
||||
@@ -67,9 +63,9 @@ class VideoPlayerControls extends StateNotifier<VideoPlaybackControls> {
|
||||
|
||||
void restart() {
|
||||
state = const VideoPlaybackControls(position: 0, pause: false, restarted: true);
|
||||
ref.read(videoPlaybackValueProvider.notifier).value = ref.read(videoPlaybackValueProvider.notifier).value.copyWith(
|
||||
state: VideoPlaybackState.playing,
|
||||
position: Duration.zero,
|
||||
);
|
||||
ref.read(videoPlaybackValueProvider.notifier).value = ref
|
||||
.read(videoPlaybackValueProvider.notifier)
|
||||
.value
|
||||
.copyWith(state: VideoPlaybackState.playing, position: Duration.zero);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:native_video_player/native_video_player.dart';
|
||||
|
||||
enum VideoPlaybackState {
|
||||
initializing,
|
||||
paused,
|
||||
playing,
|
||||
buffering,
|
||||
completed,
|
||||
}
|
||||
enum VideoPlaybackState { initializing, paused, playing, buffering, completed }
|
||||
|
||||
class VideoPlaybackValue {
|
||||
/// The current position of the video
|
||||
@@ -22,16 +16,9 @@ class VideoPlaybackValue {
|
||||
/// The volume of the video
|
||||
final double volume;
|
||||
|
||||
const VideoPlaybackValue({
|
||||
required this.position,
|
||||
required this.duration,
|
||||
required this.state,
|
||||
required this.volume,
|
||||
});
|
||||
const VideoPlaybackValue({required this.position, required this.duration, required this.state, required this.volume});
|
||||
|
||||
factory VideoPlaybackValue.fromNativeController(
|
||||
NativeVideoPlayerController controller,
|
||||
) {
|
||||
factory VideoPlaybackValue.fromNativeController(NativeVideoPlayerController controller) {
|
||||
final playbackInfo = controller.playbackInfo;
|
||||
final videoInfo = controller.videoInfo;
|
||||
|
||||
@@ -53,12 +40,7 @@ class VideoPlaybackValue {
|
||||
);
|
||||
}
|
||||
|
||||
VideoPlaybackValue copyWith({
|
||||
Duration? position,
|
||||
Duration? duration,
|
||||
VideoPlaybackState? state,
|
||||
double? volume,
|
||||
}) {
|
||||
VideoPlaybackValue copyWith({Duration? position, Duration? duration, VideoPlaybackState? state, double? volume}) {
|
||||
return VideoPlaybackValue(
|
||||
position: position ?? this.position,
|
||||
duration: duration ?? this.duration,
|
||||
@@ -92,22 +74,12 @@ class VideoPlaybackValueState extends StateNotifier<VideoPlaybackValue> {
|
||||
|
||||
set position(Duration value) {
|
||||
if (state.position == value) return;
|
||||
state = VideoPlaybackValue(
|
||||
position: value,
|
||||
duration: state.duration,
|
||||
state: state.state,
|
||||
volume: state.volume,
|
||||
);
|
||||
state = VideoPlaybackValue(position: value, duration: state.duration, state: state.state, volume: state.volume);
|
||||
}
|
||||
|
||||
set status(VideoPlaybackState value) {
|
||||
if (state.state == value) return;
|
||||
state = VideoPlaybackValue(
|
||||
position: state.position,
|
||||
duration: state.duration,
|
||||
state: value,
|
||||
volume: state.volume,
|
||||
);
|
||||
state = VideoPlaybackValue(position: state.position, duration: state.duration, state: value, volume: state.volume);
|
||||
}
|
||||
|
||||
void reset() {
|
||||
|
||||
@@ -49,16 +49,16 @@ class AuthNotifier extends StateNotifier<AuthState> {
|
||||
this._secureStorageService,
|
||||
this._widgetService,
|
||||
) : super(
|
||||
const AuthState(
|
||||
deviceId: "",
|
||||
userId: "",
|
||||
userEmail: "",
|
||||
name: '',
|
||||
profileImagePath: '',
|
||||
isAdmin: false,
|
||||
isAuthenticated: false,
|
||||
),
|
||||
);
|
||||
const AuthState(
|
||||
deviceId: "",
|
||||
userId: "",
|
||||
userEmail: "",
|
||||
name: '',
|
||||
profileImagePath: '',
|
||||
isAdmin: false,
|
||||
isAuthenticated: false,
|
||||
),
|
||||
);
|
||||
|
||||
Future<String> validateServerUrl(String url) {
|
||||
return _authService.validateServerUrl(url);
|
||||
@@ -118,15 +118,10 @@ class AuthNotifier extends StateNotifier<AuthState> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> saveAuthInfo({
|
||||
required String accessToken,
|
||||
}) async {
|
||||
Future<bool> saveAuthInfo({required String accessToken}) async {
|
||||
await _apiService.setAccessToken(accessToken);
|
||||
|
||||
await _widgetService.writeCredentials(
|
||||
Store.get(StoreKey.serverEndpoint),
|
||||
accessToken,
|
||||
);
|
||||
await _widgetService.writeCredentials(Store.get(StoreKey.serverEndpoint), accessToken);
|
||||
|
||||
// Get the deviceid from the store if it exists, otherwise generate a new one
|
||||
String deviceId = Store.tryGet(StoreKey.deviceId) ?? await FlutterUdid.consistentUdid;
|
||||
@@ -150,21 +145,12 @@ class AuthNotifier extends StateNotifier<AuthState> {
|
||||
_log.severe("Unauthorized access, token likely expired. Logging out.");
|
||||
return false;
|
||||
}
|
||||
_log.severe(
|
||||
"Error getting user information from the server [API EXCEPTION]",
|
||||
stackTrace,
|
||||
);
|
||||
_log.severe("Error getting user information from the server [API EXCEPTION]", stackTrace);
|
||||
} catch (error, stackTrace) {
|
||||
_log.severe(
|
||||
"Error getting user information from the server [CATCH ALL]",
|
||||
error,
|
||||
stackTrace,
|
||||
);
|
||||
_log.severe("Error getting user information from the server [CATCH ALL]", error, stackTrace);
|
||||
|
||||
if (kDebugMode) {
|
||||
debugPrint(
|
||||
"Error getting user information from the server [CATCH ALL] $error $stackTrace",
|
||||
);
|
||||
debugPrint("Error getting user information from the server [CATCH ALL] $error $stackTrace");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,43 +60,38 @@ class BackupNotifier extends StateNotifier<BackUpState> {
|
||||
this._backupAlbumService,
|
||||
this.ref,
|
||||
) : super(
|
||||
BackUpState(
|
||||
backupProgress: BackUpProgressEnum.idle,
|
||||
allAssetsInDatabase: const [],
|
||||
progressInPercentage: 0,
|
||||
progressInFileSize: "0 B / 0 B",
|
||||
progressInFileSpeed: 0,
|
||||
progressInFileSpeeds: const [],
|
||||
progressInFileSpeedUpdateTime: DateTime.now(),
|
||||
progressInFileSpeedUpdateSentBytes: 0,
|
||||
cancelToken: CancellationToken(),
|
||||
autoBackup: Store.get(StoreKey.autoBackup, false),
|
||||
backgroundBackup: Store.get(StoreKey.backgroundBackup, false),
|
||||
backupRequireWifi: Store.get(StoreKey.backupRequireWifi, true),
|
||||
backupRequireCharging: Store.get(StoreKey.backupRequireCharging, false),
|
||||
backupTriggerDelay: Store.get(StoreKey.backupTriggerDelay, 5000),
|
||||
serverInfo: const ServerDiskInfo(
|
||||
diskAvailable: "0",
|
||||
diskSize: "0",
|
||||
diskUse: "0",
|
||||
diskUsagePercentage: 0,
|
||||
),
|
||||
availableAlbums: const [],
|
||||
selectedBackupAlbums: const {},
|
||||
excludedBackupAlbums: const {},
|
||||
allUniqueAssets: const {},
|
||||
selectedAlbumsBackupAssetsIds: const {},
|
||||
currentUploadAsset: CurrentUploadAsset(
|
||||
id: '...',
|
||||
fileCreatedAt: DateTime.parse('2020-10-04'),
|
||||
fileName: '...',
|
||||
fileType: '...',
|
||||
fileSize: 0,
|
||||
iCloudAsset: false,
|
||||
),
|
||||
iCloudDownloadProgress: 0.0,
|
||||
BackUpState(
|
||||
backupProgress: BackUpProgressEnum.idle,
|
||||
allAssetsInDatabase: const [],
|
||||
progressInPercentage: 0,
|
||||
progressInFileSize: "0 B / 0 B",
|
||||
progressInFileSpeed: 0,
|
||||
progressInFileSpeeds: const [],
|
||||
progressInFileSpeedUpdateTime: DateTime.now(),
|
||||
progressInFileSpeedUpdateSentBytes: 0,
|
||||
cancelToken: CancellationToken(),
|
||||
autoBackup: Store.get(StoreKey.autoBackup, false),
|
||||
backgroundBackup: Store.get(StoreKey.backgroundBackup, false),
|
||||
backupRequireWifi: Store.get(StoreKey.backupRequireWifi, true),
|
||||
backupRequireCharging: Store.get(StoreKey.backupRequireCharging, false),
|
||||
backupTriggerDelay: Store.get(StoreKey.backupTriggerDelay, 5000),
|
||||
serverInfo: const ServerDiskInfo(diskAvailable: "0", diskSize: "0", diskUse: "0", diskUsagePercentage: 0),
|
||||
availableAlbums: const [],
|
||||
selectedBackupAlbums: const {},
|
||||
excludedBackupAlbums: const {},
|
||||
allUniqueAssets: const {},
|
||||
selectedAlbumsBackupAssetsIds: const {},
|
||||
currentUploadAsset: CurrentUploadAsset(
|
||||
id: '...',
|
||||
fileCreatedAt: DateTime.parse('2020-10-04'),
|
||||
fileName: '...',
|
||||
fileType: '...',
|
||||
fileSize: 0,
|
||||
iCloudAsset: false,
|
||||
),
|
||||
);
|
||||
iCloudDownloadProgress: 0.0,
|
||||
),
|
||||
);
|
||||
|
||||
final log = Logger('BackupNotifier');
|
||||
final BackupService _backupService;
|
||||
@@ -153,11 +148,7 @@ class BackupNotifier extends StateNotifier<BackUpState> {
|
||||
// disable any backup
|
||||
cancelBackup();
|
||||
setAutoBackup(false);
|
||||
configureBackgroundBackup(
|
||||
enabled: false,
|
||||
onError: (msg) {},
|
||||
onBatteryInfo: () {},
|
||||
);
|
||||
configureBackgroundBackup(enabled: false, onError: (msg) {}, onBatteryInfo: () {});
|
||||
}
|
||||
return _updateBackupAssetCount();
|
||||
}
|
||||
@@ -175,9 +166,7 @@ class BackupNotifier extends StateNotifier<BackUpState> {
|
||||
required void Function(String msg) onError,
|
||||
required void Function() onBatteryInfo,
|
||||
}) async {
|
||||
assert(
|
||||
enabled != null || requireWifi != null || requireCharging != null || triggerDelay != null,
|
||||
);
|
||||
assert(enabled != null || requireWifi != null || requireCharging != null || triggerDelay != null);
|
||||
final bool wasEnabled = state.backgroundBackup;
|
||||
final bool wasWifi = state.backupRequireWifi;
|
||||
final bool wasCharging = state.backupRequireCharging;
|
||||
@@ -197,7 +186,8 @@ class BackupNotifier extends StateNotifier<BackUpState> {
|
||||
}
|
||||
success &= await _backgroundService.enableService(immediate: true);
|
||||
}
|
||||
success &= success &&
|
||||
success &=
|
||||
success &&
|
||||
await _backgroundService.configureService(
|
||||
requireUnmetered: state.backupRequireWifi,
|
||||
requireCharging: state.backupRequireCharging,
|
||||
@@ -206,10 +196,7 @@ class BackupNotifier extends StateNotifier<BackUpState> {
|
||||
);
|
||||
if (success) {
|
||||
await Store.put(StoreKey.backupRequireWifi, state.backupRequireWifi);
|
||||
await Store.put(
|
||||
StoreKey.backupRequireCharging,
|
||||
state.backupRequireCharging,
|
||||
);
|
||||
await Store.put(StoreKey.backupRequireCharging, state.backupRequireCharging);
|
||||
await Store.put(StoreKey.backupTriggerDelay, state.backupTriggerDelay);
|
||||
await Store.put(StoreKey.backgroundBackup, state.backgroundBackup);
|
||||
} else {
|
||||
@@ -296,14 +283,9 @@ class BackupNotifier extends StateNotifier<BackUpState> {
|
||||
}
|
||||
}
|
||||
|
||||
state = state.copyWith(
|
||||
selectedBackupAlbums: selectedAlbums,
|
||||
excludedBackupAlbums: excludedAlbums,
|
||||
);
|
||||
state = state.copyWith(selectedBackupAlbums: selectedAlbums, excludedBackupAlbums: excludedAlbums);
|
||||
|
||||
log.info(
|
||||
"_getBackupAlbumsInfo: Found ${availableAlbums.length} available albums",
|
||||
);
|
||||
log.info("_getBackupAlbumsInfo: Found ${availableAlbums.length} available albums");
|
||||
debugPrint("_getBackupAlbumsInfo takes ${stopwatch.elapsedMilliseconds}ms");
|
||||
}
|
||||
|
||||
@@ -333,21 +315,14 @@ class BackupNotifier extends StateNotifier<BackUpState> {
|
||||
for (final asset in assets) {
|
||||
List<String> albumNames = [album.name];
|
||||
|
||||
final existingAsset = assetsFromSelectedAlbums.firstWhereOrNull(
|
||||
(a) => a.asset.localId == asset.localId,
|
||||
);
|
||||
final existingAsset = assetsFromSelectedAlbums.firstWhereOrNull((a) => a.asset.localId == asset.localId);
|
||||
|
||||
if (existingAsset != null) {
|
||||
albumNames.addAll(existingAsset.albumNames);
|
||||
assetsFromSelectedAlbums.remove(existingAsset);
|
||||
}
|
||||
|
||||
assetsFromSelectedAlbums.add(
|
||||
BackupCandidate(
|
||||
asset: asset,
|
||||
albumNames: albumNames,
|
||||
),
|
||||
);
|
||||
assetsFromSelectedAlbums.add(BackupCandidate(asset: asset, albumNames: albumNames));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -361,9 +336,7 @@ class BackupNotifier extends StateNotifier<BackUpState> {
|
||||
final assets = await ref.read(albumMediaRepositoryProvider).getAssets(album.album.localId!);
|
||||
|
||||
for (final asset in assets) {
|
||||
assetsFromExcludedAlbums.add(
|
||||
BackupCandidate(asset: asset, albumNames: [album.name]),
|
||||
);
|
||||
assetsFromExcludedAlbums.add(BackupCandidate(asset: asset, albumNames: [album.name]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,9 +354,7 @@ class BackupNotifier extends StateNotifier<BackUpState> {
|
||||
selectedAlbumsBackupAssets.removeWhere((assetId) => !allAssetsInDatabase.contains(assetId));
|
||||
|
||||
// Remove duplicated asset from all unique assets
|
||||
allUniqueAssets.removeWhere(
|
||||
(candidate) => duplicatedAssetIds.contains(candidate.asset.localId),
|
||||
);
|
||||
allUniqueAssets.removeWhere((candidate) => duplicatedAssetIds.contains(candidate.asset.localId));
|
||||
|
||||
if (allUniqueAssets.isEmpty) {
|
||||
log.info("No assets are selected for back up");
|
||||
@@ -509,9 +480,7 @@ class BackupNotifier extends StateNotifier<BackUpState> {
|
||||
}
|
||||
|
||||
void setAvailableAlbums(availableAlbums) {
|
||||
state = state.copyWith(
|
||||
availableAlbums: availableAlbums,
|
||||
);
|
||||
state = state.copyWith(availableAlbums: availableAlbums);
|
||||
}
|
||||
|
||||
void _onBackupError(ErrorUploadAsset errorAssetInfo) {
|
||||
@@ -541,28 +510,20 @@ class BackupNotifier extends StateNotifier<BackUpState> {
|
||||
if (result.isDuplicate) {
|
||||
state = state.copyWith(
|
||||
allUniqueAssets: state.allUniqueAssets
|
||||
.where(
|
||||
(candidate) => candidate.asset.localId != result.candidate.asset.localId,
|
||||
)
|
||||
.where((candidate) => candidate.asset.localId != result.candidate.asset.localId)
|
||||
.toSet(),
|
||||
);
|
||||
} else {
|
||||
state = state.copyWith(
|
||||
selectedAlbumsBackupAssetsIds: {
|
||||
...state.selectedAlbumsBackupAssetsIds,
|
||||
result.candidate.asset.localId!,
|
||||
},
|
||||
allAssetsInDatabase: [
|
||||
...state.allAssetsInDatabase,
|
||||
result.candidate.asset.localId!,
|
||||
],
|
||||
selectedAlbumsBackupAssetsIds: {...state.selectedAlbumsBackupAssetsIds, result.candidate.asset.localId!},
|
||||
allAssetsInDatabase: [...state.allAssetsInDatabase, result.candidate.asset.localId!],
|
||||
);
|
||||
}
|
||||
|
||||
if (state.allUniqueAssets.length - state.selectedAlbumsBackupAssetsIds.length == 0) {
|
||||
final latestAssetBackup = state.allUniqueAssets.map((candidate) => candidate.asset.fileModifiedAt).reduce(
|
||||
(v, e) => e.isAfter(v) ? e : v,
|
||||
);
|
||||
final latestAssetBackup = state.allUniqueAssets
|
||||
.map((candidate) => candidate.asset.fileModifiedAt)
|
||||
.reduce((v, e) => e.isAfter(v) ? e : v);
|
||||
state = state.copyWith(
|
||||
selectedBackupAlbums: state.selectedBackupAlbums.map((e) => e.copyWith(lastBackup: latestAssetBackup)).toSet(),
|
||||
excludedBackupAlbums: state.excludedBackupAlbums.map((e) => e.copyWith(lastBackup: latestAssetBackup)).toSet(),
|
||||
@@ -594,9 +555,7 @@ class BackupNotifier extends StateNotifier<BackUpState> {
|
||||
}
|
||||
|
||||
if (duration.inSeconds > 0) {
|
||||
lastUploadSpeeds.add(
|
||||
((sent - lastSentBytes) / duration.inSeconds).abs().roundToDouble(),
|
||||
);
|
||||
lastUploadSpeeds.add(((sent - lastSentBytes) / duration.inSeconds).abs().roundToDouble());
|
||||
|
||||
lastUploadSpeed = lastUploadSpeeds.average.abs().roundToDouble();
|
||||
lastUpdateTime = now;
|
||||
@@ -618,9 +577,7 @@ class BackupNotifier extends StateNotifier<BackUpState> {
|
||||
|
||||
// Update server info
|
||||
if (diskInfo != null) {
|
||||
state = state.copyWith(
|
||||
serverInfo: diskInfo,
|
||||
);
|
||||
state = state.copyWith(serverInfo: diskInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -665,17 +622,11 @@ class BackupNotifier extends StateNotifier<BackUpState> {
|
||||
Set<AvailableAlbum> selectedAlbums = state.selectedBackupAlbums;
|
||||
Set<AvailableAlbum> excludedAlbums = state.excludedBackupAlbums;
|
||||
if (selectedAlbums.isNotEmpty) {
|
||||
selectedAlbums = _updateAlbumsBackupTime(
|
||||
selectedAlbums,
|
||||
selectedBackupAlbums,
|
||||
);
|
||||
selectedAlbums = _updateAlbumsBackupTime(selectedAlbums, selectedBackupAlbums);
|
||||
}
|
||||
|
||||
if (excludedAlbums.isNotEmpty) {
|
||||
excludedAlbums = _updateAlbumsBackupTime(
|
||||
excludedAlbums,
|
||||
excludedBackupAlbums,
|
||||
);
|
||||
excludedAlbums = _updateAlbumsBackupTime(excludedAlbums, excludedBackupAlbums);
|
||||
}
|
||||
final BackUpProgressEnum previous = state.backupProgress;
|
||||
state = state.copyWith(
|
||||
@@ -692,32 +643,21 @@ class BackupNotifier extends StateNotifier<BackUpState> {
|
||||
return _resumeBackup();
|
||||
}
|
||||
|
||||
Set<AvailableAlbum> _updateAlbumsBackupTime(
|
||||
Set<AvailableAlbum> albums,
|
||||
List<BackupAlbum> backupAlbums,
|
||||
) {
|
||||
Set<AvailableAlbum> _updateAlbumsBackupTime(Set<AvailableAlbum> albums, List<BackupAlbum> backupAlbums) {
|
||||
Set<AvailableAlbum> result = {};
|
||||
for (BackupAlbum ba in backupAlbums) {
|
||||
try {
|
||||
AvailableAlbum a = albums.firstWhere((e) => e.id == ba.id);
|
||||
result.add(a.copyWith(lastBackup: ba.lastBackup));
|
||||
} on StateError {
|
||||
log.severe(
|
||||
"[_updateAlbumBackupTime] failed to find album in state",
|
||||
"State Error",
|
||||
StackTrace.current,
|
||||
);
|
||||
log.severe("[_updateAlbumBackupTime] failed to find album in state", "State Error", StackTrace.current);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Future<void> notifyBackgroundServiceCanRun() async {
|
||||
const allowedStates = [
|
||||
AppLifeCycleEnum.inactive,
|
||||
AppLifeCycleEnum.paused,
|
||||
AppLifeCycleEnum.detached,
|
||||
];
|
||||
const allowedStates = [AppLifeCycleEnum.inactive, AppLifeCycleEnum.paused, AppLifeCycleEnum.detached];
|
||||
if (allowedStates.contains(ref.read(appStateProvider.notifier).state)) {
|
||||
_backgroundService.releaseLock();
|
||||
}
|
||||
|
||||
@@ -5,9 +5,7 @@ import 'package:immich_mobile/infrastructure/repositories/local_album.repository
|
||||
import 'package:immich_mobile/providers/infrastructure/album.provider.dart';
|
||||
|
||||
final backupAlbumProvider = StateNotifierProvider<BackupAlbumNotifier, List<LocalAlbum>>(
|
||||
(ref) => BackupAlbumNotifier(
|
||||
ref.watch(localAlbumServiceProvider),
|
||||
),
|
||||
(ref) => BackupAlbumNotifier(ref.watch(localAlbumServiceProvider)),
|
||||
);
|
||||
|
||||
class BackupAlbumNotifier extends StateNotifier<List<LocalAlbum>> {
|
||||
|
||||
@@ -64,7 +64,8 @@ class BackupVerification extends _$BackupVerification {
|
||||
onOk: () => _performDeletion(context, toDelete),
|
||||
title: "Corrupt backups!",
|
||||
ok: "Delete",
|
||||
content: "Found ${toDelete.length} (max $limit at once) corrupt asset backups. "
|
||||
content:
|
||||
"Found ${toDelete.length} (max $limit at once) corrupt asset backups. "
|
||||
"Run the check again to find more.\n"
|
||||
"Do you want to delete the corrupt asset backups now?",
|
||||
),
|
||||
@@ -77,23 +78,18 @@ class BackupVerification extends _$BackupVerification {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _performDeletion(
|
||||
BuildContext context,
|
||||
List<Asset> assets,
|
||||
) async {
|
||||
Future<void> _performDeletion(BuildContext context, List<Asset> assets) async {
|
||||
try {
|
||||
state = true;
|
||||
if (context.mounted) {
|
||||
ImmichToast.show(
|
||||
context: context,
|
||||
msg: "Deleting ${assets.length} assets on the server...",
|
||||
);
|
||||
ImmichToast.show(context: context, msg: "Deleting ${assets.length} assets on the server...");
|
||||
}
|
||||
await ref.read(assetProvider.notifier).deleteAssets(assets, force: true);
|
||||
if (context.mounted) {
|
||||
ImmichToast.show(
|
||||
context: context,
|
||||
msg: "Deleted ${assets.length} assets on the server. "
|
||||
msg:
|
||||
"Deleted ${assets.length} assets on the server. "
|
||||
"You can now start a manual backup",
|
||||
toastType: ToastType.success,
|
||||
);
|
||||
|
||||
@@ -13,14 +13,14 @@ String _$backupVerificationHash() =>
|
||||
@ProviderFor(BackupVerification)
|
||||
final backupVerificationProvider =
|
||||
AutoDisposeNotifierProvider<BackupVerification, bool>.internal(
|
||||
BackupVerification.new,
|
||||
name: r'backupVerificationProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$backupVerificationHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
BackupVerification.new,
|
||||
name: r'backupVerificationProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$backupVerificationHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$BackupVerification = AutoDisposeNotifier<bool>;
|
||||
// ignore_for_file: type=lint
|
||||
|
||||
@@ -14,19 +14,10 @@ class EnqueueStatus {
|
||||
final int enqueueCount;
|
||||
final int totalCount;
|
||||
|
||||
const EnqueueStatus({
|
||||
required this.enqueueCount,
|
||||
required this.totalCount,
|
||||
});
|
||||
const EnqueueStatus({required this.enqueueCount, required this.totalCount});
|
||||
|
||||
EnqueueStatus copyWith({
|
||||
int? enqueueCount,
|
||||
int? totalCount,
|
||||
}) {
|
||||
return EnqueueStatus(
|
||||
enqueueCount: enqueueCount ?? this.enqueueCount,
|
||||
totalCount: totalCount ?? this.totalCount,
|
||||
);
|
||||
EnqueueStatus copyWith({int? enqueueCount, int? totalCount}) {
|
||||
return EnqueueStatus(enqueueCount: enqueueCount ?? this.enqueueCount, totalCount: totalCount ?? this.totalCount);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -197,25 +188,22 @@ class DriftBackupState {
|
||||
}
|
||||
|
||||
final driftBackupProvider = StateNotifierProvider<ExpBackupNotifier, DriftBackupState>((ref) {
|
||||
return ExpBackupNotifier(
|
||||
ref.watch(uploadServiceProvider),
|
||||
);
|
||||
return ExpBackupNotifier(ref.watch(uploadServiceProvider));
|
||||
});
|
||||
|
||||
class ExpBackupNotifier extends StateNotifier<DriftBackupState> {
|
||||
ExpBackupNotifier(
|
||||
this._uploadService,
|
||||
) : super(
|
||||
const DriftBackupState(
|
||||
totalCount: 0,
|
||||
backupCount: 0,
|
||||
remainderCount: 0,
|
||||
enqueueCount: 0,
|
||||
enqueueTotalCount: 0,
|
||||
isCanceling: false,
|
||||
uploadItems: {},
|
||||
),
|
||||
) {
|
||||
ExpBackupNotifier(this._uploadService)
|
||||
: super(
|
||||
const DriftBackupState(
|
||||
totalCount: 0,
|
||||
backupCount: 0,
|
||||
remainderCount: 0,
|
||||
enqueueCount: 0,
|
||||
enqueueTotalCount: 0,
|
||||
isCanceling: false,
|
||||
uploadItems: {},
|
||||
),
|
||||
) {
|
||||
{
|
||||
_uploadService.taskStatusStream.listen(_handleTaskStatusUpdate);
|
||||
_uploadService.taskProgressStream.listen(_handleTaskProgressUpdate);
|
||||
@@ -241,10 +229,7 @@ class ExpBackupNotifier extends StateNotifier<DriftBackupState> {
|
||||
switch (update.status) {
|
||||
case TaskStatus.complete:
|
||||
if (update.task.group == kBackupGroup) {
|
||||
state = state.copyWith(
|
||||
backupCount: state.backupCount + 1,
|
||||
remainderCount: state.remainderCount - 1,
|
||||
);
|
||||
state = state.copyWith(backupCount: state.backupCount + 1, remainderCount: state.remainderCount - 1);
|
||||
}
|
||||
|
||||
// Remove the completed task from the upload items
|
||||
@@ -260,14 +245,7 @@ class ExpBackupNotifier extends StateNotifier<DriftBackupState> {
|
||||
return;
|
||||
}
|
||||
|
||||
state = state.copyWith(
|
||||
uploadItems: {
|
||||
...state.uploadItems,
|
||||
taskId: currentItem.copyWith(
|
||||
isFailed: true,
|
||||
),
|
||||
},
|
||||
);
|
||||
state = state.copyWith(uploadItems: {...state.uploadItems, taskId: currentItem.copyWith(isFailed: true)});
|
||||
break;
|
||||
|
||||
case TaskStatus.canceled:
|
||||
@@ -299,9 +277,7 @@ class ExpBackupNotifier extends StateNotifier<DriftBackupState> {
|
||||
fileSize: update.expectedFileSize,
|
||||
networkSpeedAsString: update.networkSpeedAsString,
|
||||
)
|
||||
: currentItem.copyWith(
|
||||
progress: progress,
|
||||
),
|
||||
: currentItem.copyWith(progress: progress),
|
||||
},
|
||||
);
|
||||
|
||||
@@ -329,11 +305,7 @@ class ExpBackupNotifier extends StateNotifier<DriftBackupState> {
|
||||
_uploadService.getBackupRemainderCount(userId),
|
||||
]);
|
||||
|
||||
state = state.copyWith(
|
||||
totalCount: totalCount,
|
||||
backupCount: backupCount,
|
||||
remainderCount: remainderCount,
|
||||
);
|
||||
state = state.copyWith(totalCount: totalCount, backupCount: backupCount, remainderCount: remainderCount);
|
||||
}
|
||||
|
||||
Future<void> startBackup(String userId) {
|
||||
@@ -341,34 +313,22 @@ class ExpBackupNotifier extends StateNotifier<DriftBackupState> {
|
||||
}
|
||||
|
||||
void _updateEnqueueCount(EnqueueStatus status) {
|
||||
state = state.copyWith(
|
||||
enqueueCount: status.enqueueCount,
|
||||
enqueueTotalCount: status.totalCount,
|
||||
);
|
||||
state = state.copyWith(enqueueCount: status.enqueueCount, enqueueTotalCount: status.totalCount);
|
||||
}
|
||||
|
||||
Future<void> cancel() async {
|
||||
debugPrint("Canceling backup tasks...");
|
||||
state = state.copyWith(
|
||||
enqueueCount: 0,
|
||||
enqueueTotalCount: 0,
|
||||
isCanceling: true,
|
||||
);
|
||||
state = state.copyWith(enqueueCount: 0, enqueueTotalCount: 0, isCanceling: true);
|
||||
|
||||
final activeTaskCount = await _uploadService.cancelBackup();
|
||||
|
||||
if (activeTaskCount > 0) {
|
||||
debugPrint(
|
||||
"$activeTaskCount tasks left, continuing to cancel...",
|
||||
);
|
||||
debugPrint("$activeTaskCount tasks left, continuing to cancel...");
|
||||
await cancel();
|
||||
} else {
|
||||
debugPrint("All tasks canceled successfully.");
|
||||
// Clear all upload items when cancellation is complete
|
||||
state = state.copyWith(
|
||||
isCanceling: false,
|
||||
uploadItems: {},
|
||||
);
|
||||
state = state.copyWith(isCanceling: false, uploadItems: {});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -56,44 +56,43 @@ class ManualUploadNotifier extends StateNotifier<ManualUploadState> {
|
||||
this._backupAlbumService,
|
||||
this.ref,
|
||||
) : super(
|
||||
ManualUploadState(
|
||||
progressInPercentage: 0,
|
||||
progressInFileSize: "0 B / 0 B",
|
||||
progressInFileSpeed: 0,
|
||||
progressInFileSpeeds: const [],
|
||||
progressInFileSpeedUpdateTime: DateTime.now(),
|
||||
progressInFileSpeedUpdateSentBytes: 0,
|
||||
cancelToken: CancellationToken(),
|
||||
currentUploadAsset: CurrentUploadAsset(
|
||||
id: '...',
|
||||
fileCreatedAt: DateTime.parse('2020-10-04'),
|
||||
fileName: '...',
|
||||
fileType: '...',
|
||||
),
|
||||
totalAssetsToUpload: 0,
|
||||
successfulUploads: 0,
|
||||
currentAssetIndex: 0,
|
||||
showDetailedNotification: false,
|
||||
ManualUploadState(
|
||||
progressInPercentage: 0,
|
||||
progressInFileSize: "0 B / 0 B",
|
||||
progressInFileSpeed: 0,
|
||||
progressInFileSpeeds: const [],
|
||||
progressInFileSpeedUpdateTime: DateTime.now(),
|
||||
progressInFileSpeedUpdateSentBytes: 0,
|
||||
cancelToken: CancellationToken(),
|
||||
currentUploadAsset: CurrentUploadAsset(
|
||||
id: '...',
|
||||
fileCreatedAt: DateTime.parse('2020-10-04'),
|
||||
fileName: '...',
|
||||
fileType: '...',
|
||||
),
|
||||
);
|
||||
totalAssetsToUpload: 0,
|
||||
successfulUploads: 0,
|
||||
currentAssetIndex: 0,
|
||||
showDetailedNotification: false,
|
||||
),
|
||||
);
|
||||
|
||||
String _lastPrintedDetailContent = '';
|
||||
String? _lastPrintedDetailTitle;
|
||||
|
||||
static const notifyInterval = Duration(milliseconds: 500);
|
||||
late final ThrottleProgressUpdate _throttledNotifiy = ThrottleProgressUpdate(_updateProgress, notifyInterval);
|
||||
late final ThrottleProgressUpdate _throttledDetailNotify =
|
||||
ThrottleProgressUpdate(_updateDetailProgress, notifyInterval);
|
||||
late final ThrottleProgressUpdate _throttledDetailNotify = ThrottleProgressUpdate(
|
||||
_updateDetailProgress,
|
||||
notifyInterval,
|
||||
);
|
||||
|
||||
void _updateProgress(String? title, int progress, int total) {
|
||||
// Guard against throttling calling this method after the upload is done
|
||||
if (_backupProvider.backupProgress == BackUpProgressEnum.manualInProgress) {
|
||||
_localNotificationService.showOrUpdateManualUploadStatus(
|
||||
"backup_background_service_in_progress_notification".tr(),
|
||||
formatAssetBackupProgress(
|
||||
state.currentAssetIndex,
|
||||
state.totalAssetsToUpload,
|
||||
),
|
||||
formatAssetBackupProgress(state.currentAssetIndex, state.totalAssetsToUpload),
|
||||
maxProgress: state.totalAssetsToUpload,
|
||||
progress: state.currentAssetIndex,
|
||||
showActions: true,
|
||||
@@ -146,9 +145,7 @@ class ManualUploadNotifier extends StateNotifier<ManualUploadState> {
|
||||
}
|
||||
|
||||
if (duration.inSeconds > 0) {
|
||||
lastUploadSpeeds.add(
|
||||
((sent - lastSentBytes) / duration.inSeconds).abs().roundToDouble(),
|
||||
);
|
||||
lastUploadSpeeds.add(((sent - lastSentBytes) / duration.inSeconds).abs().roundToDouble());
|
||||
|
||||
lastUploadSpeed = lastUploadSpeeds.average.abs().roundToDouble();
|
||||
lastUpdateTime = now;
|
||||
@@ -165,23 +162,22 @@ class ManualUploadNotifier extends StateNotifier<ManualUploadState> {
|
||||
);
|
||||
|
||||
if (state.showDetailedNotification) {
|
||||
final title = "backup_background_service_current_upload_notification"
|
||||
.tr(namedArgs: {'filename': state.currentUploadAsset.fileName});
|
||||
final title = "backup_background_service_current_upload_notification".tr(
|
||||
namedArgs: {'filename': state.currentUploadAsset.fileName},
|
||||
);
|
||||
_throttledDetailNotify(title: title, progress: sent, total: total);
|
||||
}
|
||||
}
|
||||
|
||||
void _onSetCurrentBackupAsset(CurrentUploadAsset currentUploadAsset) {
|
||||
state = state.copyWith(
|
||||
currentUploadAsset: currentUploadAsset,
|
||||
currentAssetIndex: state.currentAssetIndex + 1,
|
||||
);
|
||||
state = state.copyWith(currentUploadAsset: currentUploadAsset, currentAssetIndex: state.currentAssetIndex + 1);
|
||||
if (state.totalAssetsToUpload > 1) {
|
||||
_throttledNotifiy();
|
||||
}
|
||||
if (state.showDetailedNotification) {
|
||||
_throttledDetailNotify.title = "backup_background_service_current_upload_notification"
|
||||
.tr(namedArgs: {'filename': currentUploadAsset.fileName});
|
||||
_throttledDetailNotify.title = "backup_background_service_current_upload_notification".tr(
|
||||
namedArgs: {'filename': currentUploadAsset.fileName},
|
||||
);
|
||||
_throttledDetailNotify.progress = 0;
|
||||
_throttledDetailNotify.total = 0;
|
||||
}
|
||||
@@ -216,10 +212,7 @@ class ManualUploadNotifier extends StateNotifier<ManualUploadState> {
|
||||
// Extrack candidate from allAssetsFromDevice
|
||||
final uploadAssets = candidates.where(
|
||||
(candidate) =>
|
||||
allAssetsFromDevice.firstWhereOrNull(
|
||||
(asset) => asset.localId == candidate.asset.localId,
|
||||
) !=
|
||||
null,
|
||||
allAssetsFromDevice.firstWhereOrNull((asset) => asset.localId == candidate.asset.localId) != null,
|
||||
);
|
||||
|
||||
if (uploadAssets.isEmpty) {
|
||||
@@ -251,14 +244,15 @@ class ManualUploadNotifier extends StateNotifier<ManualUploadState> {
|
||||
}
|
||||
|
||||
// Show detailed asset if enabled in settings or if a single asset is uploaded
|
||||
bool showDetailedNotification = ref.read(appSettingsServiceProvider).getSetting<bool>(
|
||||
AppSettingsEnum.backgroundBackupSingleProgress,
|
||||
) ||
|
||||
bool showDetailedNotification =
|
||||
ref.read(appSettingsServiceProvider).getSetting<bool>(AppSettingsEnum.backgroundBackupSingleProgress) ||
|
||||
state.totalAssetsToUpload == 1;
|
||||
state = state.copyWith(showDetailedNotification: showDetailedNotification);
|
||||
final pmProgressHandler = Platform.isIOS ? PMProgressHandler() : null;
|
||||
|
||||
final bool ok = await ref.read(backupServiceProvider).backupAsset(
|
||||
final bool ok = await ref
|
||||
.read(backupServiceProvider)
|
||||
.backupAsset(
|
||||
uploadAssets,
|
||||
state.cancelToken,
|
||||
pmProgressHandler: pmProgressHandler,
|
||||
@@ -269,9 +263,7 @@ class ManualUploadNotifier extends StateNotifier<ManualUploadState> {
|
||||
);
|
||||
|
||||
// Close detailed notification
|
||||
await _localNotificationService.closeNotification(
|
||||
LocalNotificationService.manualUploadDetailedNotificationID,
|
||||
);
|
||||
await _localNotificationService.closeNotification(LocalNotificationService.manualUploadDetailedNotificationID);
|
||||
|
||||
_log.info(
|
||||
'[_startUpload] Manual Upload Completed - success: ${state.successfulUploads},'
|
||||
@@ -310,9 +302,7 @@ class ManualUploadNotifier extends StateNotifier<ManualUploadState> {
|
||||
} finally {
|
||||
_backupProvider.updateBackupProgress(BackUpProgressEnum.idle);
|
||||
_handleAppInActivity();
|
||||
await _localNotificationService.closeNotification(
|
||||
LocalNotificationService.manualUploadDetailedNotificationID,
|
||||
);
|
||||
await _localNotificationService.closeNotification(LocalNotificationService.manualUploadDetailedNotificationID);
|
||||
await _backupProvider.notifyBackgroundServiceCanRun();
|
||||
}
|
||||
return !hasErrors;
|
||||
@@ -345,10 +335,7 @@ class ManualUploadNotifier extends StateNotifier<ManualUploadState> {
|
||||
);
|
||||
}
|
||||
|
||||
Future<bool> uploadAssets(
|
||||
BuildContext context,
|
||||
Iterable<Asset> allManualUploads,
|
||||
) async {
|
||||
Future<bool> uploadAssets(BuildContext context, Iterable<Asset> allManualUploads) async {
|
||||
// assumes the background service is currently running and
|
||||
// waits until it has stopped to start the backup.
|
||||
final bool hasLock = await ref.read(backgroundServiceProvider).acquireLock();
|
||||
|
||||
@@ -15,15 +15,15 @@ class CastNotifier extends StateNotifier<CastManagerState> {
|
||||
List<(String, CastDestinationType, dynamic)> discovered = List.empty();
|
||||
|
||||
CastNotifier(this._gCastService)
|
||||
: super(
|
||||
const CastManagerState(
|
||||
isCasting: false,
|
||||
currentTime: Duration.zero,
|
||||
duration: Duration.zero,
|
||||
receiverName: '',
|
||||
castState: CastState.idle,
|
||||
),
|
||||
) {
|
||||
: super(
|
||||
const CastManagerState(
|
||||
isCasting: false,
|
||||
currentTime: Duration.zero,
|
||||
duration: Duration.zero,
|
||||
receiverName: '',
|
||||
castState: CastState.idle,
|
||||
),
|
||||
) {
|
||||
_gCastService.onConnectionState = _onConnectionState;
|
||||
_gCastService.onCurrentTime = _onCurrentTime;
|
||||
_gCastService.onDuration = _onDuration;
|
||||
@@ -65,8 +65,8 @@ class CastNotifier extends StateNotifier<CastManagerState> {
|
||||
type: asset.type == old_asset_entity.AssetType.image
|
||||
? AssetType.image
|
||||
: asset.type == old_asset_entity.AssetType.video
|
||||
? AssetType.video
|
||||
: AssetType.other,
|
||||
? AssetType.video
|
||||
: AssetType.other,
|
||||
createdAt: asset.fileCreatedAt,
|
||||
updatedAt: asset.updatedAt,
|
||||
);
|
||||
|
||||
@@ -23,9 +23,7 @@ class FolderStructureNotifier extends StateNotifier<AsyncValue<RootFolder>> {
|
||||
}
|
||||
|
||||
final folderStructureProvider = StateNotifierProvider<FolderStructureNotifier, AsyncValue<RootFolder>>((ref) {
|
||||
return FolderStructureNotifier(
|
||||
ref.watch(folderServiceProvider),
|
||||
);
|
||||
return FolderStructureNotifier(ref.watch(folderServiceProvider));
|
||||
});
|
||||
|
||||
class FolderRenderListNotifier extends StateNotifier<AsyncValue<RenderList>> {
|
||||
@@ -49,8 +47,5 @@ class FolderRenderListNotifier extends StateNotifier<AsyncValue<RenderList>> {
|
||||
|
||||
final folderRenderListProvider =
|
||||
StateNotifierProvider.family<FolderRenderListNotifier, AsyncValue<RenderList>, RootFolder>((ref, folder) {
|
||||
return FolderRenderListNotifier(
|
||||
ref.watch(folderServiceProvider),
|
||||
folder,
|
||||
);
|
||||
});
|
||||
return FolderRenderListNotifier(ref.watch(folderServiceProvider), folder);
|
||||
});
|
||||
|
||||
@@ -5,8 +5,9 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
|
||||
class GalleryPermissionNotifier extends StateNotifier<PermissionStatus> {
|
||||
GalleryPermissionNotifier() : super(PermissionStatus.denied) // Denied is the initial state
|
||||
{
|
||||
GalleryPermissionNotifier()
|
||||
: super(PermissionStatus.denied) // Denied is the initial state
|
||||
{
|
||||
// Sets the initial state
|
||||
getGalleryPermissionStatus();
|
||||
}
|
||||
|
||||
+2
-9
@@ -19,20 +19,13 @@ class ImageLoader {
|
||||
}) async {
|
||||
final headers = ApiService.getRequestHeaders();
|
||||
|
||||
final stream = cache.getFileStream(
|
||||
uri,
|
||||
withProgress: chunkEvents != null,
|
||||
headers: headers,
|
||||
);
|
||||
final stream = cache.getFileStream(uri, withProgress: chunkEvents != null, headers: headers);
|
||||
|
||||
await for (final result in stream) {
|
||||
if (result is DownloadProgress) {
|
||||
// We are downloading the file, so update the [chunkEvents]
|
||||
chunkEvents?.add(
|
||||
ImageChunkEvent(
|
||||
cumulativeBytesLoaded: result.downloaded,
|
||||
expectedTotalBytes: result.totalSize,
|
||||
),
|
||||
ImageChunkEvent(cumulativeBytesLoaded: result.downloaded, expectedTotalBytes: result.totalSize),
|
||||
);
|
||||
} else if (result is FileInfo) {
|
||||
// We have the file
|
||||
|
||||
@@ -9,12 +9,5 @@ class RemoteImageCacheManager extends CacheManager {
|
||||
return _instance;
|
||||
}
|
||||
|
||||
RemoteImageCacheManager._()
|
||||
: super(
|
||||
Config(
|
||||
key,
|
||||
maxNrOfCacheObjects: 500,
|
||||
stalePeriod: const Duration(days: 30),
|
||||
),
|
||||
);
|
||||
RemoteImageCacheManager._() : super(Config(key, maxNrOfCacheObjects: 500, stalePeriod: const Duration(days: 30)));
|
||||
}
|
||||
|
||||
@@ -9,12 +9,5 @@ class ThumbnailImageCacheManager extends CacheManager {
|
||||
return _instance;
|
||||
}
|
||||
|
||||
ThumbnailImageCacheManager._()
|
||||
: super(
|
||||
Config(
|
||||
key,
|
||||
maxNrOfCacheObjects: 5000,
|
||||
stalePeriod: const Duration(days: 30),
|
||||
),
|
||||
);
|
||||
ThumbnailImageCacheManager._() : super(Config(key, maxNrOfCacheObjects: 5000, stalePeriod: const Duration(days: 30)));
|
||||
}
|
||||
|
||||
@@ -18,11 +18,8 @@ class ImmichLocalImageProvider extends ImageProvider<ImmichLocalImageProvider> {
|
||||
final double height;
|
||||
final Logger log = Logger('ImmichLocalImageProvider');
|
||||
|
||||
ImmichLocalImageProvider({
|
||||
required this.asset,
|
||||
required this.width,
|
||||
required this.height,
|
||||
}) : assert(asset.local != null, 'Only usable when asset.local is set');
|
||||
ImmichLocalImageProvider({required this.asset, required this.width, required this.height})
|
||||
: assert(asset.local != null, 'Only usable when asset.local is set');
|
||||
|
||||
/// Converts an [ImageProvider]'s settings plus an [ImageConfiguration] to a key
|
||||
/// that describes the precise image to load.
|
||||
@@ -32,10 +29,7 @@ class ImmichLocalImageProvider extends ImageProvider<ImmichLocalImageProvider> {
|
||||
}
|
||||
|
||||
@override
|
||||
ImageStreamCompleter loadImage(
|
||||
ImmichLocalImageProvider key,
|
||||
ImageDecoderCallback decode,
|
||||
) {
|
||||
ImageStreamCompleter loadImage(ImmichLocalImageProvider key, ImageDecoderCallback decode) {
|
||||
final chunkEvents = StreamController<ImageChunkEvent>();
|
||||
return MultiImageStreamCompleter(
|
||||
codec: _codec(key.asset, decode, chunkEvents),
|
||||
|
||||
@@ -32,17 +32,12 @@ class ImmichLocalThumbnailProvider extends ImageProvider<ImmichLocalThumbnailPro
|
||||
/// Converts an [ImageProvider]'s settings plus an [ImageConfiguration] to a key
|
||||
/// that describes the precise image to load.
|
||||
@override
|
||||
Future<ImmichLocalThumbnailProvider> obtainKey(
|
||||
ImageConfiguration configuration,
|
||||
) {
|
||||
Future<ImmichLocalThumbnailProvider> obtainKey(ImageConfiguration configuration) {
|
||||
return SynchronousFuture(this);
|
||||
}
|
||||
|
||||
@override
|
||||
ImageStreamCompleter loadImage(
|
||||
ImmichLocalThumbnailProvider key,
|
||||
ImageDecoderCallback decode,
|
||||
) {
|
||||
ImageStreamCompleter loadImage(ImmichLocalThumbnailProvider key, ImageDecoderCallback decode) {
|
||||
final cache = cacheManager ?? ThumbnailImageCacheManager();
|
||||
return MultiImageStreamCompleter(
|
||||
codec: _codec(key.asset, cache, decode),
|
||||
@@ -54,11 +49,7 @@ class ImmichLocalThumbnailProvider extends ImageProvider<ImmichLocalThumbnailPro
|
||||
}
|
||||
|
||||
// Streams in each stage of the image as we ask for it
|
||||
Stream<ui.Codec> _codec(
|
||||
Asset assetData,
|
||||
CacheManager cache,
|
||||
ImageDecoderCallback decode,
|
||||
) async* {
|
||||
Stream<ui.Codec> _codec(Asset assetData, CacheManager cache, ImageDecoderCallback decode) async* {
|
||||
final cacheKey = '$userId${assetData.localId}${assetData.checksum}$width$height';
|
||||
final fileFromCache = await cache.getFileFromCache(cacheKey);
|
||||
if (fileFromCache != null) {
|
||||
@@ -72,14 +63,9 @@ class ImmichLocalThumbnailProvider extends ImageProvider<ImmichLocalThumbnailPro
|
||||
}
|
||||
}
|
||||
|
||||
final thumbnailBytes = await assetData.local?.thumbnailDataWithSize(
|
||||
ThumbnailSize(width, height),
|
||||
quality: 80,
|
||||
);
|
||||
final thumbnailBytes = await assetData.local?.thumbnailDataWithSize(ThumbnailSize(width, height), quality: 80);
|
||||
if (thumbnailBytes == null) {
|
||||
throw StateError(
|
||||
"Loading thumb for local photo ${assetData.fileName} failed",
|
||||
);
|
||||
throw StateError("Loading thumb for local photo ${assetData.fileName} failed");
|
||||
}
|
||||
|
||||
final buffer = await ui.ImmutableBuffer.fromUint8List(thumbnailBytes);
|
||||
|
||||
@@ -22,25 +22,17 @@ class ImmichRemoteImageProvider extends ImageProvider<ImmichRemoteImageProvider>
|
||||
/// The image cache manager
|
||||
final CacheManager? cacheManager;
|
||||
|
||||
const ImmichRemoteImageProvider({
|
||||
required this.assetId,
|
||||
this.cacheManager,
|
||||
});
|
||||
const ImmichRemoteImageProvider({required this.assetId, this.cacheManager});
|
||||
|
||||
/// Converts an [ImageProvider]'s settings plus an [ImageConfiguration] to a key
|
||||
/// that describes the precise image to load.
|
||||
@override
|
||||
Future<ImmichRemoteImageProvider> obtainKey(
|
||||
ImageConfiguration configuration,
|
||||
) {
|
||||
Future<ImmichRemoteImageProvider> obtainKey(ImageConfiguration configuration) {
|
||||
return SynchronousFuture(this);
|
||||
}
|
||||
|
||||
@override
|
||||
ImageStreamCompleter loadImage(
|
||||
ImmichRemoteImageProvider key,
|
||||
ImageDecoderCallback decode,
|
||||
) {
|
||||
ImageStreamCompleter loadImage(ImmichRemoteImageProvider key, ImageDecoderCallback decode) {
|
||||
final cache = cacheManager ?? RemoteImageCacheManager();
|
||||
final chunkEvents = StreamController<ImageChunkEvent>();
|
||||
return MultiImageStreamCompleter(
|
||||
@@ -51,10 +43,7 @@ class ImmichRemoteImageProvider extends ImageProvider<ImmichRemoteImageProvider>
|
||||
}
|
||||
|
||||
/// Whether to show the original file or load a compressed version
|
||||
bool get _useOriginal => Store.get(
|
||||
AppSettingsEnum.loadOriginal.storeKey,
|
||||
AppSettingsEnum.loadOriginal.defaultValue,
|
||||
);
|
||||
bool get _useOriginal => Store.get(AppSettingsEnum.loadOriginal.storeKey, AppSettingsEnum.loadOriginal.defaultValue);
|
||||
|
||||
// Streams in each stage of the image as we ask for it
|
||||
Stream<ui.Codec> _codec(
|
||||
@@ -64,28 +53,15 @@ class ImmichRemoteImageProvider extends ImageProvider<ImmichRemoteImageProvider>
|
||||
StreamController<ImageChunkEvent> chunkEvents,
|
||||
) async* {
|
||||
// Load the higher resolution version of the image
|
||||
final url = getThumbnailUrlForRemoteId(
|
||||
key.assetId,
|
||||
type: api.AssetMediaSize.preview,
|
||||
);
|
||||
final codec = await ImageLoader.loadImageFromCache(
|
||||
url,
|
||||
cache: cache,
|
||||
decode: decode,
|
||||
chunkEvents: chunkEvents,
|
||||
);
|
||||
final url = getThumbnailUrlForRemoteId(key.assetId, type: api.AssetMediaSize.preview);
|
||||
final codec = await ImageLoader.loadImageFromCache(url, cache: cache, decode: decode, chunkEvents: chunkEvents);
|
||||
yield codec;
|
||||
|
||||
// Load the final remote image
|
||||
if (_useOriginal) {
|
||||
// Load the original image
|
||||
final url = getOriginalUrlForRemoteId(key.assetId);
|
||||
final codec = await ImageLoader.loadImageFromCache(
|
||||
url,
|
||||
cache: cache,
|
||||
decode: decode,
|
||||
chunkEvents: chunkEvents,
|
||||
);
|
||||
final codec = await ImageLoader.loadImageFromCache(url, cache: cache, decode: decode, chunkEvents: chunkEvents);
|
||||
yield codec;
|
||||
}
|
||||
await chunkEvents.close();
|
||||
|
||||
@@ -23,51 +23,27 @@ class ImmichRemoteThumbnailProvider extends ImageProvider<ImmichRemoteThumbnailP
|
||||
/// The image cache manager
|
||||
final CacheManager? cacheManager;
|
||||
|
||||
const ImmichRemoteThumbnailProvider({
|
||||
required this.assetId,
|
||||
this.height,
|
||||
this.width,
|
||||
this.cacheManager,
|
||||
});
|
||||
const ImmichRemoteThumbnailProvider({required this.assetId, this.height, this.width, this.cacheManager});
|
||||
|
||||
/// Converts an [ImageProvider]'s settings plus an [ImageConfiguration] to a key
|
||||
/// that describes the precise image to load.
|
||||
@override
|
||||
Future<ImmichRemoteThumbnailProvider> obtainKey(
|
||||
ImageConfiguration configuration,
|
||||
) {
|
||||
Future<ImmichRemoteThumbnailProvider> obtainKey(ImageConfiguration configuration) {
|
||||
return SynchronousFuture(this);
|
||||
}
|
||||
|
||||
@override
|
||||
ImageStreamCompleter loadImage(
|
||||
ImmichRemoteThumbnailProvider key,
|
||||
ImageDecoderCallback decode,
|
||||
) {
|
||||
ImageStreamCompleter loadImage(ImmichRemoteThumbnailProvider key, ImageDecoderCallback decode) {
|
||||
final cache = cacheManager ?? ThumbnailImageCacheManager();
|
||||
return MultiImageStreamCompleter(
|
||||
codec: _codec(key, cache, decode),
|
||||
scale: 1.0,
|
||||
);
|
||||
return MultiImageStreamCompleter(codec: _codec(key, cache, decode), scale: 1.0);
|
||||
}
|
||||
|
||||
// Streams in each stage of the image as we ask for it
|
||||
Stream<ui.Codec> _codec(
|
||||
ImmichRemoteThumbnailProvider key,
|
||||
CacheManager cache,
|
||||
ImageDecoderCallback decode,
|
||||
) async* {
|
||||
Stream<ui.Codec> _codec(ImmichRemoteThumbnailProvider key, CacheManager cache, ImageDecoderCallback decode) async* {
|
||||
// Load a preview to the chunk events
|
||||
final preview = getThumbnailUrlForRemoteId(
|
||||
key.assetId,
|
||||
type: api.AssetMediaSize.thumbnail,
|
||||
);
|
||||
final preview = getThumbnailUrlForRemoteId(key.assetId, type: api.AssetMediaSize.thumbnail);
|
||||
|
||||
yield await ImageLoader.loadImageFromCache(
|
||||
preview,
|
||||
cache: cache,
|
||||
decode: decode,
|
||||
);
|
||||
yield await ImageLoader.loadImageFromCache(preview, cache: cache, decode: decode);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
+3
-2
@@ -13,8 +13,9 @@ String _$immichLogoHash() => r'6de7fcca1ef9acef6ab7398eb0c664080747e0ea';
|
||||
final immichLogoProvider = AutoDisposeFutureProvider<Uint8List>.internal(
|
||||
immichLogo,
|
||||
name: r'immichLogoProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product') ? null : _$immichLogoHash,
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$immichLogoHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@@ -12,10 +12,7 @@ import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
final actionProvider = NotifierProvider<ActionNotifier, void>(
|
||||
ActionNotifier.new,
|
||||
dependencies: [
|
||||
multiSelectProvider,
|
||||
timelineServiceProvider,
|
||||
],
|
||||
dependencies: [multiSelectProvider, timelineServiceProvider],
|
||||
);
|
||||
|
||||
class ActionResult {
|
||||
@@ -74,37 +71,31 @@ class ActionNotifier extends Notifier<void> {
|
||||
Iterable<T> _getIdsForSource<T extends BaseAsset>(ActionSource source) {
|
||||
final Set<BaseAsset> assets = _getAssets(source);
|
||||
return switch (T) {
|
||||
const (RemoteAsset) => assets.whereType<RemoteAsset>(),
|
||||
const (LocalAsset) => assets.whereType<LocalAsset>(),
|
||||
_ => const [],
|
||||
} as Iterable<T>;
|
||||
const (RemoteAsset) => assets.whereType<RemoteAsset>(),
|
||||
const (LocalAsset) => assets.whereType<LocalAsset>(),
|
||||
_ => const [],
|
||||
}
|
||||
as Iterable<T>;
|
||||
}
|
||||
|
||||
Set<BaseAsset> _getAssets(ActionSource source) {
|
||||
return switch (source) {
|
||||
ActionSource.timeline => ref.read(multiSelectProvider).selectedAssets,
|
||||
ActionSource.viewer => switch (ref.read(currentAssetNotifier)) {
|
||||
BaseAsset asset => {asset},
|
||||
null => const {},
|
||||
},
|
||||
BaseAsset asset => {asset},
|
||||
null => const {},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Future<ActionResult> shareLink(
|
||||
ActionSource source,
|
||||
BuildContext context,
|
||||
) async {
|
||||
Future<ActionResult> shareLink(ActionSource source, BuildContext context) async {
|
||||
final ids = _getRemoteIdsForSource(source);
|
||||
try {
|
||||
await _service.shareLink(ids, context);
|
||||
return ActionResult(count: ids.length, success: true);
|
||||
} catch (error, stack) {
|
||||
_logger.severe('Failed to create shared link for assets', error, stack);
|
||||
return ActionResult(
|
||||
count: ids.length,
|
||||
success: false,
|
||||
error: error.toString(),
|
||||
);
|
||||
return ActionResult(count: ids.length, success: false, error: error.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,11 +106,7 @@ class ActionNotifier extends Notifier<void> {
|
||||
return ActionResult(count: ids.length, success: true);
|
||||
} catch (error, stack) {
|
||||
_logger.severe('Failed to favorite assets', error, stack);
|
||||
return ActionResult(
|
||||
count: ids.length,
|
||||
success: false,
|
||||
error: error.toString(),
|
||||
);
|
||||
return ActionResult(count: ids.length, success: false, error: error.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,11 +117,7 @@ class ActionNotifier extends Notifier<void> {
|
||||
return ActionResult(count: ids.length, success: true);
|
||||
} catch (error, stack) {
|
||||
_logger.severe('Failed to unfavorite assets', error, stack);
|
||||
return ActionResult(
|
||||
count: ids.length,
|
||||
success: false,
|
||||
error: error.toString(),
|
||||
);
|
||||
return ActionResult(count: ids.length, success: false, error: error.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,11 +128,7 @@ class ActionNotifier extends Notifier<void> {
|
||||
return ActionResult(count: ids.length, success: true);
|
||||
} catch (error, stack) {
|
||||
_logger.severe('Failed to archive assets', error, stack);
|
||||
return ActionResult(
|
||||
count: ids.length,
|
||||
success: false,
|
||||
error: error.toString(),
|
||||
);
|
||||
return ActionResult(count: ids.length, success: false, error: error.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,11 +139,7 @@ class ActionNotifier extends Notifier<void> {
|
||||
return ActionResult(count: ids.length, success: true);
|
||||
} catch (error, stack) {
|
||||
_logger.severe('Failed to unarchive assets', error, stack);
|
||||
return ActionResult(
|
||||
count: ids.length,
|
||||
success: false,
|
||||
error: error.toString(),
|
||||
);
|
||||
return ActionResult(count: ids.length, success: false, error: error.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,11 +151,7 @@ class ActionNotifier extends Notifier<void> {
|
||||
return ActionResult(count: ids.length, success: true);
|
||||
} catch (error, stack) {
|
||||
_logger.severe('Failed to move assets to lock folder', error, stack);
|
||||
return ActionResult(
|
||||
count: ids.length,
|
||||
success: false,
|
||||
error: error.toString(),
|
||||
);
|
||||
return ActionResult(count: ids.length, success: false, error: error.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,11 +162,7 @@ class ActionNotifier extends Notifier<void> {
|
||||
return ActionResult(count: ids.length, success: true);
|
||||
} catch (error, stack) {
|
||||
_logger.severe('Failed to remove assets from lock folder', error, stack);
|
||||
return ActionResult(
|
||||
count: ids.length,
|
||||
success: false,
|
||||
error: error.toString(),
|
||||
);
|
||||
return ActionResult(count: ids.length, success: false, error: error.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,11 +174,7 @@ class ActionNotifier extends Notifier<void> {
|
||||
return ActionResult(count: ids.length, success: true);
|
||||
} catch (error, stack) {
|
||||
_logger.severe('Failed to trash assets', error, stack);
|
||||
return ActionResult(
|
||||
count: ids.length,
|
||||
success: false,
|
||||
error: error.toString(),
|
||||
);
|
||||
return ActionResult(count: ids.length, success: false, error: error.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,11 +185,7 @@ class ActionNotifier extends Notifier<void> {
|
||||
return ActionResult(count: ids.length, success: true);
|
||||
} catch (error, stack) {
|
||||
_logger.severe('Failed to restore trash assets', error, stack);
|
||||
return ActionResult(
|
||||
count: ids.length,
|
||||
success: false,
|
||||
error: error.toString(),
|
||||
);
|
||||
return ActionResult(count: ids.length, success: false, error: error.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,11 +197,7 @@ class ActionNotifier extends Notifier<void> {
|
||||
return ActionResult(count: ids.length, success: true);
|
||||
} catch (error, stack) {
|
||||
_logger.severe('Failed to delete assets', error, stack);
|
||||
return ActionResult(
|
||||
count: ids.length,
|
||||
success: false,
|
||||
error: error.toString(),
|
||||
);
|
||||
return ActionResult(count: ids.length, success: false, error: error.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,11 +209,7 @@ class ActionNotifier extends Notifier<void> {
|
||||
return ActionResult(count: ids.length, success: true);
|
||||
} catch (error, stack) {
|
||||
_logger.severe('Failed to delete assets', error, stack);
|
||||
return ActionResult(
|
||||
count: ids.length,
|
||||
success: false,
|
||||
error: error.toString(),
|
||||
);
|
||||
return ActionResult(count: ids.length, success: false, error: error.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,18 +220,11 @@ class ActionNotifier extends Notifier<void> {
|
||||
return ActionResult(count: deletedCount, success: true);
|
||||
} catch (error, stack) {
|
||||
_logger.severe('Failed to delete assets', error, stack);
|
||||
return ActionResult(
|
||||
count: ids.length,
|
||||
success: false,
|
||||
error: error.toString(),
|
||||
);
|
||||
return ActionResult(count: ids.length, success: false, error: error.toString());
|
||||
}
|
||||
}
|
||||
|
||||
Future<ActionResult?> editLocation(
|
||||
ActionSource source,
|
||||
BuildContext context,
|
||||
) async {
|
||||
Future<ActionResult?> editLocation(ActionSource source, BuildContext context) async {
|
||||
final ids = _getOwnedRemoteIdsForSource(source);
|
||||
try {
|
||||
final isEdited = await _service.editLocation(ids, context);
|
||||
@@ -291,29 +235,18 @@ class ActionNotifier extends Notifier<void> {
|
||||
return ActionResult(count: ids.length, success: true);
|
||||
} catch (error, stack) {
|
||||
_logger.severe('Failed to edit location for assets', error, stack);
|
||||
return ActionResult(
|
||||
count: ids.length,
|
||||
success: false,
|
||||
error: error.toString(),
|
||||
);
|
||||
return ActionResult(count: ids.length, success: false, error: error.toString());
|
||||
}
|
||||
}
|
||||
|
||||
Future<ActionResult> removeFromAlbum(
|
||||
ActionSource source,
|
||||
String albumId,
|
||||
) async {
|
||||
Future<ActionResult> removeFromAlbum(ActionSource source, String albumId) async {
|
||||
final ids = _getRemoteIdsForSource(source);
|
||||
try {
|
||||
final removedCount = await _service.removeFromAlbum(ids, albumId);
|
||||
return ActionResult(count: removedCount, success: true);
|
||||
} catch (error, stack) {
|
||||
_logger.severe('Failed to remove assets from album', error, stack);
|
||||
return ActionResult(
|
||||
count: ids.length,
|
||||
success: false,
|
||||
error: error.toString(),
|
||||
);
|
||||
return ActionResult(count: ids.length, success: false, error: error.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,11 +257,7 @@ class ActionNotifier extends Notifier<void> {
|
||||
return ActionResult(count: ids.length, success: true);
|
||||
} catch (error, stack) {
|
||||
_logger.severe('Failed to stack assets', error, stack);
|
||||
return ActionResult(
|
||||
count: ids.length,
|
||||
success: false,
|
||||
error: error.toString(),
|
||||
);
|
||||
return ActionResult(count: ids.length, success: false, error: error.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,10 +268,7 @@ class ActionNotifier extends Notifier<void> {
|
||||
return ActionResult(count: assets.length, success: true);
|
||||
} catch (error, stack) {
|
||||
_logger.severe('Failed to unstack assets', error, stack);
|
||||
return ActionResult(
|
||||
count: assets.length,
|
||||
success: false,
|
||||
);
|
||||
return ActionResult(count: assets.length, success: false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -354,11 +280,7 @@ class ActionNotifier extends Notifier<void> {
|
||||
return ActionResult(count: count, success: true);
|
||||
} catch (error, stack) {
|
||||
_logger.severe('Failed to share assets', error, stack);
|
||||
return ActionResult(
|
||||
count: ids.length,
|
||||
success: false,
|
||||
error: error.toString(),
|
||||
);
|
||||
return ActionResult(count: ids.length, success: false, error: error.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -371,11 +293,7 @@ class ActionNotifier extends Notifier<void> {
|
||||
return ActionResult(count: enqueueCount, success: true);
|
||||
} catch (error, stack) {
|
||||
_logger.severe('Failed to download assets', error, stack);
|
||||
return ActionResult(
|
||||
count: assets.length,
|
||||
success: false,
|
||||
error: error.toString(),
|
||||
);
|
||||
return ActionResult(count: assets.length, success: false, error: error.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -386,11 +304,7 @@ class ActionNotifier extends Notifier<void> {
|
||||
return ActionResult(count: assets.length, success: true);
|
||||
} catch (error, stack) {
|
||||
_logger.severe('Failed manually upload assets', error, stack);
|
||||
return ActionResult(
|
||||
count: assets.length,
|
||||
success: false,
|
||||
error: error.toString(),
|
||||
);
|
||||
return ActionResult(count: assets.length, success: false, error: error.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,10 +30,7 @@ final remoteAlbumRepository = Provider<DriftRemoteAlbumRepository>(
|
||||
);
|
||||
|
||||
final remoteAlbumServiceProvider = Provider<RemoteAlbumService>(
|
||||
(ref) => RemoteAlbumService(
|
||||
ref.watch(remoteAlbumRepository),
|
||||
ref.watch(driftAlbumApiRepositoryProvider),
|
||||
),
|
||||
(ref) => RemoteAlbumService(ref.watch(remoteAlbumRepository), ref.watch(driftAlbumApiRepositoryProvider)),
|
||||
dependencies: [remoteAlbumRepository],
|
||||
);
|
||||
|
||||
|
||||
@@ -4,9 +4,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/asset.provider.dart';
|
||||
|
||||
final currentAssetNotifier = AutoDisposeNotifierProvider<CurrentAssetNotifier, BaseAsset?>(
|
||||
CurrentAssetNotifier.new,
|
||||
);
|
||||
final currentAssetNotifier = AutoDisposeNotifierProvider<CurrentAssetNotifier, BaseAsset?>(CurrentAssetNotifier.new);
|
||||
|
||||
class CurrentAssetNotifier extends AutoDisposeNotifier<BaseAsset?> {
|
||||
KeepAliveLink? _keepAliveLink;
|
||||
@@ -33,12 +31,10 @@ class CurrentAssetNotifier extends AutoDisposeNotifier<BaseAsset?> {
|
||||
}
|
||||
}
|
||||
|
||||
final currentAssetExifProvider = FutureProvider.autoDispose(
|
||||
(ref) {
|
||||
final currentAsset = ref.watch(currentAssetNotifier);
|
||||
if (currentAsset == null) {
|
||||
return null;
|
||||
}
|
||||
return ref.watch(assetServiceProvider).getExif(currentAsset);
|
||||
},
|
||||
);
|
||||
final currentAssetExifProvider = FutureProvider.autoDispose((ref) {
|
||||
final currentAsset = ref.watch(currentAssetNotifier);
|
||||
if (currentAsset == null) {
|
||||
return null;
|
||||
}
|
||||
return ref.watch(assetServiceProvider).getExif(currentAsset);
|
||||
});
|
||||
|
||||
+3
-2
@@ -13,8 +13,9 @@ String _$isarHash() => r'69d3a06aa7e69a4381478e03f7956eb07d7f7feb';
|
||||
final isarProvider = Provider<Isar>.internal(
|
||||
isar,
|
||||
name: r'isarProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product') ? null : _$isarHash,
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$isarHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@@ -2,6 +2,4 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/infrastructure/repositories/person.repository.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
|
||||
|
||||
final driftPersonProvider = Provider<DriftPersonRepository>(
|
||||
(ref) => DriftPersonRepository(ref.watch(driftProvider)),
|
||||
);
|
||||
final driftPersonProvider = Provider<DriftPersonRepository>((ref) => DriftPersonRepository(ref.watch(driftProvider)));
|
||||
|
||||
@@ -15,19 +15,11 @@ class RemoteAlbumState {
|
||||
final List<RemoteAlbum> albums;
|
||||
final List<RemoteAlbum> filteredAlbums;
|
||||
|
||||
const RemoteAlbumState({
|
||||
required this.albums,
|
||||
List<RemoteAlbum>? filteredAlbums,
|
||||
}) : filteredAlbums = filteredAlbums ?? albums;
|
||||
const RemoteAlbumState({required this.albums, List<RemoteAlbum>? filteredAlbums})
|
||||
: filteredAlbums = filteredAlbums ?? albums;
|
||||
|
||||
RemoteAlbumState copyWith({
|
||||
List<RemoteAlbum>? albums,
|
||||
List<RemoteAlbum>? filteredAlbums,
|
||||
}) {
|
||||
return RemoteAlbumState(
|
||||
albums: albums ?? this.albums,
|
||||
filteredAlbums: filteredAlbums ?? this.filteredAlbums,
|
||||
);
|
||||
RemoteAlbumState copyWith({List<RemoteAlbum>? albums, List<RemoteAlbum>? filteredAlbums}) {
|
||||
return RemoteAlbumState(albums: albums ?? this.albums, filteredAlbums: filteredAlbums ?? this.filteredAlbums);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -57,10 +49,7 @@ class RemoteAlbumNotifier extends Notifier<RemoteAlbumState> {
|
||||
Future<List<RemoteAlbum>> _getAll() async {
|
||||
try {
|
||||
final albums = await _remoteAlbumService.getAll();
|
||||
state = state.copyWith(
|
||||
albums: albums,
|
||||
filteredAlbums: albums,
|
||||
);
|
||||
state = state.copyWith(albums: albums, filteredAlbums: albums);
|
||||
return albums;
|
||||
} catch (error, stack) {
|
||||
_logger.severe('Failed to fetch albums', error, stack);
|
||||
@@ -72,33 +61,17 @@ class RemoteAlbumNotifier extends Notifier<RemoteAlbumState> {
|
||||
await _getAll();
|
||||
}
|
||||
|
||||
void searchAlbums(
|
||||
String query,
|
||||
String? userId, [
|
||||
QuickFilterMode filterMode = QuickFilterMode.all,
|
||||
]) {
|
||||
final filtered = _remoteAlbumService.searchAlbums(
|
||||
state.albums,
|
||||
query,
|
||||
userId,
|
||||
filterMode,
|
||||
);
|
||||
void searchAlbums(String query, String? userId, [QuickFilterMode filterMode = QuickFilterMode.all]) {
|
||||
final filtered = _remoteAlbumService.searchAlbums(state.albums, query, userId, filterMode);
|
||||
|
||||
state = state.copyWith(
|
||||
filteredAlbums: filtered,
|
||||
);
|
||||
state = state.copyWith(filteredAlbums: filtered);
|
||||
}
|
||||
|
||||
void clearSearch() {
|
||||
state = state.copyWith(
|
||||
filteredAlbums: state.albums,
|
||||
);
|
||||
state = state.copyWith(filteredAlbums: state.albums);
|
||||
}
|
||||
|
||||
void sortFilteredAlbums(
|
||||
RemoteAlbumSortMode sortMode, {
|
||||
bool isReverse = false,
|
||||
}) {
|
||||
void sortFilteredAlbums(RemoteAlbumSortMode sortMode, {bool isReverse = false}) {
|
||||
final sortedAlbums = _remoteAlbumService.sortAlbums(state.filteredAlbums, sortMode, isReverse: isReverse);
|
||||
state = state.copyWith(filteredAlbums: sortedAlbums);
|
||||
}
|
||||
@@ -109,16 +82,9 @@ class RemoteAlbumNotifier extends Notifier<RemoteAlbumState> {
|
||||
List<String> assetIds = const [],
|
||||
}) async {
|
||||
try {
|
||||
final album = await _remoteAlbumService.createAlbum(
|
||||
title: title,
|
||||
description: description,
|
||||
assetIds: assetIds,
|
||||
);
|
||||
final album = await _remoteAlbumService.createAlbum(title: title, description: description, assetIds: assetIds);
|
||||
|
||||
state = state.copyWith(
|
||||
albums: [...state.albums, album],
|
||||
filteredAlbums: [...state.filteredAlbums, album],
|
||||
);
|
||||
state = state.copyWith(albums: [...state.albums, album], filteredAlbums: [...state.filteredAlbums, album]);
|
||||
|
||||
return album;
|
||||
} catch (error, stack) {
|
||||
@@ -153,10 +119,7 @@ class RemoteAlbumNotifier extends Notifier<RemoteAlbumState> {
|
||||
return album.id == albumId ? updatedAlbum : album;
|
||||
}).toList();
|
||||
|
||||
state = state.copyWith(
|
||||
albums: updatedAlbums,
|
||||
filteredAlbums: updatedFilteredAlbums,
|
||||
);
|
||||
state = state.copyWith(albums: updatedAlbums, filteredAlbums: updatedFilteredAlbums);
|
||||
|
||||
return updatedAlbum;
|
||||
} catch (error, stack) {
|
||||
@@ -179,10 +142,7 @@ class RemoteAlbumNotifier extends Notifier<RemoteAlbumState> {
|
||||
final updatedAlbums = state.albums.where((album) => album.id != albumId).toList();
|
||||
final updatedFilteredAlbums = state.filteredAlbums.where((album) => album.id != albumId).toList();
|
||||
|
||||
state = state.copyWith(
|
||||
albums: updatedAlbums,
|
||||
filteredAlbums: updatedFilteredAlbums,
|
||||
);
|
||||
state = state.copyWith(albums: updatedAlbums, filteredAlbums: updatedFilteredAlbums);
|
||||
}
|
||||
|
||||
Future<List<RemoteAsset>> getAssets(String albumId) {
|
||||
@@ -190,32 +150,22 @@ class RemoteAlbumNotifier extends Notifier<RemoteAlbumState> {
|
||||
}
|
||||
|
||||
Future<int> addAssets(String albumId, List<String> assetIds) {
|
||||
return _remoteAlbumService.addAssets(
|
||||
albumId: albumId,
|
||||
assetIds: assetIds,
|
||||
);
|
||||
return _remoteAlbumService.addAssets(albumId: albumId, assetIds: assetIds);
|
||||
}
|
||||
|
||||
Future<void> addUsers(String albumId, List<String> userIds) {
|
||||
return _remoteAlbumService.addUsers(
|
||||
albumId: albumId,
|
||||
userIds: userIds,
|
||||
);
|
||||
return _remoteAlbumService.addUsers(albumId: albumId, userIds: userIds);
|
||||
}
|
||||
}
|
||||
|
||||
final remoteAlbumDateRangeProvider = FutureProvider.family<(DateTime, DateTime), String>(
|
||||
(ref, albumId) async {
|
||||
final service = ref.watch(remoteAlbumServiceProvider);
|
||||
return service.getDateRange(albumId);
|
||||
},
|
||||
);
|
||||
final remoteAlbumDateRangeProvider = FutureProvider.family<(DateTime, DateTime), String>((ref, albumId) async {
|
||||
final service = ref.watch(remoteAlbumServiceProvider);
|
||||
return service.getDateRange(albumId);
|
||||
});
|
||||
|
||||
final remoteAlbumSharedUsersProvider = FutureProvider.autoDispose.family<List<UserDto>, String>(
|
||||
(ref, albumId) async {
|
||||
final link = ref.keepAlive();
|
||||
ref.onDispose(() => link.close());
|
||||
final service = ref.watch(remoteAlbumServiceProvider);
|
||||
return service.getSharedUsers(albumId);
|
||||
},
|
||||
);
|
||||
final remoteAlbumSharedUsersProvider = FutureProvider.autoDispose.family<List<UserDto>, String>((ref, albumId) async {
|
||||
final link = ref.keepAlive();
|
||||
ref.onDispose(() => link.close());
|
||||
final service = ref.watch(remoteAlbumServiceProvider);
|
||||
return service.getSharedUsers(albumId);
|
||||
});
|
||||
|
||||
@@ -3,10 +3,6 @@ import 'package:immich_mobile/domain/services/search.service.dart';
|
||||
import 'package:immich_mobile/infrastructure/repositories/search_api.repository.dart';
|
||||
import 'package:immich_mobile/providers/api.provider.dart';
|
||||
|
||||
final searchApiRepositoryProvider = Provider(
|
||||
(ref) => SearchApiRepository(ref.watch(apiServiceProvider).searchApi),
|
||||
);
|
||||
final searchApiRepositoryProvider = Provider((ref) => SearchApiRepository(ref.watch(apiServiceProvider).searchApi));
|
||||
|
||||
final searchServiceProvider = Provider(
|
||||
(ref) => SearchService(ref.watch(searchApiRepositoryProvider)),
|
||||
);
|
||||
final searchServiceProvider = Provider((ref) => SearchService(ref.watch(searchApiRepositoryProvider)));
|
||||
|
||||
@@ -2,6 +2,4 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/infrastructure/repositories/stack.repository.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
|
||||
|
||||
final driftStackProvider = Provider<DriftStackRepository>(
|
||||
(ref) => DriftStackRepository(ref.watch(driftProvider)),
|
||||
);
|
||||
final driftStackProvider = Provider<DriftStackRepository>((ref) => DriftStackRepository(ref.watch(driftProvider)));
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/infrastructure/repositories/storage.repository.dart';
|
||||
|
||||
final storageRepositoryProvider = Provider<StorageRepository>(
|
||||
(ref) => const StorageRepository(),
|
||||
);
|
||||
final storageRepositoryProvider = Provider<StorageRepository>((ref) => const StorageRepository());
|
||||
|
||||
+3
-2
@@ -30,8 +30,9 @@ String _$storeServiceHash() => r'250e10497c42df360e9e1f9a618d0b19c1b5b0a0';
|
||||
final storeServiceProvider = Provider<StoreService>.internal(
|
||||
storeService,
|
||||
name: r'storeServiceProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product') ? null : _$storeServiceHash,
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$storeServiceHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@@ -20,13 +20,9 @@ final syncStreamServiceProvider = Provider(
|
||||
),
|
||||
);
|
||||
|
||||
final syncApiRepositoryProvider = Provider(
|
||||
(ref) => SyncApiRepository(ref.watch(apiServiceProvider)),
|
||||
);
|
||||
final syncApiRepositoryProvider = Provider((ref) => SyncApiRepository(ref.watch(apiServiceProvider)));
|
||||
|
||||
final syncStreamRepositoryProvider = Provider(
|
||||
(ref) => SyncStreamRepository(ref.watch(driftProvider)),
|
||||
);
|
||||
final syncStreamRepositoryProvider = Provider((ref) => SyncStreamRepository(ref.watch(driftProvider)));
|
||||
|
||||
final localSyncServiceProvider = Provider(
|
||||
(ref) => LocalSyncService(
|
||||
|
||||
@@ -33,13 +33,11 @@ final timelineFactoryProvider = Provider<TimelineFactory>(
|
||||
),
|
||||
);
|
||||
|
||||
final timelineUsersProvider = StreamProvider<List<String>>(
|
||||
(ref) {
|
||||
final currentUserId = ref.watch(currentUserProvider.select((u) => u?.id));
|
||||
if (currentUserId == null) {
|
||||
return Stream.value([]);
|
||||
}
|
||||
final timelineUsersProvider = StreamProvider<List<String>>((ref) {
|
||||
final currentUserId = ref.watch(currentUserProvider.select((u) => u?.id));
|
||||
if (currentUserId == null) {
|
||||
return Stream.value([]);
|
||||
}
|
||||
|
||||
return ref.watch(timelineRepositoryProvider).watchTimelineUserIds(currentUserId);
|
||||
},
|
||||
);
|
||||
return ref.watch(timelineRepositoryProvider).watchTimelineUserIds(currentUserId);
|
||||
});
|
||||
|
||||
@@ -22,10 +22,10 @@ UserApiRepository userApiRepository(Ref ref) => UserApiRepository(ref.watch(apiS
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
UserService userService(Ref ref) => UserService(
|
||||
isarUserRepository: ref.watch(userRepositoryProvider),
|
||||
userApiRepository: ref.watch(userApiRepositoryProvider),
|
||||
storeService: ref.watch(storeServiceProvider),
|
||||
);
|
||||
isarUserRepository: ref.watch(userRepositoryProvider),
|
||||
userApiRepository: ref.watch(userApiRepositoryProvider),
|
||||
storeService: ref.watch(storeServiceProvider),
|
||||
);
|
||||
|
||||
/// Drifts
|
||||
final driftPartnerRepositoryProvider = Provider<DriftPartnerRepository>(
|
||||
@@ -33,12 +33,7 @@ final driftPartnerRepositoryProvider = Provider<DriftPartnerRepository>(
|
||||
);
|
||||
|
||||
final driftPartnerServiceProvider = Provider<DriftPartnerService>(
|
||||
(ref) => DriftPartnerService(
|
||||
ref.watch(driftPartnerRepositoryProvider),
|
||||
ref.watch(partnerApiRepositoryProvider),
|
||||
),
|
||||
(ref) => DriftPartnerService(ref.watch(driftPartnerRepositoryProvider), ref.watch(partnerApiRepositoryProvider)),
|
||||
);
|
||||
|
||||
final partnerUsersProvider = NotifierProvider<PartnerNotifier, List<PartnerUserDto>>(
|
||||
PartnerNotifier.new,
|
||||
);
|
||||
final partnerUsersProvider = NotifierProvider<PartnerNotifier, List<PartnerUserDto>>(PartnerNotifier.new);
|
||||
|
||||
+3
-2
@@ -47,8 +47,9 @@ String _$userServiceHash() => r'181414dddc7891be6237e13d568c287a804228d1';
|
||||
final userServiceProvider = Provider<UserService>.internal(
|
||||
userService,
|
||||
name: r'userServiceProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product') ? null : _$userServiceHash,
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$userServiceHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@@ -10,10 +10,7 @@ import 'package:immich_mobile/services/secure_storage.service.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
final localAuthProvider = StateNotifierProvider<LocalAuthNotifier, BiometricStatus>((ref) {
|
||||
return LocalAuthNotifier(
|
||||
ref.watch(localAuthServiceProvider),
|
||||
ref.watch(secureStorageServiceProvider),
|
||||
);
|
||||
return LocalAuthNotifier(ref.watch(localAuthServiceProvider), ref.watch(secureStorageServiceProvider));
|
||||
});
|
||||
|
||||
class LocalAuthNotifier extends StateNotifier<BiometricStatus> {
|
||||
@@ -23,17 +20,9 @@ class LocalAuthNotifier extends StateNotifier<BiometricStatus> {
|
||||
final _log = Logger("LocalAuthNotifier");
|
||||
|
||||
LocalAuthNotifier(this._localAuthService, this._secureStorageService)
|
||||
: super(
|
||||
const BiometricStatus(
|
||||
availableBiometrics: [],
|
||||
canAuthenticate: false,
|
||||
),
|
||||
) {
|
||||
: super(const BiometricStatus(availableBiometrics: [], canAuthenticate: false)) {
|
||||
_localAuthService.getStatus().then((value) {
|
||||
state = state.copyWith(
|
||||
canAuthenticate: value.canAuthenticate,
|
||||
availableBiometrics: value.availableBiometrics,
|
||||
);
|
||||
state = state.copyWith(canAuthenticate: value.canAuthenticate, availableBiometrics: value.availableBiometrics);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -79,10 +68,7 @@ class LocalAuthNotifier extends StateNotifier<BiometricStatus> {
|
||||
if (errorMessage.isNotEmpty) {
|
||||
context.showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
errorMessage,
|
||||
style: context.textTheme.labelLarge,
|
||||
),
|
||||
content: Text(errorMessage, style: context.textTheme.labelLarge),
|
||||
duration: const Duration(seconds: 3),
|
||||
backgroundColor: context.colorScheme.errorContainer,
|
||||
),
|
||||
|
||||
+3
-2
@@ -13,8 +13,9 @@ String _$mapMarkersHash() => r'a0c129fcddbf1b9bce4aafcd2e47a858ab6ef1c9';
|
||||
final mapMarkersProvider = AutoDisposeFutureProvider<List<MapMarker>>.internal(
|
||||
mapMarkers,
|
||||
name: r'mapMarkersProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product') ? null : _$mapMarkersHash,
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$mapMarkersHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
+3
-2
@@ -13,8 +13,9 @@ String _$mapServiceHash() => r'ffc8f38b726083452b9df236ed58903879348987';
|
||||
final mapServiceProvider = AutoDisposeProvider<MapService>.internal(
|
||||
mapService,
|
||||
name: r'mapServiceProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product') ? null : _$mapServiceHash,
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$mapServiceHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@@ -28,22 +28,13 @@ class MapStateNotifier extends _$MapStateNotifier {
|
||||
}
|
||||
|
||||
void switchTheme(ThemeMode mode) {
|
||||
ref.read(appSettingsServiceProvider).setSetting(
|
||||
AppSettingsEnum.mapThemeMode,
|
||||
mode.index,
|
||||
);
|
||||
ref.read(appSettingsServiceProvider).setSetting(AppSettingsEnum.mapThemeMode, mode.index);
|
||||
state = state.copyWith(themeMode: mode);
|
||||
}
|
||||
|
||||
void switchFavoriteOnly(bool isFavoriteOnly) {
|
||||
ref.read(appSettingsServiceProvider).setSetting(
|
||||
AppSettingsEnum.mapShowFavoriteOnly,
|
||||
isFavoriteOnly,
|
||||
);
|
||||
state = state.copyWith(
|
||||
showFavoriteOnly: isFavoriteOnly,
|
||||
shouldRefetchMarkers: true,
|
||||
);
|
||||
ref.read(appSettingsServiceProvider).setSetting(AppSettingsEnum.mapShowFavoriteOnly, isFavoriteOnly);
|
||||
state = state.copyWith(showFavoriteOnly: isFavoriteOnly, shouldRefetchMarkers: true);
|
||||
}
|
||||
|
||||
void setRefetchMarkers(bool shouldRefetch) {
|
||||
@@ -51,35 +42,17 @@ class MapStateNotifier extends _$MapStateNotifier {
|
||||
}
|
||||
|
||||
void switchIncludeArchived(bool isIncludeArchived) {
|
||||
ref.read(appSettingsServiceProvider).setSetting(
|
||||
AppSettingsEnum.mapIncludeArchived,
|
||||
isIncludeArchived,
|
||||
);
|
||||
state = state.copyWith(
|
||||
includeArchived: isIncludeArchived,
|
||||
shouldRefetchMarkers: true,
|
||||
);
|
||||
ref.read(appSettingsServiceProvider).setSetting(AppSettingsEnum.mapIncludeArchived, isIncludeArchived);
|
||||
state = state.copyWith(includeArchived: isIncludeArchived, shouldRefetchMarkers: true);
|
||||
}
|
||||
|
||||
void switchWithPartners(bool isWithPartners) {
|
||||
ref.read(appSettingsServiceProvider).setSetting(
|
||||
AppSettingsEnum.mapwithPartners,
|
||||
isWithPartners,
|
||||
);
|
||||
state = state.copyWith(
|
||||
withPartners: isWithPartners,
|
||||
shouldRefetchMarkers: true,
|
||||
);
|
||||
ref.read(appSettingsServiceProvider).setSetting(AppSettingsEnum.mapwithPartners, isWithPartners);
|
||||
state = state.copyWith(withPartners: isWithPartners, shouldRefetchMarkers: true);
|
||||
}
|
||||
|
||||
void setRelativeTime(int relativeTime) {
|
||||
ref.read(appSettingsServiceProvider).setSetting(
|
||||
AppSettingsEnum.mapRelativeDate,
|
||||
relativeTime,
|
||||
);
|
||||
state = state.copyWith(
|
||||
relativeTime: relativeTime,
|
||||
shouldRefetchMarkers: true,
|
||||
);
|
||||
ref.read(appSettingsServiceProvider).setSetting(AppSettingsEnum.mapRelativeDate, relativeTime);
|
||||
state = state.copyWith(relativeTime: relativeTime, shouldRefetchMarkers: true);
|
||||
}
|
||||
}
|
||||
|
||||
+8
-8
@@ -12,14 +12,14 @@ String _$mapStateNotifierHash() => r'22e4e571bd0730dbc34b109255a62b920e9c7d66';
|
||||
@ProviderFor(MapStateNotifier)
|
||||
final mapStateNotifierProvider =
|
||||
NotifierProvider<MapStateNotifier, MapState>.internal(
|
||||
MapStateNotifier.new,
|
||||
name: r'mapStateNotifierProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$mapStateNotifierHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
MapStateNotifier.new,
|
||||
name: r'mapStateNotifierProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$mapStateNotifierHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$MapStateNotifier = Notifier<MapState>;
|
||||
// ignore_for_file: type=lint
|
||||
|
||||
@@ -2,9 +2,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/services/network.service.dart';
|
||||
|
||||
final networkProvider = StateNotifierProvider<NetworkNotifier, String>((ref) {
|
||||
return NetworkNotifier(
|
||||
ref.watch(networkServiceProvider),
|
||||
);
|
||||
return NetworkNotifier(ref.watch(networkServiceProvider));
|
||||
});
|
||||
|
||||
class NetworkNotifier extends StateNotifier<String> {
|
||||
|
||||
@@ -5,9 +5,7 @@ import 'package:permission_handler/permission_handler.dart';
|
||||
|
||||
class NotificationPermissionNotifier extends StateNotifier<PermissionStatus> {
|
||||
NotificationPermissionNotifier()
|
||||
: super(
|
||||
Platform.isAndroid ? PermissionStatus.granted : PermissionStatus.restricted,
|
||||
) {
|
||||
: super(Platform.isAndroid ? PermissionStatus.granted : PermissionStatus.restricted) {
|
||||
// Sets the initial state
|
||||
getNotificationPermission().then((p) => state = p);
|
||||
}
|
||||
|
||||
@@ -12,17 +12,20 @@ class PartnerSharedWithNotifier extends StateNotifier<List<UserDto>> {
|
||||
|
||||
PartnerSharedWithNotifier(this._partnerService) : super([]) {
|
||||
Function eq = const ListEquality<UserDto>().equals;
|
||||
_partnerService.getSharedWith().then((partners) {
|
||||
if (!eq(state, partners)) {
|
||||
state = partners;
|
||||
}
|
||||
}).then((_) {
|
||||
streamSub = _partnerService.watchSharedWith().listen((partners) {
|
||||
if (!eq(state, partners)) {
|
||||
state = partners;
|
||||
}
|
||||
});
|
||||
});
|
||||
_partnerService
|
||||
.getSharedWith()
|
||||
.then((partners) {
|
||||
if (!eq(state, partners)) {
|
||||
state = partners;
|
||||
}
|
||||
})
|
||||
.then((_) {
|
||||
streamSub = _partnerService.watchSharedWith().listen((partners) {
|
||||
if (!eq(state, partners)) {
|
||||
state = partners;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Future<bool> updatePartner(UserDto partner, {required bool inTimeline}) {
|
||||
@@ -39,9 +42,7 @@ class PartnerSharedWithNotifier extends StateNotifier<List<UserDto>> {
|
||||
}
|
||||
|
||||
final partnerSharedWithProvider = StateNotifierProvider<PartnerSharedWithNotifier, List<UserDto>>((ref) {
|
||||
return PartnerSharedWithNotifier(
|
||||
ref.watch(partnerServiceProvider),
|
||||
);
|
||||
return PartnerSharedWithNotifier(ref.watch(partnerServiceProvider));
|
||||
});
|
||||
|
||||
class PartnerSharedByNotifier extends StateNotifier<List<UserDto>> {
|
||||
@@ -50,17 +51,20 @@ class PartnerSharedByNotifier extends StateNotifier<List<UserDto>> {
|
||||
|
||||
PartnerSharedByNotifier(this._partnerService) : super([]) {
|
||||
Function eq = const ListEquality<UserDto>().equals;
|
||||
_partnerService.getSharedBy().then((partners) {
|
||||
if (!eq(state, partners)) {
|
||||
state = partners;
|
||||
}
|
||||
}).then((_) {
|
||||
streamSub = _partnerService.watchSharedBy().listen((partners) {
|
||||
if (!eq(state, partners)) {
|
||||
state = partners;
|
||||
}
|
||||
});
|
||||
});
|
||||
_partnerService
|
||||
.getSharedBy()
|
||||
.then((partners) {
|
||||
if (!eq(state, partners)) {
|
||||
state = partners;
|
||||
}
|
||||
})
|
||||
.then((_) {
|
||||
streamSub = _partnerService.watchSharedBy().listen((partners) {
|
||||
if (!eq(state, partners)) {
|
||||
state = partners;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -28,10 +28,7 @@ class PaginatedSearchNotifier extends StateNotifier<SearchResult> {
|
||||
return false;
|
||||
}
|
||||
|
||||
state = SearchResult(
|
||||
assets: [...state.assets, ...result.assets],
|
||||
nextPage: result.nextPage,
|
||||
);
|
||||
state = SearchResult(assets: [...state.assets, ...result.assets], nextPage: result.nextPage);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -42,13 +39,8 @@ class PaginatedSearchNotifier extends StateNotifier<SearchResult> {
|
||||
}
|
||||
|
||||
@riverpod
|
||||
Future<RenderList> paginatedSearchRenderList(
|
||||
Ref ref,
|
||||
) {
|
||||
Future<RenderList> paginatedSearchRenderList(Ref ref) {
|
||||
final result = ref.watch(paginatedSearchProvider);
|
||||
final timelineService = ref.watch(timelineServiceProvider);
|
||||
return timelineService.getTimelineFromAssets(
|
||||
result.assets,
|
||||
GroupAssetsBy.none,
|
||||
);
|
||||
return timelineService.getTimelineFromAssets(result.assets, GroupAssetsBy.none);
|
||||
}
|
||||
|
||||
@@ -13,14 +13,14 @@ String _$paginatedSearchRenderListHash() =>
|
||||
@ProviderFor(paginatedSearchRenderList)
|
||||
final paginatedSearchRenderListProvider =
|
||||
AutoDisposeFutureProvider<RenderList>.internal(
|
||||
paginatedSearchRenderList,
|
||||
name: r'paginatedSearchRenderListProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$paginatedSearchRenderListHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
paginatedSearchRenderList,
|
||||
name: r'paginatedSearchRenderListProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$paginatedSearchRenderListHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
|
||||
@@ -9,9 +9,7 @@ import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
part 'people.provider.g.dart';
|
||||
|
||||
@riverpod
|
||||
Future<List<PersonDto>> getAllPeople(
|
||||
Ref ref,
|
||||
) async {
|
||||
Future<List<PersonDto>> getAllPeople(Ref ref) async {
|
||||
final PersonService personService = ref.read(personServiceProvider);
|
||||
|
||||
final people = await personService.getAllPeople();
|
||||
@@ -30,11 +28,7 @@ Future<RenderList> personAssets(Ref ref, String personId) async {
|
||||
}
|
||||
|
||||
@riverpod
|
||||
Future<bool> updatePersonName(
|
||||
Ref ref,
|
||||
String personId,
|
||||
String updatedName,
|
||||
) async {
|
||||
Future<bool> updatePersonName(Ref ref, String personId, String updatedName) async {
|
||||
final PersonService personService = ref.read(personServiceProvider);
|
||||
final person = await personService.updateName(personId, updatedName);
|
||||
|
||||
|
||||
+47
-69
@@ -12,13 +12,14 @@ String _$getAllPeopleHash() => r'2c5e6a207683f15ab209650615fdf9cb7f76c736';
|
||||
@ProviderFor(getAllPeople)
|
||||
final getAllPeopleProvider =
|
||||
AutoDisposeFutureProvider<List<PersonDto>>.internal(
|
||||
getAllPeople,
|
||||
name: r'getAllPeopleProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product') ? null : _$getAllPeopleHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
getAllPeople,
|
||||
name: r'getAllPeopleProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$getAllPeopleHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
@@ -56,21 +57,15 @@ class PersonAssetsFamily extends Family<AsyncValue<RenderList>> {
|
||||
const PersonAssetsFamily();
|
||||
|
||||
/// See also [personAssets].
|
||||
PersonAssetsProvider call(
|
||||
String personId,
|
||||
) {
|
||||
return PersonAssetsProvider(
|
||||
personId,
|
||||
);
|
||||
PersonAssetsProvider call(String personId) {
|
||||
return PersonAssetsProvider(personId);
|
||||
}
|
||||
|
||||
@override
|
||||
PersonAssetsProvider getProviderOverride(
|
||||
covariant PersonAssetsProvider provider,
|
||||
) {
|
||||
return call(
|
||||
provider.personId,
|
||||
);
|
||||
return call(provider.personId);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
@@ -91,24 +86,19 @@ class PersonAssetsFamily extends Family<AsyncValue<RenderList>> {
|
||||
/// See also [personAssets].
|
||||
class PersonAssetsProvider extends AutoDisposeFutureProvider<RenderList> {
|
||||
/// See also [personAssets].
|
||||
PersonAssetsProvider(
|
||||
String personId,
|
||||
) : this._internal(
|
||||
(ref) => personAssets(
|
||||
ref as PersonAssetsRef,
|
||||
personId,
|
||||
),
|
||||
from: personAssetsProvider,
|
||||
name: r'personAssetsProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$personAssetsHash,
|
||||
dependencies: PersonAssetsFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
PersonAssetsFamily._allTransitiveDependencies,
|
||||
personId: personId,
|
||||
);
|
||||
PersonAssetsProvider(String personId)
|
||||
: this._internal(
|
||||
(ref) => personAssets(ref as PersonAssetsRef, personId),
|
||||
from: personAssetsProvider,
|
||||
name: r'personAssetsProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$personAssetsHash,
|
||||
dependencies: PersonAssetsFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
PersonAssetsFamily._allTransitiveDependencies,
|
||||
personId: personId,
|
||||
);
|
||||
|
||||
PersonAssetsProvider._internal(
|
||||
super._createNotifier, {
|
||||
@@ -167,7 +157,8 @@ mixin PersonAssetsRef on AutoDisposeFutureProviderRef<RenderList> {
|
||||
}
|
||||
|
||||
class _PersonAssetsProviderElement
|
||||
extends AutoDisposeFutureProviderElement<RenderList> with PersonAssetsRef {
|
||||
extends AutoDisposeFutureProviderElement<RenderList>
|
||||
with PersonAssetsRef {
|
||||
_PersonAssetsProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
@@ -186,24 +177,15 @@ class UpdatePersonNameFamily extends Family<AsyncValue<bool>> {
|
||||
const UpdatePersonNameFamily();
|
||||
|
||||
/// See also [updatePersonName].
|
||||
UpdatePersonNameProvider call(
|
||||
String personId,
|
||||
String updatedName,
|
||||
) {
|
||||
return UpdatePersonNameProvider(
|
||||
personId,
|
||||
updatedName,
|
||||
);
|
||||
UpdatePersonNameProvider call(String personId, String updatedName) {
|
||||
return UpdatePersonNameProvider(personId, updatedName);
|
||||
}
|
||||
|
||||
@override
|
||||
UpdatePersonNameProvider getProviderOverride(
|
||||
covariant UpdatePersonNameProvider provider,
|
||||
) {
|
||||
return call(
|
||||
provider.personId,
|
||||
provider.updatedName,
|
||||
);
|
||||
return call(provider.personId, provider.updatedName);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
@@ -224,27 +206,21 @@ class UpdatePersonNameFamily extends Family<AsyncValue<bool>> {
|
||||
/// See also [updatePersonName].
|
||||
class UpdatePersonNameProvider extends AutoDisposeFutureProvider<bool> {
|
||||
/// See also [updatePersonName].
|
||||
UpdatePersonNameProvider(
|
||||
String personId,
|
||||
String updatedName,
|
||||
) : this._internal(
|
||||
(ref) => updatePersonName(
|
||||
ref as UpdatePersonNameRef,
|
||||
personId,
|
||||
updatedName,
|
||||
),
|
||||
from: updatePersonNameProvider,
|
||||
name: r'updatePersonNameProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$updatePersonNameHash,
|
||||
dependencies: UpdatePersonNameFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
UpdatePersonNameFamily._allTransitiveDependencies,
|
||||
personId: personId,
|
||||
updatedName: updatedName,
|
||||
);
|
||||
UpdatePersonNameProvider(String personId, String updatedName)
|
||||
: this._internal(
|
||||
(ref) =>
|
||||
updatePersonName(ref as UpdatePersonNameRef, personId, updatedName),
|
||||
from: updatePersonNameProvider,
|
||||
name: r'updatePersonNameProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$updatePersonNameHash,
|
||||
dependencies: UpdatePersonNameFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
UpdatePersonNameFamily._allTransitiveDependencies,
|
||||
personId: personId,
|
||||
updatedName: updatedName,
|
||||
);
|
||||
|
||||
UpdatePersonNameProvider._internal(
|
||||
super._createNotifier, {
|
||||
@@ -312,7 +288,8 @@ mixin UpdatePersonNameRef on AutoDisposeFutureProviderRef<bool> {
|
||||
}
|
||||
|
||||
class _UpdatePersonNameProviderElement
|
||||
extends AutoDisposeFutureProviderElement<bool> with UpdatePersonNameRef {
|
||||
extends AutoDisposeFutureProviderElement<bool>
|
||||
with UpdatePersonNameRef {
|
||||
_UpdatePersonNameProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
@@ -320,5 +297,6 @@ class _UpdatePersonNameProviderElement
|
||||
@override
|
||||
String get updatedName => (origin as UpdatePersonNameProvider).updatedName;
|
||||
}
|
||||
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
|
||||
+23
-23
@@ -95,29 +95,28 @@ class GetSearchSuggestionsProvider
|
||||
String? make,
|
||||
String? model,
|
||||
}) : this._internal(
|
||||
(ref) => getSearchSuggestions(
|
||||
ref as GetSearchSuggestionsRef,
|
||||
type,
|
||||
locationCountry: locationCountry,
|
||||
locationState: locationState,
|
||||
make: make,
|
||||
model: model,
|
||||
),
|
||||
from: getSearchSuggestionsProvider,
|
||||
name: r'getSearchSuggestionsProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$getSearchSuggestionsHash,
|
||||
dependencies: GetSearchSuggestionsFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
GetSearchSuggestionsFamily._allTransitiveDependencies,
|
||||
type: type,
|
||||
locationCountry: locationCountry,
|
||||
locationState: locationState,
|
||||
make: make,
|
||||
model: model,
|
||||
);
|
||||
(ref) => getSearchSuggestions(
|
||||
ref as GetSearchSuggestionsRef,
|
||||
type,
|
||||
locationCountry: locationCountry,
|
||||
locationState: locationState,
|
||||
make: make,
|
||||
model: model,
|
||||
),
|
||||
from: getSearchSuggestionsProvider,
|
||||
name: r'getSearchSuggestionsProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$getSearchSuggestionsHash,
|
||||
dependencies: GetSearchSuggestionsFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
GetSearchSuggestionsFamily._allTransitiveDependencies,
|
||||
type: type,
|
||||
locationCountry: locationCountry,
|
||||
locationState: locationState,
|
||||
make: make,
|
||||
model: model,
|
||||
);
|
||||
|
||||
GetSearchSuggestionsProvider._internal(
|
||||
super._createNotifier, {
|
||||
@@ -227,5 +226,6 @@ class _GetSearchSuggestionsProviderElement
|
||||
@override
|
||||
String? get model => (origin as GetSearchSuggestionsProvider).model;
|
||||
}
|
||||
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
|
||||
@@ -14,14 +14,7 @@ final getPreviewPlacesProvider = FutureProvider.autoDispose<List<SearchCuratedCo
|
||||
|
||||
final locations = exploreData.firstWhere((data) => data.fieldName == "exifInfo.city").items;
|
||||
|
||||
final curatedContent = locations
|
||||
.map(
|
||||
(l) => SearchCuratedContent(
|
||||
label: l.value,
|
||||
id: l.data.id,
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
final curatedContent = locations.map((l) => SearchCuratedContent(label: l.value, id: l.data.id)).toList();
|
||||
|
||||
return curatedContent;
|
||||
});
|
||||
@@ -36,12 +29,7 @@ final getAllPlacesProvider = FutureProvider.autoDispose<List<SearchCuratedConten
|
||||
}
|
||||
|
||||
final curatedContent = assetPlaces
|
||||
.map(
|
||||
(data) => SearchCuratedContent(
|
||||
label: data.exifInfo!.city!,
|
||||
id: data.id,
|
||||
),
|
||||
)
|
||||
.map((data) => SearchCuratedContent(label: data.exifInfo!.city!, id: data.id))
|
||||
.toList();
|
||||
|
||||
return curatedContent;
|
||||
|
||||
@@ -11,42 +11,24 @@ import 'package:package_info_plus/package_info_plus.dart';
|
||||
|
||||
class ServerInfoNotifier extends StateNotifier<ServerInfo> {
|
||||
ServerInfoNotifier(this._serverInfoService)
|
||||
: super(
|
||||
const ServerInfo(
|
||||
serverVersion: ServerVersion(
|
||||
major: 0,
|
||||
minor: 0,
|
||||
patch: 0,
|
||||
),
|
||||
latestVersion: ServerVersion(
|
||||
major: 0,
|
||||
minor: 0,
|
||||
patch: 0,
|
||||
),
|
||||
serverFeatures: ServerFeatures(
|
||||
map: true,
|
||||
trash: true,
|
||||
oauthEnabled: false,
|
||||
passwordLogin: true,
|
||||
),
|
||||
serverConfig: ServerConfig(
|
||||
trashDays: 30,
|
||||
oauthButtonText: '',
|
||||
externalDomain: '',
|
||||
mapLightStyleUrl: 'https://tiles.immich.cloud/v1/style/light.json',
|
||||
mapDarkStyleUrl: 'https://tiles.immich.cloud/v1/style/dark.json',
|
||||
),
|
||||
serverDiskInfo: ServerDiskInfo(
|
||||
diskAvailable: "0",
|
||||
diskSize: "0",
|
||||
diskUse: "0",
|
||||
diskUsagePercentage: 0,
|
||||
),
|
||||
isVersionMismatch: false,
|
||||
isNewReleaseAvailable: false,
|
||||
versionMismatchErrorMessage: "",
|
||||
: super(
|
||||
const ServerInfo(
|
||||
serverVersion: ServerVersion(major: 0, minor: 0, patch: 0),
|
||||
latestVersion: ServerVersion(major: 0, minor: 0, patch: 0),
|
||||
serverFeatures: ServerFeatures(map: true, trash: true, oauthEnabled: false, passwordLogin: true),
|
||||
serverConfig: ServerConfig(
|
||||
trashDays: 30,
|
||||
oauthButtonText: '',
|
||||
externalDomain: '',
|
||||
mapLightStyleUrl: 'https://tiles.immich.cloud/v1/style/light.json',
|
||||
mapDarkStyleUrl: 'https://tiles.immich.cloud/v1/style/dark.json',
|
||||
),
|
||||
);
|
||||
serverDiskInfo: ServerDiskInfo(diskAvailable: "0", diskSize: "0", diskUse: "0", diskUsagePercentage: 0),
|
||||
isVersionMismatch: false,
|
||||
isNewReleaseAvailable: false,
|
||||
versionMismatchErrorMessage: "",
|
||||
),
|
||||
);
|
||||
|
||||
final ServerInfoService _serverInfoService;
|
||||
final _log = Logger("ServerInfoNotifier");
|
||||
@@ -62,19 +44,14 @@ class ServerInfoNotifier extends StateNotifier<ServerInfo> {
|
||||
final serverVersion = await _serverInfoService.getServerVersion();
|
||||
|
||||
if (serverVersion == null) {
|
||||
state = state.copyWith(
|
||||
isVersionMismatch: true,
|
||||
versionMismatchErrorMessage: "common_server_error".tr(),
|
||||
);
|
||||
state = state.copyWith(isVersionMismatch: true, versionMismatchErrorMessage: "common_server_error".tr());
|
||||
return;
|
||||
}
|
||||
|
||||
await _checkServerVersionMismatch(serverVersion);
|
||||
} catch (e, stackTrace) {
|
||||
_log.severe("Failed to get server version", e, stackTrace);
|
||||
state = state.copyWith(
|
||||
isVersionMismatch: true,
|
||||
);
|
||||
state = state.copyWith(isVersionMismatch: true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -118,29 +95,21 @@ class ServerInfoNotifier extends StateNotifier<ServerInfo> {
|
||||
return;
|
||||
}
|
||||
|
||||
state = state.copyWith(
|
||||
isVersionMismatch: false,
|
||||
versionMismatchErrorMessage: "",
|
||||
);
|
||||
state = state.copyWith(isVersionMismatch: false, versionMismatchErrorMessage: "");
|
||||
}
|
||||
|
||||
handleNewRelease(
|
||||
ServerVersion serverVersion,
|
||||
ServerVersion latestVersion,
|
||||
) {
|
||||
handleNewRelease(ServerVersion serverVersion, ServerVersion latestVersion) {
|
||||
// Update local server version
|
||||
_checkServerVersionMismatch(serverVersion);
|
||||
|
||||
final majorEqual = latestVersion.major == serverVersion.major;
|
||||
final minorEqual = majorEqual && latestVersion.minor == serverVersion.minor;
|
||||
final newVersionAvailable = latestVersion.major > serverVersion.major ||
|
||||
final newVersionAvailable =
|
||||
latestVersion.major > serverVersion.major ||
|
||||
(majorEqual && latestVersion.minor > serverVersion.minor) ||
|
||||
(minorEqual && latestVersion.patch > serverVersion.patch);
|
||||
|
||||
state = state.copyWith(
|
||||
latestVersion: latestVersion,
|
||||
isNewReleaseAvailable: newVersionAvailable,
|
||||
);
|
||||
state = state.copyWith(latestVersion: latestVersion, isNewReleaseAvailable: newVersionAvailable);
|
||||
}
|
||||
|
||||
getServerFeatures() async {
|
||||
@@ -166,11 +135,7 @@ class ServerInfoNotifier extends StateNotifier<ServerInfo> {
|
||||
var minor = detail[1];
|
||||
var patch = detail[2];
|
||||
|
||||
return {
|
||||
"major": int.parse(major),
|
||||
"minor": int.parse(minor),
|
||||
"patch": int.parse(patch.replaceAll("-DEBUG", "")),
|
||||
};
|
||||
return {"major": int.parse(major), "minor": int.parse(minor), "patch": int.parse(patch.replaceAll("-DEBUG", ""))};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,5 @@ class SharedLinksNotifier extends StateNotifier<AsyncValue<List<SharedLink>>> {
|
||||
}
|
||||
|
||||
final sharedLinksStateProvider = StateNotifierProvider<SharedLinksNotifier, AsyncValue<List<SharedLink>>>((ref) {
|
||||
return SharedLinksNotifier(
|
||||
ref.watch(sharedLinkServiceProvider),
|
||||
);
|
||||
return SharedLinksNotifier(ref.watch(sharedLinkServiceProvider));
|
||||
});
|
||||
|
||||
@@ -12,7 +12,7 @@ enum SyncStatus {
|
||||
SyncStatus.idle => "idle".tr(),
|
||||
SyncStatus.syncing => "running".tr(),
|
||||
SyncStatus.success => "success".tr(),
|
||||
SyncStatus.error => "error".tr()
|
||||
SyncStatus.error => "error".tr(),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -60,12 +60,7 @@ class SyncStatusState {
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
remoteSyncStatus,
|
||||
localSyncStatus,
|
||||
hashJobStatus,
|
||||
errorMessage,
|
||||
);
|
||||
int get hashCode => Object.hash(remoteSyncStatus, localSyncStatus, hashJobStatus, errorMessage);
|
||||
}
|
||||
|
||||
class SyncStatusNotifier extends Notifier<SyncStatusState> {
|
||||
@@ -84,10 +79,7 @@ class SyncStatusNotifier extends Notifier<SyncStatusState> {
|
||||
///
|
||||
|
||||
void setRemoteSyncStatus(SyncStatus status, [String? errorMessage]) {
|
||||
state = state.copyWith(
|
||||
remoteSyncStatus: status,
|
||||
errorMessage: status == SyncStatus.error ? errorMessage : null,
|
||||
);
|
||||
state = state.copyWith(remoteSyncStatus: status, errorMessage: status == SyncStatus.error ? errorMessage : null);
|
||||
}
|
||||
|
||||
void startRemoteSync() => setRemoteSyncStatus(SyncStatus.syncing);
|
||||
@@ -99,10 +91,7 @@ class SyncStatusNotifier extends Notifier<SyncStatusState> {
|
||||
///
|
||||
|
||||
void setLocalSyncStatus(SyncStatus status, [String? errorMessage]) {
|
||||
state = state.copyWith(
|
||||
localSyncStatus: status,
|
||||
errorMessage: status == SyncStatus.error ? errorMessage : null,
|
||||
);
|
||||
state = state.copyWith(localSyncStatus: status, errorMessage: status == SyncStatus.error ? errorMessage : null);
|
||||
}
|
||||
|
||||
void startLocalSync() => setLocalSyncStatus(SyncStatus.syncing);
|
||||
@@ -114,10 +103,7 @@ class SyncStatusNotifier extends Notifier<SyncStatusState> {
|
||||
///
|
||||
|
||||
void setHashJobStatus(SyncStatus status, [String? errorMessage]) {
|
||||
state = state.copyWith(
|
||||
hashJobStatus: status,
|
||||
errorMessage: status == SyncStatus.error ? errorMessage : null,
|
||||
);
|
||||
state = state.copyWith(hashJobStatus: status, errorMessage: status == SyncStatus.error ? errorMessage : null);
|
||||
}
|
||||
|
||||
void startHashJob() => setHashJobStatus(SyncStatus.syncing);
|
||||
@@ -125,6 +111,4 @@ class SyncStatusNotifier extends Notifier<SyncStatusState> {
|
||||
void errorHashJob(String error) => setHashJobStatus(SyncStatus.error, error);
|
||||
}
|
||||
|
||||
final syncStatusProvider = NotifierProvider<SyncStatusNotifier, SyncStatusState>(
|
||||
SyncStatusNotifier.new,
|
||||
);
|
||||
final syncStatusProvider = NotifierProvider<SyncStatusNotifier, SyncStatusState>(SyncStatusNotifier.new);
|
||||
|
||||
@@ -3,6 +3,4 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
enum TabEnum { home, search, albums, library }
|
||||
|
||||
/// Provides the currently active tab
|
||||
final tabProvider = StateProvider<TabEnum>(
|
||||
(ref) => TabEnum.home,
|
||||
);
|
||||
final tabProvider = StateProvider<TabEnum>((ref) => TabEnum.home);
|
||||
|
||||
@@ -31,13 +31,8 @@ final immichThemePresetProvider = StateProvider<ImmichColorPreset>((ref) {
|
||||
try {
|
||||
return ImmichColorPreset.values.firstWhere((e) => e.name == primaryColorPreset);
|
||||
} catch (e) {
|
||||
debugPrint(
|
||||
"Theme preset $primaryColorPreset not found. Applying default preset.",
|
||||
);
|
||||
appSettingsProvider.setSetting(
|
||||
AppSettingsEnum.primaryColor,
|
||||
defaultColorPresetName,
|
||||
);
|
||||
debugPrint("Theme preset $primaryColorPreset not found. Applying default preset.");
|
||||
appSettingsProvider.setSetting(AppSettingsEnum.primaryColor, defaultColorPresetName);
|
||||
return defaultColorPreset;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -5,27 +5,21 @@ import 'package:immich_mobile/providers/locale_provider.dart';
|
||||
import 'package:immich_mobile/services/timeline.service.dart';
|
||||
import 'package:immich_mobile/widgets/asset_grid/asset_grid_data_structure.dart';
|
||||
|
||||
final singleUserTimelineProvider = StreamProvider.family<RenderList, String?>(
|
||||
(ref, userId) {
|
||||
if (userId == null) {
|
||||
return const Stream.empty();
|
||||
}
|
||||
final singleUserTimelineProvider = StreamProvider.family<RenderList, String?>((ref, userId) {
|
||||
if (userId == null) {
|
||||
return const Stream.empty();
|
||||
}
|
||||
|
||||
ref.watch(localeProvider);
|
||||
final timelineService = ref.watch(timelineServiceProvider);
|
||||
return timelineService.watchHomeTimeline(userId);
|
||||
},
|
||||
dependencies: [localeProvider],
|
||||
);
|
||||
ref.watch(localeProvider);
|
||||
final timelineService = ref.watch(timelineServiceProvider);
|
||||
return timelineService.watchHomeTimeline(userId);
|
||||
}, dependencies: [localeProvider]);
|
||||
|
||||
final multiUsersTimelineProvider = StreamProvider.family<RenderList, List<String>>(
|
||||
(ref, userIds) {
|
||||
ref.watch(localeProvider);
|
||||
final timelineService = ref.watch(timelineServiceProvider);
|
||||
return timelineService.watchMultiUsersTimeline(userIds);
|
||||
},
|
||||
dependencies: [localeProvider],
|
||||
);
|
||||
final multiUsersTimelineProvider = StreamProvider.family<RenderList, List<String>>((ref, userIds) {
|
||||
ref.watch(localeProvider);
|
||||
final timelineService = ref.watch(timelineServiceProvider);
|
||||
return timelineService.watchMultiUsersTimeline(userIds);
|
||||
}, dependencies: [localeProvider]);
|
||||
|
||||
final albumTimelineProvider = StreamProvider.autoDispose.family<RenderList, int>((ref, id) {
|
||||
final album = ref.watch(albumWatcher(id)).value;
|
||||
@@ -65,10 +59,7 @@ final assetSelectionTimelineProvider = StreamProvider<RenderList>((ref) {
|
||||
|
||||
final assetsTimelineProvider = FutureProvider.family<RenderList, List<Asset>>((ref, assets) {
|
||||
final timelineService = ref.watch(timelineServiceProvider);
|
||||
return timelineService.getTimelineFromAssets(
|
||||
assets,
|
||||
null,
|
||||
);
|
||||
return timelineService.getTimelineFromAssets(assets, null);
|
||||
});
|
||||
|
||||
final lockedTimelineProvider = StreamProvider<RenderList>((ref) {
|
||||
|
||||
@@ -15,26 +15,17 @@ class MultiSelectState {
|
||||
final Set<BaseAsset> lockedSelectionAssets;
|
||||
final bool forceEnable;
|
||||
|
||||
const MultiSelectState({
|
||||
required this.selectedAssets,
|
||||
required this.lockedSelectionAssets,
|
||||
this.forceEnable = false,
|
||||
});
|
||||
const MultiSelectState({required this.selectedAssets, required this.lockedSelectionAssets, this.forceEnable = false});
|
||||
|
||||
bool get isEnabled => selectedAssets.isNotEmpty;
|
||||
|
||||
/// Cloud only
|
||||
bool get hasRemote => selectedAssets.any(
|
||||
(asset) => asset.storage == AssetState.remote || asset.storage == AssetState.merged,
|
||||
);
|
||||
bool get hasRemote =>
|
||||
selectedAssets.any((asset) => asset.storage == AssetState.remote || asset.storage == AssetState.merged);
|
||||
|
||||
bool get hasLocal => selectedAssets.any(
|
||||
(asset) => asset.storage == AssetState.local,
|
||||
);
|
||||
bool get hasLocal => selectedAssets.any((asset) => asset.storage == AssetState.local);
|
||||
|
||||
bool get hasMerged => selectedAssets.any(
|
||||
(asset) => asset.storage == AssetState.merged,
|
||||
);
|
||||
bool get hasMerged => selectedAssets.any((asset) => asset.storage == AssetState.merged);
|
||||
|
||||
MultiSelectState copyWith({
|
||||
Set<BaseAsset>? selectedAssets,
|
||||
@@ -74,12 +65,7 @@ class MultiSelectNotifier extends Notifier<MultiSelectState> {
|
||||
|
||||
@override
|
||||
MultiSelectState build() {
|
||||
return _defaultState ??
|
||||
const MultiSelectState(
|
||||
selectedAssets: {},
|
||||
lockedSelectionAssets: {},
|
||||
forceEnable: false,
|
||||
);
|
||||
return _defaultState ?? const MultiSelectState(selectedAssets: {}, lockedSelectionAssets: {}, forceEnable: false);
|
||||
}
|
||||
|
||||
void selectAsset(BaseAsset asset) {
|
||||
@@ -87,9 +73,7 @@ class MultiSelectNotifier extends Notifier<MultiSelectState> {
|
||||
return;
|
||||
}
|
||||
|
||||
state = state.copyWith(
|
||||
selectedAssets: {...state.selectedAssets, asset},
|
||||
);
|
||||
state = state.copyWith(selectedAssets: {...state.selectedAssets, asset});
|
||||
}
|
||||
|
||||
void deselectAsset(BaseAsset asset) {
|
||||
@@ -97,9 +81,7 @@ class MultiSelectNotifier extends Notifier<MultiSelectState> {
|
||||
return;
|
||||
}
|
||||
|
||||
state = state.copyWith(
|
||||
selectedAssets: state.selectedAssets.where((a) => a != asset).toSet(),
|
||||
);
|
||||
state = state.copyWith(selectedAssets: state.selectedAssets.where((a) => a != asset).toSet());
|
||||
}
|
||||
|
||||
void toggleAssetSelection(BaseAsset asset) {
|
||||
@@ -111,11 +93,7 @@ class MultiSelectNotifier extends Notifier<MultiSelectState> {
|
||||
}
|
||||
|
||||
void reset() {
|
||||
state = const MultiSelectState(
|
||||
selectedAssets: {},
|
||||
lockedSelectionAssets: {},
|
||||
forceEnable: false,
|
||||
);
|
||||
state = const MultiSelectState(selectedAssets: {}, lockedSelectionAssets: {}, forceEnable: false);
|
||||
}
|
||||
|
||||
/// Bucket bulk operations
|
||||
@@ -125,9 +103,7 @@ class MultiSelectNotifier extends Notifier<MultiSelectState> {
|
||||
|
||||
selectedAssets.addAll(assets);
|
||||
|
||||
state = state.copyWith(
|
||||
selectedAssets: selectedAssets,
|
||||
);
|
||||
state = state.copyWith(selectedAssets: selectedAssets);
|
||||
}
|
||||
|
||||
void deselectBucket(int offset, int bucketCount) async {
|
||||
@@ -164,20 +140,15 @@ class MultiSelectNotifier extends Notifier<MultiSelectState> {
|
||||
}
|
||||
|
||||
void setLockedSelectionAssets(Set<BaseAsset> assets) {
|
||||
state = state.copyWith(
|
||||
lockedSelectionAssets: assets,
|
||||
);
|
||||
state = state.copyWith(lockedSelectionAssets: assets);
|
||||
}
|
||||
}
|
||||
|
||||
final bucketSelectionProvider = Provider.family<bool, List<BaseAsset>>(
|
||||
(ref, bucketAssets) {
|
||||
final selectedAssets = ref.watch(multiSelectProvider.select((s) => s.selectedAssets));
|
||||
final bucketSelectionProvider = Provider.family<bool, List<BaseAsset>>((ref, bucketAssets) {
|
||||
final selectedAssets = ref.watch(multiSelectProvider.select((s) => s.selectedAssets));
|
||||
|
||||
if (bucketAssets.isEmpty) return false;
|
||||
if (bucketAssets.isEmpty) return false;
|
||||
|
||||
// Check if all assets in the bucket are selected
|
||||
return bucketAssets.every((asset) => selectedAssets.contains(asset));
|
||||
},
|
||||
dependencies: [multiSelectProvider, timelineServiceProvider],
|
||||
);
|
||||
// Check if all assets in the bucket are selected
|
||||
return bucketAssets.every((asset) => selectedAssets.contains(asset));
|
||||
}, dependencies: [multiSelectProvider, timelineServiceProvider]);
|
||||
|
||||
@@ -7,9 +7,7 @@ class TrashNotifier extends StateNotifier<bool> {
|
||||
final TrashService _trashService;
|
||||
final _log = Logger('TrashNotifier');
|
||||
|
||||
TrashNotifier(
|
||||
this._trashService,
|
||||
) : super(false);
|
||||
TrashNotifier(this._trashService) : super(false);
|
||||
|
||||
Future<void> emptyTrash() async {
|
||||
try {
|
||||
@@ -43,7 +41,5 @@ class TrashNotifier extends StateNotifier<bool> {
|
||||
}
|
||||
|
||||
final trashProvider = StateNotifierProvider<TrashNotifier, bool>((ref) {
|
||||
return TrashNotifier(
|
||||
ref.watch(trashServiceProvider),
|
||||
);
|
||||
return TrashNotifier(ref.watch(trashServiceProvider));
|
||||
});
|
||||
|
||||
@@ -6,26 +6,15 @@ import 'package:image_picker/image_picker.dart';
|
||||
import 'package:immich_mobile/domain/services/user.service.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/user.provider.dart';
|
||||
|
||||
enum UploadProfileStatus {
|
||||
idle,
|
||||
loading,
|
||||
success,
|
||||
failure,
|
||||
}
|
||||
enum UploadProfileStatus { idle, loading, success, failure }
|
||||
|
||||
class UploadProfileImageState {
|
||||
// enum
|
||||
final UploadProfileStatus status;
|
||||
final String profileImagePath;
|
||||
const UploadProfileImageState({
|
||||
required this.status,
|
||||
required this.profileImagePath,
|
||||
});
|
||||
const UploadProfileImageState({required this.status, required this.profileImagePath});
|
||||
|
||||
UploadProfileImageState copyWith({
|
||||
UploadProfileStatus? status,
|
||||
String? profileImagePath,
|
||||
}) {
|
||||
UploadProfileImageState copyWith({UploadProfileStatus? status, String? profileImagePath}) {
|
||||
return UploadProfileImageState(
|
||||
status: status ?? this.status,
|
||||
profileImagePath: profileImagePath ?? this.profileImagePath,
|
||||
@@ -68,29 +57,18 @@ class UploadProfileImageState {
|
||||
|
||||
class UploadProfileImageNotifier extends StateNotifier<UploadProfileImageState> {
|
||||
UploadProfileImageNotifier(this._userService)
|
||||
: super(
|
||||
const UploadProfileImageState(
|
||||
profileImagePath: '',
|
||||
status: UploadProfileStatus.idle,
|
||||
),
|
||||
);
|
||||
: super(const UploadProfileImageState(profileImagePath: '', status: UploadProfileStatus.idle));
|
||||
|
||||
final UserService _userService;
|
||||
|
||||
Future<bool> upload(XFile file) async {
|
||||
state = state.copyWith(status: UploadProfileStatus.loading);
|
||||
|
||||
var profileImagePath = await _userService.createProfileImage(
|
||||
file.name,
|
||||
await file.readAsBytes(),
|
||||
);
|
||||
var profileImagePath = await _userService.createProfileImage(file.name, await file.readAsBytes());
|
||||
|
||||
if (profileImagePath != null) {
|
||||
debugPrint("Successfully upload profile image");
|
||||
state = state.copyWith(
|
||||
status: UploadProfileStatus.success,
|
||||
profileImagePath: profileImagePath,
|
||||
);
|
||||
state = state.copyWith(status: UploadProfileStatus.success, profileImagePath: profileImagePath);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,23 +22,14 @@ import 'package:logging/logging.dart';
|
||||
import 'package:openapi/api.dart';
|
||||
import 'package:socket_io_client/socket_io_client.dart';
|
||||
|
||||
enum PendingAction {
|
||||
assetDelete,
|
||||
assetUploaded,
|
||||
assetHidden,
|
||||
assetTrash,
|
||||
}
|
||||
enum PendingAction { assetDelete, assetUploaded, assetHidden, assetTrash }
|
||||
|
||||
class PendingChange {
|
||||
final String id;
|
||||
final PendingAction action;
|
||||
final dynamic value;
|
||||
|
||||
const PendingChange(
|
||||
this.id,
|
||||
this.action,
|
||||
this.value,
|
||||
);
|
||||
const PendingChange(this.id, this.action, this.value);
|
||||
|
||||
@override
|
||||
String toString() => 'PendingChange(id: $id, action: $action, value: $value)';
|
||||
@@ -59,17 +50,9 @@ class WebsocketState {
|
||||
final bool isConnected;
|
||||
final List<PendingChange> pendingChanges;
|
||||
|
||||
const WebsocketState({
|
||||
this.socket,
|
||||
required this.isConnected,
|
||||
required this.pendingChanges,
|
||||
});
|
||||
const WebsocketState({this.socket, required this.isConnected, required this.pendingChanges});
|
||||
|
||||
WebsocketState copyWith({
|
||||
Socket? socket,
|
||||
bool? isConnected,
|
||||
List<PendingChange>? pendingChanges,
|
||||
}) {
|
||||
WebsocketState copyWith({Socket? socket, bool? isConnected, List<PendingChange>? pendingChanges}) {
|
||||
return WebsocketState(
|
||||
socket: socket ?? this.socket,
|
||||
isConnected: isConnected ?? this.isConnected,
|
||||
@@ -92,14 +75,7 @@ class WebsocketState {
|
||||
}
|
||||
|
||||
class WebsocketNotifier extends StateNotifier<WebsocketState> {
|
||||
WebsocketNotifier(this._ref)
|
||||
: super(
|
||||
const WebsocketState(
|
||||
socket: null,
|
||||
isConnected: false,
|
||||
pendingChanges: [],
|
||||
),
|
||||
);
|
||||
WebsocketNotifier(this._ref) : super(const WebsocketState(socket: null, isConnected: false, pendingChanges: []));
|
||||
|
||||
final _log = Logger('WebsocketNotifier');
|
||||
final Ref _ref;
|
||||
@@ -147,29 +123,17 @@ class WebsocketNotifier extends StateNotifier<WebsocketState> {
|
||||
|
||||
socket.onConnect((_) {
|
||||
debugPrint("Established Websocket Connection");
|
||||
state = WebsocketState(
|
||||
isConnected: true,
|
||||
socket: socket,
|
||||
pendingChanges: state.pendingChanges,
|
||||
);
|
||||
state = WebsocketState(isConnected: true, socket: socket, pendingChanges: state.pendingChanges);
|
||||
});
|
||||
|
||||
socket.onDisconnect((_) {
|
||||
debugPrint("Disconnect to Websocket Connection");
|
||||
state = WebsocketState(
|
||||
isConnected: false,
|
||||
socket: null,
|
||||
pendingChanges: state.pendingChanges,
|
||||
);
|
||||
state = WebsocketState(isConnected: false, socket: null, pendingChanges: state.pendingChanges);
|
||||
});
|
||||
|
||||
socket.on('error', (errorMessage) {
|
||||
_log.severe("Websocket Error - $errorMessage");
|
||||
state = WebsocketState(
|
||||
isConnected: false,
|
||||
socket: null,
|
||||
pendingChanges: state.pendingChanges,
|
||||
);
|
||||
state = WebsocketState(isConnected: false, socket: null, pendingChanges: state.pendingChanges);
|
||||
});
|
||||
|
||||
if (!Store.isBetaTimelineEnabled) {
|
||||
@@ -200,11 +164,7 @@ class WebsocketNotifier extends StateNotifier<WebsocketState> {
|
||||
var socket = state.socket?.disconnect();
|
||||
|
||||
if (socket?.disconnected == true) {
|
||||
state = WebsocketState(
|
||||
isConnected: false,
|
||||
socket: null,
|
||||
pendingChanges: state.pendingChanges,
|
||||
);
|
||||
state = WebsocketState(isConnected: false, socket: null, pendingChanges: state.pendingChanges);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,10 +208,7 @@ class WebsocketNotifier extends StateNotifier<WebsocketState> {
|
||||
void addPendingChange(PendingAction action, dynamic value) {
|
||||
final now = DateTime.now();
|
||||
state = state.copyWith(
|
||||
pendingChanges: [
|
||||
...state.pendingChanges,
|
||||
PendingChange(now.millisecondsSinceEpoch.toString(), action, value),
|
||||
],
|
||||
pendingChanges: [...state.pendingChanges, PendingChange(now.millisecondsSinceEpoch.toString(), action, value)],
|
||||
);
|
||||
_debounce.run(handlePendingChanges);
|
||||
}
|
||||
@@ -264,9 +221,7 @@ class WebsocketNotifier extends StateNotifier<WebsocketState> {
|
||||
await _ref.read(syncServiceProvider).handleRemoteAssetRemoval(remoteIds);
|
||||
await _ref.read(assetProvider.notifier).getAllAsset();
|
||||
|
||||
state = state.copyWith(
|
||||
pendingChanges: state.pendingChanges.whereNot((c) => trashChanges.contains(c)).toList(),
|
||||
);
|
||||
state = state.copyWith(pendingChanges: state.pendingChanges.whereNot((c) => trashChanges.contains(c)).toList());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,9 +230,7 @@ class WebsocketNotifier extends StateNotifier<WebsocketState> {
|
||||
if (deleteChanges.isNotEmpty) {
|
||||
List<String> remoteIds = deleteChanges.map((a) => a.value.toString()).toList();
|
||||
await _ref.read(syncServiceProvider).handleRemoteAssetRemoval(remoteIds);
|
||||
state = state.copyWith(
|
||||
pendingChanges: state.pendingChanges.whereNot((c) => deleteChanges.contains(c)).toList(),
|
||||
);
|
||||
state = state.copyWith(pendingChanges: state.pendingChanges.whereNot((c) => deleteChanges.contains(c)).toList());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,9 +257,7 @@ class WebsocketNotifier extends StateNotifier<WebsocketState> {
|
||||
final db = _ref.watch(dbProvider);
|
||||
await db.writeTxn(() => db.assets.deleteAllByRemoteId(remoteIds));
|
||||
|
||||
state = state.copyWith(
|
||||
pendingChanges: state.pendingChanges.whereNot((c) => hiddenChanges.contains(c)).toList(),
|
||||
);
|
||||
state = state.copyWith(pendingChanges: state.pendingChanges.whereNot((c) => hiddenChanges.contains(c)).toList());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -372,9 +323,7 @@ class WebsocketNotifier extends StateNotifier<WebsocketState> {
|
||||
}
|
||||
|
||||
try {
|
||||
unawaited(
|
||||
_ref.read(backgroundSyncProvider).syncWebsocketBatch(_batchedAssetUploadReady.toList()),
|
||||
);
|
||||
unawaited(_ref.read(backgroundSyncProvider).syncWebsocketBatch(_batchedAssetUploadReady.toList()));
|
||||
} catch (error) {
|
||||
_log.severe("Error processing batched AssetUploadReadyV1 events: $error");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user