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:
shenlong
2025-07-29 00:34:03 +05:30
committed by GitHub
parent 9b3718120b
commit e52b9d15b5
643 changed files with 32561 additions and 35292 deletions
+3 -6
View File
@@ -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
View File
@@ -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
View File
@@ -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
+6 -28
View File
@@ -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);
}
}
@@ -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
View File
@@ -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
+3 -2
View File
@@ -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);
}
}
+6 -23
View File
@@ -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
View File
@@ -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() {
+15 -29
View File
@@ -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");
}
}
+56 -116
View File
@@ -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();
+11 -11
View File
@@ -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,
);
+3 -8
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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,
);
+4 -18
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+1 -3
View File
@@ -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);
}
+29 -25
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+25 -60
View File
@@ -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));
});
+6 -22
View File
@@ -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);
+1 -3
View File
@@ -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);
+2 -7
View File
@@ -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;
}
});
+14 -23
View File
@@ -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]);
+2 -6
View File
@@ -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;
}
+14 -65
View File
@@ -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");
}