From c8ab2d41ab4f92e711c389a5aeacd508146ba0e7 Mon Sep 17 00:00:00 2001 From: Jim Cook Date: Fri, 12 Apr 2024 11:49:01 -0400 Subject: [PATCH 1/6] Allows for the animation duration to be adjusted using SlotLayout.from() --- .../flutter_adaptive_scaffold/lib/src/slot_layout.dart | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/flutter_adaptive_scaffold/lib/src/slot_layout.dart b/packages/flutter_adaptive_scaffold/lib/src/slot_layout.dart index ce3f5a374c4..72a5e4773cc 100644 --- a/packages/flutter_adaptive_scaffold/lib/src/slot_layout.dart +++ b/packages/flutter_adaptive_scaffold/lib/src/slot_layout.dart @@ -74,12 +74,14 @@ class SlotLayout extends StatefulWidget { WidgetBuilder? builder, Widget Function(Widget, Animation)? inAnimation, Widget Function(Widget, Animation)? outAnimation, + Duration? duration, required Key key, }) => SlotLayoutConfig._( builder: builder, inAnimation: inAnimation, outAnimation: outAnimation, + duration: duration, key: key, ); @@ -96,7 +98,7 @@ class _SlotLayoutState extends State chosenWidget = SlotLayout.pickWidget(context, widget.config); bool hasAnimation = false; return AnimatedSwitcher( - duration: const Duration(milliseconds: 1000), + duration: chosenWidget?.duration ?? const Duration(milliseconds: 1000), layoutBuilder: (Widget? currentChild, List previousChildren) { final Stack elements = Stack( children: [ @@ -137,6 +139,7 @@ class SlotLayoutConfig extends StatelessWidget { required this.builder, this.inAnimation, this.outAnimation, + this.duration, }); /// The child Widget that [SlotLayout] eventually returns with an animation. @@ -160,6 +163,9 @@ class SlotLayoutConfig extends StatelessWidget { /// as the returned widget. final Widget Function(Widget, Animation)? outAnimation; + /// The amount of time taken by the execution of the in and out animations + final Duration? duration; + /// An empty [SlotLayoutConfig] to be placed in a slot to indicate that the slot /// should show nothing. static SlotLayoutConfig empty() { From ac390eeb77695d0ac673a285ae7a8c78b6e55f6b Mon Sep 17 00:00:00 2001 From: Jim Cook Date: Fri, 12 Apr 2024 12:08:35 -0400 Subject: [PATCH 2/6] Updated the pubspec and changelog according to PR requirements --- packages/flutter_adaptive_scaffold/CHANGELOG.md | 5 +++++ packages/flutter_adaptive_scaffold/pubspec.yaml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/flutter_adaptive_scaffold/CHANGELOG.md b/packages/flutter_adaptive_scaffold/CHANGELOG.md index 065983360e9..df5b798ad2e 100644 --- a/packages/flutter_adaptive_scaffold/CHANGELOG.md +++ b/packages/flutter_adaptive_scaffold/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.1.11 + +* Allows custom animation duration for the NavigationRail and + BottomNavigationBar transitions. [flutter/flutter#112938](https://github.com/flutter/flutter/issues/112938) + ## 0.1.10+1 * Removes a broken design document link from the README. diff --git a/packages/flutter_adaptive_scaffold/pubspec.yaml b/packages/flutter_adaptive_scaffold/pubspec.yaml index cd322d41d2a..d1519465c9f 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.1.10+1 +version: 0.1.11 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 From 4d7259c0399a5fa9efec956a6c0140e78e60ddab Mon Sep 17 00:00:00 2001 From: Jim Cook Date: Fri, 12 Apr 2024 15:03:32 -0400 Subject: [PATCH 3/6] Added tests to ensure the animation duration can be configured and impacts the animation speed --- .../test/adaptive_layout_test.dart | 50 +++++++++++++------ 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/packages/flutter_adaptive_scaffold/test/adaptive_layout_test.dart b/packages/flutter_adaptive_scaffold/test/adaptive_layout_test.dart index 5924f0a8a74..c7483ff5624 100644 --- a/packages/flutter_adaptive_scaffold/test/adaptive_layout_test.dart +++ b/packages/flutter_adaptive_scaffold/test/adaptive_layout_test.dart @@ -120,11 +120,11 @@ void main() { testWidgets( 'slot layout properly switches between items with the appropriate animation', (WidgetTester tester) async { - await tester.pumpWidget(slot(300, tester)); + await tester.pumpWidget(slot(300, 1000, tester)); expect(begin, findsOneWidget); expect(end, findsNothing); - await tester.pumpWidget(slot(500, tester)); + await tester.pumpWidget(slot(500, 1000, tester)); await tester.pump(); await tester.pump(const Duration(milliseconds: 500)); expect(tester.widget(slideOut('0')).position.value, @@ -146,7 +146,7 @@ void main() { testWidgets('AnimatedSwitcher does not spawn duplicate keys on rapid resize', (WidgetTester tester) async { // Populate the smaller slot layout and let the animation settle. - await tester.pumpWidget(slot(300, tester)); + await tester.pumpWidget(slot(300, 1000, tester)); await tester.pumpAndSettle(); expect(begin, findsOneWidget); expect(end, findsNothing); @@ -157,12 +157,12 @@ void main() { for (int i = 0; i < 2; i++) { // Resize between the two slot layouts, but do not pump the animation // until completion. - await tester.pumpWidget(slot(500, tester)); + await tester.pumpWidget(slot(500, 1000, tester)); await tester.pump(const Duration(milliseconds: 100)); expect(begin, findsOneWidget); expect(end, findsOneWidget); - await tester.pumpWidget(slot(300, tester)); + await tester.pumpWidget(slot(300, 1000, tester)); await tester.pump(const Duration(milliseconds: 100)); expect(begin, findsOneWidget); expect(end, findsOneWidget); @@ -171,18 +171,18 @@ void main() { testWidgets('slot layout can tolerate rapid changes in breakpoints', (WidgetTester tester) async { - await tester.pumpWidget(slot(300, tester)); + await tester.pumpWidget(slot(300, 1000, tester)); expect(begin, findsOneWidget); expect(end, findsNothing); - await tester.pumpWidget(slot(500, tester)); + await tester.pumpWidget(slot(500, 1000, tester)); await tester.pump(); await tester.pump(const Duration(milliseconds: 100)); expect(tester.widget(slideOut('0')).position.value, offsetMoreOrLessEquals(const Offset(-0.1, 0), epsilon: 0.05)); expect(tester.widget(slideIn('400')).position.value, offsetMoreOrLessEquals(const Offset(-0.9, 0), epsilon: 0.05)); - await tester.pumpWidget(slot(300, tester)); + await tester.pumpWidget(slot(300, 1000, tester)); await tester.pumpAndSettle(); expect(begin, findsOneWidget); expect(end, findsNothing); @@ -243,11 +243,33 @@ void main() { tester.getBottomRight(secondaryTestBreakpoint), const Offset(390, 790)); }); + testWidgets('adaptive layout can adjust animation duration', + (WidgetTester tester) async { + // Populate the smaller slot layout and let the animation settle. + await tester.pumpWidget(slot(300, 100, tester)); + await tester.pumpAndSettle(); + expect(begin, findsOneWidget); + expect(end, findsNothing); + + // expand in 1/5 second + await tester.pumpWidget(slot(500, 200, tester)); + + // after 100ms, we expect both widgets to be present + await tester.pump(const Duration(milliseconds: 50)); + expect(begin, findsOneWidget); + expect(end, findsOneWidget); + + // After 1/5 second, all animations should be done + await tester.pump(const Duration(milliseconds: 200)); + expect(begin, findsNothing); + expect(end, findsOneWidget); + + await tester.pumpAndSettle(); + }); + testWidgets('adaptive layout does not animate when animations off', (WidgetTester tester) async { final Finder testBreakpoint = find.byKey(const Key('Test Breakpoint')); - final Finder secondaryTestBreakpoint = - find.byKey(const Key('Secondary Test Breakpoint')); await tester.pumpWidget( await layout(width: 400, tester: tester, animations: false)); @@ -257,9 +279,6 @@ void main() { expect(tester.getTopLeft(testBreakpoint), const Offset(10, 10)); expect(tester.getBottomRight(testBreakpoint), const Offset(200, 790)); - expect(tester.getTopLeft(secondaryTestBreakpoint), const Offset(200, 10)); - expect( - tester.getBottomRight(secondaryTestBreakpoint), const Offset(390, 790)); }); } @@ -306,6 +325,7 @@ Future layout({ TextDirection directionality = TextDirection.ltr, double? bodyRatio, bool animations = true, + int durationMs = 1000, }) async { await tester.binding.setSurfaceSize(Size(width, 800)); return MediaQuery( @@ -415,7 +435,7 @@ AnimatedWidget leftInOut(Widget child, Animation animation) { ); } -MediaQuery slot(double width, WidgetTester tester) { +MediaQuery slot(double width, int durationMs, WidgetTester tester) { return MediaQuery( data: MediaQueryData.fromView(tester.view).copyWith(size: Size(width, 800)), child: Directionality( @@ -425,12 +445,14 @@ MediaQuery slot(double width, WidgetTester tester) { TestBreakpoint0(): SlotLayout.from( inAnimation: leftOutIn, outAnimation: leftInOut, + duration: Duration(milliseconds: durationMs), key: const Key('0'), builder: (_) => const SizedBox(width: 10, height: 10), ), TestBreakpoint400(): SlotLayout.from( inAnimation: leftOutIn, outAnimation: leftInOut, + duration: Duration(milliseconds: durationMs), key: const Key('400'), builder: (_) => const SizedBox(width: 10, height: 10), ), From c1d0f3ce924db9ee84884070e75e3c9b382c8db2 Mon Sep 17 00:00:00 2001 From: Jim Cook Date: Wed, 29 May 2024 10:48:04 -0400 Subject: [PATCH 4/6] Made requested changes from the PR --- .../lib/src/slot_layout.dart | 2 +- .../test/adaptive_layout_test.dart | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/packages/flutter_adaptive_scaffold/lib/src/slot_layout.dart b/packages/flutter_adaptive_scaffold/lib/src/slot_layout.dart index 72a5e4773cc..38789fb8660 100644 --- a/packages/flutter_adaptive_scaffold/lib/src/slot_layout.dart +++ b/packages/flutter_adaptive_scaffold/lib/src/slot_layout.dart @@ -163,7 +163,7 @@ class SlotLayoutConfig extends StatelessWidget { /// as the returned widget. final Widget Function(Widget, Animation)? outAnimation; - /// The amount of time taken by the execution of the in and out animations + /// The amount of time taken by the execution of the in and out animations. final Duration? duration; /// An empty [SlotLayoutConfig] to be placed in a slot to indicate that the slot diff --git a/packages/flutter_adaptive_scaffold/test/adaptive_layout_test.dart b/packages/flutter_adaptive_scaffold/test/adaptive_layout_test.dart index c7483ff5624..eec22365a8f 100644 --- a/packages/flutter_adaptive_scaffold/test/adaptive_layout_test.dart +++ b/packages/flutter_adaptive_scaffold/test/adaptive_layout_test.dart @@ -120,11 +120,13 @@ void main() { testWidgets( 'slot layout properly switches between items with the appropriate animation', (WidgetTester tester) async { - await tester.pumpWidget(slot(300, 1000, tester)); + await tester + .pumpWidget(slot(300, const Duration(milliseconds: 1000), tester)); expect(begin, findsOneWidget); expect(end, findsNothing); - await tester.pumpWidget(slot(500, 1000, tester)); + await tester + .pumpWidget(slot(500, const Duration(milliseconds: 1000), tester)); await tester.pump(); await tester.pump(const Duration(milliseconds: 500)); expect(tester.widget(slideOut('0')).position.value, @@ -251,15 +253,15 @@ void main() { expect(begin, findsOneWidget); expect(end, findsNothing); - // expand in 1/5 second + // expand in 1/5 second. await tester.pumpWidget(slot(500, 200, tester)); - // after 100ms, we expect both widgets to be present + // after 100ms, we expect both widgets to be present. await tester.pump(const Duration(milliseconds: 50)); expect(begin, findsOneWidget); expect(end, findsOneWidget); - // After 1/5 second, all animations should be done + // After 1/5 second, all animations should be done. await tester.pump(const Duration(milliseconds: 200)); expect(begin, findsNothing); expect(end, findsOneWidget); @@ -435,7 +437,7 @@ AnimatedWidget leftInOut(Widget child, Animation animation) { ); } -MediaQuery slot(double width, int durationMs, WidgetTester tester) { +MediaQuery slot(double width, Duration duration, WidgetTester tester) { return MediaQuery( data: MediaQueryData.fromView(tester.view).copyWith(size: Size(width, 800)), child: Directionality( @@ -445,14 +447,14 @@ MediaQuery slot(double width, int durationMs, WidgetTester tester) { TestBreakpoint0(): SlotLayout.from( inAnimation: leftOutIn, outAnimation: leftInOut, - duration: Duration(milliseconds: durationMs), + duration: duration, key: const Key('0'), builder: (_) => const SizedBox(width: 10, height: 10), ), TestBreakpoint400(): SlotLayout.from( inAnimation: leftOutIn, outAnimation: leftInOut, - duration: Duration(milliseconds: durationMs), + duration: duration, key: const Key('400'), builder: (_) => const SizedBox(width: 10, height: 10), ), From f5da939327229378f0081e7864bce47e4ef739bb Mon Sep 17 00:00:00 2001 From: Jim Cook Date: Mon, 24 Jun 2024 13:16:12 -0400 Subject: [PATCH 5/6] Ensuring tests and analyze pass. Using 0.1.11+1 as new version number --- packages/flutter_adaptive_scaffold/pubspec.yaml | 2 +- .../test/adaptive_layout_test.dart | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/flutter_adaptive_scaffold/pubspec.yaml b/packages/flutter_adaptive_scaffold/pubspec.yaml index ed61991cf35..c3815b4abf3 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.1.11 +version: 0.1.11+1 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_layout_test.dart b/packages/flutter_adaptive_scaffold/test/adaptive_layout_test.dart index eec22365a8f..a2b73b01d18 100644 --- a/packages/flutter_adaptive_scaffold/test/adaptive_layout_test.dart +++ b/packages/flutter_adaptive_scaffold/test/adaptive_layout_test.dart @@ -148,7 +148,7 @@ void main() { testWidgets('AnimatedSwitcher does not spawn duplicate keys on rapid resize', (WidgetTester tester) async { // Populate the smaller slot layout and let the animation settle. - await tester.pumpWidget(slot(300, 1000, tester)); + await tester.pumpWidget(slot(300, const Duration(seconds: 1), tester)); await tester.pumpAndSettle(); expect(begin, findsOneWidget); expect(end, findsNothing); @@ -159,12 +159,12 @@ void main() { for (int i = 0; i < 2; i++) { // Resize between the two slot layouts, but do not pump the animation // until completion. - await tester.pumpWidget(slot(500, 1000, tester)); + await tester.pumpWidget(slot(500, const Duration(seconds: 1), tester)); await tester.pump(const Duration(milliseconds: 100)); expect(begin, findsOneWidget); expect(end, findsOneWidget); - await tester.pumpWidget(slot(300, 1000, tester)); + await tester.pumpWidget(slot(300, const Duration(seconds: 1), tester)); await tester.pump(const Duration(milliseconds: 100)); expect(begin, findsOneWidget); expect(end, findsOneWidget); @@ -173,18 +173,18 @@ void main() { testWidgets('slot layout can tolerate rapid changes in breakpoints', (WidgetTester tester) async { - await tester.pumpWidget(slot(300, 1000, tester)); + await tester.pumpWidget(slot(300, const Duration(seconds: 1), tester)); expect(begin, findsOneWidget); expect(end, findsNothing); - await tester.pumpWidget(slot(500, 1000, tester)); + await tester.pumpWidget(slot(500, const Duration(seconds: 1), tester)); await tester.pump(); await tester.pump(const Duration(milliseconds: 100)); expect(tester.widget(slideOut('0')).position.value, offsetMoreOrLessEquals(const Offset(-0.1, 0), epsilon: 0.05)); expect(tester.widget(slideIn('400')).position.value, offsetMoreOrLessEquals(const Offset(-0.9, 0), epsilon: 0.05)); - await tester.pumpWidget(slot(300, 1000, tester)); + await tester.pumpWidget(slot(300, const Duration(seconds: 1), tester)); await tester.pumpAndSettle(); expect(begin, findsOneWidget); expect(end, findsNothing); @@ -248,13 +248,13 @@ void main() { testWidgets('adaptive layout can adjust animation duration', (WidgetTester tester) async { // Populate the smaller slot layout and let the animation settle. - await tester.pumpWidget(slot(300, 100, tester)); + await tester.pumpWidget(slot(300, const Duration(milliseconds: 100), tester)); await tester.pumpAndSettle(); expect(begin, findsOneWidget); expect(end, findsNothing); // expand in 1/5 second. - await tester.pumpWidget(slot(500, 200, tester)); + await tester.pumpWidget(slot(500, const Duration(milliseconds: 200), tester)); // after 100ms, we expect both widgets to be present. await tester.pump(const Duration(milliseconds: 50)); From d49bb8b8840d910e14a997c6cfba6b2b8d91ead9 Mon Sep 17 00:00:00 2001 From: Jim Cook Date: Mon, 24 Jun 2024 13:31:46 -0400 Subject: [PATCH 6/6] Fixed file formatting --- .../test/adaptive_layout_test.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/flutter_adaptive_scaffold/test/adaptive_layout_test.dart b/packages/flutter_adaptive_scaffold/test/adaptive_layout_test.dart index a2b73b01d18..3166e5b382d 100644 --- a/packages/flutter_adaptive_scaffold/test/adaptive_layout_test.dart +++ b/packages/flutter_adaptive_scaffold/test/adaptive_layout_test.dart @@ -248,13 +248,15 @@ void main() { testWidgets('adaptive layout can adjust animation duration', (WidgetTester tester) async { // Populate the smaller slot layout and let the animation settle. - await tester.pumpWidget(slot(300, const Duration(milliseconds: 100), tester)); + await tester + .pumpWidget(slot(300, const Duration(milliseconds: 100), tester)); await tester.pumpAndSettle(); expect(begin, findsOneWidget); expect(end, findsNothing); // expand in 1/5 second. - await tester.pumpWidget(slot(500, const Duration(milliseconds: 200), tester)); + await tester + .pumpWidget(slot(500, const Duration(milliseconds: 200), tester)); // after 100ms, we expect both widgets to be present. await tester.pump(const Duration(milliseconds: 50));