mirror of
https://invent.kde.org/marcoa/a-la-karte.git
synced 2026-02-09 21:13:08 +00:00
217 lines
6.9 KiB
QML
217 lines
6.9 KiB
QML
|
|
// 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"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|