[flutter_adaptive_scaffold] Fuchsia is mobile. (#2727)

diff --git a/packages/flutter_adaptive_scaffold/CHANGELOG.md b/packages/flutter_adaptive_scaffold/CHANGELOG.md
index 86a954a..85dcaaa 100644
--- a/packages/flutter_adaptive_scaffold/CHANGELOG.md
+++ b/packages/flutter_adaptive_scaffold/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.0.8
+
+Make fuchsia a mobile platform.
+
 ## 0.0.7
 
 * Patch duplicate key error in SlotLayout.
diff --git a/packages/flutter_adaptive_scaffold/lib/src/breakpoints.dart b/packages/flutter_adaptive_scaffold/lib/src/breakpoints.dart
index e236189..4fc0687 100644
--- a/packages/flutter_adaptive_scaffold/lib/src/breakpoints.dart
+++ b/packages/flutter_adaptive_scaffold/lib/src/breakpoints.dart
@@ -5,14 +5,15 @@
 import 'package:flutter/material.dart';
 
 const Set<TargetPlatform> _desktop = <TargetPlatform>{
-  TargetPlatform.fuchsia,
   TargetPlatform.linux,
   TargetPlatform.macOS,
   TargetPlatform.windows
 };
+
 const Set<TargetPlatform> _mobile = <TargetPlatform>{
+  TargetPlatform.android,
+  TargetPlatform.fuchsia,
   TargetPlatform.iOS,
-  TargetPlatform.android
 };
 
 /// A group of standard breakpoints built according to the material
@@ -89,18 +90,16 @@
 
   @override
   bool isActive(BuildContext context) {
-    bool size = false;
-    final bool isRightPlatform =
-        platform?.contains(Theme.of(context).platform) ?? true;
-    if (begin != null && end != null) {
-      size = MediaQuery.of(context).size.width >= begin! &&
-          MediaQuery.of(context).size.width < end!;
-    } else if (begin != null && end == null) {
-      size = MediaQuery.of(context).size.width >= begin!;
-    } else if (begin == null && end != null) {
-      size = MediaQuery.of(context).size.width < end!;
-    }
-    return size && isRightPlatform;
+    final TargetPlatform host = Theme.of(context).platform;
+    final bool isRightPlatform = platform?.contains(host) ?? true;
+
+    // Null boundaries are unbounded, assign the max/min of their associated
+    // direction on a number line.
+    final double width = MediaQuery.of(context).size.width;
+    final double lowerBound = begin ?? double.negativeInfinity;
+    final double upperBound = end ?? double.infinity;
+
+    return width >= lowerBound && width < upperBound && isRightPlatform;
   }
 }
 
diff --git a/packages/flutter_adaptive_scaffold/pubspec.yaml b/packages/flutter_adaptive_scaffold/pubspec.yaml
index 01ff56f..36a30a2 100644
--- a/packages/flutter_adaptive_scaffold/pubspec.yaml
+++ b/packages/flutter_adaptive_scaffold/pubspec.yaml
@@ -1,6 +1,6 @@
 name: flutter_adaptive_scaffold
 description: Widgets to easily build adaptive layouts, including navigation elements.
-version: 0.0.7
+version: 0.0.8
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+flutter_adaptive_scaffold%22
 repository: https://github.com/flutter/packages/tree/main/packages/flutter_adaptive_scaffold
 
diff --git a/packages/flutter_adaptive_scaffold/test/adaptive_scaffold_test.dart b/packages/flutter_adaptive_scaffold/test/adaptive_scaffold_test.dart
index 4b8b632..41377d1 100644
--- a/packages/flutter_adaptive_scaffold/test/adaptive_scaffold_test.dart
+++ b/packages/flutter_adaptive_scaffold/test/adaptive_scaffold_test.dart
@@ -4,8 +4,9 @@
 
 import 'package:flutter/material.dart';
 import 'package:flutter_adaptive_scaffold/src/adaptive_scaffold.dart';
-import 'package:flutter_adaptive_scaffold/src/breakpoints.dart';
 import 'package:flutter_test/flutter_test.dart';
+import 'simulated_layout.dart';
+import 'test_breakpoints.dart';
 
 void main() {
   testWidgets('adaptive scaffold lays out slots as expected',
@@ -20,8 +21,8 @@
     final Finder primaryNav = find.byKey(const Key('primaryNavigation'));
     final Finder primaryNav1 = find.byKey(const Key('primaryNavigation1'));
 
-    await tester.binding.setSurfaceSize(SimulatedLayout.mobile.size);
-    await tester.pumpWidget(SimulatedLayout.mobile.app());
+    await tester.binding.setSurfaceSize(SimulatedLayout.small.size);
+    await tester.pumpWidget(SimulatedLayout.small.app());
     await tester.pumpAndSettle();
 
     expect(smallBody, findsOneWidget);
@@ -33,8 +34,8 @@
     expect(tester.getTopLeft(smallSBody), const Offset(200, 0));
     expect(tester.getTopLeft(bottomNav), const Offset(0, 744));
 
-    await tester.binding.setSurfaceSize(SimulatedLayout.tablet.size);
-    await tester.pumpWidget(SimulatedLayout.tablet.app());
+    await tester.binding.setSurfaceSize(SimulatedLayout.medium.size);
+    await tester.pumpWidget(SimulatedLayout.medium.app());
     await tester.pumpAndSettle();
 
     expect(smallBody, findsNothing);
@@ -49,8 +50,8 @@
     expect(tester.getTopLeft(primaryNav), Offset.zero);
     expect(tester.getBottomRight(primaryNav), const Offset(88, 800));
 
-    await tester.binding.setSurfaceSize(SimulatedLayout.desktop.size);
-    await tester.pumpWidget(SimulatedLayout.desktop.app());
+    await tester.binding.setSurfaceSize(SimulatedLayout.large.size);
+    await tester.pumpWidget(SimulatedLayout.large.app());
     await tester.pumpAndSettle();
 
     expect(body, findsNothing);
@@ -71,10 +72,10 @@
     final Finder b = find.byKey(const Key('body'));
     final Finder sBody = find.byKey(const Key('sBody'));
 
-    await tester.binding.setSurfaceSize(SimulatedLayout.mobile.size);
-    await tester.pumpWidget(SimulatedLayout.mobile.app());
-    await tester.binding.setSurfaceSize(SimulatedLayout.tablet.size);
-    await tester.pumpWidget(SimulatedLayout.tablet.app());
+    await tester.binding.setSurfaceSize(SimulatedLayout.small.size);
+    await tester.pumpWidget(SimulatedLayout.small.app());
+    await tester.binding.setSurfaceSize(SimulatedLayout.medium.size);
+    await tester.pumpWidget(SimulatedLayout.medium.app());
 
     await tester.pump();
     await tester.pump(const Duration(milliseconds: 200));
@@ -112,11 +113,11 @@
     final Finder b = find.byKey(const Key('body'));
     final Finder sBody = find.byKey(const Key('sBody'));
 
-    await tester.binding.setSurfaceSize(SimulatedLayout.mobile.size);
-    await tester.pumpWidget(SimulatedLayout.mobile.app(animations: false));
+    await tester.binding.setSurfaceSize(SimulatedLayout.small.size);
+    await tester.pumpWidget(SimulatedLayout.small.app(animations: false));
 
-    await tester.binding.setSurfaceSize(SimulatedLayout.tablet.size);
-    await tester.pumpWidget(SimulatedLayout.tablet.app(animations: false));
+    await tester.binding.setSurfaceSize(SimulatedLayout.medium.size);
+    await tester.pumpWidget(SimulatedLayout.medium.app(animations: false));
 
     await tester.pump();
     await tester.pump(const Duration(milliseconds: 200));
@@ -209,126 +210,3 @@
   @override
   Size get preferredSize => const Size(200, 200);
 }
-
-class TestBreakpoint0 extends Breakpoint {
-  @override
-  bool isActive(BuildContext context) {
-    return MediaQuery.of(context).size.width >= 0 &&
-        MediaQuery.of(context).size.width < 800;
-  }
-}
-
-class TestBreakpoint800 extends Breakpoint {
-  @override
-  bool isActive(BuildContext context) {
-    return MediaQuery.of(context).size.width >= 800 &&
-        MediaQuery.of(context).size.width < 1000;
-  }
-}
-
-class TestBreakpoint1000 extends Breakpoint {
-  @override
-  bool isActive(BuildContext context) {
-    return MediaQuery.of(context).size.width >= 1000;
-  }
-}
-
-class NeverOnBreakpoint extends Breakpoint {
-  @override
-  bool isActive(BuildContext context) {
-    return false;
-  }
-}
-
-class TestScaffold extends StatefulWidget {
-  const TestScaffold({
-    super.key,
-    this.initialIndex = 0,
-    this.isAnimated = true,
-  });
-
-  final int initialIndex;
-  final bool isAnimated;
-
-  static const List<NavigationDestination> destinations =
-      <NavigationDestination>[
-    NavigationDestination(
-      key: Key('Inbox'),
-      icon: Icon(Icons.inbox),
-      label: 'Inbox',
-    ),
-    NavigationDestination(
-      key: Key('Articles'),
-      icon: Icon(Icons.article),
-      label: 'Articles',
-    ),
-    NavigationDestination(
-      key: Key('Chat'),
-      icon: Icon(Icons.chat),
-      label: 'Chat',
-    ),
-  ];
-
-  @override
-  State<TestScaffold> createState() => TestScaffoldState();
-}
-
-class TestScaffoldState extends State<TestScaffold> {
-  late int index = widget.initialIndex;
-
-  @override
-  Widget build(BuildContext context) {
-    return AdaptiveScaffold(
-      selectedIndex: index,
-      onSelectedIndexChange: (int index) {
-        setState(() {
-          this.index = index;
-        });
-      },
-      drawerBreakpoint: NeverOnBreakpoint(),
-      internalAnimations: widget.isAnimated,
-      smallBreakpoint: TestBreakpoint0(),
-      mediumBreakpoint: TestBreakpoint800(),
-      largeBreakpoint: TestBreakpoint1000(),
-      destinations: TestScaffold.destinations,
-      smallBody: (_) => Container(color: Colors.red),
-      body: (_) => Container(color: Colors.green),
-      largeBody: (_) => Container(color: Colors.blue),
-      smallSecondaryBody: (_) => Container(color: Colors.red),
-      secondaryBody: (_) => Container(color: Colors.green),
-      largeSecondaryBody: (_) => Container(color: Colors.blue),
-    );
-  }
-}
-
-enum SimulatedLayout {
-  mobile(width: 400, navSlotKey: 'bottomNavigation'),
-  tablet(width: 800, navSlotKey: 'primaryNavigation'),
-  desktop(width: 1100, navSlotKey: 'primaryNavigation1');
-
-  const SimulatedLayout({
-    required double width,
-    required this.navSlotKey,
-  }) : _width = width;
-
-  final double _width;
-  final double _height = 800;
-  final String navSlotKey;
-
-  Size get size => Size(_width, _height);
-
-  MaterialApp app({
-    int initialIndex = 0,
-    bool animations = true,
-  }) {
-    return MaterialApp(
-      home: MediaQuery(
-        data: MediaQueryData(size: size),
-        child: TestScaffold(
-          initialIndex: initialIndex,
-          isAnimated: animations,
-        ),
-      ),
-    );
-  }
-}
diff --git a/packages/flutter_adaptive_scaffold/test/breakpoint_test.dart b/packages/flutter_adaptive_scaffold/test/breakpoint_test.dart
new file mode 100644
index 0000000..9eada7d
--- /dev/null
+++ b/packages/flutter_adaptive_scaffold/test/breakpoint_test.dart
@@ -0,0 +1,54 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'simulated_layout.dart';
+
+void main() {
+  testWidgets('Desktop breakpoints do not show on mobile device',
+      (WidgetTester tester) async {
+    // Pump a small layout on a mobile device. The small slot
+    // should give the mobile slot layout, not the desktop layout.
+    await tester.pumpWidget(SimulatedLayout.small.slot);
+    await tester.pumpAndSettle();
+    expect(find.byKey(const Key('Breakpoints.smallMobile')), findsOneWidget);
+    expect(find.byKey(const Key('Breakpoints.smallDesktop')), findsNothing);
+
+    // Do the same with a medium layout on a mobile
+    await tester.pumpWidget(SimulatedLayout.medium.slot);
+    await tester.pumpAndSettle();
+    expect(find.byKey(const Key('Breakpoints.mediumMobile')), findsOneWidget);
+    expect(find.byKey(const Key('Breakpoints.mediumDesktop')), findsNothing);
+
+    // Large layout on mobile
+    await tester.pumpWidget(SimulatedLayout.large.slot);
+    await tester.pumpAndSettle();
+    expect(find.byKey(const Key('Breakpoints.largeMobile')), findsOneWidget);
+    expect(find.byKey(const Key('Breakpoints.largeDesktop')), findsNothing);
+  }, variant: TargetPlatformVariant.mobile());
+
+  testWidgets('Mobile breakpoints do not show on desktop device',
+      (WidgetTester tester) async {
+    // Pump a small layout on a desktop device. The small slot
+    // should give the mobile slot layout, not the desktop layout.
+    await tester.pumpWidget(SimulatedLayout.small.slot);
+    await tester.pumpAndSettle();
+    expect(find.byKey(const Key('Breakpoints.smallDesktop')), findsOneWidget);
+    expect(find.byKey(const Key('Breakpoints.smallMobile')), findsNothing);
+
+    // Do the same with a medium layout on a desktop
+    await tester.pumpWidget(SimulatedLayout.medium.slot);
+    await tester.pumpAndSettle();
+    expect(find.byKey(const Key('Breakpoints.mediumDesktop')), findsOneWidget);
+    expect(find.byKey(const Key('Breakpoints.mediumMobile')), findsNothing);
+
+    // Large layout on desktop
+    await tester.pumpWidget(SimulatedLayout.large.slot);
+    await tester.pumpAndSettle();
+    expect(find.byKey(const Key('Breakpoints.largeDesktop')), findsOneWidget);
+    expect(find.byKey(const Key('Breakpoints.largeMobile')), findsNothing);
+  }, variant: TargetPlatformVariant.desktop());
+}
diff --git a/packages/flutter_adaptive_scaffold/test/simulated_layout.dart b/packages/flutter_adaptive_scaffold/test/simulated_layout.dart
new file mode 100644
index 0000000..231b6b2
--- /dev/null
+++ b/packages/flutter_adaptive_scaffold/test/simulated_layout.dart
@@ -0,0 +1,176 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/material.dart';
+import 'package:flutter_adaptive_scaffold/flutter_adaptive_scaffold.dart';
+
+import 'test_breakpoints.dart';
+
+AnimatedWidget leftOutIn(Widget child, Animation<double> animation) {
+  return SlideTransition(
+    key: Key('in-${child.key}'),
+    position: Tween<Offset>(
+      begin: const Offset(-1, 0),
+      end: Offset.zero,
+    ).animate(animation),
+    child: child,
+  );
+}
+
+AnimatedWidget leftInOut(Widget child, Animation<double> animation) {
+  return SlideTransition(
+    key: Key('out-${child.key}'),
+    position: Tween<Offset>(
+      begin: Offset.zero,
+      end: const Offset(-1, 0),
+    ).animate(animation),
+    child: child,
+  );
+}
+
+class TestScaffold extends StatefulWidget {
+  const TestScaffold({
+    super.key,
+    this.initialIndex = 0,
+    this.isAnimated = true,
+  });
+
+  final int initialIndex;
+  final bool isAnimated;
+
+  static const List<NavigationDestination> destinations =
+      <NavigationDestination>[
+    NavigationDestination(
+      key: Key('Inbox'),
+      icon: Icon(Icons.inbox),
+      label: 'Inbox',
+    ),
+    NavigationDestination(
+      key: Key('Articles'),
+      icon: Icon(Icons.article),
+      label: 'Articles',
+    ),
+    NavigationDestination(
+      key: Key('Chat'),
+      icon: Icon(Icons.chat),
+      label: 'Chat',
+    ),
+  ];
+
+  @override
+  State<TestScaffold> createState() => TestScaffoldState();
+}
+
+class TestScaffoldState extends State<TestScaffold> {
+  late int index = widget.initialIndex;
+
+  @override
+  Widget build(BuildContext context) {
+    return AdaptiveScaffold(
+      selectedIndex: index,
+      onSelectedIndexChange: (int index) {
+        setState(() {
+          this.index = index;
+        });
+      },
+      drawerBreakpoint: NeverOnBreakpoint(),
+      internalAnimations: widget.isAnimated,
+      smallBreakpoint: TestBreakpoint0(),
+      mediumBreakpoint: TestBreakpoint800(),
+      largeBreakpoint: TestBreakpoint1000(),
+      destinations: TestScaffold.destinations,
+      smallBody: (_) => Container(color: Colors.red),
+      body: (_) => Container(color: Colors.green),
+      largeBody: (_) => Container(color: Colors.blue),
+      smallSecondaryBody: (_) => Container(color: Colors.red),
+      secondaryBody: (_) => Container(color: Colors.green),
+      largeSecondaryBody: (_) => Container(color: Colors.blue),
+    );
+  }
+}
+
+enum SimulatedLayout {
+  small(width: 400, navSlotKey: 'bottomNavigation'),
+  medium(width: 800, navSlotKey: 'primaryNavigation'),
+  large(width: 1100, navSlotKey: 'primaryNavigation1');
+
+  const SimulatedLayout({
+    required double width,
+    required this.navSlotKey,
+  }) : _width = width;
+
+  final double _width;
+  final double _height = 800;
+  final String navSlotKey;
+
+  Size get size => Size(_width, _height);
+
+  MaterialApp app({
+    int initialIndex = 0,
+    bool animations = true,
+  }) {
+    return MaterialApp(
+      home: MediaQuery(
+        data: MediaQueryData(size: size),
+        child: TestScaffold(
+          initialIndex: initialIndex,
+          isAnimated: animations,
+        ),
+      ),
+    );
+  }
+
+  MediaQuery get slot {
+    return MediaQuery(
+      data: MediaQueryData.fromWindow(WidgetsBinding.instance.window)
+          .copyWith(size: Size(_width, _height)),
+      child: Theme(
+        data: ThemeData(),
+        child: Directionality(
+          textDirection: TextDirection.ltr,
+          child: SlotLayout(
+            config: <Breakpoint, SlotLayoutConfig>{
+              Breakpoints.small: SlotLayout.from(
+                key: const Key('Breakpoints.small'),
+                builder: (BuildContext context) => Container(),
+              ),
+              Breakpoints.smallMobile: SlotLayout.from(
+                key: const Key('Breakpoints.smallMobile'),
+                builder: (BuildContext context) => Container(),
+              ),
+              Breakpoints.smallDesktop: SlotLayout.from(
+                key: const Key('Breakpoints.smallDesktop'),
+                builder: (BuildContext context) => Container(),
+              ),
+              Breakpoints.medium: SlotLayout.from(
+                key: const Key('Breakpoints.medium'),
+                builder: (BuildContext context) => Container(),
+              ),
+              Breakpoints.mediumMobile: SlotLayout.from(
+                key: const Key('Breakpoints.mediumMobile'),
+                builder: (BuildContext context) => Container(),
+              ),
+              Breakpoints.mediumDesktop: SlotLayout.from(
+                key: const Key('Breakpoints.mediumDesktop'),
+                builder: (BuildContext context) => Container(),
+              ),
+              Breakpoints.large: SlotLayout.from(
+                key: const Key('Breakpoints.large'),
+                builder: (BuildContext context) => Container(),
+              ),
+              Breakpoints.largeMobile: SlotLayout.from(
+                key: const Key('Breakpoints.largeMobile'),
+                builder: (BuildContext context) => Container(),
+              ),
+              Breakpoints.largeDesktop: SlotLayout.from(
+                key: const Key('Breakpoints.largeDesktop'),
+                builder: (BuildContext context) => Container(),
+              ),
+            },
+          ),
+        ),
+      ),
+    );
+  }
+}
diff --git a/packages/flutter_adaptive_scaffold/test/test_breakpoints.dart b/packages/flutter_adaptive_scaffold/test/test_breakpoints.dart
new file mode 100644
index 0000000..5b3c88c
--- /dev/null
+++ b/packages/flutter_adaptive_scaffold/test/test_breakpoints.dart
@@ -0,0 +1,43 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/widgets.dart';
+import 'package:flutter_adaptive_scaffold/src/breakpoints.dart';
+
+class TestBreakpoint0 extends Breakpoint {
+  @override
+  bool isActive(BuildContext context) {
+    return MediaQuery.of(context).size.width >= 0 &&
+        MediaQuery.of(context).size.width < 800;
+  }
+}
+
+class TestBreakpoint400 extends Breakpoint {
+  @override
+  bool isActive(BuildContext context) {
+    return MediaQuery.of(context).size.width > 400;
+  }
+}
+
+class TestBreakpoint800 extends Breakpoint {
+  @override
+  bool isActive(BuildContext context) {
+    return MediaQuery.of(context).size.width >= 800 &&
+        MediaQuery.of(context).size.width < 1000;
+  }
+}
+
+class TestBreakpoint1000 extends Breakpoint {
+  @override
+  bool isActive(BuildContext context) {
+    return MediaQuery.of(context).size.width >= 1000;
+  }
+}
+
+class NeverOnBreakpoint extends Breakpoint {
+  @override
+  bool isActive(BuildContext context) {
+    return false;
+  }
+}