on xenial help sign in
Forward-port Wizard fixes from older Unity (#105)

* Bring in Wizard from xenial branch * Delete unused Wizard pages * Update remaining Wizard pages for newer APIs Some APIs have changed slightly - SystemImage is gone and replaced with Ubuntu.SystemSettings.Update - Connectivity is replaced with NetworkingStatus I've also taken some liberty to make the update check more robust. Now it will happen on upgrade runs of the Wizard as well.

commit7f172ec231a50527e970103128dbbde8de2bcec4 authorDalton Durst <UniversalSuperBox@users.noreply.github.com> dateMon 18 Mar 2019, 10:21 (8 years ago) parent2c9d263
32 files changed+2002−454
plugins/Wizard/CMakeLists.txt+1 plugins/Wizard/Changelog.cpp+58 plugins/Wizard/Changelog.h+52 plugins/Wizard/PageList.cpp+6−5 plugins/Wizard/System.cpp+68−3 plugins/Wizard/System.h+17 plugins/Wizard/plugin.cpp+2 plugins/Wizard/timezonemodel.h+1−1 qml/Wizard/Components/InputMethod.qml+9−9 qml/Wizard/Page.qml+15 qml/Wizard/Pages.qml+90−16 qml/Wizard/Pages/10-welcome-update.qml+137 qml/Wizard/Pages/10-welcome.qml+2 qml/Wizard/Pages/11-changelog.qml+95 qml/Wizard/Pages/30-wifi.qml+3−2 qml/Wizard/Pages/40-location.qml−290 qml/Wizard/Pages/50-timezone.qml+2−1 qml/Wizard/Pages/60-account.qml+12−10 qml/Wizard/Pages/70-passwd-type.qml+1 qml/Wizard/Pages/75-report-check.qml−91 qml/Wizard/Pages/76-app-update.qml+241 qml/Wizard/Pages/78-firmware-update.qml.disabled+246 qml/Wizard/Pages/79-system-update.qml+148 qml/Wizard/Pages/80-finished.qml+4−2 qml/Wizard/Pages/ClickUpdateDelegate.qml+26 qml/Wizard/Pages/DownloadHandler.qml+204 qml/Wizard/Pages/GlobalUpdateControls.qml+138 qml/Wizard/Pages/UpdateDelegate.qml+389 qml/Wizard/Pages/passcode-desktop.qml+14−5 qml/Wizard/Pages/password-set.qml+12−4 qml/Wizard/Wizard.qml+5−2 tests/qmltests/Wizard/tst_Wizard.qml+4−13
plugins/Wizard/CMakeLists.txt+1
@@ -10,6 +10,7 @@ add_library(Wizard-qml MODULE
1010 timezonemodel.cpp
1111 Status.cpp
1212 keyboardLayoutsModel.cpp
13+ Changelog.cpp
1314)
1415
1516qt5_use_modules(Wizard-qml DBus Qml)
plugins/Wizard/Changelog.cppnew file+58
@@ -0,0 +1,58 @@
1+/*
2+ * Copyright (C) 2018 The UBports project
3+ * Written by: Marius Gripsgard <marius@ubports.com>
4+ *
5+ * This program is free software: you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 3, as published
7+ * by the Free Software Foundation.
8+ *
9+ * This program is distributed in the hope that it will be useful, but
10+ * WITHOUT ANY WARRANTY; without even the implied warranties of
11+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
12+ * PURPOSE. See the GNU General Public License for more details.
13+ *
14+ * You should have received a copy of the GNU General Public License along
15+ * with this program. If not, see <http://www.gnu.org/licenses/>.
16+ */
17+
18+#include "Changelog.h"
19+
20+#include <QDir>
21+#include <QFile>
22+#include <QTextStream>
23+
24+Changelog::Changelog()
25+ : QObject()
26+{
27+ readChangelog();
28+ if(QFile::exists(changelogPath()))
29+ m_fsWatcher.addPath(changelogPath());
30+ connect(&m_fsWatcher, &QFileSystemWatcher::fileChanged, this, &Changelog::watcherFileChanged);
31+}
32+
33+QString Changelog::changelogPath()
34+{
35+ return "/usr/share/ubports/changelogs/current";
36+}
37+
38+QString Changelog::text() const
39+{
40+ return m_text;
41+}
42+
43+void Changelog::readChangelog()
44+{
45+ if(!QFile::exists(changelogPath()))
46+ return;
47+ QFile f(changelogPath());
48+ if (!f.open(QFile::ReadOnly | QFile::Text)) return;
49+ QTextStream in(&f);
50+ m_text = in.readAll();
51+ Q_EMIT textChanged();
52+}
53+
54+void Changelog::watcherFileChanged()
55+{
56+ readChangelog();
57+ m_fsWatcher.removePath(changelogPath());
58+}
plugins/Wizard/Changelog.hnew file+52
@@ -0,0 +1,52 @@
1+/*
2+ * Copyright (C) 2018 The UBports project
3+ * Written by: Marius Gripsgard <marius@ubports.com>
4+ *
5+ * This program is free software: you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 3, as published
7+ * by the Free Software Foundation.
8+ *
9+ * This program is distributed in the hope that it will be useful, but
10+ * WITHOUT ANY WARRANTY; without even the implied warranties of
11+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
12+ * PURPOSE. See the GNU General Public License for more details.
13+ *
14+ * You should have received a copy of the GNU General Public License along
15+ * with this program. If not, see <http://www.gnu.org/licenses/>.
16+ */
17+
18+#ifndef WIZARD_CHANGELOG_H
19+#define WIZARD_CHANGELOG_H
20+
21+#include <QFileSystemWatcher>
22+#include <QObject>
23+#include <QString>
24+
25+class Changelog : public QObject
26+{
27+ Q_OBJECT
28+ Q_PROPERTY(QString text READ text NOTIFY textChanged)
29+
30+public:
31+ Changelog();
32+ ~Changelog() = default;
33+
34+ QString text() const;
35+
36+Q_SIGNALS:
37+ void textChanged();
38+
39+private Q_SLOTS:
40+ void watcherFileChanged();
41+
42+private:
43+ Q_DISABLE_COPY(Changelog)
44+
45+ static QString changelogPath();
46+ void readChangelog();
47+
48+ QFileSystemWatcher m_fsWatcher;
49+ QString m_text;
50+};
51+
52+#endif
plugins/Wizard/PageList.cpp+6−5
@@ -46,9 +46,7 @@ PageList::PageList(QObject *parent)
4646 QSet<QString> disabledPages;
4747 QStringList dataDirs;
4848
49− if (getenv("WIZARD_TESTING") != nullptr) {
50− dataDirs = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
51− } else if (!isRunningInstalled()) {
49+ if (!isRunningInstalled() && getenv("WIZARD_TESTING") == nullptr) {
5250 dataDirs << qmlDirectory();
5351 } else {
5452 dataDirs = shellDataDirs();
@@ -73,8 +71,11 @@ PageList::PageList(QObject *parent)
7371 // If there was a system update installed, skip until the last page to just greet the user
7472 QSettings settings;
7573 if (settings.value(QStringLiteral("Wizard/SkipUntilFinishedPage")).toBool()) {
76− while (m_pages.count() > 1) {
77− m_pages.erase(m_pages.begin());
74+ const QString lastPage = m_pages.lastKey();
75+ Q_FOREACH(const QString &page, m_pages.keys()) {
76+ if (Q_UNLIKELY(page != lastPage)) {
77+ m_pages.remove(page);
78+ }
7879 }
7980
8081 // ... and reset it again for the next run
plugins/Wizard/System.cpp+68−3
@@ -1,4 +1,5 @@
11/*
2+ * Copyright (C) 2018 The UBports project
23 * Copyright (C) 2014-2016 Canonical Ltd.
34 *
45 * This program is free software: you can redistribute it and/or modify it
@@ -46,29 +47,93 @@ QString System::wizardEnabledPath()
4647 return QDir::home().filePath(QStringLiteral(".config/ubuntu-system-settings/wizard-has-run"));
4748}
4849
50+QString System::currentFrameworkPath()
51+{
52+ QFileInfo f("/usr/share/click/frameworks/current");
53+ return f.canonicalFilePath();
54+}
55+
56+/*
57+wizardEnabled and isUpdate logic
58+
59+if wizard-has-run does NOT exist == is new install
60+if wizard-has-run exists but does NOT match current framework == is update
61+if wizard-has-run exists but does match current framework == show no wizard
62+*/
63+
64+bool System::wizardPathExists() {
65+ return QFile::exists(wizardEnabledPath());
66+}
67+
4968bool System::wizardEnabled() const
5069{
51− return !QFile::exists(wizardEnabledPath());
70+ if (!wizardPathExists()) {
71+ return true;
72+ }
73+ return isUpdate();
74+}
75+
76+QString System::readCurrentFramework()
77+{
78+ QFile f(currentFrameworkPath());
79+ if (!f.open(QFile::ReadOnly | QFile::Text)) return "";
80+ QTextStream in(&f);
81+ return in.readAll();
82+}
83+
84+QString System::readWizardEnabled()
85+{
86+ QFile f(wizardEnabledPath());
87+ if (!f.open(QFile::ReadOnly | QFile::Text)) return "";
88+ QTextStream in(&f);
89+ return in.readAll();
90+}
91+
92+QString System::version() const
93+{
94+ return readCurrentFramework();
95+}
96+
97+bool System::isUpdate() const
98+{
99+ if (!wizardPathExists()) {
100+ return false;
101+ }
102+
103+ return readCurrentFramework() != readWizardEnabled();
52104}
53105
54106void System::setWizardEnabled(bool enabled)
55107{
56− if (wizardEnabled() == enabled)
108+ if (wizardEnabled() == enabled && !isUpdate())
57109 return;
58110
59111 if (enabled) {
60112 QFile::remove(wizardEnabledPath());
61113 } else {
62114 QDir(wizardEnabledPath()).mkpath(QStringLiteral(".."));
63− QFile(wizardEnabledPath()).open(QIODevice::WriteOnly);
115+ if (QFile::exists(wizardEnabledPath())) {
116+ QFile::remove(wizardEnabledPath());
117+ }
118+ // For special cases check if wizardEnabledPath is a folder
119+ if (QDir(wizardEnabledPath()).exists()) {
120+ QDir(wizardEnabledPath()).removeRecursively();
121+ }
122+ if (!QFile::copy(currentFrameworkPath(), wizardEnabledPath())) {
123+ // Make en empty file if framework does not exist
124+ QFile f(wizardEnabledPath());
125+ f.open(QFile::WriteOnly);
126+ }
64127 m_fsWatcher.addPath(wizardEnabledPath());
65128 Q_EMIT wizardEnabledChanged();
129+ Q_EMIT isUpdateChanged();
66130 }
67131}
68132
69133void System::watcherFileChanged()
70134{
71135 Q_EMIT wizardEnabledChanged();
136+ Q_EMIT isUpdateChanged();
72137 m_fsWatcher.removePath(wizardEnabledPath());
73138}
74139
plugins/Wizard/System.h+17
@@ -1,4 +1,5 @@
11/*
2+ * Copyright (C) 2018 The UBports project
23 * Copyright (C) 2014-2016 Canonical Ltd.
34 *
45 * This program is free software: you can redistribute it and/or modify it
@@ -18,6 +19,7 @@
1819#define WIZARD_SYSTEM_H
1920
2021#include <QFileSystemWatcher>
22+#include <QVersionNumber>
2123#include <QObject>
2224#include <QString>
2325
@@ -25,12 +27,21 @@ class System : public QObject
2527{
2628 Q_OBJECT
2729 Q_PROPERTY(bool wizardEnabled READ wizardEnabled WRITE setWizardEnabled NOTIFY wizardEnabledChanged)
30+ Q_PROPERTY(QString version READ version NOTIFY versionChanged)
31+ Q_PROPERTY(bool isUpdate READ isUpdate NOTIFY isUpdateChanged)
2832
2933public:
3034 System();
3135 ~System() = default;
3236
37+ /**
38+ * Checks whether the wizard is enabled for first-run or otherwise.
39+ */
3340 bool wizardEnabled() const;
41+
42+ QString version() const;
43+ bool isUpdate() const;
44+
3445 void setWizardEnabled(bool enabled);
3546
3647public Q_SLOTS:
@@ -42,6 +53,8 @@ public Q_SLOTS:
4253
4354Q_SIGNALS:
4455 void wizardEnabledChanged();
56+ void versionChanged();
57+ void isUpdateChanged();
4558
4659private Q_SLOTS:
4760 void watcherFileChanged();
@@ -50,7 +63,11 @@ private:
5063 Q_DISABLE_COPY(System)
5164
5265 static QString wizardEnabledPath();
66+ static QString currentFrameworkPath();
5367 static void setSessionVariable(const QString &variable, const QString &value);
68+ static QString readCurrentFramework();
69+ static QString readWizardEnabled();
70+ static bool wizardPathExists();
5471
5572 QFileSystemWatcher m_fsWatcher;
5673};
plugins/Wizard/plugin.cpp+2
@@ -20,6 +20,7 @@
2020#include "timezonemodel.h"
2121#include "LocalePlugin.h"
2222#include "Status.h"
23+#include "Changelog.h"
2324#include "keyboardLayoutsModel.h"
2425
2526#include <QtQml/qqml.h>
@@ -30,6 +31,7 @@ void WizardPlugin::registerTypes(const char *uri)
3031 qmlRegisterType<PageList>(uri, 0, 1, "PageList");
3132 qmlRegisterSingletonType<System>(uri, 0, 1, "System", [](QQmlEngine*, QJSEngine*) -> QObject* { return new System; });
3233 qmlRegisterSingletonType<Status>(uri, 0, 1, "Status", [](QQmlEngine*, QJSEngine*) -> QObject* { return new Status; });
34+ qmlRegisterSingletonType<Changelog>(uri, 0, 1, "Changelog", [](QQmlEngine*, QJSEngine*) -> QObject* { return new Changelog; });
3335 qmlRegisterType<TimeZoneLocationModel>(uri, 0, 1, "TimeZoneModel");
3436 qmlRegisterType<KeyboardLayoutsModel>(uri, 0, 1, "KeyboardLayoutsModel");
3537 qmlRegisterType<LocalePlugin>(uri, 0, 1, "LocalePlugin");
plugins/Wizard/timezonemodel.h+1−1
@@ -27,6 +27,7 @@ class TimeZoneLocationModel: public QAbstractListModel
2727 Q_PROPERTY(bool listUpdating READ listUpdating NOTIFY listUpdatingChanged)
2828 Q_PROPERTY(QString filter READ filter WRITE setFilter NOTIFY filterChanged)
2929 Q_PROPERTY(QString country READ country WRITE setCountry NOTIFY countryChanged)
30+ Q_ENUMS(Roles)
3031
3132public:
3233 explicit TimeZoneLocationModel(QObject *parent = nullptr);
@@ -41,7 +42,6 @@ public:
4142 LatitudeRole,
4243 LongitudeRole
4344 };
44− Q_ENUM(Roles)
4545
4646 int rowCount(const QModelIndex &parent = QModelIndex()) const override;
4747 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
qml/Wizard/Components/InputMethod.qml+9−9
@@ -21,19 +21,19 @@ import Ubuntu.Components 0.1
2121// TODO: try to share this code with that from the unity8 shell
2222
2323Item {
24− id: root
24+ id: inputMethodRoot
2525
2626 Connections {
2727 target: SurfaceManager
2828 onSurfaceCreated: {
2929 if (surface.type == MirSurfaceItem.InputMethod) {
30− root.surface = surface;
30+ inputMethodRoot.surface = surface;
3131 }
3232 }
3333
3434 onSurfaceDestroyed: {
35− if (root.surface == surface) {
36− root.surface = null;
35+ if (inputMethodRoot.surface == surface) {
36+ inputMethodRoot.surface = null;
3737 surface.parent = null;
3838 }
3939 if (!surface.parent) {
@@ -71,7 +71,7 @@ Item {
7171 visible: false
7272 // half-way down because the vkb occupies only the lower half of the surface
7373 // TODO: consider keyboard rotation
74− y: root.parent.height / 2.0
74+ y: inputMethodRoot.parent.height / 2.0
7575 }
7676 }
7777 ]
@@ -89,17 +89,17 @@ Item {
8989 ignoreUnknownSignals: true // don't wanna spam the log when surface is null
9090 onStateChanged: {
9191 if (state == MirSurfaceItem.Minimized) {
92− root.hide();
92+ inputMethodRoot.hide();
9393 } else if (state == MirSurfaceItem.Maximized) {
94− root.show();
94+ inputMethodRoot.show();
9595 }
9696 }
9797 }
9898
9999 onSurfaceChanged: {
100100 if (surface) {
101− surface.parent = root;
102− surface.anchors.fill = root;
101+ surface.parent = inputMethodRoot;
102+ surface.anchors.fill = inputMethodRoot;
103103 }
104104 }
105105
qml/Wizard/Page.qml+15
@@ -1,4 +1,5 @@
11/*
2+ * Copyright (C) 2018 The UBports project
23 * Copyright (C) 2013-2016 Canonical, Ltd.
34 *
45 * This program is free software; you can redistribute it and/or modify
@@ -50,6 +51,10 @@ Item {
5051 property bool skipValid: true
5152 property bool skip: false
5253
54+ // Marks if should be only shown if update or install
55+ property bool onlyOnUpdate: false
56+ property bool onlyOnInstall: false
57+
5358 property bool hasBackButton: true
5459 property string backButtonText: i18n.ctr("Button: Go back one page in the Wizard", "Back")
5560 property bool customBack: false
@@ -59,6 +64,10 @@ Item {
5964 property bool lastPage: false
6065 property bool buttonBarVisible: true
6166
67+ // Item that will receive input focus when the page is in front
68+ // May be useful to open the keyboard automatically for a text field
69+ property Item focusItem
70+
6271 property string title: ""
6372
6473 signal backClicked()
@@ -66,6 +75,12 @@ Item {
6675 visible: false
6776 anchors.fill: parent
6877
78+ onVisibleChanged: {
79+ if (visible && focusItem) {
80+ focusItem.forceActiveFocus();
81+ }
82+ }
83+
6984 Timer {
7085 id: indicatorTimer
7186 interval: 1000
qml/Wizard/Pages.qml+90−16
@@ -1,4 +1,5 @@
11/*
2+ * Copyright (C) 2018 The UBports project
23 * Copyright (C) 2013-2016 Canonical, Ltd.
34 *
45 * This program is free software; you can redistribute it and/or modify
@@ -18,7 +19,8 @@ import QtQuick 2.4
1819import MeeGo.QOfono 0.2
1920import Ubuntu.Components 1.3
2021import Ubuntu.SystemSettings.SecurityPrivacy 1.0
21−import Ubuntu.SystemSettings.Diagnostics 1.0
22+import Ubuntu.SystemSettings.Update 1.0
23+import Ubuntu.Connectivity 1.0
2224import Wizard 0.1
2325import "../Components"
2426
@@ -35,6 +37,10 @@ StyledItem {
3537 property string password: ""
3638
3739 property bool seenSIMPage: false // we want to see the SIM page at most once
40+ readonly property bool connected: NetworkingStatus.online
41+
42+ property bool checkedForUpdates: false
43+ property bool updateDownloaded: false
3844
3945 property alias modemManager: modemManager
4046 property alias simManager0: simManager0
@@ -49,11 +55,6 @@ StyledItem {
4955 objectName: "securityPrivacy"
5056 }
5157
52− UbuntuDiagnostics {
53− id: diagnostics
54− objectName: "diagnostics"
55− }
56−
5758 OfonoManager { // need it here for the language and country detection
5859 id: modemManager
5960 readonly property bool gotSimCard: available && ((simManager0.ready && simManager0.present) || (simManager1.ready && simManager1.present))
@@ -75,6 +76,14 @@ StyledItem {
7576 modemPath: modemManager.modems.length >= 2 ? modemManager.modems[1] : ""
7677 }
7778
79+ function checkForUpdatesIfConnected() {
80+ if (connected && !checkedForUpdates) {
81+ console.info("Wizard: Checking for system-image update");
82+ SystemImage.checkForUpdate();
83+ checkedForUpdates = true;
84+ }
85+ }
86+
7887 function quitWizard() {
7988 pageStack.currentPage.enabled = false;
8089
@@ -84,7 +93,7 @@ StyledItem {
8493 // Ignore (but log) any errors, since we're past where the user set
8594 // the method. Worst case, we just leave the user with a swipe
8695 // security method and they fix it in the system settings.
87− console.log("Error setting security method:", errorMsg)
96+ console.log("Wizard: Error setting security method:", errorMsg)
8897 }
8998 }
9099
@@ -105,6 +114,59 @@ StyledItem {
105114 id: pageList
106115 }
107116
117+ ActivityIndicator {
118+ id: pagesSpinner
119+ anchors.centerIn: parent
120+ z: 100
121+ running: false
122+ visible: running
123+
124+ NumberAnimation on opacity {
125+ id: fadeInAnimation
126+ from: 0
127+ to: 1
128+ duration: 200
129+ }
130+
131+ onVisibleChanged: {
132+ if (visible) {
133+ opacity = 0;
134+ fadeInAnimation.start();
135+ }
136+ }
137+ }
138+
139+ onConnectedChanged: {
140+ checkForUpdatesIfConnected();
141+ }
142+
143+ Connections {
144+ target: SystemImage
145+ onUpdateDownloaded: {
146+ console.info("Wizard: A system-image update has been downloaded!")
147+ root.updateDownloaded = true;
148+ }
149+ onCheckingForUpdatesChanged: {
150+ if (!SystemImage.checkingForUpdates) {
151+ console.info("Wizard: Update check finished")
152+ if (SystemImage.updateAvailable) {
153+ console.info("Wizard: A system-image update is available!")
154+ } else {
155+ console.info("Wizard: No update found.")
156+ }
157+ }
158+ }
159+ }
160+
161+ Timer {
162+ id: impatientLoadingTimer
163+ interval: 1700
164+ onTriggered: {
165+ console.warn("Wizard: Impatient timer going off. Fix the wizard, it's too slow at skipping pages.")
166+ pagesSpinner.running = true;
167+ }
168+ }
169+
108170 PageStack {
109171 id: pageStack
110172 objectName: "pageStack"
@@ -139,18 +201,21 @@ StyledItem {
139201
140202 function load(path) {
141203 if (currentPage) {
142− currentPage.enabled = false
204+ currentPage.enabled = false;
143205 }
144206
145207 // First load it invisible, check that we should actually use
146208 // this page, and either skip it or continue.
147− push(path, {"opacity": 0, "enabled": false})
209+ push(path, {"opacity": 0, "enabled": false});
148210
149211 timeout.restart();
212+ impatientLoadingTimer.start();
213+
214+ console.info("Wizard: Loading page " + currentPage.objectName);
150215
151216 // Check for immediate skip or not. We may have to wait for
152217 // skipValid to be assigned (see Connections object below)
153− checkSkip()
218+ checkSkip();
154219
155220 var isPrimaryPage = !currentPage.customTitle;
156221 if (isPrimaryPage) {
@@ -162,13 +227,19 @@ StyledItem {
162227
163228 function checkSkip() {
164229 if (!currentPage) { // may have had a parse error
165− next()
230+ console.warn("Wizard: page skipped due to possible parse error.");
231+ next();
166232 } else if (currentPage.skipValid) {
167233 if (currentPage.skip) {
168− next()
234+ next();
235+ } else if ((currentPage.onlyOnUpdate && !wizard.isUpdate) ||
236+ (currentPage.onlyOnInstall && wizard.isUpdate)) {
237+ next();
169238 } else {
170− currentPage.opacity = 1
171− currentPage.enabled = true
239+ impatientLoadingTimer.stop()
240+ pagesSpinner.running = false;
241+ currentPage.opacity = 1;
242+ currentPage.enabled = true;
172243 timeout.stop();
173244 }
174245 }
@@ -179,7 +250,7 @@ StyledItem {
179250 objectName: "timeout"
180251 interval: 2000 // wizard pages shouldn't take long
181252 onTriggered: {
182− console.warn("Wizard page " + pageStack.currentPage.objectName + " skipped due to taking too long!!!");
253+ console.warn("Wizard: Page " + pageStack.currentPage.objectName + " skipped due to taking too long!!!");
183254 pageStack.currentPage.skip = true;
184255 pageStack.currentPage.skipValid = true;
185256 }
@@ -190,6 +261,9 @@ StyledItem {
190261 onSkipValidChanged: pageStack.checkSkip()
191262 }
192263
193− Component.onCompleted: next()
264+ Component.onCompleted: {
265+ checkForUpdatesIfConnected();
266+ next();
267+ }
194268 }
195269}
qml/Wizard/Pages/10-welcome-update.qmlnew file+137
@@ -0,0 +1,137 @@
1+/*
2+ * Copyright (C) 2018 The UBports project
3+ *
4+ * Written by: Marius Gripsgard <marius@ubports.com>
5+ *
6+ * This program is free software; you can redistribute it and/or modify
7+ * it under the terms of the GNU General Public License as published by
8+ * the Free Software Foundation; version 3.
9+ *
10+ * This program is distributed in the hope that it will be useful,
11+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+ * GNU General Public License for more details.
14+ *
15+ * You should have received a copy of the GNU General Public License
16+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
17+ */
18+
19+import QtQuick 2.4
20+import Ubuntu.Components 1.3
21+import Wizard 0.1
22+import ".." as LocalComponents
23+
24+LocalComponents.Page {
25+ objectName: "welcomeUpdate"
26+
27+ hasBackButton: false
28+ customTitle: true
29+ buttonBarVisible: false
30+ onlyOnUpdate: true
31+
32+ Component.onCompleted: {
33+ state = "reanchored";
34+ }
35+
36+ states: State {
37+ name: "reanchored"
38+ AnchorChanges { target: bgImage; anchors.top: parent.top; anchors.bottom: parent.bottom }
39+ AnchorChanges { target: column;
40+ anchors.verticalCenter: parent.verticalCenter;
41+ anchors.top: undefined
42+ }
43+ }
44+
45+ SequentialAnimation {
46+ id: splashAnimation
47+ PauseAnimation { duration: UbuntuAnimation.BriskDuration }
48+ SmoothedAnimation {
49+ target: bgImage
50+ property: "height"
51+ to: units.gu(16)
52+ duration: UbuntuAnimation.BriskDuration
53+ }
54+ NumberAnimation {
55+ target: bgImage
56+ property: 'opacity'
57+ from: 1
58+ to: 0
59+ }
60+ }
61+
62+ Image {
63+ id: bgImage
64+ source: wideMode ? "data/Desktop_splash_screen_bkg.png" : "data/Phone_splash_screen_bkg.png"
65+ scale: Image.PreserveAspectFit
66+ anchors.left: parent.left
67+ anchors.right: parent.right
68+ anchors.bottom: parent.top // outside to let it slide down
69+ visible: opacity > 0
70+ }
71+
72+ Item {
73+ id: column
74+ anchors.leftMargin: leftMargin
75+ anchors.rightMargin: rightMargin
76+ anchors.left: parent.left
77+ anchors.right: parent.right
78+ anchors.top: parent.bottom // outside to let it slide in
79+ height: childrenRect.height
80+ visible: opacity > 0
81+
82+ Label {
83+ id: welcomeLabel
84+ anchors.left: parent.left
85+ anchors.right: parent.right
86+ horizontalAlignment: Text.AlignHCenter
87+ wrapMode: Text.Wrap
88+ fontSize: "x-large"
89+ font.weight: Font.Light
90+ lineHeight: 1.2
91+ text: i18n.tr("Welcome to ") + System.version.split("Base-Version: ")[1]
92+ color: whiteColor
93+ }
94+
95+ Label {
96+ id: welcomeText
97+ anchors.left: parent.left
98+ anchors.right: parent.right
99+ anchors.top: welcomeLabel.bottom
100+ anchors.topMargin: units.gu(2)
101+ horizontalAlignment: Text.AlignHCenter
102+ wrapMode: Text.Wrap
103+ fontSize: "large"
104+ font.weight: Font.Light
105+ lineHeight: 1.2
106+ text: i18n.tr("We will make sure your device is ready to use ") + System.version.split("Base-Version: ")[1]
107+ color: whiteColor
108+ }
109+
110+ Rectangle {
111+ anchors {
112+ top: welcomeText.bottom
113+ horizontalCenter: parent.horizontalCenter
114+ topMargin: units.gu(4)
115+ }
116+ color: "transparent"
117+ border.width: units.dp(1)
118+ border.color: whiteColor
119+ radius: units.dp(4)
120+ width: buttonLabel.paintedWidth + units.gu(6)
121+ height: buttonLabel.paintedHeight + units.gu(1.8)
122+
123+ Label {
124+ id: buttonLabel
125+ color: whiteColor
126+ text: i18n.tr("Next")
127+ fontSize: "medium"
128+ anchors.centerIn: parent
129+ }
130+ AbstractButton {
131+ objectName: "nextButton"
132+ anchors.fill: parent
133+ onClicked: pageStack.next();
134+ }
135+ }
136+ }
137+}
qml/Wizard/Pages/10-welcome.qml+2
@@ -1,4 +1,5 @@
11/*
2+ * Copyright (C) 2018 The UBports project
23 * Copyright (C) 2013-2016 Canonical, Ltd.
34 *
45 * This program is free software; you can redistribute it and/or modify
@@ -27,6 +28,7 @@ LocalComponents.Page {
2728
2829 title: i18n.tr("Language")
2930 forwardButtonSourceComponent: forwardButton
31+ onlyOnInstall: true
3032
3133 UbuntuLanguagePlugin {
3234 id: plugin
qml/Wizard/Pages/11-changelog.qmlnew file+95
@@ -0,0 +1,95 @@
1+/*
2+ * Copyright (C) 2018 The UBports project
3+ *
4+ * Written by: Dalton Durst <dalton@ubports.com>
5+ * Marius Gripsgard <marius@ubports.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+import QtQuick 2.4
21+import Ubuntu.Components 1.3
22+import AccountsService 0.1
23+import Wizard 0.1
24+import ".." as LocalComponents
25+
26+LocalComponents.Page {
27+ objectName: "changelogPage"
28+ title: i18n.tr("What's new")
29+ id: changelogPage
30+
31+ // See skipTimer below for information about this hack
32+ property bool loading: false
33+
34+ forwardButtonSourceComponent: forwardButton
35+ onlyOnUpdate: true
36+
37+ ScrollView {
38+ id: scroll
39+
40+ anchors {
41+ fill: content
42+ leftMargin: wideMode ? parent.leftMargin : staticMargin
43+ rightMargin: wideMode ? parent.rightMargin : staticMargin
44+ }
45+
46+ Column {
47+ id: column
48+
49+ width: scroll.width
50+
51+ // Make it appear that the text is hiding behind the header
52+ Item {
53+ height: staticMargin
54+ width: units.gu(1)
55+ }
56+
57+ Label {
58+ anchors {
59+ // Keep the scroll bar from interfering with text
60+ rightMargin: units.gu(1)
61+ }
62+ id: changelogText
63+ width: parent.width
64+ wrapMode: Text.WordWrap
65+ textSize: Label.Medium
66+ text: Changelog.text
67+ }
68+ }
69+ }
70+
71+ Component {
72+ id: forwardButton
73+ LocalComponents.StackButton {
74+ text: loading ? i18n.tr("Loading...") : i18n.tr("Next")
75+ onClicked: {
76+ changelogPage.loading = true;
77+ skipTimer.restart();
78+ }
79+ }
80+ }
81+
82+ // A horrible hack to make sure the UI refreshes before actually skipping
83+ // Without this, people press the Next button multiple times and skip
84+ // multiple pages at once.
85+ Timer {
86+ id: skipTimer
87+ interval: 100
88+ repeat: false
89+ running: false
90+ onTriggered: {
91+ changelogPage.loading = false;
92+ pageStack.next();
93+ }
94+ }
95+}
qml/Wizard/Pages/30-wifi.qml+3−2
@@ -20,6 +20,7 @@ import QMenuModel 0.1 as QMenuModel
2020import Ubuntu.Components 1.3
2121import Wizard 0.1
2222import Ubuntu.Connectivity 1.0
23+import Ubuntu.SystemSettings.Update 1.0
2324import ".." as LocalComponents
2425import "../../Components"
2526
@@ -30,7 +31,7 @@ LocalComponents.Page {
3031 title: i18n.tr("Connect to Wi‑Fi")
3132 forwardButtonSourceComponent: forwardButton
3233
33− readonly property bool connected: Connectivity.online
34+ skip: root.connected
3435
3536 function getExtendedProperty(object, propertyName, defaultValue) {
3637 if (object && object.hasOwnProperty(propertyName)) {
@@ -203,7 +204,7 @@ LocalComponents.Page {
203204 Component {
204205 id: forwardButton
205206 LocalComponents.StackButton {
206− text: (connected || listview.count === 0) ? i18n.tr("Next") : i18n.tr("Skip")
207+ text: (root.connected || listview.count === 0) ? i18n.tr("Next") : i18n.tr("Skip")
207208 onClicked: {
208209 pageStack.next();
209210 }
qml/Wizard/Pages/40-location.qmldeleted−290
@@ -1,290 +0,0 @@
1−/*
2− * Copyright (C) 2013-2016 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.4
18−import AccountsService 0.1
19−import QMenuModel 0.1 as QMenuModel
20−import Qt.labs.folderlistmodel 2.1
21−import Ubuntu.Components 1.3
22−import ".." as LocalComponents
23−
24−LocalComponents.Page {
25− objectName: "locationPage"
26−
27− title: i18n.tr("Location Services")
28− forwardButtonSourceComponent: forwardButton
29−
30− readonly property bool pathSet: AccountsService.hereLicensePathValid
31− skipValid: pathSet && (AccountsService.hereLicensePath === "" || termsModel.count > 0)
32− skip: skipValid && (AccountsService.hereLicensePath === "" || termsModel.count === 2) // no files but . and ..
33−
34− FolderListModel {
35− id: termsModel
36− folder: AccountsService.hereLicensePath
37− nameFilters: ["*.html"]
38− showOnlyReadable: true
39− showDotAndDotDot: true // so that count == 0 means we're not done scanning yet
40− }
41−
42− QMenuModel.QDBusActionGroup {
43− id: locationActionGroup
44− objectName: "locationActionGroup"
45− busType: QMenuModel.DBus.SessionBus
46− busName: "com.canonical.indicator.location"
47− objectPath: "/com/canonical/indicator/location"
48− property variant location: action("location-detection-enabled")
49− property variant gps: action("gps-detection-enabled")
50− Component.onCompleted: start()
51− }
52−
53− Item {
54− id: column
55− anchors.fill: content
56− anchors.topMargin: customMargin
57− anchors.leftMargin: wideMode ? parent.leftMargin : 0
58− anchors.rightMargin: wideMode ? parent.rightMargin : 0
59−
60− Item {
61− id: hereCheckGroup
62− anchors {
63− left: parent.left
64− right: parent.right
65− top: parent.top
66− }
67− height: hereCheckLabel.height + hereTermsLabel.height
68−
69− Label {
70− id: hereCheckLabel
71− objectName: "hereCheckLabel"
72− anchors {
73− left: parent.left
74− right: hereTermsCheck.left
75− top: parent.top
76− leftMargin: column.anchors.leftMargin == 0 ? staticMargin : 0
77− rightMargin: units.gu(2)
78− }
79− lineHeight: 1.2
80− wrapMode: Text.WordWrap
81− color: textColor
82− font.weight: checked ? Font.Normal : Font.Light
83− text: i18n.tr("Use GPS, Wi-Fi hotspots and mobile network anonymously to detect location (recommended)")
84− property bool checked: true
85− }
86−
87− Label {
88− id: hereTermsLabel
89− objectName: "hereTermsLabel"
90− anchors {
91− left: parent.left
92− right: hereTermsCheck.left
93− top: hereCheckLabel.bottom
94− topMargin: units.gu(1)
95− leftMargin: column.anchors.leftMargin == 0 ? staticMargin : 0
96− rightMargin: units.gu(2)
97− }
98−
99− wrapMode: Text.WordWrap
100− color: textColor
101− font.weight: Font.Light
102− fontSize: "small"
103− lineHeight: 1.2
104− linkColor: UbuntuColors.orange
105− text: i18n.tr("By selecting this option you agree to the Nokia HERE %1.")
106− .arg("<a href='#'>" + i18n.ctr("part of: Nokia HERE terms and conditions", "terms and conditions") + "</a>")
107− Mouse.forwardTo: hereCheckArea // clicking on the link also selects this group
108− Mouse.priority: Mouse.AfterItem
109− onLinkActivated: {
110− pageStack.load(Qt.resolvedUrl("here-terms.qml"));
111− }
112− }
113−
114− Image {
115− id: hereTermsCheck
116− fillMode: Image.PreserveAspectFit
117− height: units.gu(1.5)
118− source: "data/Tick@30.png"
119− opacity: hereCheckLabel.checked ? 1 : 0
120− anchors.right: parent.right
121− anchors.verticalCenter: hereCheckLabel.verticalCenter
122− anchors.rightMargin: column.anchors.rightMargin == 0 ? staticMargin : 0
123− }
124−
125− MouseArea {
126− id: hereCheckArea
127− anchors.fill: parent
128− z: hereCheckGroup.z - 1 // so that the link can be activated
129− onClicked: {
130− if (!hereCheckLabel.checked) {
131− hereCheckLabel.checked = true;
132− gpsCheckLabel.checked = false;
133− nopeCheckLabel.checked = false;
134− }
135− }
136− }
137− }
138−
139− Rectangle {
140− id: divider
141− anchors.left: parent.left
142− anchors.right: parent.right
143− anchors.top: hereCheckGroup.bottom
144− anchors.topMargin: units.gu(3)
145− height: units.dp(1)
146− color: dividerColor
147− }
148−
149− Label {
150− id: gpsCheckLabel
151− objectName: "gpsCheckLabel"
152− anchors {
153− left: parent.left
154− right: parent.right
155− top: divider.bottom
156− topMargin: units.gu(3)
157− leftMargin: column.anchors.leftMargin == 0 ? staticMargin : 0
158− rightMargin: units.gu(2)
159− }
160− text: i18n.tr("GPS only")
161− wrapMode: Text.WordWrap
162− color: textColor
163− font.weight: checked ? Font.Normal : Font.Light
164− width: content.width
165− property bool checked: false
166−
167− MouseArea {
168− anchors.fill: parent
169− onClicked: {
170− if (!gpsCheckLabel.checked) {
171− hereCheckLabel.checked = false;
172− gpsCheckLabel.checked = true;
173− nopeCheckLabel.checked = false;
174− }
175− }
176− }
177− }
178−
179− Image {
180− fillMode: Image.PreserveAspectFit
181− height: units.gu(1.5)
182− source: "data/Tick@30.png"
183− opacity: gpsCheckLabel.checked ? 1 : 0
184− anchors.right: parent.right
185− anchors.verticalCenter: gpsCheckLabel.verticalCenter
186− anchors.rightMargin: column.anchors.rightMargin == 0 ? staticMargin : 0
187− }
188−
189− Rectangle {
190− id: divider2
191− anchors.left: parent.left
192− anchors.right: parent.right
193− anchors.top: gpsCheckLabel.bottom
194− anchors.topMargin: units.gu(3)
195− height: units.dp(1)
196− color: dividerColor
197− }
198−
199− Label {
200− id: nopeCheckLabel
201− objectName: "nopeCheckLabel"
202− anchors {
203− left: parent.left
204− right: parent.right
205− top: divider2.bottom
206− topMargin: units.gu(3)
207− leftMargin: column.anchors.leftMargin == 0 ? staticMargin : 0
208− rightMargin: units.gu(2)
209− }
210− wrapMode: Text.WordWrap
211− color: textColor
212− font.weight: checked ? Font.Normal : Font.Light
213− width: content.width
214− text: i18n.tr("Don't use my location")
215− property bool checked: false
216−
217− MouseArea {
218− anchors.fill: parent
219− onClicked: {
220− if (!nopeCheckLabel.checked) {
221− hereCheckLabel.checked = false;
222− gpsCheckLabel.checked = false;
223− nopeCheckLabel.checked = true;
224− }
225− }
226− }
227− }
228−
229− Image {
230− fillMode: Image.PreserveAspectFit
231− height: units.gu(1.5)
232− source: "data/Tick@30.png"
233− opacity: nopeCheckLabel.checked ? 1 : 0
234− anchors.right: parent.right
235− anchors.verticalCenter: nopeCheckLabel.verticalCenter
236− anchors.rightMargin: column.anchors.rightMargin == 0 ? staticMargin : 0
237− }
238−
239− Rectangle {
240− id: divider3
241− anchors.left: parent.left
242− anchors.right: parent.right
243− anchors.top: nopeCheckLabel.bottom
244− anchors.topMargin: units.gu(3)
245− height: units.dp(1)
246− color: dividerColor
247− }
248−
249− Label {
250− id: infoLabel
251− anchors {
252− left: parent.left
253− right: parent.right
254− top: divider3.bottom
255− topMargin: units.gu(4)
256− leftMargin: column.anchors.leftMargin == 0 ? staticMargin : 0
257− rightMargin: column.anchors.rightMargin == 0 ? staticMargin : 0
258− }
259− wrapMode: Text.Wrap
260− text: i18n.tr("You can change it later in System Settings.")
261− color: textColor
262− fontSize: "small"
263− font.weight: Font.Light
264− width: content.width
265− }
266− }
267−
268− Component {
269− id: forwardButton
270− LocalComponents.StackButton {
271− text: i18n.tr("Next")
272− onClicked: {
273− var locationOn = gpsCheckLabel.checked || hereCheckLabel.checked;
274− var gpsOn = gpsCheckLabel.checked || hereCheckLabel.checked;
275− var hereOn = hereCheckLabel.checked;
276−
277− // location service doesn't currently listen to updateState
278− // requests, so we activate the actions if needed.
279− if (locationActionGroup.location.state != locationOn) {
280− locationActionGroup.location.activate();
281− }
282− if (locationActionGroup.gps.state != gpsOn) {
283− locationActionGroup.gps.activate();
284− }
285− AccountsService.hereEnabled = hereOn;
286− pageStack.next();
287− }
288− }
289− }
290−}
qml/Wizard/Pages/50-timezone.qml+2−1
@@ -28,6 +28,7 @@ LocalComponents.Page {
2828 objectName: "tzPage"
2929
3030 title: i18n.tr("Time Zone")
31+ focusItem: searchField
3132 forwardButtonSourceComponent: forwardButton
3233
3334 property string selectedTimeZone: ""
@@ -36,6 +37,7 @@ LocalComponents.Page {
3637
3738 // for testing
3839 readonly property alias tdModule: timeDatePanel
40+ onlyOnInstall: true
3941
4042 function highlightTimezone(offset) {
4143 highlightImage.source = "data/timezonemap/timezone_" + offset + ".png";
@@ -90,7 +92,6 @@ LocalComponents.Page {
9092 }
9193
9294 resetViews();
93− searchField.forceActiveFocus();
9495 }
9596 }
9697
qml/Wizard/Pages/60-account.qml+12−10
@@ -22,12 +22,18 @@ import ".." as LocalComponents
2222LocalComponents.Page {
2323 objectName: "accountPage"
2424 title: i18n.tr("Personalize Your Device")
25+ focusItem: nameInput
2526
2627 forwardButtonSourceComponent: forwardButton
28+ onlyOnInstall: true
2729
28− QtObject {
29− id: d
30− readonly property string validName: nameInput.text.trim()
30+ readonly property string validName: nameInput.text.trim()
31+
32+ function saveNameAndGoNext() {
33+ if (validName) {
34+ AccountsService.realName = validName;
35+ }
36+ pageStack.next();
3137 }
3238
3339 Column {
@@ -56,19 +62,15 @@ LocalComponents.Page {
5662 anchors.left: parent.left
5763 anchors.right: parent.right
5864 inputMethodHints: Qt.ImhNoPredictiveText
65+ onAccepted: saveNameAndGoNext()
5966 }
6067 }
6168
6269 Component {
6370 id: forwardButton
6471 LocalComponents.StackButton {
65− text: d.validName ? i18n.tr("Next") : i18n.tr("Skip")
66− onClicked: {
67− if (d.validName) {
68− AccountsService.realName = d.validName;
69− }
70− pageStack.next();
71− }
72+ text: validName ? i18n.tr("Next") : i18n.tr("Skip")
73+ onClicked: saveNameAndGoNext()
7274 }
7375 }
7476}
qml/Wizard/Pages/70-passwd-type.qml+1
@@ -44,6 +44,7 @@ LocalComponents.Page {
4444 // or this isn't the first time the wizard has been run, etc). We can't
4545 // properly set the password again, so let's not pretend we can.
4646 skip: securityPrivacy.securityType !== UbuntuSecurityPrivacyPanel.Swipe
47+ onlyOnInstall: true
4748
4849 function indexToMethod(index) {
4950 if (index === 0/* || index === 1*/)
qml/Wizard/Pages/75-report-check.qmldeleted−91
@@ -1,91 +0,0 @@
1−/*
2− * Copyright (C) 2015-2016 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.4
18−import Ubuntu.Components 1.3
19−import Ubuntu.Web 0.2
20−import ".." as LocalComponents
21−
22−LocalComponents.Page {
23− id: reportingPage
24− objectName: "reportingPage"
25−
26− title: webview.visible ? i18n.tr("Privacy Policy") : i18n.tr("Help Us Improve")
27− forwardButtonSourceComponent: !webview.visible ? forwardButton : null
28− customBack: true
29− customTitle: webview.visible
30−
31− skip: !diagnostics.reportCrashes // skip the page when the system is configured not to report crashes
32−
33− onBackClicked: {
34− if (webview.visible) {
35− webview.visible = false;
36− } else {
37− pageStack.prev();
38− }
39− }
40−
41− Column {
42− id: column
43− anchors {
44− fill: content
45− leftMargin: leftMargin
46− rightMargin: rightMargin
47− topMargin: customMargin
48− }
49−
50− LocalComponents.CheckableSetting {
51− anchors {
52− left: parent.left
53− right: parent.right
54− }
55−
56− id: reportCheck
57− objectName: "reportCheck"
58− showDivider: false
59− text: i18n.tr("Improve system performance by sending us crashes and error reports.") + "<br><br><a href='#'>" +
60− i18n.tr("Privacy policy") + "</a>"
61− checked: diagnostics.reportCrashes
62− visible: !webview.visible
63− onLinkActivated: {
64− webview.url = "http://www.ubuntu.com/legal/terms-and-policies/privacy-policy";
65− webview.visible = true;
66− }
67− }
68−
69− WebView {
70− id: webview
71− objectName: "webview"
72− anchors.left: parent.left
73− anchors.right: parent.right
74− anchors.leftMargin: -leftMargin
75− anchors.rightMargin: -rightMargin
76− height: parent.height
77− visible: false
78− }
79− }
80−
81− Component {
82− id: forwardButton
83− LocalComponents.StackButton {
84− text: i18n.tr("Next")
85− onClicked: {
86− diagnostics.setReportCrashes(reportCheck.checked);
87− pageStack.next();
88− }
89− }
90− }
91−}
qml/Wizard/Pages/76-app-update.qmlnew file+241
@@ -0,0 +1,241 @@
1+/*
2+ * Copyright (C) 2018 The UBports project
3+ *
4+ * Written by: Dalton Durst <dalton@ubports.com>
5+ * Marius Gripsgard <marius@ubports.com>
6+ *
7+ * This program is free software: you can redistribute it and/or modify it
8+ * under the terms of the GNU General Public License version 3, as published
9+ * by the Free Software Foundation.
10+ *
11+ * This program is distributed in the hope that it will be useful, but
12+ * WITHOUT ANY WARRANTY; without even the implied warranties of
13+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
14+ * PURPOSE. See the GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License along
17+ * with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+import QMenuModel 0.1
21+import QtQuick 2.4
22+import QtQuick.Layouts 1.1
23+import Ubuntu.Components 1.3
24+import Ubuntu.Components.ListItems 1.3 as ListItem
25+import Ubuntu.Components.Popups 1.3
26+import Ubuntu.SystemSettings.Update 1.0
27+import Wizard 0.1
28+import ".." as LocalComponents
29+
30+LocalComponents.Page {
31+ id: appUpdatePage
32+ objectName: "appUpdatePage"
33+
34+ title: i18n.tr("Update Apps")
35+ forwardButtonSourceComponent: forwardButton
36+
37+ property bool batchMode: false
38+
39+ onlyOnUpdate: true
40+
41+ property int updatesCount: {
42+ var count = 0;
43+ count += clickRepeater.count;
44+ return count;
45+ }
46+
47+ function check(force) {
48+ UpdateManager.check(UpdateManager.CheckClickIgnoreVersion);
49+ }
50+
51+ DownloadHandler {
52+ id: downloadHandler
53+ updateModel: UpdateManager.model
54+ }
55+
56+ Flickable {
57+ id: scrollWidget
58+ anchors {
59+ fill: content
60+ leftMargin: parent.leftMargin
61+ rightMargin: parent.rightMargin
62+ }
63+ clip: true
64+ contentHeight: scrollWidgetContent.height
65+ boundsBehavior: (contentHeight > scrollWidgetContent.height) ?
66+ Flickable.DragAndOvershootBounds :
67+ Flickable.StopAtBounds
68+ flickableDirection: Flickable.VerticalFlick
69+
70+ Column {
71+ id: scrollWidgetContent
72+ anchors {
73+ left: parent.left
74+ right: parent.right
75+ }
76+
77+ GlobalUpdateControls {
78+ id: g
79+ objectName: "global"
80+ anchors { left: parent.left; right: parent.right }
81+
82+ height: hidden ? 0 : units.gu(8)
83+ clip: true
84+ status: UpdateManager.status
85+ batchMode: appUpdatePage.batchMode
86+ updatesCount: appUpdatePage.updatesCount
87+ online: root.connected
88+ onStop: UpdateManager.cancel()
89+
90+ onRequestInstall: {
91+ install();
92+ }
93+ onInstall: {
94+ appUpdatePage.batchMode = true
95+ postClickBatchHandler.target = appUpdatePage;
96+ }
97+ }
98+
99+ Rectangle {
100+ id: overlay
101+ objectName: "overlay"
102+ anchors {
103+ left: parent.left
104+ leftMargin: units.gu(2)
105+ right: parent.right
106+ rightMargin: units.gu(2)
107+ }
108+ visible: placeholder.text
109+ color: theme.palette.normal.background
110+ height: units.gu(10)
111+
112+ Label {
113+ id: placeholder
114+ objectName: "overlayText"
115+ anchors.fill: parent
116+ verticalAlignment: Text.AlignVCenter
117+ horizontalAlignment: Text.AlignHCenter
118+ wrapMode: Text.WordWrap
119+ text: {
120+ var s = UpdateManager.status;
121+ if (!root.connected) {
122+ return i18n.tr("This device is not connected to the internet.") + " " +
123+ i18n.tr("Use the OpenStore app to check for updates once connected.");
124+ } else if (s === UpdateManager.StatusIdle && updatesCount === 0) {
125+ return i18n.tr("Software is up to date");
126+ } else if (s === UpdateManager.StatusServerError ||
127+ s === UpdateManager.StatusNetworkError) {
128+ return i18n.tr("The update server is not responding.") + " " +
129+ i18n.tr("Use the OpenStore app to check for updates once connected.");
130+ }
131+ return "";
132+ }
133+ }
134+ }
135+
136+ Column {
137+ id: clickUpdatesCol
138+ objectName: "clickUpdates"
139+ anchors { left: parent.left; right: parent.right }
140+ visible: {
141+ var s = UpdateManager.status;
142+ var haveUpdates = clickRepeater.count > 0;
143+ switch (s) {
144+ case UpdateManager.StatusCheckingImageUpdates:
145+ case UpdateManager.StatusIdle:
146+ return haveUpdates && root.connected;
147+ }
148+ return false;
149+ }
150+
151+ Repeater {
152+ id: clickRepeater
153+ model: UpdateManager.clickUpdates
154+
155+ delegate: ClickUpdateDelegate {
156+ objectName: "clickUpdatesDelegate" + index
157+ width: clickUpdatesCol.width
158+ updateState: model.updateState
159+ progress: model.progress
160+ version: remoteVersion
161+ size: model.size
162+ name: title
163+ iconUrl: model.iconUrl
164+ kind: model.kind
165+ error: model.error
166+ signedUrl: signedDownloadUrl
167+
168+ onInstall: downloadHandler.createDownload(model);
169+ onPause: downloadHandler.pauseDownload(model)
170+ onResume: downloadHandler.resumeDownload(model)
171+ onRetry: {
172+ /* This creates a new signed URL with which we can
173+ retry the download. See onSignedUrlChanged. */
174+ UpdateManager.retry(model.identifier,
175+ model.revision);
176+ }
177+
178+ onSignedUrlChanged: {
179+ // If we have a signedUrl, user intend to retry.
180+ if (signedUrl) {
181+ downloadHandler.retryDownload(model);
182+ }
183+ }
184+
185+ Connections {
186+ target: g
187+ onInstall: install()
188+ }
189+
190+ /* If we a downloadId, we expect UDM to restore it
191+ after some time. Workaround for lp:1603770. */
192+ Timer {
193+ id: downloadTimeout
194+ interval: 30000
195+ running: true
196+ onTriggered: {
197+ var s = updateState;
198+ if (model.downloadId
199+ || s === Update.StateQueuedForDownload
200+ || s === Update.StateDownloading) {
201+ downloadHandler.assertDownloadExist(model);
202+ }
203+ }
204+ }
205+ }
206+ }
207+ }
208+ } // Column inside flickable
209+ } // Flickable
210+
211+ Connections {
212+ id: postClickBatchHandler
213+ ignoreUnknownSignals: true
214+ target: null
215+ onUpdatesCountChanged: {
216+ if (target.updatesCount === 0) {
217+ appUpdatePage.batchMode = false;
218+ target = null;
219+ }
220+ }
221+ }
222+
223+ Component.onCompleted: check()
224+
225+ Component {
226+ id: forwardButton
227+ LocalComponents.StackButton {
228+ text: {
229+ var s = UpdateManager.status;
230+ if (s === UpdateManager.StatusIdle && updatesCount === 0) {
231+ return i18n.tr("Next");
232+ } else if (s === UpdateManager.StatusCheckingClickUpdates) {
233+ return i18n.tr("Please wait...")
234+ } else {
235+ return i18n.tr("Skip");
236+ }
237+ }
238+ onClicked: pageStack.next()
239+ }
240+ }
241+}
qml/Wizard/Pages/78-firmware-update.qml.disablednew file+246
@@ -0,0 +1,246 @@
1+/*
2+ * Copyright (C) 2018 The UBports project
3+ *
4+ * Written by: Marius Gripsgard <marius@ubports.com>
5+ *
6+ * This program is free software; you can redistribute it and/or modify
7+ * it under the terms of the GNU General Public License as published by
8+ * the Free Software Foundation; version 3.
9+ *
10+ * This program is distributed in the hope that it will be useful,
11+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+ * GNU General Public License for more details.
14+ *
15+ * You should have received a copy of the GNU General Public License
16+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
17+ */
18+
19+import QtQuick 2.4
20+import QtQuick.Layouts 1.1
21+import Ubuntu.Components 1.3
22+import Ubuntu.SystemSettings.Update 1.0
23+import Ubuntu.Connectivity 1.0
24+import Wizard 0.1
25+import ".." as LocalComponents
26+
27+LocalComponents.Page {
28+ id: firmwareUpdatePage
29+ objectName: "firmwareUpdatePage"
30+
31+ title: i18n.tr("Firmware Update")
32+ forwardButtonSourceComponent: forwardButton
33+
34+ skip: !SystemImage.supportsFirmwareUpdate()
35+
36+ property bool online: root.connected
37+ property bool hasUpdate: false
38+ property bool isUpdating: false
39+ property bool isChecking: true
40+ property var partitions: ""
41+
42+ function check() {
43+ if (!SystemImage.supportsFirmwareUpdate()) {
44+ return;
45+ }
46+ firmwareUpdatePage.isChecking = true;
47+ SystemImage.checkForFirmwareUpdate();
48+ }
49+
50+ function flash() {
51+ if (!SystemImage.supportsFirmwareUpdate()) {
52+ return pageStack.next();
53+ }
54+ firmwareUpdatePage.isUpdating = true;
55+ SystemImage.updateFirmware();
56+ }
57+
58+ Connections {
59+ target: SystemImage
60+ onCheckForFirmwareUpdateDone: {
61+ var updateobj = JSON.parse(updateObj);
62+ if (Array.isArray(updateobj) && updateobj.length > 0) {
63+ for (var u in updateobj) {
64+ console.log(u);
65+ if (firmwareUpdatePage.partitions === "") {
66+ firmwareUpdatePage.partitions += updateobj[u].file;
67+ } else {
68+ firmwareUpdatePage.partitions += ", " + updateobj[u].file;
69+ }
70+ }
71+ firmwareUpdatePage.hasUpdate = true;
72+ }
73+ console.log(updateobj);
74+ firmwareUpdatePage.isChecking = false;
75+ }
76+ onUpdateFirmwareDone: {
77+ var updateobj = JSON.parse(updateObj);
78+ if (Array.isArray(updateobj) && updateobj.length === 0) {
79+ // This means success!
80+ firmwareUpdatePage.hasUpdate = false;
81+ firmwareUpdatePage.partitions = "";
82+ System.skipUntilFinishedPage();
83+ SystemImage.reboot();
84+ return;
85+ }
86+ console.log(updateobj);
87+ firmwareUpdatePage.isUpdating = false;
88+ }
89+ }
90+
91+ Column {
92+ id: column
93+ anchors {
94+ fill: content
95+ leftMargin: firmwareUpdatePage.leftMargin
96+ rightMargin: firmwareUpdatePage.rightMargin
97+ topMargin: firmwareUpdatePage.customMargin
98+ }
99+ spacing: units.gu(3)
100+ opacity: spinner.visible ? 0.5 : 1
101+ Behavior on opacity {
102+ UbuntuNumberAnimation {}
103+ }
104+
105+ Label {
106+ visible: !firmwareUpdatePage.isChecking
107+ anchors.horizontalCenter: parent.horizontalCenter
108+ font.weight: Font.Light
109+ wrapMode: Text.Wrap
110+ textSize: Label.Medium
111+ text: firmwareUpdatePage.hasUpdate ? i18n.tr("There is a firmware update available!")
112+ : online ? i18n.tr("Firmware is up to date!")
113+ : i18n.tr("Please connect to the Internet to check for updates.")
114+
115+ }
116+
117+ GridLayout {
118+ rows: 3
119+ columns: 2
120+ rowSpacing: units.gu(1)
121+ columnSpacing: units.gu(2)
122+ anchors.horizontalCenter: parent.horizontalCenter
123+ visible: hasUpdate
124+
125+ Icon {
126+ Layout.rowSpan: 3
127+ Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
128+ width: units.gu(5)
129+ height: width
130+ name: "security-alert"
131+ }
132+
133+ Label {
134+ font.weight: Font.Normal
135+ textSize: Label.Medium
136+ text: i18n.tr("Firmware Update")
137+ }
138+
139+ Label {
140+ font.weight: Font.Light
141+ wrapMode: Text.WordWrap
142+ fontSize: "small"
143+ text: firmwareUpdatePage.partitions
144+ }
145+
146+ Label {
147+ font.weight: Font.Light
148+ fontSize: "small"
149+ text: i18n.tr("The device will automatically restart after installing is done.")
150+ }
151+ }
152+
153+ Rectangle {
154+ anchors.left: parent.left
155+ anchors.leftMargin: 3
156+ anchors.horizontalCenter: parent.horizontalCenter
157+ color: theme.palette.normal.foreground
158+ radius: units.dp(4)
159+ width: buttonLabel.paintedWidth + units.gu(3)
160+ height: buttonLabel.paintedHeight + units.gu(1.8)
161+ visible: hasUpdate
162+
163+ Label {
164+ id: buttonLabel
165+ text: i18n.tr("Install and restart now")
166+ font.weight: Font.Light
167+ anchors.horizontalCenter: parent.horizontalCenter
168+ anchors.centerIn: parent
169+ }
170+
171+ AbstractButton {
172+ id: button
173+ objectName: "installButton"
174+ anchors.fill: parent
175+ anchors.horizontalCenter: parent.horizontalCenter
176+ onClicked: {
177+ firmwareUpdatePage.flash()
178+ }
179+ }
180+
181+ transformOrigin: Item.Top
182+ scale: button.pressed ? 0.98 : 1.0
183+ Behavior on scale {
184+ ScaleAnimator {
185+ duration: UbuntuAnimation.SnapDuration
186+ easing.type: Easing.Linear
187+ }
188+ }
189+ }
190+ }
191+
192+ Column {
193+ id: spinner
194+ anchors.centerIn: firmwareUpdatePage
195+ visible: firmwareUpdatePage.isChecking || firmwareUpdatePage.isUpdating
196+ spacing: units.gu(1)
197+
198+ ActivityIndicator {
199+ anchors.horizontalCenter: parent.horizontalCenter
200+ running: parent.visible
201+ }
202+
203+ Label {
204+ wrapMode: Text.Wrap
205+ width: firmwareUpdatePage.width - units.gu(3)
206+ fontSize: "small"
207+ text: i18n.tr("Downloading and Flashing firmware updates, this could take a few minutes...")
208+ visible: firmwareUpdatePage.isUpdating
209+ }
210+
211+ Label {
212+ wrapMode: Text.Wrap
213+ fontSize: "small"
214+ text: i18n.tr("Checking for firmware update")
215+ visible: firmwareUpdatePage.isChecking
216+ }
217+
218+ Component.onCompleted: {
219+ if (online) {
220+ firmwareUpdatePage.check();
221+ }
222+ else {
223+ firmwareUpdatePage.isChecking = false;
224+ }
225+ }
226+ }
227+
228+ Connections {
229+ target: NetworkingStatus
230+ onOnlineChanged: {
231+ if (online) {
232+ firmwareUpdatePage.check();
233+ } else {
234+ firmwareUpdatePage.isChecking = false;
235+ }
236+ }
237+ }
238+
239+ Component {
240+ id: forwardButton
241+ LocalComponents.StackButton {
242+ text: (!firmwareUpdatePage.hasUpdate && !spinner.visible) ? i18n.tr("Next") : i18n.tr("Skip");
243+ onClicked: pageStack.next();
244+ }
245+ }
246+}
qml/Wizard/Pages/79-system-update.qmlnew file+148
@@ -0,0 +1,148 @@
1+/*
2+ * Copyright (C) 2016 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.4
18+import QtQuick.Layouts 1.1
19+import Ubuntu.Components 1.3
20+import Ubuntu.SystemSettings.Update 1.0
21+import Wizard 0.1
22+import ".." as LocalComponents
23+
24+LocalComponents.Page {
25+ id: systemUpdatePage
26+ objectName: "systemUpdatePage"
27+
28+ title: i18n.tr("Update Device")
29+ forwardButtonSourceComponent: forwardButton
30+
31+ skip: !root.updateDownloaded // skip the page when the system update is not ready to install
32+
33+ Column {
34+ id: column
35+ anchors {
36+ fill: content
37+ leftMargin: systemUpdatePage.leftMargin
38+ rightMargin: systemUpdatePage.rightMargin
39+ topMargin: systemUpdatePage.customMargin
40+ }
41+ spacing: units.gu(3)
42+ opacity: spinner.running ? 0.5 : 1
43+ Behavior on opacity {
44+ UbuntuNumberAnimation {}
45+ }
46+
47+ Label {
48+ anchors.left: parent.left
49+ anchors.right: parent.right
50+ anchors.leftMargin: column.anchors.leftMargin == 0 ? staticMargin : 0
51+ font.weight: Font.Light
52+ color: textColor
53+ wrapMode: Text.Wrap
54+ fontSize: "small"
55+ text: i18n.tr("There is a system update available and ready to install. Afterwards, the device will automatically restart.")
56+ }
57+
58+ GridLayout {
59+ rows: 3
60+ columns: 2
61+ rowSpacing: units.gu(1)
62+ columnSpacing: units.gu(2)
63+
64+ Image {
65+ Layout.rowSpan: 3
66+ Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
67+ sourceSize: Qt.size(units.gu(3), units.gu(3))
68+ fillMode: Image.PreserveAspectFit
69+ source: "image://theme/distributor-logo"
70+ }
71+
72+ Label {
73+ color: textColor
74+ font.weight: Font.Normal
75+ fontSize: "small"
76+ text: i18n.ctr("string identifying name of the update", "Ubuntu Touch system")
77+ }
78+
79+ Label {
80+ font.weight: Font.Light
81+ fontSize: "small"
82+ color: textColor
83+ text: i18n.ctr("version of the system update", "Version %1").arg(SystemImage.targetBuildNumber)
84+ }
85+ }
86+
87+ Label {
88+ anchors.left: parent.left
89+ anchors.right: parent.right
90+ anchors.leftMargin: column.anchors.leftMargin == 0 ? staticMargin : 0
91+ font.weight: Font.Light
92+ color: textColor
93+ wrapMode: Text.Wrap
94+ fontSize: "small"
95+ text: i18n.tr("This could take a few minutes...")
96+ }
97+
98+ Rectangle {
99+ anchors.left: parent.left
100+ anchors.leftMargin: column.anchors.leftMargin == 0 ? staticMargin : 0
101+ color: theme.palette.normal.foreground
102+ radius: units.dp(4)
103+ width: buttonLabel.paintedWidth + units.gu(3)
104+ height: buttonLabel.paintedHeight + units.gu(1.8)
105+
106+ Label {
107+ id: buttonLabel
108+ color: textColor
109+ text: i18n.tr("Install and restart now")
110+ font.weight: Font.Light
111+ anchors.centerIn: parent
112+ }
113+
114+ AbstractButton {
115+ id: button
116+ objectName: "installButton"
117+ anchors.fill: parent
118+ onClicked: {
119+ System.skipUntilFinishedPage();
120+ SystemImage.applyUpdate();
121+ }
122+ }
123+
124+ transformOrigin: Item.Top
125+ scale: button.pressed ? 0.98 : 1.0
126+ Behavior on scale {
127+ ScaleAnimator {
128+ duration: UbuntuAnimation.SnapDuration
129+ easing.type: Easing.Linear
130+ }
131+ }
132+ }
133+ }
134+
135+ ActivityIndicator {
136+ id: spinner
137+ anchors.centerIn: systemUpdatePage
138+ visible: running
139+ }
140+
141+ Component {
142+ id: forwardButton
143+ LocalComponents.StackButton {
144+ text: i18n.tr("Skip")
145+ onClicked: pageStack.next()
146+ }
147+ }
148+}
qml/Wizard/Pages/80-finished.qml+4−2
@@ -1,4 +1,5 @@
11/*
2+ * Copyright (C) 2018 The UBports project
23 * Copyright (C) 2013-2016 Canonical, Ltd.
34 *
45 * This program is free software; you can redistribute it and/or modify
@@ -16,6 +17,7 @@
1617
1718import QtQuick 2.4
1819import Ubuntu.Components 1.3
20+import Wizard 0.1
1921import ".." as LocalComponents
2022
2123LocalComponents.Page {
@@ -86,7 +88,7 @@ LocalComponents.Page {
8688 fontSize: "x-large"
8789 font.weight: Font.Light
8890 lineHeight: 1.2
89− text: i18n.tr("Welcome to Ubuntu")
91+ text: (System.isUpdate) ? i18n.tr("Welcome Back") : i18n.tr("Welcome to Ubuntu")
9092 color: whiteColor
9193 }
9294
@@ -121,7 +123,7 @@ LocalComponents.Page {
121123 Label {
122124 id: buttonLabel
123125 color: whiteColor
124− text: i18n.tr("Get Started")
126+ text: (System.isUpdate) ? i18n.tr("Continue") : i18n.tr("Get Started")
125127 fontSize: "medium"
126128 anchors.centerIn: parent
127129 }
qml/Wizard/Pages/ClickUpdateDelegate.qmlnew file+26
@@ -0,0 +1,26 @@
1+/*
2+ * This file is part of system-settings
3+ *
4+ * Copyright (C) 2016 Canonical Ltd.
5+ *
6+ * This program is free software: you can redistribute it and/or modify it
7+ * under the terms of the GNU General Public License version 3, as published
8+ * by the Free Software Foundation.
9+ *
10+ * This program is distributed in the hope that it will be useful, but
11+ * WITHOUT ANY WARRANTY; without even the implied warranties of
12+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13+ * PURPOSE. See the GNU General Public License for more details.
14+ *
15+ * You should have received a copy of the GNU General Public License along
16+ * with this program. If not, see <http://www.gnu.org/licenses/>.
17+ */
18+
19+import QtQuick 2.4
20+import Ubuntu.SystemSettings.Update 1.0
21+
22+UpdateDelegate {
23+ id: update
24+
25+ property string signedUrl
26+}
qml/Wizard/Pages/DownloadHandler.qmlnew file+204
@@ -0,0 +1,204 @@
1+/*
2+ * This file is part of system-settings
3+ *
4+ * Copyright (C) 2016 Canonical Ltd.
5+ *
6+ * This program is free software: you can redistribute it and/or modify it
7+ * under the terms of the GNU General Public License version 3, as published
8+ * by the Free Software Foundation.
9+ *
10+ * This program is distributed in the hope that it will be useful, but
11+ * WITHOUT ANY WARRANTY; without even the implied warranties of
12+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13+ * PURPOSE. See the GNU General Public License for more details.
14+ *
15+ * You should have received a copy of the GNU General Public License along
16+ * with this program. If not, see <http://www.gnu.org/licenses/>.
17+ *
18+ */
19+import QtQuick 2.4
20+import Ubuntu.DownloadManager 1.2
21+
22+Item {
23+ id: downloadHandler
24+ property var updateModel
25+ property alias downloads: downloadManager.downloads
26+ property var udm: DownloadManager {
27+ id: downloadManager
28+ onDownloadFinished: {
29+ updateModel.setInstalled(download.metadata.custom.identifier,
30+ download.metadata.custom.revision);
31+ }
32+ onDownloadPaused: {
33+ updateModel.pauseUpdate(download.metadata.custom.identifier,
34+ download.metadata.custom.revision)
35+ }
36+ onDownloadResumed: {
37+ updateModel.resumeUpdate(download.metadata.custom.identifier,
38+ download.metadata.custom.revision)
39+ }
40+ onDownloadCanceled: {
41+ updateModel.cancelUpdate(download.metadata.custom.identifier,
42+ download.metadata.custom.revision)
43+ }
44+ onErrorFound: {
45+ updateModel.setError(download.metadata.custom.identifier,
46+ download.metadata.custom.revision,
47+ download.errorMessage)
48+ }
49+ onDownloadsChanged: restoreDownloads()
50+ Component.onCompleted: restoreDownloads()
51+ }
52+
53+ function downloadAll() {
54+
55+ }
56+
57+ function restoreDownloads() {
58+ var dl;
59+ for (var i = 0; i<downloads.length; i++) {
60+ dl = downloads[i];
61+ if (!dl._bound) {
62+ /* We only bind those signals here, that the UDM does not
63+ receive, i.e. processing and progressChanged. */
64+ dl.progressChanged.connect(onDownloadProgress.bind(dl));
65+ dl.processing.connect(onDownloadProcessing.bind(dl));
66+ dl._bound = true;
67+ }
68+ }
69+ }
70+
71+ function resumeDownload(click) {
72+ var download = getDownloadFor(click);
73+ if (download && !download.downloading && !download.isCompleted) {
74+ download.resume();
75+ }
76+ }
77+
78+ function pauseDownload(click) {
79+ var download = getDownloadFor(click);
80+ if (download && download.downloading) {
81+ download.pause();
82+ }
83+ }
84+
85+ // Return download for a click update.
86+ function getDownloadFor(click) {
87+ var cust;
88+ var dl;
89+
90+ for (var i = 0; i<downloads.length; i++) {
91+ dl = downloads[i];
92+ if (dl.errorMessage || dl.isCompleted) {
93+ // Ignore failed and completed downloads.
94+ continue;
95+ }
96+
97+ cust = downloads[i].metadata.custom;
98+ if (cust.identifier === click.identifier && cust.revision === click.revision) {
99+ return downloads[i];
100+ }
101+ }
102+ return null;
103+ }
104+
105+ function hasExistingDownload(click) {
106+ var existingDownload = getDownloadFor(click);
107+ return (existingDownload !== null &&
108+ !existingDownload.errorMessage &&
109+ !existingDownload.isCompleted);
110+ }
111+
112+ function retryDownload(click) {
113+ return createDownload(click, true);
114+ }
115+
116+ function createDownload(click, useSignedUrl) {
117+ if (hasExistingDownload(click)) {
118+ return null;
119+ }
120+ var downloadUrl = click.downloadUrl;
121+ var metadata = {
122+ "command": click.command,
123+ "title": click.title,
124+ "showInIndicator": false
125+ };
126+ var metadataObj = mdt.createObject(root, metadata);
127+ metadataObj.custom = {
128+ "identifier": click.identifier,
129+ "package-name": click.identifier,
130+ "revision": click.revision,
131+ };
132+
133+ var hdrs = {}
134+ if (useSignedUrl) {
135+ if (!click.signedDownloadUrl) {
136+ console.warn('The signed download URL was empty.');
137+ }
138+ downloadUrl = click.signedDownloadUrl;
139+ } else {
140+ // If we're using an unsigned URL, we need to provide this header.
141+ hdrs["X-Click-Token"] = click.token;
142+ }
143+
144+ var singleDownloadObj = sdl.createObject(root, {
145+ "autoStart": true,
146+ "hash": click.downloadHash,
147+ "algorithm": "sha512",
148+ "headers": hdrs,
149+ "metadata": metadataObj,
150+ "revision": click.revision,
151+ "identifier": click.identifier
152+ });
153+ singleDownloadObj.download(downloadUrl);
154+ return singleDownloadObj;
155+ }
156+
157+ function onDownloadProgress(progress) {
158+ updateModel.setProgress(this.metadata.custom.identifier,
159+ this.metadata.custom.revision,
160+ this.progress);
161+ }
162+
163+ function onDownloadProcessing() {
164+ updateModel.processUpdate(this.metadata.custom.identifier,
165+ this.metadata.custom.revision);
166+ }
167+
168+ /* If a update's model has a downloadId, check if UDM knows it. If not,
169+ treat this as a failure. Workaround for lp:1603770. */
170+ function assertDownloadExist(click) {
171+ if (!getDownloadFor(click)) {
172+ updateModel.setError(
173+ click.identifier, click.revision,
174+ i18n.tr("Installation failed")
175+ );
176+ }
177+ }
178+
179+ Component {
180+ id: sdl
181+ SingleDownload {
182+ id: download
183+ objectName: "singleDownload"
184+ property bool _bound: true
185+
186+ onDownloadIdChanged: {
187+ updateModel.queueUpdate(metadata.custom.identifier,
188+ metadata.custom.revision,
189+ downloadId);
190+ }
191+ onStarted: {
192+ updateModel.startUpdate(metadata.custom.identifier,
193+ metadata.custom.revision);
194+ }
195+ onProgressChanged: onDownloadProgress.call(download)
196+ onProcessing: onDownloadProcessing.call(download)
197+ }
198+ }
199+
200+ Component {
201+ id: mdt
202+ Metadata {}
203+ }
204+}
qml/Wizard/Pages/GlobalUpdateControls.qmlnew file+138
@@ -0,0 +1,138 @@
1+/*
2+ * This file is part of system-settings
3+ *
4+ * Copyright (C) 2016 Canonical Ltd.
5+ *
6+ * This program is free software: you can redistribute it and/or modify it
7+ * under the terms of the GNU General Public License version 3, as published
8+ * by the Free Software Foundation.
9+ *
10+ * This program is distributed in the hope that it will be useful, but
11+ * WITHOUT ANY WARRANTY; without even the implied warranties of
12+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13+ * PURPOSE. See the GNU General Public License for more details.
14+ *
15+ * You should have received a copy of the GNU General Public License along
16+ * with this program. If not, see <http://www.gnu.org/licenses/>.
17+ */
18+
19+import QtQuick 2.4
20+import QtQuick.Layouts 1.1
21+import Ubuntu.Components 1.3
22+import Ubuntu.Components.ListItems 1.3 as ListItems
23+import Ubuntu.SystemSettings.Update 1.0
24+
25+Item {
26+ id: g
27+
28+ property bool batchMode
29+ property int status // A UpdateManager::Status
30+ property bool requireRestart: false
31+ property int updatesCount: 0
32+ property bool online: false
33+
34+ property bool hidden: {
35+ switch (status) {
36+ case UpdateManager.StatusNetworkError:
37+ case UpdateManager.StatusServerError:
38+ return true;
39+ }
40+ return !online ||
41+ (updatesCount <= 1 && status === UpdateManager.StatusIdle) ||
42+ batchMode
43+ }
44+
45+ signal stop()
46+ signal requestInstall()
47+ signal install()
48+
49+ Behavior on height {
50+ UbuntuNumberAnimation {}
51+ }
52+
53+ RowLayout {
54+ id: checking
55+ spacing: units.gu(2)
56+ anchors {
57+ fill: parent
58+ margins: units.gu(2)
59+ }
60+
61+ Behavior on opacity {
62+ UbuntuNumberAnimation {}
63+ }
64+
65+ opacity: visible ? 1 : 0
66+ visible: {
67+ switch (g.status) {
68+ case UpdateManager.StatusCheckingClickUpdates:
69+ case UpdateManager.StatusCheckingImageUpdates:
70+ case UpdateManager.StatusCheckingAllUpdates:
71+ return true;
72+ }
73+ return false;
74+ }
75+
76+ ActivityIndicator {
77+ running: parent.visible
78+ }
79+
80+ Label {
81+ objectName: "checkLabel"
82+ Layout.fillWidth: true
83+ elide: Text.ElideRight
84+ text: i18n.tr("Checking for updates…")
85+ }
86+ }
87+
88+ RowLayout {
89+ id: install
90+ anchors {
91+ fill: parent
92+ margins: units.gu(2)
93+ }
94+ spacing: units.gu(2)
95+
96+ Behavior on opacity {
97+ UbuntuNumberAnimation {}
98+ }
99+
100+ opacity: visible ? 1 : 0
101+ visible: {
102+ var canInstall = g.status === UpdateManager.StatusIdle;
103+ return canInstall && updatesCount > 1;
104+ }
105+
106+ Label {
107+ objectName: "updatesGlobalInfoLabel"
108+ // // TRANSLATORS: %1 is number of software updates available.
109+ text: i18n.tr("%1 update available",
110+ "%1 updates available",
111+ updatesCount).arg(updatesCount)
112+ Layout.fillWidth: true
113+ }
114+
115+ Button {
116+ objectName: "updatesGlobalInstallButton"
117+ text: {
118+ if (g.requireRestart === true) {
119+ return i18n.tr("Update all…");
120+ } else {
121+ return i18n.tr("Update all");
122+ }
123+ }
124+ onClicked: g.requestInstall()
125+ color: theme.palette.normal.positive
126+ strokeColor: "transparent"
127+ }
128+ }
129+
130+ ListItems.ThinDivider {
131+ visible: !g.hidden
132+ anchors {
133+ left: parent.left
134+ right: parent.right
135+ bottom: parent.bottom
136+ }
137+ }
138+}
qml/Wizard/Pages/UpdateDelegate.qmlnew file+389
@@ -0,0 +1,389 @@
1+/*
2+ * This file is part of system-settings
3+ *
4+ * Copyright (C) 2016 Canonical Ltd.
5+ *
6+ * Contact: Jonas G. Drange <jonas.drange@canonical.com>
7+ *
8+ * This program is free software: you can redistribute it and/or modify it
9+ * under the terms of the GNU General Public License version 3, as published
10+ * by the Free Software Foundation.
11+ *
12+ * This program is distributed in the hope that it will be useful, but
13+ * WITHOUT ANY WARRANTY; without even the implied warranties of
14+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
15+ * PURPOSE. See the GNU General Public License for more details.
16+ *
17+ * You should have received a copy of the GNU General Public License along
18+ * with this program. If not, see <http://www.gnu.org/licenses/>.
19+ *
20+ */
21+
22+import QtQuick 2.4
23+import QtQuick.Layouts 1.1
24+import Ubuntu.Components 1.3
25+import Ubuntu.Components.ListItems 1.3 as ListItems
26+import Ubuntu.Components.Themes 1.3
27+import Ubuntu.SystemSettings.Update 1.0
28+
29+ListItem {
30+ id: update
31+
32+ property int updateState // This is an Update::State
33+ property int kind // This is an Update::Kind
34+ property real size
35+ property string version
36+ property string downloadId
37+ property date updatedAt
38+ property bool launchable: false
39+
40+ property alias name: nameLabel.text
41+ property alias error: errorElementDetail.text
42+ property alias iconUrl: icon.source
43+ property alias progress: progressBar.value
44+
45+ signal retry()
46+ signal download()
47+ signal pause()
48+ signal resume()
49+ signal install()
50+ signal launch()
51+
52+ height: layout.height + (divider.visible ? divider.height : 0)
53+ Behavior on height {
54+ animation: UbuntuNumberAnimation {}
55+ }
56+
57+ SlotsLayout {
58+ id: layout
59+ mainSlot: ColumnLayout {
60+ spacing: units.gu(1)
61+ // Width the parent, minus the icon and some padding
62+ width: parent.width - (icon.width + (layout.padding.top * 3))
63+
64+ RowLayout {
65+ spacing: units.gu(2)
66+
67+ Label {
68+ id: nameLabel
69+ verticalAlignment: Text.AlignVCenter
70+ elide: Text.ElideMiddle
71+ Layout.fillWidth: true
72+ Layout.fillHeight: true
73+ }
74+
75+ Button {
76+ id: button
77+ objectName: "updateButton"
78+ Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
79+ visible: {
80+ switch (updateState) {
81+ case Update.StateInstalled:
82+ return launchable;
83+ default:
84+ return true;
85+ }
86+ }
87+ enabled: {
88+ switch(updateState) {
89+ case Update.StateAvailable:
90+ case Update.StateDownloading:
91+ case Update.StateDownloadingAutomatically:
92+ case Update.StateDownloadPaused:
93+ case Update.StateAutomaticDownloadPaused:
94+ case Update.StateInstallPaused:
95+ case Update.StateDownloaded:
96+ case Update.StateFailed:
97+ return true;
98+
99+ // Enabled if installed and a click app (can launch).
100+ case Update.StateInstalled:
101+ return kind === Update.KindClick;
102+
103+ case Update.StateInstalling:
104+ case Update.StateInstallingAutomatically:
105+ case Update.StateUnavailable:
106+ case Update.StateInstallFinished:
107+ case Update.StateQueuedForDownload:
108+ case Update.StateUnknown:
109+ default:
110+ return false;
111+ }
112+ }
113+ text: {
114+ switch(updateState) {
115+ case Update.StateUnknown:
116+ case Update.StateUnavailable:
117+ case Update.StateFailed:
118+ return i18n.tr("Retry");
119+
120+ case Update.StateAvailable:
121+ case Update.StateQueuedForDownload:
122+ if (update.kind === Update.KindClick) {
123+ return i18n.tr("Update");
124+ } else {
125+ return i18n.tr("Download");
126+ }
127+
128+ case Update.StateDownloadPaused:
129+ case Update.StateAutomaticDownloadPaused:
130+ case Update.StateInstallPaused:
131+ return i18n.tr("Resume");
132+
133+ case Update.StateDownloading:
134+ case Update.StateDownloadingAutomatically:
135+ case Update.StateInstalling:
136+ case Update.StateInstallingAutomatically:
137+ case Update.StateInstallFinished:
138+ return i18n.tr("Pause");
139+
140+ case Update.StateDownloaded:
141+ if (kind === Update.KindImage) {
142+ return i18n.tr("Install…");
143+ } else {
144+ return i18n.tr("Install");
145+ }
146+
147+ case Update.StateInstalled:
148+ return i18n.tr("Open");
149+
150+ default:
151+ console.error("Unknown update state", updateState);
152+ }
153+ }
154+
155+ onClicked: {
156+ switch (updateState) {
157+
158+ // Retries.
159+ case Update.StateUnknown:
160+ case Update.StateUnavailable:
161+ case Update.StateFailed:
162+ update.retry();
163+ break;
164+
165+ case Update.StateDownloadPaused:
166+ case Update.StateAutomaticDownloadPaused:
167+ case Update.StateInstallPaused:
168+ update.resume();
169+ break;
170+
171+ case Update.StateAvailable:
172+ if (kind === Update.KindClick) {
173+ update.install();
174+ } else {
175+ update.download();
176+ }
177+ break;
178+
179+ case Update.StateDownloaded:
180+ update.install();
181+ break;
182+
183+ case Update.StateDownloading:
184+ case Update.StateDownloadingAutomatically:
185+ case Update.StateInstalling:
186+ case Update.StateInstallingAutomatically:
187+ update.pause();
188+ break;
189+
190+ case Update.StateInstalled:
191+ update.launch();
192+ break;
193+ }
194+ }
195+ } // Button
196+ } // Name/button RowLayout
197+
198+ RowLayout {
199+ spacing: units.gu(2)
200+
201+ Label {
202+ id: downloadLabel
203+ objectName: "updateDownloadLabel"
204+
205+ Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
206+
207+ visible: text !== ""
208+
209+ fontSize: "small"
210+ text: {
211+ switch (updateState) {
212+
213+ case Update.StateInstalling:
214+ case Update.StateInstallingAutomatically:
215+ case Update.StateInstallPaused:
216+ return i18n.tr("Installing");
217+
218+ case Update.StateInstallPaused:
219+ case Update.StateDownloadPaused:
220+ return i18n.tr("Paused");
221+
222+ case Update.StateQueuedForDownload:
223+ return i18n.tr("Waiting to download");
224+
225+ case Update.StateDownloading:
226+ return i18n.tr("Downloading");
227+
228+ default:
229+ return "";
230+ }
231+ }
232+ }
233+
234+ Label {
235+ id: statusLabel
236+ objectName: "updateStatusLabel"
237+
238+ visible: text !== ""
239+ Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
240+ Layout.fillWidth: true
241+
242+ horizontalAlignment: Text.AlignRight
243+ fontSize: "small"
244+
245+ text: {
246+
247+ function humanFileSize(bytes, si) {
248+ var thresh = si ? 1000 : 1024;
249+ if(Math.abs(bytes) < thresh) {
250+ return bytes + ' B';
251+ }
252+ var units = si
253+ ? ['kB','MB','GB','TB','PB','EB','ZB','YB']
254+ : ['KiB','MiB','GiB','TiB','PiB','EiB','ZiB','YiB'];
255+ var u = -1;
256+ do {
257+ bytes /= thresh;
258+ ++u;
259+ } while(Math.abs(bytes) >= thresh && u < units.length - 1);
260+ return bytes.toFixed(1)+' '+units[u];
261+ }
262+
263+ switch (updateState) {
264+ case Update.StateAvailable:
265+ return humanFileSize(size, 1000);
266+
267+ case Update.StateDownloading:
268+ case Update.StateDownloadingAutomatically:
269+ case Update.StateDownloadPaused:
270+ case Update.StateAutomaticDownloadPaused:
271+ var down = humanFileSize((size / 100) * progress, 1000);
272+ var left = humanFileSize(size, 1000);
273+ if (progress > 100) {
274+ return left;
275+ } else {
276+ /* TRANSLATORS: %1 is the human readable amount
277+ of bytes downloaded, and %2 is the total to be
278+ downloaded. */
279+ return i18n.tr("%1 of %2").arg(down).arg(left);
280+ }
281+
282+ case Update.StateDownloaded:
283+ return i18n.tr("Downloaded");
284+
285+ case Update.StateInstallFinished:
286+ return i18n.tr("Installed");
287+
288+ case Update.StateInstalled:
289+ /* TRANSLATORS: %1 is the date at which this
290+ update was applied. */
291+ return i18n.tr("Updated %1").arg(
292+ updatedAt.toLocaleDateString(Qt.locale(), "d MMMM")
293+ );
294+ default:
295+ return "";
296+ }
297+ }
298+
299+ /* Seems AlignRight causes a rendering issue that can be
300+ fixed by doing an explicit doLayout. */
301+ Component.onCompleted: doLayout()
302+ }
303+ }
304+
305+ Column {
306+ id: error
307+ objectName: "updateError"
308+ spacing: units.gu(1)
309+ height: childrenRect.height
310+ Layout.fillWidth: true
311+ visible: errorElementDetail.text
312+
313+ Label {
314+ id: errorElementTitle
315+ text: i18n.tr("Update failed")
316+ color: UbuntuColors.red
317+ }
318+
319+ Label {
320+ id: errorElementDetail
321+ anchors { left: parent.left; right: parent.right }
322+ fontSize: "small"
323+ wrapMode: Text.WrapAnywhere
324+ }
325+ } // Error column
326+
327+ ProgressBar {
328+ id: progressBar
329+ objectName: "updateProgressbar"
330+
331+ visible: {
332+ switch (updateState) {
333+ case Update.StateQueuedForDownload:
334+ case Update.StateDownloading:
335+ case Update.StateDownloadPaused:
336+ case Update.StateInstalling:
337+ case Update.StateInstallPaused:
338+ return true;
339+
340+ default:
341+ return false;
342+ }
343+ }
344+ Layout.maximumHeight: units.gu(0.5)
345+ Layout.fillWidth: true
346+ indeterminate: update.progress < 0 || update.progress > 100
347+ minimumValue: 0
348+ maximumValue: 100
349+ showProgressPercentage: false
350+
351+ Behavior on value {
352+ animation: UbuntuNumberAnimation {}
353+ }
354+ } // Progress bar
355+ } // Layout for the rest of the stuff
356+
357+ Item {
358+ SlotsLayout.position: SlotsLayout.Leading;
359+ width: units.gu(4)
360+ height: width
361+
362+ Image {
363+ id: icon
364+ visible: kind === Update.KindImage && !fallback.visible
365+ anchors.fill: parent
366+ asynchronous: true
367+ smooth: true
368+ mipmap: true
369+ }
370+
371+ UbuntuShape {
372+ id: shape
373+ visible: kind !== Update.KindImage && !fallback.visible
374+ anchors.fill: parent
375+ source: icon
376+ }
377+
378+ Image {
379+ id: fallback
380+ visible: icon.status === Image.Error
381+ source : Qt.resolvedUrl("/usr/share/icons/suru/apps/scalable/ubuntu-logo-symbolic.svg")
382+ anchors.fill: parent
383+ asynchronous: true
384+ smooth: true
385+ mipmap: true
386+ }
387+ }
388+ }
389+}
qml/Wizard/Pages/passcode-desktop.qml+14−5
@@ -29,10 +29,17 @@ LocalComponents.Page {
2929 id: passwdSetPage
3030 objectName: "passcodeDesktopPage"
3131 title: i18n.tr("Lock Screen Passcode")
32+ focusItem: passwordField
3233 forwardButtonSourceComponent: forwardButton
3334
3435 readonly property alias password: passwordField.text
3536 readonly property alias password2: password2Field.text
37+ readonly property bool passwordsMatching: password != "" && password == password2
38+
39+ function savePasswordAndGoNext() {
40+ root.password = password;
41+ pageStack.next();
42+ }
3643
3744 Flickable {
3845 id: column
@@ -105,6 +112,11 @@ LocalComponents.Page {
105112 inputMethodHints: Qt.ImhDigitsOnly
106113 validator: RegExpValidator { regExp: /^\d{4}$/ }
107114 maximumLength: 4
115+ onAccepted: {
116+ if (passwordsMatching) {
117+ savePasswordAndGoNext();
118+ }
119+ }
108120 onActiveFocusChanged: {
109121 if (activeFocus) {
110122 column.contentY = y
@@ -140,11 +152,8 @@ LocalComponents.Page {
140152 id: forwardButton
141153 LocalComponents.StackButton {
142154 text: i18n.tr("Next")
143− enabled: password != "" && password == password2
144− onClicked: {
145− root.password = password;
146− pageStack.next();
147− }
155+ enabled: passwordsMatching
156+ onClicked: savePasswordAndGoNext()
148157 }
149158 }
150159}
qml/Wizard/Pages/password-set.qml+12−4
@@ -29,12 +29,18 @@ LocalComponents.Page {
2929 id: passwdSetPage
3030 objectName: "passwdSetPage"
3131 title: i18n.tr("Lock Screen Password")
32+ focusItem: passwordField
3233 forwardButtonSourceComponent: forwardButton
3334
3435 readonly property alias password: passwordField.text
3536 readonly property alias password2: password2Field.text
3637 readonly property bool passwordsMatching: password == password2 && password.trim().length > 7
3738
39+ function savePasswordAndGoNext() {
40+ root.password = password;
41+ pageStack.next();
42+ }
43+
3844 Flickable {
3945 id: column
4046 clip: true
@@ -114,6 +120,11 @@ LocalComponents.Page {
114120 id: password2Field
115121 objectName: "password2Field"
116122 echoMode: TextInput.Password
123+ onAccepted: {
124+ if (passwordsMatching) {
125+ savePasswordAndGoNext();
126+ }
127+ }
117128 onActiveFocusChanged: {
118129 if (activeFocus) {
119130 column.contentY = pass2Label.y
@@ -141,10 +152,7 @@ LocalComponents.Page {
141152 LocalComponents.StackButton {
142153 text: i18n.tr("Next")
143154 enabled: passwordsMatching
144− onClicked: {
145− root.password = password;
146− pageStack.next();
147− }
155+ onClicked: savePasswordAndGoNext()
148156 }
149157 }
150158}
qml/Wizard/Wizard.qml+5−2
@@ -1,4 +1,5 @@
11/*
2+ * Copyright (C) 2018 The UBports project
23 * Copyright (C) 2013, 2015 Canonical, Ltd.
34 *
45 * This program is free software; you can redistribute it and/or modify
@@ -20,7 +21,7 @@ import Wizard 0.1
2021import "../Components"
2122
2223Showable {
23− id: root
24+ id: wizard
2425
2526 // This is a bool instead of an alias because Loader classes like to emit
2627 // changed signals for 'active' during startup even if they aren't actually
@@ -29,6 +30,8 @@ Showable {
2930 // expected behavior of no emission on startup.
3031 readonly property bool active: loader.active
3132
33+ property bool isUpdate: System.isUpdate
34+
3235 // The wizard should be run at a later time if, for example, unity8 is
3336 // in greeter mode
3437 property bool deferred: false
@@ -49,7 +52,7 @@ Showable {
4952
5053 Connections {
5154 target: loader.item
52− onQuit: root.hide()
55+ onQuit: wizard.hide()
5356 }
5457 }
5558}
tests/qmltests/Wizard/tst_Wizard.qml+4−13
@@ -168,16 +168,13 @@ Item {
168168 return stack.currentPage;
169169 }
170170
171− function goToPage(name, skipSim, skipLocation, skipReporting) {
171+ function goToPage(name, skipSim, skipLocation) {
172172 if (skipSim === undefined) {
173173 skipSim = false;
174174 }
175175 if (skipLocation === undefined) {
176176 skipLocation = false;
177177 }
178− if (skipReporting === undefined) {
179− skipReporting = false;
180− }
181178
182179 var page = waitForPage("languagePage");
183180 if (name === page.objectName) return page;
@@ -222,12 +219,6 @@ Item {
222219 if (name === page.objectName) return page;
223220 tap(findChild(page, "forwardButton"));
224221
225− if (!skipReporting) {
226− page = waitForPage("reportingPage");
227− if (name === page.objectName) return page;
228− tap(findChild(page, "forwardButton"));
229− }
230−
231222 page = waitForPage("finishedPage");
232223 if (name === page.objectName) return page;
233224 waitUntilTransitionsEnd(page);
@@ -334,7 +325,7 @@ Item {
334325 enterPasscode("1111");
335326
336327 // now finish up
337− page = waitForPage("reportingPage");
328+ page = waitForPage("systemUpdatePage");
338329 tap(findChild(page, "forwardButton"));
339330 page = waitForPage("finishedPage");
340331 waitUntilTransitionsEnd(page);
@@ -374,7 +365,7 @@ Item {
374365 tap(continueButton);
375366
376367 // now finish up
377− page = waitForPage("reportingPage");
368+ page = waitForPage("systemUpdatePage");
378369 tap(findChild(page, "forwardButton"));
379370 page = waitForPage("finishedPage");
380371 waitUntilTransitionsEnd(page);
@@ -392,7 +383,7 @@ Item {
392383
393384 // now finish up
394385 tap(findChild(page, "forwardButton"));
395− page = waitForPage("reportingPage");
386+ page = waitForPage("systemUpdatePage");
396387 tap(findChild(page, "forwardButton"));
397388 page = waitForPage("finishedPage");
398389 waitUntilTransitionsEnd(page);