Changeset View
Changeset View
Standalone View
Standalone View
Modules/energy/package/contents/ui/main.qml
| Show All 10 Lines | |||||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
| 12 | * GNU General Public License for more details. * | 12 | * GNU General Public License for more details. * | ||
| 13 | * * | 13 | * * | ||
| 14 | * You should have received a copy of the GNU General Public License * | 14 | * You should have received a copy of the GNU General Public License * | ||
| 15 | * along with this program; if not, write to the * | 15 | * along with this program; if not, write to the * | ||
| 16 | * Free Software Foundation, Inc., * | 16 | * Free Software Foundation, Inc., * | ||
| 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * | 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * | ||
| 18 | ***************************************************************************/ | 18 | ***************************************************************************/ | ||
| 19 | 19 | | |||
| 20 | import QtQuick 2.2 | 20 | import QtQuick 2.5 | ||
broulik: and also getting rid of QQC1 | |||||
| 21 | import QtQuick.Controls 1.3 | 21 | import QtQuick.Controls 2.12 | ||
I might be too aggressive here, what would be the best version to set here ? meven: I might be too aggressive here, what would be the best version to set here ? | |||||
ngraham: 2.5 is always a safe bet. | |||||
| 22 | import QtQuick.Controls 2.0 as QQC2 | | |||
| 23 | import QtQuick.Layouts 1.1 | 22 | import QtQuick.Layouts 1.1 | ||
| 23 | import org.kde.kirigami 2.5 as Kirigami | ||||
| 24 | 24 | | |||
| 25 | import org.kde.kquickcontrolsaddons 2.0 | 25 | import org.kde.kquickcontrolsaddons 2.0 | ||
| 26 | import org.kde.kinfocenter.energy.private 1.0 | 26 | import org.kde.kinfocenter.energy.private 1.0 | ||
| 27 | 27 | | |||
| 28 | //We need units from it | 28 | //We need units from it | ||
| 29 | import org.kde.plasma.core 2.0 as PlasmaCore | 29 | import org.kde.plasma.core 2.0 as PlasmaCore | ||
broulik: A goal is to get rid of these plasma imports, too | |||||
Now that you've imported Kirigami, you can use Kirigami.Units and drop the PlasmaCore import filipf: Now that you've imported Kirigami, you can use Kirigami.Units and drop the PlasmaCore import | |||||
| 30 | import org.kde.plasma.extras 2.0 as PlasmaExtras | 30 | import org.kde.plasma.extras 2.0 as PlasmaExtras | ||
| 31 | 31 | | |||
| 32 | import org.kde.plasma.workspace.components 2.0 as WorkspaceComponents | 32 | import org.kde.plasma.workspace.components 2.0 as WorkspaceComponents | ||
| 33 | 33 | | |||
| 34 | Item { | 34 | Item { | ||
| 35 | id: root | 35 | id: root | ||
| 36 | property QtObject currentBattery: null | 36 | property QtObject currentBattery: null | ||
| 37 | property string currentUdi: "" | 37 | property string currentUdi: "" | ||
| 38 | property bool compact: (root.width / units.gridUnit) < 25 | 38 | property bool compact: (root.width / units.gridUnit) < 25 | ||
| 39 | 39 | | |||
| 40 | onCurrentBatteryChanged: { | 40 | onCurrentBatteryChanged: { | ||
| 41 | if (!currentBattery) { | 41 | if (!currentBattery) { | ||
| 42 | currentBattery = kcm.batteries.get(0) | 42 | currentBattery = kcm.batteries.get(0) | ||
| 43 | currentUdi = kcm.batteries.udi(0) | 43 | currentUdi = kcm.batteries.udi(0) | ||
| 44 | } | 44 | } | ||
| 45 | } | 45 | } | ||
| 46 | 46 | | |||
| 47 | SystemPalette { id: sysPal; colorGroup: SystemPalette.Active } | 47 | SystemPalette { id: sysPal; colorGroup: SystemPalette.Active } | ||
| 48 | 48 | | |||
filipf: there is trailing space in this row | |||||
| 49 | property bool showWakeUps: true | 49 | property bool showWakeUps: true | ||
| 50 | property int historyType: HistoryModel.ChargeType | 50 | property int historyType: HistoryModel.ChargeType | ||
| 51 | 51 | | |||
| 52 | readonly property var details: [ | 52 | readonly property var details: [ | ||
| 53 | { | 53 | { | ||
| 54 | title: i18n("Battery"), | 54 | title: i18n("Battery"), | ||
| 55 | data: [ | 55 | data: [ | ||
| 56 | {label: i18n("Rechargeable"), value: "rechargeable"}, | 56 | {label: i18n("Rechargeable"), value: "rechargeable"}, | ||
| ▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Line(s) | |||||
| 102 | Component.onCompleted: { | 102 | Component.onCompleted: { | ||
| 103 | currentBattery = kcm.batteries.get(0) | 103 | currentBattery = kcm.batteries.get(0) | ||
| 104 | currentUdi = kcm.batteries.udi(0) | 104 | currentUdi = kcm.batteries.udi(0) | ||
| 105 | } | 105 | } | ||
| 106 | 106 | | |||
| 107 | implicitWidth: units.gridUnit * 25 | 107 | implicitWidth: units.gridUnit * 25 | ||
| 108 | implicitHeight: !!currentBattery ? units.gridUnit * 25 : units.gridUnit * 12 | 108 | implicitHeight: !!currentBattery ? units.gridUnit * 25 : units.gridUnit * 12 | ||
| 109 | 109 | | |||
| 110 | SystemPalette { | 110 | readonly property var timespanComboChoices: [i18n("Last hour"),i18n("Last 2 hours"),i18n("Last 12 hours"),i18n("Last 24 hours"),i18n("Last 48 hours"), i18n("Last 7 days")] | ||
| 111 | id: syspal | 111 | readonly property var timespanComboDurations: [3600, 7200, 43200, 86400, 172800, 604800] | ||
| 112 | } | | |||
| 113 | 112 | | |||
| 114 | ScrollView { | 113 | Kirigami.ScrollablePage { | ||
| 115 | id: scrollView | | |||
| 116 | anchors.fill: parent | 114 | anchors.fill: parent | ||
| 117 | 115 | | |||
| 118 | horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff | | |||
| 119 | | ||||
| 120 | ColumnLayout { | 116 | ColumnLayout { | ||
| 121 | id: column | 117 | id: column | ||
| 122 | 118 | Kirigami.ScrollablePage { | |||
| 123 | width: scrollView.viewport.width | | |||
| 124 | spacing: units.largeSpacing | | |||
| 125 | | ||||
| 126 | ScrollView { | | |||
| 127 | id: tabView | 119 | id: tabView | ||
| 128 | Layout.fillWidth: true | | |||
| 129 | Layout.minimumHeight: units.gridUnit * 3 | 120 | Layout.minimumHeight: units.gridUnit * 3 | ||
| 130 | Layout.maximumHeight: Layout.minimumHeight | 121 | Layout.maximumHeight: Layout.minimumHeight | ||
| 131 | 122 | | |||
| 132 | frameVisible: true | 123 | // frameVisible: true | ||
| 133 | visible: kcm.batteries.count > 1 | 124 | visible: kcm.batteries.count > 1 | ||
| 134 | 125 | | |||
| 135 | verticalScrollBarPolicy: Qt.ScrollBarAlwaysOff | 126 | verticalScrollBarPolicy: ScrollBar.AlwaysOff | ||
| 136 | 127 | | |||
| 137 | Row { | 128 | Row { | ||
| 138 | Repeater { | 129 | Repeater { | ||
| 139 | model: kcm.batteries | 130 | model: kcm.batteries | ||
| 140 | 131 | | |||
| 141 | Button { | 132 | Button { | ||
| 142 | id: button | 133 | id: button | ||
| 143 | width: height | 134 | width: height | ||
| 144 | height: tabView.viewport.height | 135 | height: tabView.height | ||
| 145 | checked: model.battery == root.currentBattery | 136 | checked: model.battery == root.currentBattery | ||
| 146 | checkable: true | 137 | checkable: true | ||
| 147 | onClicked: { | 138 | onClicked: { | ||
| 148 | root.currentUdi = model.udi | 139 | root.currentUdi = model.udi | ||
| 149 | root.currentBattery = model.battery | 140 | root.currentBattery = model.battery | ||
| 150 | // override checked property | 141 | // override checked property | ||
| 151 | checked = Qt.binding(function() { | 142 | checked = Qt.binding(function() { | ||
| 152 | return model.battery == root.currentBattery | 143 | return model.battery == root.currentBattery | ||
| Show All 26 Lines | 160 | batteryType: { | |||
| 179 | } | 170 | } | ||
| 180 | } | 171 | } | ||
| 181 | percent: model.battery.chargePercent | 172 | percent: model.battery.chargePercent | ||
| 182 | //pluggedIn: model.battery.chargeState === 1 // Makes it hard to see | 173 | //pluggedIn: model.battery.chargeState === 1 // Makes it hard to see | ||
| 183 | } | 174 | } | ||
| 184 | 175 | | |||
| 185 | ProgressBar { // TODO make progress bar not eat mouse events | 176 | ProgressBar { // TODO make progress bar not eat mouse events | ||
| 186 | Layout.fillWidth: true | 177 | Layout.fillWidth: true | ||
| 187 | minimumValue: 0 | 178 | from: 0 | ||
| 188 | maximumValue: 100 | 179 | to: 100 | ||
| 189 | value: model.battery.chargePercent | 180 | value: model.battery.chargePercent | ||
| 190 | enabled: button.checked ? false : true | 181 | enabled: button.checked ? false : true | ||
| 191 | } | 182 | } | ||
| 192 | } | 183 | } | ||
| 193 | } | 184 | } | ||
| 194 | } | 185 | } | ||
| 195 | } | 186 | } | ||
| 196 | } | 187 | } | ||
| Show All 30 Lines | 194 | GridLayout { | |||
| 227 | 218 | | |||
| 228 | Item { | 219 | Item { | ||
| 229 | Layout.fillWidth: true | 220 | Layout.fillWidth: true | ||
| 230 | } | 221 | } | ||
| 231 | 222 | | |||
| 232 | ComboBox { | 223 | ComboBox { | ||
| 233 | id: timespanCombo | 224 | id: timespanCombo | ||
| 234 | Layout.minimumWidth: units.gridUnit * 6 | 225 | Layout.minimumWidth: units.gridUnit * 6 | ||
| 235 | model: [ | 226 | model: timespanComboChoices | ||
| 236 | {text: i18n("Last hour"), value: 3600}, | | |||
| 237 | {text: i18n("Last 2 hours"), value: 7200}, | | |||
| 238 | {text: i18n("Last 12 hours"), value: 43200}, | | |||
| 239 | {text: i18n("Last 24 hours"), value: 86400}, | | |||
| 240 | {text: i18n("Last 48 hours"), value: 172800}, | | |||
| 241 | {text: i18n("Last 7 days"), value: 604800} | | |||
| 242 | ] | | |||
| 243 | Accessible.name: i18n("Timespan") | 227 | Accessible.name: i18n("Timespan") | ||
| 244 | Accessible.description: i18n("Timespan of data to display") | 228 | Accessible.description: i18n("Timespan of data to display") | ||
| 245 | } | 229 | } | ||
| 246 | 230 | | |||
| 247 | Button { | 231 | Button { | ||
| 248 | iconName: "view-refresh" | 232 | icon.name: "view-refresh" | ||
| 249 | tooltip: i18n("Refresh") | 233 | hoverEnabled: true | ||
| 250 | Accessible.name: tooltip | 234 | ToolTip.text: i18n("Refresh") | ||
| 235 | ToolTip.visible: hovered | ||||
| 236 | ToolTip.delay: Kirigami.Units.toolTipDelay | ||||
| 237 | Accessible.name: ToolTip.text | ||||
| 251 | onClicked: history.refresh() | 238 | onClicked: history.refresh() | ||
| 252 | } | 239 | } | ||
| 253 | } | 240 | } | ||
| 254 | 241 | | |||
| 255 | HistoryModel { | 242 | HistoryModel { | ||
| 256 | id: history | 243 | id: history | ||
| 257 | duration: timespanCombo.model[timespanCombo.currentIndex].value | 244 | duration: timespanComboDurations[timespanCombo.currentIndex] | ||
| 258 | device: currentUdi | 245 | device: currentUdi | ||
| 259 | type: root.historyType | 246 | type: root.historyType | ||
| 260 | } | 247 | } | ||
| 261 | 248 | | |||
| 262 | Graph { | 249 | Graph { | ||
| 263 | id: graph | 250 | id: graph | ||
| 264 | Layout.fillWidth: true | 251 | Layout.fillWidth: true | ||
| 265 | Layout.minimumHeight: column.width / 3 | 252 | Layout.minimumHeight: column.width / 3 | ||
| Show All 15 Lines | 260 | yMax: { | |||
| 281 | } else { | 268 | } else { | ||
| 282 | return 100; | 269 | return 100; | ||
| 283 | } | 270 | } | ||
| 284 | } | 271 | } | ||
| 285 | yStep: root.historyType == HistoryModel.RateType ? 10 : 20 | 272 | yStep: root.historyType == HistoryModel.RateType ? 10 : 20 | ||
| 286 | visible: history.count > 1 | 273 | visible: history.count > 1 | ||
| 287 | } | 274 | } | ||
| 288 | 275 | | |||
| 289 | QQC2.Label { | 276 | Label { | ||
| 290 | Layout.fillWidth: true | 277 | Layout.fillWidth: true | ||
| 291 | Layout.minimumHeight: column.width / 3 | 278 | Layout.minimumHeight: column.width / 3 | ||
| 292 | Layout.maximumHeight: column.width / 3 | 279 | Layout.maximumHeight: column.width / 3 | ||
| 293 | horizontalAlignment: Text.AlignHCenter | 280 | horizontalAlignment: Text.AlignHCenter | ||
| 294 | verticalAlignment: Text.AlignVCenter | 281 | verticalAlignment: Text.AlignVCenter | ||
| 295 | text: i18n("This type of history is currently not available for this device.") | 282 | text: i18n("This type of history is currently not available for this device.") | ||
| 296 | wrapMode: Text.WordWrap | 283 | wrapMode: Text.WordWrap | ||
| 297 | visible: !graph.visible | 284 | visible: !graph.visible | ||
| ▲ Show 20 Lines • Show All 63 Lines • ▼ Show 20 Line(s) | 339 | RowLayout { | |||
| 361 | 348 | | |||
| 362 | ColumnLayout { | 349 | ColumnLayout { | ||
| 363 | Layout.fillWidth: true | 350 | Layout.fillWidth: true | ||
| 364 | spacing: 0 | 351 | spacing: 0 | ||
| 365 | 352 | | |||
| 366 | RowLayout { | 353 | RowLayout { | ||
| 367 | Layout.fillWidth: true | 354 | Layout.fillWidth: true | ||
| 368 | 355 | | |||
| 369 | QQC2.Label { | 356 | Label { | ||
| 370 | Layout.fillWidth: true | 357 | Layout.fillWidth: true | ||
| 371 | elide: Text.ElideRight | 358 | elide: Text.ElideRight | ||
| 372 | text: model.prettyName || model.name | 359 | text: model.prettyName || model.name | ||
| 373 | } | 360 | } | ||
| 374 | 361 | | |||
| 375 | /*Label { | 362 | /*Label { | ||
| 376 | text: i18n("System Service") | 363 | text: i18n("System Service") | ||
| 377 | visible: !model.userSpace | 364 | visible: !model.userSpace | ||
| 378 | opacity: 0.6 | 365 | opacity: 0.6 | ||
| 379 | }*/ | 366 | }*/ | ||
| 380 | } | 367 | } | ||
| 381 | 368 | | |||
| 382 | ProgressBar { | 369 | ProgressBar { | ||
| 383 | Layout.fillWidth: true | 370 | Layout.fillWidth: true | ||
| 384 | minimumValue: 0 | 371 | from: 0 | ||
| 385 | maximumValue: 100 | 372 | to: 100 | ||
| 386 | value: model.wakeUps / kcm.wakeUps.total * 100 | 373 | value: model.wakeUps / kcm.wakeUps.total * 100 | ||
| 387 | } | 374 | } | ||
| 388 | } | 375 | } | ||
| 389 | } | 376 | } | ||
| 390 | } | 377 | } | ||
| 391 | } | 378 | } | ||
| 392 | } | 379 | } | ||
| 393 | } | 380 | } | ||
| 394 | 381 | | |||
| 395 | Rectangle { | 382 | Rectangle { | ||
| 396 | Layout.fillWidth: true | 383 | Layout.fillWidth: true | ||
| 397 | height: 1 | 384 | height: 1 | ||
| 398 | color: "#ccc" // FIXME palette | 385 | color: "#ccc" // FIXME palette | ||
| 399 | //Layout.topMargin: (compact ? units.gridUnit * 2 : 0) | 386 | //Layout.topMargin: (compact ? units.gridUnit * 2 : 0) | ||
| 400 | visible: wakeUpsGrid.visible | 387 | visible: wakeUpsGrid.visible | ||
| 401 | } | 388 | } | ||
| 402 | 389 | | |||
| 403 | ColumnLayout { | 390 | ColumnLayout { | ||
| 404 | id: detailsColumn | 391 | id: detailsColumn | ||
| 405 | property int legendWidth: 10 | | |||
| 406 | 392 | | |||
| 407 | Layout.fillWidth: true | 393 | Layout.fillWidth: true | ||
| 408 | spacing: 0 | | |||
| 409 | visible: !!currentBattery | 394 | visible: !!currentBattery | ||
| 410 | 395 | | |||
| 411 | Repeater { | 396 | Repeater { | ||
| 397 | id: titleRepeater | ||||
| 412 | model: root.details | 398 | model: root.details | ||
| 399 | property list<Kirigami.FormLayout> layouts | ||||
| 413 | 400 | | |||
| 414 | ColumnLayout { | 401 | delegate: Kirigami.FormLayout { | ||
| 415 | spacing: 0//units.smallSpacing | 402 | id: currentLayout | ||
| 416 | 403 | | |||
| 417 | PlasmaExtras.Heading { | 404 | Component.onCompleted: { | ||
| 418 | level: 4 | 405 | // ensure that all visible FormLayout share the same set of twinFormLayouts | ||
| 419 | color: sysPal.text | 406 | titleRepeater.layouts.push(currentLayout); | ||
| 407 | for (var i = 0, length = titleRepeater.layouts.length; i < length; ++i) { | ||||
| 408 | titleRepeater.layouts[i].twinFormLayouts = titleRepeater.layouts; | ||||
| 409 | } | ||||
| 410 | } | ||||
| 411 | | ||||
| 412 | Kirigami.Heading { | ||||
| 420 | text: modelData.title | 413 | text: modelData.title | ||
| 414 | Kirigami.FormData.isSection: true | ||||
| 415 | level: 2 | ||||
| 421 | // HACK hide section header if all labels are invisible | 416 | // HACK hide section header if all labels are invisible | ||
| 422 | visible: { | 417 | visible: { | ||
| 423 | for (var i = 0, length = detailsRepeater.count; i < length; ++i) { | 418 | for (var i = 0, length = detailsRepeater.count; i < length; ++i) { | ||
| 424 | var item = detailsRepeater.itemAt(i) | 419 | var item = detailsRepeater.itemAt(i) | ||
| 425 | if (item && item.visible) { | 420 | if (item && item.visible) { | ||
| 426 | return true | 421 | return true | ||
| 427 | } | 422 | } | ||
| 428 | } | 423 | } | ||
| 429 | 424 | | |||
| 430 | return false | 425 | return false | ||
| 431 | } | 426 | } | ||
| 432 | } | 427 | } | ||
| 433 | 428 | | |||
| 434 | Repeater { | 429 | Repeater { | ||
| 435 | id: detailsRepeater | 430 | id: detailsRepeater | ||
| 436 | model: modelData.data || [] | 431 | model: modelData.data || [] | ||
| 437 | 432 | | |||
| 438 | RowLayout { | 433 | Label { | ||
filipf: trailing space her as well, as well as in the preceding row | |||||
| 439 | Layout.fillWidth: true | | |||
| 440 | spacing: units.smallSpacing * 2 | | |||
| 441 | visible: valueLabel.text !== "" | | |||
| 442 | | ||||
| 443 | QQC2.Label { | | |||
| 444 | Layout.minimumWidth: detailsColumn.legendWidth + units.gridUnit | | |||
| 445 | horizontalAlignment: Text.AlignRight | | |||
| 446 | text: i18n("%1:", modelData.label) | | |||
| 447 | wrapMode: Text.NoWrap | | |||
| 448 | opacity: 0.8 | | |||
| 449 | onPaintedWidthChanged: { | | |||
| 450 | if (paintedWidth > detailsColumn.legendWidth) { | | |||
| 451 | detailsColumn.legendWidth = paintedWidth | | |||
| 452 | } | | |||
| 453 | } | | |||
| 454 | } | | |||
| 455 | | ||||
| 456 | QQC2.Label { | | |||
| 457 | id: valueLabel | 434 | id: valueLabel | ||
| 458 | Layout.fillWidth: true | 435 | Kirigami.FormData.label: i18n("%1:", modelData.label) | ||
| 459 | text: { | 436 | text: { | ||
| 460 | var value = currentBattery[modelData.value] | 437 | var value = currentBattery[modelData.value] | ||
| 461 | 438 | | |||
| 462 | if (typeof value === "boolean") { | 439 | if (typeof value === "boolean") { | ||
| 463 | if (value) { | 440 | if (value) { | ||
| 464 | return i18n("Yes") | 441 | return i18n("Yes") | ||
| 465 | } else { | 442 | } else { | ||
| 466 | return i18n("No") | 443 | return i18n("No") | ||
| 467 | } | 444 | } | ||
| 468 | } | 445 | } | ||
| 469 | 446 | | |||
| 470 | if (!value) { | 447 | if (!value) { | ||
broulik: Shouldn't be neccessary as it's `QQC2.Label` | |||||
For breeze dark this makes the label, dark gray on a dark background. See before screenshot. Could it be a breeze dark bug ? meven: For breeze dark this makes the label, dark gray on a dark background. See before screenshot. | |||||
| 471 | return "" | 448 | return "" | ||
| 472 | } | 449 | } | ||
| 473 | 450 | | |||
| 474 | var precision = modelData.precision | 451 | var precision = modelData.precision | ||
| 475 | if (typeof precision === "number") { // round to decimals | 452 | if (typeof precision === "number") { // round to decimals | ||
| 476 | value = Number(value).toLocaleString(Qt.locale(), "f", precision) | 453 | value = Number(value).toLocaleString(Qt.locale(), "f", precision) | ||
| 477 | } | 454 | } | ||
| 478 | 455 | | |||
| 479 | if (modelData.modifier && root["modifier_" + modelData.modifier]) { | 456 | if (modelData.modifier && root["modifier_" + modelData.modifier]) { | ||
| 480 | value = root["modifier_" + modelData.modifier](value) | 457 | value = root["modifier_" + modelData.modifier](value) | ||
| 481 | } | 458 | } | ||
| 482 | 459 | | |||
| 483 | if (modelData.unit) { | 460 | if (modelData.unit) { | ||
| 484 | value = i18nc("%1 is value, %2 is unit", "%1 %2", value, modelData.unit) | 461 | value = i18nc("%1 is value, %2 is unit", "%1 %2", value, modelData.unit) | ||
| 485 | } | 462 | } | ||
| 486 | 463 | | |||
| 487 | return value | 464 | return value | ||
| 488 | } | 465 | } | ||
| 489 | } | 466 | visible: valueLabel.text !== "" | ||
| 490 | } | 467 | } | ||
| 491 | } | 468 | } | ||
| 492 | } | 469 | } | ||
| 493 | } | 470 | } | ||
| 494 | } | 471 | } | ||
| 495 | } | 472 | } | ||
| 496 | } | 473 | } | ||
| 497 | } | 474 | } | ||
and also getting rid of QQC1