// Copyright (C) 2026 Danilo M. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2 as // published by the Free Software Foundation. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. import QtQuick Flickable { contentHeight: col.implicitHeight clip: true Column { id: col width: parent.width spacing: 12 Row { spacing: 8 Text { anchors.verticalCenter: parent.verticalCenter text: "Lat" color: Theme.subtext font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 3 } } Field { width: 90; value: Hyprsunset.lat; onEdited: Hyprsunset.lat = value; placeholder: "lat" } Text { anchors.verticalCenter: parent.verticalCenter text: "Lon" color: Theme.subtext font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 3 } } Field { width: 90; value: Hyprsunset.lon; onEdited: Hyprsunset.lon = value; placeholder: "lon" } Toggle { anchors.verticalCenter: parent.verticalCenter checked: Hyprsunset.autoDetect label: "auto" onToggled: Hyprsunset.autoDetect = checked } Tab { text: "Detect"; onClicked: Hyprsunset.detect() } Tab { text: Hyprsunset.busy ? "fetching…" : "Fetch sun times"; onClicked: Hyprsunset.fetchSun() } Text { anchors.verticalCenter: parent.verticalCenter text: Hyprsunset.sunSummary color: Theme.overlay font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 4 } } } Repeater { model: Hyprsunset.profiles Rectangle { required property var modelData required property int index width: col.width implicitHeight: 40 radius: 8 color: Qt.alpha(Theme.surface, 0.35) Row { anchors.fill: parent anchors.margins: 8 spacing: 8 Text { anchors.verticalCenter: parent.verticalCenter text: index === Hyprsunset.dayIndex(Hyprsunset.profiles) ? "day" : index === Hyprsunset.nightIndex(Hyprsunset.profiles) ? "night" : "profile" color: Theme.subtext font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 4 } } Field { anchors.verticalCenter: parent.verticalCenter width: 60 value: modelData.time placeholder: "HH:MM" onEdited: Hyprsunset.profiles = Hyprsunset.profiles.map( (p, i) => i === index ? Object.assign({}, p, { time: value }) : p) } Toggle { anchors.verticalCenter: parent.verticalCenter checked: modelData.identity label: "identity" onToggled: Hyprsunset.profiles = Hyprsunset.profiles.map( (p, i) => i === index ? Object.assign({}, p, { identity: checked }) : p) } Toggle { anchors.verticalCenter: parent.verticalCenter checked: modelData.temperature !== null && modelData.temperature !== undefined label: "temp" onToggled: Hyprsunset.profiles = Hyprsunset.profiles.map( (p, i) => i === index ? Object.assign({}, p, { temperature: checked ? (p.temperature ?? 5500) : null }) : p) } Field { anchors.verticalCenter: parent.verticalCenter width: 70 value: modelData.temperature === null || modelData.temperature === undefined ? "" : String(modelData.temperature) placeholder: "5500" onEdited: Hyprsunset.profiles = Hyprsunset.profiles.map( (p, i) => i === index ? Object.assign({}, p, { temperature: value === "" ? null : parseInt(value, 10) }) : p) } Toggle { anchors.verticalCenter: parent.verticalCenter checked: modelData.gamma !== null && modelData.gamma !== undefined label: "gamma" onToggled: Hyprsunset.profiles = Hyprsunset.profiles.map( (p, i) => i === index ? Object.assign({}, p, { gamma: checked ? (p.gamma ?? 1.0) : null }) : p) } Field { anchors.verticalCenter: parent.verticalCenter width: 60 value: modelData.gamma === null || modelData.gamma === undefined ? "" : String(modelData.gamma) placeholder: "0.8" onEdited: Hyprsunset.profiles = Hyprsunset.profiles.map( (p, i) => i === index ? Object.assign({}, p, { gamma: value === "" ? null : parseFloat(value) }) : p) } Item { width: 8; height: 1 } Tab { anchors.verticalCenter: parent.verticalCenter text: "✕" onClicked: Hyprsunset.profiles = Hyprsunset.profiles.filter((p, i) => i !== index) } // The Row is pinned to the card width, so parent.width is // real, but bound it anyway: a narrow enough panel would // make the subtraction negative and put the Row in a // negative-width state. Item { width: Math.max(0, parent.width - 640); height: 1 } } } } Row { spacing: 8 Tab { text: "+ Add profile" onClicked: Hyprsunset.profiles = Hyprsunset.profiles.concat([{ time: "0:00", identity: false, temperature: null, gamma: null }]) } Tab { text: "Live preview"; onClicked: Hyprsunset.preview() } Tab { text: "Save + Restart" selected: true onClicked: Hyprsunset.save() } } Text { width: parent.width wrapMode: Text.Wrap visible: Hyprsunset.notice !== "" text: Hyprsunset.notice color: Hyprsunset.notice.indexOf("invalid") === 0 ? Theme.red : Theme.green font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 3 } } } }