fix weird focus issues with android OSK

This commit is contained in:
Henry Hiles 2026-11-06 10:08:04 -05:00
commit 29840d595a
Signed by: Henry-Hiles
SSH key fingerprint: SHA256:VKQUdS31Q90KvX7EkKMHMBpUspcmItAh86a+v7PGiIs
3 changed files with 24 additions and 9 deletions

View file

@ -0,0 +1,9 @@
import "package:material_ui/material_ui.dart";
extension RefocusAfterRebuild on FocusNode {
/// Focuses this again once the text field using it has been replaced.
void refocusAfterRebuild() {
unfocus();
WidgetsBinding.instance.addPostFrameCallback((_) => requestFocus());
}
}

View file

@ -3,6 +3,7 @@ import "package:flutter_hooks/flutter_hooks.dart";
import "package:hooks_riverpod/hooks_riverpod.dart"; import "package:hooks_riverpod/hooks_riverpod.dart";
import "package:material_ui/material_ui.dart"; import "package:material_ui/material_ui.dart";
import "package:nexus/controllers/composer_draft.dart"; import "package:nexus/controllers/composer_draft.dart";
import "package:nexus/helpers/extensions/refocus_after_rebuild.dart";
import "package:nexus/models/composer_params.dart"; import "package:nexus/models/composer_params.dart";
import "package:nexus/models/relation_type.dart"; import "package:nexus/models/relation_type.dart";
@ -17,11 +18,10 @@ final class ChatComposer({
final node = useFocusNode( final node = useFocusNode(
onKeyEvent: (node, event) { onKeyEvent: (node, event) {
if (event is KeyDownEvent && event.logicalKey == .escape) { if (event is KeyDownEvent && event.logicalKey == .escape) {
final isEditing = ref.read(provider).isEditing;
ref.read(provider.notifier).dismiss(); ref.read(provider.notifier).dismiss();
// Ending an edit replaces the text field, losing its focus // Ending an edit replaces the text field
WidgetsBinding.instance.addPostFrameCallback( if (isEditing) node.refocusAfterRebuild();
(_) => node.requestFocus(),
);
return .handled; return .handled;
} }
@ -44,7 +44,11 @@ final class ChatComposer({
void relate(int rowId, RelationType type) { void relate(int rowId, RelationType type) {
notifier.relate(rowId, type); notifier.relate(rowId, type);
// Starting an edit replaces the text field, losing its focus // Starting or ending an edit replaces the text field
WidgetsBinding.instance.addPostFrameCallback((_) => node.requestFocus()); if (type == .edit || relationType == .edit) {
node.refocusAfterRebuild();
} else {
node.requestFocus();
}
} }
} }

View file

@ -8,6 +8,7 @@ import "package:nexus/controllers/bot_command_draft.dart";
import "package:nexus/controllers/bot_commands.dart"; import "package:nexus/controllers/bot_commands.dart";
import "package:nexus/controllers/composer_draft.dart"; import "package:nexus/controllers/composer_draft.dart";
import "package:nexus/controllers/rooms.dart"; import "package:nexus/controllers/rooms.dart";
import "package:nexus/helpers/extensions/refocus_after_rebuild.dart";
import "package:nexus/helpers/extensions/show_error_snack_bar.dart"; import "package:nexus/helpers/extensions/show_error_snack_bar.dart";
import "package:nexus/helpers/extensions/with_latest_edit.dart"; import "package:nexus/helpers/extensions/with_latest_edit.dart";
import "package:nexus/models/bot_command.dart"; import "package:nexus/models/bot_command.dart";
@ -178,8 +179,8 @@ class const Composer(
void dismiss() { void dismiss() {
draftNotifier.dismiss(); draftNotifier.dismiss();
// Ending an edit replaces the text field, losing its focus // Ending an edit replaces the text field
WidgetsBinding.instance.addPostFrameCallback((_) => node?.requestFocus()); if (isEditing && (node?.hasFocus ?? false)) node?.refocusAfterRebuild();
} }
final sinceTypingSent = useMemoized(Stopwatch.new); final sinceTypingSent = useMemoized(Stopwatch.new);
@ -302,7 +303,8 @@ class const Composer(
); );
} }
ref.read(botCommandProvider.notifier).clear(); ref.read(botCommandProvider.notifier).clear();
WidgetsBinding.instance.addPostFrameCallback((_) => node?.requestFocus()); // The text field replaces the command form
node?.refocusAfterRebuild();
} }
void send() { void send() {