feat(mobile): unify partner assets on timeline (#4974)
* feat(mobile): unify partner assets on timeline * skip non-owned assets in bulk actions * add message when trying to delete partner assets
This commit is contained in:
committed by
GitHub
parent
0c482960ce
commit
9fa9ad05b1
@@ -31,7 +31,8 @@ class User {
|
||||
isPartnerSharedWith = false,
|
||||
profileImagePath = dto.profileImagePath,
|
||||
isAdmin = dto.isAdmin,
|
||||
memoryEnabled = dto.memoriesEnabled;
|
||||
memoryEnabled = dto.memoriesEnabled ?? false,
|
||||
inTimeline = false;
|
||||
|
||||
User.fromPartnerDto(PartnerResponseDto dto)
|
||||
: id = dto.id,
|
||||
@@ -42,8 +43,8 @@ class User {
|
||||
isPartnerSharedWith = false,
|
||||
profileImagePath = dto.profileImagePath,
|
||||
isAdmin = dto.isAdmin,
|
||||
memoryEnabled = dto.memoriesEnabled,
|
||||
inTimeline = dto.inTimeline;
|
||||
memoryEnabled = dto.memoriesEnabled ?? false,
|
||||
inTimeline = dto.inTimeline ?? false;
|
||||
|
||||
@Index(unique: true, replace: false, type: IndexType.hash)
|
||||
String id;
|
||||
@@ -54,8 +55,8 @@ class User {
|
||||
bool isPartnerSharedWith;
|
||||
bool isAdmin;
|
||||
String profileImagePath;
|
||||
bool? memoryEnabled;
|
||||
bool? inTimeline;
|
||||
bool memoryEnabled;
|
||||
bool inTimeline;
|
||||
|
||||
@Backlink(to: 'owner')
|
||||
final IsarLinks<Album> albums = IsarLinks<Album>();
|
||||
|
||||
@@ -151,11 +151,11 @@ User _userDeserialize(
|
||||
final object = User(
|
||||
email: reader.readString(offsets[0]),
|
||||
id: reader.readString(offsets[1]),
|
||||
inTimeline: reader.readBoolOrNull(offsets[2]),
|
||||
inTimeline: reader.readBoolOrNull(offsets[2]) ?? false,
|
||||
isAdmin: reader.readBool(offsets[3]),
|
||||
isPartnerSharedBy: reader.readBoolOrNull(offsets[4]) ?? false,
|
||||
isPartnerSharedWith: reader.readBoolOrNull(offsets[5]) ?? false,
|
||||
memoryEnabled: reader.readBoolOrNull(offsets[6]),
|
||||
memoryEnabled: reader.readBoolOrNull(offsets[6]) ?? true,
|
||||
name: reader.readString(offsets[7]),
|
||||
profileImagePath: reader.readStringOrNull(offsets[8]) ?? '',
|
||||
updatedAt: reader.readDateTime(offsets[9]),
|
||||
@@ -175,7 +175,7 @@ P _userDeserializeProp<P>(
|
||||
case 1:
|
||||
return (reader.readString(offset)) as P;
|
||||
case 2:
|
||||
return (reader.readBoolOrNull(offset)) as P;
|
||||
return (reader.readBoolOrNull(offset) ?? false) as P;
|
||||
case 3:
|
||||
return (reader.readBool(offset)) as P;
|
||||
case 4:
|
||||
@@ -183,7 +183,7 @@ P _userDeserializeProp<P>(
|
||||
case 5:
|
||||
return (reader.readBoolOrNull(offset) ?? false) as P;
|
||||
case 6:
|
||||
return (reader.readBoolOrNull(offset)) as P;
|
||||
return (reader.readBoolOrNull(offset) ?? true) as P;
|
||||
case 7:
|
||||
return (reader.readString(offset)) as P;
|
||||
case 8:
|
||||
@@ -638,24 +638,8 @@ extension UserQueryFilter on QueryBuilder<User, User, QFilterCondition> {
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<User, User, QAfterFilterCondition> inTimelineIsNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNull(
|
||||
property: r'inTimeline',
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<User, User, QAfterFilterCondition> inTimelineIsNotNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNotNull(
|
||||
property: r'inTimeline',
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<User, User, QAfterFilterCondition> inTimelineEqualTo(
|
||||
bool? value) {
|
||||
bool value) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.equalTo(
|
||||
property: r'inTimeline',
|
||||
@@ -745,24 +729,8 @@ extension UserQueryFilter on QueryBuilder<User, User, QFilterCondition> {
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<User, User, QAfterFilterCondition> memoryEnabledIsNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNull(
|
||||
property: r'memoryEnabled',
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<User, User, QAfterFilterCondition> memoryEnabledIsNotNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNotNull(
|
||||
property: r'memoryEnabled',
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<User, User, QAfterFilterCondition> memoryEnabledEqualTo(
|
||||
bool? value) {
|
||||
bool value) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.equalTo(
|
||||
property: r'memoryEnabled',
|
||||
@@ -1540,7 +1508,7 @@ extension UserQueryProperty on QueryBuilder<User, User, QQueryProperty> {
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<User, bool?, QQueryOperations> inTimelineProperty() {
|
||||
QueryBuilder<User, bool, QQueryOperations> inTimelineProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'inTimeline');
|
||||
});
|
||||
@@ -1564,7 +1532,7 @@ extension UserQueryProperty on QueryBuilder<User, User, QQueryProperty> {
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<User, bool?, QQueryOperations> memoryEnabledProperty() {
|
||||
QueryBuilder<User, bool, QQueryOperations> memoryEnabledProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'memoryEnabled');
|
||||
});
|
||||
|
||||
@@ -54,6 +54,7 @@ class AppStateNotiifer extends StateNotifier<AppStateEnum> {
|
||||
switch (ref.read(tabProvider)) {
|
||||
case TabEnum.home:
|
||||
ref.read(assetProvider.notifier).getAllAsset();
|
||||
ref.read(assetProvider.notifier).getPartnerAssets();
|
||||
case TabEnum.search:
|
||||
// nothing to do
|
||||
case TabEnum.sharing:
|
||||
|
||||
@@ -8,12 +8,11 @@ import 'package:immich_mobile/shared/providers/db.provider.dart';
|
||||
import 'package:immich_mobile/shared/providers/user.provider.dart';
|
||||
import 'package:immich_mobile/shared/services/asset.service.dart';
|
||||
import 'package:immich_mobile/modules/home/ui/asset_grid/asset_grid_data_structure.dart';
|
||||
import 'package:immich_mobile/modules/settings/providers/app_settings.provider.dart';
|
||||
import 'package:immich_mobile/modules/settings/services/app_settings.service.dart';
|
||||
import 'package:immich_mobile/shared/models/asset.dart';
|
||||
import 'package:immich_mobile/shared/services/sync.service.dart';
|
||||
import 'package:immich_mobile/shared/services/user.service.dart';
|
||||
import 'package:immich_mobile/utils/db.dart';
|
||||
import 'package:immich_mobile/utils/renderlist_generator.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:photo_manager/photo_manager.dart';
|
||||
@@ -251,26 +250,23 @@ final assetWatcher =
|
||||
return db.assets.watchObject(asset.id, fireImmediately: true);
|
||||
});
|
||||
|
||||
final assetsProvider =
|
||||
StreamProvider.family<RenderList, int?>((ref, userId) async* {
|
||||
if (userId == null) return;
|
||||
final query = ref
|
||||
.watch(dbProvider)
|
||||
.assets
|
||||
.where()
|
||||
.ownerIdEqualToAnyChecksum(userId)
|
||||
.filter()
|
||||
.isArchivedEqualTo(false)
|
||||
.isTrashedEqualTo(false)
|
||||
.stackParentIdIsNull()
|
||||
.sortByFileCreatedAtDesc();
|
||||
final settings = ref.watch(appSettingsServiceProvider);
|
||||
final groupBy =
|
||||
GroupAssetsBy.values[settings.getSetting(AppSettingsEnum.groupAssetsBy)];
|
||||
yield await RenderList.fromQuery(query, groupBy);
|
||||
await for (final _ in query.watchLazy()) {
|
||||
yield await RenderList.fromQuery(query, groupBy);
|
||||
}
|
||||
final assetsProvider = StreamProvider.family<RenderList, int?>((ref, userId) {
|
||||
if (userId == null) return const Stream.empty();
|
||||
final query = _commonFilterAndSort(
|
||||
_assets(ref).where().ownerIdEqualToAnyChecksum(userId),
|
||||
);
|
||||
return renderListGenerator(query, ref);
|
||||
});
|
||||
|
||||
final multiUserAssetsProvider =
|
||||
StreamProvider.family<RenderList, List<int>>((ref, userIds) {
|
||||
if (userIds.isEmpty) return const Stream.empty();
|
||||
final query = _commonFilterAndSort(
|
||||
_assets(ref)
|
||||
.where()
|
||||
.anyOf(userIds, (q, u) => q.ownerIdEqualToAnyChecksum(u)),
|
||||
);
|
||||
return renderListGenerator(query, ref);
|
||||
});
|
||||
|
||||
QueryBuilder<Asset, Asset, QAfterSortBy>? getRemoteAssetQuery(WidgetRef ref) {
|
||||
@@ -289,3 +285,17 @@ QueryBuilder<Asset, Asset, QAfterSortBy>? getRemoteAssetQuery(WidgetRef ref) {
|
||||
.stackParentIdIsNull()
|
||||
.sortByFileCreatedAtDesc();
|
||||
}
|
||||
|
||||
IsarCollection<Asset> _assets(StreamProviderRef<RenderList> ref) =>
|
||||
ref.watch(dbProvider).assets;
|
||||
|
||||
QueryBuilder<Asset, Asset, QAfterSortBy> _commonFilterAndSort(
|
||||
QueryBuilder<Asset, Asset, QAfterWhereClause> query,
|
||||
) {
|
||||
return query
|
||||
.filter()
|
||||
.isArchivedEqualTo(false)
|
||||
.isTrashedEqualTo(false)
|
||||
.stackParentIdIsNull()
|
||||
.sortByFileCreatedAtDesc();
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ import 'dart:async';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/shared/models/store.dart';
|
||||
import 'package:immich_mobile/shared/models/user.dart';
|
||||
import 'package:immich_mobile/shared/providers/db.provider.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
|
||||
class CurrentUserProvider extends StateNotifier<User?> {
|
||||
CurrentUserProvider() : super(null) {
|
||||
@@ -24,3 +26,32 @@ final currentUserProvider =
|
||||
StateNotifierProvider<CurrentUserProvider, User?>((ref) {
|
||||
return CurrentUserProvider();
|
||||
});
|
||||
|
||||
class TimelineUserIdsProvider extends StateNotifier<List<int>> {
|
||||
TimelineUserIdsProvider(Isar db, User? currentUser) : super([]) {
|
||||
final query = db.users
|
||||
.filter()
|
||||
.inTimelineEqualTo(true)
|
||||
.or()
|
||||
.isarIdEqualTo(currentUser?.isarId ?? Isar.autoIncrement)
|
||||
.isarIdProperty();
|
||||
query.findAll().then((users) => state = users);
|
||||
streamSub = query.watch().listen((users) => state = users);
|
||||
}
|
||||
|
||||
late final StreamSubscription<List<int>> streamSub;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
streamSub.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
final timelineUsersIdsProvider =
|
||||
StateNotifierProvider<TimelineUserIdsProvider, List<int>>((ref) {
|
||||
return TimelineUserIdsProvider(
|
||||
ref.watch(dbProvider),
|
||||
ref.watch(currentUserProvider),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -99,7 +99,11 @@ class UserService {
|
||||
users,
|
||||
sharedWith,
|
||||
compare: (User a, User b) => a.id.compareTo(b.id),
|
||||
both: (User a, User b) => a.isPartnerSharedWith = true,
|
||||
both: (User a, User b) {
|
||||
a.isPartnerSharedWith = true;
|
||||
a.inTimeline = b.inTimeline;
|
||||
return true;
|
||||
},
|
||||
onlyFirst: (_) {},
|
||||
onlySecond: (_) {},
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user