shift-shell/components/mobileshell/qml/actiondrawer/private/QuickSettingsStatusRow.qml

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

250 lines
9.8 KiB
QML
Raw Normal View History

// SPDX-FileCopyrightText: 2026 Marco Allegretti
// SPDX-License-Identifier: EUPL-1.2
import QtQuick 2.15
import QtQuick.Layouts 1.1
import org.kde.kirigami as Kirigami
import org.kde.plasma.private.mobileshell as MobileShell
/**
* Management/detail row shown in convergence mode. Two interaction zones:
* - Left toggle pill: icon + indicator dot, tap toggles the service.
* - Right detail area: name + status + chevron, tap opens detail popup.
*/
Item {
id: root
required property string text
required property string status
required property string icon
required property bool enabled
required property var toggleFunction
property bool compact: false
signal detailClicked()
implicitHeight: Kirigami.Units.gridUnit * (compact ? 3.1 : 3.6)
Kirigami.Theme.inherit: false
Kirigami.Theme.colorSet: Kirigami.Theme.Button
2026-04-29 06:39:34 +00:00
readonly property int rowRadius: Kirigami.Units.largeSpacing + Kirigami.Units.smallSpacing
readonly property color enabledBg: mixColor(Kirigami.Theme.backgroundColor, Kirigami.Theme.highlightColor, 0.25)
readonly property color enabledBgHover: mixColor(Kirigami.Theme.backgroundColor, Kirigami.Theme.highlightColor, 0.32)
readonly property color enabledBgPressed: mixColor(Kirigami.Theme.backgroundColor, Kirigami.Theme.highlightColor, 0.12)
readonly property color enabledBorder: Qt.darker(Kirigami.Theme.highlightColor, 1.25)
readonly property bool hasToggle: toggleFunction !== null && toggleFunction !== undefined
2026-04-29 06:39:34 +00:00
readonly property color disabledBg: Kirigami.Theme.alternateBackgroundColor
readonly property color disabledBgHover: mixColor(Kirigami.Theme.alternateBackgroundColor, Kirigami.Theme.textColor, 0.06)
readonly property color disabledBgPressed: Qt.darker(disabledBg, 1.1)
readonly property color disabledBorder: {
let bg = Kirigami.Theme.backgroundColor;
let fg = Kirigami.Theme.textColor;
if (Kirigami.ColorUtils.brightnessForColor(bg) === Kirigami.ColorUtils.Light) {
return Kirigami.ColorUtils.linearInterpolation(bg, fg, 0.2);
} else {
return Kirigami.ColorUtils.linearInterpolation(bg, fg, 0.1);
}
}
readonly property int shortAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsFast)
readonly property int pressAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.Press)
readonly property real pressedScale: MobileShell.Motion.pressScaleIn
2026-04-29 06:39:34 +00:00
function mixColor(base, overlay, ratio) {
return Qt.rgba(
base.r + (overlay.r - base.r) * ratio,
base.g + (overlay.g - base.g) * ratio,
base.b + (overlay.b - base.b) * ratio,
base.a + (overlay.a - base.a) * ratio)
}
MobileShell.HapticsEffect { id: haptics }
// ── Outer card ──────────────────────────────────────────────────────
// Shadow
Rectangle {
anchors.top: parent.top
anchors.topMargin: 1
anchors.left: parent.left
anchors.right: parent.right
height: parent.height
2026-04-29 06:39:34 +00:00
radius: root.rowRadius
color: Qt.rgba(0, 0, 0, root.enabled ? 0.12 : 0.08)
}
// Card background — always neutral base (the toggle pill carries the
// enabled highlight, not the whole row).
Rectangle {
id: cardBg
anchors.fill: parent
2026-04-29 06:39:34 +00:00
radius: root.rowRadius
border.pixelAligned: false
border.width: 1
border.color: root.disabledBorder
color: root.disabledBg
}
RowLayout {
anchors.fill: parent
anchors.margins: Kirigami.Units.smallSpacing
spacing: Kirigami.Units.smallSpacing
// ── Toggle pill (left zone) ─────────────────────────────────
Item {
id: togglePill
Layout.alignment: Qt.AlignVCenter
Layout.preferredWidth: root.height - Kirigami.Units.smallSpacing * 2
Layout.fillHeight: true
Rectangle {
id: pillBg
anchors.fill: parent
radius: Kirigami.Units.cornerRadius
border.pixelAligned: false
border.width: 1
border.color: root.enabled ? root.enabledBorder : root.disabledBorder
color: {
if (root.enabled) {
2026-04-29 06:39:34 +00:00
if (toggleMouse.pressed) {
return root.enabledBgPressed;
}
return toggleMouse.containsMouse ? root.enabledBgHover : root.enabledBg;
}
if (toggleMouse.pressed) {
return root.disabledBgPressed;
}
2026-04-29 06:39:34 +00:00
return toggleMouse.containsMouse ? root.disabledBgHover : root.disabledBg;
}
Behavior on color {
MobileShell.MotionColorAnimation { type: MobileShell.Motion.EffectsFast }
}
}
// Scale on press
property real zoomScale: toggleMouse.pressed ? root.pressedScale : 1
Behavior on zoomScale {
MobileShell.MotionNumberAnimation { type: MobileShell.Motion.Press }
}
transform: Scale {
origin.x: togglePill.width / 2
origin.y: togglePill.height / 2
xScale: togglePill.zoomScale
yScale: togglePill.zoomScale
}
ColumnLayout {
anchors.centerIn: parent
spacing: Kirigami.Units.smallSpacing
Kirigami.Icon {
Layout.alignment: Qt.AlignHCenter
implicitWidth: Kirigami.Units.iconSizes.smallMedium
implicitHeight: implicitWidth
source: root.icon
Kirigami.Theme.inherit: false
Kirigami.Theme.colorSet: Kirigami.Theme.Window
isMask: true
color: Kirigami.Theme.textColor
}
2026-04-29 06:39:34 +00:00
// Indicator bar
Rectangle {
Layout.alignment: Qt.AlignHCenter
visible: root.hasToggle
Layout.preferredHeight: visible ? Math.max(2, Math.round(Kirigami.Units.devicePixelRatio)) : 0
2026-04-29 06:39:34 +00:00
width: root.enabled ? Kirigami.Units.smallSpacing * 3 : Kirigami.Units.smallSpacing * 1.5
height: Layout.preferredHeight
2026-04-29 06:39:34 +00:00
radius: height / 2
color: root.enabled ? Kirigami.Theme.highlightColor : Kirigami.Theme.disabledTextColor
opacity: root.enabled ? 1.0 : 0.4
2026-04-29 06:39:34 +00:00
Behavior on width {
MobileShell.MotionNumberAnimation { type: MobileShell.Motion.EffectsFast }
2026-04-29 06:39:34 +00:00
}
}
}
MouseArea {
id: toggleMouse
anchors.fill: parent
2026-04-29 06:39:34 +00:00
hoverEnabled: true
cursorShape: root.hasToggle ? Qt.PointingHandCursor : Qt.ArrowCursor
onPressed: {
if (root.hasToggle) {
haptics.buttonVibrate()
}
}
onClicked: {
if (root.hasToggle) root.toggleFunction();
}
}
}
// ── Detail area (right zone) ────────────────────────────────
Item {
Layout.fillWidth: true
Layout.fillHeight: true
MobileShell.MotionStateLayer {
anchors.fill: parent
radius: Kirigami.Units.cornerRadius
hovered: detailMouse.containsMouse
pressed: detailMouse.pressed
hoverOpacity: 0.03
pressedOpacity: 0.06
}
MouseArea {
id: detailMouse
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onPressed: haptics.buttonVibrate()
onClicked: root.detailClicked()
}
RowLayout {
anchors.fill: parent
anchors.leftMargin: Kirigami.Units.smallSpacing * 2
anchors.rightMargin: Kirigami.Units.smallSpacing * 2
spacing: Kirigami.Units.smallSpacing
ColumnLayout {
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
spacing: 2
MobileShell.MarqueeLabel {
Layout.fillWidth: true
inputText: root.text
font.weight: Font.Bold
font.pointSize: Kirigami.Theme.defaultFont.pointSize * 0.9
}
MobileShell.MarqueeLabel {
Layout.fillWidth: true
inputText: root.status ? root.status : (root.enabled ? i18n("On") : i18n("Off"))
opacity: 0.6
font.pointSize: Kirigami.Theme.defaultFont.pointSize * 0.8
}
}
Kirigami.Icon {
Layout.alignment: Qt.AlignVCenter
implicitWidth: Kirigami.Units.iconSizes.small
implicitHeight: implicitWidth
source: "go-next-symbolic"
Kirigami.Theme.inherit: false
Kirigami.Theme.colorSet: Kirigami.Theme.Window
isMask: true
color: Kirigami.Theme.textColor
opacity: 0.5
}
}
}
}
}