feat: sidenav on desktop

This commit is contained in:
edde746
2025-12-06 12:43:31 +01:00
parent 7b0aa12c38
commit a373477105
15 changed files with 826 additions and 311 deletions
+53 -1
View File
@@ -2,6 +2,23 @@ import 'dart:io' show Platform;
import 'package:flutter/material.dart';
import '../services/fullscreen_state_manager.dart';
/// InheritedWidget to indicate that a side navigation is present in the widget tree.
/// When present, app bars should skip their left padding since the side nav
/// already handles the macOS traffic lights area.
class SideNavigationScope extends InheritedWidget {
const SideNavigationScope({
super.key,
required super.child,
});
static bool isPresent(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<SideNavigationScope>() != null;
}
@override
bool updateShouldNotify(SideNavigationScope oldWidget) => false;
}
/// Padding values for desktop window controls
class DesktopWindowPadding {
/// Left padding for macOS traffic lights (normal window mode)
@@ -45,14 +62,28 @@ class DesktopAppBarHelper {
/// Builds leading widget with appropriate left padding for macOS traffic lights
///
/// [includeGestureDetector] - If true, wraps in GestureDetector to prevent window dragging
/// [context] - Required to check if side navigation is visible
static Widget? buildAdjustedLeading(
Widget? leading, {
bool includeGestureDetector = false,
BuildContext? context,
}) {
if (!Platform.isMacOS || leading == null) {
return leading;
}
// Skip left padding when side navigation scope is present in widget tree
if (context != null && SideNavigationScope.isPresent(context)) {
if (includeGestureDetector) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onPanDown: (_) {},
child: leading,
);
}
return leading;
}
return ListenableBuilder(
listenable: FullscreenStateManager(),
builder: (context, _) {
@@ -94,11 +125,17 @@ class DesktopAppBarHelper {
}
/// Calculates the leading width for SliverAppBar to account for macOS traffic lights
static double? calculateLeadingWidth(Widget? leading) {
/// [context] - Required to check if side navigation is visible
static double? calculateLeadingWidth(Widget? leading, {BuildContext? context}) {
if (!Platform.isMacOS || leading == null) {
return null;
}
// Skip extra width when side navigation scope is present in widget tree
if (context != null && SideNavigationScope.isPresent(context)) {
return null;
}
final isFullscreen = FullscreenStateManager().isFullscreen;
final leftPadding = isFullscreen
? DesktopWindowPadding.macOSLeftFullscreen
@@ -125,6 +162,8 @@ class DesktopAppBarHelper {
/// A widget that adds padding to account for desktop window controls.
/// On macOS, adds left padding for traffic lights (reduced in fullscreen).
/// When side navigation is visible, left padding is skipped as the side nav
/// already occupies the traffic lights area.
class DesktopTitleBarPadding extends StatelessWidget {
final Widget child;
final double? leftPadding;
@@ -143,6 +182,19 @@ class DesktopTitleBarPadding extends StatelessWidget {
return child;
}
// Skip left padding when side navigation scope is present in widget tree
// (side nav already handles the traffic lights area)
if (SideNavigationScope.isPresent(context)) {
final right = rightPadding ?? 0.0;
if (right == 0.0) {
return child;
}
return Padding(
padding: EdgeInsets.only(right: right),
child: child,
);
}
return ListenableBuilder(
listenable: FullscreenStateManager(),
builder: (context, _) {