Warning, /plasma/plasma-workspace/kcms/nightcolor/ui/main.qml is written in an unsupported language. File is not indexed.
0001 /*
0002 SPDX-FileCopyrightText: 2017 Roman Gilg <subdiff@gmail.com>
0003
0004 SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006
0007 import QtQuick 2.15
0008 import QtQuick.Layouts 1.1
0009 import QtQuick.Controls 2.5 as QQC2
0010
0011 import org.kde.kirigami 2.20 as Kirigami
0012 import org.kde.kcmutils as KCM
0013
0014 import org.kde.colorcorrect as CC
0015
0016 import org.kde.private.kcms.nightcolor 1.0
0017
0018 KCM.SimpleKCM {
0019 id: root
0020 property int error: cA.error
0021 property bool defaultRequested: false
0022 property QtObject locator
0023 readonly property bool doneLocating: locator && !(locator.latitude == 0 && locator.longitude == 0)
0024 implicitHeight: Kirigami.Units.gridUnit * 29
0025 implicitWidth: Kirigami.Units.gridUnit * 35
0026
0027 CC.CompositorAdaptor {
0028 id: cA
0029 }
0030
0031 CC.SunCalc {
0032 id: sunCalc
0033 }
0034
0035 // the Geolocator object is created dynamically so we can have control over when geolocation is attempted
0036 // because the object attempts geolocation immediately when created, which is unnecessary (and bad for privacy)
0037
0038 function startLocator() {
0039 root.locator = Qt.createQmlObject('import org.kde.colorcorrect as CC; CC.Geolocator {}', root, "geoLocatorObj");
0040 }
0041
0042 function endLocator() {
0043 root.locator?.destroy();
0044 }
0045
0046 Connections {
0047 target: kcm.nightColorSettings
0048 function onActiveChanged() {
0049 if (kcm.nightColorSettings.active && kcm.nightColorSettings.mode == NightColorMode.Automatic) {
0050 startLocator();
0051 } else {
0052 endLocator();
0053 }
0054 }
0055 }
0056
0057 Component.onCompleted: {
0058 if (kcm.nightColorSettings.mode == NightColorMode.Automatic && kcm.nightColorSettings.active) {
0059 startLocator();
0060 }
0061 }
0062
0063 // Update backend when locator is changed
0064 Connections {
0065 target: root.locator
0066 function onLatitudeChanged() {
0067 kcm.nightColorSettings.latitudeAuto = Math.round(root.locator.latitude * 100) / 100
0068 }
0069 function onLongitudeChanged() {
0070 kcm.nightColorSettings.longitudeAuto = Math.round(root.locator.longitude * 100) / 100
0071 }
0072 }
0073
0074 header: ColumnLayout{
0075 Kirigami.InlineMessage {
0076 id: errorMessage
0077 Layout.fillWidth: true
0078 visible: error != CC.CompositorAdaptor.ErrorCodeSuccess
0079 type: Kirigami.MessageType.Error
0080 text: cA.errorText
0081 }
0082 }
0083
0084 Timer {
0085 id: previewTimer
0086 interval: Kirigami.Units.humanMoment
0087 onTriggered: cA.stopPreview()
0088 }
0089
0090 ColumnLayout {
0091 spacing: 0
0092
0093 QQC2.Label {
0094 Layout.margins: Kirigami.Units.gridUnit
0095 Layout.alignment: Qt.AlignHCenter
0096
0097 Layout.maximumWidth: Math.round(root.width - (Kirigami.Units.gridUnit * 2))
0098 text: i18n("The blue light filter makes the colors on the screen warmer.")
0099 textFormat: Text.PlainText
0100 wrapMode: Text.WordWrap
0101 }
0102
0103 DayNightView {
0104 Layout.margins: Kirigami.Units.smallSpacing
0105 Layout.bottomMargin: Kirigami.Units.gridUnit
0106 Layout.maximumWidth: Kirigami.Units.gridUnit * 30
0107 Layout.alignment: Qt.AlignCenter
0108
0109 readonly property real latitude: kcm.nightColorSettings.mode === NightColorMode.Location
0110 ? kcm.nightColorSettings.latitudeFixed
0111 : (locator?.locatingDone) ? locator.latitude : kcm.nightColorSettings.latitudeAuto
0112 readonly property real longitude: kcm.nightColorSettings.mode === NightColorMode.Location
0113 ? kcm.nightColorSettings.longitudeFixed
0114 : (locator?.locatingDone) ? locator.longitude : kcm.nightColorSettings.longitudeAuto
0115
0116 readonly property var morningTimings: sunCalc.getMorningTimings(latitude, longitude)
0117 readonly property var eveningTimings: sunCalc.getEveningTimings(latitude, longitude)
0118
0119 enabled: kcm.nightColorSettings.active
0120
0121 dayTemperature: kcm.nightColorSettings.dayTemperature
0122 nightTemperature: kcm.nightColorSettings.nightTemperature
0123
0124 alwaysOn: kcm.nightColorSettings.mode === NightColorMode.Constant
0125 dayTransitionOn: kcm.nightColorSettings.mode === NightColorMode.Timings
0126 ? minutesForFixed(kcm.nightColorSettings.morningBeginFixed)
0127 : minutesForDate(morningTimings.begin)
0128 dayTransitionOff: kcm.nightColorSettings.mode === NightColorMode.Timings
0129 ? (minutesForFixed(kcm.nightColorSettings.morningBeginFixed) + kcm.nightColorSettings.transitionTime) % 1440
0130 : minutesForDate(morningTimings.end)
0131 nightTransitionOn: kcm.nightColorSettings.mode === NightColorMode.Timings
0132 ? minutesForFixed(kcm.nightColorSettings.eveningBeginFixed)
0133 : minutesForDate(eveningTimings.begin)
0134 nightTransitionOff: kcm.nightColorSettings.mode === NightColorMode.Timings
0135 ? (minutesForFixed(kcm.nightColorSettings.eveningBeginFixed) + kcm.nightColorSettings.transitionTime) % 1440
0136 : minutesForDate(eveningTimings.end)
0137
0138 function minutesForFixed(dateString) {
0139 // The fixed timings format is "hhmm"
0140 const hours = parseInt(dateString.substring(0, 2), 10)
0141 const mins = parseInt(dateString.substring(2, 4), 10)
0142 return hours * 60 + mins
0143 }
0144 }
0145
0146
0147 Kirigami.FormLayout {
0148 id: parentLayout
0149
0150 QQC2.ComboBox {
0151 id: modeSwitcher
0152 // Work around https://bugs.kde.org/show_bug.cgi?id=403153
0153 Layout.minimumWidth: Kirigami.Units.gridUnit * 17
0154 Kirigami.FormData.label: i18n("Switching times:")
0155 currentIndex: kcm.nightColorSettings.active ? kcm.nightColorSettings.mode + 1 : 0
0156 model: [
0157 i18n("Always off"), // This is not actually a Mode, but represents Night Color being disabled
0158 i18n("Sunset and sunrise at current location"),
0159 i18n("Sunset and sunrise at manual location"),
0160 i18n("Custom times"),
0161 i18n("Always on night light")
0162 ]
0163 onCurrentIndexChanged: {
0164 if (currentIndex !== 0) {
0165 kcm.nightColorSettings.mode = currentIndex - 1;
0166 }
0167 kcm.nightColorSettings.active = (currentIndex !== 0);
0168 if (currentIndex - 1 == NightColorMode.Automatic && kcm.nightColorSettings.active) {
0169 startLocator();
0170 } else {
0171 endLocator();
0172 }
0173 }
0174 }
0175
0176 // Workaround for Layout.margins not working in Kirigami FormLayout (bug 434625)
0177 Item { implicitHeight: Kirigami.Units.largeSpacing }
0178
0179 Item {
0180 Kirigami.FormData.isSection: true
0181 }
0182
0183 GridLayout {
0184 Kirigami.FormData.label: i18n("Day light temperature:")
0185 Kirigami.FormData.buddyFor: tempSliderDay
0186 enabled: kcm.nightColorSettings.active && kcm.nightColorSettings.mode !== NightColorMode.Constant
0187
0188 columns: 4
0189
0190 QQC2.Slider {
0191 id: tempSliderDay
0192 // Match combobox width
0193 Layout.minimumWidth: modeSwitcher.width
0194 Layout.columnSpan: 3
0195 from: kcm.maxDayTemp
0196 to: kcm.minDayTemp
0197 stepSize: -100
0198 live: true
0199
0200 value: kcm.nightColorSettings.dayTemperature
0201
0202 onMoved: {
0203 kcm.nightColorSettings.dayTemperature = value
0204 cA.preview(value)
0205
0206 // This can fire for scroll events; in this case we need
0207 // to use a timer to make the preview message disappear, since
0208 // we can't make it disappear in the onPressedChanged handler
0209 // since there is no press
0210 if (!pressed) {
0211 previewTimer.restart()
0212 }
0213 }
0214 onPressedChanged: {
0215 if (!pressed) {
0216 cA.stopPreview()
0217 }
0218 }
0219
0220 KCM.SettingStateBinding {
0221 configObject: kcm.nightColorSettings
0222 settingName: "DayTemperature"
0223 extraEnabledConditions: kcm.nightColorSettings.active
0224 }
0225 }
0226 QQC2.Label {
0227 text: i18nc("Color temperature in Kelvin", "%1K", tempSliderDay.value)
0228 textFormat: Text.PlainText
0229 }
0230 //row 2
0231 QQC2.Label {
0232 text: i18nc("Night colour blue-ish; no blue light filter activated", "Cool (no filter)")
0233 textFormat: Text.PlainText
0234 }
0235 Item {
0236 Layout.fillWidth: true
0237 }
0238 QQC2.Label {
0239 text: i18nc("Night colour red-ish", "Warm")
0240 textFormat: Text.PlainText
0241 }
0242 Item {}
0243 }
0244
0245 GridLayout {
0246 Kirigami.FormData.label: i18n("Night light temperature:")
0247 Kirigami.FormData.buddyFor: tempSliderNight
0248 enabled: kcm.nightColorSettings.active
0249
0250 columns: 4
0251
0252 QQC2.Slider {
0253 id: tempSliderNight
0254 // Match combobox width
0255 Layout.minimumWidth: modeSwitcher.width
0256 Layout.columnSpan: 3
0257 from: kcm.maxNightTemp
0258 to: kcm.minNightTemp
0259 stepSize: -100
0260 live: true
0261
0262 value: kcm.nightColorSettings.nightTemperature
0263
0264 onMoved: {
0265 kcm.nightColorSettings.nightTemperature = value
0266 cA.preview(value)
0267
0268 // This can fire for scroll events; in this case we need
0269 // to use a timer to make the preview disappear, since
0270 // we can't make it disappear in the onPressedChanged handler
0271 // since there is no press
0272 if (!pressed) {
0273 previewTimer.restart()
0274 }
0275 }
0276 onPressedChanged: {
0277 if (!pressed) {
0278 cA.stopPreview()
0279 }
0280 }
0281
0282 KCM.SettingStateBinding {
0283 configObject: kcm.nightColorSettings
0284 settingName: "NightTemperature"
0285 extraEnabledConditions: kcm.nightColorSettings.active
0286 }
0287 }
0288 QQC2.Label {
0289 text: i18nc("Color temperature in Kelvin", "%1K", tempSliderNight.value)
0290 textFormat: Text.PlainText
0291 }
0292 //row 2
0293 QQC2.Label {
0294 text: i18nc("Night colour blue-ish; no blue light filter activated", "Cool (no filter)")
0295 textFormat: Text.PlainText
0296 }
0297 Item {
0298 Layout.fillWidth: true
0299 }
0300 QQC2.Label {
0301 text: i18nc("Night colour red-ish", "Warm")
0302 textFormat: Text.PlainText
0303 }
0304 Item {}
0305 }
0306
0307 Item { implicitHeight: Kirigami.Units.largeSpacing }
0308
0309 // Show current location in auto mode
0310 QQC2.Label {
0311 Kirigami.FormData.label: i18nc("@label The coordinates for the current location", "Current location:")
0312
0313 visible: kcm.nightColorSettings.mode === NightColorMode.Automatic && kcm.nightColorSettings.active
0314 && root.doneLocating
0315 enabled: kcm.nightColorSettings.active
0316 wrapMode: Text.Wrap
0317 text: i18n("Latitude: %1° Longitude: %2°", Math.round((locator?.latitude || 0) * 100)/100, Math.round((locator?.longitude || 0) * 100)/100)
0318 textFormat: Text.PlainText
0319 }
0320
0321 // Inform about geolocation access in auto mode
0322 // The system settings window likes to take over the cursor with a plain label.
0323 // The TextEdit 'takes priority' over the system settings window trying to eat the mouse,
0324 // allowing us to use the HoverHandler boilerplate for proper link handling
0325 TextEdit {
0326 Layout.maximumWidth: modeSwitcher.width
0327
0328 visible: modeSwitcher.currentIndex - 1 === NightColorMode.Automatic && kcm.nightColorSettings.active
0329 enabled: kcm.nightColorSettings.active
0330
0331 textFormat: TextEdit.RichText
0332 wrapMode: Text.Wrap
0333 readOnly: true
0334
0335 color: Kirigami.Theme.textColor
0336 selectedTextColor: Kirigami.Theme.highlightedTextColor
0337 selectionColor: Kirigami.Theme.highlightColor
0338
0339 text: xi18nc("@info", "The device's location will be periodically updated using GPS (if available), or by sending network information to <link url='https://location.services.mozilla.com'>Mozilla Location Service</link>.")
0340 font: Kirigami.Theme.smallFont
0341
0342 onLinkActivated: (url) => Qt.openUrlExternally(url)
0343
0344 HoverHandler {
0345 acceptedButtons: Qt.NoButton
0346 cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
0347 }
0348 }
0349
0350 // Show time entry fields in manual timings mode
0351 TimeField {
0352 id: evenBeginManField
0353 // Match combobox width
0354 Layout.minimumWidth: modeSwitcher.width
0355 Layout.maximumWidth: modeSwitcher.width
0356 visible: kcm.nightColorSettings.mode === NightColorMode.Timings && kcm.nightColorSettings.active
0357 Kirigami.FormData.label: i18n("Begin night light at:")
0358 backend: kcm.nightColorSettings.eveningBeginFixed
0359 onBackendChanged: {
0360 kcm.nightColorSettings.eveningBeginFixed = backend;
0361 }
0362
0363 KCM.SettingStateBinding {
0364 configObject: kcm.nightColorSettings
0365 settingName: "EveningBeginFixed"
0366 extraEnabledConditions: kcm.nightColorSettings.active && kcm.nightColorSettings.mode === NightColorMode.Timings
0367 }
0368
0369 QQC2.ToolTip {
0370 text: i18n("Input format: HH:MM")
0371 }
0372 }
0373
0374 TimeField {
0375 id: mornBeginManField
0376 // Match combobox width
0377 Layout.minimumWidth: modeSwitcher.width
0378 Layout.maximumWidth: modeSwitcher.width
0379 visible: kcm.nightColorSettings.mode === NightColorMode.Timings && kcm.nightColorSettings.active
0380 Kirigami.FormData.label: i18n("Begin day light at:")
0381 backend: kcm.nightColorSettings.morningBeginFixed
0382 onBackendChanged: {
0383 kcm.nightColorSettings.morningBeginFixed = backend;
0384 }
0385
0386 KCM.SettingStateBinding {
0387 configObject: kcm.nightColorSettings
0388 settingName: "MorningBeginFixed"
0389 extraEnabledConditions: kcm.nightColorSettings.active && kcm.nightColorSettings.mode === NightColorMode.Timings
0390 }
0391
0392 QQC2.ToolTip {
0393 text: i18n("Input format: HH:MM")
0394 }
0395 }
0396
0397 QQC2.SpinBox {
0398 id: transTimeField
0399 visible: kcm.nightColorSettings.mode === NightColorMode.Timings && kcm.nightColorSettings.active
0400 // Match width of combobox and input fields
0401 Layout.minimumWidth: modeSwitcher.width
0402 Kirigami.FormData.label: i18n("Transition duration:")
0403 from: 1
0404 to: 600 // less than 12 hours (in minutes: 720)
0405 value: kcm.nightColorSettings.transitionTime
0406 editable: true
0407 onValueModified: {
0408 kcm.nightColorSettings.transitionTime = value;
0409 }
0410 textFromValue: function(value, locale) {
0411 return i18np("%1 minute", "%1 minutes", value)
0412 }
0413 valueFromText: function(text, locale) {
0414 return parseInt(text);
0415 }
0416
0417 KCM.SettingStateBinding {
0418 configObject: kcm.nightColorSettings
0419 settingName: "TransitionTime"
0420 extraEnabledConditions: kcm.nightColorSettings.active
0421 }
0422
0423 QQC2.ToolTip {
0424 text: i18n("Input minutes - min. 1, max. 600")
0425 }
0426 }
0427
0428 QQC2.Label {
0429 id: manualTimingsError
0430 visible: {
0431 var day = 86400000;
0432 var trTime = transTimeField.value * 60 * 1000;
0433 var mor = mornBeginManField.getNormedDate();
0434 var eve = evenBeginManField.getNormedDate();
0435
0436 var diffMorEve = eve > mor ? eve - mor : mor - eve;
0437 var diffMin = Math.min(diffMorEve, day - diffMorEve);
0438
0439 return diffMin <= trTime && kcm.nightColorSettings.active;
0440 }
0441 font.italic: true
0442 text: i18n("Error: Transition time overlaps.")
0443 textFormat: Text.PlainText
0444 }
0445 }
0446
0447 // Show location chooser in manual location mode
0448 LocationsFixedView {
0449 visible: kcm.nightColorSettings.mode === NightColorMode.Location && kcm.nightColorSettings.active
0450 Layout.alignment: Qt.AlignHCenter
0451 enabled: kcm.nightColorSettings.active
0452 }
0453
0454 Item {
0455 visible: kcm.nightColorSettings.active
0456 && kcm.nightColorSettings.mode === NightColorMode.Automatic
0457 && (!locator || !root.doneLocating)
0458 Layout.topMargin: Kirigami.Units.largeSpacing * 4
0459 Layout.fillWidth: true
0460 implicitHeight: loadingPlaceholder.implicitHeight
0461
0462 Kirigami.LoadingPlaceholder {
0463 id: loadingPlaceholder
0464
0465 text: i18nc("@info:placeholder", "Locating…")
0466 anchors.centerIn: parent
0467 }
0468 }
0469 }
0470 }