formatter
This commit is contained in:
+54
-50
@@ -8,49 +8,49 @@ import ZShell
|
||||
import qs.Components
|
||||
|
||||
Scope {
|
||||
LazyLoader {
|
||||
id: root
|
||||
LazyLoader {
|
||||
id: root
|
||||
|
||||
property bool freeze
|
||||
property bool closing
|
||||
property bool closing
|
||||
property bool freeze
|
||||
|
||||
Variants {
|
||||
model: Quickshell.screens
|
||||
PanelWindow {
|
||||
id: win
|
||||
color: "transparent"
|
||||
Variants {
|
||||
model: Quickshell.screens
|
||||
|
||||
required property ShellScreen modelData
|
||||
PanelWindow {
|
||||
id: win
|
||||
|
||||
screen: modelData
|
||||
WlrLayershell.namespace: "areapicker"
|
||||
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
||||
WlrLayershell.layer: WlrLayer.Overlay
|
||||
WlrLayershell.keyboardFocus: root.closing ? WlrKeyboardFocus.None : WlrKeyboardFocus.Exclusive
|
||||
mask: root.closing ? empty : null
|
||||
required property ShellScreen modelData
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
bottom: true
|
||||
left: true
|
||||
right: true
|
||||
}
|
||||
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
||||
WlrLayershell.keyboardFocus: root.closing ? WlrKeyboardFocus.None : WlrKeyboardFocus.Exclusive
|
||||
WlrLayershell.layer: WlrLayer.Overlay
|
||||
WlrLayershell.namespace: "areapicker"
|
||||
color: "transparent"
|
||||
mask: root.closing ? empty : null
|
||||
screen: modelData
|
||||
|
||||
Region {
|
||||
id: empty
|
||||
}
|
||||
anchors {
|
||||
bottom: true
|
||||
left: true
|
||||
right: true
|
||||
top: true
|
||||
}
|
||||
|
||||
Picker {
|
||||
loader: root
|
||||
screen: win.modelData
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Region {
|
||||
id: empty
|
||||
|
||||
}
|
||||
|
||||
Picker {
|
||||
loader: root
|
||||
screen: win.modelData
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
target: "picker"
|
||||
|
||||
function open(): void {
|
||||
root.freeze = false;
|
||||
root.closing = false;
|
||||
@@ -62,23 +62,27 @@ Scope {
|
||||
root.closing = false;
|
||||
root.activeAsync = true;
|
||||
}
|
||||
|
||||
target: "picker"
|
||||
}
|
||||
|
||||
CustomShortcut {
|
||||
name: "screenshot"
|
||||
onPressed: {
|
||||
root.freeze = false;
|
||||
root.closing = false;
|
||||
root.activeAsync = true;
|
||||
}
|
||||
}
|
||||
CustomShortcut {
|
||||
name: "screenshot"
|
||||
|
||||
CustomShortcut {
|
||||
name: "screenshotFreeze"
|
||||
onPressed: {
|
||||
root.freeze = true;
|
||||
root.closing = false;
|
||||
root.activeAsync = true;
|
||||
}
|
||||
}
|
||||
onPressed: {
|
||||
root.freeze = false;
|
||||
root.closing = false;
|
||||
root.activeAsync = true;
|
||||
}
|
||||
}
|
||||
|
||||
CustomShortcut {
|
||||
name: "screenshotFreeze"
|
||||
|
||||
onPressed: {
|
||||
root.freeze = true;
|
||||
root.closing = false;
|
||||
root.activeAsync = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+180
-176
@@ -8,219 +8,223 @@ import qs.Config
|
||||
import qs.Components
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
property list<var> ddcMonitors: []
|
||||
readonly property list<Monitor> monitors: variants.instances
|
||||
property bool appleDisplayPresent: false
|
||||
property bool appleDisplayPresent: false
|
||||
property list<var> ddcMonitors: []
|
||||
readonly property list<Monitor> monitors: variants.instances
|
||||
|
||||
function getMonitorForScreen(screen: ShellScreen): var {
|
||||
return monitors.find(m => m.modelData === screen);
|
||||
}
|
||||
function decreaseBrightness(): void {
|
||||
const monitor = getMonitor("active");
|
||||
if (monitor)
|
||||
monitor.setBrightness(monitor.brightness - Config.services.brightnessIncrement);
|
||||
}
|
||||
|
||||
function getMonitor(query: string): var {
|
||||
if (query === "active") {
|
||||
return monitors.find(m => Hypr.monitorFor(m.modelData)?.focused);
|
||||
}
|
||||
function getMonitor(query: string): var {
|
||||
if (query === "active") {
|
||||
return monitors.find(m => Hypr.monitorFor(m.modelData)?.focused);
|
||||
}
|
||||
|
||||
if (query.startsWith("model:")) {
|
||||
const model = query.slice(6);
|
||||
return monitors.find(m => m.modelData.model === model);
|
||||
}
|
||||
if (query.startsWith("model:")) {
|
||||
const model = query.slice(6);
|
||||
return monitors.find(m => m.modelData.model === model);
|
||||
}
|
||||
|
||||
if (query.startsWith("serial:")) {
|
||||
const serial = query.slice(7);
|
||||
return monitors.find(m => m.modelData.serialNumber === serial);
|
||||
}
|
||||
if (query.startsWith("serial:")) {
|
||||
const serial = query.slice(7);
|
||||
return monitors.find(m => m.modelData.serialNumber === serial);
|
||||
}
|
||||
|
||||
if (query.startsWith("id:")) {
|
||||
const id = parseInt(query.slice(3), 10);
|
||||
return monitors.find(m => Hypr.monitorFor(m.modelData)?.id === id);
|
||||
}
|
||||
if (query.startsWith("id:")) {
|
||||
const id = parseInt(query.slice(3), 10);
|
||||
return monitors.find(m => Hypr.monitorFor(m.modelData)?.id === id);
|
||||
}
|
||||
|
||||
return monitors.find(m => m.modelData.name === query);
|
||||
}
|
||||
return monitors.find(m => m.modelData.name === query);
|
||||
}
|
||||
|
||||
function increaseBrightness(): void {
|
||||
const monitor = getMonitor("active");
|
||||
if (monitor)
|
||||
monitor.setBrightness(monitor.brightness + Config.services.brightnessIncrement);
|
||||
}
|
||||
function getMonitorForScreen(screen: ShellScreen): var {
|
||||
return monitors.find(m => m.modelData === screen);
|
||||
}
|
||||
|
||||
function decreaseBrightness(): void {
|
||||
const monitor = getMonitor("active");
|
||||
if (monitor)
|
||||
monitor.setBrightness(monitor.brightness - Config.services.brightnessIncrement);
|
||||
}
|
||||
function increaseBrightness(): void {
|
||||
const monitor = getMonitor("active");
|
||||
if (monitor)
|
||||
monitor.setBrightness(monitor.brightness + Config.services.brightnessIncrement);
|
||||
}
|
||||
|
||||
onMonitorsChanged: {
|
||||
ddcMonitors = [];
|
||||
ddcProc.running = true;
|
||||
}
|
||||
onMonitorsChanged: {
|
||||
ddcMonitors = [];
|
||||
ddcProc.running = true;
|
||||
}
|
||||
|
||||
Variants {
|
||||
id: variants
|
||||
Variants {
|
||||
id: variants
|
||||
|
||||
model: Quickshell.screens
|
||||
model: Quickshell.screens
|
||||
|
||||
Monitor {}
|
||||
}
|
||||
Monitor {
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
running: true
|
||||
command: ["sh", "-c", "asdbctl get"] // To avoid warnings if asdbctl is not installed
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: root.appleDisplayPresent = text.trim().length > 0
|
||||
}
|
||||
}
|
||||
Process {
|
||||
command: ["sh", "-c", "asdbctl get"] // To avoid warnings if asdbctl is not installed
|
||||
running: true
|
||||
|
||||
Process {
|
||||
id: ddcProc
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: root.appleDisplayPresent = text.trim().length > 0
|
||||
}
|
||||
}
|
||||
|
||||
command: ["ddcutil", "detect", "--brief"]
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: root.ddcMonitors = text.trim().split("\n\n").filter(d => d.startsWith("Display ")).map(d => ({
|
||||
busNum: d.match(/I2C bus:[ ]*\/dev\/i2c-([0-9]+)/)[1],
|
||||
connector: d.match(/DRM connector:\s+(.*)/)[1].replace(/^card\d+-/, "") // strip "card1-"
|
||||
}))
|
||||
}
|
||||
}
|
||||
Process {
|
||||
id: ddcProc
|
||||
|
||||
CustomShortcut {
|
||||
name: "brightnessUp"
|
||||
description: "Increase brightness"
|
||||
onPressed: root.increaseBrightness()
|
||||
}
|
||||
command: ["ddcutil", "detect", "--brief"]
|
||||
|
||||
CustomShortcut {
|
||||
name: "brightnessDown"
|
||||
description: "Decrease brightness"
|
||||
onPressed: root.decreaseBrightness()
|
||||
}
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: root.ddcMonitors = text.trim().split("\n\n").filter(d => d.startsWith("Display ")).map(d => ({
|
||||
busNum: d.match(/I2C bus:[ ]*\/dev\/i2c-([0-9]+)/)[1],
|
||||
connector: d.match(/DRM connector:\s+(.*)/)[1].replace(/^card\d+-/, "") // strip "card1-"
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
target: "brightness"
|
||||
CustomShortcut {
|
||||
description: "Increase brightness"
|
||||
name: "brightnessUp"
|
||||
|
||||
function get(): real {
|
||||
return getFor("active");
|
||||
}
|
||||
onPressed: root.increaseBrightness()
|
||||
}
|
||||
|
||||
// Allows searching by active/model/serial/id/name
|
||||
function getFor(query: string): real {
|
||||
return root.getMonitor(query)?.brightness ?? -1;
|
||||
}
|
||||
CustomShortcut {
|
||||
description: "Decrease brightness"
|
||||
name: "brightnessDown"
|
||||
|
||||
function set(value: string): string {
|
||||
return setFor("active", value);
|
||||
}
|
||||
onPressed: root.decreaseBrightness()
|
||||
}
|
||||
|
||||
// Handles brightness value like brightnessctl: 0.1, +0.1, 0.1-, 10%, +10%, 10%-
|
||||
function setFor(query: string, value: string): string {
|
||||
const monitor = root.getMonitor(query);
|
||||
if (!monitor)
|
||||
return "Invalid monitor: " + query;
|
||||
IpcHandler {
|
||||
function get(): real {
|
||||
return getFor("active");
|
||||
}
|
||||
|
||||
let targetBrightness;
|
||||
if (value.endsWith("%-")) {
|
||||
const percent = parseFloat(value.slice(0, -2));
|
||||
targetBrightness = monitor.brightness - (percent / 100);
|
||||
} else if (value.startsWith("+") && value.endsWith("%")) {
|
||||
const percent = parseFloat(value.slice(1, -1));
|
||||
targetBrightness = monitor.brightness + (percent / 100);
|
||||
} else if (value.endsWith("%")) {
|
||||
const percent = parseFloat(value.slice(0, -1));
|
||||
targetBrightness = percent / 100;
|
||||
} else if (value.startsWith("+")) {
|
||||
const increment = parseFloat(value.slice(1));
|
||||
targetBrightness = monitor.brightness + increment;
|
||||
} else if (value.endsWith("-")) {
|
||||
const decrement = parseFloat(value.slice(0, -1));
|
||||
targetBrightness = monitor.brightness - decrement;
|
||||
} else if (value.includes("%") || value.includes("-") || value.includes("+")) {
|
||||
return `Invalid brightness format: ${value}\nExpected: 0.1, +0.1, 0.1-, 10%, +10%, 10%-`;
|
||||
} else {
|
||||
targetBrightness = parseFloat(value);
|
||||
}
|
||||
// Allows searching by active/model/serial/id/name
|
||||
function getFor(query: string): real {
|
||||
return root.getMonitor(query)?.brightness ?? -1;
|
||||
}
|
||||
|
||||
if (isNaN(targetBrightness))
|
||||
return `Failed to parse value: ${value}\nExpected: 0.1, +0.1, 0.1-, 10%, +10%, 10%-`;
|
||||
function set(value: string): string {
|
||||
return setFor("active", value);
|
||||
}
|
||||
|
||||
monitor.setBrightness(targetBrightness);
|
||||
// Handles brightness value like brightnessctl: 0.1, +0.1, 0.1-, 10%, +10%, 10%-
|
||||
function setFor(query: string, value: string): string {
|
||||
const monitor = root.getMonitor(query);
|
||||
if (!monitor)
|
||||
return "Invalid monitor: " + query;
|
||||
|
||||
return `Set monitor ${monitor.modelData.name} brightness to ${+monitor.brightness.toFixed(2)}`;
|
||||
}
|
||||
}
|
||||
let targetBrightness;
|
||||
if (value.endsWith("%-")) {
|
||||
const percent = parseFloat(value.slice(0, -2));
|
||||
targetBrightness = monitor.brightness - (percent / 100);
|
||||
} else if (value.startsWith("+") && value.endsWith("%")) {
|
||||
const percent = parseFloat(value.slice(1, -1));
|
||||
targetBrightness = monitor.brightness + (percent / 100);
|
||||
} else if (value.endsWith("%")) {
|
||||
const percent = parseFloat(value.slice(0, -1));
|
||||
targetBrightness = percent / 100;
|
||||
} else if (value.startsWith("+")) {
|
||||
const increment = parseFloat(value.slice(1));
|
||||
targetBrightness = monitor.brightness + increment;
|
||||
} else if (value.endsWith("-")) {
|
||||
const decrement = parseFloat(value.slice(0, -1));
|
||||
targetBrightness = monitor.brightness - decrement;
|
||||
} else if (value.includes("%") || value.includes("-") || value.includes("+")) {
|
||||
return `Invalid brightness format: ${value}\nExpected: 0.1, +0.1, 0.1-, 10%, +10%, 10%-`;
|
||||
} else {
|
||||
targetBrightness = parseFloat(value);
|
||||
}
|
||||
|
||||
component Monitor: QtObject {
|
||||
id: monitor
|
||||
if (isNaN(targetBrightness))
|
||||
return `Failed to parse value: ${value}\nExpected: 0.1, +0.1, 0.1-, 10%, +10%, 10%-`;
|
||||
|
||||
required property ShellScreen modelData
|
||||
readonly property bool isDdc: root.ddcMonitors.some(m => m.connector === modelData.name)
|
||||
readonly property string busNum: root.ddcMonitors.find(m => m.connector === modelData.name)?.busNum ?? ""
|
||||
readonly property bool isAppleDisplay: root.appleDisplayPresent && modelData.model.startsWith("StudioDisplay")
|
||||
property real brightness
|
||||
property real queuedBrightness: NaN
|
||||
monitor.setBrightness(targetBrightness);
|
||||
|
||||
readonly property Process initProc: Process {
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
if (monitor.isAppleDisplay) {
|
||||
const val = parseInt(text.trim());
|
||||
monitor.brightness = val / 101;
|
||||
} else {
|
||||
const [, , , cur, max] = text.split(" ");
|
||||
monitor.brightness = parseInt(cur) / parseInt(max);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return `Set monitor ${monitor.modelData.name} brightness to ${+monitor.brightness.toFixed(2)}`;
|
||||
}
|
||||
|
||||
readonly property Timer timer: Timer {
|
||||
interval: 500
|
||||
onTriggered: {
|
||||
if (!isNaN(monitor.queuedBrightness)) {
|
||||
monitor.setBrightness(monitor.queuedBrightness);
|
||||
monitor.queuedBrightness = NaN;
|
||||
}
|
||||
}
|
||||
}
|
||||
target: "brightness"
|
||||
}
|
||||
|
||||
function setBrightness(value: real): void {
|
||||
value = Math.max(0, Math.min(1, value));
|
||||
const rounded = Math.round(value * 100);
|
||||
if (Math.round(brightness * 100) === rounded)
|
||||
return;
|
||||
component Monitor: QtObject {
|
||||
id: monitor
|
||||
|
||||
if (isDdc && timer.running) {
|
||||
queuedBrightness = value;
|
||||
return;
|
||||
}
|
||||
property real brightness
|
||||
readonly property string busNum: root.ddcMonitors.find(m => m.connector === modelData.name)?.busNum ?? ""
|
||||
readonly property Process initProc: Process {
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
if (monitor.isAppleDisplay) {
|
||||
const val = parseInt(text.trim());
|
||||
monitor.brightness = val / 101;
|
||||
} else {
|
||||
const [, , , cur, max] = text.split(" ");
|
||||
monitor.brightness = parseInt(cur) / parseInt(max);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
readonly property bool isAppleDisplay: root.appleDisplayPresent && modelData.model.startsWith("StudioDisplay")
|
||||
readonly property bool isDdc: root.ddcMonitors.some(m => m.connector === modelData.name)
|
||||
required property ShellScreen modelData
|
||||
property real queuedBrightness: NaN
|
||||
readonly property Timer timer: Timer {
|
||||
interval: 500
|
||||
|
||||
brightness = value;
|
||||
onTriggered: {
|
||||
if (!isNaN(monitor.queuedBrightness)) {
|
||||
monitor.setBrightness(monitor.queuedBrightness);
|
||||
monitor.queuedBrightness = NaN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isAppleDisplay)
|
||||
Quickshell.execDetached(["asdbctl", "set", rounded]);
|
||||
else if (isDdc)
|
||||
Quickshell.execDetached(["ddcutil", "--disable-dynamic-sleep", "--sleep-multiplier", ".1", "--skip-ddc-checks", "-b", busNum, "setvcp", "10", rounded]);
|
||||
else
|
||||
Quickshell.execDetached(["brightnessctl", "s", `${rounded}%`]);
|
||||
function initBrightness(): void {
|
||||
if (isAppleDisplay)
|
||||
initProc.command = ["asdbctl", "get"];
|
||||
else if (isDdc)
|
||||
initProc.command = ["ddcutil", "-b", busNum, "getvcp", "10", "--brief"];
|
||||
else
|
||||
initProc.command = ["sh", "-c", "echo a b c $(brightnessctl g) $(brightnessctl m)"];
|
||||
|
||||
if (isDdc)
|
||||
timer.restart();
|
||||
}
|
||||
initProc.running = true;
|
||||
}
|
||||
|
||||
function initBrightness(): void {
|
||||
if (isAppleDisplay)
|
||||
initProc.command = ["asdbctl", "get"];
|
||||
else if (isDdc)
|
||||
initProc.command = ["ddcutil", "-b", busNum, "getvcp", "10", "--brief"];
|
||||
else
|
||||
initProc.command = ["sh", "-c", "echo a b c $(brightnessctl g) $(brightnessctl m)"];
|
||||
function setBrightness(value: real): void {
|
||||
value = Math.max(0, Math.min(1, value));
|
||||
const rounded = Math.round(value * 100);
|
||||
if (Math.round(brightness * 100) === rounded)
|
||||
return;
|
||||
|
||||
initProc.running = true;
|
||||
}
|
||||
if (isDdc && timer.running) {
|
||||
queuedBrightness = value;
|
||||
return;
|
||||
}
|
||||
|
||||
onBusNumChanged: initBrightness()
|
||||
Component.onCompleted: initBrightness()
|
||||
}
|
||||
brightness = value;
|
||||
|
||||
if (isAppleDisplay)
|
||||
Quickshell.execDetached(["asdbctl", "set", rounded]);
|
||||
else if (isDdc)
|
||||
Quickshell.execDetached(["ddcutil", "--disable-dynamic-sleep", "--sleep-multiplier", ".1", "--skip-ddc-checks", "-b", busNum, "setvcp", "10", rounded]);
|
||||
else
|
||||
Quickshell.execDetached(["brightnessctl", "s", `${rounded}%`]);
|
||||
|
||||
if (isDdc)
|
||||
timer.restart();
|
||||
}
|
||||
|
||||
Component.onCompleted: initBrightness()
|
||||
onBusNumChanged: initBrightness()
|
||||
}
|
||||
}
|
||||
|
||||
+15
-15
@@ -4,25 +4,25 @@ import QtQuick
|
||||
import qs.Paths
|
||||
|
||||
Image {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
property alias path: manager.path
|
||||
property alias path: manager.path
|
||||
|
||||
asynchronous: true
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
asynchronous: true
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
|
||||
Connections {
|
||||
target: QsWindow.window
|
||||
Connections {
|
||||
function onDevicePixelRatioChanged(): void {
|
||||
manager.updateSource();
|
||||
}
|
||||
|
||||
function onDevicePixelRatioChanged(): void {
|
||||
manager.updateSource();
|
||||
}
|
||||
}
|
||||
target: QsWindow.window
|
||||
}
|
||||
|
||||
CachingImageManager {
|
||||
id: manager
|
||||
CachingImageManager {
|
||||
id: manager
|
||||
|
||||
item: root
|
||||
cacheDir: Qt.resolvedUrl(Paths.imagecache)
|
||||
}
|
||||
cacheDir: Qt.resolvedUrl(Paths.imagecache)
|
||||
item: root
|
||||
}
|
||||
}
|
||||
|
||||
+48
-50
@@ -10,6 +10,53 @@ Singleton {
|
||||
property int displayYear: new Date().getFullYear()
|
||||
readonly property int weekStartDay: 1 // 0 = Sunday, 1 = Monday
|
||||
|
||||
function getISOWeekNumber(date: var): int {
|
||||
const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
|
||||
const dayNum = d.getUTCDay() || 7;
|
||||
d.setUTCDate(d.getUTCDate() + 4 - dayNum);
|
||||
const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
|
||||
return Math.ceil((((d - yearStart) / 86400000) + 1) / 7);
|
||||
}
|
||||
|
||||
function getWeekNumbers(month: int, year: int): var {
|
||||
const days = getWeeksForMonth(month, year);
|
||||
const weekNumbers = [];
|
||||
let lastWeekNumber = -1;
|
||||
|
||||
for (let i = 0; i < days.length; i++) {
|
||||
// Only add week numbers for days that belong to the current month
|
||||
if (days[i].isCurrentMonth) {
|
||||
const dayDate = new Date(days[i].year, days[i].month, days[i].day);
|
||||
const weekNumber = getISOWeekNumber(dayDate);
|
||||
|
||||
// Only push if this is a new week
|
||||
if (weekNumber !== lastWeekNumber) {
|
||||
weekNumbers.push(weekNumber);
|
||||
lastWeekNumber = weekNumber;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return weekNumbers;
|
||||
}
|
||||
|
||||
function getWeekStartIndex(month: int, year: int): int {
|
||||
const today = new Date();
|
||||
if (today.getMonth() !== month || today.getFullYear() !== year) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const days = getWeeksForMonth(month, year);
|
||||
for (let i = 0; i < days.length; i++) {
|
||||
if (days[i].isToday) {
|
||||
// Return the start index of the week containing today
|
||||
return Math.floor(i / 7) * 7;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
function getWeeksForMonth(month: int, year: int): var {
|
||||
const firstDayOfMonth = new Date(year, month, 1);
|
||||
const lastDayOfMonth = new Date(year, month + 1, 0);
|
||||
@@ -43,57 +90,8 @@ Singleton {
|
||||
return days;
|
||||
}
|
||||
|
||||
function getWeekNumbers(month: int, year: int): var {
|
||||
const days = getWeeksForMonth(month, year);
|
||||
const weekNumbers = [];
|
||||
let lastWeekNumber = -1;
|
||||
|
||||
for (let i = 0; i < days.length; i++) {
|
||||
// Only add week numbers for days that belong to the current month
|
||||
if (days[i].isCurrentMonth) {
|
||||
const dayDate = new Date(days[i].year, days[i].month, days[i].day);
|
||||
const weekNumber = getISOWeekNumber(dayDate);
|
||||
|
||||
// Only push if this is a new week
|
||||
if (weekNumber !== lastWeekNumber) {
|
||||
weekNumbers.push(weekNumber);
|
||||
lastWeekNumber = weekNumber;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return weekNumbers;
|
||||
}
|
||||
|
||||
function getISOWeekNumber(date: var): int {
|
||||
const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
|
||||
const dayNum = d.getUTCDay() || 7;
|
||||
d.setUTCDate(d.getUTCDate() + 4 - dayNum);
|
||||
const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
|
||||
return Math.ceil((((d - yearStart) / 86400000) + 1) / 7);
|
||||
}
|
||||
|
||||
function isDateToday(date: var): bool {
|
||||
const today = new Date();
|
||||
return date.getDate() === today.getDate() &&
|
||||
date.getMonth() === today.getMonth() &&
|
||||
date.getFullYear() === today.getFullYear();
|
||||
}
|
||||
|
||||
function getWeekStartIndex(month: int, year: int): int {
|
||||
const today = new Date();
|
||||
if (today.getMonth() !== month || today.getFullYear() !== year) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const days = getWeeksForMonth(month, year);
|
||||
for (let i = 0; i < days.length; i++) {
|
||||
if (days[i].isToday) {
|
||||
// Return the start index of the week containing today
|
||||
return Math.floor(i / 7) * 7;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return date.getDate() === today.getDate() && date.getMonth() === today.getMonth() && date.getFullYear() === today.getFullYear();
|
||||
}
|
||||
}
|
||||
|
||||
+10
-10
@@ -3,15 +3,15 @@ pragma Singleton
|
||||
import Quickshell
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
function getTrayIcon(id: string, icon: string): string {
|
||||
if (icon.includes("?path=")) {
|
||||
const [name, path] = icon.split("?path=");
|
||||
icon = Qt.resolvedUrl(`${path}/${name.slice(name.lastIndexOf("/") + 1)}`);
|
||||
} else if (icon.includes("qspixmap") && id === "chrome_status_icon_1") {
|
||||
icon = icon.replace("qspixmap", "icon/discord-tray");
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
function getTrayIcon(id: string, icon: string): string {
|
||||
if (icon.includes("?path=")) {
|
||||
const [name, path] = icon.split("?path=");
|
||||
icon = Qt.resolvedUrl(`${path}/${name.slice(name.lastIndexOf("/") + 1)}`);
|
||||
} else if (icon.includes("qspixmap") && id === "chrome_status_icon_1") {
|
||||
icon = icon.replace("qspixmap", "icon/discord-tray");
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,12 +4,13 @@ import Quickshell
|
||||
import Quickshell.Io
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
property alias hasNotifications: adapter.hasNotifications
|
||||
property alias hasNotifications: adapter.hasNotifications
|
||||
|
||||
JsonObject {
|
||||
id: adapter
|
||||
property bool hasNotifications: false
|
||||
}
|
||||
JsonObject {
|
||||
id: adapter
|
||||
|
||||
property bool hasNotifications: false
|
||||
}
|
||||
}
|
||||
|
||||
+127
-129
@@ -9,157 +9,155 @@ import QtQuick
|
||||
import qs.Components
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
readonly property var toplevels: Hyprland.toplevels
|
||||
readonly property var workspaces: Hyprland.workspaces
|
||||
readonly property var monitors: Hyprland.monitors
|
||||
property string activeName
|
||||
readonly property HyprlandToplevel activeToplevel: Hyprland.activeToplevel
|
||||
readonly property int activeWsId: focusedWorkspace?.id ?? 1
|
||||
property string applicationDir: "/usr/share/applications/"
|
||||
readonly property bool capsLock: keyboard?.capsLock ?? false
|
||||
readonly property string defaultKbLayout: keyboard?.layout.split(",")[0] ?? "??"
|
||||
property string desktopName: ""
|
||||
readonly property alias devices: extras.devices
|
||||
readonly property alias extras: extras
|
||||
readonly property HyprlandMonitor focusedMonitor: Hyprland.focusedMonitor
|
||||
readonly property HyprlandWorkspace focusedWorkspace: Hyprland.focusedWorkspace
|
||||
property bool hadKeyboard
|
||||
readonly property string kbLayout: kbMap.get(kbLayoutFull) ?? "??"
|
||||
readonly property string kbLayoutFull: keyboard?.activeKeymap ?? "Unknown"
|
||||
readonly property var kbMap: new Map()
|
||||
readonly property HyprKeyboard keyboard: extras.devices.keyboards.find(kb => kb.main) ?? null
|
||||
readonly property var monitors: Hyprland.monitors
|
||||
readonly property bool numLock: keyboard?.numLock ?? false
|
||||
readonly property alias options: extras.options
|
||||
readonly property var toplevels: Hyprland.toplevels
|
||||
readonly property var workspaces: Hyprland.workspaces
|
||||
|
||||
readonly property HyprlandToplevel activeToplevel: Hyprland.activeToplevel
|
||||
readonly property HyprlandWorkspace focusedWorkspace: Hyprland.focusedWorkspace
|
||||
readonly property HyprlandMonitor focusedMonitor: Hyprland.focusedMonitor
|
||||
readonly property int activeWsId: focusedWorkspace?.id ?? 1
|
||||
signal configReloaded
|
||||
|
||||
property string activeName
|
||||
property string applicationDir: "/usr/share/applications/"
|
||||
property string desktopName: ""
|
||||
|
||||
readonly property HyprKeyboard keyboard: extras.devices.keyboards.find(kb => kb.main) ?? null
|
||||
readonly property bool capsLock: keyboard?.capsLock ?? false
|
||||
readonly property bool numLock: keyboard?.numLock ?? false
|
||||
readonly property string defaultKbLayout: keyboard?.layout.split(",")[0] ?? "??"
|
||||
readonly property string kbLayoutFull: keyboard?.activeKeymap ?? "Unknown"
|
||||
readonly property string kbLayout: kbMap.get(kbLayoutFull) ?? "??"
|
||||
readonly property var kbMap: new Map()
|
||||
|
||||
readonly property alias extras: extras
|
||||
readonly property alias options: extras.options
|
||||
readonly property alias devices: extras.devices
|
||||
|
||||
property bool hadKeyboard
|
||||
|
||||
signal configReloaded
|
||||
|
||||
function getActiveScreen(): ShellScreen {
|
||||
return Quickshell.screens.find(screen => root.monitorFor(screen) === root.focusedMonitor)
|
||||
function dispatch(request: string): void {
|
||||
Hyprland.dispatch(request);
|
||||
}
|
||||
|
||||
function dispatch(request: string): void {
|
||||
Hyprland.dispatch(request);
|
||||
}
|
||||
function getActiveScreen(): ShellScreen {
|
||||
return Quickshell.screens.find(screen => root.monitorFor(screen) === root.focusedMonitor);
|
||||
}
|
||||
|
||||
function monitorFor(screen: ShellScreen): HyprlandMonitor {
|
||||
return Hyprland.monitorFor(screen);
|
||||
}
|
||||
function monitorFor(screen: ShellScreen): HyprlandMonitor {
|
||||
return Hyprland.monitorFor(screen);
|
||||
}
|
||||
|
||||
function reloadDynamicConfs(): void {
|
||||
extras.batchMessage(["keyword bindlni ,Caps_Lock,global,zshell:refreshDevices", "keyword bindlni ,Num_Lock,global,zshell:refreshDevices"]);
|
||||
}
|
||||
function reloadDynamicConfs(): void {
|
||||
extras.batchMessage(["keyword bindlni ,Caps_Lock,global,zshell:refreshDevices", "keyword bindlni ,Num_Lock,global,zshell:refreshDevices"]);
|
||||
}
|
||||
|
||||
Component.onCompleted: reloadDynamicConfs()
|
||||
Component.onCompleted: reloadDynamicConfs()
|
||||
|
||||
// function updateActiveWindow(): void {
|
||||
// root.desktopName = root.applicationDir + root.activeToplevel?.lastIpcObject.class + ".desktop";
|
||||
// }
|
||||
// function updateActiveWindow(): void {
|
||||
// root.desktopName = root.applicationDir + root.activeToplevel?.lastIpcObject.class + ".desktop";
|
||||
// }
|
||||
|
||||
Connections {
|
||||
target: Hyprland
|
||||
Connections {
|
||||
function onRawEvent(event: HyprlandEvent): void {
|
||||
const n = event.name;
|
||||
if (n.endsWith("v2"))
|
||||
return;
|
||||
|
||||
function onRawEvent(event: HyprlandEvent): void {
|
||||
const n = event.name;
|
||||
if (n.endsWith("v2"))
|
||||
return;
|
||||
if (n === "configreloaded") {
|
||||
root.configReloaded();
|
||||
root.reloadDynamicConfs();
|
||||
} else if (["workspace", "moveworkspace", "activespecial", "focusedmon"].includes(n)) {
|
||||
Hyprland.refreshWorkspaces();
|
||||
Hyprland.refreshMonitors();
|
||||
// Qt.callLater( root.updateActiveWindow );
|
||||
} else if (["openwindow", "closewindow", "movewindow"].includes(n)) {
|
||||
Hyprland.refreshToplevels();
|
||||
Hyprland.refreshWorkspaces();
|
||||
// Qt.callLater( root.updateActiveWindow );
|
||||
} else if (n.includes("mon")) {
|
||||
Hyprland.refreshMonitors();
|
||||
// Qt.callLater( root.updateActiveWindow );
|
||||
} else if (n.includes("workspace")) {
|
||||
Hyprland.refreshWorkspaces();
|
||||
// Qt.callLater( root.updateActiveWindow );
|
||||
} else if (n.includes("window") || n.includes("group") || ["pin", "fullscreen", "changefloatingmode", "minimize"].includes(n)) {
|
||||
Hyprland.refreshToplevels();
|
||||
// Qt.callLater( root.updateActiveWindow );
|
||||
}
|
||||
}
|
||||
|
||||
if (n === "configreloaded") {
|
||||
root.configReloaded();
|
||||
root.reloadDynamicConfs();
|
||||
} else if (["workspace", "moveworkspace", "activespecial", "focusedmon"].includes(n)) {
|
||||
Hyprland.refreshWorkspaces();
|
||||
Hyprland.refreshMonitors();
|
||||
// Qt.callLater( root.updateActiveWindow );
|
||||
} else if (["openwindow", "closewindow", "movewindow"].includes(n)) {
|
||||
Hyprland.refreshToplevels();
|
||||
Hyprland.refreshWorkspaces();
|
||||
// Qt.callLater( root.updateActiveWindow );
|
||||
} else if (n.includes("mon")) {
|
||||
Hyprland.refreshMonitors();
|
||||
// Qt.callLater( root.updateActiveWindow );
|
||||
} else if (n.includes("workspace")) {
|
||||
Hyprland.refreshWorkspaces();
|
||||
// Qt.callLater( root.updateActiveWindow );
|
||||
} else if (n.includes("window") || n.includes("group") || ["pin", "fullscreen", "changefloatingmode", "minimize"].includes(n)) {
|
||||
Hyprland.refreshToplevels();
|
||||
// Qt.callLater( root.updateActiveWindow );
|
||||
}
|
||||
}
|
||||
}
|
||||
target: Hyprland
|
||||
}
|
||||
|
||||
FileView {
|
||||
id: desktopEntryName
|
||||
FileView {
|
||||
id: desktopEntryName
|
||||
|
||||
path: root.desktopName
|
||||
path: root.desktopName
|
||||
|
||||
onLoaded: {
|
||||
const lines = text().split( "\n" );
|
||||
for ( const line of lines ) {
|
||||
if ( line.startsWith( "Name=" )) {
|
||||
let name = line.replace( "Name=", "" );
|
||||
let caseFix = name[ 0 ].toUpperCase() + name.slice( 1 );
|
||||
root.activeName = caseFix;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
onLoaded: {
|
||||
const lines = text().split("\n");
|
||||
for (const line of lines) {
|
||||
if (line.startsWith("Name=")) {
|
||||
let name = line.replace("Name=", "");
|
||||
let caseFix = name[0].toUpperCase() + name.slice(1);
|
||||
root.activeName = caseFix;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FileView {
|
||||
id: kbLayoutFile
|
||||
FileView {
|
||||
id: kbLayoutFile
|
||||
|
||||
path: Quickshell.env("ZSHELL_XKB_RULES_PATH") || "/usr/share/X11/xkb/rules/base.lst"
|
||||
onLoaded: {
|
||||
const layoutMatch = text().match(/! layout\n([\s\S]*?)\n\n/);
|
||||
if (layoutMatch) {
|
||||
const lines = layoutMatch[1].split("\n");
|
||||
for (const line of lines) {
|
||||
if (!line.trim() || line.trim().startsWith("!"))
|
||||
continue;
|
||||
path: Quickshell.env("ZSHELL_XKB_RULES_PATH") || "/usr/share/X11/xkb/rules/base.lst"
|
||||
|
||||
const match = line.match(/^\s*([a-z]{2,})\s+([a-zA-Z() ]+)$/);
|
||||
if (match)
|
||||
root.kbMap.set(match[2], match[1]);
|
||||
}
|
||||
}
|
||||
onLoaded: {
|
||||
const layoutMatch = text().match(/! layout\n([\s\S]*?)\n\n/);
|
||||
if (layoutMatch) {
|
||||
const lines = layoutMatch[1].split("\n");
|
||||
for (const line of lines) {
|
||||
if (!line.trim() || line.trim().startsWith("!"))
|
||||
continue;
|
||||
|
||||
const variantMatch = text().match(/! variant\n([\s\S]*?)\n\n/);
|
||||
if (variantMatch) {
|
||||
const lines = variantMatch[1].split("\n");
|
||||
for (const line of lines) {
|
||||
if (!line.trim() || line.trim().startsWith("!"))
|
||||
continue;
|
||||
const match = line.match(/^\s*([a-z]{2,})\s+([a-zA-Z() ]+)$/);
|
||||
if (match)
|
||||
root.kbMap.set(match[2], match[1]);
|
||||
}
|
||||
}
|
||||
|
||||
const match = line.match(/^\s*([a-zA-Z0-9_-]+)\s+([a-z]{2,}): (.+)$/);
|
||||
if (match)
|
||||
root.kbMap.set(match[3], match[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const variantMatch = text().match(/! variant\n([\s\S]*?)\n\n/);
|
||||
if (variantMatch) {
|
||||
const lines = variantMatch[1].split("\n");
|
||||
for (const line of lines) {
|
||||
if (!line.trim() || line.trim().startsWith("!"))
|
||||
continue;
|
||||
|
||||
IpcHandler {
|
||||
target: "hypr"
|
||||
const match = line.match(/^\s*([a-zA-Z0-9_-]+)\s+([a-z]{2,}): (.+)$/);
|
||||
if (match)
|
||||
root.kbMap.set(match[3], match[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function refreshDevices(): void {
|
||||
extras.refreshDevices();
|
||||
}
|
||||
}
|
||||
IpcHandler {
|
||||
function refreshDevices(): void {
|
||||
extras.refreshDevices();
|
||||
}
|
||||
|
||||
CustomShortcut {
|
||||
name: "refreshDevices"
|
||||
onPressed: extras.refreshDevices()
|
||||
onReleased: extras.refreshDevices()
|
||||
}
|
||||
target: "hypr"
|
||||
}
|
||||
|
||||
HyprExtras {
|
||||
id: extras
|
||||
}
|
||||
CustomShortcut {
|
||||
name: "refreshDevices"
|
||||
|
||||
onPressed: extras.refreshDevices()
|
||||
onReleased: extras.refreshDevices()
|
||||
}
|
||||
|
||||
HyprExtras {
|
||||
id: extras
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+167
-168
@@ -6,182 +6,181 @@ import Quickshell.Services.Notifications
|
||||
import QtQuick
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
readonly property var weatherIcons: ({
|
||||
"0": "clear_day",
|
||||
"1": "clear_day",
|
||||
"2": "partly_cloudy_day",
|
||||
"3": "cloud",
|
||||
"45": "foggy",
|
||||
"48": "foggy",
|
||||
"51": "rainy",
|
||||
"53": "rainy",
|
||||
"55": "rainy",
|
||||
"56": "rainy",
|
||||
"57": "rainy",
|
||||
"61": "rainy",
|
||||
"63": "rainy",
|
||||
"65": "rainy",
|
||||
"66": "rainy",
|
||||
"67": "rainy",
|
||||
"71": "cloudy_snowing",
|
||||
"73": "cloudy_snowing",
|
||||
"75": "snowing_heavy",
|
||||
"77": "cloudy_snowing",
|
||||
"80": "rainy",
|
||||
"81": "rainy",
|
||||
"82": "rainy",
|
||||
"85": "cloudy_snowing",
|
||||
"86": "snowing_heavy",
|
||||
"95": "thunderstorm",
|
||||
"96": "thunderstorm",
|
||||
"99": "thunderstorm"
|
||||
})
|
||||
readonly property var categoryIcons: ({
|
||||
WebBrowser: "web",
|
||||
Printing: "print",
|
||||
Security: "security",
|
||||
Network: "chat",
|
||||
Archiving: "archive",
|
||||
Compression: "archive",
|
||||
Development: "code",
|
||||
IDE: "code",
|
||||
TextEditor: "edit_note",
|
||||
Audio: "music_note",
|
||||
Music: "music_note",
|
||||
Player: "music_note",
|
||||
Recorder: "mic",
|
||||
Game: "sports_esports",
|
||||
FileTools: "files",
|
||||
FileManager: "files",
|
||||
Filesystem: "files",
|
||||
FileTransfer: "files",
|
||||
Settings: "settings",
|
||||
DesktopSettings: "settings",
|
||||
HardwareSettings: "settings",
|
||||
TerminalEmulator: "terminal",
|
||||
ConsoleOnly: "terminal",
|
||||
Utility: "build",
|
||||
Monitor: "monitor_heart",
|
||||
Midi: "graphic_eq",
|
||||
Mixer: "graphic_eq",
|
||||
AudioVideoEditing: "video_settings",
|
||||
AudioVideo: "music_video",
|
||||
Video: "videocam",
|
||||
Building: "construction",
|
||||
Graphics: "photo_library",
|
||||
"2DGraphics": "photo_library",
|
||||
RasterGraphics: "photo_library",
|
||||
TV: "tv",
|
||||
System: "host",
|
||||
Office: "content_paste"
|
||||
})
|
||||
readonly property var weatherIcons: ({
|
||||
"0": "clear_day",
|
||||
"1": "clear_day",
|
||||
"2": "partly_cloudy_day",
|
||||
"3": "cloud",
|
||||
"45": "foggy",
|
||||
"48": "foggy",
|
||||
"51": "rainy",
|
||||
"53": "rainy",
|
||||
"55": "rainy",
|
||||
"56": "rainy",
|
||||
"57": "rainy",
|
||||
"61": "rainy",
|
||||
"63": "rainy",
|
||||
"65": "rainy",
|
||||
"66": "rainy",
|
||||
"67": "rainy",
|
||||
"71": "cloudy_snowing",
|
||||
"73": "cloudy_snowing",
|
||||
"75": "snowing_heavy",
|
||||
"77": "cloudy_snowing",
|
||||
"80": "rainy",
|
||||
"81": "rainy",
|
||||
"82": "rainy",
|
||||
"85": "cloudy_snowing",
|
||||
"86": "snowing_heavy",
|
||||
"95": "thunderstorm",
|
||||
"96": "thunderstorm",
|
||||
"99": "thunderstorm"
|
||||
})
|
||||
|
||||
readonly property var categoryIcons: ({
|
||||
WebBrowser: "web",
|
||||
Printing: "print",
|
||||
Security: "security",
|
||||
Network: "chat",
|
||||
Archiving: "archive",
|
||||
Compression: "archive",
|
||||
Development: "code",
|
||||
IDE: "code",
|
||||
TextEditor: "edit_note",
|
||||
Audio: "music_note",
|
||||
Music: "music_note",
|
||||
Player: "music_note",
|
||||
Recorder: "mic",
|
||||
Game: "sports_esports",
|
||||
FileTools: "files",
|
||||
FileManager: "files",
|
||||
Filesystem: "files",
|
||||
FileTransfer: "files",
|
||||
Settings: "settings",
|
||||
DesktopSettings: "settings",
|
||||
HardwareSettings: "settings",
|
||||
TerminalEmulator: "terminal",
|
||||
ConsoleOnly: "terminal",
|
||||
Utility: "build",
|
||||
Monitor: "monitor_heart",
|
||||
Midi: "graphic_eq",
|
||||
Mixer: "graphic_eq",
|
||||
AudioVideoEditing: "video_settings",
|
||||
AudioVideo: "music_video",
|
||||
Video: "videocam",
|
||||
Building: "construction",
|
||||
Graphics: "photo_library",
|
||||
"2DGraphics": "photo_library",
|
||||
RasterGraphics: "photo_library",
|
||||
TV: "tv",
|
||||
System: "host",
|
||||
Office: "content_paste"
|
||||
})
|
||||
function getAppCategoryIcon(name: string, fallback: string): string {
|
||||
const categories = DesktopEntries.heuristicLookup(name)?.categories;
|
||||
|
||||
function getAppIcon(name: string, fallback: string): string {
|
||||
const icon = DesktopEntries.heuristicLookup(name)?.icon;
|
||||
if (fallback !== "undefined")
|
||||
return Quickshell.iconPath(icon, fallback);
|
||||
return Quickshell.iconPath(icon);
|
||||
}
|
||||
if (categories)
|
||||
for (const [key, value] of Object.entries(categoryIcons))
|
||||
if (categories.includes(key))
|
||||
return value;
|
||||
return fallback;
|
||||
}
|
||||
|
||||
function getAppCategoryIcon(name: string, fallback: string): string {
|
||||
const categories = DesktopEntries.heuristicLookup(name)?.categories;
|
||||
function getAppIcon(name: string, fallback: string): string {
|
||||
const icon = DesktopEntries.heuristicLookup(name)?.icon;
|
||||
if (fallback !== "undefined")
|
||||
return Quickshell.iconPath(icon, fallback);
|
||||
return Quickshell.iconPath(icon);
|
||||
}
|
||||
|
||||
if (categories)
|
||||
for (const [key, value] of Object.entries(categoryIcons))
|
||||
if (categories.includes(key))
|
||||
return value;
|
||||
return fallback;
|
||||
}
|
||||
function getBluetoothIcon(icon: string): string {
|
||||
if (icon.includes("headset") || icon.includes("headphones"))
|
||||
return "headphones";
|
||||
if (icon.includes("audio"))
|
||||
return "speaker";
|
||||
if (icon.includes("phone"))
|
||||
return "smartphone";
|
||||
if (icon.includes("mouse"))
|
||||
return "mouse";
|
||||
if (icon.includes("keyboard"))
|
||||
return "keyboard";
|
||||
return "bluetooth";
|
||||
}
|
||||
|
||||
function getNetworkIcon(strength: int, isSecure = false): string {
|
||||
if (isSecure) {
|
||||
if (strength >= 80)
|
||||
return "network_wifi_locked";
|
||||
if (strength >= 60)
|
||||
return "network_wifi_3_bar_locked";
|
||||
if (strength >= 40)
|
||||
return "network_wifi_2_bar_locked";
|
||||
if (strength >= 20)
|
||||
return "network_wifi_1_bar_locked";
|
||||
return "signal_wifi_0_bar";
|
||||
} else {
|
||||
if (strength >= 80)
|
||||
return "network_wifi";
|
||||
if (strength >= 60)
|
||||
return "network_wifi_3_bar";
|
||||
if (strength >= 40)
|
||||
return "network_wifi_2_bar";
|
||||
if (strength >= 20)
|
||||
return "network_wifi_1_bar";
|
||||
return "signal_wifi_0_bar";
|
||||
}
|
||||
}
|
||||
function getMicVolumeIcon(volume: real, isMuted: bool): string {
|
||||
if (!isMuted && volume > 0)
|
||||
return "mic";
|
||||
return "mic_off";
|
||||
}
|
||||
|
||||
function getBluetoothIcon(icon: string): string {
|
||||
if (icon.includes("headset") || icon.includes("headphones"))
|
||||
return "headphones";
|
||||
if (icon.includes("audio"))
|
||||
return "speaker";
|
||||
if (icon.includes("phone"))
|
||||
return "smartphone";
|
||||
if (icon.includes("mouse"))
|
||||
return "mouse";
|
||||
if (icon.includes("keyboard"))
|
||||
return "keyboard";
|
||||
return "bluetooth";
|
||||
}
|
||||
function getNetworkIcon(strength: int, isSecure = false): string {
|
||||
if (isSecure) {
|
||||
if (strength >= 80)
|
||||
return "network_wifi_locked";
|
||||
if (strength >= 60)
|
||||
return "network_wifi_3_bar_locked";
|
||||
if (strength >= 40)
|
||||
return "network_wifi_2_bar_locked";
|
||||
if (strength >= 20)
|
||||
return "network_wifi_1_bar_locked";
|
||||
return "signal_wifi_0_bar";
|
||||
} else {
|
||||
if (strength >= 80)
|
||||
return "network_wifi";
|
||||
if (strength >= 60)
|
||||
return "network_wifi_3_bar";
|
||||
if (strength >= 40)
|
||||
return "network_wifi_2_bar";
|
||||
if (strength >= 20)
|
||||
return "network_wifi_1_bar";
|
||||
return "signal_wifi_0_bar";
|
||||
}
|
||||
}
|
||||
|
||||
function getWeatherIcon(code: string): string {
|
||||
if (weatherIcons.hasOwnProperty(code))
|
||||
return weatherIcons[code];
|
||||
return "air";
|
||||
}
|
||||
function getNotifIcon(summary: string, urgency: int): string {
|
||||
summary = summary.toLowerCase();
|
||||
if (summary.includes("reboot"))
|
||||
return "restart_alt";
|
||||
if (summary.includes("recording"))
|
||||
return "screen_record";
|
||||
if (summary.includes("battery"))
|
||||
return "power";
|
||||
if (summary.includes("screenshot"))
|
||||
return "screenshot_monitor";
|
||||
if (summary.includes("welcome"))
|
||||
return "waving_hand";
|
||||
if (summary.includes("time") || summary.includes("a break"))
|
||||
return "schedule";
|
||||
if (summary.includes("installed"))
|
||||
return "download";
|
||||
if (summary.includes("update"))
|
||||
return "update";
|
||||
if (summary.includes("unable to"))
|
||||
return "deployed_code_alert";
|
||||
if (summary.includes("profile"))
|
||||
return "person";
|
||||
if (summary.includes("file"))
|
||||
return "folder_copy";
|
||||
if (urgency === NotificationUrgency.Critical)
|
||||
return "release_alert";
|
||||
return "chat";
|
||||
}
|
||||
|
||||
function getNotifIcon(summary: string, urgency: int): string {
|
||||
summary = summary.toLowerCase();
|
||||
if (summary.includes("reboot"))
|
||||
return "restart_alt";
|
||||
if (summary.includes("recording"))
|
||||
return "screen_record";
|
||||
if (summary.includes("battery"))
|
||||
return "power";
|
||||
if (summary.includes("screenshot"))
|
||||
return "screenshot_monitor";
|
||||
if (summary.includes("welcome"))
|
||||
return "waving_hand";
|
||||
if (summary.includes("time") || summary.includes("a break"))
|
||||
return "schedule";
|
||||
if (summary.includes("installed"))
|
||||
return "download";
|
||||
if (summary.includes("update"))
|
||||
return "update";
|
||||
if (summary.includes("unable to"))
|
||||
return "deployed_code_alert";
|
||||
if (summary.includes("profile"))
|
||||
return "person";
|
||||
if (summary.includes("file"))
|
||||
return "folder_copy";
|
||||
if (urgency === NotificationUrgency.Critical)
|
||||
return "release_alert";
|
||||
return "chat";
|
||||
}
|
||||
function getVolumeIcon(volume: real, isMuted: bool): string {
|
||||
if (isMuted)
|
||||
return "no_sound";
|
||||
if (volume >= 0.5)
|
||||
return "volume_up";
|
||||
if (volume > 0)
|
||||
return "volume_down";
|
||||
return "volume_mute";
|
||||
}
|
||||
|
||||
function getVolumeIcon(volume: real, isMuted: bool): string {
|
||||
if (isMuted)
|
||||
return "no_sound";
|
||||
if (volume >= 0.5)
|
||||
return "volume_up";
|
||||
if (volume > 0)
|
||||
return "volume_down";
|
||||
return "volume_mute";
|
||||
}
|
||||
|
||||
function getMicVolumeIcon(volume: real, isMuted: bool): string {
|
||||
if (!isMuted && volume > 0)
|
||||
return "mic";
|
||||
return "mic_off";
|
||||
}
|
||||
function getWeatherIcon(code: string): string {
|
||||
if (weatherIcons.hasOwnProperty(code))
|
||||
return weatherIcons[code];
|
||||
return "air";
|
||||
}
|
||||
}
|
||||
|
||||
+40
-37
@@ -5,52 +5,55 @@ import Quickshell.Io
|
||||
import Quickshell.Wayland
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
property alias enabled: props.enabled
|
||||
readonly property alias enabledSince: props.enabledSince
|
||||
property alias enabled: props.enabled
|
||||
readonly property alias enabledSince: props.enabledSince
|
||||
|
||||
onEnabledChanged: {
|
||||
if (enabled)
|
||||
props.enabledSince = new Date();
|
||||
}
|
||||
onEnabledChanged: {
|
||||
if (enabled)
|
||||
props.enabledSince = new Date();
|
||||
}
|
||||
|
||||
PersistentProperties {
|
||||
id: props
|
||||
PersistentProperties {
|
||||
id: props
|
||||
|
||||
property bool enabled
|
||||
property date enabledSince
|
||||
property bool enabled
|
||||
property date enabledSince
|
||||
|
||||
reloadableId: "idleInhibitor"
|
||||
}
|
||||
reloadableId: "idleInhibitor"
|
||||
}
|
||||
|
||||
IdleInhibitor {
|
||||
enabled: props.enabled
|
||||
window: PanelWindow {
|
||||
implicitWidth: 0
|
||||
implicitHeight: 0
|
||||
color: "transparent"
|
||||
mask: Region {}
|
||||
}
|
||||
}
|
||||
IdleInhibitor {
|
||||
enabled: props.enabled
|
||||
|
||||
IpcHandler {
|
||||
target: "idleInhibitor"
|
||||
window: PanelWindow {
|
||||
color: "transparent"
|
||||
implicitHeight: 0
|
||||
implicitWidth: 0
|
||||
|
||||
function isEnabled(): bool {
|
||||
return props.enabled;
|
||||
}
|
||||
mask: Region {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function toggle(): void {
|
||||
props.enabled = !props.enabled;
|
||||
}
|
||||
IpcHandler {
|
||||
function disable(): void {
|
||||
props.enabled = false;
|
||||
}
|
||||
|
||||
function enable(): void {
|
||||
props.enabled = true;
|
||||
}
|
||||
function enable(): void {
|
||||
props.enabled = true;
|
||||
}
|
||||
|
||||
function disable(): void {
|
||||
props.enabled = false;
|
||||
}
|
||||
}
|
||||
function isEnabled(): bool {
|
||||
return props.enabled;
|
||||
}
|
||||
|
||||
function toggle(): void {
|
||||
props.enabled = !props.enabled;
|
||||
}
|
||||
|
||||
target: "idleInhibitor"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,14 +5,14 @@ import Quickshell.Hyprland
|
||||
import qs.Helpers
|
||||
|
||||
Singleton {
|
||||
function getInitialTitle(callback) {
|
||||
let activeWindow = Hypr.activeToplevel.title
|
||||
let activeClass = Hypr.activeToplevel.lastIpcObject.class.toString()
|
||||
let regex = new RegExp(activeClass, "i")
|
||||
function getInitialTitle(callback) {
|
||||
let activeWindow = Hypr.activeToplevel.title;
|
||||
let activeClass = Hypr.activeToplevel.lastIpcObject.class.toString();
|
||||
let regex = new RegExp(activeClass, "i");
|
||||
|
||||
console.log("ActiveWindow", activeWindow, "ActiveClass", activeClass, "Regex", regex)
|
||||
console.log("ActiveWindow", activeWindow, "ActiveClass", activeClass, "Regex", regex);
|
||||
|
||||
const evalTitle = activeWindow.match(regex)
|
||||
callback(evalTitle)
|
||||
}
|
||||
const evalTitle = activeWindow.match(regex);
|
||||
callback(evalTitle);
|
||||
}
|
||||
}
|
||||
|
||||
+35
-35
@@ -10,32 +10,11 @@ import qs.Paths
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
readonly property int darkStart: Config.general.color.scheduleDarkStart
|
||||
readonly property int darkEnd: Config.general.color.scheduleDarkEnd
|
||||
|
||||
Timer {
|
||||
id: darkModeTimer
|
||||
|
||||
interval: 5000
|
||||
|
||||
running: true
|
||||
repeat: true
|
||||
onTriggered: {
|
||||
if ( darkStart === darkEnd )
|
||||
return;
|
||||
var now = new Date();
|
||||
if ( now.getHours() >= darkStart || now.getHours() < darkEnd ) {
|
||||
if ( DynamicColors.light )
|
||||
applyDarkMode();
|
||||
} else {
|
||||
if ( !DynamicColors.light )
|
||||
applyLightMode();
|
||||
}
|
||||
}
|
||||
}
|
||||
readonly property int darkStart: Config.general.color.scheduleDarkStart
|
||||
|
||||
function applyDarkMode() {
|
||||
if ( Config.general.color.schemeGeneration ) {
|
||||
if (Config.general.color.schemeGeneration) {
|
||||
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--image-path", `${WallpaperPath.currentWallpaperPath}`, "--thumbnail-path", `${Paths.cache}/imagecache/thumbnail.jpg`, "--output", `${Paths.state}/scheme.json`, "--scheme", `${Config.colors.schemeType}`, "--mode", "dark"]);
|
||||
} else {
|
||||
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--preset", `${DynamicColors.scheme}:${DynamicColors.flavour}`, "--output", `${Paths.state}/scheme.json`, "--mode", "dark"]);
|
||||
@@ -43,18 +22,18 @@ Singleton {
|
||||
|
||||
Config.general.color.mode = "dark";
|
||||
|
||||
Quickshell.execDetached(["gsettings", "set", "org.gnome.desktop.interface", "color-scheme", "'prefer-dark'"])
|
||||
Quickshell.execDetached(["gsettings", "set", "org.gnome.desktop.interface", "color-scheme", "'prefer-dark'"]);
|
||||
|
||||
Quickshell.execDetached(["sh", "-c", `sed -i 's/color_scheme_path=\\(.*\\)Light.colors/color_scheme_path=\\1Dark.colors/' ${Paths.home}/.config/qt6ct/qt6ct.conf`])
|
||||
Quickshell.execDetached(["sh", "-c", `sed -i 's/color_scheme_path=\\(.*\\)Light.colors/color_scheme_path=\\1Dark.colors/' ${Paths.home}/.config/qt6ct/qt6ct.conf`]);
|
||||
|
||||
Quickshell.execDetached(["sed", "-i", "'s/\\(vim.cmd.colorscheme \\).*/\\1\"tokyodark\"/'", "~/.config/nvim/lua/config/load-colorscheme.lua"])
|
||||
Quickshell.execDetached(["sed", "-i", "'s/\\(vim.cmd.colorscheme \\).*/\\1\"tokyodark\"/'", "~/.config/nvim/lua/config/load-colorscheme.lua"]);
|
||||
|
||||
if( Config.general.color.wallust )
|
||||
if (Config.general.color.wallust)
|
||||
Wallust.generateColors(WallpaperPath.currentWallpaperPath);
|
||||
}
|
||||
|
||||
function applyLightMode() {
|
||||
if ( Config.general.color.neovimColors ) {
|
||||
if (Config.general.color.neovimColors) {
|
||||
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--image-path", `${WallpaperPath.currentWallpaperPath}`, "--thumbnail-path", `${Paths.cache}/imagecache/thumbnail.jpg`, "--output", `${Paths.state}/scheme.json`, "--scheme", `${Config.colors.schemeType}`, "--mode", "light"]);
|
||||
} else {
|
||||
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--preset", `${DynamicColors.scheme}:${DynamicColors.flavour}`, "--output", `${Paths.state}/scheme.json`, "--mode", "light"]);
|
||||
@@ -62,25 +41,46 @@ Singleton {
|
||||
|
||||
Config.general.color.mode = "light";
|
||||
|
||||
Quickshell.execDetached(["gsettings", "set", "org.gnome.desktop.interface", "color-scheme", "'prefer-light'"])
|
||||
Quickshell.execDetached(["gsettings", "set", "org.gnome.desktop.interface", "color-scheme", "'prefer-light'"]);
|
||||
|
||||
Quickshell.execDetached(["sh", "-c", `sed -i 's/color_scheme_path=\\(.*\\)Dark.colors/color_scheme_path=\\1Light.colors/' ${Paths.home}/.config/qt6ct/qt6ct.conf`])
|
||||
Quickshell.execDetached(["sh", "-c", `sed -i 's/color_scheme_path=\\(.*\\)Dark.colors/color_scheme_path=\\1Light.colors/' ${Paths.home}/.config/qt6ct/qt6ct.conf`]);
|
||||
|
||||
if ( Config.general.color.neovimColors )
|
||||
Quickshell.execDetached(["sed", "-i", "'s/\\(vim.cmd.colorscheme \\).*/\\1\"onelight\"/'", "~/.config/nvim/lua/config/load-colorscheme.lua"])
|
||||
if (Config.general.color.neovimColors)
|
||||
Quickshell.execDetached(["sed", "-i", "'s/\\(vim.cmd.colorscheme \\).*/\\1\"onelight\"/'", "~/.config/nvim/lua/config/load-colorscheme.lua"]);
|
||||
|
||||
if( Config.general.color.wallust )
|
||||
if (Config.general.color.wallust)
|
||||
Wallust.generateColors(WallpaperPath.currentWallpaperPath);
|
||||
}
|
||||
|
||||
function checkStartup() {
|
||||
if ( darkStart === darkEnd )
|
||||
if (darkStart === darkEnd)
|
||||
return;
|
||||
var now = new Date();
|
||||
if ( now.getHours() >= darkStart || now.getHours() < darkEnd ) {
|
||||
if (now.getHours() >= darkStart || now.getHours() < darkEnd) {
|
||||
applyDarkMode();
|
||||
} else {
|
||||
applyLightMode();
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: darkModeTimer
|
||||
|
||||
interval: 5000
|
||||
repeat: true
|
||||
running: true
|
||||
|
||||
onTriggered: {
|
||||
if (darkStart === darkEnd)
|
||||
return;
|
||||
var now = new Date();
|
||||
if (now.getHours() >= darkStart || now.getHours() < darkEnd) {
|
||||
if (DynamicColors.light)
|
||||
applyDarkMode();
|
||||
} else {
|
||||
if (!DynamicColors.light)
|
||||
applyLightMode();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -6,6 +6,6 @@ import Quickshell.Networking
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
property list<NetworkDevice> devices: Networking.devices.values
|
||||
property NetworkDevice activeDevice: devices.find(d => d.connected)
|
||||
property list<NetworkDevice> devices: Networking.devices.values
|
||||
}
|
||||
|
||||
@@ -4,13 +4,13 @@ import Quickshell
|
||||
import Quickshell.Io
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
property alias centerX: notifCenterSpacing.centerX
|
||||
property alias centerX: notifCenterSpacing.centerX
|
||||
|
||||
JsonAdapter {
|
||||
id: notifCenterSpacing
|
||||
JsonAdapter {
|
||||
id: notifCenterSpacing
|
||||
|
||||
property int centerX
|
||||
}
|
||||
property int centerX
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,13 +4,13 @@ import Quickshell.Io
|
||||
import Quickshell
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
property alias notifPath: storage.notifPath
|
||||
property alias notifPath: storage.notifPath
|
||||
|
||||
JsonAdapter {
|
||||
id: storage
|
||||
JsonAdapter {
|
||||
id: storage
|
||||
|
||||
property string notifPath: Quickshell.statePath("notifications.json")
|
||||
}
|
||||
property string notifPath: Quickshell.statePath("notifications.json")
|
||||
}
|
||||
}
|
||||
|
||||
+234
-243
@@ -10,286 +10,277 @@ import qs.Config
|
||||
import qs.Helpers
|
||||
|
||||
MouseArea {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
required property LazyLoader loader
|
||||
required property ShellScreen screen
|
||||
property list<var> clients: {
|
||||
const mon = Hypr.monitorFor(screen);
|
||||
if (!mon)
|
||||
return [];
|
||||
|
||||
property bool onClient
|
||||
const special = mon.lastIpcObject.specialWorkspace;
|
||||
const wsId = special.name ? special.id : mon.activeWorkspace.id;
|
||||
|
||||
property real realBorderWidth: onClient ? (Hypr.options["general:border_size"] ?? 1) : 2
|
||||
property real realRounding: onClient ? (Hypr.options["decoration:rounding"] ?? 0) : 0
|
||||
return Hypr.toplevels.values.filter(c => c.workspace?.id === wsId).sort((a, b) => {
|
||||
const ac = a.lastIpcObject;
|
||||
const bc = b.lastIpcObject;
|
||||
return (bc.pinned - ac.pinned) || ((bc.fullscreen !== 0) - (ac.fullscreen !== 0)) || (bc.floating - ac.floating);
|
||||
});
|
||||
}
|
||||
property real ex: screen.width
|
||||
property real ey: screen.height
|
||||
required property LazyLoader loader
|
||||
property bool onClient
|
||||
property real realBorderWidth: onClient ? (Hypr.options["general:border_size"] ?? 1) : 2
|
||||
property real realRounding: onClient ? (Hypr.options["decoration:rounding"] ?? 0) : 0
|
||||
property real rsx: Math.min(sx, ex)
|
||||
property real rsy: Math.min(sy, ey)
|
||||
required property ShellScreen screen
|
||||
property real sh: Math.abs(sy - ey)
|
||||
property real ssx
|
||||
property real ssy
|
||||
property real sw: Math.abs(sx - ex)
|
||||
property real sx: 0
|
||||
property real sy: 0
|
||||
|
||||
property real ssx
|
||||
property real ssy
|
||||
function checkClientRects(x: real, y: real): void {
|
||||
for (const client of clients) {
|
||||
if (!client)
|
||||
continue;
|
||||
|
||||
property real sx: 0
|
||||
property real sy: 0
|
||||
property real ex: screen.width
|
||||
property real ey: screen.height
|
||||
let {
|
||||
at: [cx, cy],
|
||||
size: [cw, ch]
|
||||
} = client.lastIpcObject;
|
||||
cx -= screen.x;
|
||||
cy -= screen.y;
|
||||
if (cx <= x && cy <= y && cx + cw >= x && cy + ch >= y) {
|
||||
onClient = true;
|
||||
sx = cx;
|
||||
sy = cy;
|
||||
ex = cx + cw;
|
||||
ey = cy + ch;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property real rsx: Math.min(sx, ex)
|
||||
property real rsy: Math.min(sy, ey)
|
||||
property real sw: Math.abs(sx - ex)
|
||||
property real sh: Math.abs(sy - ey)
|
||||
function save(): void {
|
||||
const tmpfile = Qt.resolvedUrl(`/tmp/zshell-picker-${Quickshell.processId}-${Date.now()}.png`);
|
||||
ZShellIo.saveItem(screencopy, tmpfile, Qt.rect(Math.ceil(rsx), Math.ceil(rsy), Math.floor(sw), Math.floor(sh)), path => Quickshell.execDetached(["swappy", "-f", path]));
|
||||
closeAnim.start();
|
||||
}
|
||||
|
||||
property list<var> clients: {
|
||||
const mon = Hypr.monitorFor(screen);
|
||||
if (!mon)
|
||||
return [];
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.CrossCursor
|
||||
focus: true
|
||||
hoverEnabled: true
|
||||
opacity: 0
|
||||
|
||||
const special = mon.lastIpcObject.specialWorkspace;
|
||||
const wsId = special.name ? special.id : mon.activeWorkspace.id;
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
duration: 300
|
||||
}
|
||||
}
|
||||
Behavior on rsx {
|
||||
enabled: !root.pressed
|
||||
|
||||
return Hypr.toplevels.values.filter(c => c.workspace?.id === wsId).sort((a, b) => {
|
||||
const ac = a.lastIpcObject;
|
||||
const bc = b.lastIpcObject;
|
||||
return (bc.pinned - ac.pinned) || ((bc.fullscreen !== 0) - (ac.fullscreen !== 0)) || (bc.floating - ac.floating);
|
||||
});
|
||||
}
|
||||
ExAnim {
|
||||
}
|
||||
}
|
||||
Behavior on rsy {
|
||||
enabled: !root.pressed
|
||||
|
||||
function checkClientRects(x: real, y: real): void {
|
||||
for (const client of clients) {
|
||||
if (!client)
|
||||
continue;
|
||||
ExAnim {
|
||||
}
|
||||
}
|
||||
Behavior on sh {
|
||||
enabled: !root.pressed
|
||||
|
||||
let {
|
||||
at: [cx, cy],
|
||||
size: [cw, ch]
|
||||
} = client.lastIpcObject;
|
||||
cx -= screen.x;
|
||||
cy -= screen.y;
|
||||
if (cx <= x && cy <= y && cx + cw >= x && cy + ch >= y) {
|
||||
onClient = true;
|
||||
sx = cx;
|
||||
sy = cy;
|
||||
ex = cx + cw;
|
||||
ey = cy + ch;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ExAnim {
|
||||
}
|
||||
}
|
||||
Behavior on sw {
|
||||
enabled: !root.pressed
|
||||
|
||||
function save(): void {
|
||||
const tmpfile = Qt.resolvedUrl(`/tmp/zshell-picker-${Quickshell.processId}-${Date.now()}.png`);
|
||||
ZShellIo.saveItem(screencopy, tmpfile, Qt.rect(Math.ceil(rsx), Math.ceil(rsy), Math.floor(sw), Math.floor(sh)), path => Quickshell.execDetached(["swappy", "-f", path]));
|
||||
closeAnim.start();
|
||||
}
|
||||
ExAnim {
|
||||
}
|
||||
}
|
||||
|
||||
onClientsChanged: checkClientRects(mouseX, mouseY)
|
||||
Component.onCompleted: {
|
||||
Hypr.extras.refreshOptions();
|
||||
if (loader.freeze)
|
||||
clients = clients;
|
||||
|
||||
anchors.fill: parent
|
||||
opacity: 0
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.CrossCursor
|
||||
opacity = 1;
|
||||
|
||||
Component.onCompleted: {
|
||||
Hypr.extras.refreshOptions();
|
||||
if (loader.freeze)
|
||||
clients = clients;
|
||||
const c = clients[0];
|
||||
if (c) {
|
||||
const cx = c.lastIpcObject.at[0] - screen.x;
|
||||
const cy = c.lastIpcObject.at[1] - screen.y;
|
||||
onClient = true;
|
||||
sx = cx;
|
||||
sy = cy;
|
||||
ex = cx + c.lastIpcObject.size[0];
|
||||
ey = cy + c.lastIpcObject.size[1];
|
||||
} else {
|
||||
sx = screen.width / 2 - 100;
|
||||
sy = screen.height / 2 - 100;
|
||||
ex = screen.width / 2 + 100;
|
||||
ey = screen.height / 2 + 100;
|
||||
}
|
||||
}
|
||||
Keys.onEscapePressed: closeAnim.start()
|
||||
onClientsChanged: checkClientRects(mouseX, mouseY)
|
||||
onPositionChanged: event => {
|
||||
const x = event.x;
|
||||
const y = event.y;
|
||||
|
||||
opacity = 1;
|
||||
if (pressed) {
|
||||
onClient = false;
|
||||
sx = ssx;
|
||||
sy = ssy;
|
||||
ex = x;
|
||||
ey = y;
|
||||
} else {
|
||||
checkClientRects(x, y);
|
||||
}
|
||||
}
|
||||
onPressed: event => {
|
||||
ssx = event.x;
|
||||
ssy = event.y;
|
||||
}
|
||||
onReleased: {
|
||||
if (closeAnim.running)
|
||||
return;
|
||||
|
||||
const c = clients[0];
|
||||
if (c) {
|
||||
const cx = c.lastIpcObject.at[0] - screen.x;
|
||||
const cy = c.lastIpcObject.at[1] - screen.y;
|
||||
onClient = true;
|
||||
sx = cx;
|
||||
sy = cy;
|
||||
ex = cx + c.lastIpcObject.size[0];
|
||||
ey = cy + c.lastIpcObject.size[1];
|
||||
} else {
|
||||
sx = screen.width / 2 - 100;
|
||||
sy = screen.height / 2 - 100;
|
||||
ex = screen.width / 2 + 100;
|
||||
ey = screen.height / 2 + 100;
|
||||
}
|
||||
}
|
||||
if (root.loader.freeze) {
|
||||
save();
|
||||
} else {
|
||||
overlay.visible = border.visible = false;
|
||||
screencopy.visible = false;
|
||||
screencopy.active = true;
|
||||
}
|
||||
}
|
||||
|
||||
onPressed: event => {
|
||||
ssx = event.x;
|
||||
ssy = event.y;
|
||||
}
|
||||
SequentialAnimation {
|
||||
id: closeAnim
|
||||
|
||||
onReleased: {
|
||||
if (closeAnim.running)
|
||||
return;
|
||||
PropertyAction {
|
||||
property: "closing"
|
||||
target: root.loader
|
||||
value: true
|
||||
}
|
||||
|
||||
if (root.loader.freeze) {
|
||||
save();
|
||||
} else {
|
||||
overlay.visible = border.visible = false;
|
||||
screencopy.visible = false;
|
||||
screencopy.active = true;
|
||||
}
|
||||
}
|
||||
ParallelAnimation {
|
||||
Anim {
|
||||
duration: 300
|
||||
property: "opacity"
|
||||
target: root
|
||||
to: 0
|
||||
}
|
||||
|
||||
onPositionChanged: event => {
|
||||
const x = event.x;
|
||||
const y = event.y;
|
||||
ExAnim {
|
||||
properties: "rsx,rsy"
|
||||
target: root
|
||||
to: 0
|
||||
}
|
||||
|
||||
if (pressed) {
|
||||
onClient = false;
|
||||
sx = ssx;
|
||||
sy = ssy;
|
||||
ex = x;
|
||||
ey = y;
|
||||
} else {
|
||||
checkClientRects(x, y);
|
||||
}
|
||||
}
|
||||
ExAnim {
|
||||
property: "sw"
|
||||
target: root
|
||||
to: root.screen.width
|
||||
}
|
||||
|
||||
focus: true
|
||||
Keys.onEscapePressed: closeAnim.start()
|
||||
ExAnim {
|
||||
property: "sh"
|
||||
target: root
|
||||
to: root.screen.height
|
||||
}
|
||||
}
|
||||
|
||||
SequentialAnimation {
|
||||
id: closeAnim
|
||||
PropertyAction {
|
||||
property: "activeAsync"
|
||||
target: root.loader
|
||||
value: false
|
||||
}
|
||||
}
|
||||
|
||||
PropertyAction {
|
||||
target: root.loader
|
||||
property: "closing"
|
||||
value: true
|
||||
}
|
||||
ParallelAnimation {
|
||||
Anim {
|
||||
target: root
|
||||
property: "opacity"
|
||||
to: 0
|
||||
duration: 300
|
||||
}
|
||||
ExAnim {
|
||||
target: root
|
||||
properties: "rsx,rsy"
|
||||
to: 0
|
||||
}
|
||||
ExAnim {
|
||||
target: root
|
||||
property: "sw"
|
||||
to: root.screen.width
|
||||
}
|
||||
ExAnim {
|
||||
target: root
|
||||
property: "sh"
|
||||
to: root.screen.height
|
||||
}
|
||||
}
|
||||
PropertyAction {
|
||||
target: root.loader
|
||||
property: "activeAsync"
|
||||
value: false
|
||||
}
|
||||
}
|
||||
Loader {
|
||||
id: screencopy
|
||||
|
||||
Loader {
|
||||
id: screencopy
|
||||
active: root.loader.freeze
|
||||
anchors.fill: parent
|
||||
asynchronous: true
|
||||
|
||||
anchors.fill: parent
|
||||
sourceComponent: ScreencopyView {
|
||||
captureSource: root.screen
|
||||
paintCursor: false
|
||||
|
||||
active: root.loader.freeze
|
||||
asynchronous: true
|
||||
onHasContentChanged: {
|
||||
if (hasContent && !root.loader.freeze) {
|
||||
overlay.visible = border.visible = true;
|
||||
root.save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceComponent: ScreencopyView {
|
||||
captureSource: root.screen
|
||||
Rectangle {
|
||||
id: overlay
|
||||
|
||||
paintCursor: false
|
||||
anchors.fill: parent
|
||||
color: "white"
|
||||
layer.enabled: true
|
||||
opacity: 0.3
|
||||
radius: root.realRounding
|
||||
|
||||
onHasContentChanged: {
|
||||
if (hasContent && !root.loader.freeze) {
|
||||
overlay.visible = border.visible = true;
|
||||
root.save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
layer.effect: MultiEffect {
|
||||
maskEnabled: true
|
||||
maskInverted: true
|
||||
maskSource: selectionWrapper
|
||||
maskSpreadAtMin: 1
|
||||
maskThresholdMin: 0.5
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: overlay
|
||||
Item {
|
||||
id: selectionWrapper
|
||||
|
||||
anchors.fill: parent
|
||||
color: "white"
|
||||
opacity: 0.3
|
||||
anchors.fill: parent
|
||||
layer.enabled: true
|
||||
visible: false
|
||||
|
||||
radius: root.realRounding
|
||||
Rectangle {
|
||||
id: selectionRect
|
||||
|
||||
layer.enabled: true
|
||||
layer.effect: MultiEffect {
|
||||
maskSource: selectionWrapper
|
||||
maskEnabled: true
|
||||
maskInverted: true
|
||||
maskSpreadAtMin: 1
|
||||
maskThresholdMin: 0.5
|
||||
}
|
||||
}
|
||||
implicitHeight: root.sh
|
||||
implicitWidth: root.sw
|
||||
radius: root.realRounding
|
||||
x: root.rsx
|
||||
y: root.rsy
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: selectionWrapper
|
||||
Rectangle {
|
||||
id: border
|
||||
|
||||
anchors.fill: parent
|
||||
layer.enabled: true
|
||||
visible: false
|
||||
border.color: DynamicColors.palette.m3primary
|
||||
border.width: root.realBorderWidth
|
||||
color: "transparent"
|
||||
implicitHeight: selectionRect.implicitHeight + root.realBorderWidth * 2
|
||||
implicitWidth: selectionRect.implicitWidth + root.realBorderWidth * 2
|
||||
radius: root.realRounding > 0 ? root.realRounding + root.realBorderWidth : 0
|
||||
x: selectionRect.x - root.realBorderWidth
|
||||
y: selectionRect.y - root.realBorderWidth
|
||||
|
||||
Rectangle {
|
||||
id: selectionRect
|
||||
Behavior on border.color {
|
||||
Anim {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
radius: root.realRounding
|
||||
x: root.rsx
|
||||
y: root.rsy
|
||||
implicitWidth: root.sw
|
||||
implicitHeight: root.sh
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: border
|
||||
|
||||
color: "transparent"
|
||||
radius: root.realRounding > 0 ? root.realRounding + root.realBorderWidth : 0
|
||||
border.width: root.realBorderWidth
|
||||
border.color: DynamicColors.palette.m3primary
|
||||
|
||||
x: selectionRect.x - root.realBorderWidth
|
||||
y: selectionRect.y - root.realBorderWidth
|
||||
implicitWidth: selectionRect.implicitWidth + root.realBorderWidth * 2
|
||||
implicitHeight: selectionRect.implicitHeight + root.realBorderWidth * 2
|
||||
|
||||
Behavior on border.color {
|
||||
Anim {}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
duration: 300
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on rsx {
|
||||
enabled: !root.pressed
|
||||
|
||||
ExAnim {}
|
||||
}
|
||||
|
||||
Behavior on rsy {
|
||||
enabled: !root.pressed
|
||||
|
||||
ExAnim {}
|
||||
}
|
||||
|
||||
Behavior on sw {
|
||||
enabled: !root.pressed
|
||||
|
||||
ExAnim {}
|
||||
}
|
||||
|
||||
Behavior on sh {
|
||||
enabled: !root.pressed
|
||||
|
||||
ExAnim {}
|
||||
}
|
||||
|
||||
component ExAnim: Anim {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
component ExAnim: Anim {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
}
|
||||
|
||||
+95
-91
@@ -9,115 +9,119 @@ import qs.Config
|
||||
import qs.Components
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
readonly property list<MprisPlayer> list: Mpris.players.values
|
||||
readonly property MprisPlayer active: props.manualActive ?? list.find(p => getIdentity(p) === Config.services.defaultPlayer) ?? list[0] ?? null
|
||||
property alias manualActive: props.manualActive
|
||||
readonly property MprisPlayer active: props.manualActive ?? list.find(p => getIdentity(p) === Config.services.defaultPlayer) ?? list[0] ?? null
|
||||
readonly property list<MprisPlayer> list: Mpris.players.values
|
||||
property alias manualActive: props.manualActive
|
||||
|
||||
function getIdentity(player: MprisPlayer): string {
|
||||
const alias = Config.services.playerAliases.find(a => a.from === player.identity);
|
||||
return alias?.to ?? player.identity;
|
||||
}
|
||||
function getIdentity(player: MprisPlayer): string {
|
||||
const alias = Config.services.playerAliases.find(a => a.from === player.identity);
|
||||
return alias?.to ?? player.identity;
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: active
|
||||
Connections {
|
||||
function onPostTrackChanged() {
|
||||
if (!Config.utilities.toasts.nowPlaying) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function onPostTrackChanged() {
|
||||
if (!Config.utilities.toasts.nowPlaying) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
target: active
|
||||
}
|
||||
|
||||
PersistentProperties {
|
||||
id: props
|
||||
PersistentProperties {
|
||||
id: props
|
||||
|
||||
property MprisPlayer manualActive
|
||||
property MprisPlayer manualActive
|
||||
|
||||
reloadableId: "players"
|
||||
}
|
||||
reloadableId: "players"
|
||||
}
|
||||
|
||||
CustomShortcut {
|
||||
name: "mediaToggle"
|
||||
description: "Toggle media playback"
|
||||
onPressed: {
|
||||
const active = root.active;
|
||||
if (active && active.canTogglePlaying)
|
||||
active.togglePlaying();
|
||||
}
|
||||
}
|
||||
CustomShortcut {
|
||||
description: "Toggle media playback"
|
||||
name: "mediaToggle"
|
||||
|
||||
CustomShortcut {
|
||||
name: "mediaPrev"
|
||||
description: "Previous track"
|
||||
onPressed: {
|
||||
const active = root.active;
|
||||
if (active && active.canGoPrevious)
|
||||
active.previous();
|
||||
}
|
||||
}
|
||||
onPressed: {
|
||||
const active = root.active;
|
||||
if (active && active.canTogglePlaying)
|
||||
active.togglePlaying();
|
||||
}
|
||||
}
|
||||
|
||||
CustomShortcut {
|
||||
name: "mediaNext"
|
||||
description: "Next track"
|
||||
onPressed: {
|
||||
const active = root.active;
|
||||
if (active && active.canGoNext)
|
||||
active.next();
|
||||
}
|
||||
}
|
||||
CustomShortcut {
|
||||
description: "Previous track"
|
||||
name: "mediaPrev"
|
||||
|
||||
CustomShortcut {
|
||||
name: "mediaStop"
|
||||
description: "Stop media playback"
|
||||
onPressed: root.active?.stop()
|
||||
}
|
||||
onPressed: {
|
||||
const active = root.active;
|
||||
if (active && active.canGoPrevious)
|
||||
active.previous();
|
||||
}
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
target: "mpris"
|
||||
CustomShortcut {
|
||||
description: "Next track"
|
||||
name: "mediaNext"
|
||||
|
||||
function getActive(prop: string): string {
|
||||
const active = root.active;
|
||||
return active ? active[prop] ?? "Invalid property" : "No active player";
|
||||
}
|
||||
onPressed: {
|
||||
const active = root.active;
|
||||
if (active && active.canGoNext)
|
||||
active.next();
|
||||
}
|
||||
}
|
||||
|
||||
function list(): string {
|
||||
return root.list.map(p => root.getIdentity(p)).join("\n");
|
||||
}
|
||||
CustomShortcut {
|
||||
description: "Stop media playback"
|
||||
name: "mediaStop"
|
||||
|
||||
function play(): void {
|
||||
const active = root.active;
|
||||
if (active?.canPlay)
|
||||
active.play();
|
||||
}
|
||||
onPressed: root.active?.stop()
|
||||
}
|
||||
|
||||
function pause(): void {
|
||||
const active = root.active;
|
||||
if (active?.canPause)
|
||||
active.pause();
|
||||
}
|
||||
IpcHandler {
|
||||
function getActive(prop: string): string {
|
||||
const active = root.active;
|
||||
return active ? active[prop] ?? "Invalid property" : "No active player";
|
||||
}
|
||||
|
||||
function playPause(): void {
|
||||
const active = root.active;
|
||||
if (active?.canTogglePlaying)
|
||||
active.togglePlaying();
|
||||
}
|
||||
function list(): string {
|
||||
return root.list.map(p => root.getIdentity(p)).join("\n");
|
||||
}
|
||||
|
||||
function previous(): void {
|
||||
const active = root.active;
|
||||
if (active?.canGoPrevious)
|
||||
active.previous();
|
||||
}
|
||||
function next(): void {
|
||||
const active = root.active;
|
||||
if (active?.canGoNext)
|
||||
active.next();
|
||||
}
|
||||
|
||||
function next(): void {
|
||||
const active = root.active;
|
||||
if (active?.canGoNext)
|
||||
active.next();
|
||||
}
|
||||
function pause(): void {
|
||||
const active = root.active;
|
||||
if (active?.canPause)
|
||||
active.pause();
|
||||
}
|
||||
|
||||
function stop(): void {
|
||||
root.active?.stop();
|
||||
}
|
||||
}
|
||||
function play(): void {
|
||||
const active = root.active;
|
||||
if (active?.canPlay)
|
||||
active.play();
|
||||
}
|
||||
|
||||
function playPause(): void {
|
||||
const active = root.active;
|
||||
if (active?.canTogglePlaying)
|
||||
active.togglePlaying();
|
||||
}
|
||||
|
||||
function previous(): void {
|
||||
const active = root.active;
|
||||
if (active?.canGoPrevious)
|
||||
active.previous();
|
||||
}
|
||||
|
||||
function stop(): void {
|
||||
root.active?.stop();
|
||||
}
|
||||
|
||||
target: "mpris"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,41 +9,41 @@ import qs.Helpers
|
||||
import qs.Paths
|
||||
|
||||
Searcher {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
property bool showPreview: false
|
||||
readonly property string current: showPreview ? previewPath : actualCurrent
|
||||
property string previewPath
|
||||
property string actualCurrent: WallpaperPath.currentWallpaperPath
|
||||
property string actualCurrent: WallpaperPath.currentWallpaperPath
|
||||
readonly property string current: showPreview ? previewPath : actualCurrent
|
||||
property string previewPath
|
||||
property bool showPreview: false
|
||||
|
||||
function setWallpaper(path: string): void {
|
||||
actualCurrent = path;
|
||||
WallpaperPath.currentWallpaperPath = path;
|
||||
function preview(path: string): void {
|
||||
previewPath = path;
|
||||
showPreview = true;
|
||||
}
|
||||
|
||||
function setWallpaper(path: string): void {
|
||||
actualCurrent = path;
|
||||
WallpaperPath.currentWallpaperPath = path;
|
||||
Quickshell.execDetached(["sh", "-c", `python3 ${Quickshell.shellPath("scripts/LockScreenBg.py")} --input_image=${root.actualCurrent} --output_path=${Paths.state}/lockscreen_bg.png`]);
|
||||
}
|
||||
}
|
||||
|
||||
function preview(path: string): void {
|
||||
previewPath = path;
|
||||
showPreview = true;
|
||||
}
|
||||
function stopPreview(): void {
|
||||
showPreview = false;
|
||||
Quickshell.execDetached(["sh", "-c", `python3 ${Quickshell.shellPath("scripts/SchemeColorGen.py")} --path=${root.actualCurrent} --thumbnail=${Paths.cache}/imagecache/thumbnail.jpg --output=${Paths.state}/scheme.json --scheme=${Config.colors.schemeType}`]);
|
||||
}
|
||||
|
||||
function stopPreview(): void {
|
||||
showPreview = false;
|
||||
Quickshell.execDetached(["sh", "-c", `python3 ${Quickshell.shellPath("scripts/SchemeColorGen.py")} --path=${root.actualCurrent} --thumbnail=${Paths.cache}/imagecache/thumbnail.jpg --output=${Paths.state}/scheme.json --scheme=${Config.colors.schemeType}`]);
|
||||
}
|
||||
extraOpts: useFuzzy ? ({}) : ({
|
||||
forward: false
|
||||
})
|
||||
key: "relativePath"
|
||||
list: wallpapers.entries
|
||||
useFuzzy: true
|
||||
|
||||
list: wallpapers.entries
|
||||
key: "relativePath"
|
||||
useFuzzy: true
|
||||
extraOpts: useFuzzy ? ({}) : ({
|
||||
forward: false
|
||||
})
|
||||
FileSystemModel {
|
||||
id: wallpapers
|
||||
|
||||
FileSystemModel {
|
||||
id: wallpapers
|
||||
|
||||
recursive: true
|
||||
path: Config.general.wallpaperPath
|
||||
filter: FileSystemModel.Images
|
||||
}
|
||||
filter: FileSystemModel.Images
|
||||
path: Config.general.wallpaperPath
|
||||
recursive: true
|
||||
}
|
||||
}
|
||||
|
||||
+41
-42
@@ -4,52 +4,51 @@ import "../scripts/fuzzysort.js" as Fuzzy
|
||||
import QtQuick
|
||||
|
||||
Singleton {
|
||||
required property list<QtObject> list
|
||||
property string key: "name"
|
||||
property bool useFuzzy: false
|
||||
property var extraOpts: ({})
|
||||
property var extraOpts: ({})
|
||||
readonly property list<var> fuzzyPrepped: useFuzzy ? list.map(e => {
|
||||
const obj = {
|
||||
_item: e
|
||||
};
|
||||
for (const k of keys)
|
||||
obj[k] = Fuzzy.prepare(e[k]);
|
||||
return obj;
|
||||
}) : []
|
||||
readonly property var fzf: useFuzzy ? [] : new Fzf.Finder(list, Object.assign({
|
||||
selector
|
||||
}, extraOpts))
|
||||
property string key: "name"
|
||||
|
||||
// Extra stuff for fuzzy
|
||||
property list<string> keys: [key]
|
||||
property list<real> weights: [1]
|
||||
// Extra stuff for fuzzy
|
||||
property list<string> keys: [key]
|
||||
required property list<QtObject> list
|
||||
property bool useFuzzy: false
|
||||
property list<real> weights: [1]
|
||||
|
||||
readonly property var fzf: useFuzzy ? [] : new Fzf.Finder(list, Object.assign({
|
||||
selector
|
||||
}, extraOpts))
|
||||
readonly property list<var> fuzzyPrepped: useFuzzy ? list.map(e => {
|
||||
const obj = {
|
||||
_item: e
|
||||
};
|
||||
for (const k of keys)
|
||||
obj[k] = Fuzzy.prepare(e[k]);
|
||||
return obj;
|
||||
}) : []
|
||||
function query(search: string): list<var> {
|
||||
search = transformSearch(search);
|
||||
if (!search)
|
||||
return [...list];
|
||||
|
||||
function transformSearch(search: string): string {
|
||||
return search;
|
||||
}
|
||||
if (useFuzzy)
|
||||
return Fuzzy.go(search, fuzzyPrepped, Object.assign({
|
||||
all: true,
|
||||
keys,
|
||||
scoreFn: r => weights.reduce((a, w, i) => a + r[i].score * w, 0)
|
||||
}, extraOpts)).map(r => r.obj._item);
|
||||
|
||||
function selector(item: var): string {
|
||||
// Only for fzf
|
||||
return item[key];
|
||||
}
|
||||
return fzf.find(search).sort((a, b) => {
|
||||
if (a.score === b.score)
|
||||
return selector(a.item).trim().length - selector(b.item).trim().length;
|
||||
return b.score - a.score;
|
||||
}).map(r => r.item);
|
||||
}
|
||||
|
||||
function query(search: string): list<var> {
|
||||
search = transformSearch(search);
|
||||
if (!search)
|
||||
return [...list];
|
||||
function selector(item: var): string {
|
||||
// Only for fzf
|
||||
return item[key];
|
||||
}
|
||||
|
||||
if (useFuzzy)
|
||||
return Fuzzy.go(search, fuzzyPrepped, Object.assign({
|
||||
all: true,
|
||||
keys,
|
||||
scoreFn: r => weights.reduce((a, w, i) => a + r[i].score * w, 0)
|
||||
}, extraOpts)).map(r => r.obj._item);
|
||||
|
||||
return fzf.find(search).sort((a, b) => {
|
||||
if (a.score === b.score)
|
||||
return selector(a.item).trim().length - selector(b.item).trim().length;
|
||||
return b.score - a.score;
|
||||
}).map(r => r.item);
|
||||
}
|
||||
function transformSearch(search: string): string {
|
||||
return search;
|
||||
}
|
||||
}
|
||||
|
||||
+63
-61
@@ -6,79 +6,81 @@ import Quickshell.Io
|
||||
import QtQuick
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
property string osName
|
||||
property string osPrettyName
|
||||
property string osId
|
||||
property list<string> osIdLike
|
||||
property string osLogo
|
||||
property bool isDefaultLogo: true
|
||||
property bool isDefaultLogo: true
|
||||
property string osId
|
||||
property list<string> osIdLike
|
||||
property string osLogo
|
||||
property string osName
|
||||
property string osPrettyName
|
||||
readonly property string shell: Quickshell.env("SHELL").split("/").pop()
|
||||
property string uptime
|
||||
readonly property string user: Quickshell.env("USER")
|
||||
readonly property string wm: Quickshell.env("XDG_CURRENT_DESKTOP") || Quickshell.env("XDG_SESSION_DESKTOP")
|
||||
|
||||
property string uptime
|
||||
readonly property string user: Quickshell.env("USER")
|
||||
readonly property string wm: Quickshell.env("XDG_CURRENT_DESKTOP") || Quickshell.env("XDG_SESSION_DESKTOP")
|
||||
readonly property string shell: Quickshell.env("SHELL").split("/").pop()
|
||||
FileView {
|
||||
id: osRelease
|
||||
|
||||
FileView {
|
||||
id: osRelease
|
||||
path: "/etc/os-release"
|
||||
|
||||
path: "/etc/os-release"
|
||||
onLoaded: {
|
||||
const lines = text().split("\n");
|
||||
onLoaded: {
|
||||
const lines = text().split("\n");
|
||||
|
||||
const fd = key => lines.find(l => l.startsWith(`${key}=`))?.split("=")[1].replace(/"/g, "") ?? "";
|
||||
const fd = key => lines.find(l => l.startsWith(`${key}=`))?.split("=")[1].replace(/"/g, "") ?? "";
|
||||
|
||||
root.osName = fd("NAME");
|
||||
root.osPrettyName = fd("PRETTY_NAME");
|
||||
root.osId = fd("ID");
|
||||
root.osIdLike = fd("ID_LIKE").split(" ");
|
||||
root.osName = fd("NAME");
|
||||
root.osPrettyName = fd("PRETTY_NAME");
|
||||
root.osId = fd("ID");
|
||||
root.osIdLike = fd("ID_LIKE").split(" ");
|
||||
|
||||
const logo = Quickshell.iconPath(fd("LOGO"), true);
|
||||
if (Config.general.logo) {
|
||||
root.osLogo = Quickshell.iconPath(Config.general.logo, true) || "file://" + Paths.absolutePath(Config.general.logo);
|
||||
root.isDefaultLogo = false;
|
||||
} else if (logo) {
|
||||
root.osLogo = logo;
|
||||
root.isDefaultLogo = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
const logo = Quickshell.iconPath(fd("LOGO"), true);
|
||||
if (Config.general.logo) {
|
||||
root.osLogo = Quickshell.iconPath(Config.general.logo, true) || "file://" + Paths.absolutePath(Config.general.logo);
|
||||
root.isDefaultLogo = false;
|
||||
} else if (logo) {
|
||||
root.osLogo = logo;
|
||||
root.isDefaultLogo = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Config.general
|
||||
Connections {
|
||||
function onLogoChanged(): void {
|
||||
osRelease.reload();
|
||||
}
|
||||
|
||||
function onLogoChanged(): void {
|
||||
osRelease.reload();
|
||||
}
|
||||
}
|
||||
target: Config.general
|
||||
}
|
||||
|
||||
Timer {
|
||||
running: true
|
||||
repeat: true
|
||||
interval: 15000
|
||||
onTriggered: fileUptime.reload()
|
||||
}
|
||||
Timer {
|
||||
interval: 15000
|
||||
repeat: true
|
||||
running: true
|
||||
|
||||
FileView {
|
||||
id: fileUptime
|
||||
onTriggered: fileUptime.reload()
|
||||
}
|
||||
|
||||
path: "/proc/uptime"
|
||||
onLoaded: {
|
||||
const up = parseInt(text().split(" ")[0] ?? 0);
|
||||
FileView {
|
||||
id: fileUptime
|
||||
|
||||
const days = Math.floor(up / 86400);
|
||||
const hours = Math.floor((up % 86400) / 3600);
|
||||
const minutes = Math.floor((up % 3600) / 60);
|
||||
path: "/proc/uptime"
|
||||
|
||||
let str = "";
|
||||
if (days > 0)
|
||||
str += `${days} day${days === 1 ? "" : "s"}`;
|
||||
if (hours > 0)
|
||||
str += `${str ? ", " : ""}${hours} hour${hours === 1 ? "" : "s"}`;
|
||||
if (minutes > 0 || !str)
|
||||
str += `${str ? ", " : ""}${minutes} minute${minutes === 1 ? "" : "s"}`;
|
||||
root.uptime = str;
|
||||
}
|
||||
}
|
||||
onLoaded: {
|
||||
const up = parseInt(text().split(" ")[0] ?? 0);
|
||||
|
||||
const days = Math.floor(up / 86400);
|
||||
const hours = Math.floor((up % 86400) / 3600);
|
||||
const minutes = Math.floor((up % 3600) / 60);
|
||||
|
||||
let str = "";
|
||||
if (days > 0)
|
||||
str += `${days} day${days === 1 ? "" : "s"}`;
|
||||
if (hours > 0)
|
||||
str += `${str ? ", " : ""}${hours} hour${hours === 1 ? "" : "s"}`;
|
||||
if (minutes > 0 || !str)
|
||||
str += `${str ? ", " : ""}${minutes} minute${minutes === 1 ? "" : "s"}`;
|
||||
root.uptime = str;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+200
-193
@@ -6,232 +6,239 @@ import QtQuick
|
||||
import qs.Config
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
property real cpuPerc
|
||||
property real cpuTemp
|
||||
readonly property string gpuType: Config.services.gpuType.toUpperCase() || autoGpuType
|
||||
property string autoGpuType: "NONE"
|
||||
property real gpuPerc
|
||||
property real gpuTemp
|
||||
property real gpuMemUsed
|
||||
property string autoGpuType: "NONE"
|
||||
property real cpuPerc
|
||||
property real cpuTemp
|
||||
property real gpuMemTotal: 0
|
||||
property real memUsed
|
||||
property real memTotal
|
||||
readonly property real memPerc: memTotal > 0 ? memUsed / memTotal : 0
|
||||
property real storageUsed
|
||||
property real storageTotal
|
||||
property real storagePerc: storageTotal > 0 ? storageUsed / storageTotal : 0
|
||||
property real gpuMemUsed
|
||||
property real gpuPerc
|
||||
property real gpuTemp
|
||||
readonly property string gpuType: Config.services.gpuType.toUpperCase() || autoGpuType
|
||||
property real lastCpuIdle
|
||||
property real lastCpuTotal
|
||||
readonly property real memPerc: memTotal > 0 ? memUsed / memTotal : 0
|
||||
property real memTotal
|
||||
property real memUsed
|
||||
property int refCount
|
||||
property real storagePerc: storageTotal > 0 ? storageUsed / storageTotal : 0
|
||||
property real storageTotal
|
||||
property real storageUsed
|
||||
|
||||
property real lastCpuIdle
|
||||
property real lastCpuTotal
|
||||
function formatKib(kib: real): var {
|
||||
const mib = 1024;
|
||||
const gib = 1024 ** 2;
|
||||
const tib = 1024 ** 3;
|
||||
|
||||
property int refCount
|
||||
if (kib >= tib)
|
||||
return {
|
||||
value: kib / tib,
|
||||
unit: "TiB"
|
||||
};
|
||||
if (kib >= gib)
|
||||
return {
|
||||
value: kib / gib,
|
||||
unit: "GiB"
|
||||
};
|
||||
if (kib >= mib)
|
||||
return {
|
||||
value: kib / mib,
|
||||
unit: "MiB"
|
||||
};
|
||||
return {
|
||||
value: kib,
|
||||
unit: "KiB"
|
||||
};
|
||||
}
|
||||
|
||||
function formatKib(kib: real): var {
|
||||
const mib = 1024;
|
||||
const gib = 1024 ** 2;
|
||||
const tib = 1024 ** 3;
|
||||
Timer {
|
||||
interval: 3000
|
||||
repeat: true
|
||||
running: root.refCount > 0
|
||||
triggeredOnStart: true
|
||||
|
||||
if (kib >= tib)
|
||||
return {
|
||||
value: kib / tib,
|
||||
unit: "TiB"
|
||||
};
|
||||
if (kib >= gib)
|
||||
return {
|
||||
value: kib / gib,
|
||||
unit: "GiB"
|
||||
};
|
||||
if (kib >= mib)
|
||||
return {
|
||||
value: kib / mib,
|
||||
unit: "MiB"
|
||||
};
|
||||
return {
|
||||
value: kib,
|
||||
unit: "KiB"
|
||||
};
|
||||
}
|
||||
onTriggered: {
|
||||
stat.reload();
|
||||
meminfo.reload();
|
||||
storage.running = true;
|
||||
gpuUsage.running = true;
|
||||
sensors.running = true;
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
running: root.refCount > 0
|
||||
interval: 3000
|
||||
repeat: true
|
||||
triggeredOnStart: true
|
||||
onTriggered: {
|
||||
stat.reload();
|
||||
meminfo.reload();
|
||||
storage.running = true;
|
||||
gpuUsage.running = true;
|
||||
sensors.running = true;
|
||||
}
|
||||
}
|
||||
FileView {
|
||||
id: stat
|
||||
|
||||
FileView {
|
||||
id: stat
|
||||
path: "/proc/stat"
|
||||
|
||||
path: "/proc/stat"
|
||||
onLoaded: {
|
||||
const data = text().match(/^cpu\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/);
|
||||
if (data) {
|
||||
const stats = data.slice(1).map(n => parseInt(n, 10));
|
||||
const total = stats.reduce((a, b) => a + b, 0);
|
||||
const idle = stats[3] + (stats[4] ?? 0);
|
||||
onLoaded: {
|
||||
const data = text().match(/^cpu\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/);
|
||||
if (data) {
|
||||
const stats = data.slice(1).map(n => parseInt(n, 10));
|
||||
const total = stats.reduce((a, b) => a + b, 0);
|
||||
const idle = stats[3] + (stats[4] ?? 0);
|
||||
|
||||
const totalDiff = total - root.lastCpuTotal;
|
||||
const idleDiff = idle - root.lastCpuIdle;
|
||||
root.cpuPerc = totalDiff > 0 ? (1 - idleDiff / totalDiff) : 0;
|
||||
const totalDiff = total - root.lastCpuTotal;
|
||||
const idleDiff = idle - root.lastCpuIdle;
|
||||
root.cpuPerc = totalDiff > 0 ? (1 - idleDiff / totalDiff) : 0;
|
||||
|
||||
root.lastCpuTotal = total;
|
||||
root.lastCpuIdle = idle;
|
||||
}
|
||||
}
|
||||
}
|
||||
root.lastCpuTotal = total;
|
||||
root.lastCpuIdle = idle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FileView {
|
||||
id: meminfo
|
||||
FileView {
|
||||
id: meminfo
|
||||
|
||||
path: "/proc/meminfo"
|
||||
onLoaded: {
|
||||
const data = text();
|
||||
root.memTotal = parseInt(data.match(/MemTotal: *(\d+)/)[1], 10) || 1;
|
||||
root.memUsed = (root.memTotal - parseInt(data.match(/MemAvailable: *(\d+)/)[1], 10)) || 0;
|
||||
}
|
||||
}
|
||||
path: "/proc/meminfo"
|
||||
|
||||
Process {
|
||||
id: storage
|
||||
onLoaded: {
|
||||
const data = text();
|
||||
root.memTotal = parseInt(data.match(/MemTotal: *(\d+)/)[1], 10) || 1;
|
||||
root.memUsed = (root.memTotal - parseInt(data.match(/MemAvailable: *(\d+)/)[1], 10)) || 0;
|
||||
}
|
||||
}
|
||||
|
||||
command: ["sh", "-c", "df | grep '^/dev/' | awk '{print $1, $3, $4}'"]
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
const deviceMap = new Map();
|
||||
Process {
|
||||
id: storage
|
||||
|
||||
for (const line of text.trim().split("\n")) {
|
||||
if (line.trim() === "")
|
||||
continue;
|
||||
command: ["sh", "-c", "df | grep '^/dev/' | awk '{print $1, $3, $4}'"]
|
||||
|
||||
const parts = line.trim().split(/\s+/);
|
||||
if (parts.length >= 3) {
|
||||
const device = parts[0];
|
||||
const used = parseInt(parts[1], 10) || 0;
|
||||
const avail = parseInt(parts[2], 10) || 0;
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
const deviceMap = new Map();
|
||||
|
||||
// Only keep the entry with the largest total space for each device
|
||||
if (!deviceMap.has(device) || (used + avail) > (deviceMap.get(device).used + deviceMap.get(device).avail)) {
|
||||
deviceMap.set(device, {
|
||||
used: used,
|
||||
avail: avail
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const line of text.trim().split("\n")) {
|
||||
if (line.trim() === "")
|
||||
continue;
|
||||
|
||||
let totalUsed = 0;
|
||||
let totalAvail = 0;
|
||||
const parts = line.trim().split(/\s+/);
|
||||
if (parts.length >= 3) {
|
||||
const device = parts[0];
|
||||
const used = parseInt(parts[1], 10) || 0;
|
||||
const avail = parseInt(parts[2], 10) || 0;
|
||||
|
||||
for (const [device, stats] of deviceMap) {
|
||||
totalUsed += stats.used;
|
||||
totalAvail += stats.avail;
|
||||
}
|
||||
// Only keep the entry with the largest total space for each device
|
||||
if (!deviceMap.has(device) || (used + avail) > (deviceMap.get(device).used + deviceMap.get(device).avail)) {
|
||||
deviceMap.set(device, {
|
||||
used: used,
|
||||
avail: avail
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
root.storageUsed = totalUsed;
|
||||
root.storageTotal = totalUsed + totalAvail;
|
||||
}
|
||||
}
|
||||
}
|
||||
let totalUsed = 0;
|
||||
let totalAvail = 0;
|
||||
|
||||
Process {
|
||||
id: gpuTypeCheck
|
||||
for (const [device, stats] of deviceMap) {
|
||||
totalUsed += stats.used;
|
||||
totalAvail += stats.avail;
|
||||
}
|
||||
|
||||
running: !Config.services.gpuType
|
||||
command: ["sh", "-c", "if command -v nvidia-smi &>/dev/null && nvidia-smi -L &>/dev/null; then echo NVIDIA; elif ls /sys/class/drm/card*/device/gpu_busy_percent 2>/dev/null | grep -q .; then echo GENERIC; else echo NONE; fi"]
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: root.autoGpuType = text.trim()
|
||||
}
|
||||
}
|
||||
root.storageUsed = totalUsed;
|
||||
root.storageTotal = totalUsed + totalAvail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: oneshotMem
|
||||
command: ["nvidia-smi", "--query-gpu=memory.total", "--format=csv,noheader,nounits"]
|
||||
running: root.gpuType === "NVIDIA" && root.gpuMemTotal === 0
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
root.gpuMemTotal = Number(this.text.trim())
|
||||
oneshotMem.running = false
|
||||
}
|
||||
}
|
||||
}
|
||||
Process {
|
||||
id: gpuTypeCheck
|
||||
|
||||
Process {
|
||||
id: gpuUsage
|
||||
command: ["sh", "-c", "if command -v nvidia-smi &>/dev/null && nvidia-smi -L &>/dev/null; then echo NVIDIA; elif ls /sys/class/drm/card*/device/gpu_busy_percent 2>/dev/null | grep -q .; then echo GENERIC; else echo NONE; fi"]
|
||||
running: !Config.services.gpuType
|
||||
|
||||
command: root.gpuType === "GENERIC" ? ["sh", "-c", "cat /sys/class/drm/card*/device/gpu_busy_percent"] : root.gpuType === "NVIDIA" ? ["nvidia-smi", "--query-gpu=utilization.gpu,temperature.gpu,memory.used", "--format=csv,noheader,nounits"] : ["echo"]
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
if (root.gpuType === "GENERIC") {
|
||||
const percs = text.trim().split("\n");
|
||||
const sum = percs.reduce((acc, d) => acc + parseInt(d, 10), 0);
|
||||
root.gpuPerc = sum / percs.length / 100;
|
||||
} else if (root.gpuType === "NVIDIA") {
|
||||
const [usage, temp, mem] = text.trim().split(",");
|
||||
root.gpuPerc = parseInt(usage, 10) / 100;
|
||||
root.gpuTemp = parseInt(temp, 10);
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: root.autoGpuType = text.trim()
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: oneshotMem
|
||||
|
||||
command: ["nvidia-smi", "--query-gpu=memory.total", "--format=csv,noheader,nounits"]
|
||||
running: root.gpuType === "NVIDIA" && root.gpuMemTotal === 0
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
root.gpuMemTotal = Number(this.text.trim());
|
||||
oneshotMem.running = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: gpuUsage
|
||||
|
||||
command: root.gpuType === "GENERIC" ? ["sh", "-c", "cat /sys/class/drm/card*/device/gpu_busy_percent"] : root.gpuType === "NVIDIA" ? ["nvidia-smi", "--query-gpu=utilization.gpu,temperature.gpu,memory.used", "--format=csv,noheader,nounits"] : ["echo"]
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
if (root.gpuType === "GENERIC") {
|
||||
const percs = text.trim().split("\n");
|
||||
const sum = percs.reduce((acc, d) => acc + parseInt(d, 10), 0);
|
||||
root.gpuPerc = sum / percs.length / 100;
|
||||
} else if (root.gpuType === "NVIDIA") {
|
||||
const [usage, temp, mem] = text.trim().split(",");
|
||||
root.gpuPerc = parseInt(usage, 10) / 100;
|
||||
root.gpuTemp = parseInt(temp, 10);
|
||||
root.gpuMemUsed = parseInt(mem, 10) / root.gpuMemTotal;
|
||||
} else {
|
||||
root.gpuPerc = 0;
|
||||
root.gpuTemp = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
root.gpuPerc = 0;
|
||||
root.gpuTemp = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: sensors
|
||||
Process {
|
||||
id: sensors
|
||||
|
||||
command: ["sensors"]
|
||||
environment: ({
|
||||
LANG: "C.UTF-8",
|
||||
LC_ALL: "C.UTF-8"
|
||||
})
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
let cpuTemp = text.match(/(?:Package id [0-9]+|Tdie):\s+((\+|-)[0-9.]+)(°| )C/);
|
||||
if (!cpuTemp)
|
||||
// If AMD Tdie pattern failed, try fallback on Tctl
|
||||
cpuTemp = text.match(/Tctl:\s+((\+|-)[0-9.]+)(°| )C/);
|
||||
command: ["sensors"]
|
||||
environment: ({
|
||||
LANG: "C.UTF-8",
|
||||
LC_ALL: "C.UTF-8"
|
||||
})
|
||||
|
||||
if (cpuTemp)
|
||||
root.cpuTemp = parseFloat(cpuTemp[1]);
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
let cpuTemp = text.match(/(?:Package id [0-9]+|Tdie):\s+((\+|-)[0-9.]+)(°| )C/);
|
||||
if (!cpuTemp)
|
||||
// If AMD Tdie pattern failed, try fallback on Tctl
|
||||
cpuTemp = text.match(/Tctl:\s+((\+|-)[0-9.]+)(°| )C/);
|
||||
|
||||
if (root.gpuType !== "GENERIC")
|
||||
return;
|
||||
if (cpuTemp)
|
||||
root.cpuTemp = parseFloat(cpuTemp[1]);
|
||||
|
||||
let eligible = false;
|
||||
let sum = 0;
|
||||
let count = 0;
|
||||
if (root.gpuType !== "GENERIC")
|
||||
return;
|
||||
|
||||
for (const line of text.trim().split("\n")) {
|
||||
if (line === "Adapter: PCI adapter")
|
||||
eligible = true;
|
||||
else if (line === "")
|
||||
eligible = false;
|
||||
else if (eligible) {
|
||||
let match = line.match(/^(temp[0-9]+|GPU core|edge)+:\s+\+([0-9]+\.[0-9]+)(°| )C/);
|
||||
if (!match)
|
||||
// Fall back to junction/mem if GPU doesn't have edge temp (for AMD GPUs)
|
||||
match = line.match(/^(junction|mem)+:\s+\+([0-9]+\.[0-9]+)(°| )C/);
|
||||
let eligible = false;
|
||||
let sum = 0;
|
||||
let count = 0;
|
||||
|
||||
if (match) {
|
||||
sum += parseFloat(match[2]);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const line of text.trim().split("\n")) {
|
||||
if (line === "Adapter: PCI adapter")
|
||||
eligible = true;
|
||||
else if (line === "")
|
||||
eligible = false;
|
||||
else if (eligible) {
|
||||
let match = line.match(/^(temp[0-9]+|GPU core|edge)+:\s+\+([0-9]+\.[0-9]+)(°| )C/);
|
||||
if (!match)
|
||||
// Fall back to junction/mem if GPU doesn't have edge temp (for AMD GPUs)
|
||||
match = line.match(/^(junction|mem)+:\s+\+([0-9]+\.[0-9]+)(°| )C/);
|
||||
|
||||
root.gpuTemp = count > 0 ? sum / count : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
sum += parseFloat(match[2]);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
root.gpuTemp = count > 0 ? sum / count : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import QtQuick
|
||||
|
||||
Text {
|
||||
renderType: Text.NativeRendering
|
||||
textFormat: Text.PlainText
|
||||
renderType: Text.NativeRendering
|
||||
textFormat: Text.PlainText
|
||||
}
|
||||
|
||||
+189
-187
@@ -6,6 +6,30 @@ import Quickshell
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
property list<DesktopEntry> entryList: []
|
||||
property var preppedIcons: []
|
||||
property var preppedIds: []
|
||||
property var preppedNames: []
|
||||
|
||||
// Dynamic fixups
|
||||
property var regexSubstitutions: [
|
||||
{
|
||||
"regex": /^steam_app_(\d+)$/,
|
||||
"replace": "steam_icon_$1"
|
||||
},
|
||||
{
|
||||
"regex": /Minecraft.*/,
|
||||
"replace": "minecraft-launcher"
|
||||
},
|
||||
{
|
||||
"regex": /.*polkit.*/,
|
||||
"replace": "system-lock-screen"
|
||||
},
|
||||
{
|
||||
"regex": /gcr.prompter/,
|
||||
"replace": "system-lock-screen"
|
||||
}
|
||||
]
|
||||
property real scoreThreshold: 0.2
|
||||
|
||||
// Manual overrides for tricky apps
|
||||
@@ -17,178 +41,23 @@ Singleton {
|
||||
"wps": "wps-office2019-kprometheus",
|
||||
"wpsoffice": "wps-office2019-kprometheus",
|
||||
"footclient": "foot"
|
||||
})
|
||||
})
|
||||
|
||||
// Dynamic fixups
|
||||
property var regexSubstitutions: [
|
||||
{
|
||||
"regex": /^steam_app_(\d+)$/,
|
||||
"replace": "steam_icon_$1"
|
||||
},
|
||||
{
|
||||
"regex": /Minecraft.*/,
|
||||
"replace": "minecraft-launcher"
|
||||
},
|
||||
{
|
||||
"regex": /.*polkit.*/,
|
||||
"replace": "system-lock-screen"
|
||||
},
|
||||
{
|
||||
"regex": /gcr.prompter/,
|
||||
"replace": "system-lock-screen"
|
||||
}
|
||||
]
|
||||
|
||||
property list<DesktopEntry> entryList: []
|
||||
property var preppedNames: []
|
||||
property var preppedIcons: []
|
||||
property var preppedIds: []
|
||||
|
||||
Component.onCompleted: refreshEntries()
|
||||
|
||||
Connections {
|
||||
target: DesktopEntries.applications
|
||||
function onValuesChanged() {
|
||||
refreshEntries();
|
||||
}
|
||||
}
|
||||
|
||||
function refreshEntries() {
|
||||
if (typeof DesktopEntries === 'undefined')
|
||||
return;
|
||||
|
||||
const values = Array.from(DesktopEntries.applications.values);
|
||||
if (values) {
|
||||
entryList = values.sort((a, b) => a.name.localeCompare(b.name));
|
||||
updatePreppedData();
|
||||
}
|
||||
}
|
||||
|
||||
function updatePreppedData() {
|
||||
if (typeof FuzzySort === 'undefined')
|
||||
return;
|
||||
|
||||
const list = Array.from(entryList);
|
||||
preppedNames = list.map(a => ({
|
||||
name: FuzzySort.prepare(`${a.name} `), entry: a}));
|
||||
preppedIcons = list.map(a => ({
|
||||
name: FuzzySort.prepare(`${a.icon} `),
|
||||
entry: a
|
||||
}));
|
||||
preppedIds = list.map(a => ({
|
||||
name: FuzzySort.prepare(`${a.id} `),
|
||||
entry: a
|
||||
}));
|
||||
}
|
||||
|
||||
function iconForAppId(appId, fallbackName) {
|
||||
const fallback = fallbackName || "application-x-executable";
|
||||
if (!appId)
|
||||
return iconFromName(fallback, fallback);
|
||||
|
||||
const entry = findAppEntry(appId);
|
||||
if (entry) {
|
||||
return iconFromName(entry.icon, fallback);
|
||||
}
|
||||
|
||||
return iconFromName(appId, fallback);
|
||||
}
|
||||
|
||||
// Robust lookup strategy
|
||||
function findAppEntry(str) {
|
||||
if (!str || str.length === 0)
|
||||
function checkCleanMatch(str) {
|
||||
if (!str || str.length <= 3)
|
||||
return null;
|
||||
|
||||
let result = null;
|
||||
|
||||
if (result = checkHeuristic(str))
|
||||
return result;
|
||||
if (result = checkSubstitutions(str))
|
||||
return result;
|
||||
if (result = checkRegex(str))
|
||||
return result;
|
||||
if (result = checkSimpleTransforms(str))
|
||||
return result;
|
||||
if (result = checkFuzzySearch(str))
|
||||
return result;
|
||||
if (result = checkCleanMatch(str))
|
||||
return result;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function iconFromName(iconName, fallbackName) {
|
||||
const fallback = fallbackName || "application-x-executable";
|
||||
try {
|
||||
if (iconName && typeof Quickshell !== 'undefined' && Quickshell.iconPath) {
|
||||
const p = Quickshell.iconPath(iconName, fallback);
|
||||
if (p && p !== "")
|
||||
return p;
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
try {
|
||||
return Quickshell.iconPath ? (Quickshell.iconPath(fallback, true) || "") : "";
|
||||
} catch (e2) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
function distroLogoPath() {
|
||||
try {
|
||||
return (typeof OSInfo !== 'undefined' && OSInfo.distroIconPath) ? OSInfo.distroIconPath : "";
|
||||
} catch (e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
// --- Lookup Helpers ---
|
||||
|
||||
function checkHeuristic(str) {
|
||||
if (typeof DesktopEntries !== 'undefined' && DesktopEntries.heuristicLookup) {
|
||||
const entry = DesktopEntries.heuristicLookup(str);
|
||||
if (entry)
|
||||
return entry;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function checkSubstitutions(str) {
|
||||
let effectiveStr = substitutions[str];
|
||||
if (!effectiveStr)
|
||||
effectiveStr = substitutions[str.toLowerCase()];
|
||||
|
||||
if (effectiveStr && effectiveStr !== str) {
|
||||
return findAppEntry(effectiveStr);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function checkRegex(str) {
|
||||
for (let i = 0; i < regexSubstitutions.length; i++) {
|
||||
const sub = regexSubstitutions[i];
|
||||
const replaced = str.replace(sub.regex, sub.replace);
|
||||
if (replaced !== str) {
|
||||
return findAppEntry(replaced);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function checkSimpleTransforms(str) {
|
||||
if (typeof DesktopEntries === 'undefined' || !DesktopEntries.byId)
|
||||
return null;
|
||||
|
||||
const lower = str.toLowerCase();
|
||||
// Aggressive fallback: strip all separators
|
||||
const cleanStr = str.toLowerCase().replace(/[\.\-_]/g, '');
|
||||
const list = Array.from(entryList);
|
||||
|
||||
const variants = [str, lower, getFromReverseDomain(str), getFromReverseDomain(str)?.toLowerCase(), normalizeWithHyphens(str), str.replace(/_/g, '-').toLowerCase(), str.replace(/-/g, '_').toLowerCase()];
|
||||
|
||||
for (let i = 0; i < variants.length; i++) {
|
||||
const variant = variants[i];
|
||||
if (variant) {
|
||||
const entry = DesktopEntries.byId(variant);
|
||||
if (entry)
|
||||
return entry;
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
const entry = list[i];
|
||||
const cleanId = (entry.id || "").toLowerCase().replace(/[\.\-_]/g, '');
|
||||
if (cleanId.includes(cleanStr) || cleanStr.includes(cleanId)) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -227,33 +96,108 @@ Singleton {
|
||||
return null;
|
||||
}
|
||||
|
||||
function checkCleanMatch(str) {
|
||||
if (!str || str.length <= 3)
|
||||
return null;
|
||||
// --- Lookup Helpers ---
|
||||
|
||||
function checkHeuristic(str) {
|
||||
if (typeof DesktopEntries !== 'undefined' && DesktopEntries.heuristicLookup) {
|
||||
const entry = DesktopEntries.heuristicLookup(str);
|
||||
if (entry)
|
||||
return entry;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function checkRegex(str) {
|
||||
for (let i = 0; i < regexSubstitutions.length; i++) {
|
||||
const sub = regexSubstitutions[i];
|
||||
const replaced = str.replace(sub.regex, sub.replace);
|
||||
if (replaced !== str) {
|
||||
return findAppEntry(replaced);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function checkSimpleTransforms(str) {
|
||||
if (typeof DesktopEntries === 'undefined' || !DesktopEntries.byId)
|
||||
return null;
|
||||
|
||||
// Aggressive fallback: strip all separators
|
||||
const cleanStr = str.toLowerCase().replace(/[\.\-_]/g, '');
|
||||
const list = Array.from(entryList);
|
||||
const lower = str.toLowerCase();
|
||||
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
const entry = list[i];
|
||||
const cleanId = (entry.id || "").toLowerCase().replace(/[\.\-_]/g, '');
|
||||
if (cleanId.includes(cleanStr) || cleanStr.includes(cleanId)) {
|
||||
return entry;
|
||||
const variants = [str, lower, getFromReverseDomain(str), getFromReverseDomain(str)?.toLowerCase(), normalizeWithHyphens(str), str.replace(/_/g, '-').toLowerCase(), str.replace(/-/g, '_').toLowerCase()];
|
||||
|
||||
for (let i = 0; i < variants.length; i++) {
|
||||
const variant = variants[i];
|
||||
if (variant) {
|
||||
const entry = DesktopEntries.byId(variant);
|
||||
if (entry)
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function checkSubstitutions(str) {
|
||||
let effectiveStr = substitutions[str];
|
||||
if (!effectiveStr)
|
||||
effectiveStr = substitutions[str.toLowerCase()];
|
||||
|
||||
if (effectiveStr && effectiveStr !== str) {
|
||||
return findAppEntry(effectiveStr);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function distroLogoPath() {
|
||||
try {
|
||||
return (typeof OSInfo !== 'undefined' && OSInfo.distroIconPath) ? OSInfo.distroIconPath : "";
|
||||
} catch (e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
// Robust lookup strategy
|
||||
function findAppEntry(str) {
|
||||
if (!str || str.length === 0)
|
||||
return null;
|
||||
|
||||
let result = null;
|
||||
|
||||
if (result = checkHeuristic(str))
|
||||
return result;
|
||||
if (result = checkSubstitutions(str))
|
||||
return result;
|
||||
if (result = checkRegex(str))
|
||||
return result;
|
||||
if (result = checkSimpleTransforms(str))
|
||||
return result;
|
||||
if (result = checkFuzzySearch(str))
|
||||
return result;
|
||||
if (result = checkCleanMatch(str))
|
||||
return result;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function fuzzyQuery(search, preppedData) {
|
||||
if (!search || !preppedData || preppedData.length === 0)
|
||||
return [];
|
||||
return FuzzySort.go(search, preppedData, {
|
||||
all: true,
|
||||
key: "name"
|
||||
}).map(r => r.obj.entry);
|
||||
all: true,
|
||||
key: "name"
|
||||
}).map(r => r.obj.entry);
|
||||
}
|
||||
|
||||
function getFromReverseDomain(str) {
|
||||
if (!str)
|
||||
return "";
|
||||
return str.split('.').slice(-1)[0];
|
||||
}
|
||||
|
||||
// Deprecated shim
|
||||
function guessIcon(str) {
|
||||
const entry = findAppEntry(str);
|
||||
return entry ? entry.icon : "image-missing";
|
||||
}
|
||||
|
||||
function iconExists(iconName) {
|
||||
@@ -266,10 +210,34 @@ Singleton {
|
||||
return path && path.length > 0 && !path.includes("image-missing");
|
||||
}
|
||||
|
||||
function getFromReverseDomain(str) {
|
||||
if (!str)
|
||||
function iconForAppId(appId, fallbackName) {
|
||||
const fallback = fallbackName || "application-x-executable";
|
||||
if (!appId)
|
||||
return iconFromName(fallback, fallback);
|
||||
|
||||
const entry = findAppEntry(appId);
|
||||
if (entry) {
|
||||
return iconFromName(entry.icon, fallback);
|
||||
}
|
||||
|
||||
return iconFromName(appId, fallback);
|
||||
}
|
||||
|
||||
function iconFromName(iconName, fallbackName) {
|
||||
const fallback = fallbackName || "application-x-executable";
|
||||
try {
|
||||
if (iconName && typeof Quickshell !== 'undefined' && Quickshell.iconPath) {
|
||||
const p = Quickshell.iconPath(iconName, fallback);
|
||||
if (p && p !== "")
|
||||
return p;
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
try {
|
||||
return Quickshell.iconPath ? (Quickshell.iconPath(fallback, true) || "") : "";
|
||||
} catch (e2) {
|
||||
return "";
|
||||
return str.split('.').slice(-1)[0];
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeWithHyphens(str) {
|
||||
@@ -278,9 +246,43 @@ Singleton {
|
||||
return str.toLowerCase().replace(/\s+/g, "-");
|
||||
}
|
||||
|
||||
// Deprecated shim
|
||||
function guessIcon(str) {
|
||||
const entry = findAppEntry(str);
|
||||
return entry ? entry.icon : "image-missing";
|
||||
function refreshEntries() {
|
||||
if (typeof DesktopEntries === 'undefined')
|
||||
return;
|
||||
|
||||
const values = Array.from(DesktopEntries.applications.values);
|
||||
if (values) {
|
||||
entryList = values.sort((a, b) => a.name.localeCompare(b.name));
|
||||
updatePreppedData();
|
||||
}
|
||||
}
|
||||
|
||||
function updatePreppedData() {
|
||||
if (typeof FuzzySort === 'undefined')
|
||||
return;
|
||||
|
||||
const list = Array.from(entryList);
|
||||
preppedNames = list.map(a => ({
|
||||
name: FuzzySort.prepare(`${a.name} `),
|
||||
entry: a
|
||||
}));
|
||||
preppedIcons = list.map(a => ({
|
||||
name: FuzzySort.prepare(`${a.icon} `),
|
||||
entry: a
|
||||
}));
|
||||
preppedIds = list.map(a => ({
|
||||
name: FuzzySort.prepare(`${a.id} `),
|
||||
entry: a
|
||||
}));
|
||||
}
|
||||
|
||||
Component.onCompleted: refreshEntries()
|
||||
|
||||
Connections {
|
||||
function onValuesChanged() {
|
||||
refreshEntries();
|
||||
}
|
||||
|
||||
target: DesktopEntries.applications
|
||||
}
|
||||
}
|
||||
|
||||
+17
-17
@@ -3,24 +3,24 @@ pragma Singleton
|
||||
import Quickshell
|
||||
|
||||
Singleton {
|
||||
property alias enabled: clock.enabled
|
||||
readonly property date date: clock.date
|
||||
readonly property int hours: clock.hours
|
||||
readonly property int minutes: clock.minutes
|
||||
readonly property int seconds: clock.seconds
|
||||
readonly property string amPmStr: timeComponents[2] ?? ""
|
||||
readonly property date date: clock.date
|
||||
property alias enabled: clock.enabled
|
||||
readonly property string hourStr: timeComponents[0] ?? ""
|
||||
readonly property int hours: clock.hours
|
||||
readonly property string minuteStr: timeComponents[1] ?? ""
|
||||
readonly property int minutes: clock.minutes
|
||||
readonly property int seconds: clock.seconds
|
||||
readonly property list<string> timeComponents: timeStr.split(":")
|
||||
readonly property string timeStr: format("hh:mm")
|
||||
|
||||
readonly property string timeStr: format("hh:mm")
|
||||
readonly property list<string> timeComponents: timeStr.split(":")
|
||||
readonly property string hourStr: timeComponents[0] ?? ""
|
||||
readonly property string minuteStr: timeComponents[1] ?? ""
|
||||
readonly property string amPmStr: timeComponents[2] ?? ""
|
||||
function format(fmt: string): string {
|
||||
return Qt.formatDateTime(clock.date, fmt);
|
||||
}
|
||||
|
||||
function format(fmt: string): string {
|
||||
return Qt.formatDateTime(clock.date, fmt);
|
||||
}
|
||||
SystemClock {
|
||||
id: clock
|
||||
|
||||
SystemClock {
|
||||
id: clock
|
||||
precision: SystemClock.Seconds
|
||||
}
|
||||
precision: SystemClock.Seconds
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -3,11 +3,10 @@ pragma Singleton
|
||||
import Quickshell
|
||||
import Quickshell.Services.UPower
|
||||
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
readonly property list<UPowerDevice> devices: UPower.devices.values
|
||||
readonly property bool onBattery: UPower.onBattery
|
||||
readonly property UPowerDevice displayDevice: UPower.displayDevice
|
||||
readonly property bool onBattery: UPower.onBattery
|
||||
}
|
||||
|
||||
@@ -3,14 +3,14 @@ pragma Singleton
|
||||
import Quickshell
|
||||
|
||||
Singleton {
|
||||
property var screens: new Map()
|
||||
property var bars: new Map()
|
||||
property var bars: new Map()
|
||||
property var screens: new Map()
|
||||
|
||||
function load(screen: ShellScreen, visibilities: var): void {
|
||||
screens.set(Hypr.monitorFor(screen), visibilities);
|
||||
}
|
||||
function getForActive(): PersistentProperties {
|
||||
return screens.get(Hypr.focusedMonitor);
|
||||
}
|
||||
|
||||
function getForActive(): PersistentProperties {
|
||||
return screens.get(Hypr.focusedMonitor);
|
||||
}
|
||||
function load(screen: ShellScreen, visibilities: var): void {
|
||||
screens.set(Hypr.monitorFor(screen), visibilities);
|
||||
}
|
||||
}
|
||||
|
||||
+16
-13
@@ -5,22 +5,25 @@ import Quickshell.Io
|
||||
import qs.Paths
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
property alias currentWallpaperPath: adapter.currentWallpaperPath
|
||||
property alias currentWallpaperPath: adapter.currentWallpaperPath
|
||||
property alias lockscreenBg: adapter.lockscreenBg
|
||||
|
||||
FileView {
|
||||
id: fileView
|
||||
path: `${Paths.state}/wallpaper_path.json`
|
||||
FileView {
|
||||
id: fileView
|
||||
|
||||
watchChanges: true
|
||||
onFileChanged: reload()
|
||||
onAdapterUpdated: writeAdapter()
|
||||
JsonAdapter {
|
||||
id: adapter
|
||||
property string currentWallpaperPath: ""
|
||||
path: `${Paths.state}/wallpaper_path.json`
|
||||
watchChanges: true
|
||||
|
||||
onAdapterUpdated: writeAdapter()
|
||||
onFileChanged: reload()
|
||||
|
||||
JsonAdapter {
|
||||
id: adapter
|
||||
|
||||
property string currentWallpaperPath: ""
|
||||
property string lockscreenBg: `${Paths.state}/lockscreen_bg.png`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+35
-35
@@ -9,54 +9,54 @@ import qs.Helpers
|
||||
import qs.Paths
|
||||
|
||||
Searcher {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
property bool showPreview: false
|
||||
readonly property string current: showPreview ? previewPath : actualCurrent
|
||||
property string previewPath
|
||||
property string actualCurrent: WallpaperPath.currentWallpaperPath
|
||||
property string actualCurrent: WallpaperPath.currentWallpaperPath
|
||||
readonly property string current: showPreview ? previewPath : actualCurrent
|
||||
property string previewPath
|
||||
property bool showPreview: false
|
||||
|
||||
function setWallpaper(path: string): void {
|
||||
actualCurrent = path;
|
||||
WallpaperPath.currentWallpaperPath = path;
|
||||
if ( Config.general.color.wallust )
|
||||
function preview(path: string): void {
|
||||
previewPath = path;
|
||||
if (Config.general.color.schemeGeneration)
|
||||
Quickshell.execDetached(["sh", "-c", `zshell-cli scheme generate --image-path ${previewPath} --thumbnail-path ${Paths.cache}/imagecache/thumbnail.jpg --output ${Paths.state}/scheme.json --scheme ${Config.colors.schemeType} --mode ${Config.general.color.mode}`]);
|
||||
showPreview = true;
|
||||
}
|
||||
|
||||
function setWallpaper(path: string): void {
|
||||
actualCurrent = path;
|
||||
WallpaperPath.currentWallpaperPath = path;
|
||||
if (Config.general.color.wallust)
|
||||
Wallust.generateColors(WallpaperPath.currentWallpaperPath);
|
||||
Quickshell.execDetached(["sh", "-c", `zshell-cli wallpaper lockscreen --input-image=${root.actualCurrent} --output-path=${Paths.state}/lockscreen_bg.png --blur-amount=${Config.lock.blurAmount}`]);
|
||||
}
|
||||
}
|
||||
|
||||
function preview(path: string): void {
|
||||
previewPath = path;
|
||||
if ( Config.general.color.schemeGeneration )
|
||||
Quickshell.execDetached(["sh", "-c", `zshell-cli scheme generate --image-path ${previewPath} --thumbnail-path ${Paths.cache}/imagecache/thumbnail.jpg --output ${Paths.state}/scheme.json --scheme ${Config.colors.schemeType} --mode ${Config.general.color.mode}`]);
|
||||
showPreview = true;
|
||||
}
|
||||
|
||||
function stopPreview(): void {
|
||||
showPreview = false;
|
||||
if ( Config.general.color.schemeGeneration )
|
||||
function stopPreview(): void {
|
||||
showPreview = false;
|
||||
if (Config.general.color.schemeGeneration)
|
||||
Quickshell.execDetached(["sh", "-c", `zshell-cli scheme generate --image-path ${root.actualCurrent} --thumbnail-path ${Paths.cache}/imagecache/thumbnail.jpg --output ${Paths.state}/scheme.json --scheme ${Config.colors.schemeType} --mode ${Config.general.color.mode}`]);
|
||||
}
|
||||
}
|
||||
|
||||
list: wallpapers.entries
|
||||
key: "relativePath"
|
||||
useFuzzy: true
|
||||
extraOpts: useFuzzy ? ({}) : ({
|
||||
forward: false
|
||||
})
|
||||
extraOpts: useFuzzy ? ({}) : ({
|
||||
forward: false
|
||||
})
|
||||
key: "relativePath"
|
||||
list: wallpapers.entries
|
||||
useFuzzy: true
|
||||
|
||||
IpcHandler {
|
||||
target: "wallpaper"
|
||||
|
||||
function set(path: string): void {
|
||||
root.setWallpaper(path);
|
||||
}
|
||||
|
||||
target: "wallpaper"
|
||||
}
|
||||
|
||||
FileSystemModel {
|
||||
id: wallpapers
|
||||
FileSystemModel {
|
||||
id: wallpapers
|
||||
|
||||
recursive: true
|
||||
path: Config.general.wallpaperPath
|
||||
filter: FileSystemModel.Images
|
||||
}
|
||||
filter: FileSystemModel.Images
|
||||
path: Config.general.wallpaperPath
|
||||
recursive: true
|
||||
}
|
||||
}
|
||||
|
||||
+12
-11
@@ -6,20 +6,21 @@ import QtQuick
|
||||
import qs.Config
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
property var args
|
||||
property var args
|
||||
readonly property string mode: Config.general.color.mode
|
||||
readonly property string threshold: mode === "dark" ? "--threshold=9" : "--dynamic-threshold"
|
||||
|
||||
function generateColors(wallpaperPath) {
|
||||
root.args = wallpaperPath;
|
||||
wallustProc.running = true;
|
||||
}
|
||||
function generateColors(wallpaperPath) {
|
||||
root.args = wallpaperPath;
|
||||
wallustProc.running = true;
|
||||
}
|
||||
|
||||
Process {
|
||||
id: wallustProc
|
||||
command: ["wallust", "run", root.args, `--palette=${root.mode}`, "--ignore-sequence=cursor", `${root.threshold}` ]
|
||||
running: false
|
||||
}
|
||||
Process {
|
||||
id: wallustProc
|
||||
|
||||
command: ["wallust", "run", root.args, `--palette=${root.mode}`, "--ignore-sequence=cursor", `${root.threshold}`]
|
||||
running: false
|
||||
}
|
||||
}
|
||||
|
||||
+173
-173
@@ -6,200 +6,200 @@ import ZShell
|
||||
import qs.Config
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
property string city
|
||||
property string loc
|
||||
property var cc
|
||||
property list<var> forecast
|
||||
property list<var> hourlyForecast
|
||||
readonly property var cachedCities: new Map()
|
||||
property var cc
|
||||
property string city
|
||||
readonly property string description: cc?.weatherDesc ?? qsTr("No weather")
|
||||
readonly property string feelsLike: `${cc?.feelsLikeC ?? 0}°C`
|
||||
property list<var> forecast
|
||||
property list<var> hourlyForecast
|
||||
readonly property int humidity: cc?.humidity ?? 0
|
||||
readonly property string icon: cc ? Icons.getWeatherIcon(cc.weatherCode) : "cloud_alert"
|
||||
property string loc
|
||||
readonly property string sunrise: cc ? Qt.formatDateTime(new Date(cc.sunrise), "h:mm") : "--:--"
|
||||
readonly property string sunset: cc ? Qt.formatDateTime(new Date(cc.sunset), "h:mm") : "--:--"
|
||||
readonly property string temp: `${cc?.tempC ?? 0}°C`
|
||||
readonly property real windSpeed: cc?.windSpeed ?? 0
|
||||
|
||||
readonly property string icon: cc ? Icons.getWeatherIcon(cc.weatherCode) : "cloud_alert"
|
||||
readonly property string description: cc?.weatherDesc ?? qsTr("No weather")
|
||||
readonly property string temp: `${cc?.tempC ?? 0}°C`
|
||||
readonly property string feelsLike: `${cc?.feelsLikeC ?? 0}°C`
|
||||
readonly property int humidity: cc?.humidity ?? 0
|
||||
readonly property real windSpeed: cc?.windSpeed ?? 0
|
||||
readonly property string sunrise: cc ? Qt.formatDateTime(new Date(cc.sunrise), "h:mm") : "--:--"
|
||||
readonly property string sunset: cc ? Qt.formatDateTime(new Date(cc.sunset), "h:mm") : "--:--"
|
||||
function fetchCityFromCoords(coords: string): void {
|
||||
if (cachedCities.has(coords)) {
|
||||
city = cachedCities.get(coords);
|
||||
return;
|
||||
}
|
||||
|
||||
readonly property var cachedCities: new Map()
|
||||
const [lat, lon] = coords.split(",");
|
||||
const url = `https://nominatim.openstreetmap.org/reverse?lat=${lat}&lon=${lon}&format=geocodejson`;
|
||||
Requests.get(url, text => {
|
||||
const geo = JSON.parse(text).features?.[0]?.properties.geocoding;
|
||||
if (geo) {
|
||||
const geoCity = geo.type === "city" ? geo.name : geo.city;
|
||||
city = geoCity;
|
||||
cachedCities.set(coords, geoCity);
|
||||
} else {
|
||||
city = "Unknown City";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function reload(): void {
|
||||
const configLocation = Config.services.weatherLocation;
|
||||
function fetchCoordsFromCity(cityName: string): void {
|
||||
const url = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(cityName)}&count=1&language=en&format=json`;
|
||||
|
||||
if (configLocation) {
|
||||
if (configLocation.indexOf(",") !== -1 && !isNaN(parseFloat(configLocation.split(",")[0]))) {
|
||||
loc = configLocation;
|
||||
fetchCityFromCoords(configLocation);
|
||||
} else {
|
||||
fetchCoordsFromCity(configLocation);
|
||||
}
|
||||
} else if (!loc || timer.elapsed() > 900) {
|
||||
Requests.get("https://ipinfo.io/json", text => {
|
||||
const response = JSON.parse(text);
|
||||
if (response.loc) {
|
||||
loc = response.loc;
|
||||
city = response.city ?? "";
|
||||
timer.restart();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Requests.get(url, text => {
|
||||
const json = JSON.parse(text);
|
||||
if (json.results && json.results.length > 0) {
|
||||
const result = json.results[0];
|
||||
loc = result.latitude + "," + result.longitude;
|
||||
city = result.name;
|
||||
} else {
|
||||
loc = "";
|
||||
reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function fetchCityFromCoords(coords: string): void {
|
||||
if (cachedCities.has(coords)) {
|
||||
city = cachedCities.get(coords);
|
||||
return;
|
||||
}
|
||||
function fetchWeatherData(): void {
|
||||
const url = getWeatherUrl();
|
||||
if (url === "")
|
||||
return;
|
||||
|
||||
const [lat, lon] = coords.split(",");
|
||||
const url = `https://nominatim.openstreetmap.org/reverse?lat=${lat}&lon=${lon}&format=geocodejson`;
|
||||
Requests.get(url, text => {
|
||||
const geo = JSON.parse(text).features?.[0]?.properties.geocoding;
|
||||
if (geo) {
|
||||
const geoCity = geo.type === "city" ? geo.name : geo.city;
|
||||
city = geoCity;
|
||||
cachedCities.set(coords, geoCity);
|
||||
} else {
|
||||
city = "Unknown City";
|
||||
}
|
||||
});
|
||||
}
|
||||
Requests.get(url, text => {
|
||||
const json = JSON.parse(text);
|
||||
if (!json.current || !json.daily)
|
||||
return;
|
||||
|
||||
function fetchCoordsFromCity(cityName: string): void {
|
||||
const url = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(cityName)}&count=1&language=en&format=json`;
|
||||
cc = {
|
||||
weatherCode: json.current.weather_code,
|
||||
weatherDesc: getWeatherCondition(json.current.weather_code),
|
||||
tempC: Math.round(json.current.temperature_2m),
|
||||
tempF: Math.round(toFahrenheit(json.current.temperature_2m)),
|
||||
feelsLikeC: Math.round(json.current.apparent_temperature),
|
||||
feelsLikeF: Math.round(toFahrenheit(json.current.apparent_temperature)),
|
||||
humidity: json.current.relative_humidity_2m,
|
||||
windSpeed: json.current.wind_speed_10m,
|
||||
isDay: json.current.is_day,
|
||||
sunrise: json.daily.sunrise[0],
|
||||
sunset: json.daily.sunset[0]
|
||||
};
|
||||
|
||||
Requests.get(url, text => {
|
||||
const json = JSON.parse(text);
|
||||
if (json.results && json.results.length > 0) {
|
||||
const result = json.results[0];
|
||||
loc = result.latitude + "," + result.longitude;
|
||||
city = result.name;
|
||||
} else {
|
||||
loc = "";
|
||||
reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
const forecastList = [];
|
||||
for (let i = 0; i < json.daily.time.length; i++)
|
||||
forecastList.push({
|
||||
date: json.daily.time[i],
|
||||
maxTempC: Math.round(json.daily.temperature_2m_max[i]),
|
||||
maxTempF: Math.round(toFahrenheit(json.daily.temperature_2m_max[i])),
|
||||
minTempC: Math.round(json.daily.temperature_2m_min[i]),
|
||||
minTempF: Math.round(toFahrenheit(json.daily.temperature_2m_min[i])),
|
||||
weatherCode: json.daily.weather_code[i],
|
||||
icon: Icons.getWeatherIcon(json.daily.weather_code[i])
|
||||
});
|
||||
forecast = forecastList;
|
||||
|
||||
function fetchWeatherData(): void {
|
||||
const url = getWeatherUrl();
|
||||
if (url === "")
|
||||
return;
|
||||
const hourlyList = [];
|
||||
const now = new Date();
|
||||
for (let i = 0; i < json.hourly.time.length; i++) {
|
||||
const time = new Date(json.hourly.time[i]);
|
||||
if (time < now)
|
||||
continue;
|
||||
|
||||
Requests.get(url, text => {
|
||||
const json = JSON.parse(text);
|
||||
if (!json.current || !json.daily)
|
||||
return;
|
||||
hourlyList.push({
|
||||
timestamp: json.hourly.time[i],
|
||||
hour: time.getHours(),
|
||||
tempC: Math.round(json.hourly.temperature_2m[i]),
|
||||
tempF: Math.round(toFahrenheit(json.hourly.temperature_2m[i])),
|
||||
weatherCode: json.hourly.weather_code[i],
|
||||
icon: Icons.getWeatherIcon(json.hourly.weather_code[i])
|
||||
});
|
||||
}
|
||||
hourlyForecast = hourlyList;
|
||||
});
|
||||
}
|
||||
|
||||
cc = {
|
||||
weatherCode: json.current.weather_code,
|
||||
weatherDesc: getWeatherCondition(json.current.weather_code),
|
||||
tempC: Math.round(json.current.temperature_2m),
|
||||
tempF: Math.round(toFahrenheit(json.current.temperature_2m)),
|
||||
feelsLikeC: Math.round(json.current.apparent_temperature),
|
||||
feelsLikeF: Math.round(toFahrenheit(json.current.apparent_temperature)),
|
||||
humidity: json.current.relative_humidity_2m,
|
||||
windSpeed: json.current.wind_speed_10m,
|
||||
isDay: json.current.is_day,
|
||||
sunrise: json.daily.sunrise[0],
|
||||
sunset: json.daily.sunset[0]
|
||||
};
|
||||
function getWeatherCondition(code: string): string {
|
||||
const conditions = {
|
||||
"0": "Clear",
|
||||
"1": "Clear",
|
||||
"2": "Partly cloudy",
|
||||
"3": "Overcast",
|
||||
"45": "Fog",
|
||||
"48": "Fog",
|
||||
"51": "Drizzle",
|
||||
"53": "Drizzle",
|
||||
"55": "Drizzle",
|
||||
"56": "Freezing drizzle",
|
||||
"57": "Freezing drizzle",
|
||||
"61": "Light rain",
|
||||
"63": "Rain",
|
||||
"65": "Heavy rain",
|
||||
"66": "Light rain",
|
||||
"67": "Heavy rain",
|
||||
"71": "Light snow",
|
||||
"73": "Snow",
|
||||
"75": "Heavy snow",
|
||||
"77": "Snow",
|
||||
"80": "Light rain",
|
||||
"81": "Rain",
|
||||
"82": "Heavy rain",
|
||||
"85": "Light snow showers",
|
||||
"86": "Heavy snow showers",
|
||||
"95": "Thunderstorm",
|
||||
"96": "Thunderstorm with hail",
|
||||
"99": "Thunderstorm with hail"
|
||||
};
|
||||
return conditions[code] || "Unknown";
|
||||
}
|
||||
|
||||
const forecastList = [];
|
||||
for (let i = 0; i < json.daily.time.length; i++)
|
||||
forecastList.push({
|
||||
date: json.daily.time[i],
|
||||
maxTempC: Math.round(json.daily.temperature_2m_max[i]),
|
||||
maxTempF: Math.round(toFahrenheit(json.daily.temperature_2m_max[i])),
|
||||
minTempC: Math.round(json.daily.temperature_2m_min[i]),
|
||||
minTempF: Math.round(toFahrenheit(json.daily.temperature_2m_min[i])),
|
||||
weatherCode: json.daily.weather_code[i],
|
||||
icon: Icons.getWeatherIcon(json.daily.weather_code[i])
|
||||
});
|
||||
forecast = forecastList;
|
||||
function getWeatherUrl(): string {
|
||||
if (!loc || loc.indexOf(",") === -1)
|
||||
return "";
|
||||
|
||||
const hourlyList = [];
|
||||
const now = new Date();
|
||||
for (let i = 0; i < json.hourly.time.length; i++) {
|
||||
const time = new Date(json.hourly.time[i]);
|
||||
if (time < now)
|
||||
continue;
|
||||
const [lat, lon] = loc.split(",");
|
||||
const baseUrl = "https://api.open-meteo.com/v1/forecast";
|
||||
const params = ["latitude=" + lat, "longitude=" + lon, "hourly=weather_code,temperature_2m", "daily=weather_code,temperature_2m_max,temperature_2m_min,sunrise,sunset", "current=temperature_2m,relative_humidity_2m,apparent_temperature,is_day,weather_code,wind_speed_10m", "timezone=auto", "forecast_days=7"];
|
||||
|
||||
hourlyList.push({
|
||||
timestamp: json.hourly.time[i],
|
||||
hour: time.getHours(),
|
||||
tempC: Math.round(json.hourly.temperature_2m[i]),
|
||||
tempF: Math.round(toFahrenheit(json.hourly.temperature_2m[i])),
|
||||
weatherCode: json.hourly.weather_code[i],
|
||||
icon: Icons.getWeatherIcon(json.hourly.weather_code[i])
|
||||
});
|
||||
}
|
||||
hourlyForecast = hourlyList;
|
||||
});
|
||||
}
|
||||
return baseUrl + "?" + params.join("&");
|
||||
}
|
||||
|
||||
function toFahrenheit(celcius: real): real {
|
||||
return celcius * 9 / 5 + 32;
|
||||
}
|
||||
function reload(): void {
|
||||
const configLocation = Config.services.weatherLocation;
|
||||
|
||||
function getWeatherUrl(): string {
|
||||
if (!loc || loc.indexOf(",") === -1)
|
||||
return "";
|
||||
if (configLocation) {
|
||||
if (configLocation.indexOf(",") !== -1 && !isNaN(parseFloat(configLocation.split(",")[0]))) {
|
||||
loc = configLocation;
|
||||
fetchCityFromCoords(configLocation);
|
||||
} else {
|
||||
fetchCoordsFromCity(configLocation);
|
||||
}
|
||||
} else if (!loc || timer.elapsed() > 900) {
|
||||
Requests.get("https://ipinfo.io/json", text => {
|
||||
const response = JSON.parse(text);
|
||||
if (response.loc) {
|
||||
loc = response.loc;
|
||||
city = response.city ?? "";
|
||||
timer.restart();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const [lat, lon] = loc.split(",");
|
||||
const baseUrl = "https://api.open-meteo.com/v1/forecast";
|
||||
const params = ["latitude=" + lat, "longitude=" + lon, "hourly=weather_code,temperature_2m", "daily=weather_code,temperature_2m_max,temperature_2m_min,sunrise,sunset", "current=temperature_2m,relative_humidity_2m,apparent_temperature,is_day,weather_code,wind_speed_10m", "timezone=auto", "forecast_days=7"];
|
||||
function toFahrenheit(celcius: real): real {
|
||||
return celcius * 9 / 5 + 32;
|
||||
}
|
||||
|
||||
return baseUrl + "?" + params.join("&");
|
||||
}
|
||||
onLocChanged: fetchWeatherData()
|
||||
|
||||
function getWeatherCondition(code: string): string {
|
||||
const conditions = {
|
||||
"0": "Clear",
|
||||
"1": "Clear",
|
||||
"2": "Partly cloudy",
|
||||
"3": "Overcast",
|
||||
"45": "Fog",
|
||||
"48": "Fog",
|
||||
"51": "Drizzle",
|
||||
"53": "Drizzle",
|
||||
"55": "Drizzle",
|
||||
"56": "Freezing drizzle",
|
||||
"57": "Freezing drizzle",
|
||||
"61": "Light rain",
|
||||
"63": "Rain",
|
||||
"65": "Heavy rain",
|
||||
"66": "Light rain",
|
||||
"67": "Heavy rain",
|
||||
"71": "Light snow",
|
||||
"73": "Snow",
|
||||
"75": "Heavy snow",
|
||||
"77": "Snow",
|
||||
"80": "Light rain",
|
||||
"81": "Rain",
|
||||
"82": "Heavy rain",
|
||||
"85": "Light snow showers",
|
||||
"86": "Heavy snow showers",
|
||||
"95": "Thunderstorm",
|
||||
"96": "Thunderstorm with hail",
|
||||
"99": "Thunderstorm with hail"
|
||||
};
|
||||
return conditions[code] || "Unknown";
|
||||
}
|
||||
// Refresh current location hourly
|
||||
Timer {
|
||||
interval: 3600000 // 1 hour
|
||||
repeat: true
|
||||
running: true
|
||||
|
||||
onLocChanged: fetchWeatherData()
|
||||
onTriggered: fetchWeatherData()
|
||||
}
|
||||
|
||||
// Refresh current location hourly
|
||||
Timer {
|
||||
interval: 3600000 // 1 hour
|
||||
running: true
|
||||
repeat: true
|
||||
onTriggered: fetchWeatherData()
|
||||
}
|
||||
ElapsedTimer {
|
||||
id: timer
|
||||
|
||||
ElapsedTimer {
|
||||
id: timer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+52
-416
@@ -1,420 +1,56 @@
|
||||
import Quickshell.Io
|
||||
|
||||
JsonObject {
|
||||
property list<var> week_0: [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_1: [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_2: [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_3: [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_4: [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_5: [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_6: [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_7: [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_8: [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_9: [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_10:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_11:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_12:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_13:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_14:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_15:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_16:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_17:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_18:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_19:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_20:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_21:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_22:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_23:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_24:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_25:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_26:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_27:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_28:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_29:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_30:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_31:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_32:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_33:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_34:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_35:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_36:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_37:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_38:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_39:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_40:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_41:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_42:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_43:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_44:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_45:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_46:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_47:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_48:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_49:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_50:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_51:[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
property list<var> week_0: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_1: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_10: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_11: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_12: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_13: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_14: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_15: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_16: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_17: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_18: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_19: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_2: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_20: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_21: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_22: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_23: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_24: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_25: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_26: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_27: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_28: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_29: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_3: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_30: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_31: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_32: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_33: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_34: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_35: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_36: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_37: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_38: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_39: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_4: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_40: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_41: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_42: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_43: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_44: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_45: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_46: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_47: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_48: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_49: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_5: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_50: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_51: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_6: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_7: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_8: [0, 0, 0, 0, 0, 0,]
|
||||
property list<var> week_9: [0, 0, 0, 0, 0, 0,]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user