Warning, /plasma/discover/discover/qml/UpdatesPage.qml is written in an unsupported language. File is not indexed.
0001 pragma ComponentBehavior: Bound 0002 0003 import QtQuick 0004 import QtQuick.Controls as QQC2 0005 import QtQuick.Layouts 0006 import org.kde.discover as Discover 0007 import org.kde.discover.app as DiscoverApp 0008 import org.kde.kirigami as Kirigami 0009 0010 DiscoverPage { 0011 id: page 0012 0013 title: i18n("Updates") 0014 0015 property string footerLabel: "" 0016 property int footerProgress: 0 0017 property bool busy: false 0018 readonly property string name: title 0019 0020 Discover.ResourcesUpdatesModel { 0021 id: resourcesUpdatesModel 0022 onPassiveMessage: { 0023 sheet.errorMessage = message; 0024 sheet.visible = true; 0025 } 0026 onIsProgressingChanged: { 0027 if (!isProgressing) { 0028 resourcesUpdatesModel.prepare() 0029 } 0030 } 0031 0032 Component.onCompleted: { 0033 if (!isProgressing) { 0034 resourcesUpdatesModel.prepare() 0035 } 0036 } 0037 } 0038 0039 Kirigami.OverlaySheet { 0040 id: sheet 0041 0042 property string errorMessage: "" 0043 0044 parent: page.QQC2.Overlay.overlay 0045 0046 title: contentLoader.sourceComponent === friendlyMessageComponent ? i18n("Update Issue") : i18n("Technical details") 0047 0048 Loader { 0049 id: contentLoader 0050 active: true 0051 sourceComponent: friendlyMessageComponent 0052 0053 Component { 0054 id: friendlyMessageComponent 0055 0056 ColumnLayout { 0057 QQC2.Label { 0058 id: friendlyMessage 0059 Layout.fillWidth: true 0060 Layout.maximumWidth: Math.round(page.width * 0.75) 0061 Layout.bottomMargin: Kirigami.Units.largeSpacing * 2 0062 text: i18n("There was an issue installing this update. Please try again later.") 0063 wrapMode: Text.WordWrap 0064 } 0065 QQC2.Button { 0066 id: seeDetailsAndreportIssueButton 0067 Layout.alignment: Qt.AlignRight 0068 text: i18n("See Technical Details") 0069 icon.name: "view-process-system" 0070 onClicked: { 0071 contentLoader.sourceComponent = nerdyDetailsComponent; 0072 } 0073 } 0074 } 0075 } 0076 0077 Component { 0078 id: nerdyDetailsComponent 0079 0080 ColumnLayout { 0081 spacing: Kirigami.Units.smallSpacing 0082 0083 QQC2.TextArea { 0084 Layout.fillWidth: true 0085 text: sheet.errorMessage 0086 textFormat: TextEdit.RichText 0087 wrapMode: TextEdit.Wrap 0088 } 0089 0090 QQC2.Label { 0091 Layout.fillWidth: true 0092 Layout.maximumWidth: Math.round(page.width*0.75) 0093 Layout.topMargin: Kirigami.Units.largeSpacing 0094 Layout.bottomMargin: Kirigami.Units.largeSpacing 0095 text: i18nc("@info %1 is the name of the user's distro/OS", "If the error indicated above looks like a real issue and not a temporary network error, please report it to %1, not KDE.", Discover.ResourcesModel.distroName) 0096 wrapMode: Text.WordWrap 0097 } 0098 0099 RowLayout { 0100 Layout.fillWidth: true 0101 0102 QQC2.Button { 0103 text: i18n("Copy Text") 0104 icon.name: "edit-copy" 0105 onClicked: { 0106 app.copyTextToClipboard(sheet.errorMessage); 0107 window.showPassiveNotification(i18nc("@info %1 is the name of the user's distro/OS", "Error message copied. Remember to report it to %1, not KDE!", Discover.ResourcesModel.distroName)); 0108 } 0109 } 0110 0111 Item { Layout.fillWidth: true} 0112 0113 QQC2.Button { 0114 text: i18nc("@action:button %1 is the name of the user's distro/OS", "Report Issue to %1", Discover.ResourcesModel.distroName) 0115 icon.name: "tools-report-bug" 0116 onClicked: { 0117 Qt.openUrlExternally(Discover.ResourcesModel.distroBugReportUrl()) 0118 sheet.visible = false 0119 } 0120 } 0121 } 0122 } 0123 } 0124 } 0125 0126 // Ensure that friendly message is shown if the user closes the sheet and 0127 // then opens it again 0128 onVisibleChanged: if (visible) { 0129 contentLoader.sourceComponent = friendlyMessageComponent; 0130 } 0131 } 0132 0133 Discover.UpdateModel { 0134 id: updateModel 0135 backend: resourcesUpdatesModel 0136 } 0137 0138 Kirigami.Action { 0139 id: updateAction 0140 text: page.unselected > 0 ? i18nc("@action:button as in, 'update the selected items' ", "Update Selected") : i18nc("@action:button as in, 'update all items'", "Update All") 0141 visible: updateModel.toUpdateCount 0142 icon.name: "update-none" 0143 0144 function anyPageHeaderChildrenVisible() { 0145 return page.header.children.some(item => item?.visible && item instanceof Kirigami.InlineMessage); 0146 } 0147 0148 enabled: !resourcesUpdatesModel.isProgressing && !Discover.ResourcesModel.isFetching && !anyPageHeaderChildrenVisible() 0149 onTriggered: resourcesUpdatesModel.updateAll() 0150 } 0151 0152 header: ColumnLayout { 0153 id: errorsColumn 0154 0155 spacing: Kirigami.Units.smallSpacing 0156 0157 DiscoverInlineMessage { 0158 Layout.fillWidth: true 0159 Layout.margins: Kirigami.Units.smallSpacing 0160 inlineMessage: Discover.ResourcesModel.inlineMessage 0161 } 0162 0163 Repeater { 0164 model: resourcesUpdatesModel.errorMessages 0165 delegate: Kirigami.InlineMessage { 0166 id: inline 0167 0168 required property string modelData 0169 0170 Layout.fillWidth: true 0171 Layout.margins: Kirigami.Units.smallSpacing 0172 text: modelData 0173 visible: true 0174 type: Kirigami.MessageType.Error 0175 onVisibleChanged: errorsColumn.childrenChanged() 0176 0177 actions: [ 0178 Kirigami.Action { 0179 icon.name: "dialog-cancel" 0180 text: i18n("Ignore") 0181 onTriggered: { 0182 inline.visible = false 0183 } 0184 } 0185 ] 0186 } 0187 } 0188 } 0189 0190 footer: ColumnLayout { 0191 width: parent.width 0192 spacing: 0 0193 0194 QQC2.ScrollView { 0195 id: scv 0196 Layout.fillWidth: true 0197 Layout.preferredHeight: visible ? Kirigami.Units.gridUnit * 10 : 0 0198 visible: log.contents.length > 0 0199 QQC2.TextArea { 0200 readOnly: true 0201 text: log.contents 0202 wrapMode: TextEdit.Wrap 0203 0204 cursorPosition: text.length - 1 0205 font.family: "monospace" 0206 0207 Discover.ReadFile { 0208 id: log 0209 filter: ".*ALPM-SCRIPTLET\\] .*" 0210 path: "/var/log/pacman.log" 0211 } 0212 } 0213 } 0214 0215 QQC2.ToolBar { 0216 id: footerToolbar 0217 Layout.fillWidth: true 0218 visible: (updateModel.totalUpdatesCount > 0 && resourcesUpdatesModel.isProgressing) || updateModel.hasUpdates 0219 0220 position: QQC2.ToolBar.Footer 0221 0222 contentItem: RowLayout { 0223 QQC2.ToolButton { 0224 enabled: page.unselected > 0 && updateAction.enabled && !Discover.ResourcesModel.isFetching 0225 visible: updateModel.totalUpdatesCount > 1 && !resourcesUpdatesModel.isProgressing 0226 icon.name: "edit-select-all" 0227 text: i18n("Select All") 0228 onClicked: { updateModel.checkAll(); } 0229 } 0230 0231 QQC2.ToolButton { 0232 enabled: page.unselected !== updateModel.totalUpdatesCount && updateAction.enabled && !Discover.ResourcesModel.isFetching 0233 visible: updateModel.totalUpdatesCount > 1 && !resourcesUpdatesModel.isProgressing 0234 icon.name: "edit-select-none" 0235 text: i18n("Select None") 0236 onClicked: { updateModel.uncheckAll(); } 0237 } 0238 0239 QQC2.CheckBox { 0240 id: rebootAtEnd 0241 visible: resourcesUpdatesModel.needsReboot && resourcesUpdatesModel.isProgressing 0242 text: i18n("Restart automatically after update has completed"); 0243 } 0244 0245 QQC2.Label { 0246 Layout.fillWidth: true 0247 Layout.rightMargin: Kirigami.Units.largeSpacing 0248 horizontalAlignment: Text.AlignRight 0249 text: i18n("Total size: %1", updateModel.updateSize) 0250 elide: Text.ElideLeft 0251 } 0252 } 0253 } 0254 } 0255 0256 Kirigami.Action { 0257 id: cancelUpdateAction 0258 icon.name: "dialog-cancel" 0259 text: i18n("Cancel") 0260 enabled: resourcesUpdatesModel.transaction && resourcesUpdatesModel.transaction.isCancellable 0261 onTriggered: resourcesUpdatesModel.transaction.cancel() 0262 } 0263 0264 readonly property int unselected: (updateModel.totalUpdatesCount - updateModel.toUpdateCount) 0265 0266 supportsRefreshing: true 0267 onRefreshingChanged: { 0268 Discover.ResourcesModel.updateAction.triggered() 0269 refreshing = false 0270 } 0271 0272 readonly property Item report: ColumnLayout { 0273 parent: page 0274 anchors.fill: parent 0275 anchors.margins: Kirigami.Units.largeSpacing * 2 0276 Item { 0277 Layout.fillHeight: true 0278 width: 1 0279 } 0280 0281 Kirigami.Action { 0282 id: restartAction 0283 icon.name: "system-reboot" 0284 text: i18n("Restart Now") 0285 visible: false 0286 onTriggered: app.reboot() 0287 } 0288 Kirigami.LoadingPlaceholder { 0289 id: statusLabel 0290 icon.name: { 0291 if (page.footerProgress === 0 && page.footerLabel !== "" && !page.busy) { 0292 return "update-none" 0293 } else { 0294 return "" 0295 } 0296 } 0297 text: page.footerLabel 0298 determinate: true 0299 progressBar.value: page.footerProgress 0300 } 0301 0302 Item { 0303 Layout.fillHeight: true 0304 width: 1 0305 } 0306 } 0307 ListView { 0308 id: updatesView 0309 currentIndex: -1 0310 reuseItems: true 0311 clip: true 0312 0313 model: DiscoverApp.QSortFilterProxyModel { 0314 sourceModel: updateModel 0315 sortRole: Discover.UpdateModel.SectionResourceProgressRole 0316 } 0317 0318 section { 0319 property: "section" 0320 delegate: Kirigami.ListSectionHeader { 0321 required property string section 0322 0323 width: updatesView.width 0324 label: section 0325 } 0326 } 0327 0328 delegate: QQC2.ItemDelegate { 0329 id: listItem 0330 0331 // type: roles of Discover.UpdateModel 0332 required property var model 0333 required property int index 0334 required property bool extended 0335 0336 width: updatesView.width 0337 0338 highlighted: false 0339 0340 onEnabledChanged: if (!enabled) { 0341 model.extended = false; 0342 } 0343 0344 visible: model.resourceState < Discover.AbstractBackendUpdater.Done 0345 0346 Keys.onReturnPressed: event => { 0347 itemChecked.clicked(); 0348 } 0349 Keys.onPressed: event => { 0350 if (event.key === Qt.Key_Alt) { 0351 model.extended = true; 0352 } 0353 } 0354 Keys.onReleased: event => { 0355 if (event.key === Qt.Key_Alt) { 0356 model.extended = false; 0357 } 0358 } 0359 0360 onExtendedChanged: if (extended) { 0361 updateModel.fetchUpdateDetails(index) 0362 } 0363 0364 contentItem: ColumnLayout { 0365 spacing: Kirigami.Units.smallSpacing 0366 0367 RowLayout { 0368 spacing: Kirigami.Units.smallSpacing 0369 Layout.fillWidth: true 0370 Layout.fillHeight: true 0371 0372 QQC2.CheckBox { 0373 id: itemChecked 0374 Layout.alignment: Qt.AlignVCenter 0375 checked: listItem.model.checked === Qt.Checked 0376 onClicked: listItem.model.checked = (listItem.model.checked === Qt.Checked ? Qt.Unchecked : Qt.Checked) 0377 enabled: !resourcesUpdatesModel.isProgressing 0378 } 0379 0380 Kirigami.Icon { 0381 width: Kirigami.Units.gridUnit * 2 0382 Layout.preferredHeight: width 0383 source: listItem.model.decoration 0384 smooth: true 0385 } 0386 0387 ColumnLayout { 0388 Layout.fillWidth: true 0389 Layout.leftMargin: Kirigami.Units.smallSpacing 0390 Layout.alignment: Qt.AlignVCenter 0391 0392 spacing: 0 0393 0394 // App name 0395 Kirigami.Heading { 0396 Layout.fillWidth: true 0397 text: listItem.model.display 0398 level: 3 0399 elide: Text.ElideRight 0400 } 0401 0402 // Version numbers 0403 QQC2.Label { 0404 Layout.fillWidth: true 0405 elide: truncated ? Text.ElideLeft : Text.ElideRight 0406 text: listItem.model.resource.upgradeText 0407 opacity: listItem.hovered ? 0.8 : 0.6 0408 } 0409 } 0410 0411 LabelBackground { 0412 Layout.minimumWidth: Kirigami.Units.gridUnit * 6 0413 text: listItem.model.resourceState === 2 ? i18n("Installing") : listItem.model.size 0414 0415 progress: listItem.model.resourceProgress / 100 0416 } 0417 } 0418 0419 QQC2.Frame { 0420 Layout.fillWidth: true 0421 implicitHeight: view.contentHeight 0422 visible: listItem.model.extended && listItem.model.changelog.length > 0 0423 QQC2.Label { 0424 id: view 0425 anchors { 0426 right: parent.right 0427 left: parent.left 0428 } 0429 text: listItem.model.changelog 0430 textFormat: Text.StyledText 0431 wrapMode: Text.WordWrap 0432 onLinkActivated: link => Qt.openUrlExternally(link) 0433 0434 } 0435 } 0436 0437 RowLayout { 0438 Layout.fillWidth: true 0439 spacing: Kirigami.Units.smallSpacing 0440 visible: listItem.model.extended 0441 0442 QQC2.Label { 0443 Layout.leftMargin: Kirigami.Units.gridUnit 0444 text: i18n("Update from:") 0445 } 0446 // Backend icon 0447 Kirigami.Icon { 0448 source: listItem.model.resource.sourceIcon 0449 implicitWidth: Kirigami.Units.iconSizes.smallMedium 0450 implicitHeight: Kirigami.Units.iconSizes.smallMedium 0451 } 0452 // Backend label and origin/remote 0453 QQC2.Label { 0454 Layout.fillWidth: true 0455 text: listItem.model.resource.origin.length === 0 ? listItem.model.resource.backend.displayName 0456 : i18nc("%1 is the backend that provides this app, %2 is the specific repository or address within that backend","%1 (%2)", 0457 listItem.model.resource.backend.displayName, listItem.model.resource.origin) 0458 elide: Text.ElideRight 0459 } 0460 0461 QQC2.Button { 0462 Layout.alignment: Qt.AlignRight 0463 text: i18n("More Information…") 0464 enabled: !resourcesUpdatesModel.isProgressing 0465 onClicked: Navigation.openApplication(listItem.model.resource) 0466 } 0467 } 0468 } 0469 0470 onClicked: { 0471 model.extended = !model.extended 0472 } 0473 } 0474 } 0475 0476 readonly property alias secSinceUpdate: resourcesUpdatesModel.secsToLastUpdate 0477 state: ( resourcesUpdatesModel.isProgressing ? "progressing" 0478 : Discover.ResourcesModel.isFetching ? "fetching" 0479 : updateModel.hasUpdates ? "has-updates" 0480 : resourcesUpdatesModel.needsReboot ? "reboot" 0481 : secSinceUpdate < 0 ? "unknown" 0482 : secSinceUpdate === 0 ? "now-uptodate" 0483 : secSinceUpdate < 1000 * 60 * 60 * 24 ? "uptodate" 0484 : secSinceUpdate < 1000 * 60 * 60 * 24 * 7 ? "medium" 0485 : "low" 0486 ) 0487 0488 states: [ 0489 State { 0490 name: "fetching" 0491 PropertyChanges { target: page; footerLabel: i18nc("@info", "Fetching updates…") } 0492 PropertyChanges { target: page; footerProgress: Discover.ResourcesModel.fetchingUpdatesProgress } 0493 PropertyChanges { target: page; busy: true } 0494 PropertyChanges { target: updatesView; opacity: 0 } 0495 }, 0496 State { 0497 name: "progressing" 0498 PropertyChanges { target: page; supportsRefreshing: false } 0499 PropertyChanges { target: page; actions: [cancelUpdateAction] } 0500 PropertyChanges { target: statusLabel; visible: false } 0501 }, 0502 State { 0503 name: "has-updates" 0504 PropertyChanges { target: page; title: i18nc("@info", "Updates") } 0505 // On mobile, we want "Update" to be the primary action so it's in 0506 // the center, but on desktop this feels a bit awkward and it would 0507 // be better to have "Update" be the right-most action 0508 PropertyChanges { target: page; actions: [ updateAction, refreshAction ] } 0509 PropertyChanges { target: statusLabel; visible: false } 0510 }, 0511 State { 0512 name: "reboot" 0513 PropertyChanges { target: page; footerLabel: i18nc("@info", "Restart the system to complete the update process") } 0514 PropertyChanges { target: statusLabel; helpfulAction: restartAction } 0515 PropertyChanges { target: statusLabel; explanation: "" } 0516 PropertyChanges { target: statusLabel.progressBar; visible: false } 0517 StateChangeScript { 0518 script: if (rebootAtEnd.checked && resourcesUpdatesModel.readyToReboot) { 0519 app.rebootNow() 0520 } 0521 } 0522 }, 0523 State { 0524 name: "now-uptodate" 0525 PropertyChanges { target: page; footerLabel: i18nc("@info", "Up to date") } 0526 PropertyChanges { target: page; actions: [refreshAction] } 0527 PropertyChanges { target: statusLabel; explanation: "" } 0528 PropertyChanges { target: statusLabel.progressBar; visible: false } 0529 }, 0530 State { 0531 name: "uptodate" 0532 PropertyChanges { target: page; footerLabel: i18nc("@info", "Up to date") } 0533 PropertyChanges { target: page; actions: [refreshAction] } 0534 PropertyChanges { target: statusLabel; explanation: "" } 0535 PropertyChanges { target: statusLabel.progressBar; visible: false } 0536 }, 0537 State { 0538 name: "medium" 0539 PropertyChanges { target: page; title: i18nc("@info", "Up to date") } 0540 PropertyChanges { target: page; actions: [refreshAction] } 0541 PropertyChanges { target: statusLabel; explanation: "" } 0542 PropertyChanges { target: statusLabel.progressBar; visible: false } 0543 }, 0544 State { 0545 name: "low" 0546 PropertyChanges { target: page; title: i18nc("@info", "Should check for updates") } 0547 PropertyChanges { target: page; actions: [refreshAction] } 0548 PropertyChanges { target: statusLabel; explanation: "" } 0549 PropertyChanges { target: statusLabel.progressBar; visible: false } 0550 }, 0551 State { 0552 name: "unknown" 0553 PropertyChanges { target: page; title: i18nc("@info", "Time of last update unknown") } 0554 PropertyChanges { target: page; actions: [refreshAction] } 0555 PropertyChanges { target: statusLabel; explanation: "" } 0556 PropertyChanges { target: statusLabel.progressBar; visible: false } 0557 } 0558 ] 0559 }