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:
Fynn Petersen-Frey
2023-11-13 16:54:41 +01:00
committed by GitHub
parent 0c482960ce
commit 9fa9ad05b1
17 changed files with 274 additions and 138 deletions
@@ -2,21 +2,31 @@ import 'dart:async';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/modules/album/providers/suggested_shared_users.provider.dart';
import 'package:immich_mobile/modules/partner/services/partner.service.dart';
import 'package:immich_mobile/shared/models/user.dart';
import 'package:immich_mobile/shared/providers/db.provider.dart';
import 'package:isar/isar.dart';
class PartnerSharedWithNotifier extends StateNotifier<List<User>> {
PartnerSharedWithNotifier(Isar db) : super([]) {
PartnerSharedWithNotifier(Isar db, this._ps) : super([]) {
final query = db.users.filter().isPartnerSharedWithEqualTo(true);
query.findAll().then((partners) => state = partners);
query.watch().listen((partners) => state = partners);
}
Future<bool> updatePartner(User partner, {required bool inTimeline}) {
return _ps.updatePartner(partner, inTimeline: inTimeline);
}
final PartnerService _ps;
}
final partnerSharedWithProvider =
StateNotifierProvider<PartnerSharedWithNotifier, List<User>>((ref) {
return PartnerSharedWithNotifier(ref.watch(dbProvider));
return PartnerSharedWithNotifier(
ref.watch(dbProvider),
ref.watch(partnerServiceProvider),
);
});
class PartnerSharedByNotifier extends StateNotifier<List<User>> {
@@ -5,6 +5,7 @@ import 'package:immich_mobile/shared/providers/db.provider.dart';
import 'package:immich_mobile/shared/services/api.service.dart';
import 'package:isar/isar.dart';
import 'package:logging/logging.dart';
import 'package:openapi/api.dart';
final partnerServiceProvider = Provider(
(ref) => PartnerService(
@@ -69,4 +70,19 @@ class PartnerService {
}
return false;
}
Future<bool> updatePartner(User partner, {required bool inTimeline}) async {
try {
final dto = await _apiService.partnerApi
.updatePartner(partner.id, UpdatePartnerDto(inTimeline: inTimeline));
if (dto != null) {
partner.inTimeline = dto.inTimeline ?? partner.inTimeline;
await _db.writeTxn(() => _db.users.put(partner));
return true;
}
} catch (e) {
_log.warning("failed to update partner ${partner.id}:\n$e");
}
return false;
}
}
@@ -2,9 +2,11 @@ import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/modules/home/ui/asset_grid/immich_asset_grid.dart';
import 'package:immich_mobile/modules/partner/providers/partner.provider.dart';
import 'package:immich_mobile/shared/models/user.dart';
import 'package:immich_mobile/shared/providers/asset.provider.dart';
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
import 'package:immich_mobile/shared/ui/immich_toast.dart';
class PartnerDetailPage extends HookConsumerWidget {
const PartnerDetailPage({Key? key, required this.partner}) : super(key: key);
@@ -14,6 +16,8 @@ class PartnerDetailPage extends HookConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final assets = ref.watch(assetsProvider(partner.isarId));
final inTimeline = useState(partner.inTimeline);
bool toggleInProcess = false;
useEffect(
() {
@@ -23,11 +27,49 @@ class PartnerDetailPage extends HookConsumerWidget {
[],
);
void toggleInTimeline() async {
if (toggleInProcess) return;
toggleInProcess = true;
try {
final ok = await ref
.read(partnerSharedWithProvider.notifier)
.updatePartner(partner, inTimeline: !inTimeline.value);
if (ok) {
inTimeline.value = !inTimeline.value;
final action = inTimeline.value ? "shown on" : "hidden from";
ImmichToast.show(
context: context,
toastType: ToastType.success,
durationInSecond: 1,
msg: "${partner.name}'s assets $action your timeline",
);
} else {
ImmichToast.show(
context: context,
toastType: ToastType.error,
durationInSecond: 1,
msg: "Failed to toggle the timeline setting",
);
}
} finally {
toggleInProcess = false;
}
}
return Scaffold(
appBar: AppBar(
title: Text(partner.name),
elevation: 0,
centerTitle: false,
actions: [
IconButton(
onPressed: toggleInTimeline,
icon: Icon(
inTimeline.value ? Icons.collections : Icons.collections_outlined,
),
tooltip: "Show/hide photos on your main timeline",
),
],
),
body: assets.when(
data: (renderList) => renderList.isEmpty