Merge pull request #419 from ente-io/search_improvements

Search improvements
This commit is contained in:
Ashil 2022-08-11 18:04:44 +05:30 committed by GitHub
commit f4d1c780f2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 85 additions and 97 deletions

View file

@ -15,8 +15,7 @@ import 'package:photos/services/collections_service.dart';
import 'package:photos/services/user_service.dart'; import 'package:photos/services/user_service.dart';
class SearchService { class SearchService {
List<File> _cachedFiles; Future<List<File>> _cachedFilesFuture;
Future<List<File>> _future;
final _dio = Network.instance.getDio(); final _dio = Network.instance.getDio();
final _config = Configuration.instance; final _config = Configuration.instance;
final _logger = Logger((UserService).toString()); final _logger = Logger((UserService).toString());
@ -31,26 +30,23 @@ class SearchService {
Future.delayed(const Duration(seconds: 5), () async { Future.delayed(const Duration(seconds: 5), () async {
/* In case home screen loads before 5 seconds and user starts search, /* 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. */ future will not be null.So here getAllFiles won't run again in that case. */
if (_future == null) { if (_cachedFilesFuture == null) {
getAllFiles(); getAllFiles();
} }
}); });
Bus.instance.on<LocalPhotosUpdatedEvent>().listen((event) { Bus.instance.on<LocalPhotosUpdatedEvent>().listen((event) {
_cachedFiles = null; _cachedFilesFuture = null;
getAllFiles(); getAllFiles();
}); });
} }
Future<List<File>> getAllFiles() async { Future<List<File>> getAllFiles() async {
if (_cachedFiles != null) { if (_cachedFilesFuture != null) {
return _cachedFiles; return _cachedFilesFuture;
} }
if (_future != null) { _cachedFilesFuture = FilesDB.instance.getAllFilesFromDB();
return _future; return _cachedFilesFuture;
}
_future = _fetchAllFiles();
return _future;
} }
Future<List<File>> getFileSearchResults(String query) async { Future<List<File>> getFileSearchResults(String query) async {
@ -69,19 +65,19 @@ class SearchService {
} }
void clearCache() { void clearCache() {
_cachedFiles.clear(); _cachedFilesFuture = null;
} }
Future<List<LocationSearchResult>> getLocationSearchResults( Future<List<LocationSearchResult>> getLocationSearchResults(
String query, String query,
) async { ) async {
final List<LocationSearchResult> locationSearchResults = [];
try { try {
final List<File> allFiles = await SearchService.instance.getAllFiles(); final List<File> allFiles = await SearchService.instance.getAllFiles();
final List<LocationSearchResult> locationSearchResults = [];
final response = await _dio.get( final response = await _dio.get(
_config.getHttpEndpoint() + "/search/location", _config.getHttpEndpoint() + "/search/location",
queryParameters: {"query": query, "limit": 4}, queryParameters: {"query": query, "limit": 10},
options: Options( options: Options(
headers: {"X-Auth-Token": _config.getToken()}, headers: {"X-Auth-Token": _config.getToken()},
), ),
@ -100,17 +96,19 @@ class SearchService {
filesInLocation.add(file); filesInLocation.add(file);
} }
} }
filesInLocation.sort(
(first, second) => second.creationTime.compareTo(first.creationTime),
);
if (filesInLocation.isNotEmpty) { if (filesInLocation.isNotEmpty) {
locationSearchResults.add( locationSearchResults.add(
LocationSearchResult(locationData.place, filesInLocation), LocationSearchResult(locationData.place, filesInLocation),
); );
} }
} }
return locationSearchResults; } catch (e) {
} on DioError catch (e) { _logger.severe(e);
_logger.info(e);
rethrow;
} }
return locationSearchResults;
} }
// getFilteredCollectionsWithThumbnail removes deleted or archived or // getFilteredCollectionsWithThumbnail removes deleted or archived or
@ -160,9 +158,4 @@ class SearchService {
location.longitude < locationData.bbox[2] && location.longitude < locationData.bbox[2] &&
location.latitude < locationData.bbox[3]; location.latitude < locationData.bbox[3];
} }
Future<List<File>> _fetchAllFiles() async {
_cachedFiles = await FilesDB.instance.getAllFilesFromDB();
return _cachedFiles;
}
} }

View file

@ -8,7 +8,6 @@ class ThumbnailPlaceHolder extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
debugPrint("building placeHolder for thumbnail");
return Container( return Container(
alignment: Alignment.center, alignment: Alignment.center,
color: Theme.of(context).colorScheme.galleryThumbBackgroundColor, color: Theme.of(context).colorScheme.galleryThumbBackgroundColor,

View file

@ -166,7 +166,7 @@ class _ZoomableLiveImageState extends State<ZoomableLiveImage>
void _showLivePhotoToast() async { void _showLivePhotoToast() async {
var preferences = await SharedPreferences.getInstance(); var preferences = await SharedPreferences.getInstance();
int promptTillNow = preferences.getInt(kLivePhotoToastCounterKey) ?? 0; int promptTillNow = preferences.getInt(kLivePhotoToastCounterKey) ?? 0;
if (promptTillNow < kMaxLivePhotoToastCount) { if (promptTillNow < kMaxLivePhotoToastCount && mounted) {
showToast(context, "Press and hold to play video"); showToast(context, "Press and hold to play video");
preferences.setInt(kLivePhotoToastCounterKey, promptTillNow + 1); preferences.setInt(kLivePhotoToastCounterKey, promptTillNow + 1);
} }

View file

@ -11,13 +11,15 @@ import 'package:photos/ui/viewer/gallery/gallery_overlay_widget.dart';
class FilesInLocationPage extends StatelessWidget { class FilesInLocationPage extends StatelessWidget {
final LocationSearchResult locationSearchResult; final LocationSearchResult locationSearchResult;
final String tagPrefix;
final _selectedFiles = SelectedFiles(); final _selectedFiles = SelectedFiles();
static const String kTagPrefix = "location_search";
static const GalleryType appBarType = GalleryType.searchResults; static const GalleryType appBarType = GalleryType.searchResults;
static const GalleryType overlayType = GalleryType.searchResults; static const GalleryType overlayType = GalleryType.searchResults;
FilesInLocationPage({
FilesInLocationPage(
this.locationSearchResult, this.locationSearchResult,
this.tagPrefix, {
Key key, Key key,
}) : super(key: key); }) : super(key: key);
@ -57,7 +59,7 @@ class FilesInLocationPage extends StatelessWidget {
null, null,
), ),
], ],
tagPrefix: kTagPrefix, tagPrefix: tagPrefix,
selectedFiles: _selectedFiles, selectedFiles: _selectedFiles,
initialFiles: [locationSearchResult.files[0]], initialFiles: [locationSearchResult.files[0]],
footer: const SizedBox(height: 120), footer: const SizedBox(height: 120),

View file

@ -6,12 +6,17 @@ import 'package:photos/ui/viewer/search/collections/files_in_location_page.dart'
import 'package:photos/utils/navigation_util.dart'; import 'package:photos/utils/navigation_util.dart';
class LocationSearchResultWidget extends StatelessWidget { class LocationSearchResultWidget extends StatelessWidget {
static const String _tagPrefix = "location_search";
final LocationSearchResult locationSearchResult; final LocationSearchResult locationSearchResult;
const LocationSearchResultWidget(this.locationSearchResult, {Key key}) const LocationSearchResultWidget(this.locationSearchResult, {Key key})
: super(key: key); : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final noOfMemories = locationSearchResult.files.length; final noOfMemories = locationSearchResult.files.length;
final heroTagPrefix = _tagPrefix + locationSearchResult.location;
return GestureDetector( return GestureDetector(
behavior: HitTestBehavior.opaque, behavior: HitTestBehavior.opaque,
child: Container( child: Container(
@ -53,7 +58,7 @@ class LocationSearchResultWidget extends StatelessWidget {
), ),
), ),
Hero( Hero(
tag: "location_search" + locationSearchResult.files[0].tag(), tag: heroTagPrefix + locationSearchResult.files[0].tag(),
child: SizedBox( child: SizedBox(
height: 50, height: 50,
width: 50, width: 50,
@ -67,9 +72,8 @@ class LocationSearchResultWidget extends StatelessWidget {
onTap: () { onTap: () {
routeToPage( routeToPage(
context, context,
FilesInLocationPage( FilesInLocationPage(locationSearchResult, heroTagPrefix),
locationSearchResult: locationSearchResult, forceCustomPageRoute: true,
),
); );
}, },
); );

View file

@ -29,15 +29,11 @@ class _SearchIconWidgetState extends State<SearchIconWidget> {
tag: "search_icon", tag: "search_icon",
child: IconButton( child: IconButton(
onPressed: () { onPressed: () {
setState( Navigator.push(
() { context,
Navigator.push( TransparentRoute(
context, builder: (BuildContext context) => const SearchWidget(),
TransparentRoute( ),
builder: (BuildContext context) => const SearchWidget(),
),
);
},
); );
}, },
icon: const Icon(Icons.search), icon: const Icon(Icons.search),
@ -63,65 +59,59 @@ class _SearchWidgetState extends State<SearchWidget> {
child: Column( child: Column(
children: [ children: [
const SizedBox(height: 8), const SizedBox(height: 8),
Row( Container(
children: [ color: Theme.of(context).colorScheme.defaultBackgroundColor,
Flexible( child: TextFormField(
child: Container( style: Theme.of(context).textTheme.subtitle1,
color: Theme.of(context).colorScheme.defaultBackgroundColor, decoration: InputDecoration(
child: TextFormField( hintText: 'Search for albums, locations & files',
style: Theme.of(context).textTheme.subtitle1, filled: true,
decoration: InputDecoration( contentPadding: const EdgeInsets.symmetric(
hintText: 'Search for albums, locations & files', horizontal: 16,
filled: true, vertical: 14,
contentPadding: const EdgeInsets.symmetric( ),
horizontal: 16, border: UnderlineInputBorder(
vertical: 14, borderSide: BorderSide.none,
), borderRadius: BorderRadius.circular(8),
border: UnderlineInputBorder( ),
borderSide: BorderSide.none, focusedBorder: const UnderlineInputBorder(
borderRadius: BorderRadius.circular(8), borderSide: BorderSide.none,
), ),
focusedBorder: const UnderlineInputBorder( prefixIcon: Hero(
borderSide: BorderSide.none, tag: "search_icon",
), child: Icon(
prefixIcon: Hero( Icons.search,
tag: "search_icon", color: Theme.of(context)
child: Icon( .colorScheme
Icons.search, .iconColor
color: Theme.of(context) .withOpacity(0.5),
.colorScheme ),
.iconColor ),
.withOpacity(0.5), suffixIcon: IconButton(
), onPressed: () {
), Navigator.pop(context);
suffixIcon: IconButton( },
onPressed: () { icon: Icon(
Navigator.pop(context); Icons.close,
}, color: Theme.of(context)
icon: Icon( .colorScheme
Icons.close, .iconColor
color: Theme.of(context) .withOpacity(0.5),
.colorScheme
.iconColor
.withOpacity(0.5),
),
),
),
onChanged: (value) async {
final List<SearchResult> allResults =
await getSearchResultsForQuery(value);
if (mounted) {
setState(() {
results.clear();
results.addAll(allResults);
});
}
},
autofocus: true,
), ),
), ),
), ),
], onChanged: (value) async {
final List<SearchResult> allResults =
await getSearchResultsForQuery(value);
if (mounted) {
setState(() {
results.clear();
results.addAll(allResults);
});
}
},
autofocus: true,
),
), ),
results.isNotEmpty results.isNotEmpty
? SearchSuggestionsWidget(results) ? SearchSuggestionsWidget(results)