This commit is contained in:
wuzihao051119 2025-06-04 19:25:50 +08:00
parent d7f445b78c
commit 02b62e5183
45 changed files with 138 additions and 186 deletions

View File

@ -1,12 +0,0 @@
enum SortOrder {
asc,
desc,
}
enum TextSearchType {
context,
filename,
description,
}
enum AssetVisibilityEnum { timeline, hidden, archive, locked }

View File

@ -1,12 +1,5 @@
part of 'base_asset.model.dart'; part of 'base_asset.model.dart';
enum AssetVisibility {
timeline,
hidden,
archive,
locked,
}
// Model for an asset stored in the server // Model for an asset stored in the server
class Asset extends BaseAsset { class Asset extends BaseAsset {
final String id; final String id;

View File

@ -1,14 +1,8 @@
import 'package:openapi/api.dart';
part 'asset.model.dart'; part 'asset.model.dart';
part 'local_asset.model.dart'; part 'local_asset.model.dart';
enum AssetType {
// do not change this order!
other,
image,
video,
audio,
}
sealed class BaseAsset { sealed class BaseAsset {
final String name; final String name;
final String? checksum; final String? checksum;

View File

@ -33,7 +33,7 @@ enum StoreKey<T> {
thumbnailCacheSize<int>._(110), thumbnailCacheSize<int>._(110),
imageCacheSize<int>._(111), imageCacheSize<int>._(111),
albumThumbnailCacheSize<int>._(112), albumThumbnailCacheSize<int>._(112),
selectedAlbumSortOrder<int>._(113), selectedAlbumAssetOrder<int>._(113),
advancedTroubleshooting<bool>._(114), advancedTroubleshooting<bool>._(114),
logLevel<int>._(115), logLevel<int>._(115),
preferRemoteImage<bool>._(116), preferRemoteImage<bool>._(116),

View File

@ -12,6 +12,7 @@ import 'package:immich_mobile/presentation/pages/dev/dev_logger.dart';
import 'package:immich_mobile/utils/diff.dart'; import 'package:immich_mobile/utils/diff.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:platform/platform.dart'; import 'package:platform/platform.dart';
import 'package:openapi/api.dart';
class LocalSyncService { class LocalSyncService {
final ILocalAlbumRepository _localAlbumRepository; final ILocalAlbumRepository _localAlbumRepository;
@ -365,7 +366,7 @@ extension on Iterable<PlatformAsset> {
(e) => LocalAsset( (e) => LocalAsset(
id: e.id, id: e.id,
name: e.name, name: e.name,
type: AssetType.values.elementAtOrNull(e.type) ?? AssetType.other, type: AssetType.values.elementAtOrNull(e.type) ?? AssetType.OTHER,
createdAt: e.createdAt == null createdAt: e.createdAt == null
? DateTime.now() ? DateTime.now()
: DateTime.fromMillisecondsSinceEpoch(e.createdAt! * 1000), : DateTime.fromMillisecondsSinceEpoch(e.createdAt! * 1000),

View File

@ -24,7 +24,7 @@ class Album {
this.lastModifiedAssetTimestamp, this.lastModifiedAssetTimestamp,
required this.shared, required this.shared,
required this.activityEnabled, required this.activityEnabled,
this.sortOrder = SortOrder.desc, this.sortOrder = AssetOrder.desc,
}); });
// fields stored in DB // fields stored in DB
@ -42,7 +42,7 @@ class Album {
bool shared; bool shared;
bool activityEnabled; bool activityEnabled;
@enumerated @enumerated
SortOrder sortOrder; AssetOrder assetOrder;
final IsarLink<User> owner = IsarLink<User>(); final IsarLink<User> owner = IsarLink<User>();
final IsarLink<Asset> thumbnail = IsarLink<Asset>(); final IsarLink<Asset> thumbnail = IsarLink<Asset>();
final IsarLinks<User> sharedUsers = IsarLinks<User>(); final IsarLinks<User> sharedUsers = IsarLinks<User>();
@ -160,7 +160,7 @@ class Album {
a.owner.value = await db.users.getById(dto.ownerId); a.owner.value = await db.users.getById(dto.ownerId);
if (dto.order != null) { if (dto.order != null) {
a.sortOrder = a.sortOrder =
dto.order == AssetOrder.asc ? SortOrder.asc : SortOrder.desc; dto.order == AssetOrder.asc ? AssetOrder.asc : AssetOrder.desc;
} }
if (dto.albumThumbnailAssetId != null) { if (dto.albumThumbnailAssetId != null) {

View File

@ -26,7 +26,7 @@ class Asset {
fileModifiedAt = remote.fileModifiedAt, fileModifiedAt = remote.fileModifiedAt,
updatedAt = remote.updatedAt, updatedAt = remote.updatedAt,
durationInSeconds = remote.duration.toDuration()?.inSeconds ?? 0, durationInSeconds = remote.duration.toDuration()?.inSeconds ?? 0,
type = remote.type.toAssetType(), type = remote.type,
fileName = remote.originalFileName, fileName = remote.originalFileName,
height = remote.exifInfo?.exifImageHeight?.toInt(), height = remote.exifInfo?.exifImageHeight?.toInt(),
width = remote.exifInfo?.exifImageWidth?.toInt(), width = remote.exifInfo?.exifImageWidth?.toInt(),
@ -47,7 +47,7 @@ class Asset {
stackCount = remote.stack?.assetCount ?? 0, stackCount = remote.stack?.assetCount ?? 0,
stackId = remote.stack?.id, stackId = remote.stack?.id,
thumbhash = remote.thumbhash, thumbhash = remote.thumbhash,
visibility = getVisibility(remote.visibility); visibility = remote.visibility;
Asset({ Asset({
this.id = Isar.autoIncrement, this.id = Isar.autoIncrement,
@ -73,7 +73,7 @@ class Asset {
this.stackCount = 0, this.stackCount = 0,
this.isOffline = false, this.isOffline = false,
this.thumbhash, this.thumbhash,
this.visibility = AssetVisibilityEnum.timeline, this.visibility = AssetVisibility.timeline,
}); });
@ignore @ignore
@ -177,7 +177,7 @@ class Asset {
int stackCount; int stackCount;
@Enumerated(EnumType.ordinal) @Enumerated(EnumType.ordinal)
AssetVisibilityEnum visibility; AssetVisibility visibility;
/// Returns null if the asset has no sync access to the exif info /// Returns null if the asset has no sync access to the exif info
@ignore @ignore
@ -210,10 +210,10 @@ class Asset {
bool get isRemote => remoteId != null; bool get isRemote => remoteId != null;
@ignore @ignore
bool get isImage => type == AssetType.image; bool get isImage => type == AssetType.IMAGE;
@ignore @ignore
bool get isVideo => type == AssetType.video; bool get isVideo => type == AssetType.VIDEO;
@ignore @ignore
bool get isMotionPhoto => livePhotoVideoId != null; bool get isMotionPhoto => livePhotoVideoId != null;
@ -459,7 +459,7 @@ class Asset {
String? stackPrimaryAssetId, String? stackPrimaryAssetId,
int? stackCount, int? stackCount,
String? thumbhash, String? thumbhash,
AssetVisibilityEnum? visibility, AssetVisibility? visibility,
}) => }) =>
Asset( Asset(
id: id ?? this.id, id: id ?? this.id,
@ -553,27 +553,6 @@ class Asset {
"visibility": "$visibility", "visibility": "$visibility",
}"""; }""";
} }
static getVisibility(AssetVisibility visibility) {
switch (visibility) {
case AssetVisibility.timeline:
return AssetVisibilityEnum.timeline;
case AssetVisibility.archive:
return AssetVisibilityEnum.archive;
case AssetVisibility.hidden:
return AssetVisibilityEnum.hidden;
case AssetVisibility.locked:
return AssetVisibilityEnum.locked;
}
}
}
enum AssetType {
// do not change this order!
other,
image,
video,
audio,
} }
/// Describes where the information of this asset came from: /// Describes where the information of this asset came from:

View File

@ -3,6 +3,7 @@ import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_mobile/infrastructure/entities/user.entity.dart'; import 'package:immich_mobile/infrastructure/entities/user.entity.dart';
import 'package:immich_mobile/infrastructure/utils/asset.mixin.dart'; import 'package:immich_mobile/infrastructure/utils/asset.mixin.dart';
import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart'; import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart';
import 'package:openapi/api.dart';
@TableIndex( @TableIndex(
name: 'UQ_remote_asset_owner_checksum', name: 'UQ_remote_asset_owner_checksum',

View File

@ -165,7 +165,7 @@ class DriftSyncStreamRepository extends DriftDatabaseRepository
for (final asset in data) { for (final asset in data) {
final companion = RemoteAssetEntityCompanion( final companion = RemoteAssetEntityCompanion(
name: Value(asset.originalFileName), name: Value(asset.originalFileName),
type: Value(asset.type.toAssetType()), type: Value(asset.type),
createdAt: Value.absentIfNull(asset.fileCreatedAt), createdAt: Value.absentIfNull(asset.fileCreatedAt),
updatedAt: Value.absentIfNull(asset.fileModifiedAt), updatedAt: Value.absentIfNull(asset.fileModifiedAt),
durationInSeconds: const Value(0), durationInSeconds: const Value(0),

View File

@ -1,6 +1,7 @@
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
mixin AssetEntityMixin on Table { mixin AssetEntityMixin on Table {
TextColumn get name => text()(); TextColumn get name => text()();
IntColumn get type => intEnum<AssetType>()(); IntColumn get type => intEnum<AssetType>()();

View File

@ -18,7 +18,7 @@ abstract interface class IAlbumApiRepository {
String? thumbnailAssetId, String? thumbnailAssetId,
String? description, String? description,
bool? activityEnabled, bool? activityEnabled,
SortOrder? sortOrder, AssetOrder? sortOrder,
}); });
Future<void> delete(String albumId); Future<void> delete(String albumId);

View File

@ -1,5 +1,6 @@
import 'package:immich_mobile/constants/enums.dart'; import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/entities/asset.entity.dart';
import 'package:openapi/api.dart';
abstract interface class IAssetApiRepository { abstract interface class IAssetApiRepository {
// Future<Asset> get(String id); // Future<Asset> get(String id);
@ -19,6 +20,6 @@ abstract interface class IAssetApiRepository {
Future<void> updateVisibility( Future<void> updateVisibility(
List<String> list, List<String> list,
AssetVisibilityEnum visibility, AssetVisibility visibility,
); );
} }

View File

@ -274,7 +274,7 @@ class SearchFilter {
display.isNotInAlbum == false && display.isNotInAlbum == false &&
display.isArchive == false && display.isArchive == false &&
display.isFavorite == false && display.isFavorite == false &&
mediaType == AssetType.other; mediaType == AssetType.OTHER;
} }
SearchFilter copyWith({ SearchFilter copyWith({

View File

@ -29,7 +29,7 @@ class AlbumsPage extends HookConsumerWidget {
final albums = final albums =
ref.watch(albumProvider).where((album) => album.isRemote).toList(); ref.watch(albumProvider).where((album) => album.isRemote).toList();
final albumSortOption = ref.watch(albumSortByOptionsProvider); final albumSortOption = ref.watch(albumSortByOptionsProvider);
final albumSortIsReverse = ref.watch(albumSortOrderProvider); final albumSortIsReverse = ref.watch(albumAssetOrderProvider);
final sorted = albumSortOption.sortFn(albums, albumSortIsReverse); final sorted = albumSortOption.sortFn(albums, albumSortIsReverse);
final isGrid = useState(false); final isGrid = useState(false);
final searchController = useTextEditingController(); final searchController = useTextEditingController();
@ -322,7 +322,7 @@ class SortButton extends ConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final albumSortOption = ref.watch(albumSortByOptionsProvider); final albumSortOption = ref.watch(albumSortByOptionsProvider);
final albumSortIsReverse = ref.watch(albumSortOrderProvider); final albumSortIsReverse = ref.watch(albumAssetOrderProvider);
return MenuAnchor( return MenuAnchor(
style: MenuStyle( style: MenuStyle(
@ -360,7 +360,7 @@ class SortButton extends ConsumerWidget {
// Switch direction // Switch direction
if (selected) { if (selected) {
ref ref
.read(albumSortOrderProvider.notifier) .read(albumAssetOrderProvider.notifier)
.changeSortDirection(!albumSortIsReverse); .changeSortDirection(!albumSortIsReverse);
} else { } else {
ref ref

View File

@ -15,6 +15,7 @@ import 'package:immich_mobile/routing/router.dart';
import 'package:immich_mobile/utils/bytes_units.dart'; import 'package:immich_mobile/utils/bytes_units.dart';
import 'package:immich_mobile/widgets/asset_grid/thumbnail_image.dart'; import 'package:immich_mobile/widgets/asset_grid/thumbnail_image.dart';
import 'package:immich_mobile/widgets/common/immich_toast.dart'; import 'package:immich_mobile/widgets/common/immich_toast.dart';
import 'package:openapi/api.dart';
RecursiveFolder? _findFolderInStructure( RecursiveFolder? _findFolderInStructure(
RootFolder rootFolder, RootFolder rootFolder,
@ -49,7 +50,7 @@ class FolderPage extends HookConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final folderState = ref.watch(folderStructureProvider); final folderState = ref.watch(folderStructureProvider);
final currentFolder = useState<RecursiveFolder?>(folder); final currentFolder = useState<RecursiveFolder?>(folder);
final sortOrder = useState<SortOrder>(SortOrder.asc); final sortOrder = useState<AssetOrder>(AssetOrder.asc);
useEffect( useEffect(
() { () {
@ -78,9 +79,9 @@ class FolderPage extends HookConsumerWidget {
[folderState], [folderState],
); );
void onToggleSortOrder() { void onToggleAssetOrder() {
final newOrder = final newOrder =
sortOrder.value == SortOrder.asc ? SortOrder.desc : SortOrder.asc; sortOrder.value == AssetOrder.asc ? AssetOrder.desc : AssetOrder.asc;
ref.read(folderStructureProvider.notifier).fetchFolders(newOrder); ref.read(folderStructureProvider.notifier).fetchFolders(newOrder);
@ -95,7 +96,7 @@ class FolderPage extends HookConsumerWidget {
actions: [ actions: [
IconButton( IconButton(
icon: const Icon(Icons.swap_vert), icon: const Icon(Icons.swap_vert),
onPressed: onToggleSortOrder, onPressed: onToggleAssetOrder,
), ),
], ],
), ),
@ -134,13 +135,13 @@ class FolderPage extends HookConsumerWidget {
class FolderContent extends HookConsumerWidget { class FolderContent extends HookConsumerWidget {
final RootFolder? folder; final RootFolder? folder;
final RootFolder root; final RootFolder root;
final SortOrder sortOrder; final AssetOrder sortOrder;
const FolderContent({ const FolderContent({
super.key, super.key,
this.folder, this.folder,
required this.root, required this.root,
this.sortOrder = SortOrder.asc, this.sortOrder = AssetOrder.asc,
}); });
@override @override

View File

@ -128,7 +128,7 @@ class PlaceTile extends StatelessWidget {
isArchive: false, isArchive: false,
isFavorite: false, isFavorite: false,
), ),
mediaType: AssetType.other, mediaType: AssetType.OTHER,
), ),
), ),
); );

View File

@ -5,7 +5,6 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/entities/asset.entity.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/interfaces/person_api.interface.dart'; import 'package:immich_mobile/interfaces/person_api.interface.dart';
@ -23,6 +22,7 @@ import 'package:immich_mobile/widgets/search/search_filter/media_type_picker.dar
import 'package:immich_mobile/widgets/search/search_filter/people_picker.dart'; import 'package:immich_mobile/widgets/search/search_filter/people_picker.dart';
import 'package:immich_mobile/widgets/search/search_filter/search_filter_chip.dart'; import 'package:immich_mobile/widgets/search/search_filter/search_filter_chip.dart';
import 'package:immich_mobile/widgets/search/search_filter/search_filter_utils.dart'; import 'package:immich_mobile/widgets/search/search_filter/search_filter_utils.dart';
import 'package:openapi/api.dart';
@RoutePage() @RoutePage()
class SearchPage extends HookConsumerWidget { class SearchPage extends HookConsumerWidget {
@ -47,7 +47,7 @@ class SearchPage extends HookConsumerWidget {
isArchive: false, isArchive: false,
isFavorite: false, isFavorite: false,
), ),
mediaType: prefilter?.mediaType ?? AssetType.other, mediaType: prefilter?.mediaType ?? AssetType.OTHER,
language: language:
"${context.locale.languageCode}-${context.locale.countryCode}", "${context.locale.languageCode}-${context.locale.countryCode}",
), ),
@ -371,9 +371,9 @@ class SearchPage extends HookConsumerWidget {
); );
mediaTypeCurrentFilterWidget.value = Text( mediaTypeCurrentFilterWidget.value = Text(
assetType == AssetType.image assetType == AssetType.IMAGE
? 'image'.tr() ? 'image'.tr()
: assetType == AssetType.video : assetType == AssetType.VIDEO
? 'video'.tr() ? 'video'.tr()
: 'all'.tr(), : 'all'.tr(),
style: context.textTheme.labelLarge, style: context.textTheme.labelLarge,
@ -382,7 +382,7 @@ class SearchPage extends HookConsumerWidget {
handleClear() { handleClear() {
filter.value = filter.value.copyWith( filter.value = filter.value.copyWith(
mediaType: AssetType.other, mediaType: AssetType.OTHER,
); );
mediaTypeCurrentFilterWidget.value = null; mediaTypeCurrentFilterWidget.value = null;

View File

@ -1,12 +1,12 @@
import 'dart:async'; import 'dart:async';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/domain/models/user.model.dart'; import 'package:immich_mobile/domain/models/user.model.dart';
import 'package:immich_mobile/entities/album.entity.dart'; import 'package:immich_mobile/entities/album.entity.dart';
import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/entities/asset.entity.dart';
import 'package:immich_mobile/models/albums/album_search.model.dart'; import 'package:immich_mobile/models/albums/album_search.model.dart';
import 'package:immich_mobile/services/album.service.dart'; import 'package:immich_mobile/services/album.service.dart';
import 'package:openapi/api.dart';
final isRefreshingRemoteAlbumProvider = StateProvider<bool>((ref) => false); final isRefreshingRemoteAlbumProvider = StateProvider<bool>((ref) => false);
@ -113,11 +113,11 @@ class AlbumNotifier extends StateNotifier<List<Album>> {
return albumService.setActivityStatus(album, enabled); return albumService.setActivityStatus(album, enabled);
} }
Future<Album?> toggleSortOrder(Album album) { Future<Album?> toggleAssetOrder(Album album) {
final order = final order =
album.sortOrder == SortOrder.asc ? SortOrder.desc : SortOrder.asc; album.sortOrder == AssetOrder.asc ? AssetOrder.desc : AssetOrder.asc;
return albumService.updateSortOrder(album, order); return albumService.updateAssetOrder(album, order);
} }
@override @override

View File

@ -106,7 +106,7 @@ class AlbumSortByOptions extends _$AlbumSortByOptions {
AlbumSortMode build() { AlbumSortMode build() {
final sortOpt = ref final sortOpt = ref
.watch(appSettingsServiceProvider) .watch(appSettingsServiceProvider)
.getSetting(AppSettingsEnum.selectedAlbumSortOrder); .getSetting(AppSettingsEnum.selectedAlbumAssetOrder);
return AlbumSortMode.values.firstWhere( return AlbumSortMode.values.firstWhere(
(e) => e.storeIndex == sortOpt, (e) => e.storeIndex == sortOpt,
orElse: () => AlbumSortMode.title, orElse: () => AlbumSortMode.title,
@ -116,14 +116,14 @@ class AlbumSortByOptions extends _$AlbumSortByOptions {
void changeSortMode(AlbumSortMode sortOption) { void changeSortMode(AlbumSortMode sortOption) {
state = sortOption; state = sortOption;
ref.watch(appSettingsServiceProvider).setSetting( ref.watch(appSettingsServiceProvider).setSetting(
AppSettingsEnum.selectedAlbumSortOrder, AppSettingsEnum.selectedAlbumAssetOrder,
sortOption.storeIndex, sortOption.storeIndex,
); );
} }
} }
@riverpod @riverpod
class AlbumSortOrder extends _$AlbumSortOrder { class AlbumAssetOrder extends _$AlbumAssetOrder {
@override @override
bool build() { bool build() {
return ref return ref

View File

@ -1,6 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/domain/models/store.model.dart'; import 'package:immich_mobile/domain/models/store.model.dart';
import 'package:immich_mobile/domain/services/user.service.dart'; import 'package:immich_mobile/domain/services/user.service.dart';
import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/entities/asset.entity.dart';
@ -13,6 +12,7 @@ import 'package:immich_mobile/services/etag.service.dart';
import 'package:immich_mobile/services/exif.service.dart'; import 'package:immich_mobile/services/exif.service.dart';
import 'package:immich_mobile/services/sync.service.dart'; import 'package:immich_mobile/services/sync.service.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:openapi/api.dart';
final assetProvider = StateNotifierProvider<AssetNotifier, bool>((ref) { final assetProvider = StateNotifierProvider<AssetNotifier, bool>((ref) {
return AssetNotifier( return AssetNotifier(
@ -174,7 +174,7 @@ class AssetNotifier extends StateNotifier<bool> {
Future<void> setLockedView( Future<void> setLockedView(
List<Asset> selection, List<Asset> selection,
AssetVisibilityEnum visibility, AssetVisibility visibility,
) { ) {
return _assetService.setVisibility(selection, visibility); return _assetService.setVisibility(selection, visibility);
} }

View File

@ -1,9 +1,9 @@
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/models/folder/root_folder.model.dart'; import 'package:immich_mobile/models/folder/root_folder.model.dart';
import 'package:immich_mobile/services/folder.service.dart'; import 'package:immich_mobile/services/folder.service.dart';
import 'package:immich_mobile/widgets/asset_grid/asset_grid_data_structure.dart'; import 'package:immich_mobile/widgets/asset_grid/asset_grid_data_structure.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:openapi/api.dart';
class FolderStructureNotifier extends StateNotifier<AsyncValue<RootFolder>> { class FolderStructureNotifier extends StateNotifier<AsyncValue<RootFolder>> {
final FolderService _folderService; final FolderService _folderService;
@ -11,7 +11,7 @@ class FolderStructureNotifier extends StateNotifier<AsyncValue<RootFolder>> {
FolderStructureNotifier(this._folderService) : super(const AsyncLoading()); FolderStructureNotifier(this._folderService) : super(const AsyncLoading());
Future<void> fetchFolders(SortOrder order) async { Future<void> fetchFolders(AssetOrder order) async {
try { try {
final folders = await _folderService.getFolderStructure(order); final folders = await _folderService.getFolderStructure(order);
state = AsyncData(folders); state = AsyncData(folders);
@ -38,7 +38,7 @@ class FolderRenderListNotifier extends StateNotifier<AsyncValue<RenderList>> {
FolderRenderListNotifier(this._folderService, this._folder) FolderRenderListNotifier(this._folderService, this._folder)
: super(const AsyncLoading()); : super(const AsyncLoading());
Future<void> fetchAssets(SortOrder order) async { Future<void> fetchAssets(AssetOrder order) async {
try { try {
final assets = await _folderService.getFolderAssets(_folder, order); final assets = await _folderService.getFolderAssets(_folder, order);
final renderList = final renderList =

View File

@ -9,6 +9,7 @@ import 'package:flutter/painting.dart';
import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/entities/asset.entity.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:photo_manager/photo_manager.dart' show ThumbnailSize; import 'package:photo_manager/photo_manager.dart' show ThumbnailSize;
import 'package:openapi/api.dart';
/// The local image provider for an asset /// The local image provider for an asset
class ImmichLocalImageProvider extends ImageProvider<ImmichLocalImageProvider> { class ImmichLocalImageProvider extends ImageProvider<ImmichLocalImageProvider> {
@ -60,7 +61,7 @@ class ImmichLocalImageProvider extends ImageProvider<ImmichLocalImageProvider> {
} }
switch (asset.type) { switch (asset.type) {
case AssetType.image: case AssetType.IMAGE:
final File? file = await local.originFile; final File? file = await local.originFile;
if (file == null) { if (file == null) {
throw StateError("Opening file for asset ${asset.fileName} failed"); throw StateError("Opening file for asset ${asset.fileName} failed");
@ -68,7 +69,7 @@ class ImmichLocalImageProvider extends ImageProvider<ImmichLocalImageProvider> {
final buffer = await ui.ImmutableBuffer.fromFilePath(file.path); final buffer = await ui.ImmutableBuffer.fromFilePath(file.path);
yield await decode(buffer); yield await decode(buffer);
break; break;
case AssetType.video: case AssetType.VIDEO:
final size = ThumbnailSize(width.ceil(), height.ceil()); final size = ThumbnailSize(width.ceil(), height.ceil());
final thumbBytes = await local.thumbnailDataWithSize(size); final thumbBytes = await local.thumbnailDataWithSize(size);
if (thumbBytes == null) { if (thumbBytes == null) {

View File

@ -1,5 +1,4 @@
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/entities/album.entity.dart'; import 'package:immich_mobile/entities/album.entity.dart';
import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/entities/asset.entity.dart';
import 'package:immich_mobile/infrastructure/entities/user.entity.dart' import 'package:immich_mobile/infrastructure/entities/user.entity.dart'
@ -59,11 +58,11 @@ class AlbumApiRepository extends ApiRepository implements IAlbumApiRepository {
String? thumbnailAssetId, String? thumbnailAssetId,
String? description, String? description,
bool? activityEnabled, bool? activityEnabled,
SortOrder? sortOrder, AssetOrder? sortOrder,
}) async { }) async {
AssetOrder? order; AssetOrder? order;
if (sortOrder != null) { if (sortOrder != null) {
order = sortOrder == SortOrder.asc ? AssetOrder.asc : AssetOrder.desc; order = sortOrder == AssetOrder.asc ? AssetOrder.asc : AssetOrder.desc;
} }
final response = await checkNull( final response = await checkNull(
@ -163,7 +162,7 @@ class AlbumApiRepository extends ApiRepository implements IAlbumApiRepository {
startDate: dto.startDate, startDate: dto.startDate,
endDate: dto.endDate, endDate: dto.endDate,
activityEnabled: dto.isActivityEnabled, activityEnabled: dto.isActivityEnabled,
sortOrder: dto.order == AssetOrder.asc ? SortOrder.asc : SortOrder.desc, sortOrder: dto.order == AssetOrder.asc ? AssetOrder.asc : AssetOrder.desc,
); );
album.remoteAssetCount = dto.assetCount; album.remoteAssetCount = dto.assetCount;
album.owner.value = album.owner.value =

View File

@ -1,5 +1,4 @@
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/entities/album.entity.dart'; import 'package:immich_mobile/entities/album.entity.dart';
import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/entities/asset.entity.dart';
import 'package:immich_mobile/entities/duplicated_asset.entity.dart'; import 'package:immich_mobile/entities/duplicated_asset.entity.dart';
@ -8,6 +7,7 @@ import 'package:immich_mobile/interfaces/asset.interface.dart';
import 'package:immich_mobile/providers/db.provider.dart'; import 'package:immich_mobile/providers/db.provider.dart';
import 'package:immich_mobile/repositories/database.repository.dart'; import 'package:immich_mobile/repositories/database.repository.dart';
import 'package:immich_mobile/utils/hash.dart'; import 'package:immich_mobile/utils/hash.dart';
import 'package:openapi/api.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
final assetRepositoryProvider = final assetRepositoryProvider =
@ -231,7 +231,7 @@ class AssetRepository extends DatabaseRepository implements IAssetRepository {
.where() .where()
.ownerIdEqualToAnyChecksum(fastHash(userId)) .ownerIdEqualToAnyChecksum(fastHash(userId))
.filter() .filter()
.visibilityEqualTo(AssetVisibilityEnum.timeline) .visibilityEqualTo(AssetVisibility.timeline)
.sortByFileCreatedAtDesc() .sortByFileCreatedAtDesc()
.findAll(); .findAll();
} }
@ -242,7 +242,7 @@ class AssetRepository extends DatabaseRepository implements IAssetRepository {
.where() .where()
.ownerIdEqualToAnyChecksum(fastHash(userId)) .ownerIdEqualToAnyChecksum(fastHash(userId))
.filter() .filter()
.visibilityEqualTo(AssetVisibilityEnum.timeline) .visibilityEqualTo(AssetVisibility.timeline)
.livePhotoVideoIdIsNotNull() .livePhotoVideoIdIsNotNull()
.findAll(); .findAll();
} }

View File

@ -1,5 +1,4 @@
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/entities/asset.entity.dart';
import 'package:immich_mobile/interfaces/asset_api.interface.dart'; import 'package:immich_mobile/interfaces/asset_api.interface.dart';
import 'package:immich_mobile/providers/api.provider.dart'; import 'package:immich_mobile/providers/api.provider.dart';
@ -53,23 +52,10 @@ class AssetApiRepository extends ApiRepository implements IAssetApiRepository {
@override @override
Future<void> updateVisibility( Future<void> updateVisibility(
List<String> ids, List<String> ids,
AssetVisibilityEnum visibility, AssetVisibility visibility,
) async { ) async {
return _api.updateAssets( return _api.updateAssets(
AssetBulkUpdateDto(ids: ids, visibility: _mapVisibility(visibility)), AssetBulkUpdateDto(ids: ids, visibility: visibility),
); );
} }
_mapVisibility(AssetVisibilityEnum visibility) {
switch (visibility) {
case AssetVisibilityEnum.timeline:
return AssetVisibility.timeline;
case AssetVisibilityEnum.hidden:
return AssetVisibility.hidden;
case AssetVisibilityEnum.locked:
return AssetVisibility.locked;
case AssetVisibilityEnum.archive:
return AssetVisibility.archive;
}
}
} }

View File

@ -6,6 +6,7 @@ import 'package:immich_mobile/entities/store.entity.dart';
import 'package:immich_mobile/interfaces/asset_media.interface.dart'; import 'package:immich_mobile/interfaces/asset_media.interface.dart';
import 'package:immich_mobile/utils/hash.dart'; import 'package:immich_mobile/utils/hash.dart';
import 'package:photo_manager/photo_manager.dart' hide AssetType; import 'package:photo_manager/photo_manager.dart' hide AssetType;
import 'package:openapi/api.dart';
final assetMediaRepositoryProvider = Provider((ref) => AssetMediaRepository()); final assetMediaRepositoryProvider = Provider((ref) => AssetMediaRepository());

View File

@ -1,5 +1,4 @@
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/entities/album.entity.dart'; import 'package:immich_mobile/entities/album.entity.dart';
import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/entities/asset.entity.dart';
import 'package:immich_mobile/infrastructure/entities/user.entity.dart'; import 'package:immich_mobile/infrastructure/entities/user.entity.dart';
@ -8,6 +7,7 @@ import 'package:immich_mobile/providers/db.provider.dart';
import 'package:immich_mobile/repositories/database.repository.dart'; import 'package:immich_mobile/repositories/database.repository.dart';
import 'package:immich_mobile/utils/hash.dart'; import 'package:immich_mobile/utils/hash.dart';
import 'package:immich_mobile/widgets/asset_grid/asset_grid_data_structure.dart'; import 'package:immich_mobile/widgets/asset_grid/asset_grid_data_structure.dart';
import 'package:openapi/api.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
final timelineRepositoryProvider = final timelineRepositoryProvider =
@ -46,7 +46,7 @@ class TimelineRepository extends DatabaseRepository
.ownerIdEqualToAnyChecksum(fastHash(userId)) .ownerIdEqualToAnyChecksum(fastHash(userId))
.filter() .filter()
.isTrashedEqualTo(false) .isTrashedEqualTo(false)
.visibilityEqualTo(AssetVisibilityEnum.archive) .visibilityEqualTo(AssetVisibility.archive)
.sortByFileCreatedAtDesc(); .sortByFileCreatedAtDesc();
return _watchRenderList(query, GroupAssetsBy.none); return _watchRenderList(query, GroupAssetsBy.none);
@ -60,7 +60,7 @@ class TimelineRepository extends DatabaseRepository
.filter() .filter()
.isFavoriteEqualTo(true) .isFavoriteEqualTo(true)
.not() .not()
.visibilityEqualTo(AssetVisibilityEnum.locked) .visibilityEqualTo(AssetVisibility.locked)
.isTrashedEqualTo(false) .isTrashedEqualTo(false)
.sortByFileCreatedAtDesc(); .sortByFileCreatedAtDesc();
@ -76,11 +76,11 @@ class TimelineRepository extends DatabaseRepository
.filter() .filter()
.isTrashedEqualTo(false) .isTrashedEqualTo(false)
.not() .not()
.visibilityEqualTo(AssetVisibilityEnum.locked); .visibilityEqualTo(AssetVisibility.locked);
final withSortedOption = switch (album.sortOrder) { final withSortedOption = switch (album.assetOrder) {
SortOrder.asc => query.sortByFileCreatedAt(), AssetOrder.asc => query.sortByFileCreatedAt(),
SortOrder.desc => query.sortByFileCreatedAtDesc(), AssetOrder.desc => query.sortByFileCreatedAtDesc(),
}; };
return _watchRenderList(withSortedOption, groupAssetByOption); return _watchRenderList(withSortedOption, groupAssetByOption);
@ -104,8 +104,8 @@ class TimelineRepository extends DatabaseRepository
.ownerIdEqualToAnyChecksum(fastHash(userId)) .ownerIdEqualToAnyChecksum(fastHash(userId))
.filter() .filter()
.isTrashedEqualTo(false) .isTrashedEqualTo(false)
.visibilityEqualTo(AssetVisibilityEnum.timeline) .visibilityEqualTo(AssetVisibility.timeline)
.typeEqualTo(AssetType.video) .typeEqualTo(AssetType.VIDEO)
.sortByFileCreatedAtDesc(); .sortByFileCreatedAtDesc();
return _watchRenderList(query, GroupAssetsBy.none); return _watchRenderList(query, GroupAssetsBy.none);
@ -122,7 +122,7 @@ class TimelineRepository extends DatabaseRepository
.filter() .filter()
.isTrashedEqualTo(false) .isTrashedEqualTo(false)
.stackPrimaryAssetIdIsNull() .stackPrimaryAssetIdIsNull()
.visibilityEqualTo(AssetVisibilityEnum.timeline) .visibilityEqualTo(AssetVisibility.timeline)
.sortByFileCreatedAtDesc(); .sortByFileCreatedAtDesc();
return _watchRenderList(query, groupAssetByOption); return _watchRenderList(query, groupAssetByOption);
@ -139,7 +139,7 @@ class TimelineRepository extends DatabaseRepository
.anyOf(isarUserIds, (qb, id) => qb.ownerIdEqualToAnyChecksum(id)) .anyOf(isarUserIds, (qb, id) => qb.ownerIdEqualToAnyChecksum(id))
.filter() .filter()
.isTrashedEqualTo(false) .isTrashedEqualTo(false)
.visibilityEqualTo(AssetVisibilityEnum.timeline) .visibilityEqualTo(AssetVisibility.timeline)
.stackPrimaryAssetIdIsNull() .stackPrimaryAssetIdIsNull()
.sortByFileCreatedAtDesc(); .sortByFileCreatedAtDesc();
return _watchRenderList(query, groupAssetByOption); return _watchRenderList(query, groupAssetByOption);
@ -160,7 +160,7 @@ class TimelineRepository extends DatabaseRepository
.remoteIdIsNotNull() .remoteIdIsNotNull()
.filter() .filter()
.ownerIdEqualTo(fastHash(userId)) .ownerIdEqualTo(fastHash(userId))
.visibilityEqualTo(AssetVisibilityEnum.timeline) .visibilityEqualTo(AssetVisibility.timeline)
.isTrashedEqualTo(false) .isTrashedEqualTo(false)
.stackPrimaryAssetIdIsNull() .stackPrimaryAssetIdIsNull()
.sortByFileCreatedAtDesc(); .sortByFileCreatedAtDesc();
@ -177,7 +177,7 @@ class TimelineRepository extends DatabaseRepository
.where() .where()
.ownerIdEqualToAnyChecksum(fastHash(userId)) .ownerIdEqualToAnyChecksum(fastHash(userId))
.filter() .filter()
.visibilityEqualTo(AssetVisibilityEnum.locked) .visibilityEqualTo(AssetVisibility.locked)
.isTrashedEqualTo(false) .isTrashedEqualTo(false)
.sortByFileCreatedAtDesc(); .sortByFileCreatedAtDesc();

View File

@ -5,7 +5,6 @@ import 'dart:io';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/domain/models/user.model.dart'; import 'package:immich_mobile/domain/models/user.model.dart';
import 'package:immich_mobile/domain/services/user.service.dart'; import 'package:immich_mobile/domain/services/user.service.dart';
import 'package:immich_mobile/entities/album.entity.dart'; import 'package:immich_mobile/entities/album.entity.dart';
@ -30,6 +29,7 @@ import 'package:immich_mobile/services/entity.service.dart';
import 'package:immich_mobile/services/sync.service.dart'; import 'package:immich_mobile/services/sync.service.dart';
import 'package:immich_mobile/utils/hash.dart'; import 'package:immich_mobile/utils/hash.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:openapi/api.dart';
final albumServiceProvider = Provider( final albumServiceProvider = Provider(
(ref) => AlbumService( (ref) => AlbumService(
@ -483,7 +483,7 @@ class AlbumService {
return _albumRepository.search(searchTerm, filterMode); return _albumRepository.search(searchTerm, filterMode);
} }
Future<Album?> updateSortOrder(Album album, SortOrder order) async { Future<Album?> updateAssetOrder(Album album, AssetOrder order) async {
try { try {
final updateAlbum = final updateAlbum =
await _albumApiRepository.update(album.remoteId!, sortOrder: order); await _albumApiRepository.update(album.remoteId!, sortOrder: order);

View File

@ -55,9 +55,9 @@ enum AppSettingsEnum<T> {
"albumThumbnailCacheSize", "albumThumbnailCacheSize",
200, 200,
), ),
selectedAlbumSortOrder<int>( selectedAlbumAssetOrder<int>(
StoreKey.selectedAlbumSortOrder, StoreKey.selectedAlbumAssetOrder,
"selectedAlbumSortOrder", "selectedAlbumAssetOrder",
0, 0,
), ),
advancedTroubleshooting<bool>(StoreKey.advancedTroubleshooting, null, false), advancedTroubleshooting<bool>(StoreKey.advancedTroubleshooting, null, false),

View File

@ -3,7 +3,6 @@ import 'dart:async';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/domain/interfaces/exif.interface.dart'; import 'package:immich_mobile/domain/interfaces/exif.interface.dart';
import 'package:immich_mobile/domain/interfaces/user.interface.dart'; import 'package:immich_mobile/domain/interfaces/user.interface.dart';
import 'package:immich_mobile/domain/models/user.model.dart'; import 'package:immich_mobile/domain/models/user.model.dart';
@ -241,8 +240,8 @@ class AssetService {
for (var element in assets) { for (var element in assets) {
element.isArchived = isArchived; element.isArchived = isArchived;
element.visibility = isArchived element.visibility = isArchived
? AssetVisibilityEnum.archive ? AssetVisibility.archive
: AssetVisibilityEnum.timeline; : AssetVisibility.timeline;
} }
await _syncService.upsertAssetsWithExif(assets); await _syncService.upsertAssetsWithExif(assets);
@ -480,7 +479,7 @@ class AssetService {
.where((asset) => asset.storage == AssetState.merged) .where((asset) => asset.storage == AssetState.merged)
.map((asset) { .map((asset) {
asset.remoteId = null; asset.remoteId = null;
asset.visibility = AssetVisibilityEnum.timeline; asset.visibility = AssetVisibility.timeline;
return asset; return asset;
}) })
: assets.where((asset) => asset.isRemote).map((asset) { : assets.where((asset) => asset.isRemote).map((asset) {
@ -538,7 +537,7 @@ class AssetService {
Future<void> setVisibility( Future<void> setVisibility(
List<Asset> assets, List<Asset> assets,
AssetVisibilityEnum visibility, AssetVisibility visibility,
) async { ) async {
await _assetApiRepository.updateVisibility( await _assetApiRepository.updateVisibility(
assets.map((asset) => asset.remoteId!).toList(), assets.map((asset) => asset.remoteId!).toList(),

View File

@ -520,10 +520,11 @@ class BackupService {
} }
String _getAssetType(AssetType assetType) => switch (assetType) { String _getAssetType(AssetType assetType) => switch (assetType) {
AssetType.audio => "AUDIO", AssetType.AUDIO => "AUDIO",
AssetType.image => "IMAGE", AssetType.IMAGE => "IMAGE",
AssetType.video => "VIDEO", AssetType.VIDEO => "VIDEO",
AssetType.other => "OTHER", AssetType.OTHER => "OTHER",
_ => throw Exception('Unknown AssetType value: $this'),
}; };
} }

View File

@ -21,6 +21,7 @@ import 'package:immich_mobile/repositories/file_media.repository.dart';
import 'package:immich_mobile/services/api.service.dart'; import 'package:immich_mobile/services/api.service.dart';
import 'package:immich_mobile/utils/bootstrap.dart'; import 'package:immich_mobile/utils/bootstrap.dart';
import 'package:immich_mobile/utils/diff.dart'; import 'package:immich_mobile/utils/diff.dart';
import 'package:openapi/api.dart';
/// Finds duplicates originating from missing EXIF information /// Finds duplicates originating from missing EXIF information
class BackupVerificationService { class BackupVerificationService {
@ -175,7 +176,7 @@ class BackupVerificationService {
remote.fileCreatedAt, remote.fileCreatedAt,
local.fileCreatedAt, local.fileCreatedAt,
))) { ))) {
if (remote.type == AssetType.video) { if (remote.type == AssetType.VIDEO) {
// it's very unlikely that a video of same length, filesize, name // it's very unlikely that a video of same length, filesize, name
// and date is wrong match. Cannot easily compare videos anyway // and date is wrong match. Cannot easily compare videos anyway
return true; return true;

View File

@ -5,6 +5,7 @@ import 'package:immich_mobile/models/folder/recursive_folder.model.dart';
import 'package:immich_mobile/models/folder/root_folder.model.dart'; import 'package:immich_mobile/models/folder/root_folder.model.dart';
import 'package:immich_mobile/repositories/folder_api.repository.dart'; import 'package:immich_mobile/repositories/folder_api.repository.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:openapi/api.dart';
final folderServiceProvider = Provider( final folderServiceProvider = Provider(
(ref) => FolderService(ref.watch(folderApiRepositoryProvider)), (ref) => FolderService(ref.watch(folderApiRepositoryProvider)),
@ -16,7 +17,7 @@ class FolderService {
FolderService(this._folderApiRepository); FolderService(this._folderApiRepository);
Future<RootFolder> getFolderStructure(SortOrder order) async { Future<RootFolder> getFolderStructure(AssetOrder order) async {
final paths = await _folderApiRepository.getAllUniquePaths(); final paths = await _folderApiRepository.getAllUniquePaths();
// Create folder structure // Create folder structure
@ -54,7 +55,7 @@ class FolderService {
); );
// Sort folders based on order parameter // Sort folders based on order parameter
folderMap[parentPath]!.sort( folderMap[parentPath]!.sort(
(a, b) => order == SortOrder.desc (a, b) => order == AssetOrder.desc
? b.name.compareTo(a.name) ? b.name.compareTo(a.name)
: a.name.compareTo(b.name), : a.name.compareTo(b.name),
); );
@ -71,7 +72,7 @@ class FolderService {
folder.subfolders.addAll(folderMap[fullPath]!); folder.subfolders.addAll(folderMap[fullPath]!);
// Sort subfolders based on order parameter // Sort subfolders based on order parameter
folder.subfolders.sort( folder.subfolders.sort(
(a, b) => order == SortOrder.desc (a, b) => order == AssetOrder.desc
? b.name.compareTo(a.name) ? b.name.compareTo(a.name)
: a.name.compareTo(b.name), : a.name.compareTo(b.name),
); );
@ -84,7 +85,7 @@ class FolderService {
List<RecursiveFolder> rootSubfolders = folderMap['_root_'] ?? []; List<RecursiveFolder> rootSubfolders = folderMap['_root_'] ?? [];
// Sort root subfolders based on order parameter // Sort root subfolders based on order parameter
rootSubfolders.sort( rootSubfolders.sort(
(a, b) => order == SortOrder.desc (a, b) => order == AssetOrder.desc
? b.name.compareTo(a.name) ? b.name.compareTo(a.name)
: a.name.compareTo(b.name), : a.name.compareTo(b.name),
); );
@ -101,7 +102,7 @@ class FolderService {
Future<List<Asset>> getFolderAssets( Future<List<Asset>> getFolderAssets(
RootFolder folder, RootFolder folder,
SortOrder order, AssetOrder order,
) async { ) async {
try { try {
if (folder is RecursiveFolder) { if (folder is RecursiveFolder) {
@ -110,7 +111,7 @@ class FolderService {
fullPath = fullPath[0] == '/' ? fullPath.substring(1) : fullPath; fullPath = fullPath[0] == '/' ? fullPath.substring(1) : fullPath;
var result = await _folderApiRepository.getAssetsForPath(fullPath); var result = await _folderApiRepository.getAssetsForPath(fullPath);
if (order == SortOrder.desc) { if (order == AssetOrder.desc) {
result.sort((a, b) => b.fileCreatedAt.compareTo(a.fileCreatedAt)); result.sort((a, b) => b.fileCreatedAt.compareTo(a.fileCreatedAt));
} else { } else {
result.sort((a, b) => a.fileCreatedAt.compareTo(b.fileCreatedAt)); result.sort((a, b) => a.fileCreatedAt.compareTo(b.fileCreatedAt));

View File

@ -50,9 +50,9 @@ class SearchService {
try { try {
SearchResponseDto? response; SearchResponseDto? response;
AssetType? type; AssetType? type;
if (filter.mediaType == AssetType.image) { if (filter.mediaType == AssetType.IMAGE) {
type = AssetType.IMAGE; type = AssetType.IMAGE;
} else if (filter.mediaType == AssetType.video) { } else if (filter.mediaType == AssetType.VIDEO) {
type = AssetType.VIDEO; type = AssetType.VIDEO;
} }

View File

@ -2,7 +2,6 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart'; import 'package:fluttertoast/fluttertoast.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/entities/asset.entity.dart';
import 'package:immich_mobile/extensions/asset_extensions.dart'; import 'package:immich_mobile/extensions/asset_extensions.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart';
@ -15,6 +14,7 @@ import 'package:immich_mobile/widgets/common/immich_toast.dart';
import 'package:immich_mobile/widgets/common/location_picker.dart'; import 'package:immich_mobile/widgets/common/location_picker.dart';
import 'package:immich_mobile/widgets/common/share_dialog.dart'; import 'package:immich_mobile/widgets/common/share_dialog.dart';
import 'package:maplibre_gl/maplibre_gl.dart'; import 'package:maplibre_gl/maplibre_gl.dart';
import 'package:openapi/api.dart';
void handleShareAssets( void handleShareAssets(
WidgetRef ref, WidgetRef ref,
@ -162,7 +162,7 @@ Future<void> handleEditLocation(
Future<void> handleSetAssetsVisibility( Future<void> handleSetAssetsVisibility(
WidgetRef ref, WidgetRef ref,
BuildContext context, BuildContext context,
AssetVisibilityEnum visibility, AssetVisibility visibility,
List<Asset> selection, { List<Asset> selection, {
ToastGravity toastGravity = ToastGravity.BOTTOM, ToastGravity toastGravity = ToastGravity.BOTTOM,
}) async { }) async {
@ -172,7 +172,7 @@ Future<void> handleSetAssetsVisibility(
.setLockedView(selection, visibility); .setLockedView(selection, visibility);
final assetOrAssets = selection.length > 1 ? 'assets' : 'asset'; final assetOrAssets = selection.length > 1 ? 'assets' : 'asset';
final toastMessage = visibility == AssetVisibilityEnum.locked final toastMessage = visibility == AssetVisibility.locked
? 'Added ${selection.length} $assetOrAssets to locked folder' ? 'Added ${selection.length} $assetOrAssets to locked folder'
: 'Removed ${selection.length} $assetOrAssets from locked folder'; : 'Removed ${selection.length} $assetOrAssets from locked folder';
if (context.mounted) { if (context.mounted) {

View File

@ -23,7 +23,7 @@ class AddToAlbumSliverList extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final albumSortMode = ref.watch(albumSortByOptionsProvider); final albumSortMode = ref.watch(albumSortByOptionsProvider);
final albumSortIsReverse = ref.watch(albumSortOrderProvider); final albumSortIsReverse = ref.watch(albumAssetOrderProvider);
final sortedAlbums = albumSortMode.sortFn(albums, albumSortIsReverse); final sortedAlbums = albumSortMode.sortFn(albums, albumSortIsReverse);
final sortedSharedAlbums = final sortedSharedAlbums =
albumSortMode.sortFn(sharedAlbums, albumSortIsReverse); albumSortMode.sortFn(sharedAlbums, albumSortIsReverse);

View File

@ -148,9 +148,9 @@ class AlbumViewerAppbar extends HookConsumerWidget
// } // }
} }
void onSortOrderToggled() async { void onAssetOrderToggled() async {
final updatedAlbum = final updatedAlbum =
await ref.read(albumProvider.notifier).toggleSortOrder(album); await ref.read(albumProvider.notifier).toggleAssetOrder(album);
if (updatedAlbum == null) { if (updatedAlbum == null) {
ImmichToast.show( ImmichToast.show(
@ -182,7 +182,7 @@ class AlbumViewerAppbar extends HookConsumerWidget
), ),
ListTile( ListTile(
leading: const Icon(Icons.swap_vert_rounded), leading: const Icon(Icons.swap_vert_rounded),
onTap: onSortOrderToggled, onTap: onAssetOrderToggled,
title: const Text( title: const Text(
"change_display_order", "change_display_order",
style: TextStyle(fontWeight: FontWeight.w500), style: TextStyle(fontWeight: FontWeight.w500),

View File

@ -7,7 +7,6 @@ import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:fluttertoast/fluttertoast.dart'; import 'package:fluttertoast/fluttertoast.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/entities/album.entity.dart'; import 'package:immich_mobile/entities/album.entity.dart';
import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/entities/asset.entity.dart';
import 'package:immich_mobile/extensions/collection_extensions.dart'; import 'package:immich_mobile/extensions/collection_extensions.dart';
@ -27,6 +26,7 @@ import 'package:immich_mobile/widgets/asset_grid/asset_grid_data_structure.dart'
import 'package:immich_mobile/widgets/asset_grid/control_bottom_app_bar.dart'; import 'package:immich_mobile/widgets/asset_grid/control_bottom_app_bar.dart';
import 'package:immich_mobile/widgets/asset_grid/immich_asset_grid.dart'; import 'package:immich_mobile/widgets/asset_grid/immich_asset_grid.dart';
import 'package:immich_mobile/widgets/common/immich_toast.dart'; import 'package:immich_mobile/widgets/common/immich_toast.dart';
import 'package:openapi/api.dart';
class MultiselectGrid extends HookConsumerWidget { class MultiselectGrid extends HookConsumerWidget {
const MultiselectGrid({ const MultiselectGrid({
@ -407,8 +407,8 @@ class MultiselectGrid extends HookConsumerWidget {
if (remoteAssets.isNotEmpty) { if (remoteAssets.isNotEmpty) {
final isInLockedView = ref.read(inLockedViewProvider); final isInLockedView = ref.read(inLockedViewProvider);
final visibility = isInLockedView final visibility = isInLockedView
? AssetVisibilityEnum.timeline ? AssetVisibility.timeline
: AssetVisibilityEnum.locked; : AssetVisibility.locked;
await handleSetAssetsVisibility( await handleSetAssetsVisibility(
ref, ref,

View File

@ -1,13 +1,13 @@
import 'package:auto_route/auto_route.dart'; import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:immich_mobile/domain/models/store.model.dart'; import 'package:immich_mobile/domain/models/store.model.dart';
import 'package:immich_mobile/entities/asset.entity.dart';
import 'package:immich_mobile/entities/store.entity.dart'; import 'package:immich_mobile/entities/store.entity.dart';
import 'package:immich_mobile/models/search/search_curated_content.model.dart'; import 'package:immich_mobile/models/search/search_curated_content.model.dart';
import 'package:immich_mobile/models/search/search_filter.model.dart'; import 'package:immich_mobile/models/search/search_filter.model.dart';
import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/routing/router.dart';
import 'package:immich_mobile/utils/image_url_builder.dart'; import 'package:immich_mobile/utils/image_url_builder.dart';
import 'package:immich_mobile/widgets/search/thumbnail_with_info.dart'; import 'package:immich_mobile/widgets/search/thumbnail_with_info.dart';
import 'package:openapi/api.dart';
class ExploreGrid extends StatelessWidget { class ExploreGrid extends StatelessWidget {
final List<SearchCuratedContent> curatedContent; final List<SearchCuratedContent> curatedContent;
@ -73,7 +73,7 @@ class ExploreGrid extends StatelessWidget {
isArchive: false, isArchive: false,
isFavorite: false, isFavorite: false,
), ),
mediaType: AssetType.other, mediaType: AssetType.OTHER,
), ),
), ),
); );

View File

@ -1,7 +1,7 @@
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:openapi/api.dart';
class MediaTypePicker extends HookWidget { class MediaTypePicker extends HookWidget {
const MediaTypePicker({super.key, required this.onSelect, this.filter}); const MediaTypePicker({super.key, required this.onSelect, this.filter});
@ -11,7 +11,7 @@ class MediaTypePicker extends HookWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final selectedMediaType = useState(filter ?? AssetType.other); final selectedMediaType = useState(filter ?? AssetType.OTHER);
return ListView( return ListView(
shrinkWrap: true, shrinkWrap: true,
@ -19,7 +19,7 @@ class MediaTypePicker extends HookWidget {
RadioListTile( RadioListTile(
key: const Key("all"), key: const Key("all"),
title: const Text("all").tr(), title: const Text("all").tr(),
value: AssetType.other, value: AssetType.OTHER,
onChanged: (value) { onChanged: (value) {
selectedMediaType.value = value!; selectedMediaType.value = value!;
onSelect(value); onSelect(value);
@ -29,7 +29,7 @@ class MediaTypePicker extends HookWidget {
RadioListTile( RadioListTile(
key: const Key("image"), key: const Key("image"),
title: const Text("image").tr(), title: const Text("image").tr(),
value: AssetType.image, value: AssetType.IMAGE,
onChanged: (value) { onChanged: (value) {
selectedMediaType.value = value!; selectedMediaType.value = value!;
onSelect(value); onSelect(value);
@ -39,7 +39,7 @@ class MediaTypePicker extends HookWidget {
RadioListTile( RadioListTile(
key: const Key("video"), key: const Key("video"),
title: const Text("video").tr(), title: const Text("video").tr(),
value: AssetType.video, value: AssetType.VIDEO,
onChanged: (value) { onChanged: (value) {
selectedMediaType.value = value!; selectedMediaType.value = value!;
onSelect(value); onSelect(value);

View File

@ -1,5 +1,6 @@
import 'package:immich_mobile/domain/models/exif.model.dart'; import 'package:immich_mobile/domain/models/exif.model.dart';
import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/entities/asset.entity.dart';
import 'package:openapi/api.dart';
final class AssetStub { final class AssetStub {
const AssetStub._(); const AssetStub._();
@ -13,7 +14,7 @@ final class AssetStub {
fileModifiedAt: DateTime(2020), fileModifiedAt: DateTime(2020),
updatedAt: DateTime.now(), updatedAt: DateTime.now(),
durationInSeconds: 0, durationInSeconds: 0,
type: AssetType.image, type: AssetType.IMAGE,
fileName: "image1.jpg", fileName: "image1.jpg",
isFavorite: true, isFavorite: true,
isArchived: false, isArchived: false,
@ -30,7 +31,7 @@ final class AssetStub {
fileModifiedAt: DateTime(2010), fileModifiedAt: DateTime(2010),
updatedAt: DateTime.now(), updatedAt: DateTime.now(),
durationInSeconds: 60, durationInSeconds: 60,
type: AssetType.video, type: AssetType.VIDEO,
fileName: "image2.jpg", fileName: "image2.jpg",
isFavorite: false, isFavorite: false,
isArchived: false, isArchived: false,
@ -46,7 +47,7 @@ final class AssetStub {
fileModifiedAt: DateTime(2025), fileModifiedAt: DateTime(2025),
updatedAt: DateTime.now(), updatedAt: DateTime.now(),
durationInSeconds: 60, durationInSeconds: 60,
type: AssetType.image, type: AssetType.IMAGE,
fileName: "image3.jpg", fileName: "image3.jpg",
isFavorite: true, isFavorite: true,
isArchived: false, isArchived: false,

View File

@ -233,7 +233,7 @@ void main() {
).thenAnswer((_) async => {}); ).thenAnswer((_) async => {});
when( when(
() => settingsMock.setSetting<int>( () => settingsMock.setSetting<int>(
AppSettingsEnum.selectedAlbumSortOrder, AppSettingsEnum.selectedAlbumAssetOrder,
any(), any(),
), ),
).thenAnswer((_) async => {}); ).thenAnswer((_) async => {});
@ -242,7 +242,7 @@ void main() {
test('Returns the default sort mode when none set', () { test('Returns the default sort mode when none set', () {
// Returns the default value when nothing is set // Returns the default value when nothing is set
when( when(
() => settingsMock.getSetting(AppSettingsEnum.selectedAlbumSortOrder), () => settingsMock.getSetting(AppSettingsEnum.selectedAlbumAssetOrder),
).thenReturn(0); ).thenReturn(0);
expect(container.read(albumSortByOptionsProvider), AlbumSortMode.created); expect(container.read(albumSortByOptionsProvider), AlbumSortMode.created);
@ -251,7 +251,7 @@ void main() {
test('Returns the correct sort mode with index from Store', () { test('Returns the correct sort mode with index from Store', () {
// Returns the default value when nothing is set // Returns the default value when nothing is set
when( when(
() => settingsMock.getSetting(AppSettingsEnum.selectedAlbumSortOrder), () => settingsMock.getSetting(AppSettingsEnum.selectedAlbumAssetOrder),
).thenReturn(3); ).thenReturn(3);
expect( expect(
@ -267,7 +267,7 @@ void main() {
verify( verify(
() => settingsMock.setSetting( () => settingsMock.setSetting(
AppSettingsEnum.selectedAlbumSortOrder, AppSettingsEnum.selectedAlbumAssetOrder,
AlbumSortMode.mostOldest.storeIndex, AlbumSortMode.mostOldest.storeIndex,
), ),
); );
@ -275,7 +275,7 @@ void main() {
test('Notifies listeners on state change', () { test('Notifies listeners on state change', () {
when( when(
() => settingsMock.getSetting(AppSettingsEnum.selectedAlbumSortOrder), () => settingsMock.getSetting(AppSettingsEnum.selectedAlbumAssetOrder),
).thenReturn(0); ).thenReturn(0);
final listener = ListenerMock<AlbumSortMode>(); final listener = ListenerMock<AlbumSortMode>();
@ -306,7 +306,7 @@ void main() {
}); });
/// Verify the sort order provider /// Verify the sort order provider
group('AlbumSortOrder', () { group('AlbumAssetOrder', () {
late AppSettingsService settingsMock; late AppSettingsService settingsMock;
late ProviderContainer container; late ProviderContainer container;
@ -327,7 +327,7 @@ void main() {
).thenAnswer((_) async => {}); ).thenAnswer((_) async => {});
when( when(
() => settingsMock.setSetting<int>( () => settingsMock.setSetting<int>(
AppSettingsEnum.selectedAlbumSortOrder, AppSettingsEnum.selectedAlbumAssetOrder,
any(), any(),
), ),
).thenAnswer((_) async => {}); ).thenAnswer((_) async => {});
@ -338,11 +338,11 @@ void main() {
() => settingsMock.getSetting(AppSettingsEnum.selectedAlbumSortReverse), () => settingsMock.getSetting(AppSettingsEnum.selectedAlbumSortReverse),
).thenReturn(false); ).thenReturn(false);
expect(container.read(albumSortOrderProvider), isFalse); expect(container.read(albumAssetOrderProvider), isFalse);
}); });
test('Properly saves the correct order', () { test('Properly saves the correct order', () {
container.read(albumSortOrderProvider.notifier).changeSortDirection(true); container.read(albumAssetOrderProvider.notifier).changeSortDirection(true);
verify( verify(
() => settingsMock.setSetting( () => settingsMock.setSetting(
@ -365,11 +365,11 @@ void main() {
); );
// false -> true // false -> true
container.read(albumSortOrderProvider.notifier).changeSortDirection(true); container.read(albumAssetOrderProvider.notifier).changeSortDirection(true);
// true -> false // true -> false
container container
.read(albumSortOrderProvider.notifier) .read(albumAssetOrderProvider.notifier)
.changeSortDirection(false); .changeSortDirection(false);
verifyInOrder([ verifyInOrder([

View File

@ -4,6 +4,7 @@ import 'package:immich_mobile/entities/asset.entity.dart';
import 'package:immich_mobile/extensions/asset_extensions.dart'; import 'package:immich_mobile/extensions/asset_extensions.dart';
import 'package:timezone/data/latest.dart'; import 'package:timezone/data/latest.dart';
import 'package:timezone/timezone.dart'; import 'package:timezone/timezone.dart';
import 'package:openapi/api.dart';
ExifInfo makeExif({ ExifInfo makeExif({
DateTime? dateTimeOriginal, DateTime? dateTimeOriginal,
@ -29,7 +30,7 @@ Asset makeAsset({
fileModifiedAt: DateTime.now(), fileModifiedAt: DateTime.now(),
updatedAt: DateTime.now(), updatedAt: DateTime.now(),
durationInSeconds: 0, durationInSeconds: 0,
type: AssetType.image, type: AssetType.IMAGE,
fileName: id, fileName: id,
isFavorite: false, isFavorite: false,
isArchived: false, isArchived: false,

View File

@ -1,6 +1,7 @@
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:immich_mobile/widgets/asset_grid/asset_grid_data_structure.dart'; import 'package:immich_mobile/widgets/asset_grid/asset_grid_data_structure.dart';
import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/entities/asset.entity.dart';
import 'package:openapi/api.dart';
void main() { void main() {
final List<Asset> testAssets = []; final List<Asset> testAssets = [];
@ -20,7 +21,7 @@ void main() {
fileModifiedAt: date, fileModifiedAt: date,
updatedAt: date, updatedAt: date,
durationInSeconds: 0, durationInSeconds: 0,
type: AssetType.image, type: AssetType.IMAGE,
fileName: '', fileName: '',
isFavorite: false, isFavorite: false,
isArchived: false, isArchived: false,

View File

@ -14,6 +14,7 @@ import 'package:immich_mobile/interfaces/asset.interface.dart';
import 'package:immich_mobile/interfaces/partner_api.interface.dart'; import 'package:immich_mobile/interfaces/partner_api.interface.dart';
import 'package:immich_mobile/services/sync.service.dart'; import 'package:immich_mobile/services/sync.service.dart';
import 'package:mocktail/mocktail.dart'; import 'package:mocktail/mocktail.dart';
import 'package:openapi/api.dart';
import '../../domain/service.mock.dart'; import '../../domain/service.mock.dart';
import '../../fixtures/asset.stub.dart'; import '../../fixtures/asset.stub.dart';
@ -41,7 +42,7 @@ void main() {
fileModifiedAt: date, fileModifiedAt: date,
updatedAt: date, updatedAt: date,
durationInSeconds: 0, durationInSeconds: 0,
type: AssetType.image, type: AssetType.IMAGE,
fileName: localId ?? remoteId ?? "", fileName: localId ?? remoteId ?? "",
isFavorite: false, isFavorite: false,
isArchived: false, isArchived: false,