a-la-karte/src/qml/LibraryView.qml

217 lines
6.9 KiB
QML
Raw Normal View History

// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2024 A-La-Karte Contributors
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.alakarte
import "components"
FocusScope {
id: libraryRoot
property string filterSource: "all"
property bool searchActive: false
property int focusedIndex: 0
property int adaptiveCardSize: App.config.gridSize
property bool isTouchDevice: false
signal gameSelected(var game)
signal gameLaunched(var game)
function focusSearch() {
searchField.forceActiveFocus()
}
function restoreFocus() {
if (libraryRoot.searchActive) {
libraryRoot.focusSearch()
} else {
gameGrid.forceActiveFocus()
}
}
onSearchActiveChanged: {
if (!libraryRoot.searchActive) {
Qt.callLater(function() {
gameGrid.forceActiveFocus()
})
}
}
Item {
anchors.fill: parent
anchors.margins: 0
ColumnLayout {
anchors.fill: parent
spacing: Kirigami.Units.smallSpacing
SearchHeader {
id: searchHeader
Layout.fillWidth: true
visible: libraryRoot.searchActive
searchField: searchField
onSearchChanged: function(text) {
proxyModel.filterText = text
}
onSortChanged: function(mode) {
proxyModel.sortMode = mode
}
Kirigami.SearchField {
id: searchField
Layout.fillWidth: true
placeholderText: i18n("Search games...")
onTextChanged: proxyModel.filterText = text
Keys.onEscapePressed: {
text = ""
let w = applicationWindow()
if (w && w.hasOwnProperty("searchActive")) {
w.searchActive = false
} else {
libraryRoot.searchActive = false
}
libraryRoot.restoreFocus()
}
Keys.onDownPressed: gameGrid.forceActiveFocus()
}
}
GameGridView {
id: gameGrid
Layout.fillWidth: true
Layout.fillHeight: true
cardSize: libraryRoot.adaptiveCardSize
model: GameSortFilterModel {
id: proxyModel
sourceModel: App.gameModel
showHidden: libraryRoot.filterSource === "hidden"
favoritesOnly: libraryRoot.filterSource === "favorites"
filterSource: {
if (libraryRoot.filterSource === "all") return ""
if (libraryRoot.filterSource === "favorites") return ""
if (libraryRoot.filterSource === "hidden") return ""
return libraryRoot.filterSource
}
}
delegate: Item {
width: gameGrid.cellWidth
height: gameGrid.cellHeight
function clicked() {
card.clicked()
}
GameCard {
id: card
width: gameGrid.cardSize
height: Math.round(gameGrid.cardSize * 1.4)
anchors.centerIn: parent
game: model.gameObject
focused: gameGrid.currentIndex === index && gameGrid.activeFocus
onClicked: libraryRoot.gameSelected(model.gameObject)
onDoubleClicked: libraryRoot.gameLaunched(model.gameObject)
onPlayClicked: libraryRoot.gameLaunched(model.gameObject)
Keys.onReturnPressed: libraryRoot.gameSelected(model.gameObject)
Keys.onEnterPressed: libraryRoot.gameSelected(model.gameObject)
Keys.onSpacePressed: libraryRoot.gameLaunched(model.gameObject)
}
}
Keys.onPressed: function(event) {
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
let game = proxyModel.get(currentIndex)
if (game) {
libraryRoot.gameSelected(game)
}
event.accepted = true
} else if (event.key === Qt.Key_Space) {
let game = proxyModel.get(currentIndex)
if (game) {
libraryRoot.gameLaunched(game)
}
event.accepted = true
}
}
EmptyState {
anchors.centerIn: parent
visible: proxyModel.count === 0 && !App.importing
icon: proxyModel.filterText.length > 0 ? "edit-find" : "applications-games"
title: proxyModel.filterText.length > 0 ?
i18n("No games found") : i18n("Your library is empty")
description: proxyModel.filterText.length > 0 ?
i18n("Try adjusting your search") :
i18n("Import games to get started")
actionText: proxyModel.filterText.length > 0 ? "" : i18n("Import Games")
onActionTriggered: App.importAllGames()
}
QQC2.BusyIndicator {
anchors.centerIn: parent
running: App.importing
visible: App.importing
}
}
QQC2.ToolBar {
Layout.fillWidth: true
visible: proxyModel.count > 0
leftPadding: 0
rightPadding: 0
topPadding: Kirigami.Units.smallSpacing
bottomPadding: Kirigami.Units.smallSpacing
contentItem: RowLayout {
spacing: Kirigami.Units.mediumSpacing
QQC2.Label {
text: i18np("%1 game", "%1 games", proxyModel.count)
color: Kirigami.Theme.disabledTextColor
font.pointSize: Kirigami.Theme.smallFont.pointSize
Layout.alignment: Qt.AlignVCenter
}
Item { Layout.fillWidth: true }
QQC2.Slider {
id: sizeSlider
from: 120
to: 280
stepSize: 20
value: App.config.gridSize
Layout.preferredWidth: Kirigami.Units.gridUnit * 8
Layout.alignment: Qt.AlignVCenter
onMoved: App.config.gridSize = value
QQC2.ToolTip {
parent: sizeSlider.handle
visible: sizeSlider.pressed
text: Math.round(sizeSlider.value) + " px"
}
}
}
}
}
}
}