[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;
+ }
+}