Warning, /multimedia/audiotube/src/contents/ui/SearchWithDropdown.qml is written in an unsupported language. File is not indexed.
0001 // SPDX-FileCopyrightText: 2023 Mathis BrĂ¼chert <mbb@kaidan.im> 0002 // SPDX-FileCopyrightText: 2021 Jonah BrĂ¼chert <jbb@kaidan.im> 0003 // 0004 // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 0006 import QtQuick 2.1 0007 import QtQuick.Controls 2.12 as Controls 0008 import QtQuick.Layouts 1.3 0009 import org.kde.kirigami 2.14 as Kirigami 0010 import org.kde.ytmusic 1.0 0011 0012 Item { 0013 function forceFocus(){searchField.forceActiveFocus()} 0014 function accepted(){searchField.accepted()} 0015 property alias text: searchField.text 0016 0017 id: root 0018 Controls.TextField{ 0019 id: dummy 0020 x:searchField.x 0021 y:searchField.y 0022 width: searchField.width 0023 readOnly: true 0024 } 0025 Kirigami.SearchField { 0026 id: searchField 0027 autoAccept: false 0028 width: root.width 0029 selectByMouse: true 0030 onFocusChanged: { 0031 Library.searches.filter = text 0032 if (wideScreen && focus) 0033 popup.open() 0034 } 0035 0036 onTextEdited: { 0037 Library.searches.filter = text 0038 if(completionList.count === 0) { 0039 //no matching search -> message should display 0040 Library.temporarySearch = "" 0041 } 0042 else { 0043 Library.temporarySearch = text 0044 } 0045 } 0046 0047 Keys.onPressed: { 0048 if(completionList.count > 0) { 0049 if (event.key === Qt.Key_Down) { 0050 if(completionList.selectedDelegate === -1 || completionList.selectedDelegate === completionList.count - 1) { 0051 completionList.selectedDelegate = 0 0052 mainScrollView.contentItem.contentY = 0 0053 } 0054 else { 0055 ++completionList.selectedDelegate 0056 if(!completionList.isSelectedDelegateVisible()) { 0057 if(!recentsRepeater.visible) { 0058 mainScrollView.contentItem.contentY = (completionList.selectedDelegate + 1) * completionList.empiricDelegateHeight - mainScrollView.height 0059 } 0060 else { 0061 mainScrollView.contentItem.contentY = (completionList.selectedDelegate + 1) * completionList.empiricDelegateHeight + recentsRepeater.height + mainScrollViewLayout.spacing - mainScrollView.height 0062 } 0063 } 0064 } 0065 event.accepted = true 0066 } 0067 else if(event.key === Qt.Key_Up) { 0068 if(completionList.selectedDelegate === -1 || completionList.selectedDelegate === 0) { 0069 completionList.selectedDelegate = completionList.count - 1 0070 mainScrollView.contentItem.contentY = mainScrollView.contentHeight - mainScrollView.height 0071 } 0072 else { 0073 --completionList.selectedDelegate 0074 if(!completionList.isSelectedDelegateVisible()) { 0075 if(!recentsRepeater.visible) { 0076 mainScrollView.contentItem.contentY = completionList.empiricDelegateHeight * completionList.selectedDelegate 0077 } 0078 else { 0079 mainScrollView.contentItem.contentY = completionList.empiricDelegateHeight * completionList.selectedDelegate + recentsRepeater.height + mainScrollViewLayout.spacing 0080 } 0081 } 0082 } 0083 event.accepted = true 0084 } 0085 if(event.accepted) { 0086 text = completionList.itemAt(completionList.selectedDelegate).text 0087 } 0088 else { 0089 completionList.selectedDelegate = -1 0090 mainScrollView.contentItem.contentY = 0 0091 } 0092 } 0093 } 0094 0095 onAccepted: { 0096 popup.close() 0097 completionList.selectedDelegate = -1 0098 Library.temporarySearch = "" 0099 0100 while (pageStack.depth > 0) { 0101 pageStack.pop() 0102 } 0103 0104 pageStack.layers.clear() 0105 0106 if (text) { 0107 Library.addSearch(text) 0108 pageStack.push("qrc:/SearchPage.qml", { 0109 "searchQuery": text, 0110 objectName: "searchPage" 0111 }) 0112 } else { 0113 wideScreen 0114 ? pageStack.push("qrc:/LibraryPage.qml") 0115 : pageStack.push("qrc:/SearchHistoryPage.qml") 0116 } 0117 searchField.focus = false 0118 0119 } 0120 } 0121 Controls.Popup { 0122 id: popup 0123 property int expansion: 5 0124 property int shadowSize: 15 0125 onAboutToShow:{ 0126 searchField.parent = fieldContainer 0127 onOpened: searchField.background.visible = false 0128 playOpenHeight.running = true 0129 playOpenWidth.running = true 0130 playOpenX.running = true 0131 playOpenY.running = true 0132 playOpenRadius.running = true 0133 0134 } 0135 onAboutToHide:{ 0136 searchField.parent = root 0137 onOpened: searchField.background.visible = true 0138 searchField.focus = false 0139 playCloseHeight.running = true 0140 playCloseWidth.running = true 0141 playCloseX.running = true 0142 playCloseY.running = true 0143 playCloseRadius.running = true 0144 0145 } 0146 0147 x: -(popup.shadowSize+popup.expansion) 0148 y: -(popup.shadowSize+popup.expansion) 0149 0150 rightPadding:popup.shadowSize+1 0151 leftPadding:popup.shadowSize+1 0152 bottomPadding:popup.shadowSize 0153 rightInset: popup.shadowSize 0154 leftInset: popup.shadowSize 0155 bottomInset: popup.shadowSize 0156 leftMargin:-popup.shadowSize 0157 0158 background: Kirigami.ShadowedRectangle{ 0159 id: bg 0160 Kirigami.Theme.inherit: false 0161 Kirigami.Theme.colorSet: Kirigami.Theme.View 0162 color: Kirigami.Theme.backgroundColor 0163 radius: popup.expansion+2 0164 shadow.size: popup.shadowSize 0165 shadow.yOffset: popup.expansion 0166 shadow.color: Qt.rgba(0, 0, 0, 0.2) 0167 0168 border.width: 1 0169 border.color: Kirigami.ColorUtils.linearInterpolation(Kirigami.Theme.backgroundColor, Kirigami.Theme.textColor, 0.3); 0170 NumberAnimation on radius{ 0171 id: playOpenRadius 0172 easing.type: Easing.OutCubic 0173 running: false 0174 from: 2 0175 duration: 100 0176 to: popup.expansion+2 0177 } 0178 NumberAnimation on radius{ 0179 id: playCloseRadius 0180 easing.type: Easing.OutCubic 0181 running: false 0182 from: popup.expansion+2 0183 duration: 100 0184 to: 2 0185 } 0186 0187 } 0188 width: searchField.width + 2*(popup.shadowSize+popup.expansion) 0189 height: completionList 0190 ? (Math.min(content.implicitHeight, Kirigami.Units.gridUnit * 20))+2*(popup.shadowSize+popup.expansion) 0191 : (Kirigami.Units.gridUnit * 20)+2*(popup.shadowSize+popup.expansion) 0192 0193 NumberAnimation on height{ 0194 id: playOpenHeight 0195 easing.type: Easing.OutCubic 0196 running: false 0197 from: searchField.height 0198 duration: 200 0199 to: completionList 0200 ? (Library.searches.filter && recentsRepeater.count > 0 //can't use recentsRepeater.visible directly, because it always returns false at this stage 0201 ? (Math.min(fieldContainer.height+ (completionList.count) * (completionList.delegateHeight + completionList.delegatePadding) + Kirigami.Separator.implicitHeight + recentsRepeater.implicitHeight, Kirigami.Units.gridUnit * 20))+2*(popup.shadowSize+popup.expansion) 0202 : (completionList.count === 0 0203 ?(Math.min(fieldContainer.height+ noMatchingSearchLabel.height + 2*noMatchingSearchLabel.Layout.margins, Kirigami.Units.gridUnit * 20))+2*(popup.shadowSize+popup.expansion) 0204 :(Math.min(fieldContainer.height+ (completionList.count) * (completionList.delegateHeight + 2.725*completionList.delegatePadding) + 2*mainScrollViewLayout.spacing, Kirigami.Units.gridUnit * 20))+2*(popup.shadowSize+popup.expansion) 0205 ) 0206 ) 0207 : (Kirigami.Units.gridUnit * 20)+2*(popup.shadowSize+popup.expansion) 0208 } 0209 NumberAnimation on width{ 0210 id: playOpenWidth 0211 easing.type: Easing.OutCubic 0212 running: false 0213 from: searchField.width 0214 duration: 100 0215 to: searchField.width +2*(popup.shadowSize+popup.expansion) 0216 } 0217 NumberAnimation on x{ 0218 id: playOpenX 0219 easing.type: Easing.OutCubic 0220 running: false 0221 from: 0 0222 duration: 100 0223 to: -(popup.shadowSize+popup.expansion) 0224 } 0225 NumberAnimation on y{ 0226 id: playOpenY 0227 easing.type: Easing.OutCubic 0228 running: false 0229 from: 0 0230 duration: 100 0231 to: -popup.expansion 0232 } 0233 0234 0235 0236 NumberAnimation on height{ 0237 id: playCloseHeight 0238 easing.type: Easing.OutCubic 0239 running: false 0240 from: completionList 0241 ? (Math.min(content.implicitHeight, Kirigami.Units.gridUnit * 20))+2*(popup.shadowSize+popup.expansion) 0242 : (Kirigami.Units.gridUnit * 20)+2*(popup.shadowSize+popup.expansion) 0243 duration: 100 0244 to: searchField.height 0245 } 0246 NumberAnimation on width{ 0247 id: playCloseWidth 0248 easing.type: Easing.OutCubic 0249 running: false 0250 from: searchField.width + 2*(popup.shadowSize+popup.expansion) 0251 duration: 100 0252 to: searchField.width + 2*(popup.shadowSize) 0253 } 0254 NumberAnimation on x{ 0255 id: playCloseX 0256 easing.type: Easing.OutCubic 0257 running: false 0258 from: -(popup.shadowSize+popup.expansion) 0259 duration: 100 0260 to: -popup.shadowSize 0261 } 0262 NumberAnimation on y{ 0263 id: playCloseY 0264 easing.type: Easing.OutCubic 0265 running: false 0266 from: - popup.expansion 0267 duration: 100 0268 to: -0 0269 } 0270 0271 property alias fieldContainer: fieldContainer 0272 0273 contentItem: ColumnLayout{ 0274 id: content 0275 width: parent.width 0276 Controls.Control{ 0277 Layout.fillHeight: true 0278 Layout.fillWidth: true 0279 Controls.Control{ 0280 x: popup.expansion 0281 y:-popup.expansion 0282 id: fieldContainer 0283 height:searchField.height 0284 } 0285 implicitHeight: fieldContainer.height 0286 } 0287 0288 Controls.ScrollView { 0289 id: mainScrollView 0290 implicitHeight: mainScrollViewLayout.implicitHeight 0291 0292 clip: true 0293 0294 Layout.fillHeight: true 0295 Layout.fillWidth: true 0296 0297 Keys.enabled: false 0298 contentWidth: availableWidth 0299 0300 ColumnLayout { 0301 id: mainScrollViewLayout 0302 0303 width: mainScrollView.contentWidth 0304 0305 HorizontalCoverView { 0306 id: recentsRepeater 0307 Controls.ScrollBar.horizontal.policy: Controls.ScrollBar.AlwaysOff 0308 0309 contentHeight: 120 0310 itemSpacing: 0 0311 0312 Layout.fillWidth: true 0313 0314 visible: Library.searches.filter && recentsRepeater.count > 0 //if changed, adjust playOpenHeight 0315 0316 model: LocalSearchModel { 0317 searchQuery: Library.searches.filter 0318 } 0319 0320 delegate: searchAlbum 0321 } 0322 Kirigami.Separator { 0323 visible: recentsRepeater.visible 0324 Layout.fillWidth: true 0325 implicitWidth: popup.width 0326 } 0327 RowLayout{ 0328 id: noMatchingSearchLabel 0329 0330 Layout.margins: 10 0331 visible: completionList.count == 0 0332 Kirigami.Icon { 0333 source: "documentinfo" 0334 implicitHeight: Kirigami.Units.gridUnit 0335 implicitWidth: Kirigami.Units.gridUnit 0336 color: Kirigami.Theme.disabledTextColor 0337 } 0338 Controls.Label { 0339 text: i18n("No matching previous searches") 0340 Layout.fillWidth: true 0341 color: Kirigami.Theme.disabledTextColor 0342 0343 } 0344 } 0345 Repeater { 0346 Layout.fillWidth: true 0347 0348 property int selectedDelegate: -1 0349 property int delegateHeight: Kirigami.Units.gridUnit 0350 property int delegatePadding: Kirigami.Units.smallSpacing 0351 property int empiricDelegateHeight: recentsRepeater.visible ? (mainScrollView.contentHeight - recentsRepeater.height) / count : (mainScrollView.contentHeight + mainScrollViewLayout.spacing) / (count) 0352 0353 id: completionList 0354 model: Library.searches 0355 0356 function isSelectedDelegateVisible() { 0357 if(!recentsRepeater.visible) { 0358 return selectedDelegate * empiricDelegateHeight > mainScrollView.contentItem.contentY && (selectedDelegate + 1) * empiricDelegateHeight < mainScrollView.contentItem.contentY + mainScrollView.height 0359 } 0360 else { 0361 return selectedDelegate * empiricDelegateHeight + recentsRepeater.height > mainScrollView.contentItem.contentY && (selectedDelegate + 1) * empiricDelegateHeight + recentsRepeater.height < mainScrollView.contentItem.contentY + mainScrollView.height 0362 } 0363 } 0364 0365 delegate: Controls.ItemDelegate { 0366 required property string searchQuery 0367 required property int index 0368 0369 id: completionDelegate 0370 highlighted: focus || (completionList.selectedDelegate == index) 0371 Kirigami.Theme.colorSet: Kirigami.Theme.View 0372 Kirigami.Theme.inherit: false 0373 Layout.fillWidth: true 0374 height: completionList.delegateHeight 0375 text: searchQuery 0376 padding: completionList.delegatePadding 0377 spacing: 0 0378 0379 contentItem: RowLayout { 0380 Kirigami.Icon { 0381 source: "search" 0382 implicitHeight: completionList.delegateHeight 0383 implicitWidth: completionList.delegateHeight 0384 color: Kirigami.Theme.disabledTextColor 0385 } 0386 Controls.Label{ 0387 text: searchQuery 0388 Layout.fillWidth: true 0389 elide: Text.ElideRight 0390 } 0391 Controls.ToolButton { 0392 icon.name: "list-remove" 0393 text: i18n("remove from search history") 0394 display: Controls.AbstractButton.IconOnly 0395 onClicked: { 0396 Library.removeSearch(completionDelegate.searchQuery) 0397 } 0398 implicitHeight: completionList.delegateHeight 0399 visible: Library.temporarySearch == "" || index != 0 0400 } 0401 0402 } 0403 onClicked: { 0404 searchField.text = searchQuery 0405 searchField.accepted() 0406 } 0407 } 0408 } 0409 } 0410 } 0411 } 0412 } 0413 }