From c4ddca0223b3328051dead9ed989bf446d2e334c Mon Sep 17 00:00:00 2001 From: vicrodh <103399283+vicrodh@users.noreply.github.com> Date: Thu, 16 Jul 2026 20:37:57 -0600 Subject: [PATCH] fix(input): gate hotkeys while text inputs are focused MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A use-site `changed has-focus` on a std-widgets LineEdit/TextEdit never fires — has-focus is an alias into the inner TextInput (slint#7747) — so typing a letter that doubles as a shortcut ran the action instead of inserting the character. Sweep every text-input surface (search, import, create/edit playlist & folder, tag editor, colour picker, settings fields, QConnect dev modal, kiosk shell) and drive UiFocusState.text-input-focused from a `guard-focused` probe property that the change tracker does observe. cc --- crates/qbz-ui/ui/myqbz/CreateMyQbzModal.slint | 6 ++- crates/qbz-ui/ui/myqbz/MyQbzEditModal.slint | 12 ++++- .../ui/playlist/PlaylistManagerView.slint | 6 ++- crates/qbz-ui/ui/primitives/ColorPicker.slint | 9 +++- .../ui/primitives/CreateFolderModal.slint | 6 ++- .../ui/primitives/CreatePlaylistModal.slint | 12 ++++- .../ui/primitives/EditPlaylistModal.slint | 12 ++++- .../ui/primitives/FolderEditModal.slint | 6 ++- .../qbz-ui/ui/primitives/TagEditorModal.slint | 48 +++++++++++++++---- .../ui/settings/AppearanceSettings.slint | 12 ++++- .../ui/settings/IntegrationsSettings.slint | 6 ++- .../ui/settings/LibFolderEditModal.slint | 6 ++- .../ui/settings/LocalLibrarySettings.slint | 12 ++++- .../qbz-ui/ui/settings/PlaybackSettings.slint | 10 ++-- crates/qbz-ui/ui/shell/KioskShell.slint | 8 +++- crates/qbz-ui/ui/shell/QconnectDevModal.slint | 12 ++++- crates/qbz-ui/ui/shell/Sidebar.slint | 12 ++++- .../ui/shell/SidebarPlaylistsPopup.slint | 6 ++- 18 files changed, 165 insertions(+), 36 deletions(-) diff --git a/crates/qbz-ui/ui/myqbz/CreateMyQbzModal.slint b/crates/qbz-ui/ui/myqbz/CreateMyQbzModal.slint index 6f8c62c5d..bfa060cc0 100644 --- a/crates/qbz-ui/ui/myqbz/CreateMyQbzModal.slint +++ b/crates/qbz-ui/ui/myqbz/CreateMyQbzModal.slint @@ -125,7 +125,11 @@ export component CreateMyQbzModal inherits Rectangle { } name-input := LineEdit { text <=> MyQbzCreateState.name; - changed has-focus => { UiFocusState.text-input-focused = self.has-focus; } + // Hotkey-guard probe: a use-site `changed has-focus` on a std-widgets + // input never fires (has-focus is an alias into the inner TextInput), + // so observe it through a local property instead (#619). + property guard-focused: self.has-focus; + changed guard-focused => { UiFocusState.text-input-focused = self.guard-focused; } accepted => { MyQbzCreateActions.submit(); } diff --git a/crates/qbz-ui/ui/myqbz/MyQbzEditModal.slint b/crates/qbz-ui/ui/myqbz/MyQbzEditModal.slint index e21c1242e..1e13734f3 100644 --- a/crates/qbz-ui/ui/myqbz/MyQbzEditModal.slint +++ b/crates/qbz-ui/ui/myqbz/MyQbzEditModal.slint @@ -74,7 +74,11 @@ export component MyQbzEditModal inherits Rectangle { // --- Body: rename (name input) --------------------------- if root.is-rename: rename-input := LineEdit { text <=> MyQbzEditState.draft-name; - changed has-focus => { UiFocusState.text-input-focused = self.has-focus; } + // Hotkey-guard probe: a use-site `changed has-focus` on a std-widgets + // input never fires (has-focus is an alias into the inner TextInput), + // so observe it through a local property instead (#619). + property guard-focused: self.has-focus; + changed guard-focused => { UiFocusState.text-input-focused = self.guard-focused; } accepted => { if (root.can-submit) { MyQbzEditActions.submit-rename(); @@ -87,7 +91,11 @@ export component MyQbzEditModal inherits Rectangle { height: 96px; wrap: word-wrap; text <=> MyQbzEditState.draft-description; - changed has-focus => { UiFocusState.text-input-focused = self.has-focus; } + // Hotkey-guard probe: a use-site `changed has-focus` on a std-widgets + // input never fires (has-focus is an alias into the inner TextInput), + // so observe it through a local property instead (#619). + property guard-focused: self.has-focus; + changed guard-focused => { UiFocusState.text-input-focused = self.guard-focused; } } // --- Body: delete-confirm (prompt) ----------------------- diff --git a/crates/qbz-ui/ui/playlist/PlaylistManagerView.slint b/crates/qbz-ui/ui/playlist/PlaylistManagerView.slint index 59911815f..1e92f5ab3 100644 --- a/crates/qbz-ui/ui/playlist/PlaylistManagerView.slint +++ b/crates/qbz-ui/ui/playlist/PlaylistManagerView.slint @@ -823,7 +823,11 @@ component PmListRow inherits Rectangle { height: 28px; width: parent.width; placeholder-text: @tr("Search folders"); - changed has-focus => { UiFocusState.text-input-focused = self.has-focus; } + // Hotkey-guard probe: a use-site `changed has-focus` on a std-widgets + // input never fires (has-focus is an alias into the inner TextInput), + // so observe it through a local property instead (#619). + property guard-focused: self.has-focus; + changed guard-focused => { UiFocusState.text-input-focused = self.guard-focused; } text <=> root.folder-query; edited => { PlaylistManagerActions.search-folders(self.text); diff --git a/crates/qbz-ui/ui/primitives/ColorPicker.slint b/crates/qbz-ui/ui/primitives/ColorPicker.slint index c4ca7ab2f..53b1b3f22 100644 --- a/crates/qbz-ui/ui/primitives/ColorPicker.slint +++ b/crates/qbz-ui/ui/primitives/ColorPicker.slint @@ -224,8 +224,13 @@ export component ColorPicker inherits Rectangle { hex-edit := LineEdit { text: root.current-hex; placeholder-text: "#rrggbb"; - changed has-focus => { - UiFocusState.text-input-focused = self.has-focus; + // Hotkey-guard probe: a use-site `changed has-focus` on a + // std-widgets input never fires (has-focus is an alias into + // the inner TextInput), so observe it through a local + // property instead (#619). + property guard-focused: self.has-focus; + changed guard-focused => { + UiFocusState.text-input-focused = self.guard-focused; } accepted(s) => { root.hex-committed(s); diff --git a/crates/qbz-ui/ui/primitives/CreateFolderModal.slint b/crates/qbz-ui/ui/primitives/CreateFolderModal.slint index d6afab8ad..c1df464f6 100644 --- a/crates/qbz-ui/ui/primitives/CreateFolderModal.slint +++ b/crates/qbz-ui/ui/primitives/CreateFolderModal.slint @@ -65,7 +65,11 @@ export component CreateFolderModal inherits Rectangle { name-input := LineEdit { placeholder-text: @tr("Folder name"); - changed has-focus => { UiFocusState.text-input-focused = self.has-focus; } + // Hotkey-guard probe: a use-site `changed has-focus` on a std-widgets + // input never fires (has-focus is an alias into the inner TextInput), + // so observe it through a local property instead (#619). + property guard-focused: self.has-focus; + changed guard-focused => { UiFocusState.text-input-focused = self.guard-focused; } text <=> CreateFolderState.name; accepted => { CreateFolderActions.submit(); diff --git a/crates/qbz-ui/ui/primitives/CreatePlaylistModal.slint b/crates/qbz-ui/ui/primitives/CreatePlaylistModal.slint index 85f2ecc9e..c34a39a64 100644 --- a/crates/qbz-ui/ui/primitives/CreatePlaylistModal.slint +++ b/crates/qbz-ui/ui/primitives/CreatePlaylistModal.slint @@ -79,7 +79,11 @@ export component CreatePlaylistModal inherits Rectangle { } name-input := LineEdit { placeholder-text: @tr("My Playlist"); - changed has-focus => { UiFocusState.text-input-focused = self.has-focus; } + // Hotkey-guard probe: a use-site `changed has-focus` on a std-widgets + // input never fires (has-focus is an alias into the inner TextInput), + // so observe it through a local property instead (#619). + property guard-focused: self.has-focus; + changed guard-focused => { UiFocusState.text-input-focused = self.guard-focused; } text <=> CreatePlaylistState.name; accepted => { CreatePlaylistActions.submit(); @@ -100,7 +104,11 @@ export component CreatePlaylistModal inherits Rectangle { height: 80px; wrap: word-wrap; text <=> CreatePlaylistState.description; - changed has-focus => { UiFocusState.text-input-focused = self.has-focus; } + // Hotkey-guard probe: a use-site `changed has-focus` on a std-widgets + // input never fires (has-focus is an alias into the inner TextInput), + // so observe it through a local property instead (#619). + property guard-focused: self.has-focus; + changed guard-focused => { UiFocusState.text-input-focused = self.guard-focused; } } } diff --git a/crates/qbz-ui/ui/primitives/EditPlaylistModal.slint b/crates/qbz-ui/ui/primitives/EditPlaylistModal.slint index 3ad7d2145..072b02ee8 100644 --- a/crates/qbz-ui/ui/primitives/EditPlaylistModal.slint +++ b/crates/qbz-ui/ui/primitives/EditPlaylistModal.slint @@ -65,7 +65,11 @@ export component EditPlaylistModal inherits Rectangle { name-input := LineEdit { placeholder-text: @tr("Playlist name"); - changed has-focus => { UiFocusState.text-input-focused = self.has-focus; } + // Hotkey-guard probe: a use-site `changed has-focus` on a std-widgets + // input never fires (has-focus is an alias into the inner TextInput), + // so observe it through a local property instead (#619). + property guard-focused: self.has-focus; + changed guard-focused => { UiFocusState.text-input-focused = self.guard-focused; } text <=> EditPlaylistState.name; accepted => { EditPlaylistActions.save(); @@ -81,7 +85,11 @@ export component EditPlaylistModal inherits Rectangle { height: 90px; wrap: word-wrap; text <=> EditPlaylistState.description; - changed has-focus => { UiFocusState.text-input-focused = self.has-focus; } + // Hotkey-guard probe: a use-site `changed has-focus` on a std-widgets + // input never fires (has-focus is an alias into the inner TextInput), + // so observe it through a local property instead (#619). + property guard-focused: self.has-focus; + changed guard-focused => { UiFocusState.text-input-focused = self.guard-focused; } } // Offline-only toggle (D8) — LOCAL playlists only. Unmark it diff --git a/crates/qbz-ui/ui/primitives/FolderEditModal.slint b/crates/qbz-ui/ui/primitives/FolderEditModal.slint index 5de783353..b2d307c5c 100644 --- a/crates/qbz-ui/ui/primitives/FolderEditModal.slint +++ b/crates/qbz-ui/ui/primitives/FolderEditModal.slint @@ -76,7 +76,11 @@ export component FolderEditModal inherits Rectangle { } name-input := LineEdit { placeholder-text: @tr("Enter folder name"); - changed has-focus => { UiFocusState.text-input-focused = self.has-focus; } + // Hotkey-guard probe: a use-site `changed has-focus` on a std-widgets + // input never fires (has-focus is an alias into the inner TextInput), + // so observe it through a local property instead (#619). + property guard-focused: self.has-focus; + changed guard-focused => { UiFocusState.text-input-focused = self.guard-focused; } text <=> FolderEditState.name; accepted => { FolderEditActions.save(); } } diff --git a/crates/qbz-ui/ui/primitives/TagEditorModal.slint b/crates/qbz-ui/ui/primitives/TagEditorModal.slint index e033f89f5..80f5964f1 100644 --- a/crates/qbz-ui/ui/primitives/TagEditorModal.slint +++ b/crates/qbz-ui/ui/primitives/TagEditorModal.slint @@ -96,7 +96,11 @@ export component TagEditorModal inherits Rectangle { horizontal-stretch: 1; LineEdit { placeholder-text: @tr("Album title"); - changed has-focus => { UiFocusState.text-input-focused = self.has-focus; } + // Hotkey-guard probe: a use-site `changed has-focus` on a std-widgets + // input never fires (has-focus is an alias into the inner TextInput), + // so observe it through a local property instead (#619). + property guard-focused: self.has-focus; + changed guard-focused => { UiFocusState.text-input-focused = self.guard-focused; } text <=> TagEditorState.album_title; } } @@ -105,7 +109,11 @@ export component TagEditorModal inherits Rectangle { horizontal-stretch: 1; LineEdit { placeholder-text: @tr("Album artist"); - changed has-focus => { UiFocusState.text-input-focused = self.has-focus; } + // Hotkey-guard probe: a use-site `changed has-focus` on a std-widgets + // input never fires (has-focus is an alias into the inner TextInput), + // so observe it through a local property instead (#619). + property guard-focused: self.has-focus; + changed guard-focused => { UiFocusState.text-input-focused = self.guard-focused; } text <=> TagEditorState.album_artist; } } @@ -119,7 +127,11 @@ export component TagEditorModal inherits Rectangle { width: 120px; LineEdit { placeholder-text: "—"; - changed has-focus => { UiFocusState.text-input-focused = self.has-focus; } + // Hotkey-guard probe: a use-site `changed has-focus` on a std-widgets + // input never fires (has-focus is an alias into the inner TextInput), + // so observe it through a local property instead (#619). + property guard-focused: self.has-focus; + changed guard-focused => { UiFocusState.text-input-focused = self.guard-focused; } text <=> TagEditorState.year_input; } } @@ -128,7 +140,11 @@ export component TagEditorModal inherits Rectangle { horizontal-stretch: 1; LineEdit { placeholder-text: @tr("Genre"); - changed has-focus => { UiFocusState.text-input-focused = self.has-focus; } + // Hotkey-guard probe: a use-site `changed has-focus` on a std-widgets + // input never fires (has-focus is an alias into the inner TextInput), + // so observe it through a local property instead (#619). + property guard-focused: self.has-focus; + changed guard-focused => { UiFocusState.text-input-focused = self.guard-focused; } text <=> TagEditorState.genre; } } @@ -137,7 +153,11 @@ export component TagEditorModal inherits Rectangle { horizontal-stretch: 1; LineEdit { placeholder-text: "—"; - changed has-focus => { UiFocusState.text-input-focused = self.has-focus; } + // Hotkey-guard probe: a use-site `changed has-focus` on a std-widgets + // input never fires (has-focus is an alias into the inner TextInput), + // so observe it through a local property instead (#619). + property guard-focused: self.has-focus; + changed guard-focused => { UiFocusState.text-input-focused = self.guard-focused; } text <=> TagEditorState.catalog_number; } } @@ -367,7 +387,11 @@ export component TagEditorModal inherits Rectangle { LineEdit { width: 52px; placeholder-text: "#"; - changed has-focus => { UiFocusState.text-input-focused = self.has-focus; } + // Hotkey-guard probe: a use-site `changed has-focus` on a std-widgets + // input never fires (has-focus is an alias into the inner TextInput), + // so observe it through a local property instead (#619). + property guard-focused: self.has-focus; + changed guard-focused => { UiFocusState.text-input-focused = self.guard-focused; } text: row.track_number; edited(t) => { TagEditorState.tracks[i].track_number = t; @@ -377,7 +401,11 @@ export component TagEditorModal inherits Rectangle { LineEdit { horizontal-stretch: 1; placeholder-text: @tr("Title"); - changed has-focus => { UiFocusState.text-input-focused = self.has-focus; } + // Hotkey-guard probe: a use-site `changed has-focus` on a std-widgets + // input never fires (has-focus is an alias into the inner TextInput), + // so observe it through a local property instead (#619). + property guard-focused: self.has-focus; + changed guard-focused => { UiFocusState.text-input-focused = self.guard-focused; } text: row.title; edited(t) => { TagEditorState.tracks[i].title = t; @@ -387,7 +415,11 @@ export component TagEditorModal inherits Rectangle { LineEdit { width: 52px; placeholder-text: @tr("Disc"); - changed has-focus => { UiFocusState.text-input-focused = self.has-focus; } + // Hotkey-guard probe: a use-site `changed has-focus` on a std-widgets + // input never fires (has-focus is an alias into the inner TextInput), + // so observe it through a local property instead (#619). + property guard-focused: self.has-focus; + changed guard-focused => { UiFocusState.text-input-focused = self.guard-focused; } text: row.disc_number; edited(t) => { TagEditorState.tracks[i].disc_number = t; diff --git a/crates/qbz-ui/ui/settings/AppearanceSettings.slint b/crates/qbz-ui/ui/settings/AppearanceSettings.slint index eaa400f61..652e55ffa 100644 --- a/crates/qbz-ui/ui/settings/AppearanceSettings.slint +++ b/crates/qbz-ui/ui/settings/AppearanceSettings.slint @@ -541,7 +541,11 @@ export component AppearanceSettings inherits VerticalLayout { name-edit := LineEdit { text: MyQbzBrandingState.label; placeholder-text: @tr("My QBZ"); - changed has-focus => { UiFocusState.text-input-focused = self.has-focus; } + // Hotkey-guard probe: a use-site `changed has-focus` on a std-widgets + // input never fires (has-focus is an alias into the inner TextInput), + // so observe it through a local property instead (#619). + property guard-focused: self.has-focus; + changed guard-focused => { UiFocusState.text-input-focused = self.guard-focused; } edited(s) => { MyQbzBrandingState.set-label(s); } @@ -665,7 +669,11 @@ export component AppearanceSettings inherits VerticalLayout { LineEdit { text: AppearanceState.window-title-template; placeholder-text: "{artist} - {track}"; - changed has-focus => { UiFocusState.text-input-focused = self.has-focus; } + // Hotkey-guard probe: a use-site `changed has-focus` on a std-widgets + // input never fires (has-focus is an alias into the inner TextInput), + // so observe it through a local property instead (#619). + property guard-focused: self.has-focus; + changed guard-focused => { UiFocusState.text-input-focused = self.guard-focused; } edited(s) => { AppearanceState.window-title-template = s; AppearanceState.appearance-text("window-title-template", s); diff --git a/crates/qbz-ui/ui/settings/IntegrationsSettings.slint b/crates/qbz-ui/ui/settings/IntegrationsSettings.slint index a39bbf8fa..31218efac 100644 --- a/crates/qbz-ui/ui/settings/IntegrationsSettings.slint +++ b/crates/qbz-ui/ui/settings/IntegrationsSettings.slint @@ -259,7 +259,11 @@ export component IntegrationsSettings inherits VerticalLayout { LineEdit { text: ScrobbleState.listenbrainz-token-input; placeholder-text: @tr("ListenBrainz token"); - changed has-focus => { UiFocusState.text-input-focused = self.has-focus; } + // Hotkey-guard probe: a use-site `changed has-focus` on a std-widgets + // input never fires (has-focus is an alias into the inner TextInput), + // so observe it through a local property instead (#619). + property guard-focused: self.has-focus; + changed guard-focused => { UiFocusState.text-input-focused = self.guard-focused; } input-type: password; enabled: !ScrobbleState.listenbrainz-busy; edited(s) => { diff --git a/crates/qbz-ui/ui/settings/LibFolderEditModal.slint b/crates/qbz-ui/ui/settings/LibFolderEditModal.slint index 2c19a327a..756367d19 100644 --- a/crates/qbz-ui/ui/settings/LibFolderEditModal.slint +++ b/crates/qbz-ui/ui/settings/LibFolderEditModal.slint @@ -192,7 +192,11 @@ export component LibFolderEditModal inherits Rectangle { label: @tr("Display name"); LineEdit { placeholder-text: @tr("Optional friendly name"); - changed has-focus => { UiFocusState.text-input-focused = self.has-focus; } + // Hotkey-guard probe: a use-site `changed has-focus` on a std-widgets + // input never fires (has-focus is an alias into the inner TextInput), + // so observe it through a local property instead (#619). + property guard-focused: self.has-focus; + changed guard-focused => { UiFocusState.text-input-focused = self.guard-focused; } text <=> LibFolderEditState.alias; } Text { diff --git a/crates/qbz-ui/ui/settings/LocalLibrarySettings.slint b/crates/qbz-ui/ui/settings/LocalLibrarySettings.slint index d999a639a..74fff42ae 100644 --- a/crates/qbz-ui/ui/settings/LocalLibrarySettings.slint +++ b/crates/qbz-ui/ui/settings/LocalLibrarySettings.slint @@ -538,7 +538,11 @@ export component LocalLibrarySettings inherits VerticalLayout { LineEdit { text: PlexSettingsState.server-url; placeholder-text: @tr("http://127.0.0.1:32400"); - changed has-focus => { UiFocusState.text-input-focused = self.has-focus; } + // Hotkey-guard probe: a use-site `changed has-focus` on a std-widgets + // input never fires (has-focus is an alias into the inner TextInput), + // so observe it through a local property instead (#619). + property guard-focused: self.has-focus; + changed guard-focused => { UiFocusState.text-input-focused = self.guard-focused; } edited(s) => { PlexSettingsState.server-url = s; } @@ -641,7 +645,11 @@ export component LocalLibrarySettings inherits VerticalLayout { LineEdit { text: PlexSettingsState.token-input; placeholder-text: @tr("X-Plex-Token"); - changed has-focus => { UiFocusState.text-input-focused = self.has-focus; } + // Hotkey-guard probe: a use-site `changed has-focus` on a std-widgets + // input never fires (has-focus is an alias into the inner TextInput), + // so observe it through a local property instead (#619). + property guard-focused: self.has-focus; + changed guard-focused => { UiFocusState.text-input-focused = self.guard-focused; } input-type: password; edited(s) => { PlexSettingsState.token-input = s; diff --git a/crates/qbz-ui/ui/settings/PlaybackSettings.slint b/crates/qbz-ui/ui/settings/PlaybackSettings.slint index 625a9f452..13cee3cfb 100644 --- a/crates/qbz-ui/ui/settings/PlaybackSettings.slint +++ b/crates/qbz-ui/ui/settings/PlaybackSettings.slint @@ -129,9 +129,13 @@ export component PlaybackSettings inherits VerticalLayout { placeholder-text: SettingsState.qconnect-device-name-default; // Commit on focus loss too (mirrors the Tauri onchange // semantics: blur or Enter), not only on Enter. - changed has-focus => { - UiFocusState.text-input-focused = self.has-focus; - if (!self.has-focus) { + // Probe property because a use-site `changed has-focus` on a + // std-widgets input never fires (has-focus is an alias into + // the inner TextInput) — #619. + property guard-focused: self.has-focus; + changed guard-focused => { + UiFocusState.text-input-focused = self.guard-focused; + if (!self.guard-focused) { root.settings-string("qconnect-device-name", self.text); } } diff --git a/crates/qbz-ui/ui/shell/KioskShell.slint b/crates/qbz-ui/ui/shell/KioskShell.slint index 15ba3513b..2388a37ca 100644 --- a/crates/qbz-ui/ui/shell/KioskShell.slint +++ b/crates/qbz-ui/ui/shell/KioskShell.slint @@ -166,8 +166,12 @@ export component KioskShell inherits Rectangle { // Suppress the global single-key hotkeys while typing (the // desktop search box drives the same guard); without this, // letters fire hotkeys instead of reaching the field. - changed has-focus => { - UiFocusState.text-input-focused = self.has-focus; + // Probe property because a use-site `changed has-focus` on a + // std-widgets input never fires (has-focus is an alias into + // the inner TextInput) — #619. + property guard-focused: self.has-focus; + changed guard-focused => { + UiFocusState.text-input-focused = self.guard-focused; } accepted(text) => { SearchActions.submit(text); diff --git a/crates/qbz-ui/ui/shell/QconnectDevModal.slint b/crates/qbz-ui/ui/shell/QconnectDevModal.slint index 80b532732..12d9a6f60 100644 --- a/crates/qbz-ui/ui/shell/QconnectDevModal.slint +++ b/crates/qbz-ui/ui/shell/QconnectDevModal.slint @@ -87,7 +87,11 @@ export component QconnectDevModal inherits Rectangle { : QconnectDevState.status; // Read-only but still focusable (select/copy) — keep the // single-key hotkeys quiet while it holds focus. - changed has-focus => { UiFocusState.text-input-focused = self.has-focus; } + // Hotkey-guard probe: a use-site `changed has-focus` on a std-widgets + // input never fires (has-focus is an alias into the inner TextInput), + // so observe it through a local property instead (#619). + property guard-focused: self.has-focus; + changed guard-focused => { UiFocusState.text-input-focused = self.guard-focused; } } } @@ -135,7 +139,11 @@ export component QconnectDevModal inherits Rectangle { wrap: word-wrap; font-size: 11px; text: QconnectDevState.log-text; - changed has-focus => { UiFocusState.text-input-focused = self.has-focus; } + // Hotkey-guard probe: a use-site `changed has-focus` on a std-widgets + // input never fires (has-focus is an alias into the inner TextInput), + // so observe it through a local property instead (#619). + property guard-focused: self.has-focus; + changed guard-focused => { UiFocusState.text-input-focused = self.guard-focused; } } } } diff --git a/crates/qbz-ui/ui/shell/Sidebar.slint b/crates/qbz-ui/ui/shell/Sidebar.slint index c5108b0f5..ce17f2fa2 100644 --- a/crates/qbz-ui/ui/shell/Sidebar.slint +++ b/crates/qbz-ui/ui/shell/Sidebar.slint @@ -485,7 +485,11 @@ component SidebarRow inherits Rectangle { LineEdit { height: 26px; placeholder-text: @tr("Search folders"); - changed has-focus => { UiFocusState.text-input-focused = self.has-focus; } + // Hotkey-guard probe: a use-site `changed has-focus` on a std-widgets + // input never fires (has-focus is an alias into the inner TextInput), + // so observe it through a local property instead (#619). + property guard-focused: self.has-focus; + changed guard-focused => { UiFocusState.text-input-focused = self.guard-focused; } text <=> root.folder-query; edited => { SidebarActions.search-folders(self.text); @@ -829,7 +833,11 @@ export component Sidebar inherits Rectangle { width: 100%; height: 22px; placeholder-text: @tr("Search playlists"); - changed has-focus => { UiFocusState.text-input-focused = self.has-focus; } + // Hotkey-guard probe: a use-site `changed has-focus` on a std-widgets + // input never fires (has-focus is an alias into the inner TextInput), + // so observe it through a local property instead (#619). + property guard-focused: self.has-focus; + changed guard-focused => { UiFocusState.text-input-focused = self.guard-focused; } text <=> SidebarState.search-query; edited => { SidebarActions.search-changed(self.text); diff --git a/crates/qbz-ui/ui/shell/SidebarPlaylistsPopup.slint b/crates/qbz-ui/ui/shell/SidebarPlaylistsPopup.slint index e8fbcd17c..365650724 100644 --- a/crates/qbz-ui/ui/shell/SidebarPlaylistsPopup.slint +++ b/crates/qbz-ui/ui/shell/SidebarPlaylistsPopup.slint @@ -130,7 +130,11 @@ export component SidebarPlaylistsPopup inherits Rectangle { width: parent.width - 16px; height: 26px; placeholder-text: @tr("Search playlists"); - changed has-focus => { UiFocusState.text-input-focused = self.has-focus; } + // Hotkey-guard probe: a use-site `changed has-focus` on a std-widgets + // input never fires (has-focus is an alias into the inner TextInput), + // so observe it through a local property instead (#619). + property guard-focused: self.has-focus; + changed guard-focused => { UiFocusState.text-input-focused = self.guard-focused; } text <=> SidebarState.search-query; edited => { SidebarActions.search-changed(self.text);