[mob] Render people section in GridView (#3958)

## Description

## Tests
This commit is contained in:
Neeraj Gupta
2024-11-06 14:29:49 +05:30
committed by GitHub
7 changed files with 159 additions and 20 deletions

View File

@@ -223,6 +223,8 @@ PODS:
- sqlite3/fts5
- sqlite3/perf-threadsafe
- sqlite3/rtree
- system_info_plus (0.0.1):
- Flutter
- Toast (4.1.1)
- ua_client_hints (1.4.0):
- Flutter
@@ -290,6 +292,7 @@ DEPENDENCIES:
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
- sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/ios`)
- system_info_plus (from `.symlinks/plugins/system_info_plus/ios`)
- ua_client_hints (from `.symlinks/plugins/ua_client_hints/ios`)
- uni_links (from `.symlinks/plugins/uni_links/ios`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
@@ -418,6 +421,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/sqflite_darwin/darwin"
sqlite3_flutter_libs:
:path: ".symlinks/plugins/sqlite3_flutter_libs/ios"
system_info_plus:
:path: ".symlinks/plugins/system_info_plus/ios"
ua_client_hints:
:path: ".symlinks/plugins/ua_client_hints/ios"
uni_links:
@@ -501,6 +506,7 @@ SPEC CHECKSUMS:
sqflite_darwin: a553b1fd6fe66f53bbb0fe5b4f5bab93f08d7a13
sqlite3: 0bb0e6389d824e40296f531b858a2a0b71c0d2fb
sqlite3_flutter_libs: c00457ebd31e59fa6bb830380ddba24d44fbcd3b
system_info_plus: 5393c8da281d899950d751713575fbf91c7709aa
Toast: 1f5ea13423a1e6674c4abdac5be53587ae481c4e
ua_client_hints: 46bb5817a868f9e397c0ba7e3f2f5c5d90c35156
uni_links: d97da20c7701486ba192624d99bffaaffcfc298a

View File

@@ -334,6 +334,7 @@
"${BUILT_PRODUCTS_DIR}/sqflite_darwin/sqflite_darwin.framework",
"${BUILT_PRODUCTS_DIR}/sqlite3/sqlite3.framework",
"${BUILT_PRODUCTS_DIR}/sqlite3_flutter_libs/sqlite3_flutter_libs.framework",
"${BUILT_PRODUCTS_DIR}/system_info_plus/system_info_plus.framework",
"${BUILT_PRODUCTS_DIR}/ua_client_hints/ua_client_hints.framework",
"${BUILT_PRODUCTS_DIR}/uni_links/uni_links.framework",
"${BUILT_PRODUCTS_DIR}/url_launcher_ios/url_launcher_ios.framework",
@@ -428,6 +429,7 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqflite_darwin.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqlite3.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqlite3_flutter_libs.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/system_info_plus.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ua_client_hints.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/uni_links.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher_ios.framework",

View File

@@ -16,6 +16,7 @@ final lightThemeData = ThemeData(
primary: Colors.black,
secondary: Color.fromARGB(255, 163, 163, 163),
background: Colors.white,
surfaceTint: Colors.transparent,
),
outlinedButtonTheme: buildOutlinedButtonThemeData(
bgDisabled: const Color.fromRGBO(158, 158, 158, 1),
@@ -94,6 +95,7 @@ final darkThemeData = ThemeData(
primary: Colors.white,
background: Color.fromRGBO(0, 0, 0, 1),
secondary: Color.fromARGB(255, 163, 163, 163),
surfaceTint: Colors.transparent,
),
buttonTheme: const ButtonThemeData().copyWith(
buttonColor: const Color.fromRGBO(45, 194, 98, 1.0),

View File

@@ -313,7 +313,7 @@ class _PersonActionSheetState extends State<PersonActionSheet> {
await PersonService.instance.addPerson(text, clusterID);
final bool extraPhotosFound = await ClusterFeedbackService.instance
.checkAndDoAutomaticMerges(personEntity!,
personClusterID: clusterID);
personClusterID: clusterID,);
if (extraPhotosFound) {
showShortToast(context, S.of(context).extraPhotosFound);
}

View File

@@ -0,0 +1,128 @@
import "dart:async";
import "package:collection/collection.dart";
import "package:flutter/material.dart";
import "package:flutter_animate/flutter_animate.dart";
import "package:photos/events/event.dart";
import "package:photos/models/search/generic_search_result.dart";
import "package:photos/models/search/search_result.dart";
import "package:photos/models/search/search_types.dart";
import "package:photos/ui/common/loading_widget.dart";
import "package:photos/ui/viewer/search/result/searchable_item.dart";
import "package:photos/ui/viewer/search_tab/people_section.dart";
class PeopleAllPage extends StatefulWidget {
final SectionType sectionType;
const PeopleAllPage({required this.sectionType, super.key});
@override
State<PeopleAllPage> createState() => _PeopleAllPageState();
}
class _PeopleAllPageState extends State<PeopleAllPage> {
late Future<List<SearchResult>> sectionData;
final streamSubscriptions = <StreamSubscription>[];
@override
void initState() {
super.initState();
sectionData = widget.sectionType.getData(context);
final streamsToListenTo = widget.sectionType.viewAllUpdateEvents();
for (Stream<Event> stream in streamsToListenTo) {
streamSubscriptions.add(
stream.listen((event) async {
setState(() {
sectionData = widget.sectionType.getData(context);
});
}),
);
}
}
@override
void dispose() {
for (var subscriptions in streamSubscriptions) {
subscriptions.cancel();
}
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
toolbarHeight: 48,
leadingWidth: 48,
leading: GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: const Icon(
Icons.arrow_back_outlined,
),
),
title: Text(widget.sectionType.sectionTitle(context)),
centerTitle: false,
),
body: Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 8),
child: FutureBuilder(
future: sectionData,
builder: (context, snapshot) {
if (snapshot.hasData) {
final List<SearchResult> sectionResults = snapshot.data!;
if (widget.sectionType.sortByName) {
sectionResults.sort(
(a, b) => compareAsciiLowerCaseNatural(b.name(), a.name()),
);
}
return GridView.builder(
padding: const EdgeInsets.all(0),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: MediaQuery.of(context).size.width > 600
? 4
: 3, // Dynamically adjust columns based on screen width
crossAxisSpacing: 8,
mainAxisSpacing: 0,
childAspectRatio:
0.78, // Adjust this value to control item height ratio
),
itemCount: sectionResults.length,
physics: const BouncingScrollPhysics(),
cacheExtent:
widget.sectionType == SectionType.album ? 400 : null,
itemBuilder: (context, index) {
Widget resultWidget;
if (sectionResults[index] is GenericSearchResult) {
resultWidget = PeopleRowItem(
searchResult: sectionResults[index],
);
} else {
resultWidget = SearchableItemWidget(
sectionResults[index],
);
}
return resultWidget
.animate()
.fadeIn(
duration: const Duration(milliseconds: 225),
curve: Curves.easeIn,
)
.slide(
begin: const Offset(0, -0.01),
curve: Curves.easeIn,
duration: const Duration(milliseconds: 225),
);
},
);
} else {
return const EnteLoadingWidget();
}
},
),
),
),
);
}
}

View File

@@ -15,10 +15,10 @@ class SearchableItemWidget extends StatelessWidget {
final Function? onResultTap;
const SearchableItemWidget(
this.searchResult, {
Key? key,
super.key,
this.resultCount,
this.onResultTap,
}) : super(key: key);
});
@override
Widget build(BuildContext context) {

View File

@@ -19,8 +19,8 @@ import "package:photos/ui/viewer/file/thumbnail_widget.dart";
import "package:photos/ui/viewer/people/add_person_action_sheet.dart";
import "package:photos/ui/viewer/people/people_page.dart";
import 'package:photos/ui/viewer/search/result/person_face_widget.dart';
import "package:photos/ui/viewer/search/result/search_people_all_page.dart";
import "package:photos/ui/viewer/search/result/search_result_page.dart";
import 'package:photos/ui/viewer/search/result/search_section_all_page.dart';
import "package:photos/ui/viewer/search/search_section_cta.dart";
import "package:photos/utils/navigation_util.dart";
@@ -88,7 +88,7 @@ class _PeopleSectionState extends State<PeopleSection> {
if (shouldShowMore) {
routeToPage(
context,
SearchSectionAllPage(
PeopleAllPage(
sectionType: widget.sectionType,
),
);
@@ -119,7 +119,7 @@ class _PeopleSectionState extends State<PeopleSection> {
],
),
const SizedBox(height: 2),
SearchExampleRow(_examples, widget.sectionType),
PeopleRow(_examples, widget.sectionType),
],
),
)
@@ -163,11 +163,11 @@ class _PeopleSectionState extends State<PeopleSection> {
}
}
class SearchExampleRow extends StatelessWidget {
class PeopleRow extends StatelessWidget {
final SectionType sectionType;
final List<SearchResult> examples;
const SearchExampleRow(this.examples, this.sectionType, {super.key});
const PeopleRow(this.examples, this.sectionType, {super.key});
@override
Widget build(BuildContext context) {
@@ -175,7 +175,7 @@ class SearchExampleRow extends StatelessWidget {
final scrollableExamples = <Widget>[];
examples.forEachIndexed((index, element) {
scrollableExamples.add(
SearchExample(
PeopleRowItem(
searchResult: examples.elementAt(index),
),
);
@@ -193,9 +193,9 @@ class SearchExampleRow extends StatelessWidget {
}
}
class SearchExample extends StatelessWidget {
class PeopleRowItem extends StatelessWidget {
final SearchResult searchResult;
const SearchExample({required this.searchResult, super.key});
const PeopleRowItem({required this.searchResult, super.key});
@override
Widget build(BuildContext context) {
@@ -204,9 +204,9 @@ class SearchExample extends StatelessWidget {
int.tryParse(searchResult.name()) != null);
late final double width;
if (textScaleFactor <= 1.0) {
width = 85.0;
width = 120.0;
} else {
width = 85.0 + ((textScaleFactor - 1.0) * 64);
width = 120.0 + ((textScaleFactor - 1.0) * 64);
}
final heroTag =
searchResult.heroTag() + (searchResult.previewThumbnail()?.tag ?? "");
@@ -238,19 +238,20 @@ class SearchExample extends StatelessWidget {
child: SizedBox(
width: width,
child: Padding(
padding: const EdgeInsets.only(left: 6, right: 6, top: 8),
padding: const EdgeInsets.only(left: 4, right: 4, top: 8),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
width: 64,
height: 64,
width: 100,
height: 100,
child: searchResult.previewThumbnail() != null
? Hero(
tag: heroTag,
child: ClipRRect(
borderRadius:
const BorderRadius.all(Radius.elliptical(16, 12)),
borderRadius: const BorderRadius.all(
Radius.elliptical(16, 12),
),
child: searchResult.type() != ResultType.faces
? ThumbnailWidget(
searchResult.previewThumbnail()!,
@@ -285,7 +286,7 @@ class SearchExample extends StatelessWidget {
}
},
child: Padding(
padding: const EdgeInsets.only(top: 10, bottom: 16),
padding: const EdgeInsets.only(top: 10, bottom: 10),
child: Text(
"Add name",
maxLines: 1,
@@ -296,7 +297,7 @@ class SearchExample extends StatelessWidget {
),
)
: Padding(
padding: const EdgeInsets.only(top: 10, bottom: 16),
padding: const EdgeInsets.only(top: 10, bottom: 10),
child: Text(
searchResult.name(),
maxLines: 2,