Merge pull request #422 from ente-io/search-by-year
This commit is contained in:
commit
4322cd4c12
9
lib/models/search/year_search_result.dart
Normal file
9
lib/models/search/year_search_result.dart
Normal 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);
|
||||
}
|
|
@ -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 &&
|
||||
|
|
76
lib/ui/viewer/search/collections/files_from_year_page.dart
Normal file
76
lib/ui/viewer/search/collections/files_from_year_page.dart
Normal 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,
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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) =>
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue