feat: add current weather widget, and wifi info

This commit is contained in:
Nydragon 2024-11-19 18:24:43 +01:00
parent a57cc7c1d2
commit 00aa8eaea2
Signed by: nydragon
SSH key fingerprint: SHA256:WcjW5NJPQ8Dx4uQDmoIlVPLWE27Od3fxoe0IUvuoPHE
11 changed files with 435 additions and 34 deletions

View file

@ -1,10 +1,14 @@
import Quickshell
import Quickshell.Io
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import QtQml
import "base"
import "widgets/mpris"
import "widgets/notifications"
import "widgets/weather"
import "widgets/wifi"
import "provider"
PanelWindow {
@ -73,40 +77,85 @@ PanelWindow {
Layout.fillHeight: true
}
ColumnLayout {
StackView {
id: stack
initialItem: main
Layout.fillHeight: true
Layout.fillWidth: true
height: parent.height
Layout.margins: 15
Layout.alignment: Qt.AlignBottom
clip: true
ListView {
id: popupcol
Component.onCompleted: NyshState.dashOpenChanged.connect(() => {
if (!NyshState.dashOpen) {
stack.clear();
stack.push(stack.initialItem);
}
})
}
Component {
id: main
ColumnLayout {
Layout.fillHeight: true
Layout.fillWidth: true
Layout.preferredHeight: 1000
spacing: 10
width: parent.width
Component.onCompleted: () => {}
height: parent.height
Layout.margins: 15
Layout.alignment: Qt.AlignBottom
model: Notifications.list
NotificationInbox {
Layout.fillHeight: true
Layout.fillWidth: true
}
delegate: NotificationToast {
id: toast
WeatherMedium {
Layout.fillWidth: true
height: 100
}
required property var modelData
required property int index
GridLayout {
notif: modelData
width: ListView.view.width
rows: 2
columns: 2
onClose: {
toast.notif.dismiss();
Text {
text: "brightness"
}
Slider {
id: b
from: 0
to: 100
stepSize: 1
value: Brightness.value
onMoved: Brightness.value = value
}
BButton {
text: "Internet"
onClicked: stack.push(internet)
Layout.fillHeight: true
Layout.fillWidth: true
height: 30
}
BButton {
text: "Bluetooth"
Layout.fillHeight: true
Layout.fillWidth: true
height: 30
}
}
MprisSmall {}
}
}
MprisSmall {}
Component {
id: internet
BigWifiView {
onNavigationReturn: stack.pop()
}
}
}
}

View file

@ -62,22 +62,12 @@ PanelWindow {
}
}
MouseArea {
BButton {
id: mouse
onClicked: NyshState.toggleDash()
height: width
width: 30
anchors.bottom: parent.bottom
cursorShape: Qt.PointingHandCursor
BRectangle {
anchors.fill: parent
Rectangle {
visible: mouse.containsMouse
anchors.fill: parent
radius: parent.radius
color: "#9F9F9FC8"
}
}
}
}
}

44
src/base/BButton.qml Normal file
View file

@ -0,0 +1,44 @@
import QtQuick
import "../provider"
MouseArea {
id: mouse
property string text: ""
cursorShape: Qt.PointingHandCursor
onClicked: {
click.color = "red";
b.start();
}
hoverEnabled: true
BRectangle {
id: click
anchors.fill: parent
color: Qt.darker(Config.colourMain, 1.1)
ColorAnimation on color {
id: b
to: Qt.darker(Config.colourMain, 1.1)
duration: 300
}
Rectangle {
id: hover
visible: mouse.containsMouse
anchors.fill: parent
radius: parent.radius
color: "#9F9F9FC8"
}
Text {
visible: mouse.text?.length > 0
text: mouse.text
anchors.centerIn: parent
}
}
}

View file

@ -4,8 +4,8 @@ import "../provider"
Rectangle {
width: parent.width
height: width
border.color: "black"
border.color: Qt.darker(Config.colourMain, 1.15)
border.width: 1
radius: 5
color: Config.colours.main
color: Config.colourMain
}

View file

@ -0,0 +1,42 @@
pragma Singleton
import Quickshell
import Quickshell.Io
Singleton {
id: brightness
property int value: -1
property bool first: true
function refresh() {
get.running = true;
}
onValueChanged: () => {
if (value >= 0) {
set.value = brightness.value;
set.running = true;
}
}
Process {
id: get
command: ["brightnessctl", "i", "-m"]
running: true
stdout: SplitParser {
onRead: rawData => {
const value = Number(rawData.split(",")[3]?.replace("%", "") ?? "");
if (!Number.isNaN(value)) {
brightness.value = value;
}
}
}
}
Process {
id: set
property int value
command: ["brightnessctl", "s", `${set.value}%`]
}
}

View file

@ -16,7 +16,5 @@ Singleton {
property int alignment: Config.BarAlignment.Left
property Item colours: Item {
property color main: "#BD93F9"
}
property color colourMain: "#BD93F9"
}

51
src/provider/Weather.qml Normal file
View file

@ -0,0 +1,51 @@
pragma Singleton
import Quickshell
import Quickshell.Io
import QtQuick
Singleton {
id: weather
property var lastFetch: {}
property string dataRaw: ""
property int feltTemp: lastFetch?.current_condition[0]?.FeelsLikeC ?? 0
property int actualTemp: lastFetch?.current_condition[0]?.temp_C ?? 0
property string description: lastFetch?.current_condition[0]?.weatherDesc[0].value ?? ""
property string icon: getIcon(lastFetch?.current_condition[0]?.weatherCode)
function getIcon(weatherCode: string): string {
switch (weatherCode) {
case "116":
return "weather-few-clouds";
default:
return "weather-none-available";
}
}
Process {
id: get
command: ["curl", "wttr.in?format=j1"]
running: true
stdout: SplitParser {
onRead: e => {
weather.dataRaw += e;
}
}
onRunningChanged: {
if (running) {
weather.dataRaw = "";
}
if (!running) {
weather.lastFetch = JSON.parse(weather.dataRaw);
}
}
}
Timer {
interval: 1000 * 60 * 60
repeat: true
onTriggered: get.running = true
}
}

View file

@ -5,3 +5,5 @@ singleton Player 0.1 Player.qml
singleton Inhibitor 0.1 Inhibitor.qml
singleton Notifications 0.1 Notifications.qml
singleton Time 0.1 Time.qml
singleton Brightness 0.1 Brightness.qml
singleton Weather 0.1 Weather.qml

View file

@ -0,0 +1,29 @@
import QtQuick
import QtQuick.Layouts
import "../../provider"
ListView {
id: popupcol
Layout.fillHeight: true
Layout.fillWidth: true
Layout.preferredHeight: 1000
spacing: 10
width: parent.width
Component.onCompleted: () => {}
model: Notifications.list
delegate: NotificationToast {
id: toast
required property var modelData
required property int index
notif: modelData
width: ListView.view.width
onClose: {
toast.notif.dismiss();
}
}
}

View file

@ -0,0 +1,44 @@
import QtQuick.Layouts
import QtQuick
import Quickshell.Widgets
import Quickshell
import "../../provider"
import "../../base"
BRectangle {
id: weather
property var area: Weather.lastFetch?.nearest_area[0]
property var condition: Weather.lastFetch?.current_condition[0]
RowLayout {
anchors.leftMargin: 10
anchors.fill: parent
IconImage {
source: Quickshell.iconPath(Weather.icon)
Layout.preferredWidth: parent.height - 20
Layout.preferredHeight: parent.height - 20
}
Column {
Layout.alignment: Qt.AlignLeft
Text {
text: `${weather.area?.areaName[0]?.value}, ${weather.area?.country[0]?.value}`
}
Text {
text: `${Weather.actualTemp}${Weather.actualTemp != Weather.feltTemp ? `(${Weather.feltTemp})` : ""}°C`
}
Text {
text: Weather.description
}
}
Item {
Layout.fillWidth: true
height: 1
}
}
}

View file

@ -0,0 +1,152 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell.Io
import "../../base"
ColumnLayout {
id: wifi
Layout.fillHeight: true
Layout.fillWidth: true
Layout.margins: 15
property ListModel networks: ListModel {}
signal navigationReturn
BRectangle {
width: 100
height: 100
visible: getter.running
Layout.alignment: Qt.AlignCenter
}
ListView {
id: re
model: wifi.networks
Layout.fillHeight: true
Layout.fillWidth: true
height: 500
spacing: 10
delegate: BRectangle {
id: con
required property string ssid
required property string bssid
required property bool connected
required property string rate
required property string bars
required property int index
height: 40
width: ListView.view.width
RowLayout {
anchors.fill: parent
anchors.margins: 7.5
Text {
text: con.ssid?.length ? con.ssid : con.bssid
Layout.preferredWidth: parent.width * 0.2
}
Text {
text: con.rate
Layout.preferredWidth: parent.width * 0.1
}
Text {
text: con.bars
width: 30
Layout.preferredWidth: 30
Layout.maximumWidth: 30
}
Rectangle {
width: height
height: parent.height - (con.Layout.margins * 2)
Layout.preferredWidth: 30
Layout.maximumWidth: 30
color: {
const v = con.bssid.split(":").map(n => Number.parseInt(n, 16));
const value = v.reduce((acc, v) => {
acc[acc.length - 1]?.length < 2 ? acc[acc.length - 1].push(v) : acc.push([v]);
return acc;
}, [])//
.map(([a, b]) => Math.floor(((a + b) / 2)).toString(16)) //
.join("");
return `#${value}`;
}
Layout.alignment: Qt.AlignRight
}
BButton {
text: con.connected ? "disconnect" : "connect"
Layout.alignment: Qt.AlignRight
Layout.preferredWidth: implicitWidth
Layout.maximumWidth: parent.width * 0.2
Layout.minimumWidth: parent.width * 0.2
Layout.fillHeight: true
height: 30
width: 30
}
}
}
}
RowLayout {
Layout.fillWidth: true
BButton {
text: "return"
onClicked: wifi.navigationReturn()
Layout.alignment: Qt.AlignBottom
Layout.fillWidth: true
width: 30
height: 30
}
BButton {
text: "refresh"
onClicked: getter.running = true
Layout.alignment: Qt.AlignBottom | Qt.AlignRight
Layout.fillWidth: true
width: 30
height: 30
}
}
Process {
id: getter
command: ["nmcli", "-t", "device", "wifi"]
running: true
stdout: SplitParser {
onRead: rawData => {
rawData = rawData.replace(/\\:/g, ":").split(":");
const data = {
connected: rawData[0] === "*",
bssid: rawData.slice(1, 7).join(":").replace(),
ssid: rawData[7],
mode: rawData[8],
channel: rawData[9],
rate: rawData[10],
signal: rawData[11],
bars: rawData[12],
security: rawData[13]
};
for (let i = 0; i < networks.count; i++) {
if (networks.get(i).bssid === data.bssid) {
Object.entries(data).map(([key, value]) => {
networks.setProperty(i, key, value);
});
return;
}
}
networks.append(data);
}
}
}
}