bigscreen-tube/bigscreen_tube/ui/SearchPage.qml

206 lines
6.5 KiB
QML

import QtQuick 2.15
import QtQuick.Controls 2.15 as Controls
import QtQuick.Layouts 1.15
import org.kde.kirigami 2.20 as Kirigami
import BigScreenTube 1.0
Controls.Pane
{
anchors {
fill: parent
margins: 32
}
background: Rectangle {
color: Kirigami.Theme.backgroundColor
}
Component.onCompleted: {
searchText.forceActiveFocus()
}
ColumnLayout {
anchors.fill: parent
Kirigami.Heading {
Layout.fillWidth: true
level: 1
text: qsTr("Search videos")
font.weight: Font.Light
}
Controls.TextField {
id: searchText
topPadding: 16
bottomPadding: 16
placeholderText: qsTr("Search videos...")
focus: true
Layout.fillWidth: true
Keys.onReturnPressed: {
searchController.searchVideo(text)
}
KeyNavigation.down: videoListView
}
Rectangle {
id: searchResultContainer
Layout.fillHeight: true
Layout.fillWidth: true
color: Kirigami.Theme.backgroundColor
Controls.ScrollIndicator {
id: videoListScroll
active: true
width: 12
anchors {
top: searchResultContainer.top
right: searchResultContainer.right
bottom: searchResultContainer.bottom
}
}
Keys.onEscapePressed: {
searchText.forceActiveFocus()
}
Keys.onBackPressed: {
searchText.forceActiveFocus()
}
ListView {
id: videoListView
// Model contains info to be displayed
model: searchController.model
// Delegate is how the information will be presented in the ListView
anchors.fill: parent
spacing: Kirigami.Units.largeSpacing
anchors.rightMargin: 15
clip: true
Controls.ScrollIndicator.vertical: videoListScroll
preferredHighlightBegin: currentItem ? height / 2 - currentItem.height / 2 : 0
preferredHighlightEnd: currentItem ? height / 2 + currentItem.height / 2 : height
highlightRangeMode: ListView.ApplyRange
Controls.BusyIndicator {
id: searchSpinner
running: false
anchors {
horizontalCenter: parent.horizontalCenter
verticalCenter: parent.verticalCenter
}
}
delegate: Rectangle {
color: (videoListView.currentIndex == index && videoListView.activeFocus) ? Kirigami.Theme.activeBackgroundColor : Qt.lighter(Kirigami.Theme.backgroundColor, 1.2)
width: parent ? parent.width : 0
radius: 4
// height + margins
implicitHeight: delegateLayout.implicitHeight + 20
RowLayout {
id: delegateLayout
anchors {
left: parent.left
top: parent.top
right: parent.right
bottom: parent.bottom
margins: 10
}
spacing: Kirigami.Units.largeSpacing
Rectangle {
height: 180
width: 320
color: "transparent"
Image {
source: thumbnailUrl
fillMode: Image.PreserveAspectFit
anchors.fill: parent
}
Image {
source: "images/play.svg"
fillMode: Image.PreserveAspectFit
anchors {
horizontalCenter: parent.horizontalCenter
verticalCenter: parent.verticalCenter
}
opacity: 0.7
sourceSize.width: 150
sourceSize.height: 150
visible: videoListView.currentIndex == index && videoListView.activeFocus
}
}
// Layout for positioning elements vertically
ColumnLayout {
Kirigami.Heading {
Layout.fillWidth: true
level: 1
text: title
color: Kirigami.Theme.textColor
}
Kirigami.Heading {
Layout.fillWidth: true
Layout.fillHeight: true
level: 2
text: programName
color: Kirigami.Theme.textColor
}
// Labels contain text
Controls.Label {
Layout.fillWidth: true
text: qsTr("Published") + " " + new Date(published * 1000).toLocaleDateString()
color: Kirigami.Theme.textColor
}
}
}
Keys.onReturnPressed: {
console.log("Selecting video")
appStack.push("VideoPage.qml", {videoTitle: title, videoSource: sourceUrl})
}
}
}
}
}
SearchController {
id: searchController
property var signals: Connections {
function onSearchLoaded() {
searchSpinner.running = false
videoListView.forceActiveFocus()
videoListView.currentIndex = 0
}
function onSearchStart() {
searchSpinner.running = true
}
function onSearchError() {
showPassiveNotification(qsTr("Network error occured during search"))
}
}
}
}