2026-04-19 11:51:20 +00:00
|
|
|
// SPDX-FileCopyrightText: 2026 Marco Allegretti
|
|
|
|
|
// SPDX-License-Identifier: EUPL-1.2
|
|
|
|
|
|
|
|
|
|
import QtQuick
|
|
|
|
|
import QtQuick.Layouts
|
|
|
|
|
import QtQuick.Controls as QQC2
|
|
|
|
|
import QtQuick.Window
|
|
|
|
|
|
|
|
|
|
import org.kde.kirigami as Kirigami
|
|
|
|
|
import org.kde.plasma.components 3.0 as PC3
|
|
|
|
|
import org.kde.plasma.private.mobileshell as MobileShell
|
|
|
|
|
import org.kde.plasma.private.mobileshell.state as MobileShellState
|
|
|
|
|
import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings
|
2026-04-20 07:43:11 +00:00
|
|
|
import org.kde.plasma.private.mobileshell.gamingshellplugin as GamingShell
|
2026-04-19 11:51:20 +00:00
|
|
|
import org.kde.layershell 1.0 as LayerShell
|
|
|
|
|
|
|
|
|
|
import plasma.applet.org.kde.plasma.mobile.homescreen.folio as Folio
|
|
|
|
|
|
|
|
|
|
Window {
|
|
|
|
|
id: root
|
|
|
|
|
|
|
|
|
|
required property var folio
|
|
|
|
|
|
|
|
|
|
signal gameStarted()
|
|
|
|
|
signal dismissRequested()
|
|
|
|
|
|
|
|
|
|
function requestExitGamingMode() {
|
|
|
|
|
exitGamingDialog.active = true
|
|
|
|
|
exitGamingDialog.item.open()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
width: Screen.width
|
|
|
|
|
height: Screen.height
|
|
|
|
|
color: "transparent"
|
|
|
|
|
flags: Qt.FramelessWindowHint
|
|
|
|
|
|
|
|
|
|
LayerShell.Window.scope: "gaming-overlay"
|
|
|
|
|
LayerShell.Window.layer: LayerShell.Window.LayerTop
|
|
|
|
|
LayerShell.Window.anchors: LayerShell.Window.AnchorTop | LayerShell.Window.AnchorBottom
|
|
|
|
|
| LayerShell.Window.AnchorLeft | LayerShell.Window.AnchorRight
|
|
|
|
|
LayerShell.Window.exclusionZone: -1
|
|
|
|
|
LayerShell.Window.keyboardInteractivity: LayerShell.Window.KeyboardInteractivityOnDemand
|
|
|
|
|
|
|
|
|
|
// Animate opacity on show/hide
|
|
|
|
|
opacity: visible ? 1 : 0
|
|
|
|
|
Behavior on opacity {
|
|
|
|
|
NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onVisibleChanged: {
|
|
|
|
|
if (visible) {
|
2026-04-20 08:03:41 +00:00
|
|
|
GamingShell.GameLauncherProvider.filterString = ""
|
|
|
|
|
GamingShell.GameLauncherProvider.sourceFilter = ""
|
2026-04-20 07:43:11 +00:00
|
|
|
GamingShell.GameLauncherProvider.refresh()
|
2026-04-19 11:51:20 +00:00
|
|
|
if (runningGames.hasTasks) {
|
|
|
|
|
runningGames.focusFirstTask()
|
|
|
|
|
} else {
|
|
|
|
|
grid.forceActiveFocus()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-20 07:43:11 +00:00
|
|
|
// Translate gamepad buttons to focus navigation
|
|
|
|
|
Connections {
|
|
|
|
|
target: GamingShell.GamepadManager
|
|
|
|
|
enabled: root.visible
|
|
|
|
|
|
|
|
|
|
function onButtonPressed(button, gamepadIndex) {
|
|
|
|
|
switch (button) {
|
|
|
|
|
case GamingShell.GamepadManager.ButtonDPadUp:
|
|
|
|
|
if (grid.activeFocus) {
|
|
|
|
|
if (grid.currentIndex < grid.columns && runningGames.hasTasks) {
|
|
|
|
|
runningGames.focusFirstTask()
|
|
|
|
|
} else {
|
|
|
|
|
grid.moveCurrentIndexUp()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break
|
|
|
|
|
case GamingShell.GamepadManager.ButtonDPadDown:
|
2026-04-20 08:32:30 +00:00
|
|
|
if (runningGames.activeFocus) {
|
2026-04-20 07:43:11 +00:00
|
|
|
grid.forceActiveFocus()
|
|
|
|
|
} else if (grid.activeFocus) {
|
|
|
|
|
grid.moveCurrentIndexDown()
|
|
|
|
|
}
|
|
|
|
|
break
|
|
|
|
|
case GamingShell.GamepadManager.ButtonDPadLeft:
|
|
|
|
|
if (grid.activeFocus) grid.moveCurrentIndexLeft()
|
|
|
|
|
break
|
|
|
|
|
case GamingShell.GamepadManager.ButtonDPadRight:
|
|
|
|
|
if (grid.activeFocus) grid.moveCurrentIndexRight()
|
|
|
|
|
break
|
|
|
|
|
case GamingShell.GamepadManager.ButtonA:
|
|
|
|
|
if (grid.activeFocus && grid.currentItem) {
|
|
|
|
|
GamingShell.GameLauncherProvider.launch(grid.currentIndex)
|
|
|
|
|
root.gameStarted()
|
|
|
|
|
}
|
|
|
|
|
break
|
|
|
|
|
case GamingShell.GamepadManager.ButtonB:
|
|
|
|
|
root.dismissRequested()
|
|
|
|
|
break
|
|
|
|
|
case GamingShell.GamepadManager.ButtonY:
|
|
|
|
|
root.requestExitGamingMode()
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-19 11:51:20 +00:00
|
|
|
Rectangle {
|
|
|
|
|
anchors.fill: parent
|
|
|
|
|
Kirigami.Theme.inherit: false
|
|
|
|
|
Kirigami.Theme.colorSet: Kirigami.Theme.Window
|
|
|
|
|
color: Qt.rgba(Kirigami.Theme.backgroundColor.r,
|
|
|
|
|
Kirigami.Theme.backgroundColor.g,
|
|
|
|
|
Kirigami.Theme.backgroundColor.b, 0.92)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FocusScope {
|
|
|
|
|
id: contentRoot
|
|
|
|
|
anchors.fill: parent
|
|
|
|
|
focus: root.visible
|
|
|
|
|
|
|
|
|
|
// Escape only dismisses the overlay; exiting gaming mode is explicit.
|
|
|
|
|
Keys.onEscapePressed: root.dismissRequested()
|
|
|
|
|
|
|
|
|
|
ColumnLayout {
|
|
|
|
|
anchors.fill: parent
|
|
|
|
|
anchors.margins: Kirigami.Units.largeSpacing * 2
|
|
|
|
|
spacing: Kirigami.Units.largeSpacing
|
|
|
|
|
|
|
|
|
|
// ---- header ----
|
|
|
|
|
RowLayout {
|
|
|
|
|
Layout.fillWidth: true
|
|
|
|
|
|
|
|
|
|
Kirigami.Heading {
|
|
|
|
|
Layout.fillWidth: true
|
|
|
|
|
text: i18n("Game Center")
|
|
|
|
|
level: 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QQC2.ToolButton {
|
|
|
|
|
icon.name: "window-close"
|
|
|
|
|
text: i18n("Exit Gaming Mode")
|
|
|
|
|
display: QQC2.AbstractButton.TextBesideIcon
|
|
|
|
|
Keys.onReturnPressed: clicked()
|
2026-04-20 06:57:03 +00:00
|
|
|
Keys.onEnterPressed: clicked()
|
2026-04-19 11:51:20 +00:00
|
|
|
onClicked: root.requestExitGamingMode()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ---- running games ----
|
|
|
|
|
RunningGamesView {
|
|
|
|
|
id: runningGames
|
|
|
|
|
Layout.fillWidth: true
|
|
|
|
|
onTaskActivated: root.gameStarted()
|
|
|
|
|
onMoveDownRequested: grid.forceActiveFocus()
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-20 08:03:41 +00:00
|
|
|
// ---- continue playing ----
|
|
|
|
|
ColumnLayout {
|
|
|
|
|
Layout.fillWidth: true
|
|
|
|
|
spacing: Kirigami.Units.smallSpacing
|
|
|
|
|
visible: recentList.count > 0 && !runningGames.hasTasks
|
|
|
|
|
|
|
|
|
|
Kirigami.Heading {
|
|
|
|
|
level: 2
|
|
|
|
|
text: i18n("Continue Playing")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ListView {
|
|
|
|
|
id: recentList
|
|
|
|
|
Layout.fillWidth: true
|
|
|
|
|
Layout.preferredHeight: Kirigami.Units.gridUnit * 5
|
|
|
|
|
orientation: ListView.Horizontal
|
|
|
|
|
spacing: Kirigami.Units.largeSpacing
|
|
|
|
|
clip: true
|
|
|
|
|
|
|
|
|
|
model: root.visible ? GamingShell.GameLauncherProvider.recentGames(5) : []
|
|
|
|
|
|
|
|
|
|
delegate: QQC2.ItemDelegate {
|
|
|
|
|
width: Kirigami.Units.gridUnit * 7
|
|
|
|
|
height: recentList.height
|
|
|
|
|
|
|
|
|
|
required property var modelData
|
|
|
|
|
|
|
|
|
|
readonly property bool hasArt: modelData.artwork && modelData.artwork.length > 0
|
|
|
|
|
|
|
|
|
|
background: Rectangle {
|
|
|
|
|
radius: Kirigami.Units.cornerRadius
|
|
|
|
|
color: parent.hovered ? Kirigami.Theme.hoverColor : "transparent"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
contentItem: ColumnLayout {
|
|
|
|
|
spacing: Kirigami.Units.smallSpacing
|
|
|
|
|
|
|
|
|
|
Image {
|
|
|
|
|
Layout.fillWidth: true
|
|
|
|
|
Layout.fillHeight: true
|
|
|
|
|
source: hasArt ? "file://" + modelData.artwork : ""
|
|
|
|
|
fillMode: Image.PreserveAspectCrop
|
|
|
|
|
visible: hasArt
|
|
|
|
|
asynchronous: true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Kirigami.Icon {
|
|
|
|
|
Layout.alignment: Qt.AlignHCenter
|
|
|
|
|
implicitWidth: Kirigami.Units.iconSizes.large
|
|
|
|
|
implicitHeight: Kirigami.Units.iconSizes.large
|
|
|
|
|
source: modelData.icon
|
|
|
|
|
visible: !hasArt
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PC3.Label {
|
|
|
|
|
Layout.fillWidth: true
|
|
|
|
|
text: modelData.name
|
|
|
|
|
maximumLineCount: 1
|
|
|
|
|
elide: Text.ElideRight
|
|
|
|
|
horizontalAlignment: Text.AlignHCenter
|
|
|
|
|
font.pointSize: Kirigami.Theme.defaultFont.pointSize * 0.85
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onClicked: {
|
|
|
|
|
GamingShell.GameLauncherProvider.launchByStorageId(modelData.storageId)
|
|
|
|
|
root.gameStarted()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-04-19 11:51:20 +00:00
|
|
|
}
|
|
|
|
|
|
2026-04-20 08:03:41 +00:00
|
|
|
// ---- search + filter ----
|
|
|
|
|
RowLayout {
|
|
|
|
|
Layout.fillWidth: true
|
|
|
|
|
spacing: Kirigami.Units.largeSpacing
|
|
|
|
|
|
|
|
|
|
Kirigami.SearchField {
|
|
|
|
|
id: searchField
|
|
|
|
|
Layout.fillWidth: true
|
|
|
|
|
placeholderText: i18n("Search games…")
|
|
|
|
|
onTextChanged: GamingShell.GameLauncherProvider.filterString = text
|
|
|
|
|
|
|
|
|
|
Keys.onEscapePressed: {
|
|
|
|
|
if (text.length > 0) {
|
|
|
|
|
clear()
|
|
|
|
|
} else {
|
|
|
|
|
root.dismissRequested()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Keys.onDownPressed: grid.forceActiveFocus()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QQC2.TabBar {
|
|
|
|
|
id: sourceFilterBar
|
|
|
|
|
Layout.alignment: Qt.AlignVCenter
|
|
|
|
|
|
|
|
|
|
QQC2.TabButton {
|
|
|
|
|
text: i18n("All")
|
|
|
|
|
width: implicitWidth
|
|
|
|
|
onClicked: GamingShell.GameLauncherProvider.sourceFilter = ""
|
|
|
|
|
}
|
|
|
|
|
QQC2.TabButton {
|
|
|
|
|
text: "Steam"
|
|
|
|
|
width: implicitWidth
|
|
|
|
|
onClicked: GamingShell.GameLauncherProvider.sourceFilter = "steam"
|
|
|
|
|
}
|
|
|
|
|
QQC2.TabButton {
|
|
|
|
|
text: i18n("Desktop")
|
|
|
|
|
width: implicitWidth
|
|
|
|
|
onClicked: GamingShell.GameLauncherProvider.sourceFilter = "desktop"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ---- game grid ----
|
|
|
|
|
|
2026-04-19 11:51:20 +00:00
|
|
|
GridView {
|
|
|
|
|
id: grid
|
|
|
|
|
|
|
|
|
|
Layout.fillWidth: true
|
|
|
|
|
Layout.fillHeight: true
|
|
|
|
|
|
2026-04-20 07:43:11 +00:00
|
|
|
model: GamingShell.GameLauncherProvider
|
2026-04-19 11:51:20 +00:00
|
|
|
|
2026-04-20 08:03:41 +00:00
|
|
|
readonly property real minCellSize: Kirigami.Units.gridUnit * 8
|
2026-04-19 11:51:20 +00:00
|
|
|
readonly property int columns: Math.max(2, Math.floor(width / minCellSize))
|
|
|
|
|
|
|
|
|
|
cellWidth: Math.floor(width / columns)
|
2026-04-20 08:03:41 +00:00
|
|
|
cellHeight: Math.floor(cellWidth * 1.5) + Kirigami.Units.gridUnit * 2
|
2026-04-19 11:51:20 +00:00
|
|
|
|
|
|
|
|
keyNavigationEnabled: true
|
|
|
|
|
highlightMoveDuration: 0
|
|
|
|
|
highlight: null
|
|
|
|
|
|
|
|
|
|
onActiveFocusChanged: {
|
|
|
|
|
if (activeFocus && count > 0 && currentIndex < 0) {
|
|
|
|
|
currentIndex = 0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Keys.onUpPressed: {
|
|
|
|
|
if (runningGames.hasTasks) {
|
|
|
|
|
runningGames.focusFirstTask()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-20 07:43:11 +00:00
|
|
|
Keys.onReturnPressed: {
|
|
|
|
|
if (currentIndex >= 0) {
|
|
|
|
|
GamingShell.GameLauncherProvider.launch(currentIndex)
|
|
|
|
|
root.gameStarted()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Keys.onEnterPressed: Keys.onReturnPressed(event)
|
2026-04-19 11:51:20 +00:00
|
|
|
Keys.onEscapePressed: root.dismissRequested()
|
|
|
|
|
|
|
|
|
|
delegate: Item {
|
|
|
|
|
width: grid.cellWidth
|
|
|
|
|
height: grid.cellHeight
|
|
|
|
|
|
2026-04-20 07:43:11 +00:00
|
|
|
required property int index
|
|
|
|
|
required property string name
|
|
|
|
|
required property string icon
|
|
|
|
|
required property string source
|
2026-04-20 08:03:41 +00:00
|
|
|
required property string artwork
|
|
|
|
|
|
|
|
|
|
readonly property bool hasArt: artwork.length > 0
|
2026-04-20 07:43:11 +00:00
|
|
|
|
|
|
|
|
QQC2.ItemDelegate {
|
2026-04-19 11:51:20 +00:00
|
|
|
anchors.fill: parent
|
2026-04-20 08:03:41 +00:00
|
|
|
anchors.margins: Kirigami.Units.smallSpacing
|
|
|
|
|
padding: 0
|
2026-04-20 07:43:11 +00:00
|
|
|
|
|
|
|
|
readonly property bool isCurrent: GridView.isCurrentItem && grid.activeFocus
|
|
|
|
|
|
|
|
|
|
background: Rectangle {
|
|
|
|
|
Kirigami.Theme.colorSet: Kirigami.Theme.Button
|
|
|
|
|
color: parent.isCurrent
|
|
|
|
|
? Kirigami.Theme.highlightColor
|
|
|
|
|
: (parent.hovered ? Kirigami.Theme.hoverColor : "transparent")
|
|
|
|
|
radius: Kirigami.Units.cornerRadius
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-20 08:03:41 +00:00
|
|
|
contentItem: Item {
|
|
|
|
|
// ---- cover art tile ----
|
|
|
|
|
ColumnLayout {
|
|
|
|
|
anchors.fill: parent
|
|
|
|
|
spacing: 0
|
|
|
|
|
visible: hasArt
|
|
|
|
|
|
2026-04-20 08:32:30 +00:00
|
|
|
Rectangle {
|
2026-04-20 08:03:41 +00:00
|
|
|
Layout.fillWidth: true
|
|
|
|
|
Layout.fillHeight: true
|
2026-04-20 08:32:30 +00:00
|
|
|
radius: Kirigami.Units.cornerRadius
|
|
|
|
|
clip: true
|
|
|
|
|
color: "transparent"
|
|
|
|
|
|
|
|
|
|
Image {
|
|
|
|
|
anchors.fill: parent
|
|
|
|
|
source: hasArt ? "file://" + artwork : ""
|
|
|
|
|
fillMode: Image.PreserveAspectCrop
|
|
|
|
|
smooth: true
|
|
|
|
|
asynchronous: true
|
2026-04-20 08:03:41 +00:00
|
|
|
}
|
|
|
|
|
}
|
2026-04-20 07:43:11 +00:00
|
|
|
|
2026-04-20 08:03:41 +00:00
|
|
|
// Title beneath artwork
|
|
|
|
|
PC3.Label {
|
|
|
|
|
Layout.fillWidth: true
|
|
|
|
|
Layout.preferredHeight: Kirigami.Units.gridUnit * 2
|
|
|
|
|
text: name
|
|
|
|
|
maximumLineCount: 1
|
|
|
|
|
elide: Text.ElideRight
|
|
|
|
|
horizontalAlignment: Text.AlignHCenter
|
|
|
|
|
verticalAlignment: Text.AlignVCenter
|
|
|
|
|
leftPadding: Kirigami.Units.smallSpacing
|
|
|
|
|
rightPadding: Kirigami.Units.smallSpacing
|
|
|
|
|
color: parent.parent.parent.isCurrent
|
|
|
|
|
? Kirigami.Theme.highlightedTextColor
|
|
|
|
|
: Kirigami.Theme.textColor
|
2026-04-20 07:43:11 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-20 08:03:41 +00:00
|
|
|
// ---- fallback icon tile ----
|
|
|
|
|
ColumnLayout {
|
|
|
|
|
anchors.fill: parent
|
|
|
|
|
anchors.margins: Kirigami.Units.smallSpacing
|
|
|
|
|
visible: !hasArt
|
|
|
|
|
spacing: Kirigami.Units.smallSpacing
|
|
|
|
|
|
|
|
|
|
Item { Layout.fillHeight: true }
|
|
|
|
|
|
|
|
|
|
Kirigami.Icon {
|
|
|
|
|
Layout.alignment: Qt.AlignHCenter
|
|
|
|
|
implicitWidth: Kirigami.Units.iconSizes.huge
|
|
|
|
|
implicitHeight: Kirigami.Units.iconSizes.huge
|
|
|
|
|
source: icon
|
|
|
|
|
|
|
|
|
|
scale: parent.parent.parent.isCurrent ? 1.08 : 1.0
|
|
|
|
|
Behavior on scale {
|
|
|
|
|
NumberAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.InOutQuad }
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-04-20 07:43:11 +00:00
|
|
|
|
2026-04-20 08:03:41 +00:00
|
|
|
PC3.Label {
|
|
|
|
|
Layout.alignment: Qt.AlignHCenter
|
|
|
|
|
Layout.fillWidth: true
|
|
|
|
|
text: name
|
|
|
|
|
maximumLineCount: 2
|
|
|
|
|
wrapMode: Text.Wrap
|
|
|
|
|
horizontalAlignment: Text.AlignHCenter
|
|
|
|
|
elide: Text.ElideRight
|
|
|
|
|
color: parent.parent.parent.isCurrent
|
|
|
|
|
? Kirigami.Theme.highlightedTextColor
|
|
|
|
|
: Kirigami.Theme.textColor
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Source badge
|
|
|
|
|
PC3.Label {
|
|
|
|
|
Layout.alignment: Qt.AlignHCenter
|
|
|
|
|
text: source === "steam" ? "Steam"
|
|
|
|
|
: source === "flatpak" ? "Flatpak"
|
|
|
|
|
: ""
|
|
|
|
|
visible: source !== "desktop"
|
|
|
|
|
font.pointSize: Kirigami.Theme.defaultFont.pointSize * 0.75
|
|
|
|
|
opacity: 0.6
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Item { Layout.fillHeight: true }
|
2026-04-20 07:43:11 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onClicked: {
|
|
|
|
|
GamingShell.GameLauncherProvider.launch(index)
|
|
|
|
|
root.gameStarted()
|
|
|
|
|
}
|
2026-04-19 11:51:20 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-04-20 07:43:11 +00:00
|
|
|
|
|
|
|
|
// ---- controller status bar ----
|
|
|
|
|
RowLayout {
|
|
|
|
|
Layout.fillWidth: true
|
|
|
|
|
visible: GamingShell.GamepadManager.hasGamepad
|
|
|
|
|
spacing: Kirigami.Units.largeSpacing
|
|
|
|
|
|
|
|
|
|
Kirigami.Icon {
|
|
|
|
|
implicitWidth: Kirigami.Units.iconSizes.small
|
|
|
|
|
implicitHeight: Kirigami.Units.iconSizes.small
|
|
|
|
|
source: "input-gaming"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Repeater {
|
|
|
|
|
model: GamingShell.GamepadManager
|
|
|
|
|
|
|
|
|
|
RowLayout {
|
|
|
|
|
spacing: Kirigami.Units.smallSpacing
|
|
|
|
|
required property string name
|
|
|
|
|
required property int battery
|
|
|
|
|
required property string type
|
|
|
|
|
|
|
|
|
|
PC3.Label {
|
|
|
|
|
text: name
|
|
|
|
|
font.pointSize: Kirigami.Theme.defaultFont.pointSize * 0.85
|
|
|
|
|
}
|
|
|
|
|
PC3.Label {
|
|
|
|
|
text: battery >= 0 ? battery + "%" : ""
|
|
|
|
|
visible: battery >= 0
|
|
|
|
|
font.pointSize: Kirigami.Theme.defaultFont.pointSize * 0.85
|
|
|
|
|
opacity: 0.7
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Item { Layout.fillWidth: true }
|
|
|
|
|
|
|
|
|
|
// Gamepad legend
|
|
|
|
|
PC3.Label {
|
|
|
|
|
text: i18n("A: Select B: Back Y: Exit")
|
|
|
|
|
font.pointSize: Kirigami.Theme.defaultFont.pointSize * 0.75
|
|
|
|
|
opacity: 0.5
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-04-19 11:51:20 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Loader {
|
|
|
|
|
id: exitGamingDialog
|
|
|
|
|
active: false
|
|
|
|
|
anchors.fill: parent
|
|
|
|
|
|
|
|
|
|
sourceComponent: Kirigami.PromptDialog {
|
2026-04-19 12:10:51 +00:00
|
|
|
id: theExitDialog
|
|
|
|
|
title: i18n("Leave gaming mode?")
|
|
|
|
|
subtitle: i18n("Your games will keep running in the background.")
|
|
|
|
|
standardButtons: Kirigami.Dialog.NoButton
|
|
|
|
|
customFooterActions: [
|
|
|
|
|
Kirigami.Action {
|
|
|
|
|
text: i18n("Keep Playing")
|
|
|
|
|
onTriggered: theExitDialog.close()
|
|
|
|
|
},
|
|
|
|
|
Kirigami.Action {
|
|
|
|
|
text: i18n("Leave")
|
2026-04-20 06:57:03 +00:00
|
|
|
onTriggered: {
|
|
|
|
|
ShellSettings.Settings.gamingModeEnabled = false
|
|
|
|
|
theExitDialog.close()
|
|
|
|
|
}
|
2026-04-19 12:10:51 +00:00
|
|
|
}
|
|
|
|
|
]
|
2026-04-19 11:51:20 +00:00
|
|
|
onClosed: exitGamingDialog.active = false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|