feat: add current weather widget, and wifi info
This commit is contained in:
parent
a57cc7c1d2
commit
00aa8eaea2
11 changed files with 435 additions and 34 deletions
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
44
src/base/BButton.qml
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
42
src/provider/Brightness.qml
Normal file
42
src/provider/Brightness.qml
Normal 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}%`]
|
||||
}
|
||||
}
|
|
@ -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
51
src/provider/Weather.qml
Normal 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
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
29
src/widgets/notifications/NotificationInbox.qml
Normal file
29
src/widgets/notifications/NotificationInbox.qml
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
44
src/widgets/weather/WeatherMedium.qml
Normal file
44
src/widgets/weather/WeatherMedium.qml
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
152
src/widgets/wifi/BigWifiView.qml
Normal file
152
src/widgets/wifi/BigWifiView.qml
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue