mirror of
https://github.com/immich-app/immich.git
synced 2025-12-20 09:15:35 +03:00
feat(mobile): new mobile UI (#12582)
This commit is contained in:
@@ -1,21 +1,21 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/entities/user.entity.dart';
|
||||
import 'package:immich_mobile/models/albums/album_search.model.dart';
|
||||
import 'package:immich_mobile/services/album.service.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/album.entity.dart';
|
||||
import 'package:immich_mobile/entities/store.entity.dart';
|
||||
import 'package:immich_mobile/entities/user.entity.dart';
|
||||
import 'package:immich_mobile/providers/db.provider.dart';
|
||||
import 'package:immich_mobile/utils/renderlist_generator.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
|
||||
final isRefreshingRemoteAlbumProvider = StateProvider<bool>((ref) => false);
|
||||
|
||||
class AlbumNotifier extends StateNotifier<List<Album>> {
|
||||
AlbumNotifier(this._albumService, Isar db) : super([]) {
|
||||
final query = db.albums
|
||||
.filter()
|
||||
.owner((q) => q.isarIdEqualTo(Store.get(StoreKey.currentUser).isarId));
|
||||
AlbumNotifier(this._albumService, this.db, this.ref) : super([]) {
|
||||
final query = db.albums.filter().remoteIdIsNotNull();
|
||||
query.findAll().then((value) {
|
||||
if (mounted) {
|
||||
state = value;
|
||||
@@ -25,14 +25,22 @@ class AlbumNotifier extends StateNotifier<List<Album>> {
|
||||
}
|
||||
|
||||
final AlbumService _albumService;
|
||||
final Isar db;
|
||||
final Ref ref;
|
||||
late final StreamSubscription<List<Album>> _streamSub;
|
||||
|
||||
Future<void> getAllAlbums() => Future.wait([
|
||||
_albumService.refreshDeviceAlbums(),
|
||||
_albumService.refreshRemoteAlbums(isShared: false),
|
||||
]);
|
||||
Future<void> refreshRemoteAlbums() async {
|
||||
final isRefresing =
|
||||
ref.read(isRefreshingRemoteAlbumProvider.notifier).state;
|
||||
|
||||
Future<void> getDeviceAlbums() => _albumService.refreshDeviceAlbums();
|
||||
if (isRefresing) return;
|
||||
|
||||
ref.read(isRefreshingRemoteAlbumProvider.notifier).state = true;
|
||||
await _albumService.refreshRemoteAlbums();
|
||||
ref.read(isRefreshingRemoteAlbumProvider.notifier).state = false;
|
||||
}
|
||||
|
||||
Future<void> refreshDeviceAlbums() => _albumService.refreshDeviceAlbums();
|
||||
|
||||
Future<bool> deleteAlbum(Album album) => _albumService.deleteAlbum(album);
|
||||
|
||||
@@ -59,6 +67,50 @@ class AlbumNotifier extends StateNotifier<List<Album>> {
|
||||
await createAlbum(albumName, {});
|
||||
}
|
||||
|
||||
Future<bool> leaveAlbum(Album album) async {
|
||||
var res = await _albumService.leaveAlbum(album);
|
||||
|
||||
if (res) {
|
||||
await deleteAlbum(album);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void searchAlbums(String searchTerm, QuickFilterMode filterMode) async {
|
||||
state = await _albumService.search(searchTerm, filterMode);
|
||||
}
|
||||
|
||||
Future<void> addUsers(Album album, List<String> userIds) async {
|
||||
await _albumService.addUsers(album, userIds);
|
||||
}
|
||||
|
||||
Future<bool> removeUser(Album album, User user) async {
|
||||
final isRemoved = await _albumService.removeUser(album, user);
|
||||
|
||||
if (isRemoved && album.sharedUsers.isEmpty) {
|
||||
state = state.where((element) => element.id != album.id).toList();
|
||||
}
|
||||
|
||||
return isRemoved;
|
||||
}
|
||||
|
||||
Future<void> addAssets(Album album, Iterable<Asset> assets) async {
|
||||
await _albumService.addAssets(album, assets);
|
||||
}
|
||||
|
||||
Future<bool> removeAsset(Album album, Iterable<Asset> assets) async {
|
||||
return await _albumService.removeAsset(album, assets);
|
||||
}
|
||||
|
||||
Future<bool> setActivitystatus(
|
||||
Album album,
|
||||
bool enabled,
|
||||
) {
|
||||
return _albumService.setActivityStatus(album, enabled);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_streamSub.cancel();
|
||||
@@ -71,6 +123,7 @@ final albumProvider =
|
||||
return AlbumNotifier(
|
||||
ref.watch(albumServiceProvider),
|
||||
ref.watch(dbProvider),
|
||||
ref,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -94,3 +147,31 @@ final albumRenderlistProvider =
|
||||
}
|
||||
return const Stream.empty();
|
||||
});
|
||||
|
||||
class LocalAlbumsNotifier extends StateNotifier<List<Album>> {
|
||||
LocalAlbumsNotifier(this.db) : super([]) {
|
||||
final query = db.albums.where().remoteIdIsNull();
|
||||
|
||||
query.findAll().then((value) {
|
||||
if (mounted) {
|
||||
state = value;
|
||||
}
|
||||
});
|
||||
|
||||
_streamSub = query.watch().listen((data) => state = data);
|
||||
}
|
||||
|
||||
final Isar db;
|
||||
late final StreamSubscription<List<Album>> _streamSub;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_streamSub.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
final localAlbumsProvider =
|
||||
StateNotifierProvider.autoDispose<LocalAlbumsNotifier, List<Album>>((ref) {
|
||||
return LocalAlbumsNotifier(ref.watch(dbProvider));
|
||||
});
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/models/albums/album_viewer_page_state.model.dart';
|
||||
import 'package:immich_mobile/providers/album/shared_album.provider.dart';
|
||||
import 'package:immich_mobile/services/album.service.dart';
|
||||
import 'package:immich_mobile/entities/album.entity.dart';
|
||||
|
||||
@@ -40,7 +39,6 @@ class AlbumViewerNotifier extends StateNotifier<AlbumViewerPageState> {
|
||||
|
||||
if (isSuccess) {
|
||||
state = state.copyWith(editTitleText: "", isEditAlbum: false);
|
||||
ref.read(sharedAlbumProvider.notifier).getAllSharedAlbums();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/services/album.service.dart';
|
||||
import 'package:immich_mobile/entities/album.entity.dart';
|
||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||
import 'package:immich_mobile/entities/user.entity.dart';
|
||||
import 'package:immich_mobile/providers/db.provider.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
|
||||
class SharedAlbumNotifier extends StateNotifier<List<Album>> {
|
||||
SharedAlbumNotifier(this._albumService, Isar db) : super([]) {
|
||||
final query = db.albums.filter().sharedEqualTo(true).sortByCreatedAtDesc();
|
||||
query.findAll().then((value) {
|
||||
if (mounted) {
|
||||
state = value;
|
||||
}
|
||||
});
|
||||
_streamSub = query.watch().listen((data) => state = data);
|
||||
}
|
||||
|
||||
final AlbumService _albumService;
|
||||
late final StreamSubscription<List<Album>> _streamSub;
|
||||
|
||||
Future<Album?> createSharedAlbum(
|
||||
String albumName,
|
||||
Iterable<Asset> assets,
|
||||
Iterable<User> sharedUsers,
|
||||
) async {
|
||||
try {
|
||||
return await _albumService.createAlbum(
|
||||
albumName,
|
||||
assets,
|
||||
sharedUsers,
|
||||
);
|
||||
} catch (e) {
|
||||
debugPrint("Error createSharedAlbum ${e.toString()}");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<void> getAllSharedAlbums() =>
|
||||
_albumService.refreshRemoteAlbums(isShared: true);
|
||||
|
||||
Future<bool> deleteAlbum(Album album) => _albumService.deleteAlbum(album);
|
||||
|
||||
Future<bool> leaveAlbum(Album album) async {
|
||||
var res = await _albumService.leaveAlbum(album);
|
||||
|
||||
if (res) {
|
||||
await deleteAlbum(album);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> removeAssetFromAlbum(Album album, Iterable<Asset> assets) {
|
||||
return _albumService.removeAssetFromAlbum(album, assets);
|
||||
}
|
||||
|
||||
Future<bool> removeUserFromAlbum(Album album, User user) async {
|
||||
final result = await _albumService.removeUserFromAlbum(album, user);
|
||||
|
||||
if (result && album.sharedUsers.isEmpty) {
|
||||
state = state.where((element) => element.id != album.id).toList();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Future<bool> setActivityEnabled(Album album, bool activityEnabled) {
|
||||
return _albumService.setActivityEnabled(album, activityEnabled);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_streamSub.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
final sharedAlbumProvider =
|
||||
StateNotifierProvider.autoDispose<SharedAlbumNotifier, List<Album>>((ref) {
|
||||
return SharedAlbumNotifier(
|
||||
ref.watch(albumServiceProvider),
|
||||
ref.watch(dbProvider),
|
||||
);
|
||||
});
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/providers/album/album.provider.dart';
|
||||
import 'package:immich_mobile/providers/album/shared_album.provider.dart';
|
||||
import 'package:immich_mobile/services/background.service.dart';
|
||||
import 'package:immich_mobile/models/backup/backup_state.model.dart';
|
||||
import 'package:immich_mobile/providers/backup/backup.provider.dart';
|
||||
@@ -58,11 +57,10 @@ class AppLifeCycleNotifier extends StateNotifier<AppLifeCycleEnum> {
|
||||
_ref.read(assetProvider.notifier).getAllAsset();
|
||||
case TabEnum.search:
|
||||
// nothing to do
|
||||
case TabEnum.sharing:
|
||||
_ref.read(assetProvider.notifier).getAllAsset();
|
||||
_ref.read(sharedAlbumProvider.notifier).getAllSharedAlbums();
|
||||
case TabEnum.albums:
|
||||
_ref.read(albumProvider.notifier).refreshRemoteAlbums();
|
||||
case TabEnum.library:
|
||||
_ref.read(albumProvider.notifier).getAllAlbums();
|
||||
// nothing to do
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_udid/flutter_udid.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/providers/album/album.provider.dart';
|
||||
import 'package:immich_mobile/providers/album/shared_album.provider.dart';
|
||||
import 'package:immich_mobile/entities/store.entity.dart';
|
||||
import 'package:immich_mobile/models/authentication/authentication_state.model.dart';
|
||||
import 'package:immich_mobile/entities/user.entity.dart';
|
||||
@@ -115,7 +114,6 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> {
|
||||
Store.delete(StoreKey.accessToken),
|
||||
]);
|
||||
_ref.invalidate(albumProvider);
|
||||
_ref.invalidate(sharedAlbumProvider);
|
||||
|
||||
state = state.copyWith(
|
||||
deviceId: "",
|
||||
|
||||
@@ -7,7 +7,7 @@ part of 'backup_verification.provider.dart';
|
||||
// **************************************************************************
|
||||
|
||||
String _$backupVerificationHash() =>
|
||||
r'b691e0cc27856eef189258d3c102cc73ce4812a4';
|
||||
r'021dfdf65e1903c932e4a1c14967b786dd3516fb';
|
||||
|
||||
/// See also [BackupVerification].
|
||||
@ProviderFor(BackupVerification)
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
|
||||
enum TabEnum {
|
||||
home,
|
||||
search,
|
||||
sharing,
|
||||
library,
|
||||
}
|
||||
enum TabEnum { home, search, albums, library }
|
||||
|
||||
/// Provides the currently active tab
|
||||
final tabProvider = StateProvider<TabEnum>(
|
||||
|
||||
Reference in New Issue
Block a user