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 }