From d4a545ad2adcdcede4212e17b703243344f27245 Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Thu, 19 May 2022 11:51:13 +0900 Subject: [PATCH] fixes: nav bar scroll & highlight + minor --- lib/widgets/about/bug_report.dart | 29 +++---------- lib/widgets/collection/collection_page.dart | 24 +++++++---- lib/widgets/navigation/nav_bar/floating.dart | 41 ++++--------------- lib/widgets/navigation/nav_bar/nav_bar.dart | 22 +++++++--- plugins/aves_services_google/lib/src/map.dart | 1 + pubspec.lock | 30 +++++++------- 6 files changed, 63 insertions(+), 84 deletions(-) diff --git a/lib/widgets/about/bug_report.dart b/lib/widgets/about/bug_report.dart index ff0bdd285..1dff3e106 100644 --- a/lib/widgets/about/bug_report.dart +++ b/lib/widgets/about/bug_report.dart @@ -32,7 +32,6 @@ class BugReport extends StatefulWidget { } class _BugReportState extends State with FeedbackMixin { - final ScrollController _infoScrollController = ScrollController(); late Future _infoLoader; bool _showInstructions = false; @@ -90,28 +89,12 @@ class _BugReportState extends State with FeedbackMixin { constraints: const BoxConstraints(maxHeight: 100), margin: const EdgeInsets.symmetric(vertical: 8), clipBehavior: Clip.antiAlias, - child: Theme( - data: Theme.of(context).copyWith( - scrollbarTheme: ScrollbarThemeData( - thumbVisibility: MaterialStateProperty.all(true), - radius: const Radius.circular(16), - crossAxisMargin: 6, - mainAxisMargin: 6, - interactive: true, - ), - ), - child: Scrollbar( - // when using `Scrollbar.isAlwaysShown`, a controller must be provided - // and used by both the `Scrollbar` and the `Scrollable`, but - // as of Flutter v2.8.1, `SelectableText` does not allow passing the `scrollController` - // so we wrap it in a `SingleChildScrollView` - controller: _infoScrollController, - child: SingleChildScrollView( - padding: const EdgeInsetsDirectional.only(start: 8, top: 4, end: 16, bottom: 4), - controller: _infoScrollController, - child: SelectableText(info), - ), - ), + child: SingleChildScrollView( + padding: const EdgeInsetsDirectional.only(start: 8, top: 4, end: 16, bottom: 4), + // to show a scroll bar, we would need to provide a scroll controller + // to both the `Scrollable` and the `Scrollbar`, but + // as of Flutter v3.0.0, `SelectableText` does not allow passing the `scrollController` + child: SelectableText(info), ), ); }, diff --git a/lib/widgets/collection/collection_page.dart b/lib/widgets/collection/collection_page.dart index 12a83d967..d36b14166 100644 --- a/lib/widgets/collection/collection_page.dart +++ b/lib/widgets/collection/collection_page.dart @@ -127,14 +127,22 @@ class _CollectionPageState extends State { ), ), floatingActionButton: appMode == AppMode.pickMultipleMediaExternal && hasSelection - ? FloatingActionButton( - tooltip: context.l10n.collectionPickPageTitle, - onPressed: () { - final items = context.read>().selectedItems; - final uris = items.map((entry) => entry.uri).toList(); - ViewerService.pick(uris); - }, - child: const Icon(AIcons.apply), + ? TooltipTheme( + data: TooltipTheme.of(context).copyWith( + preferBelow: false, + ), + child: FloatingActionButton( + tooltip: context.l10n.collectionPickPageTitle, + onPressed: () { + final items = context.read>().selectedItems; + final uris = items.map((entry) => entry.uri).toList(); + ViewerService.pick(uris); + }, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(16)), + ), + child: const Icon(AIcons.apply), + ), ) : null, drawer: AppDrawer(currentCollection: _collection), diff --git a/lib/widgets/navigation/nav_bar/floating.dart b/lib/widgets/navigation/nav_bar/floating.dart index b13387dbc..661568727 100644 --- a/lib/widgets/navigation/nav_bar/floating.dart +++ b/lib/widgets/navigation/nav_bar/floating.dart @@ -3,7 +3,6 @@ import 'dart:math'; import 'package:aves/widgets/common/basic/draggable_scrollbar.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; class FloatingNavBar extends StatefulWidget { final ScrollController? scrollController; @@ -28,11 +27,8 @@ class _FloatingNavBarState extends State with SingleTickerProvid late AnimationController _controller; late Animation _offsetAnimation; double? _lastOffset; - double _delta = 0; bool _isDragging = false; - static const double _deltaThreshold = 50; - @override void initState() { super.initState(); @@ -73,7 +69,6 @@ class _FloatingNavBarState extends State with SingleTickerProvid void _registerWidget(FloatingNavBar widget) { _lastOffset = null; - _delta = 0; widget.scrollController?.addListener(_onScrollChange); _subscriptions.add(widget.events.listen(_onDraggableScrollBarEvent)); } @@ -98,25 +93,19 @@ class _FloatingNavBarState extends State with SingleTickerProvid if (scrollController == null) return; final offset = scrollController.offset; - _delta += offset - (_lastOffset ?? offset); + final delta = offset - (_lastOffset ?? offset); _lastOffset = offset; - if (_isDragging) return; - - final after = scrollController.position.extentAfter; + double? newValue; final childHeight = widget.childHeight; - if (after < childHeight && scrollController.position.userScrollDirection == ScrollDirection.reverse) { - _controller.value = min(_controller.value, after / childHeight); - _delta = 0; - return; + final after = scrollController.position.extentAfter; + if (after < childHeight && delta > 0) { + newValue = min(_controller.value, after / childHeight); + } else if (!_isDragging || delta > 0) { + newValue = _controller.value + delta / childHeight; } - - if (_delta.abs() > _deltaThreshold) { - if (_delta > 0) { - _hide(); - } else { - _show(); - } + if (newValue != null) { + _controller.value = newValue.clamp(0.0, 1.0); } } @@ -124,22 +113,10 @@ class _FloatingNavBarState extends State with SingleTickerProvid switch (event) { case DraggableScrollBarEvent.dragStart: _isDragging = true; - _hide(); break; case DraggableScrollBarEvent.dragEnd: _isDragging = false; - _show(); break; } } - - void _show() { - _controller.reverse(); - _delta = 0; - } - - void _hide() { - _controller.forward(); - _delta = 0; - } } diff --git a/lib/widgets/navigation/nav_bar/nav_bar.dart b/lib/widgets/navigation/nav_bar/nav_bar.dart index ac638cbd9..904c720ae 100644 --- a/lib/widgets/navigation/nav_bar/nav_bar.dart +++ b/lib/widgets/navigation/nav_bar/nav_bar.dart @@ -15,19 +15,26 @@ import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -class AppBottomNavBar extends StatelessWidget { +class AppBottomNavBar extends StatefulWidget { final Stream events; // collection loaded in the `CollectionPage`, if any final CollectionLens? currentCollection; + static double get height => kBottomNavigationBarHeight + AvesFloatingBar.margin.vertical; + const AppBottomNavBar({ super.key, required this.events, this.currentCollection, }); - static double get height => kBottomNavigationBarHeight + AvesFloatingBar.margin.vertical; + @override + State createState() => _AppBottomNavBarState(); +} + +class _AppBottomNavBarState extends State { + String? _lastRoute; @override Widget build(BuildContext context) { @@ -68,8 +75,8 @@ class AppBottomNavBar extends StatelessWidget { }, child: FloatingNavBar( scrollController: PrimaryScrollController.of(context), - events: events, - childHeight: height + context.select((mq) => mq.effectiveBottomPadding), + events: widget.events, + childHeight: AppBottomNavBar.height + context.select((mq) => mq.effectiveBottomPadding), child: SafeArea( child: child, ), @@ -78,13 +85,16 @@ class AppBottomNavBar extends StatelessWidget { } int _getCurrentIndex(BuildContext context, List items) { - final currentRoute = context.currentRouteName; + // current route may be null during navigation + final currentRoute = context.currentRouteName ?? _lastRoute; + _lastRoute = currentRoute; + final currentItem = items.firstWhereOrNull((item) { if (currentRoute != item.route) return false; if (item.route != CollectionPage.routeName) return true; - final currentFilters = currentCollection?.filters; + final currentFilters = widget.currentCollection?.filters; if (currentFilters == null || currentFilters.length > 1) return false; return currentFilters.firstOrNull == item.filter; }); diff --git a/plugins/aves_services_google/lib/src/map.dart b/plugins/aves_services_google/lib/src/map.dart index 36822557e..173ee16d3 100644 --- a/plugins/aves_services_google/lib/src/map.dart +++ b/plugins/aves_services_google/lib/src/map.dart @@ -203,6 +203,7 @@ class _EntryGoogleMapState extends State> with WidgetsBindi myLocationEnabled: false, myLocationButtonEnabled: false, markers: { + // TODO TLAD workaround for dot location marker not showing the last value until this is fixed: https://github.com/flutter/flutter/issues/103686 ...markers, if (dotLocation != null && _dotMarkerBitmap != null) Marker( diff --git a/pubspec.lock b/pubspec.lock index d66d21fa0..106549366 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,14 +7,14 @@ packages: name: _fe_analyzer_shared url: "https://pub.dartlang.org" source: hosted - version: "39.0.0" + version: "40.0.0" analyzer: dependency: transitive description: name: analyzer url: "https://pub.dartlang.org" source: hosted - version: "4.0.0" + version: "4.1.0" archive: dependency: transitive description: @@ -296,7 +296,7 @@ packages: name: ffi url: "https://pub.dartlang.org" source: hosted - version: "1.1.2" + version: "1.2.1" fijkplayer: dependency: "direct main" description: @@ -319,35 +319,35 @@ packages: name: firebase_core url: "https://pub.dartlang.org" source: hosted - version: "1.16.0" + version: "1.17.0" firebase_core_platform_interface: dependency: transitive description: name: firebase_core_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "4.3.0" + version: "4.4.0" firebase_core_web: dependency: transitive description: name: firebase_core_web url: "https://pub.dartlang.org" source: hosted - version: "1.6.3" + version: "1.6.4" firebase_crashlytics: dependency: transitive description: name: firebase_crashlytics url: "https://pub.dartlang.org" source: hosted - version: "2.7.2" + version: "2.8.0" firebase_crashlytics_platform_interface: dependency: transitive description: name: firebase_crashlytics_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "3.2.5" + version: "3.2.6" flex_color_picker: dependency: "direct main" description: @@ -449,7 +449,7 @@ packages: name: frontend_server_client url: "https://pub.dartlang.org" source: hosted - version: "2.1.2" + version: "2.1.3" fuchsia_remote_debug_protocol: dependency: transitive description: flutter @@ -517,7 +517,7 @@ packages: name: http_parser url: "https://pub.dartlang.org" source: hosted - version: "4.0.0" + version: "4.0.1" image: dependency: transitive description: @@ -657,7 +657,7 @@ packages: name: overlay_support url: "https://pub.dartlang.org" source: hosted - version: "1.2.1" + version: "2.0.0" package_config: dependency: transitive description: @@ -769,7 +769,7 @@ packages: name: percent_indicator url: "https://pub.dartlang.org" source: hosted - version: "4.0.1" + version: "4.2.2" permission_handler: dependency: "direct main" description: @@ -1259,7 +1259,7 @@ packages: name: win32 url: "https://pub.dartlang.org" source: hosted - version: "2.5.2" + version: "2.6.1" wkt_parser: dependency: transitive description: @@ -1287,7 +1287,7 @@ packages: name: yaml url: "https://pub.dartlang.org" source: hosted - version: "3.1.0" + version: "3.1.1" sdks: dart: ">=2.17.0 <3.0.0" - flutter: ">=2.10.0" + flutter: ">=2.12.0"