fix: improve search result UI and navigation

- Overhaul SearchResultWindow navigation with StackView for push/pop transitions
- Adjust grid cell sizes for better artist and album display
- Add requestClose signal and padding/radius improvements to SearchResultDialog
- Remove sidebar auto-uncheck behavior when entering search page
- Fix connection handlers for artist and album detail navigation

fix: 优化搜索结果UI和导航

- 使用StackView重构SearchResultWindow导航,支持推入/弹出过渡动画
- 调整网格单元格大小以改善歌手和专辑显示
- 为SearchResultDialog添加requestClose信号和内边距/圆角改进
- 移除进入搜索页面时侧边栏自动取消勾选的行为
- 修复歌手和专辑详情页导航的连接处理
This commit is contained in:
Cloud
2026-08-30 20:22:27 +08:00
committed by deepin-bot[bot]
parent 9b7ccc25df
commit bc7fe7090a
3 changed files with 268 additions and 216 deletions
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
// SPDX-FileCopyrightText: 2023 - 2026 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later
@@ -18,6 +18,10 @@ Popup {
id: searchResultRect
width: 360
height: (songList == null ? 0 : songList.length + artistModel.count + albumModel.count) * itemHeight + 110
leftPadding: 8
rightPadding: 8
topPadding: 8
bottomPadding: 8
Column {
width: parent.width
@@ -64,6 +68,7 @@ Popup {
id: itemRect
width: parent.width
height: itemHeight
radius: 6
color: "#00000000"
Row {
width: parent.width
@@ -101,6 +106,7 @@ Popup {
id: itemRect
width: parent.width
height: itemHeight
radius: 6
color: "#00000000"
Row {
width: parent.width
@@ -133,7 +139,6 @@ Popup {
itemRect.color = "transparent"
}
onClicked: {
// console.log(model.type)
var type = 0
if (model.type === "artist")
+261 -204
View File
@@ -23,19 +23,22 @@ Rectangle {
property ListModel albumsModel: ListModel{}
property ListModel artistsModel: ListModel{}
property int curIndex: tabArea.currentIndex
signal itemDoubleClicked(var artistData)
property int switchType: globalVariant.globalSwitchButtonStatus
property string selectedArtistName: ""
property string selectedAlbumName: ""
signal itemDoubleClicked(var data)
property var artistData
Component {
id: artistSublistView
ArtistSublistView {
artistData:searchRootRect.artistData
artistData: searchRootRect.artistData
}
}
Component {
id: albumSublistView
AlbumSublistView {
albumData:searchRootRect.artistData
albumData: searchRootRect.artistData
}
}
@@ -56,226 +59,270 @@ Rectangle {
}
}
Rectangle {
width: parent.width
height: parent.height
color: "transparent"
StackView {
id: navigationStackView
anchors.fill: parent
visible: curIndex < 0 ? false : true
ColumnLayout {
width: parent.width
height: parent.height
Rectangle {
id: headArea
width: parent.width - 40
height: 72
Layout.leftMargin: 20
Layout.rightMargin: 20
color: "transparent"
initialItem: Rectangle {
width: navigationStackView.width
height: navigationStackView.height
color: "transparent"
ColumnLayout {
width: parent.width
height: parent.height
Row {
anchors.fill: parent
topPadding: 17
spacing: 10
FloatingButton {
id: playAllBtn
width: 28; height: 28
icon.name: "headline_play_all"
icon.width: 28
icon.height: 28
ToolTip {
visible: playAllBtn.hovered
text: qsTr("Play All")
}
onClicked: {
Presenter.playPlaylist("musicResult");
}
}
Label {
id: buttonLable
text: qsTr("Search Results")
font: DTK.fontManager.t4
}
Label {
font: DTK.fontManager.t8
text: albumsModel.count !== 1 ? qsTr("%1 albums - %2 songs").arg(albumsModel.count).arg(songsModel.count) :
(songsModel.count === 1 ? qsTr("1 album - 1 song") : qsTr("%1 album - %2 songs").arg(albumsModel.count).arg(songsModel.count))
anchors.verticalCenter: buttonLable.verticalCenter
}
}
}
RowLayout {
id: headerLayout
Layout.rightMargin: 40
TabBar {
id: tabArea
Rectangle {
id: headArea
width: parent.width - 40
height: parent.height - headArea.height
height: 72
Layout.leftMargin: 20
Layout.rightMargin: 20
currentIndex: 0
color: "transparent"
TabButton {
text: qsTr("Music")
width: 82
}
TabButton {
text: qsTr("Album")
width: 82
}
TabButton {
text: qsTr("Artist")
width: 82
}
}
Item { Layout.fillWidth: true }
SortMenu {
id: allMusicSortMenu
visible: tabArea.currentIndex === 0
sortPageHash: "musicResult"
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
pageSortType: 0
}
SortMenu {
id: albumMusicSortMenu
visible: tabArea.currentIndex === 1
sortPageHash: "albumResult"
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
pageSortType: 0
}
SortMenu {
id: artistMusicSortMenu
visible: tabArea.currentIndex === 2
sortPageHash: "artistResult"
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
pageSortType: 0
}
Component.onCompleted: {
var musicSortType = Presenter.playlistSortType("musicResult")
var artistSortType = Presenter.playlistSortType("artistResult")
var albumSortType = Presenter.playlistSortType("albumResult")
switch(musicSortType) {
case 10:
allMusicSortMenu.pageSortType = 0
break
case 11:
allMusicSortMenu.pageSortType = 1
break
case 12:
allMusicSortMenu.pageSortType = 2
break
case 13:
allMusicSortMenu.pageSortType = 3
break
default:
allMusicSortMenu.pageSortType = -1
}
switch(albumSortType) {
case 10:
albumMusicSortMenu.pageSortType = 0
break
case 13:
albumMusicSortMenu.pageSortType = 1
break
default:
albumMusicSortMenu.pageSortType = -1
}
switch(artistSortType) {
case 10:
artistMusicSortMenu.pageSortType = 0
break
case 12:
artistMusicSortMenu.pageSortType = 2
break
default:
artistMusicSortMenu.pageSortType = -1
}
}
}
StackLayout {
id: myStackView
Layout.fillHeight: true
Layout.fillWidth: true
Layout.leftMargin: 20
Layout.rightMargin: 20
clip: true
visible: curIndex < 0 ? false : true
currentIndex: tabArea.currentIndex
AllMusicListView {
id: allMusicList
width: parent.width
height: parent.height
mediaModel: songsModel
viewListHash: "musicResult"
}
GridView {
id: artistView
width: Math.floor(parent.width / 196) * 196;
height: parent.height
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top; anchors.topMargin: 34
anchors.leftMargin: (parent.width - width) / 2
anchors.rightMargin: (parent.width - width) / 2
cellWidth: 196; cellHeight: 196
ScrollBar.vertical: ScrollBar {}
clip: true
model: artistsModel
delegate: ArtistGridDelegate{
id: musicSingerGridItem
onItemDoubleClicked: {
searchRootRect.itemDoubleClicked(artistData);
Row {
anchors.fill: parent
topPadding: 17
spacing: 10
FloatingButton {
id: playAllBtn
width: 28; height: 28
icon.name: "headline_play_all"
icon.width: 28
icon.height: 28
ToolTip {
visible: playAllBtn.hovered
text: qsTr("Play All")
}
onClicked: {
Presenter.playPlaylist("musicResult");
}
}
Label {
id: buttonLable
text: qsTr("Search Results")
font: DTK.fontManager.t4
}
Label {
font: DTK.fontManager.t8
text: albumsModel.count !== 1 ? qsTr("%1 albums - %2 songs").arg(albumsModel.count).arg(songsModel.count) :
(songsModel.count === 1 ? qsTr("1 album - 1 song") : qsTr("%1 album - %2 songs").arg(albumsModel.count).arg(songsModel.count))
anchors.verticalCenter: buttonLable.verticalCenter
}
}
onWidthChanged: {
var w = Math.floor(tabArea.width / 196) * 196;
var m = (tabArea.width - w) / 2;
anchors.leftMargin = m;
anchors.rightMargin = m;
}
}
GridView {
id: albumGridView
width: Math.floor(parent.width / 201) * 201;
height: parent.height
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top; anchors.topMargin: 5
anchors.leftMargin: (parent.width - width) / 2
anchors.rightMargin: (parent.width - width) / 2
cellWidth: 201; cellHeight: 228
ScrollBar.vertical: ScrollBar {}
clip: true
model: albumsModel
delegate: AlbumGridDelegate{
id: itemDelegate
playing: (globalVariant.curPlayingStatus === DmGlobal.Playing) ? true : false
onItemDoubleClicked: {
console.log("onItemDoubleClicked: " + albumData);
searchRootRect.itemDoubleClicked(albumData);
RowLayout {
id: headerLayout
Layout.rightMargin: 40
TabBar {
id: tabArea
width: parent.width - 40
height: parent.height - headArea.height
Layout.leftMargin: 20
Layout.rightMargin: 20
currentIndex: 0
TabButton {
text: qsTr("Music")
width: 82
}
TabButton {
text: qsTr("Album")
width: 82
}
TabButton {
text: qsTr("Artist")
width: 82
}
}
onWidthChanged: {
var w = Math.floor(tabArea.width / 201) * 201;
var m = (tabArea.width - w) / 2;
anchors.leftMargin = m;
anchors.rightMargin = m;
Item { Layout.fillWidth: true }
SortMenu {
id: allMusicSortMenu
visible: tabArea.currentIndex === 0
sortPageHash: "musicResult"
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
pageSortType: 0
}
SortMenu {
id: albumMusicSortMenu
visible: tabArea.currentIndex === 1
sortPageHash: "albumResult"
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
pageSortType: 0
}
SortMenu {
id: artistMusicSortMenu
visible: tabArea.currentIndex === 2
sortPageHash: "artistResult"
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
pageSortType: 0
}
Component.onCompleted: {
var musicSortType = Presenter.playlistSortType("musicResult")
var artistSortType = Presenter.playlistSortType("artistResult")
var albumSortType = Presenter.playlistSortType("albumResult")
switch(musicSortType) {
case 10:
allMusicSortMenu.pageSortType = 0
break
case 11:
allMusicSortMenu.pageSortType = 1
break
case 12:
allMusicSortMenu.pageSortType = 2
break
case 13:
allMusicSortMenu.pageSortType = 3
break
default:
allMusicSortMenu.pageSortType = -1
}
switch(albumSortType) {
case 10:
albumMusicSortMenu.pageSortType = 0
break
case 13:
albumMusicSortMenu.pageSortType = 1
break
default:
albumMusicSortMenu.pageSortType = -1
}
switch(artistSortType) {
case 10:
artistMusicSortMenu.pageSortType = 0
break
case 12:
artistMusicSortMenu.pageSortType = 2
break
default:
artistMusicSortMenu.pageSortType = -1
}
}
}
StackLayout {
id: myStackView
Layout.fillHeight: true
Layout.fillWidth: true
clip: true
visible: curIndex < 0 ? false : true
currentIndex: tabArea.currentIndex
AllMusicListView {
id: allMusicList
mediaModel: songsModel
viewListHash: "musicResult"
}
Item {
GridView {
id: artistView
width: Math.floor(parent.width / 208) * 208
height: parent.height
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: 5
cellWidth: 208
cellHeight: 230
header: Item { width: 1; height: 10 }
ScrollBar.vertical: ScrollBar {}
clip: true
model: artistsModel
delegate: ArtistGridDelegate{
id: musicSingerGridItem
onItemDoubleClicked: {
searchRootRect.itemDoubleClicked(artistData);
}
}
}
}
Item {
GridView {
id: albumGridView
width: Math.floor(parent.width / 208) * 208
height: parent.height
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: 5
cellWidth: 208
cellHeight: 242
header: Item { width: 1; height: 10 }
ScrollBar.vertical: ScrollBar {}
clip: true
model: albumsModel
delegate: AlbumGridDelegate{
id: itemDelegate
playing: (globalVariant.curPlayingStatus === DmGlobal.Playing) ? true : false
onItemDoubleClicked: {
searchRootRect.itemDoubleClicked(albumData);
}
}
}
}
}
}
}
popEnter: Transition {
NumberAnimation { property: "scale"; from: 0.8; to: 1; duration: 300; easing.type: Easing.InOutQuad }
NumberAnimation { property: "opacity"; from: 0.0; to: 1.0; duration: 300; easing.type: Easing.InOutQuad }
}
popExit: Transition {
NumberAnimation { property: "scale"; from: 1; to: 0.8; duration: 300; easing.type: Easing.InOutQuad }
NumberAnimation { property: "opacity"; from: 1.0; to: 0.0; duration: 200; easing.type: Easing.OutExpo }
}
pushEnter: Transition {
NumberAnimation { property: "scale"; from: 1.2; to: 1; duration: 300; easing.type: Easing.InOutQuad }
NumberAnimation { property: "opacity"; from: 0.0; to: 1.0; duration: 300; easing.type: Easing.InOutQuad }
}
pushExit: Transition {
NumberAnimation { property: "opacity"; from: 1.0; to: 0.0; duration: 200; easing.type: Easing.OutExpo }
}
}
onItemDoubleClicked: {
searchRootRect.artistData = artistData
onItemDoubleClicked: function(data) {
searchRootRect.artistData = data
if (data.name !== undefined) {
selectedArtistName = data.name
selectedAlbumName = data.name
}
globalVariant.globalSwitchButtonStatus = 2;
}
onSwitchTypeChanged: {
if (switchType === 1) {
navigationStackView.pop(navigationStackView.initialItem);
} else if (switchType === 2) {
if (tabArea.currentIndex === 2) {
var artistItem = navigationStackView.find(function(item) { return item.objectName === "artistSublist" })
if (artistItem !== null) {
navigationStackView.pop(artistItem);
return;
}
navigationStackView.push(artistSublistView);
} else if (tabArea.currentIndex === 1) {
var albumItem = navigationStackView.find(function(item) { return item.objectName === "albumSublist" })
if (albumItem !== null) {
navigationStackView.pop(albumItem);
return;
}
navigationStackView.push(albumSublistView);
}
}
}
function returnUpperlevelView() {
globalVariant.globalSwitchButtonStatus = 0;
navigationStackView.pop(navigationStackView.initialItem);
}
function updateSearchResultInfo(text, type) {
songsModel.clear()
albumsModel.clear()
@@ -406,11 +453,21 @@ Rectangle {
Connections {
target: artistMoreMenu
onViewArtistDatails: { itemDoubleClicked(artistData);}
function onViewArtistDatails(artistData) {
searchRootRect.itemDoubleClicked(artistData);
}
}
Connections {
target: albumMoreMenu
onViewAlbumDatails: { itemDoubleClicked(artistData);}
function onViewAlbumDatails(albumData) {
searchRootRect.itemDoubleClicked(albumData);
}
}
Connections {
target: globalVariant
function onReturnUpperlevelView() {
searchRootRect.returnUpperlevelView();
}
}
Component.onCompleted: {
updateSearchResultInfo(pattern, curIndex)
@@ -219,7 +219,6 @@ ColumnLayout {
Connections {
target: musicBaseScrollView.contentItem
function onContentYChanged() {
// console.log("Connections........onContentYChanged ", musicBaseScrollView.contentItem.contentY)
if (control.type === "playlists")
dropArea.updateHoverIndex()
}
@@ -307,14 +306,5 @@ ColumnLayout {
}
}
Component.onCompleted: {
globalVariant.curListPageChanged.connect(function(){
if (globalVariant !== undefined && globalVariant.curListPage === "search") {
sideListView.currentItem.checked = false
}
})
// musicBaseScrollView.contentItem.contentYChanged.connect(dropArea.updateHoverIndex())
}
}