text:
Overflow warnings are impossible to disable

Problem
There are often times where we intentionally have overflow by design (example below).
Although this will look fine in production, this spamming of the console, and on-screen clutter negatively impacts developer productivity.
This is disruptive to development because it prevents you from clearly seeing the UI you are working on. You can switch to profile mode, but then you lose the ability for hot reload. Further, Android Simulator does not support profile mode.
It also confuses team members who report errors / log bugs, when they spot overflow in the console, when it was intentional by another developer. Causing a lot of wasted time and repetitive discussions.
Essentially feels like we are fighting the framework here, and it won't co-operate with what we want to do.
Possible Solution
It would be nice if the developer had the option to tell a parent not throw overflow errors at specific points in the tree.
The idea is not to disable Overflow warnings globally, but to tell specific sub-trees to not display an error.
OR
The framework could properly detect when ClipRect is applied, and then not throw the warning. Currently while it  does tell you do add a ClipRect, this seems to have no effect on whether the warning is thrown or not.
Example 1
Here we have a panel that, when child is changed, it will size itself to match that child. This requires that, when changing children, some of the content is temporarily clipped. By design.
https://user-images.githubusercontent.com/736973/160184624-4c1c176d-9460-4452-8ae4-8c5f1c4fbd14.mp4
Example on dartpad here: https://dartpad.dev/?id=8879b345a2f5eef780fa4840c3a4be30
Gist: https://gist.github.com/esDotDev/8879b345a2f5eef780fa4840c3a4be30
Resulting in this error:

The suggested fixes of adding a ClipRect or a ListView are not desired. A ClipRect is already in place in the parent, and a ListView is not desired as it adds a ton of complications and potential bugs, to an otherwise simple implementation.
Example 2
In another situation, we have a visual decorator that is already clipped (otherwise the effect wouldn't work), and we want to spin the circle around, to reveal another title, while the previous title is clipped out of view.

Again the framework decides it knows best, and aggressively tells us we're doing something wrong, when this really a nice elegant approach, and overdraw is minimal (and clipped regardless, as you can see)
You can also see how this blocks me from seeing the top or bottom of the widget, actively slowing down my development, and preventing me from seeing potential errors.
Example 3
Here we use an animated container to hide or reveal a child widget. Normally the child would scale-down here, but our design would prefer that the widget keep its natural size, and instead be cropped out of view.

This can be done simply and robustly with something like:
AnimatedContainer(
  width: _isOpen: 60 : 0,
  child: ClipRect(
      child: UnconstrainedBox(
         child: FlutterLogo(50);
      )))

But again, the overflow error blocks us from really seeing the finer pts of the animation, unless we run in profile mode. Also weird how we are usng a ClipRect, but the framework complains we should be using a ClipRect.

Hi @esDotDev, thanks for filing the issue, I believe you are trying to hide the errors shown from the Flutter framework, I believe onError can help you to handle the custom error.
Please take a look at the below code sample which just prints to the console when the overflow error occurs.

code sample
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
  FlutterError.onError = (FlutterErrorDetails details) {
    print('flutter error hidden from console');
    // FlutterError.dumpErrorToConsole(details, forceReport: false);
  };
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: PageOne(),
    );
  }
}

class PageOne extends StatelessWidget {
  const PageOne({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          for (int i = 0; i < 100; i++) Text('$i'),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        child: const Icon(Icons.add),
        onPressed: () {},
      ),
    );
  }
}

class PageTwo extends StatelessWidget {
  const PageTwo({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Builder(builder: (context) {
        return Center(
          child: ElevatedButton(
            child: const Text('Show SnackBar'),
            onPressed: () {
              ScaffoldMessenger.of(context).showSnackBar(
                const SnackBar(
                  content: Text('SnackBar!'),
                  behavior: SnackBarBehavior.floating,
                ),
              );
            },
          ),
        );
      }),
    );
  }
}

It's actually quite disruptive to development. I either have these giant yellow bars that stop me from accurately dialing in my UI, or I am forced to run it in profile mode, which disables hot-reload, also preventing me from efficiently working on the UI.

Thanks for the info, Labelling this issue for further insights from the team.

Thanks for the info, Labelling this issue for further insights from the team.

Thx! I have updated the original post to include a running example on dartpad:
https://dartpad.dev/?id=8879b345a2f5eef780fa4840c3a4be30

Hello @esDotDev. Thumbs up for this issue.  I have a use case too. I want to use UnconstrainedBox without overflow warnings (not in the console nor on screen).
In the source code it says:
  /// Creates a widget that imposes no constraints on its child, allowing it to
  /// render at its "natural" size. If the child overflows the parents
  /// constraints, a warning will be given in debug mode.

I intentionally use it so that a child widget can be rendered at its natural size.
That child widget has a parent and the width of the parent can be changed. In this case, I want to decrease the parent size and it should act like a masking widget that masks the natural-sized child widget.

As you can see, the overflow warning is shown no matter I do: a warning will be given in debug mode

@esDotDev Oh if it is solved then it is ok to close the issue. I can open another but would you mind showing a snippet of how OverflowBox solved the Example 3?
I had quite a lot of experiments with OverflowBox but couldn't make it work.
Thanks for your help :)

For any child that will overflow, you should be able to do this?
OverflowBox(
  maxWidth: double.infinity,
  maxHeight: double.infinity,
  child: someHugeChild,
)

Oh, that didn't work. Because the OverflowBox needs constraints from the parent whereas UnconstrainedBox does not. Setting maxWidth: double.infinity for OverflowBox is not the solution for my case because I needed the child to build itself as it is, with its naturally free sizing.
However, I copied and modified the UnconstrainedBox into some new widget that has the showDebugModeOverflowWarning constructor. I might release it as a package while also adding example use-cases.
Because the UnconstrainedBox was already working in my case as expected. The only thing missing was it showed an overflow warning even though the overflow was intentional.
You can close this issue safely. Thank you for your time. :)

Hm, did you try OverflowBox + InstrinsicHeight & InstrinsicWidth?

Unconstrained box should not show the warning if it has clip behavior set. Instead of ClipRect -> UnconstrainedBox why not set clip behavior directly on the UnconstrainedBox?
Other than that, I agree that Flutter should have an easier way to disable overflow warnings in certain cases. I usually just end up writing a simple render object in that case, but it would be nice not having to do that.

authors: esDotDev knopp maheshmnj yasinarik

repo: flutter/flutter


text:
[iOS Web] TextField cursor position jumps to 0 after each custom keyboard input, resulting in different behavior on different platforms

(This issue is split from #103024)
I am building a custom keyboard for my Flutter web application and have found the TextField resets the cursor position to zero after every key press on iOS web browsers (Chrome and Safari) when the readOnly property of the TextField is set to TRUE. My application requires 'readOnly = true' to prevent unauthorized text from being entered in the input box.
Note: For simplicity, the sample code only includes 3 buttons ('A', 'B', and space). Changing the TextField to an EditableText input box results in the same behavior (see #103086).
Videos of the issue comparing behavior on iOS Safari, OSX Safari, and OSX Chrome:

Newly added characters always inserted at cursor position 0 instead of the end (link)
Inserting characters into existing text results in the first character inserted at the cursor's location and all subsequent characters added at cursor position 0 (link)

Source on GitHub
Steps to Reproduce the error and Actual results

Run the code below on a web server which contains a TextField with the readOnly = true
a. For convenience, the code includes a toggle switch to change the TextField's readOnly state so you can see how the behavior is inconsistent on iOS web devices

Access the web server using either:
a. An iOS device (iPhone or iPad) running mobile Safari or mobile Chrome
b. The iOS simulator using the Safari browser built into the simulator

Use the 'A', 'B', and spacebar buttons to enter text into the TextField. The new text and cursor will always appear at cursor position 0 (appearing before previously entered text). For example, entering 'ABAB' would appear as 'BABA'. (video)

Click / tap into the TextField to move the cursor to a different position. Tap a button to enter a character. The character will be entered at the cursor's current position. Then the cursor will jump back to position 0 and subsequent characters will always appear at position 0. For example, adding 'BBB' after the 'B' in 'A B A' results in 'BBA BB A' instead of the expected 'A BBBB A'. (video)

Change the switch to readOnly = false. Now the text entry behaves "normally" with each new character added after the cursor and the cursor does not jump to position 0 after each character is entered. Repositioning the cursor to somewhere in the middle of the inputted text keeps the cursor position at the expected location.

Expected results
For both readOnly = true and readOnly = false, text entered using the custom keyboard behaves as expected - each new character is added after the cursor and the cursor does not jump to position 0 after each character is entered. Therefore, entering 'ABAB' will appear as 'ABAB' in the TextField.
Repositioning the cursor to somewhere in the middle of the inputted text keeps the cursor position at the expected location and text would be entered in the middle of the text as expected.  Adding 'BBB' after the 'B' in 'A B A' appears as expected 'A BBBB A'.
The expected behavior is what is observed on desktop browsers (Windows/OSX Chrome and Safari), Android Chrome web browser, iOS native app (simulated). Android native app was not tested.

Code sample
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: KeyboardDemo(),
    );
  }
}

class KeyboardDemo extends StatefulWidget {
  @override
  _KeyboardDemoState createState() => _KeyboardDemoState();
}

class _KeyboardDemoState extends State<KeyboardDemo> {
  TextEditingController _controller = TextEditingController();
  bool _readOnly = true;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomInset: false,
      body: Column(
        children: [
          SizedBox(height: 50),
          TextField(
            controller: _controller,
            decoration: InputDecoration(
              border: OutlineInputBorder(
                borderRadius: BorderRadius.circular(3),
              ),
            ),
            style: TextStyle(fontSize: 24),
            autofocus: true,
            showCursor: true,
            readOnly: _readOnly,
          ),
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text('TextField readOnly state: '),
              Switch(
                value: _readOnly,
                onChanged: (value) {
                  setState(() {
                    _readOnly = value;
                  });
                },
              ),
            ],
          ),
          CustomKeyboard(
            onTextInput: (myText) {
              _insertText(myText);
            },
          ),
        ],
      ),
    );
  }

  void _insertText(String myText) {
    final text = _controller.text;
    final textSelection = _controller.selection;
    final newText = text.replaceRange(
      textSelection.start,
      textSelection.end,
      myText,
    );
    final myTextLength = myText.length;
    _controller.text = newText;
    _controller.selection = textSelection.copyWith(
      baseOffset: textSelection.start + myTextLength,
      extentOffset: textSelection.start + myTextLength,
    );
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
}

class CustomKeyboard extends StatelessWidget {
  CustomKeyboard({
    Key? key,
    this.onTextInput,
  }) : super(key: key);

  final ValueSetter<String>? onTextInput;

  void _textInputHandler(String text) => onTextInput!.call(text);

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 160,
      color: Colors.white,
      child: Column(
        children: [
          Expanded(
            child: Row(
              children: [
                TextKey(
                  text: 'A',
                  onTextInput: _textInputHandler,
                ),
                TextKey(
                  text: 'B',
                  onTextInput: _textInputHandler,
                ),
              ],
            ),
          ),
          Expanded(
            child: Row(
              children: [
                TextKey(
                  text: ' ',
                  onTextInput: _textInputHandler,
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

class TextKey extends StatelessWidget {
  const TextKey({
    Key? key,
    this.text,
    this.onTextInput,
    this.flex = 1,
  }) : super(key: key);

  final String? text;
  final ValueSetter<String>? onTextInput;
  final int flex;

  @override
  Widget build(BuildContext context) {
    return Expanded(
      flex: flex,
      child: Padding(
        padding: const EdgeInsets.all(1.0),
        child: Material(
          color: Colors.blue.shade100,
          child: InkWell(
            onTap: () {
              onTextInput?.call(text!);
            },
            child: Container(
              child: Center(child: Text(text!)),
            ),
          ),
        ),
      ),
    );
  }
}

Logs
```
Because this only happens in mobile web browsers, I do not know how to capture the logs since the iOS simulator's web browser isn't connected to debugger.
```

Analyzing bug_textfield_readonly...

   info • Use key in widget constructors • lib/main.dart:5:7 • use_key_in_widget_constructors
   info • Use key in widget constructors • lib/main.dart:14:7 • use_key_in_widget_constructors
   info • Private field could be final • lib/main.dart:20:25 • prefer_final_fields
   info • Prefer const with constant constructors • lib/main.dart:29:11 • prefer_const_constructors
   info • Prefer const with constant constructors • lib/main.dart:37:20 • prefer_const_constructors
   info • Prefer const with constant constructors • lib/main.dart:45:15 • prefer_const_constructors
   info • Prefer declaring const constructors on `@immutable` classes • lib/main.dart:90:3 • prefer_const_constructors_in_immutables
   info • Avoid unnecessary containers • lib/main.dart:160:20 • avoid_unnecessary_containers

[✓] Flutter (Channel stable, 2.10.5, on macOS 12.3.1 21E258 darwin-x64, locale en-US)
    • Flutter version 2.10.5 at <REDACTED>
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 5464c5bac7 (2 weeks ago), 2022-04-18 09:55:37 -0700
    • Engine revision 57d3bac3dd
    • Dart version 2.16.2
    • DevTools version 2.9.2

[✓] Android toolchain - develop for Android devices (Android SDK version 31.0.0)
    • Android SDK at <REDACTED>
    • Platform android-31, build-tools 31.0.0
    • Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.11+0-b60-7590822)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 13.3.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • CocoaPods version 1.11.3

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2021.1)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.11+0-b60-7590822)

[✓] VS Code (version 1.66.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.40.0

[✓] Connected device (2 available)
    • iPhone 12 Pro (mobile) • <REDACTED> • ios            • com.apple.CoreSimulator.SimRuntime.iOS-15-4 (simulator)
    • Chrome (web)           • chrome                               • web-javascript • Google Chrome 100.0.4896.127

[✓] HTTP Host Availability
    • All required HTTP hosts are available

• No issues found!

@danagbemava-nc - FYI

Hi @the-ack, the TextField depends on EditableText so issues with Editable text are usually present in TextFieldsas well. In light of this, I'm going to have to close this as a duplicate of #103086.
Thank you

source: gharchive/issue

authors: danagbemava-nc the-ack

license_type: permissive

license_source: github-api


text:
windows11+visual studio2022

windows11
visual studio 2022
flutter doctor --verbose
[☠] Visual Studio - develop for Windows (the doctor check crashed)
X Due to an error, the doctor check did not complete. If the error message below is not helpful, please let us know
about this issue at https://github.com/flutter/flutter/issues.
X Exception: Bad UTF-8 encoding (U+FFFD; REPLACEMENT CHARACTER) found while decoding string: [
{
"instanceId": "1ebecc39",
"installDate": "2022-05-22T02:27:46Z",
"installationName": "VisualStudio/17.2.1+32516.85",
"installationPath": "D:\dkal\environments\Microsoft Visual Studio\2022\Community",
"installationVersion": "17.2.32516.85",
"productId": "Microsoft.VisualStudio.Product.Community",
"productPath": "D:\dkal\environments\Microsoft Visual Studio\2022\Community\Common7\IDE\devenv.exe",
"state": 4294967295,
"isComplete": true,
"isLaunchable": true,
"isPrerelease": false,
"isRebootRequired": false,
"displayName": "Visual Studio Community 2022",
"description": "����ǿ��� IDE����ѧ��������Դ��������ߺ͸������ʹ��",
"channelId": "VisualStudio.17.Release",
"channelUri": "https://aka.ms/vs/17/release/channel",
"enginePath": "C:\Program Files (x86)\Microsoft Visual
Studio\Installer\resources\app\ServiceHub\Services\Microsoft.VisualStudio.Setup.Service",
"installedChannelUri": "https://aka.ms/vs/17/release/channel",
"releaseNotes": "https://docs.microsoft.com/en-us/visualstudio/releases/2022/release-notes-v17.2#17.2.1",
"thirdPartyNotices": "https://go.microsoft.com/fwlink/?LinkId=661288",
"updateDate": "2022-05-22T02:27:46.3270756Z",
"catalog": {
"buildBranch": "d17.2",
"buildVersion": "17.2.32516.85",
"id": "VisualStudio/17.2.1+32516.85",
"localBuild": "build-lab",
"manifestName": "VisualStudio",
"manifestType": "installer",
"productDisplayVersion": "17.2.1",
"productLine": "Dev17",
"productLineVersion": "2022",
"productMilestone": "RTW",
"productMilestoneIsPreRelease": "False",
"productName": "Visual Studio",
"productPatchVersion": "1",
"productPreReleaseMilestoneSuffix": "1.0",
"productSemanticVersion": "17.2.1+32516.85",
"requiredEngineVersion": "3.2.2148.26540"
},
"properties": {
"campaignId": "2030:c3972447-edfe-4f59-8455-cb3b40f3597d",
"channelManifestId": "VisualStudio.17.Release/17.2.1+32516.85",
"nickname": "",
"setupEngineFilePath": "C:\Program Files (x86)\Microsoft Visual Studio\Installer\setup.exe"
}
}
]
. The Flutter team would greatly appreciate if you could file a bug explaining exactly what you were doing when
this happened:
https://github.com/flutter/flutter/issues/new/choose
The source bytes were:
[91, 13, 10, 32, 32, 123, 13, 10, 32, 32, 32, 32, 34, 105, 110, 115, 116, 97, 110, 99, 101, 73, 100, 34, 58, 32,
34, 49, 101, 98, 101, 99, 99, 51, 57, 34, 44, 13, 10, 32, 32, 32, 32, 34, 105, 110, 115, 116, 97, 108, 108, 68,
97, 116, 101, 34, 58, 32, 34, 50, 48, 50, 50, 45, 48, 53, 45, 50, 50, 84, 48, 50, 58, 50, 55, 58, 52, 54, 90, 34,
44, 13, 10, 32, 32, 32, 32, 34, 105, 110, 115, 116, 97, 108, 108, 97, 116, 105, 111, 110, 78, 97, 109, 101, 34,
58, 32, 34, 86, 105, 115, 117, 97, 108, 83, 116, 117, 100, 105, 111, 47, 49, 55, 46, 50, 46, 49, 43, 51, 50, 53,
49, 54, 46, 56, 53, 34, 44, 13, 10, 32, 32, 32, 32, 34, 105, 110, 115, 116, 97, 108, 108, 97, 116, 105, 111, 110,
80, 97, 116, 104, 34, 58, 32, 34, 68, 58, 92, 92, 100, 107, 97, 108, 92, 92, 101, 110, 118, 105, 114, 111, 110,
109, 101, 110, 116, 115, 92, 92, 77, 105, 99, 114, 111, 115, 111, 102, 116, 32, 86, 105, 115, 117, 97, 108, 32,
83, 116, 117, 100, 105, 111, 92, 92, 50, 48, 50, 50, 92, 92, 67, 111, 109, 109, 117, 110, 105, 116, 121, 34, 44,
13, 10, 32, 32, 32, 32, 34, 105, 110, 115, 116, 97, 108, 108, 97, 116, 105, 111, 110, 86, 101, 114, 115, 105, 111,      110, 34, 58, 32, 34, 49, 55, 46, 50, 46, 51, 50, 53, 49, 54, 46, 56, 53, 34, 44, 13, 10, 32, 32, 32, 32, 34, 112,
114, 111, 100, 117, 99, 116, 73, 100, 34, 58, 32, 34, 77, 105, 99, 114, 111, 115, 111, 102, 116, 46, 86, 105, 115,      117, 97, 108, 83, 116, 117, 100, 105, 111, 46, 80, 114, 111, 100, 117, 99, 116, 46, 67, 111, 109, 109, 117, 110,
105, 116, 121, 34, 44, 13, 10, 32, 32, 32, 32, 34, 112, 114, 111, 100, 117, 99, 116, 80, 97, 116, 104, 34, 58, 32,      34, 68, 58, 92, 92, 100, 107, 97, 108, 92, 92, 101, 110, 118, 105, 114, 111, 110, 109, 101, 110, 116, 115, 92, 92,      77, 105, 99, 114, 111, 115, 111, 102, 116, 32, 86, 105, 115, 117, 97, 108, 32, 83, 116, 117, 100, 105, 111, 92,
92, 50, 48, 50, 50, 92, 92, 67, 111, 109, 109, 117, 110, 105, 116, 121, 92, 92, 67, 111, 109, 109, 111, 110, 55,
92, 92, 73, 68, 69, 92, 92, 100, 101, 118, 101, 110, 118, 46, 101, 120, 101, 34, 44, 13, 10, 32, 32, 32, 32, 34,
115, 116, 97, 116, 101, 34, 58, 32, 52, 50, 57, 52, 57, 54, 55, 50, 57, 53, 44, 13, 10, 32, 32, 32, 32, 34, 105,
115, 67, 111, 109, 112, 108, 101, 116, 101, 34, 58, 32, 116, 114, 117, 101, 44, 13, 10, 32, 32, 32, 32, 34, 105,
115, 76, 97, 117, 110, 99, 104, 97, 98, 108, 101, 34, 58, 32, 116, 114, 117, 101, 44, 13, 10, 32, 32, 32, 32, 34,
105, 115, 80, 114, 101, 114, 101, 108, 101, 97, 115, 101, 34, 58, 32, 102, 97, 108, 115, 101, 44, 13, 10, 32, 32,
32, 32, 34, 105, 115, 82, 101, 98, 111, 111, 116, 82, 101, 113, 117, 105, 114, 101, 100, 34, 58, 32, 102, 97, 108,      115, 101, 44, 13, 10, 32, 32, 32, 32, 34, 100, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 58, 32, 34, 86,
105, 115, 117, 97, 108, 32, 83, 116, 117, 100, 105, 111, 32, 67, 111, 109, 109, 117, 110, 105, 116, 121, 32, 50,
48, 50, 50, 34, 44, 13, 10, 32, 32, 32, 32, 34, 100, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 58, 32,
34, 185, 166, 196, 220, 199, 191, 180, 243, 181, 196, 32, 73, 68, 69, 163, 172, 185, 169, 209, 167, 201, 250, 161,      162, 191, 170, 183, 197, 212, 180, 180, 250, 194, 235, 178, 206, 211, 235, 213, 223, 186, 205, 184, 246, 200, 203,      195, 226, 183, 209, 202, 185, 211, 195, 34, 44, 13, 10, 32, 32, 32, 32, 34, 99, 104, 97, 110, 110, 101, 108, 73,
100, 34, 58, 32, 34, 86, 105, 115, 117, 97, 108, 83, 116, 117, 100, 105, 111, 46, 49, 55, 46, 82, 101, 108, 101,
97, 115, 101, 34, 44, 13, 10, 32, 32, 32, 32, 34, 99, 104, 97, 110, 110, 101, 108, 85, 114, 105, 34, 58, 32, 34,
104, 116, 116, 112, 115, 58, 47, 47, 97, 107, 97, 46, 109, 115, 47, 118, 115, 47, 49, 55, 47, 114, 101, 108, 101,
97, 115, 101, 47, 99, 104, 97, 110, 110, 101, 108, 34, 44, 13, 10, 32, 32, 32, 32, 34, 101, 110, 103, 105, 110,
101, 80, 97, 116, 104, 34, 58, 32, 34, 67, 58, 92, 92, 80, 114, 111, 103, 114, 97, 109, 32, 70, 105, 108, 101,
115, 32, 40, 120, 56, 54, 41, 92, 92, 77, 105, 99, 114, 111, 115, 111, 102, 116, 32, 86, 105, 115, 117, 97, 108,
32, 83, 116, 117, 100, 105, 111, 92, 92, 73, 110, 115, 116, 97, 108, 108, 101, 114, 92, 92, 114, 101, 115, 111,
117, 114, 99, 101, 115, 92, 92, 97, 112, 112, 92, 92, 83, 101, 114, 118, 105, 99, 101, 72, 117, 98, 92, 92, 83,
101, 114, 118, 105, 99, 101, 115, 92, 92, 77, 105, 99, 114, 111, 115, 111, 102, 116, 46, 86, 105, 115, 117, 97,
108, 83, 116, 117, 100, 105, 111, 46, 83, 101, 116, 117, 112, 46, 83, 101, 114, 118, 105, 99, 101, 34, 44, 13, 10,      32, 32, 32, 32, 34, 105, 110, 115, 116, 97, 108, 108, 101, 100, 67, 104, 97, 110, 110, 101, 108, 85, 114, 105, 34,      58, 32, 34, 104, 116, 116, 112, 115, 58, 47, 47, 97, 107, 97, 46, 109, 115, 47, 118, 115, 47, 49, 55, 47, 114,
101, 108, 101, 97, 115, 101, 47, 99, 104, 97, 110, 110, 101, 108, 34, 44, 13, 10, 32, 32, 32, 32, 34, 114, 101,
108, 101, 97, 115, 101, 78, 111, 116, 101, 115, 34, 58, 32, 34, 104, 116, 116, 112, 115, 58, 47, 47, 100, 111, 99,      115, 46, 109, 105, 99, 114, 111, 115, 111, 102, 116, 46, 99, 111, 109, 47, 101, 110, 45, 117, 115, 47, 118, 105,
115, 117, 97, 108, 115, 116, 117, 100, 105, 111, 47, 114, 101, 108, 101, 97, 115, 101, 115, 47, 50, 48, 50, 50,
47, 114, 101, 108, 101, 97, 115, 101, 45, 110, 111, 116, 101, 115, 45, 118, 49, 55, 46, 50, 35, 49, 55, 46, 50,
46, 49, 34, 44, 13, 10, 32, 32, 32, 32, 34, 116, 104, 105, 114, 100, 80, 97, 114, 116, 121, 78, 111, 116, 105, 99,      101, 115, 34, 58, 32, 34, 104, 116, 116, 112, 115, 58, 47, 47, 103, 111, 46, 109, 105, 99, 114, 111, 115, 111,
102, 116, 46, 99, 111, 109, 47, 102, 119, 108, 105, 110, 107, 47, 63, 76, 105, 110, 107, 73, 100, 61, 54, 54, 49,
50, 56, 56, 34, 44, 13, 10, 32, 32, 32, 32, 34, 117, 112, 100, 97, 116, 101, 68, 97, 116, 101, 34, 58, 32, 34, 50,      48, 50, 50, 45, 48, 53, 45, 50, 50, 84, 48, 50, 58, 50, 55, 58, 52, 54, 46, 51, 50, 55, 48, 55, 53, 54, 90, 34,
44, 13, 10, 32, 32, 32, 32, 34, 99, 97, 116, 97, 108, 111, 103, 34, 58, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32,
34, 98, 117, 105, 108, 100, 66, 114, 97, 110, 99, 104, 34, 58, 32, 34, 100, 49, 55, 46, 50, 34, 44, 13, 10, 32,
32, 32, 32, 32, 32, 34, 98, 117, 105, 108, 100, 86, 101, 114, 115, 105, 111, 110, 34, 58, 32, 34, 49, 55, 46, 50,
46, 51, 50, 53, 49, 54, 46, 56, 53, 34, 44, 13, 10, 32, 32, 32, 32, 32, 32, 34, 105, 100, 34, 58, 32, 34, 86, 105,      115, 117, 97, 108, 83, 116, 117, 100, 105, 111, 47, 49, 55, 46, 50, 46, 49, 43, 51, 50, 53, 49, 54, 46, 56, 53,
34, 44, 13, 10, 32, 32, 32, 32, 32, 32, 34, 108, 111, 99, 97, 108, 66, 117, 105, 108, 100, 34, 58, 32, 34, 98,
117, 105, 108, 100, 45, 108, 97, 98, 34, 44, 13, 10, 32, 32, 32, 32, 32, 32, 34, 109, 97, 110, 105, 102, 101, 115,      116, 78, 97, 109, 101, 34, 58, 32, 34, 86, 105, 115, 117, 97, 108, 83, 116, 117, 100, 105, 111, 34, 44, 13, 10,
32, 32, 32, 32, 32, 32, 34, 109, 97, 110, 105, 102, 101, 115, 116, 84, 121, 112, 101, 34, 58, 32, 34, 105, 110,
115, 116, 97, 108, 108, 101, 114, 34, 44, 13, 10, 32, 32, 32, 32, 32, 32, 34, 112, 114, 111, 100, 117, 99, 116,
68, 105, 115, 112, 108, 97, 121, 86, 101, 114, 115, 105, 111, 110, 34, 58, 32, 34, 49, 55, 46, 50, 46, 49, 34, 44,      13, 10, 32, 32, 32, 32, 32, 32, 34, 112, 114, 111, 100, 117, 99, 116, 76, 105, 110, 101, 34, 58, 32, 34, 68, 101,
118, 49, 55, 34, 44, 13, 10, 32, 32, 32, 32, 32, 32, 34, 112, 114, 111, 100, 117, 99, 116, 76, 105, 110, 101, 86,
101, 114, 115, 105, 111, 110, 34, 58, 32, 34, 50, 48, 50, 50, 34, 44, 13, 10, 32, 32, 32, 32, 32, 32, 34, 112,
114, 111, 100, 117, 99, 116, 77, 105, 108, 101, 115, 116, 111, 110, 101, 34, 58, 32, 34, 82, 84, 87, 34, 44, 13,
10, 32, 32, 32, 32, 32, 32, 34, 112, 114, 111, 100, 117, 99, 116, 77, 105, 108, 101, 115, 116, 111, 110, 101, 73,
115, 80, 114, 101, 82, 101, 108, 101, 97, 115, 101, 34, 58, 32, 34, 70, 97, 108, 115, 101, 34, 44, 13, 10, 32, 32,      32, 32, 32, 32, 34, 112, 114, 111, 100, 117, 99, 116, 78, 97, 109, 101, 34, 58, 32, 34, 86, 105, 115, 117, 97,
108, 32, 83, 116, 117, 100, 105, 111, 34, 44, 13, 10, 32, 32, 32, 32, 32, 32, 34, 112, 114, 111, 100, 117, 99,
116, 80, 97, 116, 99, 104, 86, 101, 114, 115, 105, 111, 110, 34, 58, 32, 34, 49, 34, 44, 13, 10, 32, 32, 32, 32,
32, 32, 34, 112, 114, 111, 100, 117, 99, 116, 80, 114, 101, 82, 101, 108, 101, 97, 115, 101, 77, 105, 108, 101,
115, 116, 111, 110, 101, 83, 117, 102, 102, 105, 120, 34, 58, 32, 34, 49, 46, 48, 34, 44, 13, 10, 32, 32, 32, 32,
32, 32, 34, 112, 114, 111, 100, 117, 99, 116, 83, 101, 109, 97, 110, 116, 105, 99, 86, 101, 114, 115, 105, 111,
110, 34, 58, 32, 34, 49, 55, 46, 50, 46, 49, 43, 51, 50, 53, 49, 54, 46, 56, 53, 34, 44, 13, 10, 32, 32, 32, 32,
32, 32, 34, 114, 101, 113, 117, 105, 114, 101, 100, 69, 110, 103, 105, 110, 101, 86, 101, 114, 115, 105, 111, 110,      34, 58, 32, 34, 51, 46, 50, 46, 50, 49, 52, 56, 46, 50, 54, 53, 52, 48, 34, 13, 10, 32, 32, 32, 32, 125, 44, 13,
10, 32, 32, 32, 32, 34, 112, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 58, 32, 123, 13, 10, 32, 32, 32, 32,      32, 32, 34, 99, 97, 109, 112, 97, 105, 103, 110, 73, 100, 34, 58, 32, 34, 50, 48, 51, 48, 58, 99, 51, 57, 55, 50,
52, 52, 55, 45, 101, 100, 102, 101, 45, 52, 102, 53, 57, 45, 56, 52, 53, 53, 45, 99, 98, 51, 98, 52, 48, 102, 51,
53, 57, 55, 100, 34, 44, 13, 10, 32, 32, 32, 32, 32, 32, 34, 99, 104, 97, 110, 110, 101, 108, 77, 97, 110, 105,
102, 101, 115, 116, 73, 100, 34, 58, 32, 34, 86, 105, 115, 117, 97, 108, 83, 116, 117, 100, 105, 111, 46, 49, 55,
46, 82, 101, 108, 101, 97, 115, 101, 47, 49, 55, 46, 50, 46, 49, 43, 51, 50, 53, 49, 54, 46, 56, 53, 34, 44, 13,
10, 32, 32, 32, 32, 32, 32, 34, 110, 105, 99, 107, 110, 97, 109, 101, 34, 58, 32, 34, 34, 44, 13, 10, 32, 32, 32,
32, 32, 32, 34, 115, 101, 116, 117, 112, 69, 110, 103, 105, 110, 101, 70, 105, 108, 101, 80, 97, 116, 104, 34, 58,      32, 34, 67, 58, 92, 92, 80, 114, 111, 103, 114, 97, 109, 32, 70, 105, 108, 101, 115, 32, 40, 120, 56, 54, 41, 92,
92, 77, 105, 99, 114, 111, 115, 111, 102, 116, 32, 86, 105, 115, 117, 97, 108, 32, 83, 116, 117, 100, 105, 111,
92, 92, 73, 110, 115, 116, 97, 108, 108, 101, 114, 92, 92, 115, 101, 116, 117, 112, 46, 101, 120, 101, 34, 13, 10,      32, 32, 32, 32, 125, 13, 10, 32, 32, 125, 13, 10, 93, 13, 10]
• #0      throwToolExit (package:flutter_tools/src/base/common.dart:10:3)
  #1      Utf8Decoder.convert (package:flutter_tools/src/convert.dart:54:7)
  #2      Codec.decode (dart:convert/codec.dart:26:34)
  #3      _ProcessImpl._runAndWait.getOutput (dart:io-patch/process_patch.dart:498:23)
  #4      _ProcessImpl._runAndWait (dart:io-patch/process_patch.dart:506:9)
  #5      _runNonInteractiveProcessSync (dart:io-patch/process_patch.dart:632:18)
  #6      Process.runSync (dart:io-patch/process_patch.dart:68:12)
  #7      LocalProcessManager.runSync (package:process/src/interface/local_process_manager.dart:103:22)
  #8      ErrorHandlingProcessManager.runSync.<anonymous closure>
  (package:flutter_tools/src/base/error_handling_io.dart:712:24)
  #9      _runSync (package:flutter_tools/src/base/error_handling_io.dart:597:14)
  #10     ErrorHandlingProcessManager.runSync (package:flutter_tools/src/base/error_handling_io.dart:711:12)
  #11     _DefaultProcessUtils.runSync (package:flutter_tools/src/base/process.dart:373:51)
  #12     VisualStudio._visualStudioDetails (package:flutter_tools/src/windows/visual_studio.dart:314:51)
  #13     VisualStudio._anyVisualStudioDetails (package:flutter_tools/src/windows/visual_studio.dart:403:39)
  #14     VisualStudio._bestVisualStudioDetails (package:flutter_tools/src/windows/visual_studio.dart:419:12)
  #15     VisualStudio.isInstalled (package:flutter_tools/src/windows/visual_studio.dart:36:27)
  #16     VisualStudioValidator.validate (package:flutter_tools/src/windows/visual_studio_validator.dart:29:23)
  #17     Doctor.startValidatorTasks.<anonymous closure> (package:flutter_tools/src/doctor.dart:216:72)
  #18     asyncGuard.<anonymous closure> (package:flutter_tools/src/base/async_guard.dart:111:32)
  #19     asyncGuard.<anonymous closure> (package:flutter_tools/src/base/async_guard.dart:109:18)
  #20     _rootRun (dart:async/zone.dart:1426:13)
  #21     _CustomZone.run (dart:async/zone.dart:1328:19)
  #22     _runZoned (dart:async/zone.dart:1861:10)
  #23     runZonedGuarded (dart:async/zone.dart:1849:12)
  #24     runZoned (dart:async/zone.dart:1780:12)
  #25     asyncGuard (package:flutter_tools/src/base/async_guard.dart:109:3)
  #26     Doctor.startValidatorTasks (package:flutter_tools/src/doctor.dart:208:9)
  #27     Doctor.diagnose (package:flutter_tools/src/doctor.dart:339:72)
  #28     DoctorCommand.runCommand (package:flutter_tools/src/commands/doctor.dart:50:48)
  #29     FlutterCommand.verifyThenRunCommand (package:flutter_tools/src/runner/flutter_command.dart:1342:12)
  <asynchronous suspension>
  #30     FlutterCommand.run.<anonymous closure> (package:flutter_tools/src/runner/flutter_command.dart:1183:27)
  <asynchronous suspension>
  #31     AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:150:19)
  <asynchronous suspension>
  #32     CommandRunner.runCommand (package:args/command_runner.dart:209:13)
  <asynchronous suspension>
  #33     FlutterCommandRunner.runCommand.<anonymous closure>
  (package:flutter_tools/src/runner/flutter_command_runner.dart:281:9)
  <asynchronous suspension>
  #34     AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:150:19)
  <asynchronous suspension>
  #35     FlutterCommandRunner.runCommand (package:flutter_tools/src/runner/flutter_command_runner.dart:229:5)
  <asynchronous suspension>
  #36     run.<anonymous closure>.<anonymous closure> (package:flutter_tools/runner.dart:62:9)
  <asynchronous suspension>
  #37     AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:150:19)
  <asynchronous suspension>
  #38     main (package:flutter_tools/executable.dart:94:3)
  <asynchronous suspension>

I meet THIS, too.

Closing this as duplicate of https://github.com/flutter/flutter/issues/102451.
See the above link for fix.

authors: darshankawar ryanaltair whisper540


text:
[Proposal] Access l18n Translations with Dynamic Keys

Use case
In my app i have dynamic states for which i would need to show the correct translated string.
Let's say the .arb files contain key/value pairs like
"localStateError": "An error has occurred",
"localStateSuccess": "The transaction was successful",

If my available states in the source code are then 'Error' and 'Success' i currently cannot access the correct string by using e.g.
context.l10n['localState$state']

Proposal
A possibility to access translations with dynamic strings as keys without using reflection.

Hi @rivella50. Could you give an example on how you'd expect this to work, also including how the code would be generated? And also a minimal, reproducible example on how it currently works if possible so that it's easy to compare

Sure, here is an example of how it would work now:
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Localizations Sample App',
      localizationsDelegates: [
        AppLocalizations.delegate,
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
      ],
      supportedLocales: [
        Locale('en', ''), // English, no country code
        Locale('de', ''), // German, no country code
      ],
      home: MyWidget(),
    );
  }
}

class MyWidget extends StatelessWidget {
  const MyWidget({Key? key}) : super(key: key);

  final state = 'Success';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Test'),
      ),
      body: Center(
        child: Column(
          children: [
            Text(_getTranslation(context, state)),
          ],
        ),
      ),
    );
  }

  String _getTranslation(BuildContext context, String state) {
    if (state == 'Error') {
      return AppLocalizations.of(context)!.localStateError;
    } else {
      return AppLocalizations.of(context)!.localStateSuccess;
    }
  }
}

What i would expect is that the helper method _getTranslation is not needed at all, but the translation could be retrieved directly by using e.g.
AppLocalizations.of(context)!['localState$state']

I.e. that app_localizations.dart would not only offer getters for the keys but also some sort of Map structure in order to access the translations in a dynamic way as mentioned above.

Thank you for the detailed proposal :)

Is this something that is in consideration?
This is a very helpful feature!

Looking forward to this feature. Im currently having a need for this

@cgonzalezandrades Please do thumbs up the original post :)

I want to include this feature in my own projects, especially in my current project where I'm mapping "tool" names. It would be great to use it in this way.
AppLocalizations.of(context).toolName(tool)

app_en.arb:
  "@toolName": {
    "values": {
      "scissor":  "Scissor",
      "someTool": "Some Tool"
    }
  },

Encountered this usecase and decided to create a package to address this
https://pub.dev/packages/localization_mapper_annotation

Looking forwards for this to be implemented.

Will this be considered to be implemented?
I think the current state of the native localization solution is the best solution for Flutter with the better customization options, but not being able to get dynamic translations makes it difficult to move out from other i18n solutions that you can access the localization map with keys

I just created a workaround to be able to migrate to the native l10n solution since I don't want to use any other third party i18n solution.
pubsec.yaml
  assets:
    # FIXME: remove after https://github.com/flutter/flutter/issues/105672
    # all .arb files
    - lib/l10n/app_en.arb
    - lib/l10n/app_pt_BR.arb
    - lib/l10n/app_pt.arb

Static class storing a static locale map Map<Locale, Map<String, String>> localeMap = <Locale, Map<String, String>>{};
  // FIXME: remove after https://github.com/flutter/flutter/issues/105672
  Future loadMaps() async {
    if (localeMap.isNotEmpty) {
      return;
    }

    for (var locale in AppLocalizations.supportedLocales) {
      var fileName = "app_${locale.toLanguageTag().replaceAll('-', '_')}.arb";

      await rootBundle.loadString("lib/l10n/$fileName").then((file) {
        var data = jsonDecode(file);

        data.forEach((key, value) {
          if (value is! String) {
            return;
          }

          localeMap[locale] ??= <String, String>{};
          localeMap[locale]![key] = value;
        });
      });
    }
  }

Call loadMaps() anywhere in your main. Since it uses assets, the hot-reload feature will not be able to get updated files, it will require an app restart.
And then use it in any string with an extension:
extension LocaleStringMap on String {
  String l10n(BuildContext context) {
    var locale = Localizations.localeOf(context);

    return localeMap[locale]?[this] ??
        localeMap[Locale.fromSubtags(
          languageCode: locale.languageCode,
        )]?[this] ??
        localeMap[const Locale('en')]?[this] ??
        this;
  }
}

Usage:
var anyDynamicStringVar = 'key';

return Text(anyDynamicStringVar.l10n(context));

Not ideal but at least I can use native localization for now without using it with another i18n solution, and allowing only simple string<->string values without arguments, etc.

The generator could add a method like this: (ofc repetitive but less effort)
dynamic getProp(String key) => <String, dynamic>{
   'a' : a,
   'b' : b,
}[key];

I'd also be very happy about this feature - I have quite some messages for localized language names
app_en.arb:
   "language_en": "English",
   "language_de": "German",
   "language_tr": "Turkish",
   ...

app_de.arb:
   "language_en": "Englisch",
   "language_de": "Deutsch",
   "language_tr": "Türkisch",
   ...

For now I implemented a lengthy function as suggested by @stact - just that the BuildContext is actually not necessary:
extension LocalizationExt on AppLocalizations {
  String getMessage(String message) {
    final messageMap = <String, String>{
      'language_en': language_en,
      'language_de': language_de,
      'language_tr': language_tr,
      /* ... */
    };
    if (messageMap.containsKey(message)) {
      return messageMap[message]!;
    }
    debugPrint("Warning: message '$message' is not defined");
    return message.toUpperCase();
  }
}

Now I can everywhere use it with AppLocalizations.of(context).getMessage('language_$langCode'). However the getMessage function is a lot of boilerplate and needs attention when adding new messages. Getting rid of it would be great.

I made some changes to my package created to support dynamic access to translation. The above package will not be actively maintained by me but has been renamed and moved to my personal repo.
You can find the upgraded package at https://pub.dev/packages/l10_mapper_annotation.

I made some changes to my package created to support dynamic access to translation. The above package will not be actively maintained by me but has been renamed and moved to my personal repo.
You can find the upgraded package at https://pub.dev/packages/l10_mapper_annotation.

I made some changes to my package created to support dynamic access to translation. The above package will not be actively maintained by me but has been renamed and moved to my personal repo.
You can find the upgraded package at https://pub.dev/packages/l10_mapper_annotation.

Are there any updates on this? I was trying to use Riverpod to show a snackbar dinamically without needing to pass the context as a parameter, and reached something like this:
@riverpod
Future snackBarService(SnackBarServiceRef ref, {required String text, Duration duration = const Duration(seconds: 3)}) {
BuildContext context = ref.read(navigatorKeyProvider).currentContext!;
final messenger = ScaffoldMessenger.of(context);
final snackBar = SnackBar(
content: Text(AppLocalizations.of(context)!.text),
duration: duration,

);
final result = messenger.showSnackBar(snackBar);
return result.closed;
}
This doesn't work because the "text" string is not a valid key. If anyone sees a work around please let me know.

What if we use Intl.message() directly?
extension LocalizationExtension on AppLocalizations {
  String getCategory(String categoryKey, String default) {
    Intl.message(
      default,
      name: categoryKey,
      args: [],
      desc: "Dynamic key - $categoryKey",
    );
  }

It's not working though, I tried :) Could someone explain, why?

any update?

What if we use Intl.message() directly?
extension LocalizationExtension on AppLocalizations {
  String getCategory(String categoryKey, String default) {
    Intl.message(
      default,
      name: categoryKey,
      args: [],
      desc: "Dynamic key - $categoryKey",
    );
  }

It's not working though, I tried :) Could someone explain, why?

Hello, regarding your approach of using Intl.message() to dynamically access translation texts, it’s important to note that if you pass parameters (args) to translations that do not require them, this will cause an error. This happens because Intl.message() will attempt to apply these parameters to a string that does not have predefined placeholders. Therefore, when using dynamic keys to access translations, make sure that any parameters you pass match the placeholders in the translation text, or only pass parameters when necessary.

authors: Hegezcc TheWalkingDead1024 cgonzalezandrades exaby73 gustavolramos guy-evdev holybiber kwado-tech lucasoares lukyanov mattias-lonn rivella50 stact


text:
PageStorageKeys might benefit from a way to identify their primary client

Customer Leafy ran into a confusing problem: ExpansionTiles were asserting in initState():
Error: type 'double' is not a subtype of type 'bool' of 'value'
...

#0 _ExpansionTileState._isExpanded= (package:flutter/src/material/expansion_tile.dart:81)
#1 _ExpansionTileState.initState (package:flutter/src/material/expansion_tile.dart:95)
#2 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:3502)
...

The problem was that the ExpansionTile's were looking up their expanded/collapsed boolean with PageStorage, but only the enclosing PageView specified a PageStorageKey.  PageView uses PageStorage to save its double scroll offset.
In this case it would have been preferable for the expansion tiles to not save their state.
Some possible ways to improve things:

ExpansionTiles don't save their state by default. The  dartdoc for a default false  keepExpansionState could cover the need for a PageStorageKey.

Scrollables include an inherited widget that only exists to stop  the page storage key tree traversal. If a key wasn't found by the time this widget was reached, the traversal would short-circuit.

The second approach seems like it would result in most apps quietly getting the behavior they'd expect. It would complicate explaining how PageStorageKeys work a little.

I guess another option is that we add the type back in to the key somehow, though then you'd have all the panels stomping on each other which is no good.

I know this is old but just ran into same problem myself. For a flutter beginner it's difficult to know what the problem is from the reported error. The simple fix is to specify a PageStorageKey as the ExpansionTile key. Hope this save someone some time!
new ExpansionTile(key: new PageStorageKey("any string"),  ...

Hey I actually just ran into this problem in a slightly different way. I'm using ExpansionTiles in a TabBarView and each ExpansionTile has a number of SwitchListTiles. I added a PageStorageKey to my ExpansionTiles so the expanded state would be saved but started getting this error. The fix for me was to add a PageStorageKey to each SwitchListTile as well since they have their own boolean selected values which were probably confusing the scroll offset lookup. Just throwing this out there in case this happens to anyone else!

I know this is old but just ran into same problem myself. For a flutter beginner it's difficult to know what the problem is from the reported error. The simple fix is to specify a PageStorageKey as the ExpansionTile key. Hope this save someone some time!
new ExpansionTile(key: new PageStorageKey("any string"),  ...

You are right that the error is rather unhelpful, but there seem to be similar errors whenever widgets expect a cached State and can't find it.  If you have more than one ExpansionTile, however, I believe they will each need a unique key to avoid stepping on each other.

I know this is old but just ran into same problem myself. For a flutter beginner it's difficult to know what the problem is from the reported error. The simple fix is to specify a PageStorageKey as the ExpansionTile key. Hope this save someone some time!
new ExpansionTile(key: new PageStorageKey("any string"),  ...

I used "Key" It didnt work in my project.  Thank you for your answer

Hi. I have the opposite behavior. I am using ExpansionTile in a ListView. The doc say to use PageStorageKey
/// This widget is typically used with [ListView] to create an
/// "expand / collapse" list entry. When used with scrolling widgets like
/// [ListView], a unique [PageStorageKey] must be specified to enable the
/// [ExpansionTile] to save and restore its expanded state when it is scrolled
/// in and out of view.

when I add PageStorageKey like key: PageStorageKey<String>(event.id),, I get error when expand. Even with one item. Is it safe to use without PageStorageKey if there are multiple items and list is scrolled? Thanks.
flutter: ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
flutter: The following assertion was thrown building
flutter: EditableText-[LabeledGlobalKey<EditableTextState>#33601](controller:
flutter: TextEditingController#8c7bb(TextEditingValue(text: ┤├, selection: TextSelection(baseOffset: -1,
flutter: extentOffset: -1, affinity: TextAffinity.downstream, isDirectional: false), composing:
flutter: TextRange(start: -1, end: -1))), focusNode: FocusNode#1c794, debugLabel: (englishLike subhead
flutter: 2014).merge(blackCupertino subhead), inherit: false, color: Color(0xdd000000), family: .SF UI Text,
flutter: size: 16.0, weight: 400, baseline: alphabetic, decoration: TextDecoration.none, textAlign: start,
flutter: keyboardType: TextInputType(name: TextInputType.text, signed: null, decimal: null), dependencies:
flutter: [_FocusMarker], state: EditableTextState#fd565(tickers: tracking 2 tickers)):
flutter: type 'bool' is not a subtype of type 'double'
flutter:
flutter: Either the assertion indicates an error in the framework itself, or we should provide substantially
flutter: more information in this error message to help you determine and fix the underlying cause.
flutter: In either case, please report this assertion by filing a bug on GitHub:
flutter:   https://github.com/flutter/flutter/issues/new?template=BUG.md
flutter:
flutter: When the exception was thrown, this was the stack:
flutter: #0      ScrollPosition.restoreScrollOffset
package:flutter/…/widgets/scroll_position.dart:356
flutter: #1      new ScrollPosition
package:flutter/…/widgets/scroll_position.dart:82
flutter: #2      new ScrollPositionWithSingleContext
package:flutter/…/widgets/scroll_position_with_single_context.dart:57
flutter: #3      ScrollController.createScrollPosition
package:flutter/…/widgets/scroll_controller.dart:233
flutter: #4      ScrollableState._updatePosition
package:flutter/…/widgets/scrollable.dart:328
flutter: #5      ScrollableState.didChangeDependencies
package:flutter/…/widgets/scrollable.dart:337
flutter: #6      StatefulElement._firstBuild
package:flutter/…/widgets/framework.dart:4051
flutter: #7      ComponentElement.mount
package:flutter/…/widgets/framework.dart:3902
flutter: #8      Element.inflateWidget
package:flutter/…/widgets/framework.dart:3084
flutter: #9      Element.updateChild
package:flutter/…/widgets/framework.dart:2887
flutter: #10     ComponentElement.performRebuild
package:flutter/…/widgets/framework.dart:3935
flutter: #11     Element.rebuild
package:flutter/…/widgets/framework.dart:3721
flutter: #12     ComponentElement._firstBuild
package:flutter/…/widgets/framework.dart:3907
flutter: #13     StatefulElement._firstBuild
package:flutter/…/widgets/framework.dart:4053
flutter: #14     ComponentElement.mount
package:flutter/…/widgets/framework.dart:3902
flutter: #15     Element.inflateWidget
package:flutter/…/widgets/framework.dart:3084
flutter: #16     Element.updateChild
package:flutter/…/widgets/framework.dart:2887
flutter: #17     SingleChildRenderObjectElement.mount
package:flutter/…/widgets/framework.dart:5092
flutter: #18     Element.inflateWidget
package:flutter/…/widgets/framework.dart:3084
flutter: #19     Element.updateChild
package:flutter/…/widgets/framework.dart:2887
flutter: #20     _RenderDecorationElement._mountChild
package:flutter/…/material/input_decorator.dart:1481
flutter: #21     _RenderDecorationElement.mount
package:flutter/…/material/input_decorator.dart:1496
flutter: #22     Element.inflateWidget
package:flutter/…/widgets/framework.dart:3084
flutter: #23     Element.updateChild
package:flutter/…/widgets/framework.dart:2887
flutter: #24     ComponentElement.performRebuild
package:flutter/…/widgets/framework.dart:3935
flutter: #25     Element.rebuild
package:flutter/…/widgets/framework.dart:3721
flutter: #26     ComponentElement._firstBuild
package:flutter/…/widgets/framework.dart:3907
flutter: #27     StatefulElement._firstBuild
package:flutter/…/widgets/framework.dart:4053
flutter: #28     ComponentElement.mount
package:flutter/…/widgets/framework.dart:3902
flutter: #29     Element.inflateWidget
package:flutter/…/widgets/framework.dart:3084
flutter: #30     Element.updateChild
package:flutter/…/widgets/framework.dart:2887
flutter: #31     ComponentElement.performRebuild
package:flutter/…/widgets/framework.dart:3935
flutter: #32     Element.rebuild
package:flutter/…/widgets/framework.dart:3721
flutter: #33     ComponentElement._firstBuild
package:flutter/…/widgets/framework.dart:3907
flutter: #34     StatefulElement._firstBuild
package:flutter/…/widgets/framework.dart:4053
flutter: #35     ComponentElement.mount
package:flutter/…/widgets/framework.dart:3902
flutter: #36     Element.inflateWidget
package:flutter/…/widgets/framework.dart:3084
flutter: #37     Element.updateChild
package:flutter/…/widgets/framework.dart:2887
flutter: #38     SingleChildRenderObjectElement.mount
package:flutter/…/widgets/framework.dart:5092

authors: HansMuller Hixie bsr203 kgain21 myleftshoe psine volkangurol


text:
flutter screenshot should not require being run from a Flutter project directory

$ cd $HOME # not a Flutter directory
$ flutter screenshot
No supported devices connected.
The following devices were found, but are not supported by this project:
Purple 14 (mobile) • 00008110-0009588C2651401E • ios            • iOS 16.1.1
20B101
macOS (desktop)    • macos                     • darwin-x64     • macOS 12.6.1
21G217 darwin-x64
Chrome (web)       • chrome                    • web-javascript • Google Chrome
107.0.5304.110
If you would like your app to run on ios or macos or web, consider running
`flutter create .` to generate projects for these platforms.

flutter screenshot seems to be checking the enabled devices for the project, but it would be good to be able to run that one from anywhere.
See also https://github.com/flutter/flutter/issues/35490

I'm guessing it would be like a normal -d case where if there's only one it assume that's the device, and if there are multiple it prompts?  Should be easy to test what we already do inside of a Flutter app that's running say Android and Windows at the same time. 🙂


text:
win bots in staging are down

@kentnguyen99 please check win-5,6,7 which are down in staging pool. This is likely that they did not come back up after the power outage. If thats the case, please make sure their BIOS setting is correctly set to auto power on after power outage (as per the instructions in our flutter devicelab documentation).

Both machine win-5 & 6 power itself after power restored; However, both machine didn't have IP address and connect to network. After rebooted both machine win-5 & 6 and both machines are back online. Still looking into how to get in BIOS setup for machine win-7.

@kentnguyen99  here are the instructions: https://g3doc.corp.google.com/company/teams/flutter/infrastructure/devicelab/windows_host.md#set-bios-power-on-settings

BIOS not accessible for Windows ARM hardware. I did a lot search for BIOS for ARM hardware and poke around in BIOS settings but no luck.

BIOS is not a windows thing. It comes up before the OS. What do you see as the first thing on screen when rebooting the machine?

It displays black screen then boot to Windows after that.

Usually, if you press del or f2 key when the machine is rebooted (before windows) it will get you into BIOS.

The new Windows ARM is total different from Windows x86 box. Here is the link when you press del or f2 to get in BIOS settings. https://raesene.github.io/blog/2022/10/30/Project-Volterra-ARM-Desktop/


text:
Memory regression in windows_home_scroll_perf__timeline_summary

On the PR https://github.com/flutter/flutter/pull/119199, SkiaPerf is reporting a regression in new gen GC count. Usually those are benign, but in this case it seems to be combined with a regression in old gen GC time, and total time spent in GC becoming bimodal, with the high mode about 30% higher than the old value. Dart's GC appears to be keeping up with the new pressure, so there's no increase in frame build times, but I suspect that if we tracked cpu utilization on Windows, it also would have regressed.
cc @gspencergoog @LongCatIsLooong for https://github.com/flutter/flutter/pull/119199
cc @jonahwilliams who added the benchmark.
https://flutter-flutter-perf.skia.org/e/?begin=1681922609&end=1685459911&keys=Xd41633661a3b6de9cb75a0043a2a5733&queries=arch%3Dintel%26branch%3Dmaster%26config%3Ddefault%26device_type%3Dnone%26device_version%3Dnone%26host_type%3Dwin%26sub_result%3D90th_percentile_frame_build_time_millis%26sub_result%3D99th_percentile_frame_build_time_millis%26sub_result%3Daverage_frame_build_time_millis%26sub_result%3Dold_gen_gc_count%26sub_result%3Dworst_frame_build_time_millis%26test%3Dwindows_home_scroll_perf__timeline_summary&queries=arch%3Dintel%26branch%3Dmaster%26config%3Ddefault%26device_type%3Dnone%26device_version%3Dnone%26host_type%3Dwin%26sub_result%3D90th_percentile_frame_build_time_millis%26sub_result%3D99th_percentile_frame_build_time_millis%26sub_result%3Daverage_frame_build_time_millis%26sub_result%3Dold_gen_gc_count%26sub_result%3Dtotal_ui_gc_time%26sub_result%3Dworst_frame_build_time_millis%26test%3Dwindows_home_scroll_perf__timeline_summary&requestType=0&selected=commit%3D35007%26name%3D%252Carch%253Dintel%252Cbranch%253Dmaster%252Cconfig%253Ddefault%252Cdevice_type%253Dnone%252Cdevice_version%253Dnone%252Chost_type%253Dwin%252Csub_result%253Dnew_gen_gc_count%252Ctest%253Dwindows_home_scroll_perf__timeline_summary%252C&xbaroffset=35007

I don't have a Windows device to repro this, and looking at the code changes nothing stands out, I wonder if it could be the local const variable here?
https://github.com/LongCatIsLooong/flutter/blob/8a0bb989345f5257e7ae77225ec0dd1b878418ec/packages/flutter/lib/src/material/tooltip.dart#L516-L523

const is a compile time constant, it doesn't matter where you define it.

@jonahwilliams do const variables get gc'ed when they're out of scope? I think I've seen a similar regression: https://github.com/flutter/flutter/pull/126382

I think that you should acquire one of the desktop platforms and verify this locally. If you don't have any please talk to your manager and gcard something, guess and check is unlikely to be productive.

do const variables get gc'ed when they're out of scope?

constants are constant, they don't get allocated or deallocated.

Ok getting a cloudtop windows

Ahh yeah, you will create a new iterable. That can be avoided by using a for (var i = 0...) style loop

From Engine triage. This benchmark is running in a VM https://chromium-swarm.appspot.com/bot?id=flutter-prod-windows-us-central1-a-9-h1mw, so timing info will be suspect and/or noisy. There's an issue open that I'll cross link later for getting machines in the device lab for running host-only tests (and desktop benchmarks like this one.)
It should be an easy fix to change to a regular for-loop from an iterator, though, so I'll still mark this P3 and assign to  @LongCatIsLooong.

I couldn't reproduce this on my cloudtop instance, using dart bin/test_runner.dart test -t windows_home_scroll_perf__timeline_summary | grep gc_. The 2 commit hashes I used: #9da1d and #1b800.
results:
#9da1d (before):
new_gen_gc_count: 66,
old_gen_gc_count: 6,
total_ui_gc_time: 36.9700000

#1b800 (after):
new_gen_gc_count: 66,
old_gen_gc_count: 9,
total_ui_gc_time: 35.147

@zanderso I think the iterator issue is already fixed. It was tracked by another github issue. Should I close this one?

authors: LongCatIsLooong jonahwilliams zanderso


text:
Null check error in vm_snapshot_analysis

Starting in the Engine -> Framework roll here https://github.com/flutter/flutter/pull/129914, builds started failing with:
Null check operator used on a null value
            #0      _ProgramInfoBuilder.createInfoNodeFor (package:vm_snapshot_analysis/v8_profile.dart:450:53)
            #1      _ProgramInfoBuilder.getInfoNodeFor (package:vm_snapshot_analysis/v8_profile.dart:374:14)
            #2      _ProgramInfoBuilder.createInfoNodeFor (package:vm_snapshot_analysis/v8_profile.dart:444:23)
            #3      _ProgramInfoBuilder.getInfoNodeFor (package:vm_snapshot_analysis/v8_profile.dart:374:14)
            #4      _ProgramInfoBuilder.createInfoNodeFor (package:vm_snapshot_analysis/v8_profile.dart:419:54)
            #5      _ProgramInfoBuilder.getInfoNodeFor (package:vm_snapshot_analysis/v8_profile.dart:374:14)
            #6      ListIterable.forEach (dart:_internal/iterable.dart:39:13)
            #7      _ProgramInfoBuilder.build (package:vm_snapshot_analysis/v8_profile.dart:338:16)
            #8      toProgramInfo (package:vm_snapshot_analysis/v8_profile.dart:282:8)
            #9      _treemapFromSnapshot (package:vm_snapshot_analysis/treemap.dart:158:27)
            #10     treemapFromJson (package:vm_snapshot_analysis/treemap.dart:85:5)
            #11     SizeAnalyzer.analyzeZipSizeAndAotSnapshot (package:flutter_tools/src/base/analyze_size.dart:123:59)
            #12     AndroidGradleBuilder._performCodeSizeAnalysis (package:flutter_tools/src/android/gradle.dart:623:60)
            #13     AndroidGradleBuilder.buildGradleApp (package:flutter_tools/src/android/gradle.dart:604:15)
            <asynchronous suspension>
            #14     AndroidGradleBuilder.buildApk (package:flutter_tools/src/android/gradle.dart:242:5)
            <asynchronous suspension>
            #15     BuildApkCommand.runCommand (package:flutter_tools/src/commands/build_apk.dart:116:5)
            <asynchronous suspension>
            #16     FlutterCommand.run.<anonymous closure> (package:flutter_tools/src/runner/flutter_command.dart:1297:27)
            <asynchronous suspension>
            #17     AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:150:19)
            <asynchronous suspension>
            #18     CommandRunner.runCommand (package:args/command_runner.dart:212:13)
            <asynchronous suspension>
            #19     FlutterCommandRunner.runCommand.<anonymous closure> (package:flutter_tools/src/runner/flutter_command_runner.dart:339:9)
            <asynchronous suspension>
            #20     AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:150:19)
            <asynchronous suspension>
            #21     FlutterCommandRunner.runCommand (package:flutter_tools/src/runner/flutter_command_runner.dart:285:5)
            <asynchronous suspension>
            #22     run.<anonymous closure>.<anonymous closure> (package:flutter_tools/runner.dart:115:9)
            <asynchronous suspension>
            #23     AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:150:19)
            <asynchronous suspension>
            #24     main (package:flutter_tools/executable.dart:90:3)
            <asynchronous suspension>

It looks like this was introduced by the Dart roll here:
with the change: https://dart.googlesource.com/sdk.git/+/a4f59b8c205e69f902a1ea146e440eaa9c9c211e
cc @rmacnak-google

It looks like @rmacnak-google's change may have been an attempt to fix https://dart.googlesource.com/sdk.git/+/99db606baba3642203a2718fbd80adac5094e22b from @mkustermann

Looks like the thing that is needed to fix the roll is to update vm_snapshot_analysis dependency from 0.7.2 to 0.7.4

(Tess made https://github.com/flutter/flutter/pull/129950)

I currently have https://github.com/flutter/flutter/pull/129788 which was initially intended for another fix, but it also updates vm_snapshot_analysis from 0.7.2 to 0.7.4. It seems like the tests are continuing to give the same null check error as above.
Example: https://ci.chromium.org/p/flutter/builders/try/Linux build_tests_3_3/7356?

/cc @sstrickl Could you take a look?

Yes, I'm looking into it now.

Looks like vm_snapshot_analysis 0.7.4 expects updated dart sdk, won't work with older dart sdk.
https://dart-review.googlesource.com/c/sdk/+/312640 is to help flutter to get on 0.7.4 while staying on older dart sdk.

package:vm_snapshot_analysis 0.7.6 got rolled in as part of https://github.com/flutter/flutter/pull/130163, which should fix the issue. Please reopen if this is seen again with a release that includes it.

authors: aam drewroengoogle mkustermann sstrickl zanderso


text:
[video_player][android][Impeller][3.16.3] video play , only audio , no image

Is there an existing issue for this?

[X] I have searched the existing issues
[X] I have read the guide to filing a bug

Steps to reproduce
down video_player  example
and add android  Impeller
     <meta-data
           android:name="io.flutter.embedding.android.EnableImpeller"
            android:value="true" />

and debug or run
Expected results
show images
Actual results
no images
Code sample
Code sample
[Paste your code here]

Screenshots or Video

Screenshots / Video demonstration
[Upload media here]

Logs
Logs
[Paste your logs here]

Flutter Doctor output
Doctor output
[Paste your output here]

Because this bug is bound to appear, and this situation will occur whether it is an emulator android or a real machine android.
The code uses the video_player example official example, and then turns on Impeller
so, the code and logs are not provided.

audio is ok
no image

Hi @24 thanks for trying out Impeller on Android. The preview work is not yet complete, and the functionality that video player needs is being tracked in https://github.com/flutter/flutter/issues/139702


text:
[Linux] Couldn't able to build a Linux snap

Steps to reproduce

Use the below attached sample
Run a snapcraft --use-lxd to build a Linux snap
Geeting exception

Expected results
The snap build should generate
Actual results

Code sample
sample.zip
Screenshots or Video

Logs
Logs
[Paste your logs here]

Flutter Doctor output
Doctor output
[✓] Flutter (Channel stable, 3.19.4, on Ubuntu 22.04.2 LTS 6.5.0-26-generic,
    locale en_IN)
    • Flutter version 3.19.4 on channel stable at
      /home/syncfusion/snap/flutter/common/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 68bfaea224 (4 weeks ago), 2024-03-20 15:36:31 -0700
    • Engine revision a5c24f538d
    • Dart version 3.3.2
    • DevTools version 2.31.1

[!] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
    • Android SDK at /home/syncfusion/Android/Sdk
    ✗ cmdline-tools component is missing
      Run `path/to/sdkmanager --install "cmdline-tools;latest"`
      See https://developer.android.com/studio/command-line for more details.
    ✗ Android license status unknown.
      Run `flutter doctor --android-licenses` to accept the SDK licenses.
      See https://flutter.dev/docs/get-started/install/linux#android-setup for
      more details.

[✓] Chrome - develop for the web
    • Chrome at google-chrome

[✓] Linux toolchain - develop for Linux desktop
    • clang version 10.0.0-4ubuntu1
    • cmake version 3.16.3
    • ninja version 1.10.0
    • pkg-config version 0.29.1

[!] Android Studio (not installed)
    • Android Studio not found; download from
      https://developer.android.com/studio/index.html
      (or visit https://flutter.dev/docs/get-started/install/linux#android-setup
      for detailed instructions).

[✓] VS Code (version 1.88.1)
    • VS Code at /snap/code/current/usr/share/code
    • Flutter extension version 3.84.0

[✓] Connected device (2 available)
    • Linux (desktop) • linux  • linux-x64      • Ubuntu 22.04.2 LTS
      6.5.0-26-generic
    • Chrome (web)    • chrome • web-javascript • Google Chrome 114.0.5735.133

[✓] Network resources
    • All expected network resources are available.

! Doctor found issues in 2 categories.

Kindly report this on the flutter snap repo so that it can be properly addressed. Snap is a third-party tool not managed by the flutter team.
Closing from here.
Thank you

authors: Yuvaraj-Gajaraj danagbemava-nc


text:
mac-3 lost external connection phone device.

Type of Request
bug
Infrastructure Environment
LUCI, Github, Cocoon scheduler, Autosubmit, etc...
What is happening?
mac-3 lost external connection phone device.

Steps to reproduce
Step 1:
Step 2:
..
Step n:
Expected results
I expect to see X when Y is finished.

Rebooting phone device to restore connection.


text:
Predictive Back Gesture animation doesn't and can't implement material design spec to match native behavior

Steps to reproduce
Use PredictiveBackPageTransitionsBuilder()
Expected results
The same animations and behavior as the native apps and system.
Spec: https://developer.android.com/design/ui/mobile/guides/patterns/predictive-back
Actual results
In the "pre-commit" part of the animation:

the front page abruptly disappears when swiping across 35% of the screen
the front and back pages ignore if the gesture started from the left or right edge
the front and back pages don't go up and down following finger

In the "post-commit" part of the animation:

the animation goes way too fast (<100ms, should be ~300ms)
the animation blocks all user inputs for about 700ms after the animation is visually finished
the animation is the same as the "pre-commit" one, which is not what happens in the rest of Android and in the spec.

1. and 6. can be worked around by writing a custom PageTransitionBuilder.
2. and 3. can be partially worked around: only for the front page.
4. and 5. cannot be worked around without editing the SDK source code itself.

Flutter Doctor output
Doctor output
flutter doctor -v                                                                                devenv-shell-env
[✓] Flutter (Channel master, 3.24.0-1.0.pre.605, on NixOS 24.05 (Uakari) 6.8.12, locale en_US.UTF-8)
    • Flutter version 3.24.0-1.0.pre.605 on channel master at /home/paulg/Repos/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision bced008679 (14 hours ago), 2024-08-15 22:29:24 -0400
    • Engine revision a8fefc8118
    • Dart version 3.4.3
    • DevTools version 2.38.0

[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
    • Android SDK at /nix/store/nzwnj7rq8a6cvzbsszf4n9zfvx101zm5-androidsdk/libexec/android-sdk
    • Platform android-34, build-tools 30.0.3
    • ANDROID_HOME = /nix/store/nzwnj7rq8a6cvzbsszf4n9zfvx101zm5-androidsdk/libexec/android-sdk
    • ANDROID_SDK_ROOT = /nix/store/nzwnj7rq8a6cvzbsszf4n9zfvx101zm5-androidsdk/libexec/android-sdk
    • Java binary at: /nix/store/l7pwy1rxdrb13svqandm720d06fycd8c-openjdk-17.0.11+9/lib/openjdk/bin/java
    • Java version OpenJDK Runtime Environment (build 17.0.11+9-nixos)
    • All Android licenses accepted.

[✓] Chrome - develop for the web
    • CHROME_EXECUTABLE = /nix/store/cg5bvzxml5bbdw8wlrywb6q7hpdjq0ij-google-chrome-127.0.6533.88/bin/google-chrome-stable

[✓] Linux toolchain - develop for Linux desktop
    • clang version 16.0.6
    • cmake version 3.29.6
    • ninja version 1.12.1
    • pkg-config version 0.29.2

[!] Android Studio (not installed)
    • Android Studio not found; download from https://developer.android.com/studio/index.html
      (or visit https://flutter.dev/docs/get-started/install/linux#android-setup for detailed instructions).

[✓] Connected device (3 available)
    • Pixel 7 Pro (mobile) • 192.168.1.13:43591 • android-arm64  • Android 15 (API 35)
    • Linux (desktop)      • linux              • linux-x64      • NixOS 24.05 (Uakari) 6.8.12
    • Chrome (web)         • chrome             • web-javascript • Google Chrome 127.0.6533.88

[✓] Network resources
    • All expected network resources are available.

! Doctor found issues in 1 category.

I wrote a few comments on this PR while investigating: https://github.com/flutter/flutter/pull/141373

I guess it's important to note that I'm using Android 15 (API 35), when the current SDK implementation is based on Android 14 (API 34): https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/material/predictive_back_page_transitions_builder.dart#L181
I don't remember how this animation looked on this version, so maybe flutter's implementation was more faithful than what I'm describing here.

Hi @PaulGrandperrin

the front page abruptly disappears when swiping across 35% of the screen

I checked this on Flutter and Android native apps and I can see different swipe gesture distances. In Flutter app, I need to swipe longer than on Android native.

Demo

Flutter
Android native

the front and back pages ignore if the gesture started from the left or right edge
the front and back pages don't go up and down following finger

Can you please be more specific on these points?

Can you please be more specific on these points?

I think a lot can be explained by the differences between Android 14 and 15. The current code was tested against 14, and I now realize that on this version, the animation mostly works for several reasons:

on 14, the animation is simpler and looks like the pre-commit and post-commit phases are part of one bigger animation
on 14, there's something that nudge the progress values quickly around 35%, making it difficult to see that the front page vanishes abruptly.
on 14, I guess the animation doesn't react to the finger going up and down

However, I strongly suppose the 700ms of unresponsive app after a route pop is still there.
I captured on my Android 15 phone, what the current code looks like: https://drive.google.com/file/d/1ZfraE_JL6PA27aD0gMij3kpzcvOnOEcY/view?usp=sharing
You can see that

the abrupt opacity drop
the extremely fast postCommit animation
how the app becomes unresponsive for almost a second after the route is popped
no response to up and down
same animation from left and right

Here's how it looks on this PR: https://drive.google.com/file/d/1ZiOU_fUCc6v_npc2rTg405iyWSSXdDHj/view?usp=sharing
I also show what the animation looks like natively in the Settings.

One important thing is that on Android 15, which will be released very soon, the predictive back gestures are enabled by default.
So a lot of people will soon be exposed to it, and the flutter devs won't be able to fix those issues, even with a custom transition, because part of the responsible code is in TransitionRoute, like the curve controlling the postCommit animation pace.

To better see how the animation adapts from which side it was started: https://drive.google.com/file/d/1ZiqAj-TErJsZuU5Bg2i8gLfgvjBV0Kvp/view?usp=sharing

Thanks for providing more information. I don't have an Android 15 device now, I will label this for other's input.

Expected results
The same animations and behavior as the native apps and system. Spec: https://developer.android.com/design/ui/mobile/guides/patterns/predictive-back

To better see how the animation adapts from which side it was started: https://drive.google.com/file/d/1ZiqAj-TErJsZuU5Bg2i8gLfgvjBV0Kvp/view?usp=sharing

Hey @PaulGrandperrin, the original implementation of the transition was Shared Element Transition, but later @justinmc decided to implement the Full Screen Surfaces version.
Here is a video showing how the Shared Element Transition version looked. I still have its code.
https://github.com/flutter/flutter/assets/8436039/96e4be68-6d3f-4e89-842e-53bd5b5bfaf5

cc @justinmc

On the topic of Shared Element vs. Full Screen Surfaces, it looks like Android has now defaulted to Shared Element. This is what I see if I create a plain Compose app on API 35:

Video of native API 35 default transition between Activities
Screencast from 2024-08-26 12-44-42.webm

Also, I don't see the Full Screen Surfaces animation anywhere if I look for it in the system Android 15 apps.
So I think that Flutter should default to Shared Element transition and not worry about Full Screen Surfaces. Apologies for previously saying the opposite. It looks like the default transition on Android has changed from then and now.

I think Shared Element Transition is currently under development in issue https://github.com/flutter/packages/pull/6321. Am I right, @justinmc?

That PR is a little stale at this point, but my intention was to make the existing OpenContainer transitions work with predictive back. My implementation probably was intended to look like the Shared Element transition mentioned above, but where the popped page animates to look like it's coming from some widget on the previous page.

So @maRci002 since you still have your old code, are you interested in opening a PR to update the PredictiveBackPageTransition animation to look like Shared Element? It seems like https://github.com/flutter/flutter/pull/153635 is not intending to land.

Also, I don't see the Full Screen Surfaces animation anywhere if I look for it in the system Android 15 apps.

My observation is that Android native (using Intents) applies the Shared Element transition; however, when Compose itself animates, it applies the Full Screen Surfaces animation. The official predictive back codelab uses the Full Screen Surfaces animation.
I have created a Compose application where both can be tried out:
MainActivity.kt — don't forget to toggle the useNativeAnimations variable to try out both:
MainActivity.kt
package com.example.compose_predictive_back

import android.content.Intent
import android.os.Bundle
import android.window.BackEvent
import androidx.activity.BackEventCompat
import androidx.activity.ComponentActivity
import androidx.activity.compose.LocalOnBackPressedDispatcherOwner
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.darkColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import com.example.compose_predictive_back.ui.theme.Compose_predictive_backTheme
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
            Compose_predictive_backTheme {
                val useNativeAnimations = true;

                if (useNativeAnimations) {
                    FirstScreen(onClick = {
                        startActivity(
                            Intent(
                                this@MainActivity,
                                SecondActivity::class.java
                            )
                        )
                    })
                } else {
                    Navigator()
                }
            }
        }
    }
}

class SecondActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            SecondScreen()
        }
    }
}

@Composable
fun Navigator() {
    val navController = rememberNavController()

    NavHost(
        navController = navController,
        startDestination = "first_screen",
        // enterTransition = { slideInHorizontally { it / 2 } },
        // exitTransition = { slideOutHorizontally { -it / 2 } },
    ) {
        composable("first_screen") {
            FirstScreen(onClick = { navController.navigate("second_screen") })
        }
        composable("second_screen") {
            SecondScreen()
        }
    }
}

@Composable
fun FirstScreen(onClick: () -> Unit) {
    Surface(color = MaterialTheme.colorScheme.background, modifier = Modifier.fillMaxSize()) {
        Column(
            modifier = Modifier.fillMaxSize(),
            verticalArrangement = Arrangement.Center,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Button(onClick = onClick) {
                Text("Go to Second Screen")
            }
        }
    }
}

@Composable
fun SecondScreen() {
    MaterialTheme(colorScheme = darkColorScheme()) {
        Surface(color = MaterialTheme.colorScheme.background, modifier = Modifier.fillMaxSize()) {
            Column(
                modifier = Modifier.fillMaxSize(),
                verticalArrangement = Arrangement.Center,
                horizontalAlignment = Alignment.CenterHorizontally
            ) {
                Text(text = "Hello, Predictive back!")
                BackControlButton()
            }
        }
    }
}

@Composable
fun BackControlButton() {
    val backPressedDispatcher =
        LocalOnBackPressedDispatcherOwner.current!!.onBackPressedDispatcher

    var progress by remember { mutableFloatStateOf(0f) }

    Button(onClick = {
        CoroutineScope(Dispatchers.Main).launch {
            backPressedDispatcher.dispatchOnBackStarted(
                BackEventCompat(0.1F, 0.1F, progress, BackEvent.EDGE_LEFT)
            )

            delay(timeMillis = 500)

            for (step in 1..95) {
                val updatedProgress = step / 100f
                backPressedDispatcher.dispatchOnBackProgressed(
                    BackEventCompat(0.1F, 0.1F, updatedProgress, BackEvent.EDGE_LEFT)
                )
                progress = updatedProgress
                delay(50)
            }

            delay(timeMillis = 500)

            backPressedDispatcher.dispatchOnBackProgressed(
                BackEventCompat(0.0F, 0.0F, 0F, BackEvent.EDGE_LEFT)
            )
            progress = 0F
        }
    }) {
        Text("Progress: ${(progress * 100).toInt()}%")
    }
}

AndroidManifest.xml: Don't forget to add android:enableOnBackInvokedCallback="true" and also register the second activity like this: <activity android:name=".SecondActivity" />
In gradle/libs.versions.toml, increase the navigationCompose to 2.8.0-beta02 (this is the minimum version required to support the predictive back feature) or higher, such as 2.8.0-alpha08.
Compose - androidx.navigation:navigation-compose:2.8.0-alpha08
https://github.com/user-attachments/assets/1fa64833-24ef-471c-9939-b0ec60201f01
Native (using Intents)
https://github.com/user-attachments/assets/328dd24e-51d6-438f-96f6-2bdcd1454083

So @maRci002 since you still have your old code, are you interested in opening a PR to update the PredictiveBackPageTransition animation to look like Shared Element? It seems like #153635 is not intending to land.

Yes, I am interested in opening a PR. The PredictiveBackPageTransitionsBuilder could be made more generic, for instance, by having its own transition builder. The default could be PredictiveBackPageTransitionsBuilder.sharedElementTransitionBuilder, but the old one, PredictiveBackPageTransitionsBuilder.fullScreenSurfacesTransitionBuilder, would still be available.

@maRci002 Ah good catch, I guess ideally we should have both. Your approach looks good. I'm happy to help review if you open a PR.

authors: PaulGrandperrin goderbauer huycozy justinmc maRci002


text:
Google sign in error 400 when trying to change account after first account select screen

What package does this bug report belong to?
google_sign_in
What target platforms are you seeing this bug on?
Android
Have you already upgraded your packages?
Yes
Dependency versions
https://pastebin.com/EiBCm957
Steps to reproduce

Trigger Google sign in with googleSignIn.signIn()
Select account
Click account selector on top of screen again
Error 400

Expected results
The error should not occur. Just clicking continue after selecting the account in the first step works. It's just the button with the email address at the top that is not working for some reason?
Actual results
Error 400
The server cannot process the request because it is malformed. It should not be retried. That's all we know
Code sample
Code sample
await GoogleSignIn(
    clientId: clientId,
    forceCodeForRefreshToken: true,
  ).signIn()

Screenshots or Videos

Screenshots / Video demonstration

Logs
Logs
<there are no error logs>

Flutter Doctor output
Doctor output
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 3.24.0, on macOS 14.5 23F79 darwin-arm64, locale en-US)
[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
[✓] Xcode - develop for iOS and macOS (Xcode 15.4)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2024.1)
[✓] IntelliJ IDEA Community Edition (version 2024.1.3)
[✓] VS Code (version 1.92.2)
[✓] Connected device (7 available)
[✓] Network resources

• No issues found!

Thanks for the report @LouisHaftmann
I am unable to replicate this using the google_sign_in package example running on Android emulator.
Can you try by clearing the cache ? Are you consistently getting this error on mobile only or on other platforms too ?
Also try on other devices to see if it persists or not.

Sorry for the late replay.
I can reproduce it with the following code:
import 'package:flutter/material.dart';
import 'package:google_sign_in/google_sign_in.dart';

void main() {
  runApp(const MainApp());
}

Future<void> signIn() async {
  const clientId = 'YOUR_CLIENT_ID';
  GoogleSignIn googleSignIn = GoogleSignIn(
    clientId: clientId,
    serverClientId: clientId,
    forceCodeForRefreshToken: true,
  );
  // logout, just for testing
  await googleSignIn.signOut().catchError((_) {});
  await googleSignIn.disconnect().catchError((_) {});

  await googleSignIn.signIn();
}

class MainApp extends StatelessWidget {
  const MainApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: FilledButton(
              onPressed: () {
                signIn();
              },
              child: const Text('Sign in with Google')),
        ),
      ),
    );
  }
}

I also found out that it works without error when setting forceCodeForRefreshToken to false but then the second screen (with Sign in to NAME and account switcher) doesn't even show up.
@darshankawar

I tried with above code, but getting sign_in_failed, com.google.android.gms.common.api.ApiException: 10: which is differrent issue.
Can you add try catch block and see if you get any meaningful log apart from 400 error ?
Also, can you try on other device or other account to check if it persist still ?

You probably need to set the client id (replace the YOUR_CLIENT_ID). The app's Android package name also needs to match the package name in Google Cloud.

Also, can you try on other device or other account to check if it persist still
The error occurs on many different Android devices and Google accounts.

Can you add try catch block and see if you get any meaningful log apart from 400 error
The 400 error doesn't throw an exception in Flutter. I don't even know if such an error could be caused by Flutter or whether this is a bug on Googles side.

@darshankawar

@LouisHaftmann
With clientId as well, we are seeing same error as reported earlier. Without passing it, the code sample runs well without throwing the said error.
You seem to have declared same clientId for serverClientId which doesn't seem to be correct. So please check the implementation.

I'm also getting the same error without serverClientId

Please check this to see if it helps in your case or not.
Not sure if this is specific to macOS Sonoma or not.

authors: LouisHaftmann darshankawar


text:
GestureDetector hitbox doesn't seem to be correct

Steps to Reproduce
the docs state:
/// If this widget has a child, it defers to that child for its sizing behavior.
but it seems to be incorrect...
here's how it looks on ios sim:

if I try clicking in between the icon and text ('articles'), there is no click detected, I have to click on either the icon or text to trigger the gesture, clicking on the 'column' doesn't trigger it (red area below).
is this working as intended or is this hit box that I drew up incorrect, I assumed the red area is supposed to be the area of the gesture that should be detected, but it is really only detecting the blue areas:

Implementation Details
here's the widget using the gesture detector:
  Widget build(BuildContext cxt) {
    return new GestureDetector(
      onTap: () {
        this.onTap(this.idx);
      },
      child: new Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: <Widget>[
            new Icon(const IconData(0xf273, fontFamily: 'ionicons')),
            new Text(this.label, style: handleActive())
          ]
      )
    );
  }

Nevermind I should of read docs better, solution is to use behavior: HitTestBehavior.opaque, allows opaque targets such as the column child.


text:
Flutter beta 0.5.1 does not upgrade to Flutter Release Preview 1 on macOS 10.13.5

The Medium article at https://medium.com/flutter-io/flutter-release-preview-1-943a9b6ee65a?linkId=53249457, "Announcing Flutter Release Preview 1", says:
How do you upgrade to Flutter Release Preview 1? If you’re on the beta channel already, it just takes one command:
$ flutter upgrade
This does not work.

My understanding is that is the release preview version. It came out around a day before the article did and if you check the download links in the installation guide, they point to that version.

@MaikuB is right, the current beta is the Release Preview 1.

@MaikuB mai  you mean beta 0.5.1  is the release preview version?

Yes that was confirmed by @zoechi as well. in fact if you look at the install guides for downloading the Flutter SDK zip file then you'll see it's 0.5.1

Hey sorry for follow up question, is there no upgrade after beta 0.5.1? It seems the last update was 3 months ago? Or should I move to a different branch?
Hope someone can clarify thanks!

@allandaleho 0.5.1 seems still to be the latest beta channel version. You could switch to dev channel until a new beta is released. I don't know what blocks a new beta release.

authors: Chen-Sir MaikuB allandaleho wbeebe zoechi


text:
webview_flutter not working for Angular web app url's

The webview_flutter component is not working for all URL's. Some URL's that we tried work, but when we want to show an existing Angular web app inside a flutter app, then nothing is shown, just a white background.
The url is:
https://aquasense.birdy.life/
Is this by design, a bug or should we do something extra?

Have you tried setting the javascriptMode to JavascriptMode.unrestricted?

Hi, just want to check if this is still a problem for you.

Without additional information, we are unfortunately not sure how to resolve this issue. We are therefore reluctantly going to close this bug for now. Please don't hesitate to comment on the bug if you have any more information for us; we will reopen it right away!
Thanks for your contribution.

authors: emaddoma escamoteur frankps iapicca


text:
_TabSwitchingViewState not actually caching tab builds

Switching tabs in a CupertinoTabScaffold causes ALL of the tabs to be rebuilt, as the tabBuilder function is being called by the _TabSwitchingViewState at every tab index change.
Steps to Reproduce

Have an app using a CupertinoTabScaffold inside a CupertinoApp
Switch between any tab available
All tabs (that have been already opened at least once) will be rebuilt

Solution proposal
What happens, is the condition for rebuilding a tab, will almost always be true (tab_scaffold.dart@338):
if (active || tabs[index] != null) {
     tabs[index] = widget.tabBuilder(context, index);
}

This can be easily solved by making sure the tab is only rebuilt if active, and not already cached
if (active && tabs[index] == null) {
     tabs[index] = widget.tabBuilder(context, index);
}

Using Flutter v1.3.8

@kerberjg this was intentional originally.  Can you describe why rebuilding the tab widgets is an issue in your case? In general, we never cache widgets in Flutter because widgets represent a moment in time, rather than mutations over time.

According to the documentation found here, the behavior of the tabBuilder should be as follows:

When the tab becomes inactive, its content is still cached in the widget tree Offstage

...and we can see that this is more or less what happens in _TabSwitchingViewState's build()... except that the code responsible for building the tabs, is literally defined as: "if we have built this widget, let's rebuild it", as indicated in the code in the first post, which can be found here.
What's more, every time a tab is switched, ALL the tabs are being rebuilt, including the hidden ones.
This brings 2 potential issues:

Is it really necessary to rebuild N tab widget trees, when we need to display only one?
What is the purpose of caching tab widgets in Offstage, if we're going to rebuild them anyway?

...also...

If the aforementioned behavior is indeed correct, the documentation might be considered misleading
Why would I want to rebuild something I don't see when its state is being intact?
Does this mean that specifying the tab content either as Stateful or Stateless is meaningless, because it's going be rebuilt regardless of an actual necessity to do so?

Potential proposed solutions: either...

Make it explicit in the documentation that all of the tabs will and should be rebuilt at every tab switch, if that's the case
Have only the necessary tab widget being built, instead of all of them
Build only the tabs that haven't been cached already

So, the documentation line you mentioned is accurate:

When the tab becomes inactive, its content is still cached in the widget tree Offstage

When you're viewing tab content A, and then you switch to tab content B, tab content A remains offstage even though it's not visible. However, by placing the tab in an Offstage widget and putting it in a TickerMode widget, that widget does not paint itself, nor does it receive ticker updates for animations. This is the caching that the documentation refers to.
You mentioned

ALL the tabs are being rebuilt

But the line that you linked to shows that only the active tab, and the previously viewed tabs are being rebuilt. Any tab that has not yet been built is represented as an empty Container() offstage, which is equivalent to nothing at all.
You asked

What is the purpose of caching tab widgets in Offstage, if we're going to rebuild them anyway?

I'll look into this more. This may be a legitimate thing to change. It is unclear why the tabBuilder needs to be rerun for offstage widgets.
I'll file another ticket to look into the API. We may opt for an approach that places caching in the hands of the developer instead of automatically forcing caching behavior internally.
But I'm still interested to know, is this behavior creating a performance bottleneck for you?  Or is it interfering with some expected UI behavior? Are there any adverse effects for your app as a result of this?

Filed #30822 to investigate a possible new API for caching tab content.

But the line that you linked to shows that only the active tab, and the previously viewed tabs are being rebuilt

This is correct, my bad. After further testing, I was able to confirm that it indeed applies only to tabs that have been opened at least once.

Issue exist on
[✓] Flutter (Channel dev, v1.16.2, on Mac OS X 10.15.4 19E266, locale en-GB)
    • Flutter version 1.16.2 at /Users/taha/Code/flutter_dev
    • Framework revision 58cad787d8 (4 days ago), 2020-03-23 08:33:41 -0700
    • Engine revision 2d42c74a34
    • Dart version 2.8.0 (build 2.8.0-dev.16.0 ba8baa46b4)

[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.3)
    • Android SDK at /Users/taha/Code/sdk
    • Android NDK location not configured (optional; useful for native profiling
      support)
    • Platform android-29, build-tools 29.0.3
    • ANDROID_HOME = /Users/taha/Code/sdk
    • Java binary at: /Applications/Android
      Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build
      1.8.0_212-release-1586-b4-5784211)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 11.4)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 11.4, Build version 11E146
    • CocoaPods version 1.9.1

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 3.6)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin version 44.0.2
    • Dart plugin version 192.7761
    • Java version OpenJDK Runtime Environment (build
      1.8.0_212-release-1586-b4-5784211)

[✓] VS Code (version 1.43.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.8.1

[✓] Connected device (4 available)
    • Taha’s iPhone • 00008020-001059882212002E • ios            • iOS 13.4
    • macOS         • macOS                     • darwin-x64     • Mac OS X
      10.15.4 19E266
    • Chrome        • chrome                    • web-javascript • Google Chrome
      80.0.3987.149
    • Web Server    • web-server                • web-javascript • Flutter Tools

• No issues found!

I'm merging this into https://github.com/flutter/flutter/issues/30822 since it has more up to date discussions with context.

authors: TahaTesser kerberjg matthew-carroll xster