feat(mobile): Share album name and adaptive shared album display (#2017)

* shows the owner name of shared albums

* responsive and better names

* rich text

* localization and overflow

* unused import

* adds on tap

* suppress owner name for regular album view

* aspect ratio

* Add some styling to text

* More styling

* Style album thumbnail name

---------

Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
This commit is contained in:
martyfuhry
2023-03-19 15:47:51 -04:00
committed by GitHub
parent b29c43d86a
commit 646b912da8
5 changed files with 153 additions and 32 deletions

View File

@@ -1,15 +1,21 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:immich_mobile/shared/models/album.dart';
import 'package:immich_mobile/shared/models/store.dart';
import 'package:immich_mobile/shared/ui/immich_image.dart';
class AlbumThumbnailCard extends StatelessWidget {
final Function()? onTap;
/// Whether or not to show the owner of the album (or "Owned")
/// in the subtitle of the album
final bool showOwner;
const AlbumThumbnailCard({
Key? key,
required this.album,
this.onTap,
this.showOwner = false,
}) : super(key: key);
final Album album;
@@ -43,6 +49,44 @@ class AlbumThumbnailCard extends StatelessWidget {
height: cardSize,
);
buildAlbumTextRow() {
// Add the owner name to the subtitle
String? owner;
if (showOwner) {
if (album.ownerId == Store.get(StoreKey.userRemoteId)) {
owner = 'album_thumbnail_owned'.tr();
} else if (album.ownerName != null) {
owner = 'album_thumbnail_shared_by'.tr(args: [album.ownerName!]);
}
}
return RichText(
overflow: TextOverflow.fade,
text: TextSpan(
children: [
TextSpan(
text: album.assetCount == 1
? 'album_thumbnail_card_item'
.tr(args: ['${album.assetCount}'])
: 'album_thumbnail_card_items'
.tr(args: ['${album.assetCount}']),
style: TextStyle(
fontFamily: 'WorkSans',
fontSize: 12,
color: isDarkMode ? Colors.white : Colors.black,
),
),
if (owner != null) const TextSpan(text: ' · '),
if (owner != null)
TextSpan(
text: owner,
style: Theme.of(context).textTheme.labelSmall,
),
],
),
);
}
return GestureDetector(
onTap: onTap,
child: Flex(
@@ -68,32 +112,16 @@ class AlbumThumbnailCard extends StatelessWidget {
width: cardSize,
child: Text(
album.name,
style: const TextStyle(
style: TextStyle(
fontWeight: FontWeight.bold,
color: isDarkMode
? Theme.of(context).primaryColor
: Colors.black,
),
),
),
),
Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
album.assetCount == 1
? 'album_thumbnail_card_item'
: 'album_thumbnail_card_items',
style: const TextStyle(
fontSize: 12,
),
).tr(args: ['${album.assetCount}']),
if (album.shared)
const Text(
'album_thumbnail_card_shared',
style: TextStyle(
fontSize: 12,
),
).tr()
],
)
buildAlbumTextRow(),
],
),
),

View File

@@ -4,9 +4,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/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/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/ui/immich_image.dart';
class SharingPage extends HookConsumerWidget {
@@ -15,6 +17,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.userRemoteId);
var isDarkMode = Theme.of(context).brightness == Brightness.dark;
useEffect(
() {
@@ -24,11 +28,39 @@ class SharingPage extends HookConsumerWidget {
[],
);
buildAlbumGrid() {
return SliverPadding(
padding: const EdgeInsets.all(18.0),
sliver: SliverGrid(
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 250,
mainAxisSpacing: 12,
crossAxisSpacing: 12,
childAspectRatio: .7,
),
delegate: SliverChildBuilderDelegate(
(context, index) {
return AlbumThumbnailCard(
album: sharedAlbums[index],
showOwner: true,
onTap: () {
AutoRouter.of(context)
.push(AlbumViewerRoute(albumId: sharedAlbums[index].id));
},
);
},
childCount: sharedAlbums.length,
),
),
);
}
buildAlbumList() {
return SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
final album = sharedAlbums[index];
final isOwner = album.ownerId == userId;
return ListTile(
contentPadding:
@@ -42,13 +74,31 @@ class SharingPage extends HookConsumerWidget {
),
),
title: Text(
sharedAlbums[index].name,
album.name,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
fontWeight: FontWeight.bold,
color: isDarkMode
? Theme.of(context).primaryColor
: Colors.black,
),
),
subtitle: isOwner
? const Text(
'Owned',
style: TextStyle(
fontSize: 12.0,
),
)
: album.ownerName != null
? Text(
'Shared by ${album.ownerName!}',
style: const TextStyle(
fontSize: 12.0,
),
)
: null,
onTap: () {
AutoRouter.of(context)
.push(AlbumViewerRoute(albumId: sharedAlbums[index].id));
@@ -124,9 +174,19 @@ class SharingPage extends HookConsumerWidget {
).tr(),
),
),
sharedAlbums.isNotEmpty
? buildAlbumList()
: buildEmptyListIndication()
SliverLayoutBuilder(
builder: (context, constraints) {
if (sharedAlbums.isEmpty) {
return buildEmptyListIndication();
}
if (constraints.crossAxisExtent < 600) {
return buildAlbumList();
} else {
return buildAlbumGrid();
}
},
),
],
),
);