@@ -570,7 +570,7 @@ class _AppPageState extends ConsumerState<AppPage> {
570
570
);
571
571
}
572
572
573
- Scaffold _buildScaffold (
573
+ Widget _buildScaffold (
574
574
BuildContext context,
575
575
bool hasDrawer,
576
576
bool hasRail,
@@ -599,51 +599,58 @@ class _AppPageState extends ConsumerState<AppPage> {
599
599
);
600
600
}
601
601
if (hasRail || hasManage) {
602
- body = GestureDetector (
603
- behavior: HitTestBehavior .deferToChild,
604
- onTap: () {
605
- Actions .invoke (context, const EscapeIntent ());
606
- FocusManager .instance.primaryFocus? .unfocus ();
607
- },
608
- child: SafeArea (
602
+ body = SafeArea (
603
+ child: FocusTraversalGroup (
604
+ policy: OrderedTraversalPolicy (),
609
605
child: Row (
610
606
crossAxisAlignment: CrossAxisAlignment .stretch,
611
607
children: [
612
608
if (hasRail && (! fullyExpanded || ! showNavigation))
613
- SizedBox (
614
- width: 72 ,
615
- child: _VisibilityListener (
616
- targetKey: _navKey,
617
- controller: _navController,
618
- child: SingleChildScrollView (
619
- child: NavigationContent (
620
- key: _navKey,
621
- shouldPop: false ,
622
- extended: false ,
609
+ FocusTraversalOrder (
610
+ order: NumericFocusOrder (1 ),
611
+ child: SizedBox (
612
+ width: 72 ,
613
+ child: _VisibilityListener (
614
+ targetKey: _navKey,
615
+ controller: _navController,
616
+ child: SingleChildScrollView (
617
+ child: NavigationContent (
618
+ key: _navKey,
619
+ shouldPop: false ,
620
+ extended: false ,
621
+ ),
623
622
),
624
623
),
625
624
),
626
625
),
627
626
if (fullyExpanded && showNavigation)
628
- SizedBox (
629
- width: 280 ,
630
- child: _VisibilityListener (
631
- controller: _navController,
632
- targetKey: _navExpandedKey,
633
- child: SingleChildScrollView (
634
- child: Material (
635
- type: MaterialType .transparency,
636
- child: NavigationContent (
637
- key: _navExpandedKey,
638
- shouldPop: false ,
639
- extended: true ,
627
+ FocusTraversalOrder (
628
+ order: NumericFocusOrder (1 ),
629
+ child: SizedBox (
630
+ width: 280 ,
631
+ child: _VisibilityListener (
632
+ controller: _navController,
633
+ targetKey: _navExpandedKey,
634
+ child: SingleChildScrollView (
635
+ child: Material (
636
+ type: MaterialType .transparency,
637
+ child: NavigationContent (
638
+ key: _navExpandedKey,
639
+ shouldPop: false ,
640
+ extended: true ,
641
+ ),
640
642
),
641
643
),
642
644
),
643
645
),
644
646
),
645
647
const SizedBox (width: 8 ),
646
- Expanded (child: body),
648
+ Expanded (
649
+ child: FocusTraversalOrder (
650
+ order: NumericFocusOrder (2 ),
651
+ child: body,
652
+ ),
653
+ ),
647
654
if (hasManage &&
648
655
! hasDetailsOrKeyActions &&
649
656
showDetailView &&
@@ -654,22 +661,25 @@ class _AppPageState extends ConsumerState<AppPage> {
654
661
// - pages without Capabilities
655
662
const SizedBox (width: 336 ), // simulate column
656
663
if (hasManage && hasDetailsOrKeyActions && showDetailView)
657
- _VisibilityListener (
658
- controller: _detailsController,
659
- targetKey: _detailsViewGlobalKey,
660
- child: SingleChildScrollView (
661
- child: Padding (
662
- padding: const EdgeInsets .symmetric (horizontal: 8 ),
663
- child: SizedBox (
664
- width: 320 ,
665
- child: Column (
666
- key: _detailsViewGlobalKey,
667
- children: [
668
- if (widget.detailViewBuilder != null )
669
- widget.detailViewBuilder !(context),
670
- if (widget.keyActionsBuilder != null )
671
- widget.keyActionsBuilder !(context),
672
- ],
664
+ FocusTraversalOrder (
665
+ order: NumericFocusOrder (3 ),
666
+ child: _VisibilityListener (
667
+ controller: _detailsController,
668
+ targetKey: _detailsViewGlobalKey,
669
+ child: SingleChildScrollView (
670
+ child: Padding (
671
+ padding: const EdgeInsets .symmetric (horizontal: 8 ),
672
+ child: SizedBox (
673
+ width: 320 ,
674
+ child: Column (
675
+ key: _detailsViewGlobalKey,
676
+ children: [
677
+ if (widget.detailViewBuilder != null )
678
+ widget.detailViewBuilder !(context),
679
+ if (widget.keyActionsBuilder != null )
680
+ widget.keyActionsBuilder !(context),
681
+ ],
682
+ ),
673
683
),
674
684
),
675
685
),
@@ -680,13 +690,15 @@ class _AppPageState extends ConsumerState<AppPage> {
680
690
),
681
691
);
682
692
}
683
- return Scaffold (
684
- key: scaffoldGlobalKey,
685
- appBar: _GestureDetectorAppBar (
686
- onTap: () {
687
- Actions .invoke (context, const EscapeIntent ());
688
- FocusManager .instance.primaryFocus? .unfocus ();
689
- },
693
+ return GestureDetector (
694
+ behavior: HitTestBehavior .deferToChild,
695
+ onTap: () {
696
+ // If tap is not absorbed downstream, treat it as dead space
697
+ // and invoke escape intent
698
+ Actions .invoke (context, EscapeIntent ());
699
+ },
700
+ child: Scaffold (
701
+ key: scaffoldGlobalKey,
690
702
appBar: AppBar (
691
703
bottom: PreferredSize (
692
704
preferredSize: const Size .fromHeight (1.0 ),
@@ -822,31 +834,11 @@ class _AppPageState extends ConsumerState<AppPage> {
822
834
),
823
835
],
824
836
),
837
+ drawer: hasDrawer ? _buildDrawer (context) : null ,
838
+ body: body,
825
839
),
826
- drawer: hasDrawer ? _buildDrawer (context) : null ,
827
- body: body,
828
- );
829
- }
830
- }
831
-
832
- class _GestureDetectorAppBar extends StatelessWidget
833
- implements PreferredSizeWidget {
834
- final AppBar appBar;
835
- final void Function () onTap;
836
-
837
- const _GestureDetectorAppBar ({required this .appBar, required this .onTap});
838
-
839
- @override
840
- Widget build (BuildContext context) {
841
- return GestureDetector (
842
- behavior: HitTestBehavior .deferToChild,
843
- onTap: onTap,
844
- child: appBar,
845
840
);
846
841
}
847
-
848
- @override
849
- Size get preferredSize => const Size .fromHeight (kToolbarHeight);
850
842
}
851
843
852
844
class CapabilityBadge extends ConsumerWidget {
0 commit comments