diff --git a/lib/db/files_db.dart b/lib/db/files_db.dart index 33b3f49aa..a34de3974 100644 --- a/lib/db/files_db.dart +++ b/lib/db/files_db.dart @@ -615,8 +615,9 @@ class FilesDB { Future> getFilesCreatedWithinDurations( List> durations, - Set ignoredCollectionIDs, - ) async { + Set ignoredCollectionIDs, { + String order = 'ASC', + }) async { final db = await instance.database; String whereClause = "( "; for (int index = 0; index < durations.length; index++) { @@ -633,7 +634,7 @@ class FilesDB { final results = await db.query( table, where: whereClause, - orderBy: '$columnCreationTime ASC', + orderBy: '$columnCreationTime ' + order, ); final files = _convertToFiles(results); return _deduplicatedAndFilterIgnoredFiles(files, ignoredCollectionIDs); diff --git a/lib/services/search_service.dart b/lib/services/search_service.dart index f943bc330..97f174009 100644 --- a/lib/services/search_service.dart +++ b/lib/services/search_service.dart @@ -149,6 +149,7 @@ class SearchService { [yearInMicroseconds, nextYearInMicroseconds] ], null, + order: 'DESC', ); return yearSearchResults; } diff --git a/lib/ui/huge_listview/draggable_scrollbar.dart b/lib/ui/huge_listview/draggable_scrollbar.dart index 9f940bc5e..b5e55570b 100644 --- a/lib/ui/huge_listview/draggable_scrollbar.dart +++ b/lib/ui/huge_listview/draggable_scrollbar.dart @@ -124,20 +124,22 @@ class DraggableScrollbarState extends State } } - Widget buildThumb() => Container( - alignment: Alignment.topRight, - margin: EdgeInsets.only(top: thumbOffset), + Widget buildThumb() => Padding( padding: widget.padding, - child: ScrollBarThumb( - widget.backgroundColor, - widget.drawColor, - widget.heightScrollThumb, - widget.labelTextBuilder.call(currentFirstIndex), - _labelAnimation, - _thumbAnimation, - onDragStart, - onDragUpdate, - onDragEnd, + child: Container( + alignment: Alignment.topRight, + margin: EdgeInsets.only(top: thumbOffset), + child: ScrollBarThumb( + widget.backgroundColor, + widget.drawColor, + widget.heightScrollThumb, + widget.labelTextBuilder.call(currentFirstIndex), + _labelAnimation, + _thumbAnimation, + onDragStart, + onDragUpdate, + onDragEnd, + ), ), ); diff --git a/lib/ui/huge_listview/huge_listview.dart b/lib/ui/huge_listview/huge_listview.dart index 13d4aa886..51f93bbe8 100644 --- a/lib/ui/huge_listview/huge_listview.dart +++ b/lib/ui/huge_listview/huge_listview.dart @@ -54,6 +54,8 @@ class HugeListView extends StatefulWidget { final bool isDraggableScrollbarEnabled; + final EdgeInsetsGeometry thumbPadding; + const HugeListView({ Key key, this.controller, @@ -69,6 +71,7 @@ class HugeListView extends StatefulWidget { this.thumbDrawColor = Colors.yellow, //Colors.grey, this.thumbHeight = 48.0, this.isDraggableScrollbarEnabled = true, + this.thumbPadding, }) : super(key: key); @override @@ -135,6 +138,7 @@ class HugeListViewState extends State> { heightScrollThumb: widget.thumbHeight, currentFirstIndex: _currentFirst(), isEnabled: widget.isDraggableScrollbarEnabled, + padding: widget.thumbPadding, child: ScrollablePositionedList.builder( itemScrollController: widget.controller, itemPositionsListener: listener, diff --git a/lib/ui/payment/subscription_page.dart b/lib/ui/payment/subscription_page.dart index f1e42bcb0..72de2d53f 100644 --- a/lib/ui/payment/subscription_page.dart +++ b/lib/ui/payment/subscription_page.dart @@ -72,16 +72,16 @@ class _SubscriptionPageState extends State { purchase.verificationData.serverVerificationData, ); await InAppPurchaseConnection.instance.completePurchase(purchase); - String text = "thank you for subscribing!"; + String text = "Thank you for subscribing!"; if (!widget.isOnboarding) { final isUpgrade = _hasActiveSubscription && newSubscription.storage > _currentSubscription.storage; final isDowngrade = _hasActiveSubscription && newSubscription.storage < _currentSubscription.storage; if (isUpgrade) { - text = "your plan was successfully upgraded"; + text = "Your plan was successfully upgraded"; } else if (isDowngrade) { - text = "your plan was successfully downgraded"; + text = "Your plan was successfully downgraded"; } } showToast(context, text); @@ -98,8 +98,8 @@ class _SubscriptionPageState extends State { await _dialog.hide(); showErrorDialog( context, - "payment failed", - "please talk to " + + "Payment failed", + "Please talk to " + (Platform.isAndroid ? "PlayStore" : "AppStore") + " support if you were charged", ); @@ -458,7 +458,7 @@ class _SubscriptionPageState extends State { if (_userDetails.subscription.productID == kFreeProductID) { await showErrorDialog( context, - "Now you can share your storage plan with your family members!", + "Share your storage plan with your family members!", "Customers on paid plans can add up to 5 family members without paying extra. Each member gets their own private space.", ); return; diff --git a/lib/ui/viewer/gallery/gallery.dart b/lib/ui/viewer/gallery/gallery.dart index 2998cc8b5..7b9947e2b 100644 --- a/lib/ui/viewer/gallery/gallery.dart +++ b/lib/ui/viewer/gallery/gallery.dart @@ -234,6 +234,9 @@ class _GalleryState extends State { thumbBackgroundColor: Theme.of(context).colorScheme.galleryThumbBackgroundColor, thumbDrawColor: Theme.of(context).colorScheme.galleryThumbDrawColor, + thumbPadding: widget.header != null + ? const EdgeInsets.only(top: 60) + : const EdgeInsets.all(0), firstShown: (int firstIndex) { Bus.instance .fire(GalleryIndexUpdatedEvent(widget.tagPrefix, firstIndex)); diff --git a/lib/ui/viewer/search/search_result_widgets/collection_result_widget.dart b/lib/ui/viewer/search/search_result_widgets/collection_result_widget.dart index 4eff878f1..217e0293e 100644 --- a/lib/ui/viewer/search/search_result_widgets/collection_result_widget.dart +++ b/lib/ui/viewer/search/search_result_widgets/collection_result_widget.dart @@ -40,10 +40,13 @@ class AlbumSearchResultWidget extends StatelessWidget { ), ), const SizedBox(height: 4), - Text( - albumSearchResult.collectionWithThumbnail.collection.name, - style: const TextStyle(fontSize: 18), - overflow: TextOverflow.ellipsis, + SizedBox( + width: 220, + child: Text( + albumSearchResult.collectionWithThumbnail.collection.name, + style: const TextStyle(fontSize: 18), + overflow: TextOverflow.ellipsis, + ), ), const SizedBox(height: 2), FutureBuilder( @@ -92,7 +95,6 @@ class AlbumSearchResultWidget extends StatelessWidget { albumSearchResult.collectionWithThumbnail, tagPrefix: "collection_search", ), - forceCustomPageRoute: true, ); }, ); diff --git a/lib/ui/viewer/search/search_result_widgets/file_result_widget.dart b/lib/ui/viewer/search/search_result_widgets/file_result_widget.dart index 7db77c36e..967ade41c 100644 --- a/lib/ui/viewer/search/search_result_widgets/file_result_widget.dart +++ b/lib/ui/viewer/search/search_result_widgets/file_result_widget.dart @@ -72,6 +72,6 @@ class FileSearchResultWidget extends StatelessWidget { "file_details", ), ); - routeToPage(context, page, forceCustomPageRoute: true); + routeToPage(context, page); } } diff --git a/lib/ui/viewer/search/search_result_widgets/location_result_widget.dart b/lib/ui/viewer/search/search_result_widgets/location_result_widget.dart index 3ce199dc3..b68d8f8c2 100644 --- a/lib/ui/viewer/search/search_result_widgets/location_result_widget.dart +++ b/lib/ui/viewer/search/search_result_widgets/location_result_widget.dart @@ -43,10 +43,13 @@ class LocationSearchResultWidget extends StatelessWidget { ), ), const SizedBox(height: 6), - Text( - locationSearchResult.location, - style: const TextStyle(fontSize: 18), - overflow: TextOverflow.ellipsis, + SizedBox( + width: 220, + child: Text( + locationSearchResult.location, + style: const TextStyle(fontSize: 18), + overflow: TextOverflow.ellipsis, + ), ), const SizedBox(height: 2), RichText( @@ -79,7 +82,6 @@ class LocationSearchResultWidget extends StatelessWidget { routeToPage( context, FilesInLocationPage(locationSearchResult, heroTagPrefix), - forceCustomPageRoute: true, ); }, ); diff --git a/lib/ui/viewer/search/search_result_widgets/no_result_widget.dart b/lib/ui/viewer/search/search_result_widgets/no_result_widget.dart new file mode 100644 index 000000000..fe18cee5f --- /dev/null +++ b/lib/ui/viewer/search/search_result_widgets/no_result_widget.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; +import 'package:photos/ente_theme_data.dart'; + +class NoResultWidget extends StatelessWidget { + const NoResultWidget({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + width: double.infinity, + margin: const EdgeInsets.only(top: 8), + padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 12), + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.searchResultsColor, + borderRadius: BorderRadius.circular(8), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.2), + spreadRadius: -3, + blurRadius: 6, + offset: const Offset(0, 8), + ), + ], + ), + child: Column( + children: [ + const Text("Sorry, no results found"), + const SizedBox( + height: 12, + ), + Text( + "Try expanding your query", + style: TextStyle( + fontSize: 14, + color: Theme.of(context).colorScheme.subTextColor, + ), + ), + ], + ), + ); + } +} diff --git a/lib/ui/viewer/search/search_result_widgets/year_result_widget.dart b/lib/ui/viewer/search/search_result_widgets/year_result_widget.dart index 21de7ae76..a39b6324e 100644 --- a/lib/ui/viewer/search/search_result_widgets/year_result_widget.dart +++ b/lib/ui/viewer/search/search_result_widgets/year_result_widget.dart @@ -41,7 +41,7 @@ class YearSearchResultWidget extends StatelessWidget { color: Theme.of(context).colorScheme.subTextColor, ), ), - const SizedBox(height: 8), + const SizedBox(height: 6), Text( yearSearchResult.year.toString(), style: const TextStyle(fontSize: 18), @@ -78,7 +78,6 @@ class YearSearchResultWidget extends StatelessWidget { routeToPage( context, FilesFromYearPage(yearSearchResult, heroTagPrefix), - forceCustomPageRoute: true, ); }, ); diff --git a/lib/ui/viewer/search/search_suggestions.dart b/lib/ui/viewer/search/search_suggestions.dart index b28d81422..f98170378 100644 --- a/lib/ui/viewer/search/search_suggestions.dart +++ b/lib/ui/viewer/search/search_suggestions.dart @@ -39,35 +39,37 @@ class SearchSuggestionsWidget extends StatelessWidget { borderRadius: const BorderRadius.all(Radius.circular(8)), child: Container( margin: const EdgeInsets.only(top: 6), - constraints: BoxConstraints( - maxHeight: MediaQuery.of(context).size.height * 0.5, + constraints: const BoxConstraints( + maxHeight: 324, ), - child: ListView.builder( - physics: const ClampingScrollPhysics(), - shrinkWrap: true, - itemCount: results.length + 1, - itemBuilder: (context, index) { - if (results.length == index) { - return Container( - height: 6, - color: Theme.of(context).colorScheme.searchResultsColor, - ); - } - final result = results[index]; - if (result is AlbumSearchResult) { - return AlbumSearchResultWidget(result); - } else if (result is LocationSearchResult) { - 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"); - return const SizedBox.shrink(); - } - }, + child: Scrollbar( + child: ListView.builder( + physics: const ClampingScrollPhysics(), + shrinkWrap: true, + itemCount: results.length + 1, + itemBuilder: (context, index) { + if (results.length == index) { + return Container( + height: 6, + color: Theme.of(context).colorScheme.searchResultsColor, + ); + } + final result = results[index]; + if (result is AlbumSearchResult) { + return AlbumSearchResultWidget(result); + } else if (result is LocationSearchResult) { + 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"); + return const SizedBox.shrink(); + } + }, + ), ), ), ), diff --git a/lib/ui/viewer/search/search_widget.dart b/lib/ui/viewer/search/search_widget.dart index c56c2cf96..efb667919 100644 --- a/lib/ui/viewer/search/search_widget.dart +++ b/lib/ui/viewer/search/search_widget.dart @@ -1,13 +1,12 @@ import 'package:flutter/material.dart'; import 'package:photos/ente_theme_data.dart'; import 'package:photos/models/collection_items.dart'; -import 'package:photos/models/file.dart'; 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_result_widgets/no_result_widget.dart'; import 'package:photos/ui/viewer/search/search_suggestions.dart'; import 'package:photos/utils/navigation_util.dart'; @@ -44,14 +43,15 @@ class _SearchIconWidgetState extends State { } class SearchWidget extends StatefulWidget { - final String searchQuery = ''; const SearchWidget({Key key}) : super(key: key); @override State createState() => _SearchWidgetState(); } class _SearchWidgetState extends State { - final List results = []; + String _query = ""; + final List _results = []; + @override Widget build(BuildContext context) { return SafeArea( @@ -64,6 +64,11 @@ class _SearchWidgetState extends State { color: Theme.of(context).colorScheme.defaultBackgroundColor, child: TextFormField( style: Theme.of(context).textTheme.subtitle1, + // Below parameters are to disable auto-suggestion + enableSuggestions: false, + autocorrect: false, + keyboardType: TextInputType.visiblePassword, + // Above parameters are to disable auto-suggestion decoration: InputDecoration( hintText: 'Search for albums, places & files', filled: true, @@ -106,17 +111,20 @@ class _SearchWidgetState extends State { await getSearchResultsForQuery(value); if (mounted) { setState(() { - results.clear(); - results.addAll(allResults); + _query = value; + _results.clear(); + _results.addAll(allResults); }); } }, autofocus: true, ), ), - results.isNotEmpty - ? SearchSuggestionsWidget(results) - : const SizedBox.shrink(), + _results.isNotEmpty + ? SearchSuggestionsWidget(_results) + : _query.isNotEmpty + ? const NoResultWidget() + : const SizedBox.shrink(), ], ), ), @@ -146,11 +154,6 @@ class _SearchWidgetState extends State { 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; } diff --git a/lib/utils/navigation_util.dart b/lib/utils/navigation_util.dart index abd30b14f..76e7fce7c 100644 --- a/lib/utils/navigation_util.dart +++ b/lib/utils/navigation_util.dart @@ -13,8 +13,8 @@ Future routeToPage( ); } else { return Navigator.of(context).push( - MaterialPageRoute( - builder: (BuildContext context) { + SwipeableRouteBuilder( + pageBuilder: (context, animation, secondaryAnimation) { return page; }, ), @@ -55,6 +55,57 @@ PageRouteBuilder _buildPageRoute(Widget page) { ); } +class SwipeableRouteBuilder extends PageRoute { + final RoutePageBuilder pageBuilder; + final PageTransitionsBuilder matchingBuilder = + const CupertinoPageTransitionsBuilder(); // Default iOS/macOS (to get the swipe right to go back gesture) + // final PageTransitionsBuilder matchingBuilder = const FadeUpwardsPageTransitionsBuilder(); // Default Android/Linux/Windows + + SwipeableRouteBuilder({this.pageBuilder}); + + @override + Color get barrierColor => null; + + @override + String get barrierLabel => null; + + @override + Widget buildPage( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + ) { + return pageBuilder(context, animation, secondaryAnimation); + } + + @override + bool get maintainState => true; + + @override + Duration get transitionDuration => const Duration( + milliseconds: 300, + ); // Can give custom Duration, unlike in MaterialPageRoute + + @override + Widget buildTransitions( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + Widget child, + ) { + return matchingBuilder.buildTransitions( + this, + context, + animation, + secondaryAnimation, + child, + ); + } + + @override + bool get opaque => false; +} + class TransparentRoute extends PageRoute { TransparentRoute({ @required this.builder, diff --git a/pubspec.yaml b/pubspec.yaml index 7a3a6a6d6..7aac518ae 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,7 +11,7 @@ description: ente photos application # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 0.6.23+353 +version: 0.6.24+354 environment: sdk: ">=2.10.0 <3.0.0"