improve toolbar logic

This commit is contained in:
Fabian Freund
2026-03-02 16:30:56 +01:00
parent 8898f8a317
commit 3b61c2242d
4 changed files with 254 additions and 196 deletions
@@ -75,6 +75,8 @@ class ToolbarVisibilityController extends _$ToolbarVisibilityController {
/// Hide toolbar via scroll. All guards checked internally. /// Hide toolbar via scroll. All guards checked internally.
void requestHide() { void requestHide() {
if (state != ToolbarVisibility.visible) return;
final settings = ref.read(generalSettingsWithDefaultsProvider); final settings = ref.read(generalSettingsWithDefaultsProvider);
if (!settings.autoHideTabBar) return; if (!settings.autoHideTabBar) return;
@@ -84,15 +86,13 @@ class ToolbarVisibilityController extends _$ToolbarVisibilityController {
final viewportService = ref.read(viewportServiceProvider); final viewportService = ref.read(viewportServiceProvider);
if (!viewportService.isBrowserHandlingScrollEnabled) return; if (!viewportService.isBrowserHandlingScrollEnabled) return;
if (state == ToolbarVisibility.dismissed) return;
state = ToolbarVisibility.hidden; state = ToolbarVisibility.hidden;
} }
/// Show toolbar (scroll-up, tab change, loading start, etc). /// Show toolbar (scroll-up, tab change, loading start, etc).
/// Won't show if manually dismissed — use forceShow() for that. /// Won't show if manually dismissed — use forceShow() for that.
void show() { void show() {
if (state == ToolbarVisibility.dismissed) return; if (state != ToolbarVisibility.hidden) return;
state = ToolbarVisibility.visible; state = ToolbarVisibility.visible;
} }
@@ -61,21 +61,10 @@ import 'package:weblibre/features/user/domain/repositories/general_settings.dart
import 'package:weblibre/utils/move_to_background.dart'; import 'package:weblibre/utils/move_to_background.dart';
import 'package:weblibre/utils/ui_helper.dart' as ui_helper; import 'package:weblibre/utils/ui_helper.dart' as ui_helper;
/// Callback for toolbar animation progress updates.
/// [progress] is 0.0 when hidden, 1.0 when fully visible.
/// [heightPx] is the toolbar height in pixels.
typedef ToolbarAnimationCallback =
void Function(double progress, double heightPx);
/// Animated toolbar that slides in/out without changing layout constraints.
/// Uses SlideTransition to animate visual transform while maintaining
/// constant intrinsic size for layout purposes.
class _AnimatedToolbar extends HookWidget { class _AnimatedToolbar extends HookWidget {
final bool visible; final bool visible;
final TabBarPosition position; final TabBarPosition position;
final Widget child; final Widget child;
final double toolbarHeight;
final ToolbarAnimationCallback? onAnimationProgress;
static const _kAnimationDuration = Duration(milliseconds: 250); static const _kAnimationDuration = Duration(milliseconds: 250);
@@ -83,9 +72,6 @@ class _AnimatedToolbar extends HookWidget {
required this.visible, required this.visible,
required this.position, required this.position,
required this.child, required this.child,
required this.toolbarHeight,
// ignore: unused_element_parameter
this.onAnimationProgress,
}); });
@override @override
@@ -95,19 +81,6 @@ class _AnimatedToolbar extends HookWidget {
initialValue: visible ? 1.0 : 0.0, initialValue: visible ? 1.0 : 0.0,
); );
// Listen to animation changes and report progress
useEffect(() {
if (onAnimationProgress == null) return null;
void listener() {
onAnimationProgress?.call(controller.value, toolbarHeight);
}
controller.addListener(listener);
listener();
return () => controller.removeListener(listener);
}, [onAnimationProgress, toolbarHeight]);
useEffect(() { useEffect(() {
if (visible) { if (visible) {
unawaited(controller.forward()); unawaited(controller.forward());
@@ -352,21 +325,10 @@ class BrowserScreen extends HookConsumerWidget {
final displayedSheet = ref.watch(bottomSheetControllerProvider); final displayedSheet = ref.watch(bottomSheetControllerProvider);
final sheetDisplayed = displayedSheet != null; final sheetDisplayed = displayedSheet != null;
// Compute visibility states for toolbars // Track selected tab. Toolbar visibility is watched in scoped Consumer
// widgets below to avoid rebuilding the entire BrowserScreen on every
// hide/show cycle during scrolling.
final selectedTabId = ref.watch(selectedTabProvider); final selectedTabId = ref.watch(selectedTabProvider);
final toolbarState = ref.watch(
toolbarVisibilityControllerProvider(selectedTabId),
);
// Toolbar is visible when: sheet is shown OR (not fullscreen AND controller says visible)
// The controller handles loading-start show internally via ref.listen on isLoading
final effectiveAppBarVisible = toolbarState == ToolbarVisibility.visible;
final toolbarManuallyDismissed =
toolbarState == ToolbarVisibility.dismissed;
final topToolbarVisible =
sheetDisplayed || (!tabInFullScreen && effectiveAppBarVisible);
final bottomToolbarVisible =
sheetDisplayed || (!tabInFullScreen && effectiveAppBarVisible);
// Calculate relative safe area for sheet max size // Calculate relative safe area for sheet max size
final relativeSafeArea = MediaQuery.of(context).relativeSafeArea(); final relativeSafeArea = MediaQuery.of(context).relativeSafeArea();
@@ -384,13 +346,7 @@ class BrowserScreen extends HookConsumerWidget {
final bottomAppBarTotalHeight = final bottomAppBarTotalHeight =
bottomAppBarContentSize.height + bottomSafeArea; bottomAppBarContentSize.height + bottomSafeArea;
// When auto-hide is disabled, constrain browser to not extend behind toolbar // Calculate top toolbar size for browser offset and progress indicator
// (unless toolbar is manually dismissed via swipe gesture)
final browserBottomOffset = (!autoHideTabBar && bottomToolbarVisible)
? bottomAppBarTotalHeight
: 0.0;
// Calculate top toolbar size for browser offset
final topSafeArea = MediaQuery.of(context).padding.top; final topSafeArea = MediaQuery.of(context).padding.top;
final topAppBarContentSize = BrowserTopAppBar( final topAppBarContentSize = BrowserTopAppBar(
showMainToolbar: tabBarPosition == TabBarPosition.top, showMainToolbar: tabBarPosition == TabBarPosition.top,
@@ -399,14 +355,6 @@ class BrowserScreen extends HookConsumerWidget {
).preferredSize; ).preferredSize;
final topAppBarTotalHeight = topAppBarContentSize.height + topSafeArea; final topAppBarTotalHeight = topAppBarContentSize.height + topSafeArea;
// For top bar: always constrain browser below toolbar when visible
// (unlike bottom bar which only constrains when auto-hide is disabled)
// This ensures top-of-page content is always accessible
final browserTopOffset =
(tabBarPosition == TabBarPosition.top && topToolbarVisible)
? topAppBarTotalHeight
: 0.0;
// Get pixel ratio for converting logical pixels to physical pixels // Get pixel ratio for converting logical pixels to physical pixels
final pixelRatio = MediaQuery.of(context).devicePixelRatio; final pixelRatio = MediaQuery.of(context).devicePixelRatio;
@@ -425,11 +373,30 @@ class BrowserScreen extends HookConsumerWidget {
: 0.0; : 0.0;
final findInPageHeightPx = (findInPageHeight * pixelRatio).round(); final findInPageHeightPx = (findInPageHeight * pixelRatio).round();
final stableToolbarHeight = autoHideTabBar && !toolbarManuallyDismissed // Track dismissed state without triggering full rebuild on every
// hide/show. Updated via ref.listen below and synced on tab switch.
final toolbarDismissed = useState(false);
// Sync dismissed state when selected tab changes
useEffect(() {
toolbarDismissed.value =
ref.read(toolbarVisibilityControllerProvider(selectedTabId)) ==
ToolbarVisibility.dismissed;
return null;
}, [selectedTabId]);
final stableToolbarHeight =
autoHideTabBar && !toolbarDismissed.value && !tabInFullScreen
? bottomAppBarTotalHeight ? bottomAppBarTotalHeight
: 0.0; : 0.0;
final stableToolbarHeightPx = (stableToolbarHeight * pixelRatio).round(); final stableToolbarHeightPx = (stableToolbarHeight * pixelRatio).round();
// Compute toolbar visibility for keyboard inset math.
// Uses ref.watch via the toolbarDismissed useState to avoid
// subscribing to every hide/show toggle.
final toolbarVisibleForLayout =
sheetDisplayed || (!tabInFullScreen && !toolbarDismissed.value);
final keyboardHeightPx = useState<int?>(null); final keyboardHeightPx = useState<int?>(null);
useOnStreamChange( useOnStreamChange(
@@ -446,7 +413,7 @@ class BrowserScreen extends HookConsumerWidget {
final keyboardVisible = keyboardHeightPx.value != null; final keyboardVisible = keyboardHeightPx.value != null;
final bottomLayoutReservedPx = (!autoHideTabBar && bottomToolbarVisible) final bottomLayoutReservedPx = (!autoHideTabBar && toolbarVisibleForLayout)
? (bottomAppBarTotalHeight * pixelRatio).round() ? (bottomAppBarTotalHeight * pixelRatio).round()
: 0; : 0;
final keyboardViewportHeightPx = keyboardVisible final keyboardViewportHeightPx = keyboardVisible
@@ -469,63 +436,70 @@ class BrowserScreen extends HookConsumerWidget {
return null; return null;
}, [effectiveToolbarHeightPx]); }, [effectiveToolbarHeightPx]);
// Track last clipping value to avoid redundant platform channel calls // Track last clipping value to avoid redundant platform channel calls.
// Clipping is set once when visibility changes (before animation starts),
// rather than on every animation frame, to avoid platform channel spam.
final lastClippingPx = useRef(0); final lastClippingPx = useRef(0);
final desiredToolbarClippingPx = useRef(0);
// Keep clipping state in sync with keyboard and auto-hide states. void updateClipping() {
// While keyboard is visible, do not apply toolbar clipping. final toolbarState = ref.read(
useEffect( toolbarVisibilityControllerProvider(selectedTabId),
() { );
if (toolbarManuallyDismissed) { final effectiveVisible = toolbarState == ToolbarVisibility.visible;
desiredToolbarClippingPx.value = 0; final dismissed = toolbarState == ToolbarVisibility.dismissed;
}
final targetClippingPx = // When hidden: clip from bottom by toolbar height so GeckoView
autoHideTabBar && // can compute its layout while Flutter animates.
!toolbarManuallyDismissed && // When visible/dismissed or overridden by keyboard/loading: no clipping.
!keyboardVisible && final targetClippingPx =
!tabIsLoading autoHideTabBar &&
? desiredToolbarClippingPx.value !dismissed &&
: 0; !effectiveVisible &&
!keyboardVisible &&
if (targetClippingPx != lastClippingPx.value) { !tabIsLoading &&
lastClippingPx.value = targetClippingPx; !tabInFullScreen
unawaited(viewportService.setVerticalClipping(targetClippingPx)); ? -(bottomAppBarTotalHeight * pixelRatio).round()
} : 0;
return null;
},
[autoHideTabBar, toolbarManuallyDismissed, keyboardVisible, tabIsLoading],
);
final animationProgressCallback = useCallback((
double progress,
double heightPx,
) {
if (toolbarManuallyDismissed) {
desiredToolbarClippingPx.value = 0;
if (lastClippingPx.value != 0) {
lastClippingPx.value = 0;
unawaited(viewportService.setVerticalClipping(0));
}
return;
}
// Clip content from bottom as toolbar hides.
// Negative clipping = clip from bottom.
final clippingPx = -((1.0 - progress) * heightPx * pixelRatio).round();
desiredToolbarClippingPx.value = clippingPx;
final targetClippingPx = (keyboardVisible || tabIsLoading)
? 0
: clippingPx;
if (targetClippingPx != lastClippingPx.value) { if (targetClippingPx != lastClippingPx.value) {
lastClippingPx.value = targetClippingPx; lastClippingPx.value = targetClippingPx;
unawaited(viewportService.setVerticalClipping(targetClippingPx)); unawaited(viewportService.setVerticalClipping(targetClippingPx));
} }
}, [toolbarManuallyDismissed, keyboardVisible, pixelRatio, tabIsLoading]); }
// Update clipping when toolbar visibility changes (does NOT trigger
// full rebuild). Also tracks dismissed state via useState so that
// stableToolbarHeight / effectiveToolbarHeightPx stay correct.
ref.listen(toolbarVisibilityControllerProvider(selectedTabId), (
previous,
next,
) {
updateClipping();
// Update dismissed state — triggers a targeted rebuild only when
// the dismissed flag actually changes (not on every hide/show).
final isDismissed = next == ToolbarVisibility.dismissed;
if (toolbarDismissed.value != isDismissed) {
toolbarDismissed.value = isDismissed;
}
});
// Update clipping when other relevant state changes
useEffect(
() {
updateClipping();
return null;
},
[
autoHideTabBar,
keyboardVisible,
tabIsLoading,
tabInFullScreen,
bottomAppBarTotalHeight,
pixelRatio,
selectedTabId,
],
);
// Theme with dynamic snackbar margin to position above bottom toolbar // Theme with dynamic snackbar margin to position above bottom toolbar
final themeData = Theme.of(context).copyWith( final themeData = Theme.of(context).copyWith(
@@ -545,7 +519,8 @@ class BrowserScreen extends HookConsumerWidget {
left: 16, left: 16,
right: 16, right: 16,
bottom: bottom:
(bottomToolbarVisible ? bottomAppBarContentSize.height + 8 : 16) + bottomAppBarContentSize.height +
8 +
(findInPageVisible ? findInPageHeight : 0), (findInPageVisible ? findInPageHeight : 0),
), ),
), ),
@@ -565,18 +540,45 @@ class BrowserScreen extends HookConsumerWidget {
// Layer 0: Browser content // Layer 0: Browser content
// Position changes instantly (no animation) to avoid jarring native view resize // Position changes instantly (no animation) to avoid jarring native view resize
// The toolbar itself animates, providing visual continuity // The toolbar itself animates, providing visual continuity
Positioned( Consumer(
left: 0, builder: (context, ref, child) {
right: 0, final toolbarState = ref.watch(
top: browserTopOffset, toolbarVisibilityControllerProvider(selectedTabId),
bottom: browserBottomOffset, );
child: _Browser( final toolbarVisible =
overlayController: overlayController, sheetDisplayed ||
tabInFullScreen: tabInFullScreen, (!tabInFullScreen &&
pointerMoveEventSink: pointerMoveEventsController.sink, toolbarState == ToolbarVisibility.visible);
sheetDisplayed: sheetDisplayed,
hasTopBarOffset: browserTopOffset > 0, // When auto-hide is disabled, constrain browser above toolbar
), // (unless toolbar is manually dismissed via swipe gesture)
final bottomOffset = (!autoHideTabBar && toolbarVisible)
? bottomAppBarTotalHeight
: 0.0;
// For top bar: constrain browser below toolbar when visible
// to ensure top-of-page content is always accessible
final topOffset =
(tabBarPosition == TabBarPosition.top && toolbarVisible)
? topAppBarTotalHeight
: 0.0;
return Positioned(
left: 0,
right: 0,
top: topOffset,
bottom: bottomOffset,
child: _Browser(
overlayController: overlayController,
tabInFullScreen: tabInFullScreen,
pointerMoveEventSink: autoHideTabBar
? pointerMoveEventsController.sink
: null,
sheetDisplayed: sheetDisplayed,
hasTopBarOffset: topOffset > 0,
),
);
},
), ),
// Layer 1: Sheet (when displayed) - positioned above toolbar // Layer 1: Sheet (when displayed) - positioned above toolbar
@@ -598,24 +600,31 @@ class BrowserScreen extends HookConsumerWidget {
left: 0, left: 0,
right: 0, right: 0,
bottom: 0, bottom: 0,
child: _AnimatedToolbar( child: Consumer(
position: TabBarPosition.bottom, builder: (context, ref, _) {
visible: bottomToolbarVisible, final toolbarState = ref.watch(
toolbarHeight: bottomAppBarTotalHeight, toolbarVisibilityControllerProvider(selectedTabId),
onAnimationProgress: );
autoHideTabBar && !toolbarManuallyDismissed final visible =
? animationProgressCallback sheetDisplayed ||
: null, (!tabInFullScreen &&
child: _TabBar( toolbarState == ToolbarVisibility.visible);
tabBarPosition: TabBarPosition.bottom, return _AnimatedToolbar(
showMainToolbar: tabBarPosition == TabBarPosition.bottom, position: TabBarPosition.bottom,
showContextualToolbar: showContextualToolbar, visible: visible,
showQuickTabSwitcherBar: displayQuickTabSwitcherBar, child: _TabBar(
// Only subscribe to scroll events when this is the active position tabBarPosition: TabBarPosition.bottom,
pointerMoveEvents: tabBarPosition == TabBarPosition.bottom showMainToolbar:
? pointerMoveEventsController.stream tabBarPosition == TabBarPosition.bottom,
: null, showContextualToolbar: showContextualToolbar,
), showQuickTabSwitcherBar: displayQuickTabSwitcherBar,
pointerMoveEvents:
tabBarPosition == TabBarPosition.bottom
? pointerMoveEventsController.stream
: null,
),
);
},
), ),
), ),
@@ -625,44 +634,76 @@ class BrowserScreen extends HookConsumerWidget {
left: 0, left: 0,
right: 0, right: 0,
top: 0, top: 0,
child: _AnimatedToolbar( child: Consumer(
position: TabBarPosition.top, builder: (context, ref, _) {
visible: topToolbarVisible, final toolbarState = ref.watch(
toolbarHeight: topAppBarTotalHeight, toolbarVisibilityControllerProvider(selectedTabId),
child: _TabBar( );
tabBarPosition: TabBarPosition.top, final visible =
showMainToolbar: true, sheetDisplayed ||
showContextualToolbar: showContextualToolbar, (!tabInFullScreen &&
showQuickTabSwitcherBar: displayQuickTabSwitcherBar, toolbarState == ToolbarVisibility.visible);
pointerMoveEvents: pointerMoveEventsController.stream, return _AnimatedToolbar(
), position: TabBarPosition.top,
visible: visible,
child: _TabBar(
tabBarPosition: TabBarPosition.top,
showMainToolbar: true,
showContextualToolbar: showContextualToolbar,
showQuickTabSwitcherBar: displayQuickTabSwitcherBar,
pointerMoveEvents: pointerMoveEventsController.stream,
),
);
},
), ),
), ),
// Layer 4: FAB (draggable via long press) // Layer 4: FAB (draggable via long press)
DraggableFab( Consumer(
bottomToolbarVisible: bottomToolbarVisible, builder: (context, ref, child) {
bottomAppBarHeight: bottomAppBarTotalHeight, final toolbarState = ref.watch(
bottomSafeArea: bottomSafeArea, toolbarVisibilityControllerProvider(selectedTabId),
);
final visible =
sheetDisplayed ||
(!tabInFullScreen &&
toolbarState == ToolbarVisibility.visible);
return DraggableFab(
bottomToolbarVisible: visible,
bottomAppBarHeight: bottomAppBarTotalHeight,
bottomSafeArea: bottomSafeArea,
child: child!,
);
},
child: const BrowserFab(), child: const BrowserFab(),
), ),
// Layer 5: Page load progress indicator (animates with toolbar visibility) // Layer 5: Page load progress indicator (animates with toolbar visibility)
AnimatedPositioned( Consumer(
duration: _AnimatedToolbar._kAnimationDuration, builder: (context, ref, child) {
curve: Curves.easeInOutQuart, final toolbarState = ref.watch(
left: 0, toolbarVisibilityControllerProvider(selectedTabId),
right: 0, );
top: tabBarPosition == TabBarPosition.top && topToolbarVisible final visible =
? topAppBarTotalHeight sheetDisplayed ||
: null, (!tabInFullScreen &&
bottom: toolbarState == ToolbarVisibility.visible);
tabBarPosition == TabBarPosition.bottom && return AnimatedPositioned(
bottomToolbarVisible duration: _AnimatedToolbar._kAnimationDuration,
? bottomAppBarTotalHeight curve: Curves.easeInOutQuart,
: tabBarPosition == TabBarPosition.bottom left: 0,
? 0 right: 0,
: null, top: tabBarPosition == TabBarPosition.top && visible
? topAppBarTotalHeight
: null,
bottom: tabBarPosition == TabBarPosition.bottom && visible
? bottomAppBarTotalHeight
: tabBarPosition == TabBarPosition.bottom
? 0
: null,
child: child!,
);
},
child: Consumer( child: Consumer(
builder: (context, ref, child) { builder: (context, ref, child) {
final value = ref.watch( final value = ref.watch(
@@ -685,17 +726,27 @@ class BrowserScreen extends HookConsumerWidget {
), ),
// Layer 6: Find in Page widget (above toolbar or keyboard, whichever is higher) // Layer 6: Find in Page widget (above toolbar or keyboard, whichever is higher)
AnimatedPositioned( Consumer(
duration: _AnimatedToolbar._kAnimationDuration, builder: (context, ref, child) {
curve: Curves.easeInOutQuart, final toolbarState = ref.watch(
left: 0, toolbarVisibilityControllerProvider(selectedTabId),
right: 0, );
bottom: math.max( final visible =
bottomToolbarVisible sheetDisplayed ||
? bottomAppBarTotalHeight (!tabInFullScreen &&
: bottomSafeArea, toolbarState == ToolbarVisibility.visible);
MediaQuery.viewInsetsOf(context).bottom, return AnimatedPositioned(
), duration: _AnimatedToolbar._kAnimationDuration,
curve: Curves.easeInOutQuart,
left: 0,
right: 0,
bottom: math.max(
visible ? bottomAppBarTotalHeight : bottomSafeArea,
MediaQuery.viewInsetsOf(context).bottom,
),
child: child!,
);
},
child: Consumer( child: Consumer(
builder: (context, ref, child) { builder: (context, ref, child) {
final tabId = ref.watch(selectedTabProvider); final tabId = ref.watch(selectedTabProvider);
@@ -777,7 +828,7 @@ class _Browser extends HookConsumerWidget {
Duration get _backButtonPressTimeout => const Duration(seconds: 2); Duration get _backButtonPressTimeout => const Duration(seconds: 2);
final OverlayPortalController overlayController; final OverlayPortalController overlayController;
final StreamSink<Offset> pointerMoveEventSink; final StreamSink<Offset>? pointerMoveEventSink;
final bool tabInFullScreen; final bool tabInFullScreen;
final bool sheetDisplayed; final bool sheetDisplayed;
final bool hasTopBarOffset; final bool hasTopBarOffset;
@@ -90,6 +90,10 @@ class _BrowserViewState extends ConsumerState<BrowserView>
DateTime? _suggestionCountTime; DateTime? _suggestionCountTime;
static const _pointerThrottleInterval = Duration(milliseconds: 32);
DateTime _lastPointerEvent = DateTime(0);
Offset _accumulatedDelta = Offset.zero;
Future<void> _timerTick(Timer timer) async { Future<void> _timerTick(Timer timer) async {
await ref await ref
.read(selectedTabSessionProvider) .read(selectedTabSessionProvider)
@@ -280,10 +284,25 @@ class _BrowserViewState extends ConsumerState<BrowserView>
return Listener( return Listener(
behavior: HitTestBehavior.translucent, behavior: HitTestBehavior.translucent,
onPointerUp: (widget.pointerMoveEventSink != null)
? (_) {
if (_accumulatedDelta != Offset.zero) {
widget.pointerMoveEventSink!.add(_accumulatedDelta);
_accumulatedDelta = Offset.zero;
}
}
: null,
onPointerMove: (widget.pointerMoveEventSink != null) onPointerMove: (widget.pointerMoveEventSink != null)
? (event) { ? (event) {
if (event.down) { if (event.down) {
widget.pointerMoveEventSink!.add(event.localDelta); _accumulatedDelta += event.localDelta;
final now = DateTime.now();
if (now.difference(_lastPointerEvent) >=
_pointerThrottleInterval) {
_lastPointerEvent = now;
widget.pointerMoveEventSink!.add(_accumulatedDelta);
_accumulatedDelta = Offset.zero;
}
} }
} }
: null, : null,
@@ -8,7 +8,6 @@ package eu.weblibre.flutter_mozilla_components.api
import eu.weblibre.flutter_mozilla_components.GlobalComponents import eu.weblibre.flutter_mozilla_components.GlobalComponents
import eu.weblibre.flutter_mozilla_components.pigeons.GeckoViewportApi import eu.weblibre.flutter_mozilla_components.pigeons.GeckoViewportApi
import mozilla.components.support.base.log.logger.Logger
/** /**
* Implementation of GeckoViewportApi that controls GeckoView's viewport behavior * Implementation of GeckoViewportApi that controls GeckoView's viewport behavior
@@ -22,12 +21,6 @@ import mozilla.components.support.base.log.logger.Logger
* is called, the value is stored and applied when the EngineView becomes available. * is called, the value is stored and applied when the EngineView becomes available.
*/ */
class GeckoViewportApiImpl : GeckoViewportApi { class GeckoViewportApiImpl : GeckoViewportApi {
companion object {
private const val TAG = "GeckoViewportApi"
}
private val logger = Logger(TAG)
private val components by lazy { private val components by lazy {
requireNotNull(GlobalComponents.components) { "Components not initialized" } requireNotNull(GlobalComponents.components) { "Components not initialized" }
} }
@@ -46,13 +39,11 @@ class GeckoViewportApiImpl : GeckoViewportApi {
val engineView = components.mainBrowserEngineView val engineView = components.mainBrowserEngineView
if (engineView == null) { if (engineView == null) {
logger.debug("$TAG: setDynamicToolbarMaxHeight($height) - mainBrowserEngineView not ready, storing as pending")
pendingToolbarHeight = height pendingToolbarHeight = height
return return
} }
pendingToolbarHeight = null pendingToolbarHeight = null
logger.debug("$TAG: setDynamicToolbarMaxHeight($height)")
engineView.setDynamicToolbarMaxHeight(height) engineView.setDynamicToolbarMaxHeight(height)
} }
@@ -64,7 +55,6 @@ class GeckoViewportApiImpl : GeckoViewportApi {
val pending = pendingToolbarHeight ?: return val pending = pendingToolbarHeight ?: return
val engineView = components.mainBrowserEngineView ?: return val engineView = components.mainBrowserEngineView ?: return
pendingToolbarHeight = null pendingToolbarHeight = null
logger.debug("$TAG: Applying pending toolbar height: $pending")
engineView.setDynamicToolbarMaxHeight(pending) engineView.setDynamicToolbarMaxHeight(pending)
} }
@@ -78,11 +68,9 @@ class GeckoViewportApiImpl : GeckoViewportApi {
val engineView = components.mainBrowserEngineView val engineView = components.mainBrowserEngineView
if (engineView == null) { if (engineView == null) {
logger.warn("$TAG: setVerticalClipping called but mainBrowserEngineView is null")
return return
} }
logger.debug("$TAG: setVerticalClipping($clipping)")
engineView.setVerticalClipping(clipping) engineView.setVerticalClipping(clipping)
} }
} }