fix: add keyboard navigation for search dropdown

1. Root cause: SearchResultDialog.qml had no keyboard navigation;
   SearchEdit only handled Return key, arrow keys were consumed by
   TextField default cursor movement
2. Fix: add selectedIndex tracking, moveSelection/activateSelection
   methods and highlight in SearchResultDialog; add Keys.onDownPressed
   /onUpPressed and extend onReturnPressed in WindowTitlebar SearchEdit
3. Impact: users can now navigate search results with arrow keys and
   confirm with Enter; mouse interaction unchanged

Log: Search results now support keyboard navigation with arrow keys

Influence:
1. Test arrow key navigation in search result dropdown
2. Test Enter key to activate selected search result
3. Verify mouse hover and click still work as before

fix: 搜索结果下拉列表添加键盘导航

1. 根因:SearchResultDialog.qml 无键盘导航机制,SearchEdit 仅处理
   回车键,方向键被 TextField 默认光标移动行为消费
2. 方案:在 SearchResultDialog 添加 selectedIndex 追踪、
   moveSelection/activateSelection 方法和高亮显示;在 WindowTitlebar
   的 SearchEdit 添加方向键处理并扩展回车键逻辑
3. 影响:用户可通过方向键导航搜索结果并回车确认,鼠标交互不受影响

Log: 搜索结果支持方向键导航和回车选择

Influence:
1. 测试搜索结果下拉列表中方向键导航
2. 测试回车键激活选中的搜索结果
3. 验证鼠标悬停和点击功能无回归

PMS: BUG-375953
This commit is contained in:
wangyu
2026-09-03 11:15:18 +08:00
committed by deepin-bot[bot]
parent 92494baf59
commit 8ff4899735
2 changed files with 72 additions and 0 deletions
@@ -12,11 +12,48 @@ Popup {
property string pattern: ""
property int itemHeight: 40
property int selectedIndex: -1
property int resultCount: (songList == null ? 0 : songList.length) + artistModel.count + albumModel.count
signal searchItemTriggered(string value, int type)
id: searchResultRect
width: 360
// Moves the keyboard selection by offset, wrapping around available results.
function moveSelection(offset) {
if (resultCount <= 0)
return
if (selectedIndex < 0) {
selectedIndex = offset > 0 ? 0 : resultCount - 1
return
}
selectedIndex = (selectedIndex + offset + resultCount) % resultCount
}
// Activates the currently selected result and returns whether activation succeeded.
function activateSelection() {
if (selectedIndex < 0 || selectedIndex >= resultCount)
return false
var songCount = songList == null ? 0 : songList.length
if (selectedIndex < songCount) {
searchItemTriggered(songList[selectedIndex], 0)
return true
}
var artistIndex = selectedIndex - songCount
if (artistIndex < artistModel.count) {
searchItemTriggered(artistModel.get(artistIndex).name, 1)
return true
}
searchItemTriggered(albumModel.get(artistIndex - artistModel.count).name, 2)
return true
}
height: (songList == null ? 0 : songList.length + artistModel.count + albumModel.count) * itemHeight + 110
leftPadding: 8
rightPadding: 8
@@ -66,10 +103,17 @@ Popup {
id: resultItemTextDelegate
Rectangle {
id: itemRect
property int resultIndex: index
width: parent.width
height: itemHeight
radius: 6
color: "#00000000"
Rectangle {
anchors.fill: parent
radius: parent.radius
color: palette.highlight
visible: searchResultRect.selectedIndex === itemRect.resultIndex
}
Row {
width: parent.width
anchors.verticalCenter: parent.verticalCenter
@@ -104,10 +148,20 @@ Popup {
id: resultItemImgDelegate
Rectangle {
id: itemRect
property int resultIndex: (model.type === "album"
? (searchResultRect.songList == null ? 0 : searchResultRect.songList.length)
+ searchResultRect.artistModel.count
: (searchResultRect.songList == null ? 0 : searchResultRect.songList.length)) + index
width: parent.width
height: itemHeight
radius: 6
color: "#00000000"
Rectangle {
anchors.fill: parent
radius: parent.radius
color: palette.highlight
visible: searchResultRect.selectedIndex === itemRect.resultIndex
}
Row {
width: parent.width
anchors.verticalCenter: parent.verticalCenter
@@ -272,12 +272,29 @@ TitleBar {
Layout.alignment: Qt.AlignCenter
placeholder: qsTr("Search")
enabled: Presenter.isExistMeta()
Keys.onDownPressed: function(event) {
var searchResDlg = searchResultLoader.item
if (!searchResDlg || !searchResDlg.visible)
return
searchResDlg.moveSelection(1)
event.accepted = true
}
Keys.onUpPressed: function(event) {
var searchResDlg = searchResultLoader.item
if (!searchResDlg || !searchResDlg.visible)
return
searchResDlg.moveSelection(-1)
event.accepted = true
}
Keys.onReturnPressed: {
//console.log("SearchEdit: Keys.onEnterPressed....")
var searchResDlg = searchResultLoader.item
if (text.length <= 0 || !searchResDlg || searchResDlg.songList == null)
return
if (searchResDlg.visible && searchResDlg.activateSelection())
return
var type = -1
if (searchResDlg.songList.length > 0)
type = 0
@@ -372,6 +389,7 @@ TitleBar {
}
var searchResDlg = searchResultLoader.item
searchResDlg.selectedIndex = -1
searchResDlg.songList = []
searchResDlg.artistModel.clear()
searchResDlg.albumModel.clear()