Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementations of FocusNodes throw error. #148033

Open
FMorschel opened this issue May 9, 2024 · 6 comments
Open

Implementations of FocusNodes throw error. #148033

FMorschel opened this issue May 9, 2024 · 6 comments
Labels
a: error message Error messages from the Flutter framework f: focus Focus traversal, gaining or losing focus found in release: 3.19 Found to occur in 3.19 found in release: 3.22 Found to occur in 3.22 framework flutter/packages/flutter repository. See also f: labels. has reproducible steps The issue has been confirmed reproducible and is ready to work on P3 Issues that are less important to the Flutter project team-framework Owned by Framework team triaged-framework Triaged by Framework team

Comments

@FMorschel
Copy link
Contributor

Steps to reproduce

  1. Create a delegating/forwarding class that implements FocusNode.
  2. Create an instance of that class and pass it to a TextField.
  3. Set the TextField.autofocus property to true.
  4. Run the program.

Expected results

No errors.

Actual results

Erros in log bellow.

Code sample

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

void main() => runApp(
      MaterialApp(
        home: Scaffold(
          appBar: AppBar(
            title: const Text('Example'),
          ),
          body: TextField(
            focusNode: DelegatingFocusNode(),
            autofocus: true,
          ),
        ),
      ),
    );

class DelegatingFocusNode implements FocusNode {
  DelegatingFocusNode({
    String? debugLabel,
    // ignore: deprecated_member_use, api needed
    FocusOnKeyCallback? onKey,
    FocusOnKeyEventCallback? onKeyEvent,
    bool skipTraversal = false,
    bool canRequestFocus = true,
    bool descendantsAreFocusable = true,
    bool descendantsAreTraversable = true,
  }) : _base = FocusNode(
          canRequestFocus: canRequestFocus,
          debugLabel: debugLabel,
          descendantsAreFocusable: descendantsAreFocusable,
          descendantsAreTraversable: descendantsAreTraversable,
          // ignore: deprecated_member_use, api needed
          onKey: onKey,
          onKeyEvent: onKeyEvent,
          skipTraversal: skipTraversal,
        );

  DelegatingFocusNode.fromClass(this._base);

  final FocusNode _base;

  @override
  bool get canRequestFocus => _base.canRequestFocus;

  @override
  set canRequestFocus(bool value) => _base.canRequestFocus = value;

  @override
  String? get debugLabel => _base.debugLabel;

  @override
  set debugLabel(String? value) => _base.debugLabel = value;

  @override
  bool get descendantsAreFocusable => _base.descendantsAreFocusable;

  @override
  set descendantsAreFocusable(bool value) =>
      _base.descendantsAreFocusable = value;

  @override
  bool get descendantsAreTraversable => _base.descendantsAreTraversable;

  @override
  set descendantsAreTraversable(bool value) =>
      _base.descendantsAreTraversable = value;

  @override
  // ignore: deprecated_member_use, api needed
  FocusOnKeyCallback? get onKey => _base.onKey;

  @override
  // ignore: deprecated_member_use, api needed
  set onKey(FocusOnKeyCallback? value) => _base.onKey = value;

  @override
  FocusOnKeyEventCallback? get onKeyEvent => _base.onKeyEvent;

  @override
  set onKeyEvent(FocusOnKeyEventCallback? value) => _base.onKeyEvent = value;

  @override
  bool get skipTraversal => _base.skipTraversal;

  @override
  set skipTraversal(bool value) => _base.skipTraversal = value;

  @override
  void addListener(VoidCallback listener) => _base.addListener(listener);

  @override
  Iterable<FocusNode> get ancestors => _base.ancestors;

  @override
  FocusAttachment attach(
    BuildContext? context, {
    FocusOnKeyEventCallback? onKeyEvent,
    // ignore: deprecated_member_use, api needed
    FocusOnKeyCallback? onKey,
  }) =>
      // ignore: deprecated_member_use, api needed
      _base.attach(context, onKeyEvent: onKeyEvent, onKey: onKey);

  @override
  Iterable<FocusNode> get children => _base.children;

  @override
  bool consumeKeyboardToken() => _base.consumeKeyboardToken();

  @override
  BuildContext? get context => _base.context;

  @override
  List<DiagnosticsNode> debugDescribeChildren() =>
      _base.debugDescribeChildren();

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) =>
      _base.debugFillProperties(properties);

  @override
  Iterable<FocusNode> get descendants => _base.descendants;

  @override
  void dispose() => _base.dispose();

  @override
  FocusScopeNode? get enclosingScope => _base.enclosingScope;

  @override
  bool focusInDirection(TraversalDirection direction) =>
      _base.focusInDirection(direction);

  @override
  bool get hasFocus => _base.hasFocus;

  @override
  bool get hasListeners => _base.hasListeners;

  @override
  bool get hasPrimaryFocus => _base.hasPrimaryFocus;

  @override
  FocusHighlightMode get highlightMode => _base.highlightMode;

  @override
  FocusScopeNode? get nearestScope => _base.nearestScope;

  @override
  bool nextFocus() => _base.nextFocus();

  @override
  void notifyListeners() => _base.notifyListeners();

  @override
  Offset get offset => _base.offset;

  @override
  FocusNode? get parent => _base.parent;

  @override
  bool previousFocus() => _base.previousFocus();

  @override
  Rect get rect => _base.rect;

  @override
  void removeListener(VoidCallback listener) => _base.removeListener(listener);

  @override
  void requestFocus([FocusNode? node]) => _base.requestFocus(node);

  @override
  Size get size => _base.size;

  @override
  DiagnosticsNode toDiagnosticsNode({
    String? name,
    DiagnosticsTreeStyle? style,
  }) =>
      _base.toDiagnosticsNode(name: name, style: style);

  @override
  String toStringDeep({
    String prefixLineOne = '',
    String? prefixOtherLines,
    DiagnosticLevel minLevel = DiagnosticLevel.debug,
  }) =>
      _base.toStringDeep(
        prefixLineOne: prefixLineOne,
        prefixOtherLines: prefixOtherLines,
        minLevel: minLevel,
      );

  @override
  String toStringShallow({
    String joiner = ', ',
    DiagnosticLevel minLevel = DiagnosticLevel.debug,
  }) =>
      _base.toStringShallow(minLevel: minLevel, joiner: joiner);

  @override
  String toStringShort() => _base.toStringShort();

  @override
  String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) =>
      _base.toString(minLevel: minLevel);

  @override
  Iterable<FocusNode> get traversalChildren => _base.traversalChildren;

  @override
  Iterable<FocusNode> get traversalDescendants => _base.traversalDescendants;

  @override
  void unfocus({UnfocusDisposition disposition = UnfocusDisposition.scope}) =>
      _base.unfocus(disposition: disposition);
}

Screenshots or Video

No response

Logs

Logs
════════ Exception caught by scheduler library ═════════════════════════════════
The following NoSuchMethodError was thrown during a scheduler callback:
Class 'DelegatingFocusNode' has no instance getter '_parent'.
Receiver: Instance of 'DelegatingFocusNode'
Tried calling: _parent

When the exception was thrown, this was the stack:
#0      DelegatingFocusNode._parent (package:bug/main.dart:18:7)
main.dart:18
#1      FocusScopeNode.autofocus (package:flutter/src/widgets/focus_manager.dart:1368:14)
focus_manager.dart:1368
#2      EditableTextState.didChangeDependencies.<anonymous closure> (package:flutter/src/widgets/editable_text.dart:2883:34)
editable_text.dart:2883
#3      SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1386:15)
binding.dart:1386
#4      SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1322:11)
binding.dart:1322
#5      SchedulerBinding.scheduleWarmUpFrame.<anonymous closure> (package:flutter/src/scheduler/binding.dart:1034:7)
binding.dart:1034
#9      _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)
isolate_patch.dart:184
(elided 3 frames from class _Timer and dart:async-patch)
════════════════════════════════════════════════════════════════════════════════

Flutter Doctor output

Doctor output
[√] Flutter (Channel stable, 3.19.6, on Microsoft Windows [Version 10.0.22621.3007], locale en-GB)
    • Flutter version 3.19.6 on channel stable at C:\Users\felip_0vh5fa6\.puro\envs\stable\flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 54e66469a9 (3 weeks ago), 2024-04-17 13:08:03 -0700
    • Engine revision c4cd48e186
    • Dart version 3.3.4
    • DevTools version 2.31.1

[√] Windows Version (Installed version of Windows is version 10 or higher)

[√] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
    • Android SDK at C:\Users\felip_0vh5fa6\AppData\Local\Android\sdk
    • Platform android-34, build-tools 34.0.0
    • Java binary at: C:\Users\felip_0vh5fa6\AppData\Local\Programs\Android Studio\jbr\bin\java
    • Java version OpenJDK Runtime Environment (build 17.0.9+0--11185874)
    • All Android licenses accepted.

[√] Chrome - develop for the web
    • Chrome at C:\Program Files\Google\Chrome\Application\chrome.exe

[√] Visual Studio - develop Windows apps (Visual Studio Community 2022 17.4.5)
    • Visual Studio at C:\Program Files\Microsoft Visual Studio\2022\Community
    • Visual Studio Community 2022 version 17.4.33403.182
    • Windows 10 SDK version 10.0.19041.0

[√] Android Studio (version 2023.2)
    • Android Studio at C:\Users\felip_0vh5fa6\AppData\Local\Programs\Android Studio
    • 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 17.0.9+0--11185874)

[√] IntelliJ IDEA Community Edition (version 2024.1)
    • IntelliJ at C:\Users\felip_0vh5fa6\AppData\Local\Programs\IntelliJ IDEA Community Edition
    • Flutter plugin version 78.5.1
    • Dart plugin version 241.15845

[√] VS Code (version 1.89.0)
    • VS Code at C:\Users\felip_0vh5fa6\AppData\Local\Programs\Microsoft VS Code
    • Flutter extension version 3.78.0

[√] VS Code (version 1.88.0-insider)
    • VS Code at C:\Users\felip_0vh5fa6\AppData\Local\Programs\Microsoft VS Code Insiders
    • Flutter extension version 3.64.0

[√] Connected device (3 available)
    • Windows (desktop) • windows • windows-x64    • Microsoft Windows [Version 10.0.22621.3007]
    • Chrome (web)      • chrome  • web-javascript • Google Chrome 124.0.6367.119
    • Edge (web)        • edge    • web-javascript • Microsoft Edge 124.0.2478.67

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

• No issues found!
@danagbemava-nc danagbemava-nc added the in triage Presently being triaged by the triage team label May 9, 2024
@danagbemava-nc
Copy link
Member

Hi @FMorschel, is there a specific reason you're implementing instead of extending? If you extend, it doesn't throw the exception.

@danagbemava-nc danagbemava-nc added the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label May 9, 2024
@FMorschel
Copy link
Contributor Author

Yes, I've noticed that as well. I commented about it here: dart-lang/language#3748 (comment).

The reason I'm implementing it is because I'd like to use an already existing instance of FocusNode and to only forward the calls to it. I previously had it extended (which was so much less troublesome for me because of all 48 methods, getters and setters I had to forward).

@github-actions github-actions bot removed the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label May 9, 2024
@danagbemava-nc
Copy link
Member

Labeling for further insight from the team.

Reproducible using the code sample provided above.

flutter doctor -v
[!] Flutter (Channel stable, 3.19.6, on macOS 14.4.1 23E224 darwin-arm64, locale en-GB)
    • Flutter version 3.19.6 on channel stable at /Users/nexus/dev/sdks/flutter
    ! Warning: `flutter` on your path resolves to /Users/nexus/dev/sdks/flutters/bin/flutter, which is not inside your current Flutter SDK checkout at /Users/nexus/dev/sdks/flutter. Consider adding /Users/nexus/dev/sdks/flutter/bin to the front of your path.
    ! Warning: `dart` on your path resolves to /Users/nexus/dev/sdks/flutters/bin/dart, which is not inside your current Flutter SDK checkout at /Users/nexus/dev/sdks/flutter. Consider adding /Users/nexus/dev/sdks/flutter/bin to the front of your path.
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 54e66469a9 (3 weeks ago), 2024-04-17 13:08:03 -0700
    • Engine revision c4cd48e186
    • Dart version 3.3.4
    • DevTools version 2.31.1
    • If those were intentional, you can disregard the above warnings; however it is recommended to use "git" directly to perform update checks and upgrades.

[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
    • Android SDK at /Users/nexus/Library/Android/sdk
    • Platform android-34, build-tools 34.0.0
    • Java binary at: /Users/nexus/Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 17.0.7+0-17.0.7b1000.6-10550314)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 15.3)
    • Xcode at /Applications/Xcode-15.3.0.app/Contents/Developer
    • Build 15E204a
    • CocoaPods version 1.15.2

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

[✓] Android Studio (version 2023.1)
    • Android Studio at /Users/nexus/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 17.0.7+0-17.0.7b1000.6-10550314)

[✓] IntelliJ IDEA Ultimate Edition (version 2023.2.5)
    • IntelliJ at /Users/nexus/Applications/IntelliJ IDEA Ultimate.app
    • Flutter plugin version 77.2.2
    • Dart plugin version 232.10286

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

[✓] Connected device (4 available)
    • Nexus (mobile)       • 00008020-001875E83A38002E • ios            • iOS 17.4.1 21E236
    • Dean’s iPad (mobile) • 00008103-000825C811E3401E • ios            • iOS 17.4.1 21E236
    • macOS (desktop)      • macos                     • darwin-arm64   • macOS 14.4.1 23E224 darwin-arm64
    • Chrome (web)         • chrome                    • web-javascript • Google Chrome 124.0.6367.119

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

! Doctor found issues in 1 category.
[✓] Flutter (Channel master, 3.22.0-29.0.pre.5, on macOS 14.4.1 23E224 darwin-arm64, locale en-GB)
    • Flutter version 3.22.0-29.0.pre.5 on channel master at /Users/nexus/dev/sdks/flutters
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 076e701f46 (9 hours ago), 2024-05-08 21:45:28 -0700
    • Engine revision 69f2d9610a
    • Dart version 3.5.0 (build 3.5.0-138.0.dev)
    • DevTools version 2.36.0-dev.5

[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
    • Android SDK at /Users/nexus/Library/Android/sdk
    • Platform android-34, build-tools 34.0.0
    • Java binary at: /Users/nexus/Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 17.0.7+0-17.0.7b1000.6-10550314)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 15.3)
    • Xcode at /Applications/Xcode-15.3.0.app/Contents/Developer
    • Build 15E204a
    • CocoaPods version 1.15.2

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

[✓] Android Studio (version 2023.1)
    • Android Studio at /Users/nexus/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 17.0.7+0-17.0.7b1000.6-10550314)

[✓] IntelliJ IDEA Ultimate Edition (version 2023.2.5)
    • IntelliJ at /Users/nexus/Applications/IntelliJ IDEA Ultimate.app
    • Flutter plugin version 77.2.2
    • Dart plugin version 232.10286

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

[✓] Connected device (5 available)
    • Nexus (mobile)                  • 00008020-001875E83A38002E • ios            • iOS 17.4.1 21E236
    • Dean’s iPad (mobile)            • 00008103-000825C811E3401E • ios            • iOS 17.4.1 21E236
    • macOS (desktop)                 • macos                     • darwin-arm64   • macOS 14.4.1 23E224 darwin-arm64
    • Mac Designed for iPad (desktop) • mac-designed-for-ipad     • darwin         • macOS 14.4.1 23E224 darwin-arm64
    • Chrome (web)                    • chrome                    • web-javascript • Google Chrome 124.0.6367.119

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

• No issues found!

@danagbemava-nc danagbemava-nc added framework flutter/packages/flutter repository. See also f: labels. a: error message Error messages from the Flutter framework f: focus Focus traversal, gaining or losing focus has reproducible steps The issue has been confirmed reproducible and is ready to work on team-framework Owned by Framework team found in release: 3.19 Found to occur in 3.19 found in release: 3.22 Found to occur in 3.22 and removed in triage Presently being triaged by the triage team labels May 9, 2024
@goderbauer goderbauer added P3 Issues that are less important to the Flutter project triaged-framework Triaged by Framework team labels May 14, 2024
@FMorschel
Copy link
Contributor Author

dart-lang/linter#4975 was created and it would help make sure this doesn't happen again.

@FMorschel
Copy link
Contributor Author

The problem is within FocusNode._reparent that tries to set child._parent = this; in line 1025.

From the callstack this is being called from line 1373 FocusScopeNode.autofocus. Which throws earlier than needed because it's trying to read the _parent propriety when it could be reading the parent getter.

@FMorschel
Copy link
Contributor Author

Is there a specific reason that this should not be a public API?

If so, this could be always wrapped in a new private class with this API and any other that should continue to be private so this doesn't throw.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
a: error message Error messages from the Flutter framework f: focus Focus traversal, gaining or losing focus found in release: 3.19 Found to occur in 3.19 found in release: 3.22 Found to occur in 3.22 framework flutter/packages/flutter repository. See also f: labels. has reproducible steps The issue has been confirmed reproducible and is ready to work on P3 Issues that are less important to the Flutter project team-framework Owned by Framework team triaged-framework Triaged by Framework team
Projects
None yet
Development

No branches or pull requests

3 participants