Merge pull request #482 from ente-io/search_refactor

This commit is contained in:
Vishnu Mohandas 2022-09-15 10:36:55 +05:30 committed by GitHub
commit bea8aded44
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 232 additions and 739 deletions

View file

@ -1,4 +1,10 @@
import 'package:photos/models/search/holiday_search_result.dart';
class HolidayData {
final String name;
final int month;
final int day;
const HolidayData(this.name, {required this.month, required this.day});
}
const List<HolidayData> allHolidays = [
HolidayData('New Year', month: 1, day: 1),

View file

@ -1,5 +1,3 @@
import 'package:photos/models/search/month_search_result.dart';
List<MonthData> allMonths = [
MonthData('January', 1),
MonthData('February', 2),
@ -14,3 +12,10 @@ List<MonthData> allMonths = [
MonthData('November', 11),
MonthData('December', 12),
];
class MonthData {
final String name;
final int monthNumber;
MonthData(this.name, this.monthNumber);
}

View file

@ -1,8 +1,30 @@
import 'package:photos/models/collection_items.dart';
import 'package:photos/models/search/search_results.dart';
import 'package:photos/models/file.dart';
import 'package:photos/models/search/search_result.dart';
class AlbumSearchResult extends SearchResult {
final CollectionWithThumbnail collectionWithThumbnail;
AlbumSearchResult(this.collectionWithThumbnail);
@override
ResultType type() {
return ResultType.collection;
}
@override
String name() {
return collectionWithThumbnail.collection.name;
}
@override
File previewThumbnail() {
return collectionWithThumbnail.thumbnail;
}
@override
List<File> resultFiles() {
// for album search result, we should open the album page directly
throw UnimplementedError();
}
}

View file

@ -1,8 +1,29 @@
import 'package:photos/models/file.dart';
import 'package:photos/models/search/search_results.dart';
import 'package:photos/models/search/search_result.dart';
class FileSearchResult extends SearchResult {
final File file;
FileSearchResult(this.file);
@override
String name() {
return file.getDisplayName();
}
@override
ResultType type() {
return ResultType.file;
}
@override
File previewThumbnail() {
return file;
}
@override
List<File> resultFiles() {
// for fileSearchResult, the file detailed page view will be opened
throw UnimplementedError();
}
}

View file

@ -0,0 +1,30 @@
import 'package:photos/models/file.dart';
import 'package:photos/models/search/search_result.dart';
class GenericSearchResult extends SearchResult {
final String _name;
final List<File> _files;
final ResultType _type;
GenericSearchResult(this._type, this._name, this._files);
@override
String name() {
return _name;
}
@override
ResultType type() {
return _type;
}
@override
File previewThumbnail() {
return _files.first;
}
@override
List<File> resultFiles() {
return _files;
}
}

View file

@ -1,15 +0,0 @@
import 'package:photos/models/file.dart';
import 'package:photos/models/search/search_results.dart';
class HolidaySearchResult extends SearchResult {
final String holidayName;
final List<File> files;
HolidaySearchResult(this.holidayName, this.files);
}
class HolidayData {
final String name;
final int month;
final int day;
const HolidayData(this.name, {required this.month, required this.day});
}

View file

@ -1,9 +0,0 @@
import 'package:photos/models/file.dart';
import 'package:photos/models/search/search_results.dart';
class LocationSearchResult extends SearchResult {
final String location;
final List<File> files;
LocationSearchResult(this.location, this.files);
}

View file

@ -1,14 +0,0 @@
import 'package:photos/models/file.dart';
import 'package:photos/models/search/search_results.dart';
class MonthSearchResult extends SearchResult {
final String month;
final List<File> files;
MonthSearchResult(this.month, this.files);
}
class MonthData {
final String name;
final int monthNumber;
MonthData(this.name, this.monthNumber);
}

View file

@ -0,0 +1,17 @@
import 'package:photos/models/file.dart';
abstract class SearchResult {
ResultType type();
String name();
File previewThumbnail();
String heroTag() {
return '${type().toString()}_${name()}';
}
List<File> resultFiles();
}
enum ResultType { collection, file, location, month, year, fileType, event }

View file

@ -1 +0,0 @@
class SearchResult {}

View file

@ -1,9 +0,0 @@
import 'package:photos/models/file.dart';
import 'package:photos/models/search/search_results.dart';
class YearSearchResult extends SearchResult {
final String year;
final List<File> files;
YearSearchResult(this.year, this.files);
}

View file

@ -15,11 +15,9 @@ import 'package:photos/models/collection_items.dart';
import 'package:photos/models/file.dart';
import 'package:photos/models/location.dart';
import 'package:photos/models/search/album_search_result.dart';
import 'package:photos/models/search/holiday_search_result.dart';
import 'package:photos/models/search/generic_search_result.dart';
import 'package:photos/models/search/location_api_response.dart';
import 'package:photos/models/search/location_search_result.dart';
import 'package:photos/models/search/month_search_result.dart';
import 'package:photos/models/search/year_search_result.dart';
import 'package:photos/models/search/search_result.dart';
import 'package:photos/services/collections_service.dart';
import 'package:photos/utils/date_time_util.dart';
@ -40,27 +38,28 @@ class SearchService {
/* In case home screen loads before 5 seconds and user starts search,
future will not be null.So here getAllFiles won't run again in that case. */
if (_cachedFilesFuture == null) {
getAllFiles();
_getAllFiles();
}
});
Bus.instance.on<LocalPhotosUpdatedEvent>().listen((event) {
_cachedFilesFuture = null;
getAllFiles();
_getAllFiles();
});
}
Future<List<File>> getAllFiles() async {
Future<List<File>> _getAllFiles() async {
if (_cachedFilesFuture != null) {
return _cachedFilesFuture;
}
_logger.fine("Reading all files from db");
_cachedFilesFuture = FilesDB.instance.getAllFilesFromDB();
return _cachedFilesFuture;
}
Future<List<File>> getFileSearchResults(String query) async {
final List<File> fileSearchResults = [];
final List<File> files = await getAllFiles();
final List<File> files = await _getAllFiles();
final nonCaseSensitiveRegexForQuery = RegExp(query, caseSensitive: false);
for (var file in files) {
if (fileSearchResults.length >= _maximumResultsLimit) {
@ -77,12 +76,12 @@ class SearchService {
_cachedFilesFuture = null;
}
Future<List<LocationSearchResult>> getLocationSearchResults(
Future<List<GenericSearchResult>> getLocationSearchResults(
String query,
) async {
final List<LocationSearchResult> locationSearchResults = [];
final List<GenericSearchResult> searchResults = [];
try {
final List<File> allFiles = await SearchService.instance.getAllFiles();
final List<File> allFiles = await _getAllFiles();
final response = await _dio.get(
_config.getHttpEndpoint() + "/search/location",
@ -108,15 +107,16 @@ class SearchService {
(first, second) => second.creationTime.compareTo(first.creationTime),
);
if (filesInLocation.isNotEmpty) {
locationSearchResults.add(
LocationSearchResult(locationData.place, filesInLocation),
searchResults.add(
GenericSearchResult(
ResultType.location, locationData.place, filesInLocation),
);
}
}
} catch (e) {
_logger.severe(e);
}
return locationSearchResults;
return searchResults;
}
// getFilteredCollectionsWithThumbnail removes deleted or archived or
@ -149,16 +149,17 @@ class SearchService {
return collectionSearchResults;
}
Future<List<YearSearchResult>> getYearSearchResults(
Future<List<GenericSearchResult>> getYearSearchResults(
String yearFromQuery,
) async {
final List<YearSearchResult> yearSearchResults = [];
final List<GenericSearchResult> searchResults = [];
for (var yearData in YearsData.instance.yearsData) {
if (yearData.year.startsWith(yearFromQuery)) {
final List<File> filesInYear = await _getFilesInYear(yearData.duration);
if (filesInYear.isNotEmpty) {
yearSearchResults.add(
YearSearchResult(
searchResults.add(
GenericSearchResult(
ResultType.year,
yearData.year,
filesInYear,
),
@ -166,13 +167,13 @@ class SearchService {
}
}
}
return yearSearchResults;
return searchResults;
}
Future<List<HolidaySearchResult>> getHolidaySearchResults(
Future<List<GenericSearchResult>> getHolidaySearchResults(
String query,
) async {
final List<HolidaySearchResult> holidaySearchResults = [];
final List<GenericSearchResult> searchResults = [];
final nonCaseSensitiveRegexForQuery = RegExp(query, caseSensitive: false);
@ -185,17 +186,17 @@ class SearchService {
order: 'DESC',
);
if (matchedFiles.isNotEmpty) {
holidaySearchResults.add(
HolidaySearchResult(holiday.name, matchedFiles),
searchResults.add(
GenericSearchResult(ResultType.event, holiday.name, matchedFiles),
);
}
}
}
return holidaySearchResults;
return searchResults;
}
Future<List<MonthSearchResult>> getMonthSearchResults(String query) async {
final List<MonthSearchResult> monthSearchResults = [];
Future<List<GenericSearchResult>> getMonthSearchResults(String query) async {
final List<GenericSearchResult> searchResults = [];
final nonCaseSensitiveRegexForQuery = RegExp(query, caseSensitive: false);
for (var month in allMonths) {
@ -207,8 +208,9 @@ class SearchService {
order: 'DESC',
);
if (matchedFiles.isNotEmpty) {
monthSearchResults.add(
MonthSearchResult(
searchResults.add(
GenericSearchResult(
ResultType.month,
month.name,
matchedFiles,
),
@ -217,7 +219,7 @@ class SearchService {
}
}
return monthSearchResults;
return searchResults;
}
Future<List<File>> _getFilesInYear(List<int> durationOfYear) async {

View file

@ -1,77 +0,0 @@
// @dart=2.9
import 'package:flutter/material.dart';
import 'package:photos/core/event_bus.dart';
import 'package:photos/events/files_updated_event.dart';
import 'package:photos/events/local_photos_updated_event.dart';
import 'package:photos/models/file_load_result.dart';
import 'package:photos/models/gallery_type.dart';
import 'package:photos/models/search/holiday_search_result.dart';
import 'package:photos/models/selected_files.dart';
import 'package:photos/ui/viewer/gallery/gallery.dart';
import 'package:photos/ui/viewer/gallery/gallery_app_bar_widget.dart';
import 'package:photos/ui/viewer/gallery/gallery_overlay_widget.dart';
class FilesFromHolidayPage extends StatelessWidget {
final HolidaySearchResult holidaySearchResult;
final String tagPrefix;
final _selectedFiles = SelectedFiles();
static const GalleryType appBarType = GalleryType.searchResults;
static const GalleryType overlayType = GalleryType.searchResults;
FilesFromHolidayPage(
this.holidaySearchResult,
this.tagPrefix, {
Key key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final gallery = Gallery(
asyncLoader: (creationStartTime, creationEndTime, {limit, asc}) {
final result = holidaySearchResult.files
.where(
(file) =>
file.creationTime >= creationStartTime &&
file.creationTime <= creationEndTime,
)
.toList();
return Future.value(
FileLoadResult(
result,
result.length < holidaySearchResult.files.length,
),
);
},
reloadEvent: Bus.instance.on<LocalPhotosUpdatedEvent>(),
removalEventTypes: const {
EventType.deletedFromRemote,
EventType.deletedFromEverywhere,
},
tagPrefix: tagPrefix,
selectedFiles: _selectedFiles,
initialFiles: [holidaySearchResult.files[0]],
);
return Scaffold(
appBar: PreferredSize(
preferredSize: const Size.fromHeight(50.0),
child: GalleryAppBarWidget(
appBarType,
holidaySearchResult.holidayName,
_selectedFiles,
),
),
body: Stack(
alignment: Alignment.bottomCenter,
children: [
gallery,
GalleryOverlayWidget(
overlayType,
_selectedFiles,
)
],
),
);
}
}

View file

@ -1,77 +0,0 @@
// @dart=2.9
import 'package:flutter/material.dart';
import 'package:photos/core/event_bus.dart';
import 'package:photos/events/files_updated_event.dart';
import 'package:photos/events/local_photos_updated_event.dart';
import 'package:photos/models/file_load_result.dart';
import 'package:photos/models/gallery_type.dart';
import 'package:photos/models/search/year_search_result.dart';
import 'package:photos/models/selected_files.dart';
import 'package:photos/ui/viewer/gallery/gallery.dart';
import 'package:photos/ui/viewer/gallery/gallery_app_bar_widget.dart';
import 'package:photos/ui/viewer/gallery/gallery_overlay_widget.dart';
class FilesFromYearPage extends StatelessWidget {
final YearSearchResult yearSearchResult;
final String tagPrefix;
final _selectedFiles = SelectedFiles();
static const GalleryType appBarType = GalleryType.searchResults;
static const GalleryType overlayType = GalleryType.searchResults;
FilesFromYearPage(
this.yearSearchResult,
this.tagPrefix, {
Key key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final gallery = Gallery(
asyncLoader: (creationStartTime, creationEndTime, {limit, asc}) {
final result = yearSearchResult.files
.where(
(file) =>
file.creationTime >= creationStartTime &&
file.creationTime <= creationEndTime,
)
.toList();
return Future.value(
FileLoadResult(
result,
result.length < yearSearchResult.files.length,
),
);
},
reloadEvent: Bus.instance.on<LocalPhotosUpdatedEvent>(),
removalEventTypes: const {
EventType.deletedFromRemote,
EventType.deletedFromEverywhere,
},
tagPrefix: tagPrefix,
selectedFiles: _selectedFiles,
initialFiles: [yearSearchResult.files[0]],
);
return Scaffold(
appBar: PreferredSize(
preferredSize: const Size.fromHeight(50.0),
child: GalleryAppBarWidget(
appBarType,
yearSearchResult.year.toString(),
_selectedFiles,
),
),
body: Stack(
alignment: Alignment.bottomCenter,
children: [
gallery,
GalleryOverlayWidget(
overlayType,
_selectedFiles,
)
],
),
);
}
}

View file

@ -1,77 +0,0 @@
// @dart=2.9
import 'package:flutter/material.dart';
import 'package:photos/core/event_bus.dart';
import 'package:photos/events/files_updated_event.dart';
import 'package:photos/events/local_photos_updated_event.dart';
import 'package:photos/models/file_load_result.dart';
import 'package:photos/models/gallery_type.dart';
import 'package:photos/models/search/location_search_result.dart';
import 'package:photos/models/selected_files.dart';
import 'package:photos/ui/viewer/gallery/gallery.dart';
import 'package:photos/ui/viewer/gallery/gallery_app_bar_widget.dart';
import 'package:photos/ui/viewer/gallery/gallery_overlay_widget.dart';
class FilesInLocationPage extends StatelessWidget {
final LocationSearchResult locationSearchResult;
final String tagPrefix;
final _selectedFiles = SelectedFiles();
static const GalleryType appBarType = GalleryType.searchResults;
static const GalleryType overlayType = GalleryType.searchResults;
FilesInLocationPage(
this.locationSearchResult,
this.tagPrefix, {
Key key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final gallery = Gallery(
asyncLoader: (creationStartTime, creationEndTime, {limit, asc}) {
final result = locationSearchResult.files
.where(
(file) =>
file.creationTime >= creationStartTime &&
file.creationTime <= creationEndTime,
)
.toList();
return Future.value(
FileLoadResult(
result,
result.length < locationSearchResult.files.length,
),
);
},
reloadEvent: Bus.instance.on<LocalPhotosUpdatedEvent>(),
removalEventTypes: const {
EventType.deletedFromRemote,
EventType.deletedFromEverywhere,
},
tagPrefix: tagPrefix,
selectedFiles: _selectedFiles,
initialFiles: [locationSearchResult.files[0]],
);
return Scaffold(
appBar: PreferredSize(
preferredSize: const Size.fromHeight(50.0),
child: GalleryAppBarWidget(
appBarType,
locationSearchResult.location,
_selectedFiles,
),
),
body: Stack(
alignment: Alignment.bottomCenter,
children: [
gallery,
GalleryOverlayWidget(
overlayType,
_selectedFiles,
)
],
),
);
}
}

View file

@ -5,11 +5,12 @@ import 'package:photos/ente_theme_data.dart';
import 'package:photos/models/file.dart';
import 'package:photos/models/search/file_search_result.dart';
import 'package:photos/ui/viewer/file/detail_page.dart';
import 'package:photos/ui/viewer/search/search_result_widgets/search_result_thumbnail_widget.dart';
import 'package:photos/ui/viewer/search/result/search_thumbnail_widget.dart';
import 'package:photos/utils/navigation_util.dart';
class FileSearchResultWidget extends StatelessWidget {
final FileSearchResult matchedFile;
const FileSearchResultWidget(this.matchedFile, {Key key}) : super(key: key);
@override
@ -24,7 +25,7 @@ class FileSearchResultWidget extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SearchResultThumbnailWidget(
SearchThumbnailWidget(
matchedFile.file,
"file_details",
),

View file

@ -4,33 +4,33 @@ import 'package:flutter/material.dart';
import 'package:photos/core/event_bus.dart';
import 'package:photos/events/files_updated_event.dart';
import 'package:photos/events/local_photos_updated_event.dart';
import 'package:photos/models/file.dart';
import 'package:photos/models/file_load_result.dart';
import 'package:photos/models/gallery_type.dart';
import 'package:photos/models/search/month_search_result.dart';
import 'package:photos/models/search/search_result.dart';
import 'package:photos/models/selected_files.dart';
import 'package:photos/ui/viewer/gallery/gallery.dart';
import 'package:photos/ui/viewer/gallery/gallery_app_bar_widget.dart';
import 'package:photos/ui/viewer/gallery/gallery_overlay_widget.dart';
class FilesFromMonthPage extends StatelessWidget {
final MonthSearchResult monthSearchResult;
final String tagPrefix;
class SearchResultPage extends StatelessWidget {
final SearchResult searchResult;
final _selectedFiles = SelectedFiles();
static const GalleryType appBarType = GalleryType.searchResults;
static const GalleryType overlayType = GalleryType.searchResults;
FilesFromMonthPage(
this.monthSearchResult,
this.tagPrefix, {
SearchResultPage(
this.searchResult, {
Key key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final List<File> files = searchResult.resultFiles();
final gallery = Gallery(
asyncLoader: (creationStartTime, creationEndTime, {limit, asc}) {
final result = monthSearchResult.files
final result = files
.where(
(file) =>
file.creationTime >= creationStartTime &&
@ -40,7 +40,7 @@ class FilesFromMonthPage extends StatelessWidget {
return Future.value(
FileLoadResult(
result,
result.length < monthSearchResult.files.length,
result.length < files.length,
),
);
},
@ -49,16 +49,16 @@ class FilesFromMonthPage extends StatelessWidget {
EventType.deletedFromRemote,
EventType.deletedFromEverywhere,
},
tagPrefix: tagPrefix,
tagPrefix: searchResult.heroTag(),
selectedFiles: _selectedFiles,
initialFiles: [monthSearchResult.files[0]],
initialFiles: [searchResult.previewThumbnail()],
);
return Scaffold(
appBar: PreferredSize(
preferredSize: const Size.fromHeight(50.0),
child: GalleryAppBarWidget(
appBarType,
monthSearchResult.month,
searchResult.name(),
_selectedFiles,
),
),

View file

@ -1,21 +1,26 @@
// @dart=2.9
import 'package:flutter/material.dart';
import 'package:photos/db/files_db.dart';
import 'package:photos/ente_theme_data.dart';
import 'package:photos/models/search/album_search_result.dart';
import 'package:photos/ui/viewer/gallery/collection_page.dart';
import 'package:photos/ui/viewer/search/search_result_widgets/search_result_thumbnail_widget.dart';
import 'package:photos/models/search/search_result.dart';
import 'package:photos/ui/viewer/search/result/search_result_page.dart';
import 'package:photos/ui/viewer/search/result/search_thumbnail_widget.dart';
import 'package:photos/utils/navigation_util.dart';
class AlbumSearchResultWidget extends StatelessWidget {
final AlbumSearchResult albumSearchResult;
class SearchResultWidget extends StatelessWidget {
final SearchResult searchResult;
final Future<int>? resultCount;
final Function? onResultTap;
const AlbumSearchResultWidget(this.albumSearchResult, {Key key})
: super(key: key);
const SearchResultWidget(
this.searchResult, {
Key? key,
this.resultCount,
this.onResultTap,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final heroTagPrefix = searchResult.heroTag();
return GestureDetector(
behavior: HitTestBehavior.opaque,
child: Container(
@ -23,19 +28,19 @@ class AlbumSearchResultWidget extends StatelessWidget {
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 12),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SearchResultThumbnailWidget(
albumSearchResult.collectionWithThumbnail.thumbnail,
"collection_search",
SearchThumbnailWidget(
searchResult.previewThumbnail(),
heroTagPrefix,
),
const SizedBox(width: 16),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Album',
_resultTypeName(searchResult.type()),
style: TextStyle(
fontSize: 12,
color: Theme.of(context).colorScheme.subTextColor,
@ -45,18 +50,17 @@ class AlbumSearchResultWidget extends StatelessWidget {
SizedBox(
width: 220,
child: Text(
albumSearchResult.collectionWithThumbnail.collection.name,
searchResult.name(),
style: const TextStyle(fontSize: 18),
overflow: TextOverflow.ellipsis,
),
),
const SizedBox(height: 2),
FutureBuilder<int>(
future: FilesDB.instance.collectionFileCount(
albumSearchResult.collectionWithThumbnail.collection.id,
),
future: resultCount ??
Future.value(searchResult.resultFiles().length),
builder: (context, snapshot) {
if (snapshot.hasData && snapshot.data > 0) {
if (snapshot.hasData && snapshot.data! > 0) {
final noOfMemories = snapshot.data;
return RichText(
text: TextSpan(
@ -78,7 +82,7 @@ class AlbumSearchResultWidget extends StatelessWidget {
return const SizedBox.shrink();
}
},
),
)
],
),
const Spacer(),
@ -91,14 +95,34 @@ class AlbumSearchResultWidget extends StatelessWidget {
),
),
onTap: () {
routeToPage(
context,
CollectionPage(
albumSearchResult.collectionWithThumbnail,
tagPrefix: "collection_search",
),
);
if (onResultTap != null) {
onResultTap!();
} else {
routeToPage(
context,
SearchResultPage(searchResult),
);
}
},
);
}
String _resultTypeName(ResultType type) {
switch (type) {
case ResultType.collection:
return "Album";
case ResultType.year:
return "Year";
case ResultType.month:
return "Month";
case ResultType.file:
return "Memory";
case ResultType.event:
return "Day";
case ResultType.location:
return "Day";
default:
return type.name.toUpperCase();
}
}
}

View file

@ -4,11 +4,11 @@ import 'package:flutter/widgets.dart';
import 'package:photos/models/file.dart';
import 'package:photos/ui/viewer/file/thumbnail_widget.dart';
class SearchResultThumbnailWidget extends StatelessWidget {
class SearchThumbnailWidget extends StatelessWidget {
final File file;
final String tagPrefix;
const SearchResultThumbnailWidget(
const SearchThumbnailWidget(
this.file,
this.tagPrefix, {
Key key,

View file

@ -1,91 +0,0 @@
// @dart=2.9
import 'package:flutter/material.dart';
import 'package:photos/ente_theme_data.dart';
import 'package:photos/models/search/holiday_search_result.dart';
import 'package:photos/ui/viewer/search/collections/files_from_holiday_page.dart';
import 'package:photos/ui/viewer/search/search_result_widgets/search_result_thumbnail_widget.dart';
import 'package:photos/utils/navigation_util.dart';
class HolidaySearchResultWidget extends StatelessWidget {
static const String _tagPrefix = "holiday_search";
final HolidaySearchResult holidaySearchResult;
const HolidaySearchResultWidget(this.holidaySearchResult, {Key key})
: super(key: key);
@override
Widget build(BuildContext context) {
final noOfMemories = holidaySearchResult.files.length;
final heroTagPrefix = _tagPrefix + holidaySearchResult.holidayName;
return GestureDetector(
behavior: HitTestBehavior.opaque,
child: Container(
color: Theme.of(context).colorScheme.searchResultsColor,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 12),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SearchResultThumbnailWidget(
holidaySearchResult.files[0],
heroTagPrefix,
),
const SizedBox(width: 16),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Date',
style: TextStyle(
fontSize: 12,
color: Theme.of(context).colorScheme.subTextColor,
),
),
const SizedBox(height: 6),
SizedBox(
width: 220,
child: Text(
holidaySearchResult.holidayName,
style: const TextStyle(fontSize: 18),
overflow: TextOverflow.ellipsis,
),
),
const SizedBox(height: 2),
RichText(
text: TextSpan(
style: TextStyle(
color: Theme.of(context)
.colorScheme
.searchResultsCountTextColor,
),
children: [
TextSpan(text: noOfMemories.toString()),
TextSpan(
text: noOfMemories != 1 ? ' memories' : ' memory',
),
],
),
),
],
),
const Spacer(),
Icon(
Icons.chevron_right,
color: Theme.of(context).colorScheme.subTextColor,
),
],
),
),
),
onTap: () {
routeToPage(
context,
FilesFromHolidayPage(holidaySearchResult, heroTagPrefix),
);
},
);
}
}

View file

@ -1,91 +0,0 @@
// @dart=2.9
import 'package:flutter/material.dart';
import 'package:photos/ente_theme_data.dart';
import 'package:photos/models/search/location_search_result.dart';
import 'package:photos/ui/viewer/search/collections/files_in_location_page.dart';
import 'package:photos/ui/viewer/search/search_result_widgets/search_result_thumbnail_widget.dart';
import 'package:photos/utils/navigation_util.dart';
class LocationSearchResultWidget extends StatelessWidget {
static const String _tagPrefix = "location_search";
final LocationSearchResult locationSearchResult;
const LocationSearchResultWidget(this.locationSearchResult, {Key key})
: super(key: key);
@override
Widget build(BuildContext context) {
final noOfMemories = locationSearchResult.files.length;
final heroTagPrefix = _tagPrefix + locationSearchResult.location;
return GestureDetector(
behavior: HitTestBehavior.opaque,
child: Container(
color: Theme.of(context).colorScheme.searchResultsColor,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 12),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SearchResultThumbnailWidget(
locationSearchResult.files[0],
heroTagPrefix,
),
const SizedBox(width: 16),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Location',
style: TextStyle(
fontSize: 12,
color: Theme.of(context).colorScheme.subTextColor,
),
),
const SizedBox(height: 6),
SizedBox(
width: 220,
child: Text(
locationSearchResult.location,
style: const TextStyle(fontSize: 18),
overflow: TextOverflow.ellipsis,
),
),
const SizedBox(height: 2),
RichText(
text: TextSpan(
style: TextStyle(
color: Theme.of(context)
.colorScheme
.searchResultsCountTextColor,
),
children: [
TextSpan(text: noOfMemories.toString()),
TextSpan(
text: noOfMemories != 1 ? ' memories' : ' memory',
),
],
),
),
],
),
const Spacer(),
Icon(
Icons.chevron_right,
color: Theme.of(context).colorScheme.subTextColor,
),
],
),
),
),
onTap: () {
routeToPage(
context,
FilesInLocationPage(locationSearchResult, heroTagPrefix),
);
},
);
}
}

View file

@ -1,91 +0,0 @@
// @dart=2.9
import 'package:flutter/material.dart';
import 'package:photos/ente_theme_data.dart';
import 'package:photos/models/search/month_search_result.dart';
import 'package:photos/ui/viewer/search/collections/files_from_month_page.dart';
import 'package:photos/ui/viewer/search/search_result_widgets/search_result_thumbnail_widget.dart';
import 'package:photos/utils/navigation_util.dart';
class MonthSearchResultWidget extends StatelessWidget {
static const String _tagPrefix = "month_search";
final MonthSearchResult monthSearchResult;
const MonthSearchResultWidget(this.monthSearchResult, {Key key})
: super(key: key);
@override
Widget build(BuildContext context) {
final noOfMemories = monthSearchResult.files.length;
final heroTagPrefix = _tagPrefix + monthSearchResult.month;
return GestureDetector(
behavior: HitTestBehavior.opaque,
child: Container(
color: Theme.of(context).colorScheme.searchResultsColor,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 12),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SearchResultThumbnailWidget(
monthSearchResult.files[0],
heroTagPrefix,
),
const SizedBox(width: 16),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Month',
style: TextStyle(
fontSize: 12,
color: Theme.of(context).colorScheme.subTextColor,
),
),
const SizedBox(height: 6),
SizedBox(
width: 220,
child: Text(
monthSearchResult.month,
style: const TextStyle(fontSize: 18),
overflow: TextOverflow.ellipsis,
),
),
const SizedBox(height: 2),
RichText(
text: TextSpan(
style: TextStyle(
color: Theme.of(context)
.colorScheme
.searchResultsCountTextColor,
),
children: [
TextSpan(text: noOfMemories.toString()),
TextSpan(
text: noOfMemories != 1 ? ' memories' : ' memory',
),
],
),
),
],
),
const Spacer(),
Icon(
Icons.chevron_right,
color: Theme.of(context).colorScheme.subTextColor,
),
],
),
),
),
onTap: () {
routeToPage(
context,
FilesFromMonthPage(monthSearchResult, heroTagPrefix),
);
},
);
}
}

View file

@ -1,87 +0,0 @@
// @dart=2.9
import 'package:flutter/material.dart';
import 'package:photos/ente_theme_data.dart';
import 'package:photos/models/search/year_search_result.dart';
import 'package:photos/ui/viewer/search/collections/files_from_year_page.dart';
import 'package:photos/ui/viewer/search/search_result_widgets/search_result_thumbnail_widget.dart';
import 'package:photos/utils/navigation_util.dart';
class YearSearchResultWidget extends StatelessWidget {
static const String _tagPrefix = "year_search";
final YearSearchResult yearSearchResult;
const YearSearchResultWidget(this.yearSearchResult, {Key key})
: super(key: key);
@override
Widget build(BuildContext context) {
final noOfMemories = yearSearchResult.files.length;
final heroTagPrefix = _tagPrefix + yearSearchResult.year;
return GestureDetector(
behavior: HitTestBehavior.opaque,
child: Container(
color: Theme.of(context).colorScheme.searchResultsColor,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 12),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SearchResultThumbnailWidget(
yearSearchResult.files[0],
heroTagPrefix,
),
const SizedBox(width: 16),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Year',
style: TextStyle(
fontSize: 12,
color: Theme.of(context).colorScheme.subTextColor,
),
),
const SizedBox(height: 6),
Text(
yearSearchResult.year,
style: const TextStyle(fontSize: 18),
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 2),
RichText(
text: TextSpan(
style: TextStyle(
color: Theme.of(context)
.colorScheme
.searchResultsCountTextColor,
),
children: [
TextSpan(text: noOfMemories.toString()),
TextSpan(
text: noOfMemories != 1 ? ' memories' : ' memory',
),
],
),
),
],
),
const Spacer(),
Icon(
Icons.chevron_right,
color: Theme.of(context).colorScheme.subTextColor,
),
],
),
),
),
onTap: () {
routeToPage(
context,
FilesFromYearPage(yearSearchResult, heroTagPrefix),
);
},
);
}
}

View file

@ -2,23 +2,20 @@
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
import 'package:photos/db/files_db.dart';
import 'package:photos/ente_theme_data.dart';
import 'package:photos/models/search/album_search_result.dart';
import 'package:photos/models/search/file_search_result.dart';
import 'package:photos/models/search/holiday_search_result.dart';
import 'package:photos/models/search/location_search_result.dart';
import 'package:photos/models/search/month_search_result.dart';
import 'package:photos/models/search/search_results.dart';
import 'package:photos/models/search/year_search_result.dart';
import 'package:photos/ui/viewer/search/search_result_widgets/collection_result_widget.dart';
import 'package:photos/ui/viewer/search/search_result_widgets/file_result_widget.dart';
import 'package:photos/ui/viewer/search/search_result_widgets/holiday_result_widget.dart';
import 'package:photos/ui/viewer/search/search_result_widgets/location_result_widget.dart';
import 'package:photos/ui/viewer/search/search_result_widgets/month_result_widget.dart';
import 'package:photos/ui/viewer/search/search_result_widgets/year_result_widget.dart';
import 'package:photos/models/search/generic_search_result.dart';
import 'package:photos/models/search/search_result.dart';
import 'package:photos/ui/viewer/gallery/collection_page.dart';
import 'package:photos/ui/viewer/search/result/file_result_widget.dart';
import 'package:photos/ui/viewer/search/result/search_result_widget.dart';
import 'package:photos/utils/navigation_util.dart';
class SearchSuggestionsWidget extends StatelessWidget {
final List<SearchResult> results;
const SearchSuggestionsWidget(
this.results, {
Key key,
@ -62,17 +59,24 @@ class SearchSuggestionsWidget extends StatelessWidget {
}
final result = results[index];
if (result is AlbumSearchResult) {
return AlbumSearchResultWidget(result);
} else if (result is LocationSearchResult) {
return LocationSearchResultWidget(result);
final AlbumSearchResult albumSearchResult = result;
return SearchResultWidget(
result,
resultCount: FilesDB.instance.collectionFileCount(
albumSearchResult.collectionWithThumbnail.collection.id,
),
onResultTap: () => routeToPage(
context,
CollectionPage(
albumSearchResult.collectionWithThumbnail,
tagPrefix: result.heroTag(),
),
),
);
} else if (result is FileSearchResult) {
return FileSearchResultWidget(result);
} else if (result is YearSearchResult) {
return YearSearchResultWidget(result);
} else if (result is HolidaySearchResult) {
return HolidaySearchResultWidget(result);
} else if (result is MonthSearchResult) {
return MonthSearchResultWidget(result);
} else if (result is GenericSearchResult) {
return SearchResultWidget(result);
} else {
Logger('SearchSuggestionsWidget')
.info("Invalid/Unsupported value");

View file

@ -4,9 +4,9 @@ import 'dart:async';
import 'package:flutter/material.dart';
import 'package:photos/ente_theme_data.dart';
import 'package:photos/models/search/search_results.dart';
import 'package:photos/models/search/search_result.dart';
import 'package:photos/services/search_service.dart';
import 'package:photos/ui/viewer/search/search_result_widgets/no_result_widget.dart';
import 'package:photos/ui/viewer/search/result/no_result_widget.dart';
import 'package:photos/ui/viewer/search/search_suffix_icon_widget.dart';
import 'package:photos/ui/viewer/search/search_suggestions.dart';
import 'package:photos/utils/date_time_util.dart';