1. 29 Nov, 2023 2 commits
  2. 28 Nov, 2023 1 commit
    • Nate's avatar
      Implement `switch` expressions in `dev/` (#139048) · 3267fbc0
      Nate authored
      I previously made a PR (#136140) that used `switch` expressions to make some parts of the Flutter codebase easier to understand. It was assigned to the framework team, and @christopherfujino let me know that it was too large to effectively review and recommended breaking it up into smaller pull requests.
      
      Here's a PR that only targets files in the `dev/` directory. Hopefully this will be easier to work with!
      
      (solves issue https://github.com/flutter/flutter/issues/136139)
      3267fbc0
  3. 03 Nov, 2023 1 commit
  4. 17 Aug, 2023 2 commits
  5. 08 Aug, 2023 1 commit
  6. 04 Aug, 2023 1 commit
    • Justin McCandless's avatar
      Predictive back support for root routes (#120385) · dedd100e
      Justin McCandless authored
      This PR aims to support Android's predictive back gesture when popping the entire Flutter app.  Predictive route transitions between routes inside of a Flutter app will come later.
      
      <img width="200" src="https://user-images.githubusercontent.com/389558/217918109-945febaa-9086-41cc-a476-1a189c7831d8.gif" />
      
      ### Trying it out
      
      If you want to try this feature yourself, here are the necessary steps:
      
        1. Run Android 33 or above.
        1. Enable the feature flag for predictive back on the device under "Developer
           options".
        1. Create a Flutter project, or clone [my example project](https://github.com/justinmc/flutter_predictive_back_examples).
        1. Set `android:enableOnBackInvokedCallback="true"` in
           android/app/src/main/AndroidManifest.xml (already done in the example project).
        1. Check out this branch.
        1. Run the app. Perform a back gesture (swipe from the left side of the
           screen).
      
      You should see the predictive back animation like in the animation above and be able to commit or cancel it.
      
      ### go_router support
      
      go_router works with predictive back out of the box because it uses a Navigator internally that dispatches NavigationNotifications!
      
      ~~go_router can be supported by adding a listener to the router and updating SystemNavigator.setFrameworkHandlesBack.~~
      
      Similar to with nested Navigators, nested go_routers is supported by using a PopScope widget.
      
      <details>
      
      <summary>Full example of nested go_routers</summary>
      
      ```dart
      // Copyright 2014 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:go_router/go_router.dart';
      
      import 'package:flutter/material.dart';
      import 'package:flutter/scheduler.dart';
      
      void main() => runApp(_MyApp());
      
      class _MyApp extends StatelessWidget {
        final GoRouter router = GoRouter(
          routes: <RouteBase>[
            GoRoute(
              path: '/',
              builder: (BuildContext context, GoRouterState state) => _HomePage(),
            ),
            GoRoute(
              path: '/nested_navigators',
              builder: (BuildContext context, GoRouterState state) => _NestedGoRoutersPage(),
            ),
          ],
        );
      
        @override
        Widget build(BuildContext context) {
          return MaterialApp.router(
            routerConfig: router,
          );
        }
      }
      
      class _HomePage extends StatelessWidget {
        @override
        Widget build(BuildContext context) {
          return Scaffold(
            appBar: AppBar(
              title: const Text('Nested Navigators Example'),
            ),
            body: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  const Text('Home Page'),
                  const Text('A system back gesture here will exit the app.'),
                  const SizedBox(height: 20.0),
                  ListTile(
                    title: const Text('Nested go_router route'),
                    subtitle: const Text('This route has another go_router in addition to the one used with MaterialApp above.'),
                    onTap: () {
                      context.push('/nested_navigators');
                    },
                  ),
                ],
              ),
            ),
          );
        }
      }
      
      class _NestedGoRoutersPage extends StatefulWidget {
        @override
        State<_NestedGoRoutersPage> createState() => _NestedGoRoutersPageState();
      }
      
      class _NestedGoRoutersPageState extends State<_NestedGoRoutersPage> {
        late final GoRouter _router;
        final GlobalKey<NavigatorState> _nestedNavigatorKey = GlobalKey<NavigatorState>();
      
        // If the nested navigator has routes that can be popped, then we want to
        // block the root navigator from handling the pop so that the nested navigator
        // can handle it instead.
        bool get _popEnabled {
          // canPop will throw an error if called before build. Is this the best way
          // to avoid that?
          return _nestedNavigatorKey.currentState == null ? true : !_router.canPop();
        }
      
        void _onRouterChanged() {
          // Here the _router reports the location correctly, but canPop is still out
          // of date.  Hence the post frame callback.
          SchedulerBinding.instance.addPostFrameCallback((Duration duration) {
            setState(() {});
          });
        }
      
        @override
        void initState() {
          super.initState();
      
          final BuildContext rootContext = context;
          _router = GoRouter(
            navigatorKey: _nestedNavigatorKey,
            routes: [
              GoRoute(
                path: '/',
                builder: (BuildContext context, GoRouterState state) => _LinksPage(
                  title: 'Nested once - home route',
                  backgroundColor: Colors.indigo,
                  onBack: () {
                    rootContext.pop();
                  },
                  buttons: <Widget>[
                    TextButton(
                      onPressed: () {
                        context.push('/two');
                      },
                      child: const Text('Go to another route in this nested Navigator'),
                    ),
                  ],
                ),
              ),
              GoRoute(
                path: '/two',
                builder: (BuildContext context, GoRouterState state) => _LinksPage(
                  backgroundColor: Colors.indigo.withBlue(255),
                  title: 'Nested once - page two',
                ),
              ),
            ],
          );
      
          _router.addListener(_onRouterChanged);
        }
      
        @override
        void dispose() {
          _router.removeListener(_onRouterChanged);
          super.dispose();
        }
      
        @override
        Widget build(BuildContext context) {
          return PopScope(
            popEnabled: _popEnabled,
            onPopped: (bool success) {
              if (success) {
                return;
              }
              _router.pop();
            },
            child: Router<Object>.withConfig(
              restorationScopeId: 'router-2',
              config: _router,
            ),
          );
        }
      }
      
      class _LinksPage extends StatelessWidget {
        const _LinksPage ({
          required this.backgroundColor,
          this.buttons = const <Widget>[],
          this.onBack,
          required this.title,
        });
      
        final Color backgroundColor;
        final List<Widget> buttons;
        final VoidCallback? onBack;
        final String title;
      
        @override
        Widget build(BuildContext context) {
          return Scaffold(
            backgroundColor: backgroundColor,
            body: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Text(title),
                  //const Text('A system back here will go back to Nested Navigators Page One'),
                  ...buttons,
                  TextButton(
                    onPressed: onBack ?? () {
                      context.pop();
                    },
                    child: const Text('Go back'),
                  ),
                ],
              ),
            ),
          );
        }
      }
      ```
      
      </details>
      
      ### Resources
      
      Fixes https://github.com/flutter/flutter/issues/109513
      Depends on engine PR https://github.com/flutter/engine/pull/39208 :heavy_check_mark: 
      Design doc: https://docs.google.com/document/d/1BGCWy1_LRrXEB6qeqTAKlk-U2CZlKJ5xI97g45U7azk/edit#
      Migration guide: https://github.com/flutter/website/pull/8952
      dedd100e
  7. 24 Jul, 2023 1 commit
  8. 17 Jul, 2023 1 commit
    • LongCatIsLooong's avatar
      Replaces `textScaleFactor` with `TextScaler` (#128522) · b2e22d35
      LongCatIsLooong authored
      Deprecate `textScaleFactor` in favor of `textScaler`, in preparation for Android 14 [Non-linear font scaling to 200%](https://developer.android.com/about/versions/14/features#non-linear-font-scaling). The `TextScaler` class can be moved to `dart:ui` in the future, if we decide to use the Android platform API or AndroidX to get the scaling curve instead of hard coding the curve in the framework.
      
      I haven't put the Flutter version in the deprecation message so the analyzer checks are failing. Will do so after I finish the migration guide.
      
      **Why `TextScaler.textScaleFactor`**
      The author of a `TextScaler` subclass should provide a fallback `textScaleFactor`. By making `TextScaler` also contain the `textScaleFactor` information it also makes it easier to migrate: if a widget overrides `MediaQueryData.textScaler` in the tree, for unmigrated widgets in the subtree it would also have to override `MediaQueryData.textScaleFactor`, and that makes it difficult to remove `MediaQueryData.textScaleFactor` in the future.
      
      ## A full list of affected APIs in this PR
      
      Deprecated: The method/getter/setter/argument is annotated with a `@Deprecated()` annotation in this PR, and the caller should replace it with `textScaler` instead. Unless otherwise specified there will be a Flutter fix available to help with migration but it's still recommended to migrate case-by-case.
      **Replaced**:  The method this `textScaleFactor` argument belongs to is rarely called directly by user code and is not overridden by any of the registered custom tests, so the argument is directly replaced by `TextScaler`.
      **To Be Deprecated**:  The method/getter/setter/argument can't be deprecated in this PR because a registered customer test depends on it and a Flutter fix isn't available (or the test was run without applying flutter fixes first). This method/getter/setter/argument will be deprecated in a followup PR once the registered test is migrated.
      
      ### `Painting` Library
      
      | Affected API | State of `textScaleFactor` | Comment | 
      | --- | --- | --- |
      | `InlineSpan.build({ double textScaleFactor = 1.0 })` argument | **Replaced** | | 
      | `TextStyle.getParagraphStyle({ double TextScaleFactor = 1.0 })` argument | **Replaced** | |
      | `TextStyle.getTextStyle({ double TextScaleFactor = 1.0 })`  argument| Deprecated | Can't replace: https://github.com/superlistapp/super_editor/blob/c47fd38dca4b7f43611690913b551a1773c563d7/super_editor/lib/src/infrastructure/super_textfield/desktop/desktop_textfield.dart#L1903-L1905|
      | `TextPainter({ double TextScaleFactor = 1.0 })` constructor argument | Deprecated | |
      | `TextPainter.textScaleFactor` getter and setter | Deprecated | No Flutter Fix, not expressible yet |
      | `TextPainter.computeWidth({ double TextScaleFactor = 1.0 })` argument | Deprecated | |
      | `TextPainter.computeMaxIntrinsicWidth({ double TextScaleFactor = 1.0 })` argument | Deprecated | |
      
      ### `Rendering` Library
      
      | Affected API | State of `textScaleFactor` | Comment | 
      | --- | --- | --- |
      | `RenderEditable({ double TextScaleFactor = 1.0 })` constructor argument | Deprecated | |
      | `RenderEditable.textScaleFactor` getter and setter | Deprecated | No Flutter Fix, not expressible yet |
      | `RenderParagraph({ double TextScaleFactor = 1.0 })` constructor argument | Deprecated | |
      | `RenderParagraph.textScaleFactor` getter and setter | Deprecated | No Flutter Fix, not expressible yet |
      
      ### `Widgets` Library
      
      | Affected API | State of `textScaleFactor` | Comment | 
      | --- | --- | --- |
      | `MediaQueryData({ double TextScaleFactor = 1.0 })` constructor argument | **To Be Deprecated** | https://github.com/flutter/packages/blob/cd7b93532e5cb605a42735e20f1de70fc00adae7/packages/flutter_markdown/test/text_scale_factor_test.dart#LL39C21-L39C35 |
      | `MediaQueryData.textScaleFactor` getter | Deprecated | |
      | `MediaQueryData.copyWith({ double? TextScaleFactor })` argument | Deprecated | |
      | `MediaQuery.maybeTextScaleFactorOf(BuildContext context)` static method | Deprecated | No Flutter Fix, not expressible yet  |
      | `MediaQuery.textScaleFactorOf(BuildContext context)` static method | **To Be Deprecated** | https://github.com/flutter/packages/blob/cd7b93532e5cb605a42735e20f1de70fc00adae7/packages/flutter_markdown/lib/src/_functions_io.dart#L68-L70, No Flutter Fix, not expressible yet |
      | `RichText({ double TextScaleFactor = 1.0 })` constructor argument | **To Be Deprecated** | https://github.com/flutter/packages/blob/cd7b93532e5cb605a42735e20f1de70fc00adae7/packages/flutter_markdown/lib/src/builder.dart#L829-L843 |
      | `RichText.textScaleFactor` getter | **To Be Deprecated** | A constructor argument can't be deprecated right away|
      | `Text({ double? TextScaleFactor = 1.0 })` constructor argument | **To Be Deprecated** | https://github.com/flutter/packages/blob/914d120da12fba458c020210727831c31bd71041/packages/rfw/lib/src/flutter/core_widgets.dart#L647 , No Flutter Fix because of https://github.com/dart-lang/sdk/issues/52664 |
      | `Text.rich({ double? TextScaleFactor = 1.0 })` constructor argument | **To Be Deprecated** | The default constructor has an argument that can't be deprecated right away. No Flutter Fix because of https://github.com/dart-lang/sdk/issues/52664 |
      | `Text.textScaleFactor` getter | **To Be Deprecated** | A constructor argument can't be deprecated right away |
      | `EditableText({ double? TextScaleFactor = 1.0 })` constructor argument | Deprecated | No Flutter Fix because of https://github.com/dart-lang/sdk/issues/52664 |
      | `EditableText.textScaleFactor` getter | Deprecated | |
      
      ### `Material` Library
      
      | Affected API | State of `textScaleFactor` | Comment | 
      | --- | --- | --- |
      | `SelectableText({ double? TextScaleFactor = 1.0 })` constructor argument | **To Be Deprecated** | https://github.com/flutter/packages/blob/cd7b93532e5cb605a42735e20f1de70fc00adae7/packages/flutter_markdown/lib/src/builder.dart#L829-L843, No Flutter Fix because of https://github.com/dart-lang/sdk/issues/52664 |
      | `SelectableText.rich({ double? TextScaleFactor = 1.0 })` constructor argument | **To Be Deprecated** | The default constructor has an argument that can't be deprecated right away. No Flutter Fix because of https://github.com/dart-lang/sdk/issues/52664 |
      | `SelectableText.textScaleFactor` getter | **To Be Deprecated** | A constructor argument can't be deprecated right away |
      
      A lot of material widgets (`Slider`, `RangeSlider`, `TimePicker`, and different types of buttons) also change their layout based on `textScaleFactor`. These need to be handled in a case-by-case fashion and will be migrated in follow-up PRs.
      b2e22d35
  9. 28 Jun, 2023 1 commit
  10. 09 Jun, 2023 1 commit
  11. 15 May, 2023 1 commit
  12. 23 Mar, 2023 1 commit
  13. 22 Mar, 2023 1 commit
  14. 23 Feb, 2023 1 commit
  15. 02 Feb, 2023 1 commit
  16. 03 Jan, 2023 1 commit
  17. 27 Dec, 2022 1 commit
  18. 22 Dec, 2022 1 commit
  19. 20 Dec, 2022 1 commit
  20. 31 Oct, 2022 1 commit
  21. 06 Sep, 2022 1 commit
  22. 02 Sep, 2022 2 commits
  23. 22 Aug, 2022 1 commit
  24. 28 Jul, 2022 1 commit
  25. 22 Jun, 2022 1 commit
  26. 09 Jun, 2022 1 commit
  27. 31 May, 2022 1 commit
  28. 13 May, 2022 1 commit
  29. 06 May, 2022 1 commit
  30. 28 Apr, 2022 1 commit
  31. 28 Mar, 2022 1 commit
  32. 04 Mar, 2022 1 commit
  33. 22 Feb, 2022 1 commit
  34. 13 Jan, 2022 1 commit
  35. 10 Dec, 2021 1 commit
  36. 23 Nov, 2021 1 commit
  37. 11 Oct, 2021 1 commit