feat: init quickshell
This commit is contained in:
@@ -0,0 +1,309 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import "root:/Data" as Data
|
||||
|
||||
// Night light widget with pure Qt overlay (no external dependencies)
|
||||
Rectangle {
|
||||
id: root
|
||||
property var shell: null
|
||||
color: Qt.darker(Data.ThemeManager.bgColor, 1.15)
|
||||
radius: 20
|
||||
|
||||
property bool containsMouse: nightLightMouseArea.containsMouse
|
||||
property bool isActive: Data.Settings.nightLightEnabled
|
||||
property real warmth: Data.Settings.nightLightWarmth // 0=no filter, 1=very warm (0-1 scale)
|
||||
property real strength: isActive ? warmth : 0
|
||||
property bool autoSchedulerActive: false // Flag to prevent manual override during auto changes
|
||||
|
||||
signal entered
|
||||
signal exited
|
||||
|
||||
// Night light overlay window
|
||||
property var overlayWindow: null
|
||||
|
||||
// Hover state management for parent components
|
||||
onContainsMouseChanged: {
|
||||
if (containsMouse) {
|
||||
entered();
|
||||
} else {
|
||||
exited();
|
||||
}
|
||||
}
|
||||
|
||||
// Background with warm tint when active
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: parent.radius
|
||||
color: isActive ? Qt.rgba(1.0, 0.6, 0.2, 0.15) : "transparent"
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: 300
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: nightLightMouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
|
||||
// Right-click to cycle through warmth levels
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
onClicked: function (mouse) {
|
||||
if (mouse.button === Qt.RightButton) {
|
||||
cycleWarmth();
|
||||
} else {
|
||||
toggleNightLight();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Night light icon with dynamic color
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: isActive ? "light_mode" : "dark_mode"
|
||||
font.pixelSize: 24
|
||||
font.family: "Material Symbols Outlined"
|
||||
color: isActive ? Qt.rgba(1.0, 0.8 - strength * 0.3, 0.4 - strength * 0.2, 1.0) : // Warm orange when active
|
||||
(containsMouse ? Data.ThemeManager.accentColor : Data.ThemeManager.fgColor)
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: 200
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Warmth indicator dots
|
||||
Row {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 6
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: 3
|
||||
visible: isActive && containsMouse
|
||||
|
||||
Repeater {
|
||||
model: 3
|
||||
delegate: Rectangle {
|
||||
width: 4
|
||||
height: 4
|
||||
radius: 2
|
||||
color: index < Math.ceil(warmth * 3) ? Qt.rgba(1.0, 0.7 - index * 0.2, 0.3, 0.8) : Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.3)
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: 150
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Watch for settings changes
|
||||
Connections {
|
||||
target: Data.Settings
|
||||
function onNightLightEnabledChanged() {
|
||||
if (Data.Settings.nightLightEnabled) {
|
||||
createOverlay();
|
||||
} else {
|
||||
removeOverlay();
|
||||
}
|
||||
|
||||
// Set manual override flag if this wasn't an automatic change
|
||||
if (!autoSchedulerActive) {
|
||||
Data.Settings.nightLightManualOverride = true;
|
||||
Data.Settings.nightLightManuallyEnabled = Data.Settings.nightLightEnabled;
|
||||
console.log("Manual night light change detected - override enabled, manually set to:", Data.Settings.nightLightEnabled);
|
||||
}
|
||||
}
|
||||
function onNightLightWarmthChanged() {
|
||||
updateOverlay();
|
||||
}
|
||||
}
|
||||
|
||||
// Functions to control night light
|
||||
function toggleNightLight() {
|
||||
Data.Settings.nightLightEnabled = !Data.Settings.nightLightEnabled;
|
||||
}
|
||||
|
||||
function cycleWarmth() {
|
||||
// Cycle through warmth levels: 0.2 -> 0.4 -> 0.6 -> 1.0 -> 0.2
|
||||
var newWarmth = warmth >= 1.0 ? 0.2 : (warmth >= 0.6 ? 1.0 : warmth + 0.2);
|
||||
Data.Settings.nightLightWarmth = newWarmth;
|
||||
}
|
||||
|
||||
function createOverlay() {
|
||||
if (overlayWindow)
|
||||
return;
|
||||
|
||||
var qmlString = `
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
|
||||
PanelWindow {
|
||||
id: nightLightOverlay
|
||||
screen: Quickshell.primaryScreen || Quickshell.screens[0]
|
||||
|
||||
anchors.top: true
|
||||
anchors.left: true
|
||||
anchors.right: true
|
||||
anchors.bottom: true
|
||||
|
||||
color: "transparent"
|
||||
|
||||
WlrLayershell.layer: WlrLayershell.Overlay
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||
WlrLayershell.namespace: "quickshell-nightlight"
|
||||
exclusiveZone: 0
|
||||
|
||||
// Click-through overlay
|
||||
mask: Region {}
|
||||
|
||||
Rectangle {
|
||||
id: overlayRect
|
||||
anchors.fill: parent
|
||||
color: "transparent" // Initial color, will be set by parent
|
||||
|
||||
// Smooth transitions when warmth changes
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: 300 }
|
||||
}
|
||||
}
|
||||
|
||||
// Function to update overlay color
|
||||
function updateColor(newWarmth) {
|
||||
overlayRect.color = Qt.rgba(1.0, 0.8 - newWarmth * 0.4, 0.3 - newWarmth * 0.25, 0.1 + newWarmth * 0.2)
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
try {
|
||||
overlayWindow = Qt.createQmlObject(qmlString, root);
|
||||
// Set initial color
|
||||
updateOverlay();
|
||||
} catch (e) {
|
||||
console.error("Failed to create night light overlay:", e);
|
||||
}
|
||||
}
|
||||
|
||||
function updateOverlay() {
|
||||
if (overlayWindow && overlayWindow.updateColor) {
|
||||
overlayWindow.updateColor(warmth);
|
||||
}
|
||||
}
|
||||
|
||||
function removeOverlay() {
|
||||
if (overlayWindow) {
|
||||
overlayWindow.destroy();
|
||||
overlayWindow = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Preset warmth levels for easy access
|
||||
function setLow() {
|
||||
Data.Settings.nightLightWarmth = 0.2;
|
||||
} // Light warmth
|
||||
function setMedium() {
|
||||
Data.Settings.nightLightWarmth = 0.4;
|
||||
} // Medium warmth
|
||||
function setHigh() {
|
||||
Data.Settings.nightLightWarmth = 0.6;
|
||||
} // High warmth
|
||||
function setMax() {
|
||||
Data.Settings.nightLightWarmth = 1.0;
|
||||
} // Maximum warmth
|
||||
|
||||
// Auto-enable based on time (basic sunset/sunrise simulation)
|
||||
Timer {
|
||||
interval: 60000 // Check every minute
|
||||
running: true
|
||||
repeat: true
|
||||
onTriggered: checkAutoEnable()
|
||||
}
|
||||
|
||||
function checkAutoEnable() {
|
||||
if (!Data.Settings.nightLightAuto)
|
||||
return;
|
||||
var now = new Date();
|
||||
var hour = now.getHours();
|
||||
var minute = now.getMinutes();
|
||||
var startHour = Data.Settings.nightLightStartHour || 20;
|
||||
var endHour = Data.Settings.nightLightEndHour || 6;
|
||||
|
||||
// Handle overnight schedules (e.g., 20:00 to 6:00)
|
||||
var shouldBeActive = false;
|
||||
if (startHour > endHour) {
|
||||
// Overnight: active from startHour onwards OR before endHour
|
||||
shouldBeActive = (hour >= startHour || hour < endHour);
|
||||
} else if (startHour < endHour) {
|
||||
// Same day: active between startHour and endHour
|
||||
shouldBeActive = (hour >= startHour && hour < endHour);
|
||||
} else {
|
||||
// startHour === endHour: never auto-enable
|
||||
shouldBeActive = false;
|
||||
}
|
||||
|
||||
// Debug logging
|
||||
console.log(`Night Light Auto Check: ${hour}:${minute.toString().padStart(2, '0')} - Should be active: ${shouldBeActive}, Currently active: ${Data.Settings.nightLightEnabled}, Manual override: ${Data.Settings.nightLightManualOverride}`);
|
||||
|
||||
// Smart override logic - only block conflicting actions
|
||||
if (Data.Settings.nightLightManualOverride) {
|
||||
// If user manually enabled, allow auto-disable but block auto-enable
|
||||
if (Data.Settings.nightLightManuallyEnabled && !shouldBeActive && Data.Settings.nightLightEnabled) {
|
||||
console.log("Auto-disabling night light (respecting schedule after manual enable)");
|
||||
autoSchedulerActive = true;
|
||||
Data.Settings.nightLightEnabled = false;
|
||||
Data.Settings.nightLightManualOverride = false; // Reset after respecting schedule
|
||||
autoSchedulerActive = false;
|
||||
return;
|
||||
} else
|
||||
// If user manually disabled, block auto-enable until next cycle
|
||||
if (!Data.Settings.nightLightManuallyEnabled && shouldBeActive && !Data.Settings.nightLightEnabled) {
|
||||
// Check if this is the start of a new schedule cycle
|
||||
var isNewCycle = (hour === startHour && minute === 0);
|
||||
if (isNewCycle) {
|
||||
console.log("New schedule cycle starting - resetting manual override");
|
||||
Data.Settings.nightLightManualOverride = false;
|
||||
} else {
|
||||
console.log("Manual disable override active - skipping auto-enable");
|
||||
return;
|
||||
}
|
||||
} else
|
||||
// Other cases - reset override and continue
|
||||
{
|
||||
Data.Settings.nightLightManualOverride = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-enable when schedule starts
|
||||
if (shouldBeActive && !Data.Settings.nightLightEnabled) {
|
||||
console.log("Auto-enabling night light");
|
||||
autoSchedulerActive = true;
|
||||
Data.Settings.nightLightEnabled = true;
|
||||
autoSchedulerActive = false;
|
||||
} else
|
||||
// Auto-disable when schedule ends
|
||||
if (!shouldBeActive && Data.Settings.nightLightEnabled) {
|
||||
console.log("Auto-disabling night light");
|
||||
autoSchedulerActive = true;
|
||||
Data.Settings.nightLightEnabled = false;
|
||||
autoSchedulerActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup on destruction
|
||||
Component.onDestruction: {
|
||||
removeOverlay();
|
||||
}
|
||||
|
||||
// Initialize overlay state based on settings
|
||||
Component.onCompleted: {
|
||||
if (Data.Settings.nightLightEnabled) {
|
||||
createOverlay();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user