diff --git a/mobile/lib/ui/collections/album/row_item.dart b/mobile/lib/ui/collections/album/row_item.dart index 9c496e3575..5343fec411 100644 --- a/mobile/lib/ui/collections/album/row_item.dart +++ b/mobile/lib/ui/collections/album/row_item.dart @@ -1,3 +1,4 @@ +import "package:figma_squircle/figma_squircle.dart"; import 'package:flutter/material.dart'; import "package:intl/intl.dart"; import "package:photos/core/configuration.dart"; @@ -24,6 +25,9 @@ class AlbumRowItemWidget extends StatelessWidget { final void Function(Collection)? onTapCallback; final void Function(Collection)? onLongPressCallback; final SelectedAlbums? selectedAlbums; + final double borderWidth; + static const _cornerRadius = 12.0; + static const _cornerSmoothing = 1.0; const AlbumRowItemWidget( this.c, @@ -35,6 +39,7 @@ class AlbumRowItemWidget extends StatelessWidget { this.onTapCallback, this.onLongPressCallback, this.selectedAlbums, + this.borderWidth = 1.0, }); @override @@ -56,125 +61,146 @@ class AlbumRowItemWidget extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Stack( - children: [ - ClipRRect( - borderRadius: BorderRadius.circular(12), - child: SizedBox( - height: sideOfThumbnail, - width: sideOfThumbnail, - child: Stack( - children: [ - FutureBuilder( - future: CollectionsService.instance.getCover(c), - builder: (context, snapshot) { - EnteFile? thumbnail; - if (snapshot.hasData) { - thumbnail = snapshot.data!; - } else { - //Need to use cached thumbnail so that the hero - //animation works as expected. - thumbnail = - CollectionsService.instance.getCoverCache(c); - } - if (thumbnail != null) { - final bool isSelected = - selectedAlbums?.isAlbumSelected(c) ?? false; - final String heroTag = tagPrefix + thumbnail.tag; - final thumbnailWidget = ThumbnailWidget( - thumbnail, - shouldShowArchiveStatus: isOwner - ? c.isArchived() - : c.hasShareeArchived(), - showFavForAlbumOnly: true, - shouldShowSyncStatus: false, - shouldShowPinIcon: isOwner && c.isPinned, - key: Key(heroTag), - ); - return Hero( - tag: heroTag, - transitionOnUserGestures: true, - child: isSelected - ? ColorFiltered( - colorFilter: ColorFilter.mode( - Colors.black.withOpacity( - 0.4, - ), - BlendMode.darken, - ), - child: thumbnailWidget, - ) - : thumbnailWidget, - ); - } else { - return const NoThumbnailWidget( - borderRadius: 12, - ); - } - }, - ), - if (isOwner && (c.hasSharees || c.hasLink)) - Hero( - tag: tagPrefix + "_sharees", - transitionOnUserGestures: true, - child: Align( - alignment: Alignment.topLeft, - child: AlbumSharesIcons( - padding: const EdgeInsets.only(left: 4, top: 4), - sharees: c.getSharees(), - type: AvatarType.mini, - trailingWidget: linkIcon, - ), - ), - ), - Positioned( - top: 5, - right: 5, - child: Hero( - tag: tagPrefix + "_album_selection", - transitionOnUserGestures: true, - child: ListenableBuilder( - listenable: selectedAlbums ?? ValueNotifier(false), - builder: (context, _) { + SizedBox( + height: sideOfThumbnail + borderWidth * 2, + width: sideOfThumbnail + borderWidth * 2, + child: Stack( + clipBehavior: Clip.none, + alignment: Alignment.center, + children: [ + ClipSmoothRect( + radius: SmoothBorderRadius( + cornerRadius: _cornerRadius + borderWidth, + cornerSmoothing: _cornerSmoothing, + ), + child: Container( + color: getEnteColorScheme(context).strokeMuted, + width: sideOfThumbnail + borderWidth * 2, + height: sideOfThumbnail + borderWidth * 2, + ), + ), + ClipSmoothRect( + radius: SmoothBorderRadius( + cornerRadius: _cornerRadius, + cornerSmoothing: _cornerSmoothing, + ), + child: SizedBox( + height: sideOfThumbnail, + width: sideOfThumbnail, + child: Stack( + children: [ + FutureBuilder( + future: CollectionsService.instance.getCover(c), + builder: (context, snapshot) { + EnteFile? thumbnail; + if (snapshot.hasData) { + thumbnail = snapshot.data!; + } else { + //Need to use cached thumbnail so that the hero + //animation works as expected. + thumbnail = + CollectionsService.instance.getCoverCache(c); + } + if (thumbnail != null) { final bool isSelected = selectedAlbums?.isAlbumSelected(c) ?? false; - return AnimatedSwitcher( - duration: const Duration(milliseconds: 200), - switchInCurve: Curves.easeOut, - switchOutCurve: Curves.easeIn, - child: isSelected - ? const Icon( - Icons.check_circle_rounded, - color: Colors.white, - size: 22, - ) - : null, + final String heroTag = tagPrefix + thumbnail.tag; + final thumbnailWidget = ThumbnailWidget( + thumbnail, + shouldShowArchiveStatus: isOwner + ? c.isArchived() + : c.hasShareeArchived(), + showFavForAlbumOnly: true, + shouldShowSyncStatus: false, + shouldShowPinIcon: isOwner && c.isPinned, + key: Key(heroTag), ); - }, - ), + return Hero( + tag: heroTag, + transitionOnUserGestures: true, + child: isSelected + ? ColorFiltered( + colorFilter: ColorFilter.mode( + Colors.black.withOpacity( + 0.4, + ), + BlendMode.darken, + ), + child: thumbnailWidget, + ) + : thumbnailWidget, + ); + } else { + return const NoThumbnailWidget( + borderRadius: 12, + ); + } + }, ), - ), - if (!isOwner) - Align( - alignment: Alignment.bottomRight, - child: Hero( - tag: tagPrefix + "_owner_other", + if (isOwner && (c.hasSharees || c.hasLink)) + Hero( + tag: tagPrefix + "_sharees", transitionOnUserGestures: true, - child: Padding( - padding: - const EdgeInsets.only(right: 4, bottom: 4), - child: UserAvatarWidget( - c.owner, - thumbnailView: true, + child: Align( + alignment: Alignment.topLeft, + child: AlbumSharesIcons( + padding: const EdgeInsets.only(left: 4, top: 4), + sharees: c.getSharees(), + type: AvatarType.mini, + trailingWidget: linkIcon, ), ), ), + Positioned( + top: 5, + right: 5, + child: Hero( + tag: tagPrefix + "_album_selection", + transitionOnUserGestures: true, + child: ListenableBuilder( + listenable: + selectedAlbums ?? ValueNotifier(false), + builder: (context, _) { + final bool isSelected = + selectedAlbums?.isAlbumSelected(c) ?? false; + return AnimatedSwitcher( + duration: const Duration(milliseconds: 200), + switchInCurve: Curves.easeOut, + switchOutCurve: Curves.easeIn, + child: isSelected + ? const Icon( + Icons.check_circle_rounded, + color: Colors.white, + size: 22, + ) + : null, + ); + }, + ), + ), ), - ], + if (!isOwner) + Align( + alignment: Alignment.bottomRight, + child: Hero( + tag: tagPrefix + "_owner_other", + transitionOnUserGestures: true, + child: Padding( + padding: + const EdgeInsets.only(right: 4, bottom: 4), + child: UserAvatarWidget( + c.owner, + thumbnailView: true, + ), + ), + ), + ), + ], + ), ), ), - ), - ], + ], + ), ), const SizedBox(height: 6), Hero( diff --git a/mobile/lib/ui/collections/flex_grid_view.dart b/mobile/lib/ui/collections/flex_grid_view.dart index 2267833b1a..86370be94b 100644 --- a/mobile/lib/ui/collections/flex_grid_view.dart +++ b/mobile/lib/ui/collections/flex_grid_view.dart @@ -29,6 +29,7 @@ class CollectionsFlexiGridViewWidget extends StatefulWidget { static const maxThumbnailWidth = 224.0; static const crossAxisSpacing = 8.0; static const horizontalPadding = 16.0; + static const borderWidth = 1.0; final List? collections; // At max how many albums to display final int displayLimitCount; @@ -137,7 +138,8 @@ class _CollectionsFlexiGridViewWidgetState final double sideOfThumbnail = (screenWidth - totalCrossAxisSpacing - - CollectionsFlexiGridViewWidget.horizontalPadding) / + CollectionsFlexiGridViewWidget.horizontalPadding - + CollectionsFlexiGridViewWidget.borderWidth * 2) / albumsCountInCrossAxis; final int totalCollections = widget.collections!.length;