diff --git a/lib/models/discoverable_feature.dart b/lib/models/discoverable_feature.dart index 5acbf15b..b192e700 100644 --- a/lib/models/discoverable_feature.dart +++ b/lib/models/discoverable_feature.dart @@ -7,31 +7,38 @@ enum DiscoverableFeature { settingsShortcutOnItemScreen( featureId: 'settings_shortcut_on_item_screen', title: 'Go to Settings', - description: '''You can now go to settings page directly from a thread.''', + description: '''Tap to adjust thread appearance in Settings.''', ), login( featureId: 'log_in', title: 'Log in for more', description: - '''Log in using your Hacker News account to check out stories and comments you have posted in the past, and get in-app notification when there is new reply to your comments or stories.''', + '''Log in with your Hacker News account to view your past stories and comments and receive in-app notifications when someone replies to them.''', ), pinToTop( featureId: 'pin_to_top', title: 'Pin a Story', - description: - '''Pin this story to the top of your home screen so that you can come back later.''', + description: '''Pin this story to the top of your home screen.''', ), jumpUpButton( featureId: 'jump_up_button_with_long_press', title: 'Shortcut', - description: - '''Tapping on this button will take you to the previous root level comment.\n\nLong press on it to jump to the very beginning of this thread.''', + description: ''' +Tap this button to go to the previous root-level comment. + +Long press to jump to the beginning of the thread. + +Drag to move the button around.''', ), jumpDownButton( featureId: 'jump_down_button_with_long_press', title: 'Shortcut', - description: - '''Tapping on this button will take you to the next root level comment.\n\nLong press on it to jump to the end of this thread.''', + description: ''' +Tap this button to go to the next root-level comment. + +Long press to jump to the end of the thread. + +Drag to move the button around.''', ), searchInThread( featureId: 'search_in_thread', diff --git a/lib/screens/item/widgets/more_popup_menu.dart b/lib/screens/item/widgets/more_popup_menu.dart index a76242f9..1381ad81 100644 --- a/lib/screens/item/widgets/more_popup_menu.dart +++ b/lib/screens/item/widgets/more_popup_menu.dart @@ -274,17 +274,21 @@ class MorePopupMenu extends StatelessWidget { isScrollControlled: true, showDragHandle: true, builder: (BuildContext context) { - return BlocProvider( - create: (_) => - SearchCubit()..addFilter(PostedByFilter(author: item.by)), - child: SizedBox( - height: MediaQuery.of(context).size.height - Dimens.pt120, - child: const Column( - children: [ - Expanded(child: SearchScreen(isInBottomSheet: true)), - ], - ), - ), + return DraggableScrollableSheet( + expand: false, + initialChildSize: 0.9, + maxChildSize: 0.9, + minChildSize: 0.7, + builder: (BuildContext context, ScrollController scrollController) { + return BlocProvider( + create: (_) => + SearchCubit()..addFilter(PostedByFilter(author: item.by)), + child: SearchScreen( + isInBottomSheet: true, + scrollController: scrollController, + ), + ); + }, ); }, ); diff --git a/lib/screens/item/widgets/time_machine_dialog.dart b/lib/screens/item/widgets/time_machine_dialog.dart index 2b8eba15..3c192900 100644 --- a/lib/screens/item/widgets/time_machine_dialog.dart +++ b/lib/screens/item/widgets/time_machine_dialog.dart @@ -58,6 +58,7 @@ class TimeMachineDialog extends StatelessWidget { Expanded( child: ListView( controller: scrollController, + physics: const ClampingScrollPhysics(), children: [ switch (rootItem) { Story() => StoryTile( diff --git a/lib/screens/search/search_screen.dart b/lib/screens/search/search_screen.dart index f04a537b..9f3dda16 100644 --- a/lib/screens/search/search_screen.dart +++ b/lib/screens/search/search_screen.dart @@ -14,12 +14,20 @@ import 'package:pull_to_refresh/pull_to_refresh.dart'; import 'package:scrolls_to_top/scrolls_to_top.dart'; class SearchScreen extends StatefulWidget { - const SearchScreen({super.key, this.isInBottomSheet = false}); + const SearchScreen({ + super.key, + this.isInBottomSheet = false, + this.scrollController, + }) : assert( + !isInBottomSheet || scrollController != null, + '''ScrollController should be assigned when search screen is presented inside a sheet.''', + ); /// If user is viewing [SearchScreen] in bottom sheet, /// we navigate to [ItemScreen] directly instead of injecting the /// item into [SplitViewCubit]. final bool isInBottomSheet; + final ScrollController? scrollController; @override _SearchScreenState createState() => _SearchScreenState(); @@ -27,7 +35,7 @@ class SearchScreen extends StatefulWidget { class _SearchScreenState extends State with ItemActionMixin { final RefreshController refreshController = RefreshController(); - final ScrollController scrollController = ScrollController(); + late final ScrollController scrollController; final FocusNode focusNode = FocusNode(); final Debouncer debouncer = Debouncer(delay: AppDurations.oneSecond); @@ -36,13 +44,22 @@ class _SearchScreenState extends State with ItemActionMixin { @override void initState() { super.initState(); + scrollController = widget.scrollController ?? ScrollController(); scrollController.addListener(onScroll); } @override void dispose() { + scrollController.removeListener(onScroll); + + /// Do not dispose the scroll controller if it is being passed in from + /// the builder func of draggable scrollable sheet. It will be disposed + /// by the sheet. + if (!widget.isInBottomSheet) { + scrollController.dispose(); + } + refreshController.dispose(); - scrollController.dispose(); focusNode ..unfocus() ..dispose(); @@ -71,6 +88,7 @@ class _SearchScreenState extends State with ItemActionMixin { children: [ Expanded( child: SmartRefresher( + physics: const ClampingScrollPhysics(), scrollController: scrollController, enablePullDown: false, enablePullUp: true, @@ -108,7 +126,7 @@ class _SearchScreenState extends State with ItemActionMixin { child: ListView( physics: state.results.isEmpty ? const NeverScrollableScrollPhysics() - : null, + : const ClampingScrollPhysics(), children: [ Column( children: [ diff --git a/lib/screens/widgets/onboarding_view.dart b/lib/screens/widgets/onboarding_view.dart index bd4e4fc0..78c5c634 100644 --- a/lib/screens/widgets/onboarding_view.dart +++ b/lib/screens/widgets/onboarding_view.dart @@ -48,18 +48,17 @@ class _OnboardingViewState extends State { children: const [ _PageViewChild( path: Constants.commentTileRightSlidePath, - description: - '''Swipe right to leave a comment, vote, and more.''', + description: '''Swipe right to reply, vote, and more.''', ), _PageViewChild( path: Constants.commentTileLeftSlidePath, description: - '''Swipe left to view all the ancestor comments.''', + '''Swipe left to view all ancestor comments.''', ), _PageViewChild( path: Constants.commentTileTopTapPath, description: - '''Tap on anywhere inside a comment tile to collapse. Long press any link to copy.''', + '''Tap anywhere on a comment to collapse it. Long press any link to copy it.''', ), ], ), diff --git a/lib/services/dialog_proxy.dart b/lib/services/dialog_proxy.dart index 1930d55c..6c7df018 100644 --- a/lib/services/dialog_proxy.dart +++ b/lib/services/dialog_proxy.dart @@ -41,16 +41,20 @@ abstract final class DialogProxy { isScrollControlled: true, showDragHandle: true, builder: (BuildContext context) { - return BlocProvider( - create: (_) => SearchCubit()..search(text), - child: SizedBox( - height: MediaQuery.of(context).size.height - Dimens.pt120, - child: const Column( - children: [ - Expanded(child: SearchScreen(isInBottomSheet: true)), - ], - ), - ), + return DraggableScrollableSheet( + expand: false, + initialChildSize: 0.9, + maxChildSize: 0.9, + minChildSize: 0.7, + builder: (BuildContext context, ScrollController scrollController) { + return BlocProvider( + create: (_) => SearchCubit()..search(text), + child: SearchScreen( + isInBottomSheet: true, + scrollController: scrollController, + ), + ); + }, ); }, ); @@ -72,7 +76,7 @@ abstract final class DialogProxy { expand: false, initialChildSize: 0.9, maxChildSize: 0.9, - minChildSize: 0.85, + minChildSize: 0.7, builder: (BuildContext context, ScrollController scrollController) { return TimeMachineDialog( comment: comment,