fix: get scrubber in search view working (#22175)

* feat: add option to disable snapping

* handle offset when there is no appbar
This commit is contained in:
Alex 2025-09-19 00:20:09 -05:00 committed by GitHub
parent de897f6069
commit 642065f506
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 36 additions and 8 deletions

View File

@ -633,7 +633,7 @@ class _SearchResultGrid extends ConsumerWidget {
groupBy: GroupAssetsBy.none, groupBy: GroupAssetsBy.none,
appBar: null, appBar: null,
bottomSheet: const GeneralBottomSheet(minChildSize: 0.20), bottomSheet: const GeneralBottomSheet(minChildSize: 0.20),
withScrubber: false, snapToMonth: false,
), ),
), ),
), ),

View File

@ -31,6 +31,11 @@ class Scrubber extends ConsumerStatefulWidget {
final double? monthSegmentSnappingOffset; final double? monthSegmentSnappingOffset;
final bool snapToMonth;
/// Whether an app bar is present, affects coordinate calculations
final bool hasAppBar;
Scrubber({ Scrubber({
super.key, super.key,
Key? scrollThumbKey, Key? scrollThumbKey,
@ -39,6 +44,8 @@ class Scrubber extends ConsumerStatefulWidget {
this.topPadding = 0, this.topPadding = 0,
this.bottomPadding = 0, this.bottomPadding = 0,
this.monthSegmentSnappingOffset, this.monthSegmentSnappingOffset,
this.snapToMonth = true,
this.hasAppBar = true,
required this.child, required this.child,
}) : assert(child.scrollDirection == Axis.vertical); }) : assert(child.scrollDirection == Axis.vertical);
@ -232,7 +239,7 @@ class ScrubberState extends ConsumerState<Scrubber> with TickerProviderStateMixi
} }
} }
if (_monthCount < kMinMonthsToEnableScrubberSnap) { if (_monthCount < kMinMonthsToEnableScrubberSnap || !widget.snapToMonth) {
// If there are less than kMinMonthsToEnableScrubberSnap months, we don't need to snap to segments // If there are less than kMinMonthsToEnableScrubberSnap months, we don't need to snap to segments
setState(() { setState(() {
_thumbTopOffset = dragPosition; _thumbTopOffset = dragPosition;
@ -259,6 +266,7 @@ class ScrubberState extends ConsumerState<Scrubber> with TickerProviderStateMixi
/// - If user drags to global Y position that's 100 pixels from the top /// - If user drags to global Y position that's 100 pixels from the top
/// - The relative position would be 100 - 50 = 50 (50 pixels into the scrubber area) /// - The relative position would be 100 - 50 = 50 (50 pixels into the scrubber area)
double _calculateDragPosition(DragUpdateDetails details) { double _calculateDragPosition(DragUpdateDetails details) {
if (widget.hasAppBar) {
final dragAreaTop = widget.topPadding; final dragAreaTop = widget.topPadding;
final dragAreaBottom = widget.timelineHeight - widget.bottomPadding; final dragAreaBottom = widget.timelineHeight - widget.bottomPadding;
final dragAreaHeight = dragAreaBottom - dragAreaTop; final dragAreaHeight = dragAreaBottom - dragAreaTop;
@ -269,6 +277,19 @@ class ScrubberState extends ConsumerState<Scrubber> with TickerProviderStateMixi
return relativePosition.clamp(0.0, dragAreaHeight); return relativePosition.clamp(0.0, dragAreaHeight);
} }
// Get the local position relative to the gesture detector
final RenderBox? renderBox = context.findRenderObject() as RenderBox?;
if (renderBox != null) {
final localPosition = renderBox.globalToLocal(details.globalPosition);
return localPosition.dy.clamp(0.0, _scrubberHeight);
}
// Fallback to current logic if render box is not available
final dragAreaTop = widget.topPadding;
final relativePosition = details.globalPosition.dy - dragAreaTop;
return relativePosition.clamp(0.0, _scrubberHeight);
}
/// Find the segment closest to the given position /// Find the segment closest to the given position
_Segment? _findNearestMonthSegment(double position) { _Segment? _findNearestMonthSegment(double position) {
_Segment? nearestSegment; _Segment? nearestSegment;

View File

@ -38,6 +38,7 @@ class Timeline extends StatelessWidget {
this.bottomSheet = const GeneralBottomSheet(minChildSize: 0.18), this.bottomSheet = const GeneralBottomSheet(minChildSize: 0.18),
this.groupBy, this.groupBy,
this.withScrubber = true, this.withScrubber = true,
this.snapToMonth = true,
}); });
final Widget? topSliverWidget; final Widget? topSliverWidget;
@ -48,6 +49,7 @@ class Timeline extends StatelessWidget {
final bool withStack; final bool withStack;
final GroupAssetsBy? groupBy; final GroupAssetsBy? groupBy;
final bool withScrubber; final bool withScrubber;
final bool snapToMonth;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -73,6 +75,7 @@ class Timeline extends StatelessWidget {
appBar: appBar, appBar: appBar,
bottomSheet: bottomSheet, bottomSheet: bottomSheet,
withScrubber: withScrubber, withScrubber: withScrubber,
snapToMonth: snapToMonth,
), ),
), ),
), ),
@ -87,6 +90,7 @@ class _SliverTimeline extends ConsumerStatefulWidget {
this.appBar, this.appBar,
this.bottomSheet, this.bottomSheet,
this.withScrubber = true, this.withScrubber = true,
this.snapToMonth = true,
}); });
final Widget? topSliverWidget; final Widget? topSliverWidget;
@ -94,6 +98,7 @@ class _SliverTimeline extends ConsumerStatefulWidget {
final Widget? appBar; final Widget? appBar;
final Widget? bottomSheet; final Widget? bottomSheet;
final bool withScrubber; final bool withScrubber;
final bool snapToMonth;
@override @override
ConsumerState createState() => _SliverTimelineState(); ConsumerState createState() => _SliverTimelineState();
@ -309,11 +314,13 @@ class _SliverTimelineState extends ConsumerState<_SliverTimeline> {
final Widget timeline; final Widget timeline;
if (widget.withScrubber) { if (widget.withScrubber) {
timeline = Scrubber( timeline = Scrubber(
snapToMonth: widget.snapToMonth,
layoutSegments: segments, layoutSegments: segments,
timelineHeight: maxHeight, timelineHeight: maxHeight,
topPadding: topPadding, topPadding: topPadding,
bottomPadding: bottomPadding, bottomPadding: bottomPadding,
monthSegmentSnappingOffset: widget.topSliverWidgetHeight ?? 0 + appBarExpandedHeight, monthSegmentSnappingOffset: widget.topSliverWidgetHeight ?? 0 + appBarExpandedHeight,
hasAppBar: widget.appBar != null,
child: grid, child: grid,
); );
} else { } else {