split lock surface into LockClock, LockNotifPills, LockWidgets
This commit is contained in:
parent
de193a88cd
commit
5248261975
5 changed files with 263 additions and 238 deletions
|
|
@ -2,8 +2,6 @@ import QtQuick
|
|||
import QtQuick.Effects
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Services.Mpris
|
||||
import Quickshell.Services.Pipewire
|
||||
import "../services" as S
|
||||
import "../applets" as C
|
||||
|
||||
|
|
@ -47,7 +45,6 @@ WlSessionLockSurface {
|
|||
|
||||
// Hex wave overlay
|
||||
C.HexWaveBackground {
|
||||
id: hexWave
|
||||
anchors.fill: parent
|
||||
running: root.lock.secure
|
||||
opacity: root._bgOpacity * 0.4
|
||||
|
|
@ -83,74 +80,17 @@ WlSessionLockSurface {
|
|||
}
|
||||
}
|
||||
|
||||
// Clock - rotated, left-aligned, scaled to screen height
|
||||
Item {
|
||||
// Clock - rotated, left-aligned
|
||||
LockClock {
|
||||
id: _clockItem
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 48
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
width: _clockText.height
|
||||
|
||||
opacity: 0
|
||||
property real _slideX: -80
|
||||
|
||||
ParallelAnimation on opacity {
|
||||
NumberAnimation {
|
||||
to: 1
|
||||
duration: 400
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
NumberAnimation on _slideX {
|
||||
to: 0
|
||||
duration: 500
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
|
||||
transform: Translate {
|
||||
x: _clockItem._slideX
|
||||
}
|
||||
|
||||
Column {
|
||||
id: _clockCol
|
||||
anchors.centerIn: parent
|
||||
spacing: 8
|
||||
rotation: -90
|
||||
transformOrigin: Item.Center
|
||||
Text {
|
||||
id: _clockText
|
||||
text: Qt.formatTime(new Date(), "HH:mm")
|
||||
color: S.Theme.base05
|
||||
font.pixelSize: Math.max(48, root.height * 0.28)
|
||||
font.family: S.Theme.fontFamily
|
||||
font.bold: true
|
||||
|
||||
Timer {
|
||||
interval: 1000
|
||||
running: true
|
||||
repeat: true
|
||||
onTriggered: parent.text = Qt.formatTime(new Date(), "HH:mm")
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: Qt.formatDate(new Date(), "dddd, d MMMM")
|
||||
color: S.Theme.base04
|
||||
font.pixelSize: S.Theme.fontSize + 2
|
||||
font.family: S.Theme.fontFamily
|
||||
|
||||
Timer {
|
||||
interval: 60000
|
||||
running: true
|
||||
repeat: true
|
||||
onTriggered: parent.text = Qt.formatDate(new Date(), "dddd, d MMMM")
|
||||
}
|
||||
}
|
||||
}
|
||||
screenHeight: root.height
|
||||
}
|
||||
|
||||
// Center content
|
||||
// Center content - password and notifications
|
||||
Item {
|
||||
id: content
|
||||
anchors.centerIn: parent
|
||||
|
|
@ -175,89 +115,8 @@ WlSessionLockSurface {
|
|||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: 24
|
||||
|
||||
// Notification pills
|
||||
Row {
|
||||
LockNotifPills {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: 6
|
||||
visible: (S.Modules.lock.notifications ?? true) && _notifGroups.length > 0
|
||||
|
||||
readonly property var _notifGroups: {
|
||||
const notifs = S.NotifService.list.filter(n => n.state !== "dismissed");
|
||||
const groups = {};
|
||||
for (const n of notifs) {
|
||||
const key = n.appIcon || n.appName || "unknown";
|
||||
if (!groups[key])
|
||||
groups[key] = {
|
||||
icon: n.appIcon,
|
||||
name: n.appName,
|
||||
count: 0
|
||||
};
|
||||
groups[key].count++;
|
||||
}
|
||||
return Object.values(groups);
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: parent._notifGroups
|
||||
|
||||
delegate: Rectangle {
|
||||
id: _pill
|
||||
required property var modelData
|
||||
width: _pillRow.implicitWidth + 12
|
||||
height: 24
|
||||
radius: 12
|
||||
color: Qt.rgba(S.Theme.base01.r, S.Theme.base01.g, S.Theme.base01.b, 0.7)
|
||||
border.color: Qt.rgba(S.Theme.base03.r, S.Theme.base03.g, S.Theme.base03.b, 0.3)
|
||||
border.width: 1
|
||||
|
||||
HoverHandler {
|
||||
id: _pillHover
|
||||
}
|
||||
|
||||
// App name tooltip
|
||||
Text {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.bottom: parent.top
|
||||
anchors.bottomMargin: 4
|
||||
text: _pill.modelData.name || ""
|
||||
color: S.Theme.base04
|
||||
font.pixelSize: S.Theme.fontSize - 2
|
||||
font.family: S.Theme.fontFamily
|
||||
visible: _pillHover.hovered && text !== ""
|
||||
}
|
||||
|
||||
Row {
|
||||
id: _pillRow
|
||||
anchors.centerIn: parent
|
||||
spacing: 4
|
||||
|
||||
Image {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 14
|
||||
height: 14
|
||||
source: {
|
||||
const icon = _pill.modelData.icon;
|
||||
if (!icon)
|
||||
return "";
|
||||
if (icon.startsWith("/"))
|
||||
return icon;
|
||||
return Quickshell.iconPath(icon) ?? "";
|
||||
}
|
||||
sourceSize: Qt.size(14, 14)
|
||||
visible: source !== ""
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: _pill.modelData.count > 1 ? _pill.modelData.count.toString() : ""
|
||||
color: S.Theme.base04
|
||||
font.pixelSize: S.Theme.fontSize - 2
|
||||
font.family: S.Theme.fontFamily
|
||||
visible: _pill.modelData.count > 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Spacer
|
||||
|
|
@ -276,7 +135,6 @@ WlSessionLockSurface {
|
|||
|
||||
// Error message
|
||||
Text {
|
||||
id: _errorText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: root.auth.message
|
||||
color: S.Theme.base08
|
||||
|
|
@ -300,101 +158,12 @@ WlSessionLockSurface {
|
|||
}
|
||||
}
|
||||
|
||||
// Right column - widgets, slides in from right
|
||||
Item {
|
||||
// Right column - widgets
|
||||
LockWidgets {
|
||||
id: _widgetCol
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 48
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 280
|
||||
height: _widgetContent.implicitHeight
|
||||
visible: _mprisCard.visible || _volumeCard.visible
|
||||
|
||||
opacity: 0
|
||||
property real _slideX: 80
|
||||
|
||||
NumberAnimation on opacity {
|
||||
to: 1
|
||||
duration: 400
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
NumberAnimation on _slideX {
|
||||
to: 0
|
||||
duration: 500
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
|
||||
transform: Translate {
|
||||
x: _widgetCol._slideX
|
||||
}
|
||||
|
||||
Column {
|
||||
id: _widgetContent
|
||||
width: parent.width
|
||||
spacing: 12
|
||||
|
||||
// Media widget
|
||||
Rectangle {
|
||||
id: _mprisCard
|
||||
width: parent.width
|
||||
height: _mprisContent.implicitHeight + 16
|
||||
radius: S.Theme.radius + 2
|
||||
color: Qt.rgba(S.Theme.base01.r, S.Theme.base01.g, S.Theme.base01.b, 0.7)
|
||||
border.color: Qt.rgba(S.Theme.base03.r, S.Theme.base03.g, S.Theme.base03.b, 0.3)
|
||||
border.width: 1
|
||||
visible: (S.Modules.lock.mpris ?? true) && _mprisPlayer !== null
|
||||
|
||||
readonly property var _mprisPlayers: (Mpris.players.values ?? []).filter(p => p.trackTitle || p.playbackState === MprisPlaybackState.Playing || p.playbackState === MprisPlaybackState.Paused)
|
||||
property int _playerIdx: 0
|
||||
readonly property var _mprisPlayer: _mprisPlayers[_playerIdx] ?? _mprisPlayers[0] ?? null
|
||||
readonly property bool _playing: _mprisPlayer?.playbackState === MprisPlaybackState.Playing
|
||||
|
||||
C.MprisApplet {
|
||||
id: _mprisContent
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 8
|
||||
player: _mprisCard._mprisPlayer
|
||||
players: _mprisCard._mprisPlayers
|
||||
playing: _mprisCard._playing
|
||||
playerIdx: _mprisCard._playerIdx
|
||||
accentColor: S.Theme.base0D
|
||||
cachedArt: _mprisCard._mprisPlayer?.trackArtUrl ?? ""
|
||||
onPlayerSwitched: idx => {
|
||||
_mprisCard._playerIdx = idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Volume widget
|
||||
Rectangle {
|
||||
id: _volumeCard
|
||||
width: parent.width
|
||||
height: _volumeContent.implicitHeight + 16
|
||||
radius: S.Theme.radius + 2
|
||||
color: Qt.rgba(S.Theme.base01.r, S.Theme.base01.g, S.Theme.base01.b, 0.7)
|
||||
border.color: Qt.rgba(S.Theme.base03.r, S.Theme.base03.g, S.Theme.base03.b, 0.3)
|
||||
border.width: 1
|
||||
visible: (S.Modules.lock.volume ?? true) && Pipewire.defaultAudioSink !== null
|
||||
|
||||
PwObjectTracker {
|
||||
objects: [Pipewire.defaultAudioSink]
|
||||
}
|
||||
|
||||
C.VolumeApplet {
|
||||
id: _volumeContent
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 8
|
||||
sink: Pipewire.defaultAudioSink
|
||||
sinkList: []
|
||||
streamList: []
|
||||
accentColor: S.Theme.base0E
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue