sidebar: night light dialog

This commit is contained in:
end-4
2025-10-22 22:16:58 +02:00
parent 6ed9c9869e
commit bb08c61b76
9 changed files with 244 additions and 47 deletions
@@ -7,6 +7,7 @@ import QtQuick.Controls
RippleButton { RippleButton {
id: root id: root
property string buttonIcon property string buttonIcon
property alias iconSize: iconWidget.iconSize
Layout.fillWidth: true Layout.fillWidth: true
implicitHeight: contentItem.implicitHeight + 8 * 2 implicitHeight: contentItem.implicitHeight + 8 * 2
@@ -17,6 +18,7 @@ RippleButton {
contentItem: RowLayout { contentItem: RowLayout {
spacing: 10 spacing: 10
OptionalMaterialSymbol { OptionalMaterialSymbol {
id: iconWidget
icon: root.buttonIcon icon: root.buttonIcon
opacity: root.enabled ? 1 : 0.4 opacity: root.enabled ? 1 : 0.4
iconSize: Appearance.font.pixelSize.larger iconSize: Appearance.font.pixelSize.larger
@@ -0,0 +1,43 @@
pragma ComponentBehavior: Bound
import qs.modules.common
import qs.modules.common.widgets
import qs.services
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell.Widgets
Column {
id: root
property alias text: sliderName.text
property alias from: sliderWidget.from
property alias to: sliderWidget.to
property alias value: sliderWidget.value
property alias tooltipContent: sliderWidget.tooltipContent
property alias stopIndicatorValues: sliderWidget.stopIndicatorValues
signal moved()
spacing: -2
ContentSubsectionLabel {
id: sliderName
visible: text?.length > 0
text: ""
anchors {
left: parent.left
right: parent.right
}
}
StyledSlider {
id: sliderWidget
anchors {
left: parent.left
right: parent.right
leftMargin: 4
rightMargin: leftMargin
}
configuration: StyledSlider.Configuration.S
onMoved: root.moved()
}
}
@@ -11,19 +11,22 @@ import Quickshell.Hyprland
import qs.modules.sidebarRight.quickToggles import qs.modules.sidebarRight.quickToggles
import qs.modules.sidebarRight.quickToggles.classicStyle import qs.modules.sidebarRight.quickToggles.classicStyle
import qs.modules.sidebarRight.wifiNetworks
import qs.modules.sidebarRight.bluetoothDevices import qs.modules.sidebarRight.bluetoothDevices
import qs.modules.sidebarRight.nightLight
import qs.modules.sidebarRight.volumeMixer import qs.modules.sidebarRight.volumeMixer
import qs.modules.sidebarRight.wifiNetworks
Item { Item {
id: root id: root
property int sidebarWidth: Appearance.sizes.sidebarWidth property int sidebarWidth: Appearance.sizes.sidebarWidth
property int sidebarPadding: 10 property int sidebarPadding: 10
property string settingsQmlPath: Quickshell.shellPath("settings.qml") property string settingsQmlPath: Quickshell.shellPath("settings.qml")
property bool showWifiDialog: false
property bool showBluetoothDialog: false
property bool showAudioOutputDialog: false property bool showAudioOutputDialog: false
property bool showAudioInputDialog: false property bool showAudioInputDialog: false
property bool showBluetoothDialog: false
property bool showNightLightDialog: false
property bool showWifiDialog: false
property bool editMode: false property bool editMode: false
Connections { Connections {
@@ -109,18 +112,20 @@ Item {
} }
ToggleDialog { ToggleDialog {
id: wifiDialogLoader shownPropertyString: "showAudioOutputDialog"
shownPropertyString: "showWifiDialog" dialog: VolumeDialog {
dialog: WifiDialog {} isSink: true
onShownChanged: { }
if (!shown) return; }
Network.enableWifi();
Network.rescanWifi(); ToggleDialog {
shownPropertyString: "showAudioInputDialog"
dialog: VolumeDialog {
isSink: false
} }
} }
ToggleDialog { ToggleDialog {
id: bluetoothDialogLoader
shownPropertyString: "showBluetoothDialog" shownPropertyString: "showBluetoothDialog"
dialog: BluetoothDialog {} dialog: BluetoothDialog {}
onShownChanged: { onShownChanged: {
@@ -130,23 +135,21 @@ Item {
Bluetooth.defaultAdapter.enabled = true; Bluetooth.defaultAdapter.enabled = true;
Bluetooth.defaultAdapter.discovering = true; Bluetooth.defaultAdapter.discovering = true;
} }
} }
} }
ToggleDialog { ToggleDialog {
id: audioOutputDialogLoader shownPropertyString: "showNightLightDialog"
shownPropertyString: "showAudioOutputDialog" dialog: NightLightDialog {}
dialog: VolumeDialog {
isSink: true
}
} }
ToggleDialog { ToggleDialog {
id: audioInputDialogLoader shownPropertyString: "showWifiDialog"
shownPropertyString: "showAudioInputDialog" dialog: WifiDialog {}
dialog: VolumeDialog { onShownChanged: {
isSink: false if (!shown) return;
Network.enableWifi();
Network.rescanWifi();
} }
} }
@@ -186,18 +189,21 @@ Item {
active: Config.options.sidebar.quickToggles.style === styleName active: Config.options.sidebar.quickToggles.style === styleName
Connections { Connections {
target: quickPanelImplLoader.item target: quickPanelImplLoader.item
function onOpenWifiDialog() {
root.showWifiDialog = true;
}
function onOpenBluetoothDialog() {
root.showBluetoothDialog = true;
}
function onOpenAudioOutputDialog() { function onOpenAudioOutputDialog() {
root.showAudioOutputDialog = true; root.showAudioOutputDialog = true;
} }
function onOpenAudioInputDialog() { function onOpenAudioInputDialog() {
root.showAudioInputDialog = true; root.showAudioInputDialog = true;
} }
function onOpenBluetoothDialog() {
root.showBluetoothDialog = true;
}
function onOpenNightLightDialog() {
root.showNightLightDialog = true;
}
function onOpenWifiDialog() {
root.showWifiDialog = true;
}
} }
} }
@@ -0,0 +1,125 @@
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.common.functions
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell.Io
import Quickshell
import Quickshell.Wayland
import Quickshell.Hyprland
WindowDialog {
id: root
property var screen: root.QsWindow.window?.screen
property var brightnessMonitor: Brightness.getMonitorForScreen(screen)
WindowDialogTitle {
text: Translation.tr("Eye protection")
}
WindowDialogSectionHeader {
text: Translation.tr("Night Light")
}
WindowDialogSeparator {
Layout.topMargin: -22
Layout.leftMargin: 0
Layout.rightMargin: 0
}
Column {
id: nightLightColumn
Layout.topMargin: -16
Layout.fillWidth: true
Layout.fillHeight: true
ConfigSwitch {
anchors {
left: parent.left
right: parent.right
}
iconSize: Appearance.font.pixelSize.larger
buttonIcon: "lightbulb"
text: Translation.tr("Enable now")
checked: Hyprsunset.active
onCheckedChanged: {
Hyprsunset.toggle(checked)
}
}
ConfigSwitch {
anchors {
left: parent.left
right: parent.right
}
iconSize: Appearance.font.pixelSize.larger
buttonIcon: "night_sight_auto"
text: Translation.tr("Automatic")
checked: Config.options.light.night.automatic
onCheckedChanged: {
Config.options.light.night.automatic = checked;
}
}
WindowDialogSlider {
anchors {
left: parent.left
right: parent.right
leftMargin: 4
rightMargin: 4
}
text: Translation.tr("Color temperature")
from: 1000
to: 20000
stopIndicatorValues: [6000, to]
value: Config.options.light.night.colorTemperature
onMoved: Config.options.light.night.colorTemperature = value
tooltipContent: `${Math.round(value)}K`
}
}
WindowDialogSectionHeader {
text: Translation.tr("Brightness")
}
WindowDialogSeparator {
Layout.topMargin: -22
Layout.leftMargin: 0
Layout.rightMargin: 0
}
Column {
id: brightnessColumn
Layout.topMargin: -16
Layout.fillWidth: true
// Layout.fillHeight: true
WindowDialogSlider {
anchors {
left: parent.left
right: parent.right
leftMargin: 4
rightMargin: 4
}
// text: Translation.tr("Brightness")
value: root.brightnessMonitor.brightness
onMoved: root.brightnessMonitor.setBrightness(value)
}
}
WindowDialogButtonRow {
Layout.fillWidth: true
Item {
Layout.fillWidth: true
}
DialogButton {
buttonText: Translation.tr("Done")
onClicked: root.dismiss()
}
}
}
@@ -7,8 +7,9 @@ Rectangle {
radius: Appearance.rounding.normal radius: Appearance.rounding.normal
color: Appearance.colors.colLayer1 color: Appearance.colors.colLayer1
signal openWifiDialog()
signal openBluetoothDialog()
signal openAudioOutputDialog() signal openAudioOutputDialog()
signal openAudioInputDialog() signal openAudioInputDialog()
signal openBluetoothDialog()
signal openNightLightDialog()
signal openWifiDialog()
} }
@@ -12,15 +12,23 @@ AbstractQuickPanel {
id: root id: root
property bool editMode: false property bool editMode: false
Layout.fillWidth: true Layout.fillWidth: true
implicitHeight: (editMode ? contentItem.implicitHeight : usedRows.implicitHeight) + root.padding * 2
// Sizes
implicitHeight: (editMode ? contentItem.implicitHeight : usedRows.implicitHeight) + root.padding * 2
Behavior on implicitHeight { Behavior on implicitHeight {
animation: Appearance.animation.elementMove.numberAnimation.createObject(this) animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
} }
property real spacing: 6 property real spacing: 6
property real padding: 6 property real padding: 6
readonly property real baseCellWidth: {
// This is the wrong calculation, but it looks correct in reality???
// (theoretically spacing should be multiplied by 1 column less)
const availableWidth = root.width - (root.padding * 2) - (root.spacing * (root.columns))
return availableWidth / root.columns
}
readonly property real baseCellHeight: 56
// Toggles
readonly property list<string> availableToggleTypes: ["network", "bluetooth", "idleInhibitor", "easyEffects", "nightLight", "darkMode", "cloudflareWarp", "gameMode", "screenSnip", "colorPicker", "onScreenKeyboard", "mic", "audio", "notifications", "powerProfile"] readonly property list<string> availableToggleTypes: ["network", "bluetooth", "idleInhibitor", "easyEffects", "nightLight", "darkMode", "cloudflareWarp", "gameMode", "screenSnip", "colorPicker", "onScreenKeyboard", "mic", "audio", "notifications", "powerProfile"]
readonly property int columns: Config.options.sidebar.quickToggles.android.columns readonly property int columns: Config.options.sidebar.quickToggles.android.columns
readonly property list<var> toggles: Config.ready ? Config.options.sidebar.quickToggles.android.toggles : [] readonly property list<var> toggles: Config.ready ? Config.options.sidebar.quickToggles.android.toggles : []
@@ -30,13 +38,6 @@ AbstractQuickPanel {
return types.map(type => { return { type: type, size: 1 } }) return types.map(type => { return { type: type, size: 1 } })
} }
readonly property list<var> unusedToggleRows: toggleRowsForList(unusedToggles) readonly property list<var> unusedToggleRows: toggleRowsForList(unusedToggles)
readonly property real baseCellWidth: {
// This is the wrong calculation, but it looks correct in reality???
// (theoretically spacing should be multiplied by 1 column less)
const availableWidth = root.width - (root.padding * 2) - (root.spacing * (root.columns))
return availableWidth / root.columns
}
readonly property real baseCellHeight: 56
function toggleRowsForList(togglesList) { function toggleRowsForList(togglesList) {
var rows = []; var rows = [];
@@ -78,7 +79,10 @@ AbstractQuickPanel {
delegate: ButtonGroup { delegate: ButtonGroup {
id: toggleRow id: toggleRow
required property int index required property int index
property var modelData: root.toggleRows[index] property var modelData: {
print(JSON.stringify(root.toggleRows[index]))
return root.toggleRows[index]
}
property int startingIndex: { property int startingIndex: {
const rows = root.toggleRows; const rows = root.toggleRows;
let sum = 0; let sum = 0;
@@ -100,10 +104,11 @@ AbstractQuickPanel {
baseCellWidth: root.baseCellWidth baseCellWidth: root.baseCellWidth
baseCellHeight: root.baseCellHeight baseCellHeight: root.baseCellHeight
spacing: root.spacing spacing: root.spacing
onOpenWifiDialog: root.openWifiDialog()
onOpenBluetoothDialog: root.openBluetoothDialog()
onOpenAudioOutputDialog: root.openAudioOutputDialog() onOpenAudioOutputDialog: root.openAudioOutputDialog()
onOpenAudioInputDialog: root.openAudioInputDialog() onOpenAudioInputDialog: root.openAudioInputDialog()
onOpenBluetoothDialog: root.openBluetoothDialog()
onOpenNightLightDialog: root.openNightLightDialog()
onOpenWifiDialog: root.openWifiDialog()
} }
} }
} }
@@ -19,7 +19,7 @@ AndroidQuickToggleButton {
} }
altAction: () => { altAction: () => {
Config.options.light.night.automatic = !Config.options.light.night.automatic root.openMenu()
} }
Component.onCompleted: { Component.onCompleted: {
@@ -27,7 +27,7 @@ AndroidQuickToggleButton {
} }
StyledToolTip { StyledToolTip {
text: Translation.tr("Night Light | Right-click to toggle Auto mode") text: Translation.tr("Night Light | Right-click to configure")
} }
} }
@@ -14,10 +14,11 @@ DelegateChooser {
required property real baseCellHeight required property real baseCellHeight
required property real spacing required property real spacing
required property int startingIndex required property int startingIndex
signal openWifiDialog()
signal openBluetoothDialog()
signal openAudioOutputDialog() signal openAudioOutputDialog()
signal openAudioInputDialog() signal openAudioInputDialog()
signal openBluetoothDialog()
signal openNightLightDialog()
signal openWifiDialog()
role: "type" role: "type"
@@ -90,6 +91,9 @@ DelegateChooser {
baseCellHeight: root.baseCellHeight baseCellHeight: root.baseCellHeight
cellSpacing: root.spacing cellSpacing: root.spacing
cellSize: modelData.size cellSize: modelData.size
onOpenMenu: {
root.openNightLightDialog()
}
} } } }
DelegateChoice { roleValue: "darkMode"; AndroidDarkModeToggle { DelegateChoice { roleValue: "darkMode"; AndroidDarkModeToggle {
@@ -4,6 +4,7 @@ import QtQuick
import qs.modules.common import qs.modules.common
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import Quickshell.Hyprland
/** /**
* Simple hyprsunset service with automatic mode. * Simple hyprsunset service with automatic mode.
@@ -111,18 +112,28 @@ Singleton {
} }
} }
function toggle() { function toggle(active = undefined) {
if (root.manualActive === undefined) { if (root.manualActive === undefined) {
root.manualActive = root.active; root.manualActive = root.active;
root.manualActiveHour = root.clockHour; root.manualActiveHour = root.clockHour;
root.manualActiveMinute = root.clockMinute; root.manualActiveMinute = root.clockMinute;
} }
root.manualActive = !root.manualActive; root.manualActive = active !== undefined ? active : !root.manualActive;
if (root.manualActive) { if (root.manualActive) {
root.enable(); root.enable();
} else { } else {
root.disable(); root.disable();
} }
} }
// Change temp
Connections {
target: Config.options.light.night
onColorTemperatureChanged: {
if (!root.active) return;
Hyprland.dispatch(`hyprctl hyprsunset temperature ${Config.options.light.night.colorTemperature}`);
Quickshell.execDetached(["hyprctl", "hyprsunset", "temperature", `${Config.options.light.night.colorTemperature}`]);
}
}
} }