Browse Source

first iteration of new albums section and reuseable SectionHeader widget

ashilkn 1 năm trước cách đây
mục cha
commit
e899960ed3

+ 92 - 0
lib/ui/viewer/search_tab/albums_section.dart

@@ -0,0 +1,92 @@
+import "package:figma_squircle/figma_squircle.dart";
+import "package:flutter/material.dart";
+import "package:photos/models/search/album_search_result.dart";
+import "package:photos/models/search/search_types.dart";
+import "package:photos/services/collections_service.dart";
+import "package:photos/theme/ente_theme.dart";
+import "package:photos/ui/viewer/file/no_thumbnail_widget.dart";
+import "package:photos/ui/viewer/file/thumbnail_widget.dart";
+import "package:photos/ui/viewer/search_tab/search_tab.dart";
+import "package:photos/ui/viewer/search_tab/section_header.dart";
+
+class AlbumsSection extends StatelessWidget {
+  final List<AlbumSearchResult> albumSearchResults;
+  const AlbumsSection(this.albumSearchResults, {super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return Column(
+      crossAxisAlignment: CrossAxisAlignment.start,
+      children: [
+        SectionHeader(
+          SectionType.album,
+          hasMore: (albumSearchResults.length > SearchTab.hasMoreThreshold),
+        ),
+        const SizedBox(height: 2),
+        SizedBox(
+          child: SingleChildScrollView(
+            padding: const EdgeInsets.symmetric(horizontal: 4.5),
+            physics: const BouncingScrollPhysics(),
+            scrollDirection: Axis.horizontal,
+            child: Row(
+              crossAxisAlignment: CrossAxisAlignment.start,
+              children: albumSearchResults
+                  .map(
+                    (albumSearchResult) =>
+                        AlbumRecommendation(albumSearchResult),
+                  )
+                  .toList(),
+            ),
+          ),
+        ),
+      ],
+    );
+  }
+}
+
+class AlbumRecommendation extends StatelessWidget {
+  final AlbumSearchResult albumSearchResult;
+  const AlbumRecommendation(this.albumSearchResult, {super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    final enteTextTheme = getEnteTextTheme(context);
+    return Padding(
+      padding: const EdgeInsets.symmetric(horizontal: 2.5),
+      child: Column(
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          ClipSmoothRect(
+            radius: SmoothBorderRadius(cornerRadius: 2.35, cornerSmoothing: 1),
+            child: SizedBox(
+              width: 100,
+              height: 100,
+              child: albumSearchResult.previewThumbnail() != null
+                  ? ThumbnailWidget(
+                      albumSearchResult.previewThumbnail()!,
+                      shouldShowArchiveStatus: false,
+                    )
+                  : const NoThumbnailWidget(),
+            ),
+          ),
+          const SizedBox(height: 2),
+          Text(
+            albumSearchResult.name(),
+            style: enteTextTheme.small,
+            maxLines: 1,
+            overflow: TextOverflow.ellipsis,
+          ),
+          const SizedBox(height: 3),
+          Text(
+            CollectionsService.instance
+                .getCachedFileCount(
+                  albumSearchResult.collectionWithThumbnail.collection,
+                )
+                .toString(),
+            style: enteTextTheme.smallMuted,
+          ),
+        ],
+      ),
+    );
+  }
+}

+ 16 - 5
lib/ui/viewer/search_tab/search_tab.dart

@@ -2,6 +2,7 @@ import "package:fade_indexed_stack/fade_indexed_stack.dart";
 import "package:flutter/material.dart";
 import "package:flutter_animate/flutter_animate.dart";
 import "package:photos/core/constants.dart";
+import "package:photos/models/search/album_search_result.dart";
 import "package:photos/models/search/index_of_indexed_stack.dart";
 import "package:photos/models/search/search_types.dart";
 import "package:photos/states/all_sections_examples_state.dart";
@@ -10,8 +11,10 @@ import "package:photos/ui/viewer/search/result/no_result_widget.dart";
 import "package:photos/ui/viewer/search/search_section.dart";
 import "package:photos/ui/viewer/search/search_suggestions.dart";
 import "package:photos/ui/viewer/search/tab_empty_state.dart";
+import 'package:photos/ui/viewer/search_tab/albums_section.dart';
 
 class SearchTab extends StatefulWidget {
+  static const hasMoreThreshold = 6;
   const SearchTab({Key? key}) : super(key: key);
 
   @override
@@ -93,11 +96,19 @@ class _AllSearchSectionsState extends State<AllSearchSections> {
                   physics: const BouncingScrollPhysics(),
                   itemCount: searchTypes.length,
                   itemBuilder: (context, index) {
-                    return SearchSection(
-                      sectionType: searchTypes[index],
-                      examples: snapshot.data!.elementAt(index),
-                      limit: searchSectionLimit,
-                    );
+                    switch (searchTypes[index]) {
+                      case SectionType.album:
+                        return AlbumsSection(
+                          snapshot.data!.elementAt(index)
+                              as List<AlbumSearchResult>,
+                        );
+                      default:
+                        return SearchSection(
+                          sectionType: searchTypes[index],
+                          examples: snapshot.data!.elementAt(index),
+                          limit: searchSectionLimit,
+                        );
+                    }
                   },
                 )
                     .animate(

+ 34 - 0
lib/ui/viewer/search_tab/section_header.dart

@@ -0,0 +1,34 @@
+import "package:flutter/material.dart";
+import "package:photos/models/search/search_types.dart";
+import "package:photos/theme/ente_theme.dart";
+
+class SectionHeader extends StatelessWidget {
+  final SectionType sectionType;
+  final bool hasMore;
+  const SectionHeader(this.sectionType, {required this.hasMore, super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return Row(
+      mainAxisAlignment: MainAxisAlignment.spaceBetween,
+      children: [
+        Padding(
+          padding: const EdgeInsets.all(12),
+          child: Text(
+            sectionType.sectionTitle(context),
+            style: getEnteTextTheme(context).largeBold,
+          ),
+        ),
+        hasMore
+            ? Padding(
+                padding: const EdgeInsets.all(12),
+                child: Icon(
+                  Icons.chevron_right_outlined,
+                  color: getEnteColorScheme(context).strokeMuted,
+                ),
+              )
+            : const SizedBox.shrink(),
+      ],
+    );
+  }
+}

+ 8 - 0
pubspec.lock

@@ -507,6 +507,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "2.1.0"
+  figma_squircle:
+    dependency: "direct main"
+    description:
+      name: figma_squircle
+      sha256: "790b91a9505e90d246f6efe2fa065ff7fffe658c7b44fe9b5b20c7b0ad3818c0"
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.5.3"
   file:
     dependency: transitive
     description:

+ 1 - 0
pubspec.yaml

@@ -58,6 +58,7 @@ dependencies:
   fade_indexed_stack: ^0.2.2
   fast_base58: ^0.2.1
 
+  figma_squircle: ^0.5.3
   file_saver:
     # Use forked version till this PR is merged: https://github.com/incrediblezayed/file_saver/pull/87
     git: https://github.com/jesims/file_saver.git