feat(mobile): partner sharing (#2541)

* feat(mobile): partner sharing

* getAllAssets for other users

* i18n

* fix tests

* try to fix web tests

* shared with/by confusion

* error logging

* guard against outdated server version
This commit is contained in:
Fynn Petersen-Frey
2023-05-25 05:52:43 +02:00
committed by GitHub
parent 1613ae9185
commit bcc2c34eef
48 changed files with 1729 additions and 226 deletions

View File

@@ -8,6 +8,7 @@ import 'package:immich_mobile/shared/models/album.dart';
import 'package:immich_mobile/shared/models/asset.dart';
import 'package:immich_mobile/shared/models/user.dart';
import 'package:immich_mobile/shared/providers/db.provider.dart';
import 'package:immich_mobile/shared/providers/user.provider.dart';
import 'package:isar/isar.dart';
class SharedAlbumNotifier extends StateNotifier<List<Album>> {
@@ -73,7 +74,9 @@ final sharedAlbumProvider =
});
final sharedAlbumDetailProvider =
StreamProvider.autoDispose.family<Album, int>((ref, albumId) async* {
StreamProvider.family<Album, int>((ref, albumId) async* {
final user = ref.watch(currentUserProvider);
if (user == null) return;
final AlbumService sharedAlbumService = ref.watch(albumServiceProvider);
await for (final a in sharedAlbumService.watchAlbum(albumId)) {

View File

@@ -2,8 +2,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/shared/models/user.dart';
import 'package:immich_mobile/shared/services/user.service.dart';
final suggestedSharedUsersProvider =
FutureProvider.autoDispose<List<User>>((ref) {
final otherUsersProvider = FutureProvider.autoDispose<List<User>>((ref) {
UserService userService = ref.watch(userServiceProvider);
return userService.getUsersInDb();

View File

@@ -1,85 +0,0 @@
import 'package:auto_route/auto_route.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:immich_mobile/routing/router.dart';
class SharingSliverAppBar extends StatelessWidget {
const SharingSliverAppBar({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return SliverAppBar(
centerTitle: true,
floating: false,
pinned: true,
snap: false,
automaticallyImplyLeading: false,
title: Text(
'IMMICH',
style: TextStyle(
fontFamily: 'SnowburstOne',
fontWeight: FontWeight.bold,
fontSize: 22,
color: Theme.of(context).primaryColor,
),
),
bottom: PreferredSize(
preferredSize: const Size.fromHeight(50.0),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.only(right: 4.0),
child: ElevatedButton.icon(
onPressed: () {
AutoRouter.of(context)
.push(CreateAlbumRoute(isSharedAlbum: true));
},
icon: const Icon(
Icons.photo_album_outlined,
size: 20,
),
label: const Text(
"sharing_silver_appbar_create_shared_album",
maxLines: 1,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 11,
// color: Theme.of(context).primaryColor,
),
).tr(),
),
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.only(left: 4.0),
child: ElevatedButton.icon(
onPressed: null,
icon: const Icon(
Icons.swap_horizontal_circle_outlined,
size: 20,
),
label: const Text(
"sharing_silver_appbar_share_partner",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 11,
),
maxLines: 1,
).tr(),
),
),
)
],
),
),
),
);
}
}

View File

@@ -8,6 +8,7 @@ import 'package:immich_mobile/modules/home/ui/asset_grid/asset_grid_data_structu
import 'package:immich_mobile/modules/home/ui/asset_grid/immich_asset_grid.dart';
import 'package:immich_mobile/shared/models/asset.dart';
import 'package:immich_mobile/shared/providers/asset.provider.dart';
import 'package:immich_mobile/shared/providers/user.provider.dart';
class AssetSelectionPage extends HookConsumerWidget {
const AssetSelectionPage({
@@ -21,7 +22,8 @@ class AssetSelectionPage extends HookConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final renderList = ref.watch(remoteAssetsProvider);
final currentUser = ref.watch(currentUserProvider);
final renderList = ref.watch(remoteAssetsProvider(currentUser?.isarId));
final selected = useState<Set<Asset>>(existingAssets);
final selectionEnabledHook = useState(true);

View File

@@ -17,7 +17,7 @@ class SelectAdditionalUserForSharingPage extends HookConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final AsyncValue<List<User>> suggestedShareUsers =
ref.watch(suggestedSharedUsersProvider);
ref.watch(otherUsersProvider);
final sharedUsersList = useState<Set<User>>({});
addNewUsersHandler() {

View File

@@ -20,8 +20,7 @@ class SelectUserForSharingPage extends HookConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final sharedUsersList = useState<Set<User>>({});
AsyncValue<List<User>> suggestedShareUsers =
ref.watch(suggestedSharedUsersProvider);
final suggestedShareUsers = ref.watch(otherUsersProvider);
createSharedAlbum() async {
var newAlbum =

View File

@@ -5,10 +5,11 @@ import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/modules/album/providers/shared_album.provider.dart';
import 'package:immich_mobile/modules/album/ui/album_thumbnail_card.dart';
import 'package:immich_mobile/modules/album/ui/sharing_sliver_appbar.dart';
import 'package:immich_mobile/modules/partner/providers/partner.provider.dart';
import 'package:immich_mobile/modules/partner/ui/partner_list.dart';
import 'package:immich_mobile/routing/router.dart';
import 'package:immich_mobile/shared/models/album.dart';
import 'package:immich_mobile/shared/models/store.dart' as store;
import 'package:immich_mobile/shared/providers/user.provider.dart';
import 'package:immich_mobile/shared/ui/immich_image.dart';
class SharingPage extends HookConsumerWidget {
@@ -17,7 +18,8 @@ class SharingPage extends HookConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final List<Album> sharedAlbums = ref.watch(sharedAlbumProvider);
final userId = store.Store.get(store.StoreKey.currentUser).id;
final userId = ref.watch(currentUserProvider)?.id;
final partner = ref.watch(partnerSharedWithProvider);
var isDarkMode = Theme.of(context).brightness == Brightness.dark;
useEffect(
@@ -63,8 +65,7 @@ class SharingPage extends HookConsumerWidget {
final isOwner = album.ownerId == userId;
return ListTile(
contentPadding:
const EdgeInsets.symmetric(vertical: 12, horizontal: 12),
contentPadding: const EdgeInsets.symmetric(horizontal: 12),
leading: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: ImmichImage(
@@ -93,7 +94,8 @@ class SharingPage extends HookConsumerWidget {
)
: album.ownerName != null
? Text(
'album_thumbnail_shared_by'.tr(args: [album.ownerName!]),
'album_thumbnail_shared_by'
.tr(args: [album.ownerName!]),
style: const TextStyle(
fontSize: 12.0,
),
@@ -110,6 +112,75 @@ class SharingPage extends HookConsumerWidget {
);
}
buildTopBottons() {
return Padding(
padding: const EdgeInsets.only(
left: 12.0,
right: 12.0,
bottom: 12.0,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Expanded(
child: ElevatedButton.icon(
onPressed: () {
AutoRouter.of(context)
.push(CreateAlbumRoute(isSharedAlbum: true));
},
icon: const Icon(
Icons.photo_album_outlined,
size: 20,
),
label: const Text(
"sharing_silver_appbar_create_shared_album",
maxLines: 1,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 11,
),
).tr(),
),
),
const SizedBox(width: 12.0),
Expanded(
child: ElevatedButton.icon(
onPressed: () =>
AutoRouter.of(context).push(const PartnerRoute()),
icon: const Icon(
Icons.swap_horizontal_circle_outlined,
size: 20,
),
label: const Text(
"sharing_silver_appbar_share_partner",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 11,
),
maxLines: 1,
).tr(),
),
)
],
),
);
}
AppBar buildAppBar() {
return AppBar(
centerTitle: true,
automaticallyImplyLeading: false,
title: const Text(
'IMMICH',
style: TextStyle(
fontFamily: 'SnowburstOne',
fontWeight: FontWeight.bold,
fontSize: 22,
),
),
);
}
buildEmptyListIndication() {
return SliverToBoxAdapter(
child: Padding(
@@ -123,7 +194,6 @@ class SharingPage extends HookConsumerWidget {
width: 0.5,
),
),
// color: Colors.transparent,
child: Padding(
padding: const EdgeInsets.all(18.0),
child: Column(
@@ -160,11 +230,27 @@ class SharingPage extends HookConsumerWidget {
}
return Scaffold(
appBar: buildAppBar(),
body: CustomScrollView(
slivers: [
const SharingSliverAppBar(),
SliverToBoxAdapter(child: buildTopBottons()),
if (partner.isNotEmpty)
SliverPadding(
padding: const EdgeInsets.only(left: 12, right: 12, bottom: 4),
sliver: SliverToBoxAdapter(
child: const Text(
"partner_page_title",
style: TextStyle(fontWeight: FontWeight.bold),
).tr(),
),
),
if (partner.isNotEmpty) PartnerList(partner: partner),
SliverPadding(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12),
padding: EdgeInsets.only(
left: 12,
right: 12,
top: partner.isEmpty ? 0 : 16,
),
sliver: SliverToBoxAdapter(
child: const Text(
"sharing_page_album",