mirror of
https://github.com/AquaMorph/dotfiles.git
synced 2026-09-29 20:04:21 +00:00
387 lines
12 KiB
QML
387 lines
12 KiB
QML
import QtQuick
|
|
import Quickshell
|
|
import Quickshell.Services.UPower
|
|
|
|
PopupWindow {
|
|
id: root
|
|
|
|
property var hardware
|
|
property var sink
|
|
property var source
|
|
property var battery
|
|
property var clock
|
|
property var anchorItem: null
|
|
property string page: ""
|
|
|
|
function toggle(nextPage, item) {
|
|
if (visible && page === nextPage) {
|
|
visible = false;
|
|
return;
|
|
}
|
|
page = nextPage;
|
|
anchorItem = item;
|
|
if (page === "network")
|
|
hardware.refreshWifi();
|
|
anchor.updateAnchor();
|
|
visible = true;
|
|
}
|
|
|
|
function duration(seconds) {
|
|
if (seconds <= 0)
|
|
return "Calculating";
|
|
const hours = Math.floor(seconds / 3600);
|
|
const minutes = Math.floor((seconds % 3600) / 60);
|
|
return hours + "h " + minutes + "m";
|
|
}
|
|
|
|
function batteryState() {
|
|
switch (battery.state) {
|
|
case UPowerDeviceState.Charging: return "Charging";
|
|
case UPowerDeviceState.Discharging: return "Discharging";
|
|
case UPowerDeviceState.FullyCharged: return "Fully charged";
|
|
case UPowerDeviceState.Empty: return "Empty";
|
|
case UPowerDeviceState.PendingCharge: return "Waiting to charge";
|
|
case UPowerDeviceState.PendingDischarge: return "Waiting to discharge";
|
|
default: return "Unknown";
|
|
}
|
|
}
|
|
|
|
visible: false
|
|
implicitWidth: Theme.popupWidth
|
|
implicitHeight: contentLoader.item
|
|
? contentLoader.item.implicitHeight + Theme.popupPadding * 2 : 100
|
|
color: "transparent"
|
|
|
|
anchor {
|
|
item: root.anchorItem
|
|
edges: Edges.Bottom | Edges.Right
|
|
gravity: Edges.Bottom | Edges.Left
|
|
margins.top: 4
|
|
}
|
|
|
|
Rectangle {
|
|
anchors.fill: parent
|
|
color: Theme.popupBackground
|
|
|
|
Loader {
|
|
id: contentLoader
|
|
anchors {
|
|
left: parent.left
|
|
right: parent.right
|
|
top: parent.top
|
|
margins: Theme.popupPadding
|
|
}
|
|
sourceComponent: root.page === "clock" ? clockPage
|
|
: root.page === "audio" ? audioPage
|
|
: root.page === "network" ? networkPage
|
|
: batteryPage
|
|
}
|
|
|
|
Rectangle {
|
|
anchors {
|
|
left: parent.left
|
|
right: parent.right
|
|
bottom: parent.bottom
|
|
}
|
|
height: Theme.activeLineWidth
|
|
color: Theme.accent
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: clockPage
|
|
|
|
Item {
|
|
id: clockContent
|
|
property date now: root.clock.date
|
|
property int year: now.getFullYear()
|
|
property int month: now.getMonth()
|
|
property int firstDay: new Date(year, month, 1).getDay()
|
|
property int days: new Date(year, month + 1, 0).getDate()
|
|
|
|
implicitWidth: Theme.popupContentWidth
|
|
implicitHeight: 310
|
|
|
|
PopupHeader {
|
|
width: parent.width
|
|
text: Qt.formatDateTime(parent.now, "dddd, MMMM d")
|
|
}
|
|
|
|
Text {
|
|
anchors {
|
|
horizontalCenter: parent.horizontalCenter
|
|
top: parent.top
|
|
topMargin: 40
|
|
}
|
|
text: Qt.formatDateTime(parent.now, "h:mm:ss AP")
|
|
color: Theme.foreground
|
|
font.family: Theme.fontFamily
|
|
font.pixelSize: Theme.fontClock
|
|
}
|
|
|
|
Row {
|
|
anchors {
|
|
left: parent.left
|
|
top: parent.top
|
|
topMargin: 86
|
|
}
|
|
spacing: 4
|
|
|
|
Repeater {
|
|
model: ["S", "M", "T", "W", "T", "F", "S"]
|
|
Text {
|
|
required property string modelData
|
|
width: 37
|
|
text: modelData
|
|
color: Theme.muted
|
|
font.family: Theme.fontFamily
|
|
horizontalAlignment: Text.AlignHCenter
|
|
font.bold: true
|
|
}
|
|
}
|
|
}
|
|
|
|
Grid {
|
|
anchors {
|
|
left: parent.left
|
|
top: parent.top
|
|
topMargin: 112
|
|
}
|
|
columns: 7
|
|
spacing: 4
|
|
|
|
Repeater {
|
|
model: 42
|
|
|
|
Rectangle {
|
|
required property int index
|
|
property int day: index - clockContent.firstDay + 1
|
|
property bool today: day === clockContent.now.getDate()
|
|
|
|
width: 37
|
|
height: 29
|
|
radius: 0
|
|
color: today ? Theme.primary : "transparent"
|
|
|
|
Rectangle {
|
|
anchors {
|
|
left: parent.left
|
|
right: parent.right
|
|
bottom: parent.bottom
|
|
}
|
|
height: Theme.activeLineWidth
|
|
visible: parent.today
|
|
color: Theme.accent
|
|
}
|
|
|
|
Text {
|
|
anchors.centerIn: parent
|
|
text: parent.day > 0 && parent.day <= clockContent.days
|
|
? parent.day : ""
|
|
color: Theme.foreground
|
|
font.family: Theme.fontFamily
|
|
font.pixelSize: Theme.fontSmall
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: audioPage
|
|
|
|
Column {
|
|
width: Theme.popupContentWidth
|
|
spacing: 12
|
|
|
|
PopupHeader {
|
|
width: parent.width
|
|
text: "Audio"
|
|
}
|
|
|
|
PopupSlider {
|
|
width: parent.width
|
|
label: "Output"
|
|
value: root.sink && root.sink.audio ? root.sink.audio.volume : 0
|
|
muted: root.sink && root.sink.audio ? root.sink.audio.muted : false
|
|
onValueRequested: value => {
|
|
if (root.sink && root.sink.audio)
|
|
root.sink.audio.volume = value;
|
|
}
|
|
onMuteRequested: {
|
|
if (root.sink && root.sink.audio)
|
|
root.sink.audio.muted = !root.sink.audio.muted;
|
|
}
|
|
}
|
|
|
|
PopupSlider {
|
|
width: parent.width
|
|
label: "Microphone"
|
|
value: root.source && root.source.audio ? root.source.audio.volume : 0
|
|
muted: root.source && root.source.audio ? root.source.audio.muted : false
|
|
onValueRequested: value => {
|
|
if (root.source && root.source.audio)
|
|
root.source.audio.volume = value;
|
|
}
|
|
onMuteRequested: {
|
|
if (root.source && root.source.audio)
|
|
root.source.audio.muted = !root.source.audio.muted;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: networkPage
|
|
|
|
Column {
|
|
width: Theme.popupContentWidth
|
|
spacing: 10
|
|
|
|
PopupHeader {
|
|
width: parent.width
|
|
text: "Network"
|
|
}
|
|
|
|
Text {
|
|
text: "Connected to " + root.hardware.connection
|
|
color: Theme.foreground
|
|
font.family: Theme.fontFamily
|
|
font.pixelSize: Theme.fontBody
|
|
}
|
|
|
|
Column {
|
|
id: networks
|
|
width: parent.width
|
|
spacing: 5
|
|
|
|
Repeater {
|
|
model: root.hardware.wifiNetworks
|
|
|
|
Rectangle {
|
|
required property var modelData
|
|
width: networks.width
|
|
height: 29
|
|
radius: 0
|
|
color: modelData.active ? Theme.primary : Theme.background
|
|
|
|
Rectangle {
|
|
anchors {
|
|
left: parent.left
|
|
right: parent.right
|
|
bottom: parent.bottom
|
|
}
|
|
height: Theme.activeLineWidth
|
|
visible: parent.modelData.active
|
|
color: Theme.accent
|
|
}
|
|
|
|
Text {
|
|
anchors {
|
|
left: parent.left
|
|
leftMargin: 9
|
|
verticalCenter: parent.verticalCenter
|
|
}
|
|
width: parent.width - 70
|
|
elide: Text.ElideRight
|
|
text: modelData.ssid
|
|
color: Theme.foreground
|
|
font.family: Theme.fontFamily
|
|
font.pixelSize: Theme.fontSmall
|
|
}
|
|
|
|
Text {
|
|
anchors {
|
|
right: parent.right
|
|
rightMargin: 9
|
|
verticalCenter: parent.verticalCenter
|
|
}
|
|
text: modelData.signal + "%"
|
|
color: Theme.foreground
|
|
font.family: Theme.fontFamily
|
|
font.pixelSize: Theme.fontCaption
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
width: parent.width
|
|
height: 30
|
|
radius: 0
|
|
color: Theme.primary
|
|
|
|
Text {
|
|
anchors.centerIn: parent
|
|
text: "Open network settings"
|
|
color: Theme.foreground
|
|
font.family: Theme.fontFamily
|
|
font.pixelSize: Theme.fontCaption
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: Quickshell.execDetached(["nm-connection-editor"])
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: batteryPage
|
|
|
|
Column {
|
|
width: Theme.popupContentWidth
|
|
spacing: 12
|
|
|
|
PopupHeader {
|
|
width: parent.width
|
|
text: "Battery"
|
|
}
|
|
|
|
Text {
|
|
text: Math.round(root.battery.percentage * 100) + "% "
|
|
+ root.batteryState()
|
|
color: Theme.foreground
|
|
font.family: Theme.fontFamily
|
|
font.pixelSize: Theme.fontDisplay
|
|
}
|
|
|
|
Rectangle {
|
|
width: parent.width
|
|
height: 8
|
|
radius: 0
|
|
color: Theme.track
|
|
|
|
Rectangle {
|
|
width: parent.width * root.battery.percentage
|
|
height: parent.height
|
|
radius: 0
|
|
color: root.battery.percentage <= 0.15 ? Theme.urgent : Theme.primary
|
|
}
|
|
}
|
|
|
|
Text {
|
|
text: UPower.onBattery
|
|
? "Remaining: " + root.duration(root.battery.timeToEmpty)
|
|
: "Until full: " + root.duration(root.battery.timeToFull)
|
|
color: Theme.accent
|
|
font.family: Theme.fontFamily
|
|
font.pixelSize: Theme.fontBody
|
|
}
|
|
|
|
Text {
|
|
text: "Rate: " + Math.abs(root.battery.changeRate).toFixed(1) + " W"
|
|
+ (root.battery.healthSupported
|
|
? " Health: " + Math.round(root.battery.healthPercentage * 100) + "%"
|
|
: "")
|
|
color: Theme.foreground
|
|
font.family: Theme.fontFamily
|
|
font.pixelSize: Theme.fontSmall
|
|
}
|
|
}
|
|
}
|
|
}
|