@@ -0,0 +1,434 @@
2+ * This file is part of system-settings
4+ * Copyright (C) 2013-2016 Canonical Ltd.
6+ * Contact: Didier Roche <didier.roches@canonical.com>
7+ * Diego Sarmentero <diego.sarmentero@canonical.com>
8+ * Jonas G. Drange <jonas.drange@canonical.com>
10+ * This program is free software: you can redistribute it and/or modify it
11+ * under the terms of the GNU General Public License version 3, as published
12+ * by the Free Software Foundation.
14+ * This program is distributed in the hope that it will be useful, but
15+ * WITHOUT ANY WARRANTY; without even the implied warranties of
16+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
17+ * PURPOSE. See the GNU General Public License for more details.
19+ * You should have received a copy of the GNU General Public License along
20+ * with this program. If not, see <http://www.gnu.org/licenses/>.
25+import QtQuick.Layouts 1.1
26+import SystemSettings 1.0
27+import Ubuntu.Components 1.3
28+import Ubuntu.Components.ListItems 1.3 as ListItem
29+import Ubuntu.Components.Popups 1.3
30+import Ubuntu.SystemSettings.Update 1.0
31+import Ubuntu.Connectivity 1.0
33+import ".." as LocalComponents
35+LocalComponents.Page {
37+ objectName: "appUpdatePage"
39+ title: i18n.tr("Update Apps")
40+ forwardButtonSourceComponent: forwardButton
42+ property bool batchMode: false
43+ property bool havePower: (indicatorPower.deviceState === "charging") ||
44+ (indicatorPower.batteryLevel > 25)
45+ property bool online: NetworkingStatus.online
46+ property bool authenticated: UpdateManager.authenticated
47+ property bool forceCheck: false
49+ property int updatesCount: {
52+ count += clickRepeater.count;
54+ count += imageRepeater.count;
58+ function check(force) {
59+ UpdateManager.check(UpdateManager.CheckClickIgnoreVersion);
65+ busName: "com.canonical.indicator.power"
66+ objectPath: "/com/canonical/indicator/power"
67+ property var batteryLevel: action("battery-level").state || 0
68+ property var deviceState: action("device-state").state
69+ Component.onCompleted: start()
74+ updateModel: UpdateManager.model
83+ bottom: configuration.top
86+ contentHeight: content.height
87+ boundsBehavior: (contentHeight > parent.height) ?
88+ Flickable.DragAndOvershootBounds :
89+ Flickable.StopAtBounds
90+ flickableDirection: Flickable.VerticalFlick
94+ anchors { left: parent.left; right: parent.right }
99+ anchors { left: parent.left; right: parent.right }
101+ height: hidden ? 0 : units.gu(8)
103+ status: UpdateManager.status
104+ batchMode: root.batchMode
105+ requireRestart: imageRepeater.count > 0
106+ updatesCount: root.updatesCount
108+ onStop: UpdateManager.cancel()
111+ if (requireRestart) {
112+ var popup = PopupUtils.open(
113+ Qt.resolvedUrl("ImageUpdatePrompt.qml"), null, {
114+ havePowerForUpdate: root.havePower
117+ popup.requestSystemUpdate.connect(function () {
125+ root.batchMode = true
126+ if (requireRestart) {
127+ postAllBatchHandler.target = root;
129+ postClickBatchHandler.target = root;
136+ objectName: "overlay"
139+ leftMargin: units.gu(2)
141+ rightMargin: units.gu(2)
143+ visible: placeholder.text
144+ color: theme.palette.normal.background
145+ height: units.gu(10)
149+ objectName: "overlayText"
150+ anchors.fill: parent
151+ verticalAlignment: Text.AlignVCenter
152+ horizontalAlignment: Text.AlignHCenter
153+ wrapMode: Text.WordWrap
155+ var s = UpdateManager.status;
157+ return i18n.tr("Connect to the Internet to check for updates.");
158+ } else if (s === UpdateManager.StatusIdle && updatesCount === 0) {
159+ return i18n.tr("Software is up to date");
160+ } else if (s === UpdateManager.StatusServerError ||
161+ s === UpdateManager.StatusNetworkError) {
162+ return i18n.tr("The update server is not responding. Try again later.");
170+ id: updatesAvailableHeader
171+ text: i18n.tr("Updates Available")
172+ visible: imageUpdateCol.visible || clickUpdatesCol.visible
177+ objectName: "imageUpdates"
178+ anchors { left: parent.left; right: parent.right }
180+ var s = UpdateManager.status;
181+ var haveUpdates = imageRepeater.count > 0;
183+ case UpdateManager.StatusCheckingClickUpdates:
184+ case UpdateManager.StatusIdle:
185+ return haveUpdates && online;
192+ model: UpdateManager.imageUpdates
194+ delegate: UpdateDelegate {
195+ objectName: "imageUpdatesDelegate-" + index
196+ width: imageUpdateCol.width
197+ updateState: model.updateState
198+ progress: model.progress
199+ version: remoteVersion
201+ changelog: model.changelog
204+ iconUrl: model.iconUrl
207+ onResume: download()
210+ if (SystemImage.downloadMode < 2) {
211+ SystemImage.downloadUpdate();
212+ SystemImage.forceAllowGSMDownload();
214+ SystemImage.downloadUpdate();
217+ onPause: SystemImage.pauseDownload();
219+ var popup = PopupUtils.open(
220+ Qt.resolvedUrl("ImageUpdatePrompt.qml"), null, {
221+ havePowerForUpdate: root.havePower
224+ popup.requestSystemUpdate.connect(SystemImage.applyUpdate);
232+ objectName: "clickUpdates"
233+ anchors { left: parent.left; right: parent.right }
235+ var s = UpdateManager.status;
236+ var haveUpdates = clickRepeater.count > 0;
238+ case UpdateManager.StatusCheckingImageUpdates:
239+ case UpdateManager.StatusIdle:
240+ return haveUpdates && online && authenticated;
247+ model: UpdateManager.clickUpdates
249+ delegate: ClickUpdateDelegate {
250+ objectName: "clickUpdatesDelegate" + index
251+ width: clickUpdatesCol.width
252+ updateState: model.updateState
253+ progress: model.progress
254+ version: remoteVersion
257+ iconUrl: model.iconUrl
259+ changelog: model.changelog
261+ signedUrl: signedDownloadUrl
263+ onInstall: downloadHandler.createDownload(model);
264+ onPause: downloadHandler.pauseDownload(model)
265+ onResume: downloadHandler.resumeDownload(model)
267+ /* This creates a new signed URL with which we can
268+ retry the download. See onSignedUrlChanged. */
269+ UpdateManager.retry(model.identifier,
273+ onSignedUrlChanged: {
274+ // If we have a signedUrl, user intend to retry.
276+ downloadHandler.retryDownload(model);
282+ onInstall: install()
285+ /* If we a downloadId, we expect UDM to restore it
286+ after some time. Workaround for lp:1603770. */
292+ var s = updateState;
293+ if (model.downloadId
294+ || s === Update.StateQueuedForDownload
295+ || s === Update.StateDownloading) {
296+ downloadHandler.assertDownloadExist(model);
305+ text: i18n.tr("Recent updates")
306+ visible: installedCol.visible
311+ objectName: "installedUpdates"
312+ anchors { left: parent.left; right: parent.right }
313+ visible: installedRepeater.count > 0
316+ id: installedRepeater
317+ model: UpdateManager.installedUpdates
319+ delegate: UpdateDelegate {
320+ objectName: "installedUpdateDelegate-" + index
321+ width: installedCol.width
322+ version: remoteVersion
326+ iconUrl: model.iconUrl
327+ changelog: model.changelog
328+ updateState: Update.StateInstalled
329+ updatedAt: model.updatedAt
331+ leadingActions: ListItemActions {
335+ onTriggered: UpdateManager.remove(
336+ model.identifier, model.revision
342+ // Launchable if there's a package name on a click.
343+ launchable: (!!packageName &&
344+ model.kind === Update.KindClick)
346+ onLaunch: UpdateManager.launch(identifier, revision);
350+ } // Column inside flickable.
356+ height: childrenRect.height
359+ bottom: parent.bottom
364+ ListItem.ThinDivider {}
366+ ListItem.SingleValue {
367+ objectName: "configuration"
368+ text: i18n.tr("Update settings")
370+ onClicked: pageStack.addPageToNextColumn(
371+ root, Qt.resolvedUrl("UpdateSettings.qml"))
376+ id: postClickBatchHandler
377+ ignoreUnknownSignals: true
379+ onUpdatesCountChanged: {
380+ if (target.updatesCount === 0) {
381+ root.batchMode = false;
388+ id: postAllBatchHandler
389+ ignoreUnknownSignals: true
391+ onUpdatesCountChanged: {
392+ if (target.updatesCount === 1) {
393+ SystemImage.updateDownloaded.connect(function () {
394+ SystemImage.applyUpdate();
396+ SystemImage.downloadUpdate();
402+ target: NetworkingStatus
405+ UpdateManager.cancel();
407+ UpdateManager.check(UpdateManager.CheckClickIgnoreVersion);
415+ if (consecutiveFailureCount > SystemImage.failuresBeforeWarning) {
416+ var popup = PopupUtils.open(
417+ Qt.resolvedUrl("InstallationFailed.qml"), null, {
427+ LocalComponents.StackButton {
428+ text: i18n.tr("Skip")
429+ onClicked: pageStack.next()
433+ Component.onCompleted: check()