2023-11-08 07:42:50 +00:00
|
|
|
import "dart:async";
|
|
|
|
|
2023-10-16 14:04:31 +00:00
|
|
|
import "package:flutter/material.dart";
|
2023-11-09 05:40:09 +00:00
|
|
|
import "package:flutter_animate/flutter_animate.dart";
|
2023-11-08 07:42:50 +00:00
|
|
|
import "package:photos/events/event.dart";
|
2023-10-17 00:35:28 +00:00
|
|
|
import "package:photos/models/search/album_search_result.dart";
|
2023-11-01 06:43:15 +00:00
|
|
|
import "package:photos/models/search/recent_searches.dart";
|
2023-10-16 14:04:31 +00:00
|
|
|
import "package:photos/models/search/search_result.dart";
|
|
|
|
import "package:photos/models/search/search_types.dart";
|
2023-10-17 00:35:28 +00:00
|
|
|
import "package:photos/services/collections_service.dart";
|
2023-10-16 14:04:31 +00:00
|
|
|
import "package:photos/ui/common/loading_widget.dart";
|
|
|
|
import "package:photos/ui/components/title_bar_title_widget.dart";
|
2023-10-17 00:40:20 +00:00
|
|
|
import "package:photos/ui/viewer/gallery/collection_page.dart";
|
2023-10-18 05:42:57 +00:00
|
|
|
import "package:photos/ui/viewer/search/result/searchable_item.dart";
|
2023-10-17 00:40:20 +00:00
|
|
|
import "package:photos/utils/navigation_util.dart";
|
2023-10-16 14:04:31 +00:00
|
|
|
|
2023-11-01 03:12:42 +00:00
|
|
|
class SearchSectionAllPage extends StatefulWidget {
|
2023-10-16 14:04:31 +00:00
|
|
|
final SectionType sectionType;
|
2023-11-01 03:12:42 +00:00
|
|
|
const SearchSectionAllPage({required this.sectionType, super.key});
|
2023-10-16 14:04:31 +00:00
|
|
|
|
|
|
|
@override
|
2023-11-01 03:12:42 +00:00
|
|
|
State<SearchSectionAllPage> createState() => _SearchSectionAllPageState();
|
2023-10-16 14:04:31 +00:00
|
|
|
}
|
|
|
|
|
2023-11-01 03:12:42 +00:00
|
|
|
class _SearchSectionAllPageState extends State<SearchSectionAllPage> {
|
2023-11-08 07:42:50 +00:00
|
|
|
late Future<List<SearchResult>> sectionData;
|
2023-10-17 07:07:46 +00:00
|
|
|
late final bool _showCTATile;
|
2023-11-08 07:42:50 +00:00
|
|
|
final streamSubscriptions = <StreamSubscription>[];
|
|
|
|
|
|
|
|
@override
|
|
|
|
void initState() {
|
|
|
|
super.initState();
|
|
|
|
final streamsToListenTo = widget.sectionType.updateEvents();
|
|
|
|
for (Stream<Event> stream in streamsToListenTo) {
|
|
|
|
streamSubscriptions.add(
|
|
|
|
stream.listen((event) async {
|
|
|
|
setState(() {
|
|
|
|
sectionData = widget.sectionType.getData();
|
|
|
|
});
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-16 14:04:31 +00:00
|
|
|
@override
|
|
|
|
void didChangeDependencies() {
|
|
|
|
super.didChangeDependencies();
|
|
|
|
sectionData = widget.sectionType.getData(limit: null, context: context);
|
2023-10-17 07:07:46 +00:00
|
|
|
_showCTATile = widget.sectionType.isCTAVisible;
|
2023-10-16 14:04:31 +00:00
|
|
|
}
|
|
|
|
|
2023-11-08 07:42:50 +00:00
|
|
|
@override
|
|
|
|
void dispose() {
|
|
|
|
for (var subscriptions in streamSubscriptions) {
|
|
|
|
subscriptions.cancel();
|
|
|
|
}
|
|
|
|
super.dispose();
|
|
|
|
}
|
|
|
|
|
2023-10-16 14:04:31 +00:00
|
|
|
@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,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
2023-11-09 05:15:52 +00:00
|
|
|
body: Column(
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
children: [
|
|
|
|
Padding(
|
|
|
|
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 16),
|
|
|
|
child: Column(
|
2023-10-16 14:04:31 +00:00
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
children: [
|
2023-11-09 05:15:52 +00:00
|
|
|
TitleBarTitleWidget(
|
|
|
|
title: widget.sectionType.sectionTitle(context),
|
2023-10-16 14:04:31 +00:00
|
|
|
),
|
2023-11-09 05:15:52 +00:00
|
|
|
FutureBuilder(
|
|
|
|
future: sectionData,
|
|
|
|
builder: (context, snapshot) {
|
|
|
|
if (snapshot.hasData) {
|
|
|
|
final sectionResults = snapshot.data!;
|
2023-11-09 05:40:09 +00:00
|
|
|
return Text(sectionResults.length.toString())
|
|
|
|
.animate()
|
|
|
|
.fadeIn(
|
|
|
|
duration: const Duration(milliseconds: 150),
|
|
|
|
curve: Curves.easeIn,
|
|
|
|
);
|
2023-11-09 05:15:52 +00:00
|
|
|
} else {
|
|
|
|
return const SizedBox.shrink();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
Expanded(
|
|
|
|
child: Padding(
|
|
|
|
padding: const EdgeInsets.symmetric(
|
|
|
|
vertical: 20,
|
|
|
|
horizontal: 16,
|
|
|
|
),
|
|
|
|
child: FutureBuilder(
|
|
|
|
future: sectionData,
|
|
|
|
builder: (context, snapshot) {
|
|
|
|
if (snapshot.hasData) {
|
|
|
|
final sectionResults = snapshot.data!;
|
|
|
|
return ListView.separated(
|
2023-10-16 14:04:31 +00:00
|
|
|
itemBuilder: (context, index) {
|
2023-10-17 07:07:46 +00:00
|
|
|
if (sectionResults.length == index) {
|
2023-11-09 05:15:52 +00:00
|
|
|
return SearchableItemPlaceholder(
|
|
|
|
widget.sectionType,
|
|
|
|
);
|
2023-10-17 07:07:46 +00:00
|
|
|
}
|
2023-10-17 00:35:28 +00:00
|
|
|
if (sectionResults[index] is AlbumSearchResult) {
|
|
|
|
final albumSectionResult =
|
|
|
|
sectionResults[index] as AlbumSearchResult;
|
2023-10-18 05:42:57 +00:00
|
|
|
return SearchableItemWidget(
|
2023-10-17 00:35:28 +00:00
|
|
|
albumSectionResult,
|
|
|
|
resultCount:
|
|
|
|
CollectionsService.instance.getFileCount(
|
|
|
|
albumSectionResult
|
|
|
|
.collectionWithThumbnail.collection,
|
|
|
|
),
|
2023-11-01 06:43:15 +00:00
|
|
|
onResultTap: () {
|
2023-11-01 11:18:03 +00:00
|
|
|
RecentSearches()
|
|
|
|
.add(sectionResults[index].name());
|
2023-11-01 06:43:15 +00:00
|
|
|
|
|
|
|
routeToPage(
|
|
|
|
context,
|
|
|
|
CollectionPage(
|
|
|
|
albumSectionResult.collectionWithThumbnail,
|
|
|
|
tagPrefix: albumSectionResult.heroTag(),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
},
|
2023-10-17 00:35:28 +00:00
|
|
|
);
|
|
|
|
}
|
2023-11-09 05:15:52 +00:00
|
|
|
return SearchableItemWidget(
|
|
|
|
sectionResults[index],
|
|
|
|
);
|
2023-10-16 14:04:31 +00:00
|
|
|
},
|
|
|
|
separatorBuilder: (context, index) {
|
|
|
|
return const SizedBox(height: 10);
|
|
|
|
},
|
2023-10-17 07:07:46 +00:00
|
|
|
itemCount: sectionResults.length + (_showCTATile ? 1 : 0),
|
2023-10-17 00:35:28 +00:00
|
|
|
physics: const BouncingScrollPhysics(),
|
2023-10-18 02:33:00 +00:00
|
|
|
//This cache extend is needed for creating a new album
|
|
|
|
//using SearchSectionCTATile to work. This is so that
|
|
|
|
//SearchSectionCTATile doesn't get disposed when keyboard
|
|
|
|
//is open and the widget is out of view.
|
|
|
|
cacheExtent:
|
|
|
|
widget.sectionType == SectionType.album ? 400 : null,
|
2023-11-09 05:40:09 +00:00
|
|
|
)
|
|
|
|
.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,
|
|
|
|
),
|
|
|
|
);
|
2023-11-09 05:15:52 +00:00
|
|
|
} else {
|
|
|
|
return const EnteLoadingWidget();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
2023-10-16 14:04:31 +00:00
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|