Merge pull request #422 from ente-io/search-by-year

This commit is contained in:
Vishnu Mohandas 2022-08-12 12:33:29 +05:30 committed by GitHub
commit 4322cd4c12
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 218 additions and 13 deletions

View file

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

View file

@ -139,6 +139,20 @@ class SearchService {
return collectionSearchResults;
}
Future<List<File>> getYearSearchResults(int year) async {
final yearInMicroseconds = DateTime.utc(year).microsecondsSinceEpoch;
final nextYearInMicroseconds =
DateTime.utc(year + 1).microsecondsSinceEpoch;
final yearSearchResults =
await FilesDB.instance.getFilesCreatedWithinDurations(
[
[yearInMicroseconds, nextYearInMicroseconds]
],
null,
);
return yearSearchResults;
}
bool _isValidLocation(Location location) {
return location != null &&
location.latitude != null &&

View file

@ -0,0 +1,76 @@
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]],
footer: const SizedBox(height: 120),
);
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,6 +1,7 @@
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';
@ -41,14 +42,11 @@ class FilesInLocationPage extends StatelessWidget {
),
);
},
reloadEvent: Bus.instance.on<FilesUpdatedEvent>().where(
(event) =>
event.updatedFiles.firstWhere(
(element) => element.uploadedFileID != null,
orElse: () => null,
) !=
null,
),
reloadEvent: Bus.instance.on<LocalPhotosUpdatedEvent>(),
removalEventTypes: const {
EventType.deletedFromRemote,
EventType.deletedFromEverywhere,
},
forceReloadEvents: [
Bus.instance.on<FilesUpdatedEvent>().where(
(event) =>

View file

@ -0,0 +1,86 @@
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.toString();
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: 8),
Text(
yearSearchResult.year.toString(),
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),
forceCustomPageRoute: true,
);
},
);
}
}

View file

@ -5,9 +5,11 @@ import 'package:photos/models/search/album_search_result.dart';
import 'package:photos/models/search/file_search_result.dart';
import 'package:photos/models/search/location_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/filename_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/location_result_widget.dart';
import 'package:photos/ui/viewer/search/search_result_widgets/year_result_widget.dart';
class SearchSuggestionsWidget extends StatelessWidget {
final List<SearchResult> results;
@ -58,6 +60,8 @@ class SearchSuggestionsWidget extends StatelessWidget {
return LocationSearchResultWidget(result);
} else if (result is FileSearchResult) {
return FileSearchResultWidget(result);
} else if (result is YearSearchResult) {
return YearSearchResultWidget(result);
} else {
Logger('SearchSuggestionsWidget')
.info("Invalid/Unsupported value");

View file

@ -6,6 +6,7 @@ import 'package:photos/models/search/album_search_result.dart';
import 'package:photos/models/search/file_search_result.dart';
import 'package:photos/models/search/location_search_result.dart';
import 'package:photos/models/search/search_results.dart';
import 'package:photos/models/search/year_search_result.dart';
import 'package:photos/services/search_service.dart';
import 'package:photos/ui/viewer/search/search_suggestions.dart';
import 'package:photos/utils/navigation_util.dart';
@ -125,21 +126,38 @@ class _SearchWidgetState extends State<SearchWidget> {
Future<List<SearchResult>> getSearchResultsForQuery(String query) async {
final List<SearchResult> allResults = [];
final locationResults =
await SearchService.instance.getLocationSearchResults(query);
for (LocationSearchResult result in locationResults) {
allResults.add(result);
final queryAsIntForYear = int.tryParse(query);
if (isYearValid(queryAsIntForYear)) {
final yearResults =
await SearchService.instance.getYearSearchResults(queryAsIntForYear);
if (yearResults.isNotEmpty) {
allResults.add(YearSearchResult(queryAsIntForYear, yearResults));
}
}
final collectionResults =
await SearchService.instance.getCollectionSearchResults(query);
for (CollectionWithThumbnail collectionResult in collectionResults) {
allResults.add(AlbumSearchResult(collectionResult));
}
final locationResults =
await SearchService.instance.getLocationSearchResults(query);
for (LocationSearchResult result in locationResults) {
allResults.add(result);
}
final fileResults =
await SearchService.instance.getFileSearchResults(query);
for (File file in fileResults) {
allResults.add(FileSearchResult(file));
}
return allResults;
}
bool isYearValid(int year) {
return year != null &&
year >= 1970 &&
year <= int.parse(DateTime.now().year.toString());
}
}