diff --git a/lib/ui/collections/album/column_item.dart b/lib/ui/collections/album/column_item.dart index 021669148..d52138002 100644 --- a/lib/ui/collections/album/column_item.dart +++ b/lib/ui/collections/album/column_item.dart @@ -9,10 +9,10 @@ import 'package:photos/ui/viewer/file/no_thumbnail_widget.dart'; import 'package:photos/ui/viewer/file/thumbnail_widget.dart'; ///https://www.figma.com/file/SYtMyLBs5SAOkTbfMMzhqt/ente-Visual-Design?node-id=7480%3A33462&t=H5AvR79OYDnB9ekw-4 -class AlbumListItemWidget extends StatelessWidget { +class AlbumColumnItemWidget extends StatelessWidget { final CollectionWithThumbnail item; - const AlbumListItemWidget( + const AlbumColumnItemWidget( this.item, { super.key, }); diff --git a/lib/ui/collections/album/horizontal_list.dart b/lib/ui/collections/album/horizontal_list.dart index ca9b7bbc7..23778676b 100644 --- a/lib/ui/collections/album/horizontal_list.dart +++ b/lib/ui/collections/album/horizontal_list.dart @@ -7,7 +7,7 @@ import "package:photos/events/collection_updated_event.dart"; import "package:photos/generated/l10n.dart"; import "package:photos/models/collection_items.dart"; import "package:photos/theme/ente_theme.dart"; -import "package:photos/ui/collections/collection_item_widget.dart"; +import "package:photos/ui/collections/album/row_item.dart"; import "package:photos/ui/common/loading_widget.dart"; class AlbumHorizontalList extends StatefulWidget { @@ -83,7 +83,7 @@ class _AlbumHorizontalListState extends State { padding: const EdgeInsets.symmetric(horizontal: 8), itemBuilder: (context, index) { final item = collectionsWithThumbnail[index]; - return CollectionItem( + return AlbumRowItemWidget( item, 120, shouldRender: true, diff --git a/lib/ui/collections/album/row_item.dart b/lib/ui/collections/album/row_item.dart index 4ba0e946c..f6d36d48f 100644 --- a/lib/ui/collections/album/row_item.dart +++ b/lib/ui/collections/album/row_item.dart @@ -12,13 +12,13 @@ import 'package:photos/ui/viewer/gallery/collection_page.dart'; import 'package:photos/utils/navigation_util.dart'; import 'package:visibility_detector/visibility_detector.dart'; -class CollectionItem extends StatelessWidget { +class AlbumRowItemWidget extends StatelessWidget { final CollectionWithThumbnail c; final double sideOfThumbnail; final bool shouldRender; final bool showFileCount; - CollectionItem( + AlbumRowItemWidget( this.c, this.sideOfThumbnail, { this.shouldRender = false, diff --git a/lib/ui/collections/album/vertical_list.dart b/lib/ui/collections/album/vertical_list.dart index b514e5321..d0f1c8d1c 100644 --- a/lib/ui/collections/album/vertical_list.dart +++ b/lib/ui/collections/album/vertical_list.dart @@ -16,9 +16,9 @@ import 'package:photos/services/collections_service.dart'; import 'package:photos/services/ignored_files_service.dart'; import 'package:photos/services/remote_sync_service.dart'; import "package:photos/ui/actions/collection/collection_sharing_actions.dart"; -import "package:photos/ui/collections/album/list_item.dart"; +import "package:photos/ui/collections/album/column_item.dart"; +import "package:photos/ui/collections/album/new_list_item.dart"; import 'package:photos/ui/collections/collection_action_sheet.dart'; -import 'package:photos/ui/components/new_album_list_widget.dart'; import "package:photos/ui/sharing/share_collection_page.dart"; import 'package:photos/ui/viewer/gallery/collection_page.dart'; import "package:photos/ui/viewer/gallery/empty_state.dart"; @@ -28,7 +28,7 @@ import 'package:photos/utils/share_util.dart'; import 'package:photos/utils/toast_util.dart'; import 'package:receive_sharing_intent/receive_sharing_intent.dart'; -class CollectionsListWidget extends StatelessWidget { +class AlbumVerticalListWidget extends StatelessWidget { final List collectionsWithThumbnail; final CollectionActionType actionType; final SelectedFiles? selectedFiles; @@ -36,7 +36,7 @@ class CollectionsListWidget extends StatelessWidget { final String searchQuery; final bool shouldShowCreateAlbum; - CollectionsListWidget( + AlbumVerticalListWidget( this.collectionsWithThumbnail, this.actionType, this.selectedFiles, @@ -70,7 +70,7 @@ class CollectionsListWidget extends StatelessWidget { return GestureDetector( behavior: HitTestBehavior.opaque, onTap: () => _albumListItemOnTap(context, item), - child: AlbumListItemWidget( + child: AlbumColumnItemWidget( item, ), ); diff --git a/lib/ui/collections/button/archived_button.dart b/lib/ui/collections/button/archived_button.dart index 330c6c23c..fde845bf3 100644 --- a/lib/ui/collections/button/archived_button.dart +++ b/lib/ui/collections/button/archived_button.dart @@ -7,10 +7,10 @@ import "package:photos/services/collections_service.dart"; import 'package:photos/ui/viewer/gallery/archive_page.dart'; import 'package:photos/utils/navigation_util.dart'; -class ArchivedCollectionsButtonWidget extends StatelessWidget { +class ArchivedCollectionsButton extends StatelessWidget { final TextStyle textStyle; - const ArchivedCollectionsButtonWidget( + const ArchivedCollectionsButton( this.textStyle, { Key? key, }) : super(key: key); diff --git a/lib/ui/collections/button/trash_button.dart b/lib/ui/collections/button/trash_button.dart index e587ca7b6..18b92bac6 100644 --- a/lib/ui/collections/button/trash_button.dart +++ b/lib/ui/collections/button/trash_button.dart @@ -8,8 +8,8 @@ import "package:photos/generated/l10n.dart"; import 'package:photos/ui/viewer/gallery/trash_page.dart'; import 'package:photos/utils/navigation_util.dart'; -class TrashButtonWidget extends StatefulWidget { - const TrashButtonWidget( +class TrashSectionButton extends StatefulWidget { + const TrashSectionButton( this.textStyle, { Key? key, }) : super(key: key); @@ -17,10 +17,10 @@ class TrashButtonWidget extends StatefulWidget { final TextStyle textStyle; @override - State createState() => _TrashButtonWidgetState(); + State createState() => _TrashSectionButtonState(); } -class _TrashButtonWidgetState extends State { +class _TrashSectionButtonState extends State { late StreamSubscription _trashUpdatedEventSubscription; @override diff --git a/lib/ui/collections/button/uncategorized_button.dart b/lib/ui/collections/button/uncategorized_button.dart index 6679bc52a..2aa3adf52 100644 --- a/lib/ui/collections/button/uncategorized_button.dart +++ b/lib/ui/collections/button/uncategorized_button.dart @@ -8,10 +8,10 @@ import 'package:photos/services/hidden_service.dart'; import 'package:photos/ui/viewer/gallery/uncategorized_page.dart'; import 'package:photos/utils/navigation_util.dart'; -class UnCatCollectionsButtonWidget extends StatelessWidget { +class UnCategorizedCollections extends StatelessWidget { final TextStyle textStyle; - const UnCatCollectionsButtonWidget( + const UnCategorizedCollections( this.textStyle, { Key? key, }) : super(key: key); diff --git a/lib/ui/collections/collection_action_sheet.dart b/lib/ui/collections/collection_action_sheet.dart index 906e94a86..7fbab8998 100644 --- a/lib/ui/collections/collection_action_sheet.dart +++ b/lib/ui/collections/collection_action_sheet.dart @@ -12,7 +12,7 @@ import 'package:photos/models/selected_files.dart'; import 'package:photos/services/collections_service.dart'; import 'package:photos/theme/colors.dart'; import 'package:photos/theme/ente_theme.dart'; -import 'package:photos/ui/collections/collections_list_widget.dart'; +import 'package:photos/ui/collections/album/vertical_list.dart'; import 'package:photos/ui/common/loading_widget.dart'; import 'package:photos/ui/components/bottom_of_title_bar_widget.dart'; import 'package:photos/ui/components/buttons/button_widget.dart'; @@ -229,7 +229,7 @@ class _CollectionActionSheetState extends State { radius: const Radius.circular(2), child: Padding( padding: const EdgeInsets.only(right: 12), - child: CollectionsListWidget( + child: AlbumVerticalListWidget( searchResults, widget.actionType, widget.selectedFiles, diff --git a/lib/ui/collections/remote_collections_grid_view_widget.dart b/lib/ui/collections/remote_collections_grid_view_widget.dart index e6d483350..d1c7b5404 100644 --- a/lib/ui/collections/remote_collections_grid_view_widget.dart +++ b/lib/ui/collections/remote_collections_grid_view_widget.dart @@ -2,7 +2,7 @@ import 'dart:math'; import 'package:flutter/material.dart'; import 'package:photos/models/collection_items.dart'; -import 'package:photos/ui/collections/collection_item_widget.dart'; +import "package:photos/ui/collections/album/row_item.dart"; import 'package:photos/ui/collections/create_new_album_widget.dart'; class RemoteCollectionsGridViewWidget extends StatelessWidget { @@ -46,7 +46,7 @@ class RemoteCollectionsGridViewWidget extends StatelessWidget { // to disable GridView's scrolling itemBuilder: (context, index) { if (index < collections!.length) { - return CollectionItem( + return AlbumRowItemWidget( collections![index], sideOfThumbnail, shouldRender: index < collectionItemsToPreload, diff --git a/lib/ui/tabs/shared/new_shared_collections_gallery.dart b/lib/ui/tabs/shared/empty_state.dart similarity index 64% rename from lib/ui/tabs/shared/new_shared_collections_gallery.dart rename to lib/ui/tabs/shared/empty_state.dart index a3feffc6e..de5751652 100644 --- a/lib/ui/tabs/shared/new_shared_collections_gallery.dart +++ b/lib/ui/tabs/shared/empty_state.dart @@ -1,29 +1,19 @@ import "package:flutter/material.dart"; -import "package:photos/core/constants.dart"; +import "package:fluttertoast/fluttertoast.dart"; +import "package:photos/core/event_bus.dart"; +import "package:photos/events/tab_changed_event.dart"; import "package:photos/generated/l10n.dart"; import "package:photos/theme/ente_theme.dart"; import 'package:photos/ui/collections/collection_action_sheet.dart'; +import "package:photos/ui/common/gradient_button.dart"; import 'package:photos/ui/components/buttons/button_widget.dart'; import "package:photos/ui/components/empty_state_item_widget.dart"; import "package:photos/ui/components/models/button_type.dart"; import "package:photos/utils/share_util.dart"; +import "package:photos/utils/toast_util.dart"; -class NewSharedCollectionsGallery extends StatelessWidget { - const NewSharedCollectionsGallery({super.key}); - - @override - Widget build(BuildContext context) { - return Center( - child: ConstrainedBox( - constraints: const BoxConstraints(maxWidth: restrictedMaxWidth), - child: const EmptyStateWidget(), - ), - ); - } -} - -class EmptyStateWidget extends StatelessWidget { - const EmptyStateWidget({super.key}); +class SharedEmptyStateWidget extends StatelessWidget { + const SharedEmptyStateWidget({super.key}); @override Widget build(BuildContext context) { @@ -117,3 +107,76 @@ class EmptyStateWidget extends StatelessWidget { ); } } + +class OutgoingAlbumEmptyState extends StatelessWidget { + const OutgoingAlbumEmptyState({super.key}); + + @override + Widget build(BuildContext context) { + return SizedBox( + height: 200, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + S.of(context).shareYourFirstAlbum, + style: Theme.of(context).textTheme.caption, + ), + const Padding(padding: EdgeInsets.only(top: 14)), + SizedBox( + width: 200, + height: 50, + child: GradientButton( + onTap: () async { + await showToast( + context, + S.of(context).shareAlbumHint, + toastLength: Toast.LENGTH_LONG, + ); + Bus.instance.fire( + TabChangedEvent(1, TabChangedEventSource.collectionsPage), + ); + }, + iconData: Icons.person_add, + text: S.of(context).share, + ), + ), + const SizedBox(height: 60), + ], + ), + ); + } +} + +class IncomingAlbumEmptyState extends StatelessWidget { + const IncomingAlbumEmptyState({super.key}); + + @override + Widget build(BuildContext context) { + return SizedBox( + height: 220, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + S.of(context).askYourLovedOnesToShare, + style: Theme.of(context).textTheme.caption, + ), + const Padding(padding: EdgeInsets.only(top: 14)), + SizedBox( + width: 200, + height: 50, + child: GradientButton( + onTap: () async { + shareText(S.of(context).shareTextRecommendUsingEnte); + }, + iconData: Icons.outgoing_mail, + text: S.of(context).invite, + ), + ), + const SizedBox(height: 60), + ], + ), + ); + } +} diff --git a/lib/ui/tabs/shared/incoming_album_item.dart b/lib/ui/tabs/shared/incoming_album_item.dart new file mode 100644 index 000000000..94ff5c65c --- /dev/null +++ b/lib/ui/tabs/shared/incoming_album_item.dart @@ -0,0 +1,113 @@ +import "dart:math"; + +import "package:flutter/material.dart"; +import "package:photos/db/files_db.dart"; +import "package:photos/models/collection_items.dart"; +import "package:photos/models/gallery_type.dart"; +import "package:photos/ui/sharing/user_avator_widget.dart"; +import "package:photos/ui/viewer/file/thumbnail_widget.dart"; +import "package:photos/ui/viewer/gallery/collection_page.dart"; +import "package:photos/utils/navigation_util.dart"; + +class IncomingAlbumItem extends StatelessWidget { + final CollectionWithThumbnail c; + + const IncomingAlbumItem( + this.c, { + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + const double horizontalPaddingOfGridRow = 16; + const double crossAxisSpacingOfGrid = 9; + final TextStyle albumTitleTextStyle = + Theme.of(context).textTheme.subtitle1!.copyWith(fontSize: 14); + final Size size = MediaQuery.of(context).size; + final int albumsCountInOneRow = max(size.width ~/ 220.0, 2); + final double totalWhiteSpaceOfRow = (horizontalPaddingOfGridRow * 2) + + (albumsCountInOneRow - 1) * crossAxisSpacingOfGrid; + final double sideOfThumbnail = (size.width / albumsCountInOneRow) - + (totalWhiteSpaceOfRow / albumsCountInOneRow); + return GestureDetector( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(1), + child: SizedBox( + height: sideOfThumbnail, + width: sideOfThumbnail, + child: Stack( + children: [ + Hero( + tag: "shared_collection" + c.thumbnail!.tag, + child: ThumbnailWidget( + c.thumbnail, + key: Key("shared_collection" + c.thumbnail!.tag), + shouldShowArchiveStatus: c.collection.hasShareeArchived(), + shouldShowSyncStatus: false, + ), + ), + Align( + alignment: Alignment.bottomRight, + child: Padding( + padding: const EdgeInsets.only(right: 8.0, bottom: 8.0), + child: UserAvatarWidget( + c.collection.owner!, + thumbnailView: true, + ), + ), + ), + ], + ), + ), + ), + const SizedBox(height: 4), + Row( + children: [ + Container( + constraints: BoxConstraints(maxWidth: sideOfThumbnail - 40), + child: Text( + c.collection.displayName, + style: albumTitleTextStyle, + overflow: TextOverflow.ellipsis, + ), + ), + FutureBuilder( + future: FilesDB.instance.collectionFileCount(c.collection.id), + builder: (context, snapshot) { + if (snapshot.hasData && snapshot.data! > 0) { + return RichText( + text: TextSpan( + style: albumTitleTextStyle.copyWith( + color: albumTitleTextStyle.color!.withOpacity(0.5), + ), + children: [ + const TextSpan(text: " \u2022 "), + TextSpan(text: snapshot.data.toString()), + ], + ), + ); + } else { + return Container(); + } + }, + ), + ], + ), + ], + ), + onTap: () { + routeToPage( + context, + CollectionPage( + c, + appBarType: GalleryType.sharedCollection, + tagPrefix: "shared_collection", + ), + ); + }, + ); + } +} diff --git a/lib/ui/tabs/shared/outgoing_album_item.dart b/lib/ui/tabs/shared/outgoing_album_item.dart new file mode 100644 index 000000000..6819fd3b6 --- /dev/null +++ b/lib/ui/tabs/shared/outgoing_album_item.dart @@ -0,0 +1,116 @@ +import "package:flutter/material.dart"; +import "package:photos/generated/l10n.dart"; +import "package:photos/models/collection_items.dart"; +import "package:photos/models/gallery_type.dart"; +import 'package:photos/theme/colors.dart'; +import "package:photos/ui/viewer/file/thumbnail_widget.dart"; +import "package:photos/ui/viewer/gallery/collection_page.dart"; +import "package:photos/utils/navigation_util.dart"; + +class OutgoingAlbumItem extends StatelessWidget { + final CollectionWithThumbnail c; + + const OutgoingAlbumItem({super.key, required this.c}); + + @override + Widget build(BuildContext context) { + final shareesName = []; + if (c.collection.hasSharees) { + for (int index = 0; index < c.collection.sharees!.length; index++) { + final sharee = c.collection.sharees![index]!; + final String name = + (sharee.name?.isNotEmpty ?? false) ? sharee.name! : sharee.email; + if (index < 2) { + shareesName.add(name); + } else { + final remaining = c.collection.sharees!.length - index; + if (remaining == 1) { + // If it's the last sharee + shareesName.add(name); + } else { + shareesName.add( + "and " + + remaining.toString() + + " other" + + (remaining > 1 ? "s" : ""), + ); + } + break; + } + } + } + return GestureDetector( + behavior: HitTestBehavior.opaque, + child: Container( + margin: const EdgeInsets.fromLTRB(16, 12, 16, 12), + child: Row( + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(1), + child: SizedBox( + height: 60, + width: 60, + child: Hero( + tag: "outgoing_collection" + c.thumbnail!.tag, + child: ThumbnailWidget( + c.thumbnail, + key: Key("outgoing_collection" + c.thumbnail!.tag), + ), + ), + ), + ), + const Padding(padding: EdgeInsets.all(8)), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text( + c.collection.displayName, + style: const TextStyle( + fontSize: 16, + ), + ), + const Padding(padding: EdgeInsets.all(2)), + c.collection.hasLink + ? (c.collection.publicURLs!.first!.isExpired + ? const Icon( + Icons.link, + color: warning500, + ) + : const Icon(Icons.link)) + : Container(), + ], + ), + shareesName.isEmpty + ? Container() + : Padding( + padding: const EdgeInsets.fromLTRB(0, 4, 0, 0), + child: Text( + S.of(context).sharedWith(shareesName.join(", ")), + style: TextStyle( + fontSize: 14, + color: Theme.of(context).primaryColorLight, + ), + textAlign: TextAlign.left, + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + ), + ], + ), + ), + onTap: () { + final page = CollectionPage( + c, + appBarType: GalleryType.ownedCollection, + tagPrefix: "outgoing_collection", + ); + routeToPage(context, page); + }, + ); + } +} diff --git a/lib/ui/tabs/shared_collections_tab.dart b/lib/ui/tabs/shared_collections_tab.dart index 2e5048096..45e1b625e 100644 --- a/lib/ui/tabs/shared_collections_tab.dart +++ b/lib/ui/tabs/shared_collections_tab.dart @@ -2,31 +2,22 @@ import 'dart:async'; import 'dart:math'; import 'package:flutter/material.dart'; -import 'package:fluttertoast/fluttertoast.dart'; import 'package:logging/logging.dart'; import 'package:photos/core/configuration.dart'; import 'package:photos/core/event_bus.dart'; -import 'package:photos/db/files_db.dart'; import 'package:photos/events/collection_updated_event.dart'; import 'package:photos/events/local_photos_updated_event.dart'; -import 'package:photos/events/tab_changed_event.dart'; import 'package:photos/events/user_logged_out_event.dart'; import "package:photos/generated/l10n.dart"; import 'package:photos/models/collection.dart'; import 'package:photos/models/collection_items.dart'; -import 'package:photos/models/gallery_type.dart'; +import "package:photos/models/file.dart"; import 'package:photos/services/collections_service.dart'; -import 'package:photos/theme/colors.dart'; -import 'package:photos/ui/collections/section_title.dart'; -import 'package:photos/ui/common/gradient_button.dart'; import 'package:photos/ui/common/loading_widget.dart'; -import "package:photos/ui/sharing/user_avator_widget.dart"; -import 'package:photos/ui/tabs/shared/new_shared_collections_gallery.dart'; -import 'package:photos/ui/viewer/file/thumbnail_widget.dart'; -import 'package:photos/ui/viewer/gallery/collection_page.dart'; -import 'package:photos/utils/navigation_util.dart'; -import 'package:photos/utils/share_util.dart'; -import 'package:photos/utils/toast_util.dart'; +import 'package:photos/ui/tabs/section_title.dart'; +import "package:photos/ui/tabs/shared/empty_state.dart"; +import "package:photos/ui/tabs/shared/incoming_album_item.dart"; +import "package:photos/ui/tabs/shared/outgoing_album_item.dart"; class SharedCollectionsTab extends StatefulWidget { const SharedCollectionsTab({Key? key}) : super(key: key); @@ -68,64 +59,13 @@ class _SharedCollectionsTabState extends State future: Future.value(CollectionsService.instance.getLatestCollectionFiles()) .then((files) async { - final List outgoing = []; - final List incoming = []; - for (final file in files) { - if (file.collectionID == null) { - _logger.severe("collection id should not be null"); - continue; - } - final Collection? c = - CollectionsService.instance.getCollectionByID(file.collectionID!); - if (c == null) { - _logger - .severe("shared collection is not cached ${file.collectionID}"); - CollectionsService.instance - .fetchCollectionByID(file.collectionID!) - .ignore(); - continue; - } - if (c.owner!.id == Configuration.instance.getUserID()) { - if (c.hasSharees || c.hasLink || c.isSharedFilesCollection()) { - outgoing.add( - CollectionWithThumbnail( - c, - file, - ), - ); - } - } else { - incoming.add( - CollectionWithThumbnail( - c, - file, - ), - ); - } - } - outgoing.sort((first, second) { - if (second.collection.isSharedFilesCollection() == - first.collection.isSharedFilesCollection()) { - return second.collection.updationTime - .compareTo(first.collection.updationTime); - } else { - if (first.collection.isSharedFilesCollection()) { - return 1; - } - return -1; - } - }); - incoming.sort((first, second) { - return second.collection.updationTime - .compareTo(first.collection.updationTime); - }); - return SharedCollections(outgoing, incoming); + return _getSharedCollections(files); }), builder: (context, snapshot) { if (snapshot.hasData) { if ((snapshot.data?.incoming.length ?? 0) == 0 && (snapshot.data?.outgoing.length ?? 0) == 0) { - return const Center(child: EmptyStateWidget()); + return const Center(child: SharedEmptyStateWidget()); } return _getSharedCollectionsGallery(snapshot.data!); } else if (snapshot.hasError) { @@ -164,9 +104,10 @@ class _SharedCollectionsTabState extends State padding: const EdgeInsets.symmetric(horizontal: 16), child: GridView.builder( shrinkWrap: true, + scrollDirection: Axis.vertical, physics: const NeverScrollableScrollPhysics(), itemBuilder: (context, index) { - return IncomingCollectionItem( + return IncomingAlbumItem( collections.incoming[index], ); }, @@ -180,7 +121,7 @@ class _SharedCollectionsTabState extends State ), //24 is height of album title ), ) - : _getIncomingCollectionEmptyState(), + : const IncomingAlbumEmptyState(), const SizedBox(height: 16), SectionTitle(title: S.of(context).sharedByMe), const SizedBox(height: 12), @@ -190,13 +131,13 @@ class _SharedCollectionsTabState extends State padding: const EdgeInsets.only(bottom: 12), physics: const NeverScrollableScrollPhysics(), itemBuilder: (context, index) { - return OutgoingCollectionItem( - collections.outgoing[index], + return OutgoingAlbumItem( + c: collections.outgoing[index], ); }, itemCount: collections.outgoing.length, ) - : _getOutgoingCollectionEmptyState(), + : const OutgoingAlbumEmptyState(), const SizedBox(height: 32), ], ), @@ -204,67 +145,58 @@ class _SharedCollectionsTabState extends State ); } - Widget _getIncomingCollectionEmptyState() { - return SizedBox( - height: 220, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - S.of(context).askYourLovedOnesToShare, - style: Theme.of(context).textTheme.caption, - ), - const Padding(padding: EdgeInsets.only(top: 14)), - SizedBox( - width: 200, - height: 50, - child: GradientButton( - onTap: () async { - shareText(S.of(context).shareTextRecommendUsingEnte); - }, - iconData: Icons.outgoing_mail, - text: S.of(context).invite, + SharedCollections _getSharedCollections(List recentFileForCollections) { + final List outgoing = []; + final List incoming = []; + for (final file in recentFileForCollections) { + if (file.collectionID == null) { + _logger.severe("collection id should not be null"); + continue; + } + final Collection? c = + CollectionsService.instance.getCollectionByID(file.collectionID!); + if (c == null) { + _logger.severe("shared collection is not cached ${file.collectionID}"); + CollectionsService.instance + .fetchCollectionByID(file.collectionID!) + .ignore(); + continue; + } + if (c.owner!.id == Configuration.instance.getUserID()) { + if (c.hasSharees || c.hasLink || c.isSharedFilesCollection()) { + outgoing.add( + CollectionWithThumbnail( + c, + file, ), + ); + } + } else { + incoming.add( + CollectionWithThumbnail( + c, + file, ), - const SizedBox(height: 60), - ], - ), - ); - } - - Widget _getOutgoingCollectionEmptyState() { - return SizedBox( - height: 200, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - S.of(context).shareYourFirstAlbum, - style: Theme.of(context).textTheme.caption, - ), - const Padding(padding: EdgeInsets.only(top: 14)), - SizedBox( - width: 200, - height: 50, - child: GradientButton( - onTap: () async { - await showToast( - context, - S.of(context).shareAlbumHint, - toastLength: Toast.LENGTH_LONG, - ); - Bus.instance.fire( - TabChangedEvent(1, TabChangedEventSource.collectionsPage), - ); - }, - iconData: Icons.person_add, - text: S.of(context).share, - ), - ), - const SizedBox(height: 60), - ], - ), - ); + ); + } + } + outgoing.sort((first, second) { + if (second.collection.isSharedFilesCollection() == + first.collection.isSharedFilesCollection()) { + return second.collection.updationTime + .compareTo(first.collection.updationTime); + } else { + if (first.collection.isSharedFilesCollection()) { + return 1; + } + return -1; + } + }); + incoming.sort((first, second) { + return second.collection.updationTime + .compareTo(first.collection.updationTime); + }); + return SharedCollections(outgoing, incoming); } @override @@ -278,217 +210,3 @@ class _SharedCollectionsTabState extends State @override bool get wantKeepAlive => true; } - -class OutgoingCollectionItem extends StatelessWidget { - final CollectionWithThumbnail c; - - const OutgoingCollectionItem( - this.c, { - Key? key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - final shareesName = []; - if (c.collection.hasSharees) { - for (int index = 0; index < c.collection.sharees!.length; index++) { - final sharee = c.collection.sharees![index]!; - final String name = - (sharee.name?.isNotEmpty ?? false) ? sharee.name! : sharee.email; - if (index < 2) { - shareesName.add(name); - } else { - final remaining = c.collection.sharees!.length - index; - if (remaining == 1) { - // If it's the last sharee - shareesName.add(name); - } else { - shareesName.add( - "and " + - remaining.toString() + - " other" + - (remaining > 1 ? "s" : ""), - ); - } - break; - } - } - } - return GestureDetector( - behavior: HitTestBehavior.opaque, - child: Container( - margin: const EdgeInsets.fromLTRB(16, 12, 16, 12), - child: Row( - children: [ - ClipRRect( - borderRadius: BorderRadius.circular(1), - child: SizedBox( - height: 60, - width: 60, - child: Hero( - tag: "outgoing_collection" + c.thumbnail!.tag, - child: ThumbnailWidget( - c.thumbnail, - key: Key("outgoing_collection" + c.thumbnail!.tag), - ), - ), - ), - ), - const Padding(padding: EdgeInsets.all(8)), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Text( - c.collection.displayName, - style: const TextStyle( - fontSize: 16, - ), - ), - const Padding(padding: EdgeInsets.all(2)), - c.collection.hasLink - ? (c.collection.publicURLs!.first!.isExpired - ? const Icon( - Icons.link, - color: warning500, - ) - : const Icon(Icons.link)) - : Container(), - ], - ), - shareesName.isEmpty - ? Container() - : Padding( - padding: const EdgeInsets.fromLTRB(0, 4, 0, 0), - child: Text( - S.of(context).sharedWith(shareesName.join(", ")), - style: TextStyle( - fontSize: 14, - color: Theme.of(context).primaryColorLight, - ), - textAlign: TextAlign.left, - overflow: TextOverflow.ellipsis, - ), - ), - ], - ), - ), - ], - ), - ), - onTap: () { - final page = CollectionPage( - c, - appBarType: GalleryType.ownedCollection, - tagPrefix: "outgoing_collection", - ); - routeToPage(context, page); - }, - ); - } -} - -class IncomingCollectionItem extends StatelessWidget { - final CollectionWithThumbnail c; - - const IncomingCollectionItem( - this.c, { - Key? key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - const double horizontalPaddingOfGridRow = 16; - const double crossAxisSpacingOfGrid = 9; - final TextStyle albumTitleTextStyle = - Theme.of(context).textTheme.subtitle1!.copyWith(fontSize: 14); - final Size size = MediaQuery.of(context).size; - final int albumsCountInOneRow = max(size.width ~/ 220.0, 2); - final double totalWhiteSpaceOfRow = (horizontalPaddingOfGridRow * 2) + - (albumsCountInOneRow - 1) * crossAxisSpacingOfGrid; - final double sideOfThumbnail = (size.width / albumsCountInOneRow) - - (totalWhiteSpaceOfRow / albumsCountInOneRow); - return GestureDetector( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ClipRRect( - borderRadius: BorderRadius.circular(1), - child: SizedBox( - height: sideOfThumbnail, - width: sideOfThumbnail, - child: Stack( - children: [ - Hero( - tag: "shared_collection" + c.thumbnail!.tag, - child: ThumbnailWidget( - c.thumbnail, - key: Key("shared_collection" + c.thumbnail!.tag), - shouldShowArchiveStatus: c.collection.hasShareeArchived(), - shouldShowSyncStatus: false, - ), - ), - Align( - alignment: Alignment.bottomRight, - child: Padding( - padding: const EdgeInsets.only(right: 8.0, bottom: 8.0), - child: UserAvatarWidget( - c.collection.owner!, - thumbnailView: true, - ), - ), - ), - ], - ), - ), - ), - const SizedBox(height: 4), - Row( - children: [ - Container( - constraints: BoxConstraints(maxWidth: sideOfThumbnail - 40), - child: Text( - c.collection.displayName, - style: albumTitleTextStyle, - overflow: TextOverflow.ellipsis, - ), - ), - FutureBuilder( - future: FilesDB.instance.collectionFileCount(c.collection.id), - builder: (context, snapshot) { - if (snapshot.hasData && snapshot.data! > 0) { - return RichText( - text: TextSpan( - style: albumTitleTextStyle.copyWith( - color: albumTitleTextStyle.color!.withOpacity(0.5), - ), - children: [ - const TextSpan(text: " \u2022 "), - TextSpan(text: snapshot.data.toString()), - ], - ), - ); - } else { - return Container(); - } - }, - ), - ], - ), - ], - ), - onTap: () { - routeToPage( - context, - CollectionPage( - c, - appBarType: GalleryType.sharedCollection, - tagPrefix: "shared_collection", - ), - ); - }, - ); - } -} diff --git a/lib/ui/tabs/user_collections_tab.dart b/lib/ui/tabs/user_collections_tab.dart index bc6fef3ed..0916d755d 100644 --- a/lib/ui/tabs/user_collections_tab.dart +++ b/lib/ui/tabs/user_collections_tab.dart @@ -15,15 +15,15 @@ import 'package:photos/models/collection.dart'; import 'package:photos/models/collection_items.dart'; import 'package:photos/services/collections_service.dart'; import "package:photos/services/remote_sync_service.dart"; -import 'package:photos/ui/collections/archived_collections_button_widget.dart'; +import "package:photos/ui/collections/button/archived_button.dart"; +import "package:photos/ui/collections/button/hidden_button.dart"; +import "package:photos/ui/collections/button/trash_button.dart"; +import "package:photos/ui/collections/button/uncategorized_button.dart"; import 'package:photos/ui/collections/device_folders_grid_view_widget.dart'; -import 'package:photos/ui/collections/hidden_collections_button_widget.dart'; import 'package:photos/ui/collections/remote_collections_grid_view_widget.dart'; -import 'package:photos/ui/collections/section_title.dart'; -import 'package:photos/ui/collections/trash_button_widget.dart'; -import 'package:photos/ui/collections/uncat_collections_button_widget.dart'; import 'package:photos/ui/common/loading_widget.dart'; import 'package:photos/ui/components/buttons/icon_button_widget.dart'; +import 'package:photos/ui/tabs/section_title.dart'; import 'package:photos/ui/viewer/actions/delete_empty_albums.dart'; import 'package:photos/ui/viewer/gallery/empty_state.dart'; import 'package:photos/utils/local_settings.dart'; @@ -173,13 +173,13 @@ class _UserCollectionsTabState extends State padding: const EdgeInsets.symmetric(horizontal: 16), child: Column( children: [ - UnCatCollectionsButtonWidget(trashAndHiddenTextStyle), + UnCategorizedCollections(trashAndHiddenTextStyle), const SizedBox(height: 12), - ArchivedCollectionsButtonWidget(trashAndHiddenTextStyle), + ArchivedCollectionsButton(trashAndHiddenTextStyle), const SizedBox(height: 12), HiddenCollectionsButtonWidget(trashAndHiddenTextStyle), const SizedBox(height: 12), - TrashButtonWidget(trashAndHiddenTextStyle), + TrashSectionButton(trashAndHiddenTextStyle), ], ), ),