always place cursor at end of file when switching to edit mode

Removes the unreliable viewport-centre cursor heuristic. Switching to
edit mode now always positions the cursor at text.length and scrolls to
the bottom, whether arriving from a regular tap or a long-press. The
long-press scroll-to-end on initial load (view mode) is unchanged.

Cleans up _cursorAtEnd flag, _editorKey / GlobalKey, _getOffsetAtViewportCenter,
and the public WrappedCodeFieldState / findRenderEditable that were only
needed for the removed feature.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
randogoth 2026-06-19 19:01:21 +03:00
parent db13702e54
commit 14d6b3c44d
2 changed files with 15 additions and 20 deletions

View file

@ -43,7 +43,9 @@ class _WrappedCodeFieldState extends State<WrappedCodeField> {
@override @override
void dispose() { void dispose() {
if (widget.focusNode == null) {
_focusNode.dispose(); _focusNode.dispose();
}
super.dispose(); super.dispose();
} }

View file

@ -43,13 +43,11 @@ class _NoteEditorScreenState extends State<NoteEditorScreen> {
bool _isLoading = true; bool _isLoading = true;
bool _autoSaveEnabled = false; bool _autoSaveEnabled = false;
double _fontSize = 16.0; double _fontSize = 16.0;
bool _cursorAtEnd = false;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_mode = widget.initialMode; _mode = widget.initialMode;
_cursorAtEnd = widget.scrollToEnd;
_loadPreferences(); _loadPreferences();
_loadNoteContent(); _loadNoteContent();
} }
@ -86,18 +84,16 @@ class _NoteEditorScreenState extends State<NoteEditorScreen> {
_isLoading = false; _isLoading = false;
}); });
if (widget.initialMode == NoteMode.edit) {
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
if (widget.initialMode == NoteMode.edit) {
_controller.selection = _controller.selection =
TextSelection.collapsed(offset: _controller.text.length); TextSelection.collapsed(offset: _controller.text.length);
_editorFocusNode.requestFocus(); _editorFocusNode.requestFocus();
});
} else if (widget.scrollToEnd) { } else if (widget.scrollToEnd) {
// Two frames: first renders the content, second has a stable maxScrollExtent. // Two frames: first renders content, second has a stable maxScrollExtent.
WidgetsBinding.instance.addPostFrameCallback((_) {
WidgetsBinding.instance.addPostFrameCallback((_) => _scrollToBottom()); WidgetsBinding.instance.addPostFrameCallback((_) => _scrollToBottom());
});
} }
});
} }
void _scrollToBottom() { void _scrollToBottom() {
@ -224,15 +220,12 @@ class _NoteEditorScreenState extends State<NoteEditorScreen> {
break; break;
case 'Mode Edit': case 'Mode Edit':
setState(() { _mode = NoteMode.edit; }); setState(() { _mode = NoteMode.edit; });
if (_cursorAtEnd) {
_cursorAtEnd = false; // consume once
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
_controller.selection = TextSelection.collapsed( _controller.selection = TextSelection.collapsed(
offset: _controller.text.length); offset: _controller.text.length);
_editorFocusNode.requestFocus(); _editorFocusNode.requestFocus();
_scrollToBottom(); _scrollToBottom();
}); });
}
break; break;
case 'Mode Preview': case 'Mode Preview':
setState(() { _mode = NoteMode.preview; }); setState(() { _mode = NoteMode.preview; });