Merge pull request #419 from ente-io/search_improvements
Search improvements
This commit is contained in:
commit
f4d1c780f2
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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,
|
||||||
),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -29,8 +29,6 @@ class _SearchIconWidgetState extends State<SearchIconWidget> {
|
||||||
tag: "search_icon",
|
tag: "search_icon",
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(
|
|
||||||
() {
|
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
TransparentRoute(
|
TransparentRoute(
|
||||||
|
@ -38,8 +36,6 @@ class _SearchIconWidgetState extends State<SearchIconWidget> {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
|
||||||
},
|
|
||||||
icon: const Icon(Icons.search),
|
icon: const Icon(Icons.search),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -63,10 +59,7 @@ class _SearchWidgetState extends State<SearchWidget> {
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Row(
|
Container(
|
||||||
children: [
|
|
||||||
Flexible(
|
|
||||||
child: Container(
|
|
||||||
color: Theme.of(context).colorScheme.defaultBackgroundColor,
|
color: Theme.of(context).colorScheme.defaultBackgroundColor,
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
style: Theme.of(context).textTheme.subtitle1,
|
style: Theme.of(context).textTheme.subtitle1,
|
||||||
|
@ -120,9 +113,6 @@ class _SearchWidgetState extends State<SearchWidget> {
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
results.isNotEmpty
|
results.isNotEmpty
|
||||||
? SearchSuggestionsWidget(results)
|
? SearchSuggestionsWidget(results)
|
||||||
: const SizedBox.shrink(),
|
: const SizedBox.shrink(),
|
||||||
|
|
Loading…
Reference in a new issue