on xenial help sign in
Merge lp:~unity-team/unity8/side-stage-redesign
b379babMichał Sawicz
CMakeLists.txt+1
@@ -58,6 +58,7 @@ find_package(Qt5Concurrent 5.4 REQUIRED)
58find_package(Qt5Sql 5.4 REQUIRED)
58find_package(Qt5Sql 5.4 REQUIRED)
59
59
60pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=14)
60pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=14)
61+pkg_check_modules(GEONAMES REQUIRED geonames)
61pkg_check_modules(GIO REQUIRED gio-2.0>=2.32)
62pkg_check_modules(GIO REQUIRED gio-2.0>=2.32)
62pkg_check_modules(GLIB REQUIRED glib-2.0>=2.32)
63pkg_check_modules(GLIB REQUIRED glib-2.0>=2.32)
63pkg_check_modules(QMENUMODEL REQUIRED qmenumodel)
64pkg_check_modules(QMENUMODEL REQUIRED qmenumodel)
debian/changelog+6
@@ -1,3 +1,9 @@
1+unity8 (8.13+15.04.20150914-0ubuntu1) UNRELEASED; urgency=medium
2+
3+ * bump version to fix OOBE build
4+
5+ -- Lukas Tinkl <ltinkl@canonical.com> Mon, 14 Sep 2015 19:19:23 +0200
6+
1unity8 (8.11+16.04.20160310.4-0ubuntu1) xenial; urgency=medium
7unity8 (8.11+16.04.20160310.4-0ubuntu1) xenial; urgency=medium
2
8
3 [ Albert Astals Cid ]
9 [ Albert Astals Cid ]
debian/control+2−1
@@ -8,13 +8,14 @@ Build-Depends: cmake,
8 doxyqml,
8 doxyqml,
9# To allow cross-compiling to work, we also must append :native
9# To allow cross-compiling to work, we also must append :native
10# to g++ so we don't try to run armhf g++
10# to g++ so we don't try to run armhf g++
11−# on an x86 CPU for eaxmple, when cross-compiling.
11+# on an x86 CPU for example, when cross-compiling.
12 g++:native,
12 g++:native,
13 libandroid-properties-dev,
13 libandroid-properties-dev,
14 graphviz,
14 graphviz,
15 gsettings-ubuntu-schemas (>= 0.0.2+14.10.20140815),
15 gsettings-ubuntu-schemas (>= 0.0.2+14.10.20140815),
16 libconnectivity-qt1-dev (>= 0.7.1),
16 libconnectivity-qt1-dev (>= 0.7.1),
17 libevdev-dev,
17 libevdev-dev,
18+ libgeonames-dev (>= 0.2),
18 libgl1-mesa-dev[!armhf] | libgl-dev[!armhf],
19 libgl1-mesa-dev[!armhf] | libgl-dev[!armhf],
19 libgl1-mesa-dri,
20 libgl1-mesa-dri,
20 libgles2-mesa-dev[armhf],
21 libgles2-mesa-dev[armhf],
plugins/AccountsService/AccountsService.cpp+27−3
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2013 Canonical, Ltd.
2+ * Copyright (C) 2013, 2015 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
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
5 * it under the terms of the GNU General Public License as published by
@@ -12,8 +12,6 @@
12 *
12 *
13 * You should have received a copy of the GNU General Public License
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/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− * Author: Michael Terry <michael.terry@canonical.com>
17 */
15 */
18
16
19#include "AccountsService.h"
17#include "AccountsService.h"
@@ -34,6 +32,7 @@
34
32
35#define PROP_BACKGROUND_FILE QStringLiteral("BackgroundFile")
33#define PROP_BACKGROUND_FILE QStringLiteral("BackgroundFile")
36#define PROP_DEMO_EDGES QStringLiteral("demo-edges")
34#define PROP_DEMO_EDGES QStringLiteral("demo-edges")
35+#define PROP_EMAIL QStringLiteral("Email")
37#define PROP_ENABLE_INDICATORS_WHILE_LOCKED QStringLiteral("EnableIndicatorsWhileLocked")
36#define PROP_ENABLE_INDICATORS_WHILE_LOCKED QStringLiteral("EnableIndicatorsWhileLocked")
38#define PROP_ENABLE_LAUNCHER_WHILE_LOCKED QStringLiteral("EnableLauncherWhileLocked")
37#define PROP_ENABLE_LAUNCHER_WHILE_LOCKED QStringLiteral("EnableLauncherWhileLocked")
39#define PROP_FAILED_LOGINS QStringLiteral("FailedLogins")
38#define PROP_FAILED_LOGINS QStringLiteral("FailedLogins")
@@ -44,6 +43,7 @@
44#define PROP_MOUSE_PRIMARY_BUTTON QStringLiteral("MousePrimaryButton")
43#define PROP_MOUSE_PRIMARY_BUTTON QStringLiteral("MousePrimaryButton")
45#define PROP_MOUSE_SCROLL_SPEED QStringLiteral("MouseScrollSpeed")
44#define PROP_MOUSE_SCROLL_SPEED QStringLiteral("MouseScrollSpeed")
46#define PROP_PASSWORD_DISPLAY_HINT QStringLiteral("PasswordDisplayHint")
45#define PROP_PASSWORD_DISPLAY_HINT QStringLiteral("PasswordDisplayHint")
46+#define PROP_REAL_NAME QStringLiteral("RealName")
47#define PROP_STATS_WELCOME_SCREEN QStringLiteral("StatsWelcomeScreen")
47#define PROP_STATS_WELCOME_SCREEN QStringLiteral("StatsWelcomeScreen")
48#define PROP_TOUCHPAD_CURSOR_SPEED QStringLiteral("TouchpadCursorSpeed")
48#define PROP_TOUCHPAD_CURSOR_SPEED QStringLiteral("TouchpadCursorSpeed")
49#define PROP_TOUCHPAD_DISABLE_WHILE_TYPING QStringLiteral("TouchpadDisableWhileTyping")
49#define PROP_TOUCHPAD_DISABLE_WHILE_TYPING QStringLiteral("TouchpadDisableWhileTyping")
@@ -80,6 +80,8 @@ AccountsService::AccountsService(QObject* parent, const QString &user)
80 connect(m_service, &AccountsServiceDBusAdaptor::maybeChanged, this, &AccountsService::onMaybeChanged);
80 connect(m_service, &AccountsServiceDBusAdaptor::maybeChanged, this, &AccountsService::onMaybeChanged);
81
81
82 registerProperty(IFACE_ACCOUNTS_USER, PROP_BACKGROUND_FILE, QStringLiteral("backgroundFileChanged"));
82 registerProperty(IFACE_ACCOUNTS_USER, PROP_BACKGROUND_FILE, QStringLiteral("backgroundFileChanged"));
83+ registerProperty(IFACE_ACCOUNTS_USER, PROP_EMAIL, QStringLiteral("emailChanged"));
84+ registerProperty(IFACE_ACCOUNTS_USER, PROP_REAL_NAME, QStringLiteral("realNameChanged"));
83 registerProperty(IFACE_LOCATION_HERE, PROP_LICENSE_ACCEPTED, QStringLiteral("hereEnabledChanged"));
85 registerProperty(IFACE_LOCATION_HERE, PROP_LICENSE_ACCEPTED, QStringLiteral("hereEnabledChanged"));
84 registerProperty(IFACE_LOCATION_HERE, PROP_LICENSE_BASE_PATH, QStringLiteral("hereLicensePathChanged"));
86 registerProperty(IFACE_LOCATION_HERE, PROP_LICENSE_BASE_PATH, QStringLiteral("hereLicensePathChanged"));
85 registerProperty(IFACE_UBUNTU_SECURITY, PROP_ENABLE_LAUNCHER_WHILE_LOCKED, QStringLiteral("enableLauncherWhileLockedChanged"));
87 registerProperty(IFACE_UBUNTU_SECURITY, PROP_ENABLE_LAUNCHER_WHILE_LOCKED, QStringLiteral("enableLauncherWhileLockedChanged"));
@@ -206,6 +208,28 @@ bool AccountsService::hereLicensePathValid() const
206 return !value.toString().isNull();
208 return !value.toString().isNull();
207}
209}
208
210
211+QString AccountsService::realName() const
212+{
213+ auto value = getProperty(IFACE_ACCOUNTS_USER, PROP_REAL_NAME);
214+ return value.toString();
215+}
216+
217+void AccountsService::setRealName(const QString &realName)
218+{
219+ setProperty(IFACE_ACCOUNTS_USER, PROP_REAL_NAME, realName);
220+}
221+
222+QString AccountsService::email() const
223+{
224+ auto value = getProperty(IFACE_ACCOUNTS_USER, PROP_EMAIL);
225+ return value.toString();
226+}
227+
228+void AccountsService::setEmail(const QString &email)
229+{
230+ setProperty(IFACE_ACCOUNTS_USER, PROP_EMAIL, email);
231+}
232+
209uint AccountsService::failedLogins() const
233uint AccountsService::failedLogins() const
210{
234{
211 return getProperty(IFACE_UNITY_PRIVATE, PROP_FAILED_LOGINS).toUInt();
235 return getProperty(IFACE_UNITY_PRIVATE, PROP_FAILED_LOGINS).toUInt();
plugins/AccountsService/AccountsService.h+9−3
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2013 Canonical, Ltd.
2+ * Copyright (C) 2013, 2015 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
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
5 * it under the terms of the GNU General Public License as published by
@@ -12,8 +12,6 @@
12 *
12 *
13 * You should have received a copy of the GNU General Public License
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/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− * Authors: Michael Terry <michael.terry@canonical.com>
17 */
15 */
18
16
19#ifndef UNITY_ACCOUNTSSERVICE_H
17#ifndef UNITY_ACCOUNTSSERVICE_H
@@ -68,6 +66,8 @@ class AccountsService: public QObject
68 Q_PROPERTY(bool hereLicensePathValid // qml sees a null string as "", so we use proxy setting for that
66 Q_PROPERTY(bool hereLicensePathValid // qml sees a null string as "", so we use proxy setting for that
69 READ hereLicensePathValid
67 READ hereLicensePathValid
70 NOTIFY hereLicensePathChanged)
68 NOTIFY hereLicensePathChanged)
69+ Q_PROPERTY(QString realName READ realName WRITE setRealName NOTIFY realNameChanged)
70+ Q_PROPERTY(QString email READ email WRITE setEmail NOTIFY emailChanged)
71
71
72public:
72public:
73 enum PasswordDisplayHint {
73 enum PasswordDisplayHint {
@@ -93,6 +93,10 @@ public:
93 void setHereEnabled(bool enabled);
93 void setHereEnabled(bool enabled);
94 QString hereLicensePath() const;
94 QString hereLicensePath() const;
95 bool hereLicensePathValid() const;
95 bool hereLicensePathValid() const;
96+ QString realName() const;
97+ void setRealName(const QString &realName);
98+ QString email() const;
99+ void setEmail(const QString &email);
96
100
97Q_SIGNALS:
101Q_SIGNALS:
98 void userChanged();
102 void userChanged();
@@ -105,6 +109,8 @@ Q_SIGNALS:
105 void failedLoginsChanged();
109 void failedLoginsChanged();
106 void hereEnabledChanged();
110 void hereEnabledChanged();
107 void hereLicensePathChanged();
111 void hereLicensePathChanged();
112+ void realNameChanged();
113+ void emailChanged();
108
114
109private Q_SLOTS:
115private Q_SLOTS:
110 void onPropertiesChanged(const QString &user, const QString &interface, const QStringList &changed);
116 void onPropertiesChanged(const QString &user, const QString &interface, const QStringList &changed);
plugins/Utils/timezoneFormatter.cpp+10
@@ -33,3 +33,13 @@ QString TimezoneFormatter::currentTimeInTimezone(const QVariant &tzId) const
33 }
33 }
34 return QString();
34 return QString();
35}
35}
36+
37+QString TimezoneFormatter::currentTimeInTimezoneWithAbbrev(const QVariant &tzId) const
38+{
39+ QTimeZone tz(tzId.toByteArray());
40+ if (tz.isValid()) {
41+ const QDateTime now = QDateTime::currentDateTime().toTimeZone(tz);
42+ return QStringLiteral("%1 %2").arg(now.time().toString(QStringLiteral("h:mm"))).arg(tz.abbreviation(now));
43+ }
44+ return QString();
45+}
plugins/Utils/timezoneFormatter.h+1
@@ -27,6 +27,7 @@ public:
27 ~TimezoneFormatter() = default;
27 ~TimezoneFormatter() = default;
28
28
29 Q_INVOKABLE QString currentTimeInTimezone(const QVariant &tzId) const;
29 Q_INVOKABLE QString currentTimeInTimezone(const QVariant &tzId) const;
30+ Q_INVOKABLE QString currentTimeInTimezoneWithAbbrev(const QVariant &tzId) const;
30};
31};
31
32
32#endif
33#endif
plugins/Wizard/CMakeLists.txt+7−1
@@ -1,10 +1,16 @@
1+include_directories(${GLIB_INCLUDE_DIRS} ${GEONAMES_INCLUDE_DIRS})
2+
1add_library(Wizard-qml MODULE
3add_library(Wizard-qml MODULE
2 plugin.cpp
4 plugin.cpp
3 PageList.cpp
5 PageList.cpp
4 System.cpp
6 System.cpp
7+ LocalePlugin.cpp
8+ timezonemodel.cpp
9+ Status.cpp
5)
10)
6
11
7−qt5_use_modules(Wizard-qml DBus Qml)
12+qt5_use_modules(Wizard-qml DBus Qml Concurrent)
13+target_link_libraries(Wizard-qml ${GLIB_LDFLAGS} ${GEONAMES_LDFLAGS})
8add_unity8_plugin(Wizard 0.1 Wizard TARGETS Wizard-qml)
14add_unity8_plugin(Wizard 0.1 Wizard TARGETS Wizard-qml)
9
15
10set(POLKIT_LIB_DIR "${CMAKE_INSTALL_LOCALSTATEDIR}/lib/polkit-1")
16set(POLKIT_LIB_DIR "${CMAKE_INSTALL_LOCALSTATEDIR}/lib/polkit-1")
plugins/Wizard/LocalePlugin.cppnew file+291
@@ -0,0 +1,291 @@
1+/*
2+ * Copyright (C) 2015 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU General Public License version 3, as published
6+ * by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranties of
10+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11+ * PURPOSE. See the GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License along
14+ * with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include <QLocale>
18+#include <QStringList>
19+
20+#include <libintl.h>
21+
22+#include "LocalePlugin.h"
23+
24+class LocalePrivate {
25+public:
26+ LocalePrivate() {
27+ m_mccCodes = QHash<int, QString>
28+ ({{202,"gr"},
29+ {204,"nl"},
30+ {206,"be"},
31+ {208,"fr"},
32+ {212,"mc"},
33+ {213,"ad"},
34+ {214,"es"},
35+ {216,"hu"},
36+ {218,"ba"},
37+ {219,"hr"},
38+ {220,"rs"},
39+ {222,"it"},
40+ {226,"ro"},
41+ {228,"ch"},
42+ {230,"cz"},
43+ {231,"sk"},
44+ {232,"at"},
45+ {234,"gb"},
46+ {235,"gb"},
47+ {238,"dk"},
48+ {240,"se"},
49+ {242,"no"},
50+ {244,"fi"},
51+ {246,"lt"},
52+ {247,"lv"},
53+ {248,"ee"},
54+ {250,"ru"},
55+ {255,"ua"},
56+ {257,"by"},
57+ {259,"md"},
58+ {260,"pl"},
59+ {262,"de"},
60+ {266,"gi"},
61+ {268,"pt"},
62+ {270,"lu"},
63+ {272,"ie"},
64+ {274,"is"},
65+ {276,"al"},
66+ {278,"mt"},
67+ {280,"cy"},
68+ {282,"ge"},
69+ {283,"am"},
70+ {284,"bg"},
71+ {286,"tr"},
72+ {288,"fo"},
73+ {289,"ge"},
74+ {290,"gl"},
75+ {292,"sm"},
76+ {293,"si"},
77+ {294,"mk"},
78+ {295,"li"},
79+ {297,"me"},
80+ {302,"ca"},
81+ {308,"pm"},
82+ {310,"gu"},
83+ {310,"us"},
84+ {311,"gu"},
85+ {311,"us"},
86+ {312,"us"},
87+ {316,"us"},
88+ {330,"pr"},
89+ {334,"mx"},
90+ {338,"jm"},
91+ {340,"fg"},
92+ {340,"gp"},
93+ {340,"mq"},
94+ {342,"bb"},
95+ {344,"ag"},
96+ {346,"ky"},
97+ {348,"vg"},
98+ {350,"bm"},
99+ {352,"gd"},
100+ {354,"ms"},
101+ {356,"kn"},
102+ {358,"lc"},
103+ {360,"vc"},
104+ {362,"an"},
105+ {362,"cw"},
106+ {363,"aw"},
107+ {364,"bs"},
108+ {365,"ai"},
109+ {366,"dm"},
110+ {368,"cu"},
111+ {370,"do"},
112+ {372,"ht"},
113+ {374,"tt"},
114+ {376,"tc"},
115+ {376,"vi"},
116+ {400,"az"},
117+ {401,"kz"},
118+ {402,"bt"},
119+ {404,"in"},
120+ {405,"in"},
121+ {410,"pk"},
122+ {412,"af"},
123+ {413,"lk"},
124+ {414,"mm"},
125+ {415,"lb"},
126+ {416,"jo"},
127+ {417,"sy"},
128+ {418,"iq"},
129+ {419,"kw"},
130+ {420,"sa"},
131+ {421,"ye"},
132+ {422,"om"},
133+ {424,"ae"},
134+ {425,"il"},
135+ {425,"ps"},
136+ {426,"bh"},
137+ {427,"qa"},
138+ {428,"mn"},
139+ {429,"np"},
140+ {430,"ae"},
141+ {431,"ae"},
142+ {432,"ir"},
143+ {434,"uz"},
144+ {436,"tk"},
145+ {437,"kg"},
146+ {438,"tm"},
147+ {440,"jp"},
148+ {441,"jp"},
149+ {450,"kr"},
150+ {452,"vn"},
151+ {454,"hk"},
152+ {455,"mo"},
153+ {456,"kh"},
154+ {457,"la"},
155+ {460,"cn"},
156+ {466,"tw"},
157+ {467,"kp"},
158+ {470,"bd"},
159+ {472,"mv"},
160+ {502,"my"},
161+ {505,"au"},
162+ {510,"id"},
163+ {514,"tp"},
164+ {515,"ph"},
165+ {520,"th"},
166+ {525,"sg"},
167+ {528,"bn"},
168+ {530,"nz"},
169+ {537,"pg"},
170+ {539,"to"},
171+ {540,"sb"},
172+ {541,"vu"},
173+ {542,"fj"},
174+ {544,"as"},
175+ {545,"ki"},
176+ {546,"nc"},
177+ {547,"pf"},
178+ {548,"ck"},
179+ {549,"ws"},
180+ {550,"fm"},
181+ {552,"pw"},
182+ {553,"tv"},
183+ {555,"nu"},
184+ {602,"eg"},
185+ {603,"dz"},
186+ {604,"ma"},
187+ {605,"tn"},
188+ {606,"ly"},
189+ {607,"gm"},
190+ {608,"sn"},
191+ {609,"mr"},
192+ {610,"ml"},
193+ {611,"gn"},
194+ {612,"ci"},
195+ {613,"bf"},
196+ {614,"ne"},
197+ {615,"tg"},
198+ {616,"bj"},
199+ {617,"mu"},
200+ {618,"lr"},
201+ {619,"sl"},
202+ {620,"gh"},
203+ {621,"ng"},
204+ {622,"td"},
205+ {623,"cf"},
206+ {624,"cm"},
207+ {625,"cv"},
208+ {626,"st"},
209+ {627,"gq"},
210+ {628,"ga"},
211+ {629,"cg"},
212+ {630,"cd"},
213+ {631,"ao"},
214+ {632,"gw"},
215+ {633,"sc"},
216+ {634,"sd"},
217+ {635,"rw"},
218+ {636,"et"},
219+ {637,"so"},
220+ {638,"dj"},
221+ {639,"ke"},
222+ {640,"tz"},
223+ {641,"ug"},
224+ {642,"bi"},
225+ {643,"mz"},
226+ {645,"zm"},
227+ {646,"mg"},
228+ {647,"re"},
229+ {648,"zw"},
230+ {649,"na"},
231+ {650,"mw"},
232+ {651,"ls"},
233+ {652,"bw"},
234+ {653,"sz"},
235+ {654,"km"},
236+ {655,"za"},
237+ {657,"er"},
238+ {659,"ss"},
239+ {702,"bz"},
240+ {704,"gt"},
241+ {706,"sv"},
242+ {708,"hn"},
243+ {710,"ni"},
244+ {712,"cr"},
245+ {714,"pa"},
246+ {716,"pe"},
247+ {722,"ar"},
248+ {724,"br"},
249+ {730,"cl"},
250+ {732,"co"},
251+ {734,"ve"},
252+ {736,"bo"},
253+ {738,"gy"},
254+ {740,"ec"},
255+ {744,"py"},
256+ {746,"sr"},
257+ {748,"uy"},
258+ {750,"fk"}}
259+ );
260+ }
261+
262+ QString mccToCountryCode(int mcc) const {
263+ return m_mccCodes.value(mcc, "us").toUpper();
264+ }
265+
266+private:
267+ // MCC = Mobile Country Code, see https://en.wikipedia.org/wiki/Mobile_country_code
268+ QHash<int,QString> m_mccCodes;
269+};
270+
271+Q_GLOBAL_STATIC(LocalePrivate, d)
272+
273+LocaleAttached::LocaleAttached(QObject* parent)
274+ : QObject(parent)
275+{
276+}
277+
278+QString LocaleAttached::mccToCountryCode(int mcc) const
279+{
280+ return d->mccToCountryCode(mcc);
281+}
282+
283+LocalePlugin::LocalePlugin(QObject* parent)
284+ : QObject(parent)
285+{
286+}
287+
288+LocaleAttached* LocalePlugin::qmlAttachedProperties(QObject* parent)
289+{
290+ return new LocaleAttached(parent);
291+}
plugins/Wizard/LocalePlugin.hnew file+58
@@ -0,0 +1,58 @@
1+/*
2+ * Copyright (C) 2015 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU General Public License version 3, as published
6+ * by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranties of
10+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11+ * PURPOSE. See the GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License along
14+ * with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef LOCALE_PLUGIN_H
18+#define LOCALE_PLUGIN_H
19+
20+#include <QObject>
21+#include <QString>
22+#include <QJsonObject>
23+#include <QtQml>
24+
25+class LocaleAttached: public QObject
26+{
27+ Q_OBJECT
28+protected:
29+ explicit LocaleAttached(QObject *parent = 0);
30+
31+public:
32+ Q_INVOKABLE QString mccToCountryCode(int mcc) const;
33+
34+ friend class LocalePlugin;
35+};
36+
37+/**
38+ * A simplified wrapper around QLocale.
39+ *
40+ * The wrapper is implemented as an attached property, which makes it possible
41+ * to use it as if its methods were static:
42+ *
43+ * @code
44+ * var langs = LocalePlugin.languages();
45+ * @endcode
46+ */
47+class LocalePlugin: public QObject
48+{
49+ Q_OBJECT
50+public:
51+ explicit LocalePlugin(QObject *parent = 0);
52+
53+ static LocaleAttached* qmlAttachedProperties(QObject *parent);
54+};
55+
56+QML_DECLARE_TYPEINFO(LocalePlugin, QML_HAS_ATTACHED_PROPERTIES)
57+
58+#endif // LOCALE_PLUGIN_H
plugins/Wizard/PageList.cpp+4−4
@@ -40,20 +40,20 @@ PageList::PageList(QObject *parent)
40 m_index(-1),
40 m_index(-1),
41 m_pages()
41 m_pages()
42{
42{
43− QString qmlSuffix = QStringLiteral(".qml");
43+ const QString qmlSuffix = QStringLiteral(".qml");
44− QString disabledSuffix = QStringLiteral(".disabled");
44+ const QString disabledSuffix = QStringLiteral(".disabled");
45 QSet<QString> disabledPages;
45 QSet<QString> disabledPages;
46 QStringList dataDirs;
46 QStringList dataDirs;
47
47
48 if (!isRunningInstalled() && getenv("WIZARD_TESTING") == nullptr) {
48 if (!isRunningInstalled() && getenv("WIZARD_TESTING") == nullptr) {
49− dataDirs = QStringList() << qmlDirectory();
49+ dataDirs << qmlDirectory();
50 } else {
50 } else {
51 dataDirs = shellDataDirs();
51 dataDirs = shellDataDirs();
52 }
52 }
53
53
54 Q_FOREACH(const QString &dataDir, dataDirs) {
54 Q_FOREACH(const QString &dataDir, dataDirs) {
55 QDir dir(dataDir + "/Wizard/Pages");
55 QDir dir(dataDir + "/Wizard/Pages");
56− QStringList entries = dir.entryList(QStringList(QStringLiteral("[0-9]*")), QDir::Files | QDir::Readable);
56+ const QStringList entries = dir.entryList(QStringList(QStringLiteral("[0-9]*")), QDir::Files | QDir::Readable);
57 Q_FOREACH(const QString &entry, entries) {
57 Q_FOREACH(const QString &entry, entries) {
58 if (!m_pages.contains(entry) && entry.endsWith(qmlSuffix))
58 if (!m_pages.contains(entry) && entry.endsWith(qmlSuffix))
59 m_pages.insert(entry, dir.absoluteFilePath(entry));
59 m_pages.insert(entry, dir.absoluteFilePath(entry));
plugins/Wizard/Status.cppnew file+143
@@ -0,0 +1,143 @@
1+/*
2+ * Copyright (C) 2015 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU General Public License version 3, as published
6+ * by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranties of
10+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11+ * PURPOSE. See the GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License along
14+ * with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include <QDebug>
18+#include <QDBusConnection>
19+
20+#include "Status.h"
21+
22+Status::Status()
23+{
24+ initNM();
25+ initUPower();
26+}
27+
28+void Status::initNM()
29+{
30+ m_nmIface = new QDBusInterface("org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager", "org.freedesktop.NetworkManager",
31+ QDBusConnection::systemBus(), this);
32+
33+ QDBusConnection::systemBus().connect("org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager", "org.freedesktop.NetworkManager", "PropertiesChanged",
34+ this, SLOT(onNMPropertiesChanged(QVariantMap)));
35+}
36+
37+void Status::onNMPropertiesChanged(const QVariantMap &changedProps)
38+{
39+ if (changedProps.contains("State") || changedProps.contains("Connectivity")) {
40+ Q_EMIT onlineChanged();
41+ Q_EMIT networkIconChanged();
42+ }
43+
44+ if (changedProps.contains("PrimaryConnection") || changedProps.contains("SpecificObject") || changedProps.contains("Strength")) {
45+ Q_EMIT networkIconChanged();
46+ }
47+}
48+
49+bool Status::online() const
50+{
51+ if (!m_nmIface->isValid())
52+ return false;
53+
54+ return m_nmIface->property("State").toUInt() == 70;
55+}
56+
57+QString Status::networkIcon()
58+{
59+ QString iconName = QStringLiteral("nm-no-connection");
60+
61+ if (!online()) {
62+ return iconName;
63+ }
64+
65+ const QString primaryConn = m_nmIface->property("PrimaryConnection").value<QDBusObjectPath>().path();
66+ const QString primaryConnType = m_nmIface->property("PrimaryConnectionType").toString();
67+
68+ if (primaryConn.isEmpty()) {
69+ qWarning() << "Empty primary connection";
70+ return iconName;
71+ }
72+
73+ if (primaryConnType == "802-11-wireless") {
74+ QDBusInterface activeConn("org.freedesktop.NetworkManager", primaryConn, "org.freedesktop.NetworkManager.Connection.Active", QDBusConnection::systemBus());
75+
76+ if (activeConn.isValid()) {
77+ const QString apPath = activeConn.property("SpecificObject").value<QDBusObjectPath>().path();
78+
79+ if (apPath.isEmpty()) {
80+ qWarning() << "No AP path";
81+ return iconName;
82+ }
83+
84+ QDBusConnection::systemBus().connect("org.freedesktop.NetworkManager", primaryConn, "org.freedesktop.NetworkManager.Connection.Active", "PropertiesChanged",
85+ this, SLOT(onNMPropertiesChanged(QVariantMap)));
86+
87+ QDBusInterface ap("org.freedesktop.NetworkManager", apPath, "org.freedesktop.NetworkManager.AccessPoint", QDBusConnection::systemBus());
88+
89+ if (!ap.isValid()) {
90+ qWarning() << "Invalid AP";
91+ return iconName;
92+ }
93+
94+ QDBusConnection::systemBus().connect("org.freedesktop.NetworkManager", apPath, "org.freedesktop.NetworkManager.AccessPoint", "PropertiesChanged",
95+ this, SLOT(onNMPropertiesChanged(QVariantMap)));
96+
97+ const uint strength = ap.property("Strength").toUInt();
98+ const uint flags = ap.property("Flags").toUInt();
99+
100+ if (strength == 0) {
101+ iconName = "nm-signal-00";
102+ } else if (strength <= 25) {
103+ iconName = "nm-signal-25";
104+ } else if (strength <= 50) {
105+ iconName = "nm-signal-50";
106+ } else if (strength <= 75) {
107+ iconName = "nm-signal-75";
108+ } else if (strength <= 100) {
109+ iconName = "nm-signal-100";
110+ }
111+
112+ if (flags >= 1) {
113+ iconName += "-secure";
114+ }
115+ }
116+ }
117+
118+ return iconName;
119+}
120+
121+void Status::initUPower()
122+{
123+ m_upowerIface = new QDBusInterface("org.freedesktop.UPower", "/org/freedesktop/UPower/devices/DisplayDevice", "org.freedesktop.UPower.Device",
124+ QDBusConnection::systemBus(), this);
125+ QDBusConnection::systemBus().connect("org.freedesktop.UPower", "/org/freedesktop/UPower/devices/DisplayDevice", "org.freedesktop.DBus.Properties",
126+ "PropertiesChanged", this, SLOT(onUPowerPropertiesChanged(QString,QVariantMap,QStringList)));
127+}
128+
129+void Status::onUPowerPropertiesChanged(const QString &iface, const QVariantMap &changedProps, const QStringList &invalidatedProps)
130+{
131+ Q_UNUSED(iface)
132+ Q_UNUSED(invalidatedProps)
133+
134+ if (changedProps.contains("IconName")) {
135+ Q_EMIT batteryIconChanged();
136+ }
137+}
138+
139+QString Status::batteryIcon() const
140+{
141+ const QString iconName = m_upowerIface->property("IconName").toString();
142+ return iconName;
143+}
plugins/Wizard/Status.hnew file+60
@@ -0,0 +1,60 @@
1+/*
2+ * Copyright (C) 2015 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU General Public License version 3, as published
6+ * by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranties of
10+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11+ * PURPOSE. See the GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License along
14+ * with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef WIZARD_STATUS_H
18+#define WIZARD_STATUS_H
19+
20+#include <QObject>
21+#include <QString>
22+#include <QDBusInterface>
23+
24+class Status: public QObject
25+{
26+ Q_OBJECT
27+ Q_PROPERTY(bool online READ online NOTIFY onlineChanged)
28+ Q_PROPERTY(QString networkIcon READ networkIcon NOTIFY networkIconChanged)
29+ Q_PROPERTY(QString batteryIcon READ batteryIcon NOTIFY batteryIconChanged)
30+public:
31+ Status();
32+ ~Status() = default;
33+
34+ bool online() const;
35+ QString networkIcon();
36+
37+ QString batteryIcon() const;
38+
39+Q_SIGNALS:
40+ void networkIconChanged();
41+ void onlineChanged();
42+ void batteryIconChanged();
43+
44+private Q_SLOTS:
45+ void onNMPropertiesChanged(const QVariantMap &changedProps);
46+ void onUPowerPropertiesChanged(const QString &iface, const QVariantMap &changedProps, const QStringList &invalidatedProps);
47+
48+private:
49+ Q_DISABLE_COPY(Status)
50+
51+ // network status
52+ void initNM();
53+ QDBusInterface * m_nmIface = nullptr;
54+
55+ // battery status
56+ void initUPower();
57+ QDBusInterface * m_upowerIface = nullptr;
58+};
59+
60+#endif
plugins/Wizard/System.cpp+5−4
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2014 Canonical Ltd.
2+ * Copyright (C) 2014-2015 Canonical Ltd.
3 *
3 *
4 * This program is free software: you can redistribute it and/or modify it
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
5 * under the terms of the GNU General Public License version 3, as published
@@ -25,10 +25,10 @@
25#include <QLocale>
25#include <QLocale>
26#include <QMap>
26#include <QMap>
27#include <QProcess>
27#include <QProcess>
28+#include <QDebug>
28
29
29System::System()
30System::System()
30− : QObject(),
31+ : QObject()
31− m_fsWatcher()
32{
32{
33 // Register the argument needed for UpdateActivationEnvironment below
33 // Register the argument needed for UpdateActivationEnvironment below
34 qDBusRegisterMetaType<QMap<QString,QString>>();
34 qDBusRegisterMetaType<QMap<QString,QString>>();
@@ -88,7 +88,7 @@ void System::setSessionVariable(const QString &variable, const QString &value)
88 QDBusConnection::sessionBus().asyncCall(msg);
88 QDBusConnection::sessionBus().asyncCall(msg);
89}
89}
90
90
91−void System::updateSessionLanguage(const QString &locale)
91+void System::updateSessionLocale(const QString &locale)
92{
92{
93 const QString language = locale.split(QStringLiteral("."))[0];
93 const QString language = locale.split(QStringLiteral("."))[0];
94
94
@@ -106,5 +106,6 @@ void System::updateSessionLanguage(const QString &locale)
106 initctl stop smart-scopes-proxy; \
106 initctl stop smart-scopes-proxy; \
107 initctl emit --no-wait indicator-services-start; \
107 initctl emit --no-wait indicator-services-start; \
108 initctl restart --no-wait maliit-server; \
108 initctl restart --no-wait maliit-server; \
109+ initctl restart --no-wait indicator-messages; \
109 initctl restart --no-wait unity8-dash\""));
110 initctl restart --no-wait unity8-dash\""));
110}
111}
plugins/Wizard/System.h+3−2
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2014 Canonical Ltd.
2+ * Copyright (C) 2014-2015 Canonical Ltd.
3 *
3 *
4 * This program is free software: you can redistribute it and/or modify it
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
5 * under the terms of the GNU General Public License version 3, as published
@@ -28,12 +28,13 @@ class System : public QObject
28
28
29public:
29public:
30 System();
30 System();
31+ ~System() = default;
31
32
32 bool wizardEnabled() const;
33 bool wizardEnabled() const;
33 void setWizardEnabled(bool enabled);
34 void setWizardEnabled(bool enabled);
34
35
35public Q_SLOTS:
36public Q_SLOTS:
36− void updateSessionLanguage(const QString &locale);
37+ void updateSessionLocale(const QString &locale);
37
38
38Q_SIGNALS:
39Q_SIGNALS:
39 void wizardEnabledChanged();
40 void wizardEnabledChanged();
plugins/Wizard/plugin.cpp+7−8
@@ -17,19 +17,18 @@
17#include "plugin.h"
17#include "plugin.h"
18#include "PageList.h"
18#include "PageList.h"
19#include "System.h"
19#include "System.h"
20+#include "timezonemodel.h"
21+#include "LocalePlugin.h"
22+#include "Status.h"
20
23
21#include <QtQml/qqml.h>
24#include <QtQml/qqml.h>
22
25
23−static QObject *system_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
24−{
25− Q_UNUSED(engine)
26− Q_UNUSED(scriptEngine)
27− return new System();
28−}
29−
30void WizardPlugin::registerTypes(const char *uri)
26void WizardPlugin::registerTypes(const char *uri)
31{
27{
32 Q_ASSERT(uri == QLatin1String("Wizard"));
28 Q_ASSERT(uri == QLatin1String("Wizard"));
33 qmlRegisterType<PageList>(uri, 0, 1, "PageList");
29 qmlRegisterType<PageList>(uri, 0, 1, "PageList");
34− qmlRegisterSingletonType<System>(uri, 0, 1, "System", system_provider);
30+ qmlRegisterSingletonType<System>(uri, 0, 1, "System", [](QQmlEngine*, QJSEngine*) -> QObject* { return new System; });
31+ qmlRegisterSingletonType<Status>(uri, 0, 1, "Status", [](QQmlEngine*, QJSEngine*) -> QObject* { return new Status; });
32+ qmlRegisterType<TimeZoneLocationModel>(uri, 0, 1, "TimeZoneModel");
33+ qmlRegisterType<LocalePlugin>(uri, 0, 1, "LocalePlugin");
35}
34}
plugins/Wizard/plugin.h+1−2
@@ -17,13 +17,12 @@
17#ifndef WIZARD_PLUGIN_H
17#ifndef WIZARD_PLUGIN_H
18#define WIZARD_PLUGIN_H
18#define WIZARD_PLUGIN_H
19
19
20−#include <QtQml/QQmlEngine>
21#include <QtQml/QQmlExtensionPlugin>
20#include <QtQml/QQmlExtensionPlugin>
22
21
23class WizardPlugin : public QQmlExtensionPlugin
22class WizardPlugin : public QQmlExtensionPlugin
24{
23{
25 Q_OBJECT
24 Q_OBJECT
26− Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
25+ Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
27
26
28public:
27public:
29 void registerTypes(const char *uri) override;
28 void registerTypes(const char *uri) override;
plugins/Wizard/timezonemodel.cppnew file+239
@@ -0,0 +1,239 @@
1+/*
2+ * Copyright (C) 2016 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU General Public License version 3, as published
6+ * by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranties of
10+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11+ * PURPOSE. See the GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License along
14+ * with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include <QDebug>
18+
19+#include <glib.h>
20+#include <glib-object.h>
21+
22+#include "LocalePlugin.h"
23+#include "timezonemodel.h"
24+
25+TimeZoneLocationModel::TimeZoneLocationModel(QObject *parent):
26+ QAbstractListModel(parent),
27+ m_listUpdating(false),
28+ m_cancellable(nullptr)
29+{
30+ m_roleNames[Qt::DisplayRole] = "displayName";
31+ m_roleNames[TimeZoneRole] = "timeZone";
32+ m_roleNames[CityRole] = "city";
33+ m_roleNames[CountryRole] = "country";
34+ m_roleNames[OffsetRole] = "offset";
35+ m_roleNames[LatitudeRole] = "latitude";
36+ m_roleNames[LongitudeRole] = "longitude";
37+}
38+
39+int TimeZoneLocationModel::rowCount(const QModelIndex &parent) const
40+{
41+ if (parent.isValid()) {
42+ return 0;
43+ } else if (m_filter.isEmpty()) {
44+ return m_countryLocations.count();
45+ } else {
46+ return m_locations.count();
47+ }
48+}
49+
50+QVariant TimeZoneLocationModel::data(const QModelIndex &index, int role) const
51+{
52+ GeonamesCity *city;
53+ if (m_filter.isEmpty()) {
54+ city = m_countryLocations.value(index.row());
55+ } else {
56+ city = m_locations.value(index.row());
57+ }
58+ if (!city)
59+ return QVariant();
60+
61+ switch (role) {
62+ case Qt::DisplayRole:
63+ return QStringLiteral("%1, %2, %3").arg(geonames_city_get_name(city))
64+ .arg(geonames_city_get_state(city))
65+ .arg(geonames_city_get_country(city));
66+ case SimpleRole:
67+ return QStringLiteral("%1, %2").arg(geonames_city_get_name(city))
68+ .arg(geonames_city_get_country(city));
69+ case TimeZoneRole:
70+ return geonames_city_get_timezone(city);
71+ case CountryRole:
72+ return geonames_city_get_country(city);
73+ case CityRole:
74+ return geonames_city_get_name(city);
75+ case OffsetRole: {
76+ QTimeZone tmp(geonames_city_get_timezone(city));
77+ return static_cast<double>(tmp.standardTimeOffset(QDateTime::currentDateTime())) / 3600;
78+ }
79+ case LatitudeRole:
80+ return geonames_city_get_latitude(city);
81+ case LongitudeRole:
82+ return geonames_city_get_longitude(city);
83+ default:
84+ qWarning() << Q_FUNC_INFO << "Unknown role";
85+ return QVariant();
86+ }
87+}
88+
89+QHash<int, QByteArray> TimeZoneLocationModel::roleNames() const
90+{
91+ return m_roleNames;
92+}
93+
94+void TimeZoneLocationModel::setModel(const QList<GeonamesCity *> &locations)
95+{
96+ beginResetModel();
97+
98+ Q_FOREACH(GeonamesCity *city, m_locations) {
99+ geonames_city_free(city);
100+ }
101+
102+ m_locations = locations;
103+ endResetModel();
104+}
105+
106+void TimeZoneLocationModel::filterFinished(GObject *source_object,
107+ GAsyncResult *res,
108+ gpointer user_data)
109+{
110+ Q_UNUSED(source_object);
111+
112+ g_autofree gint *cities = nullptr;
113+ guint cities_len = 0;
114+ g_autoptr(GError) error = nullptr;
115+
116+ cities = geonames_query_cities_finish(res, &cities_len, &error);
117+ if (error) {
118+ if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
119+ TimeZoneLocationModel *model = static_cast<TimeZoneLocationModel *>(user_data);
120+ g_clear_object(&model->m_cancellable);
121+ model->setListUpdating(false);
122+ qWarning() << "Could not filter timezones:" << error->message;
123+ }
124+ return;
125+ }
126+
127+ QList<GeonamesCity *> locations;
128+
129+ for (guint i = 0; i < cities_len; ++i) {
130+ GeonamesCity *city = geonames_get_city(cities[i]);
131+ if (city) {
132+ locations.append(city);
133+ }
134+ }
135+
136+ TimeZoneLocationModel *model = static_cast<TimeZoneLocationModel *>(user_data);
137+
138+ g_clear_object(&model->m_cancellable);
139+
140+ model->setModel(locations);
141+ model->setListUpdating(false);
142+}
143+
144+bool TimeZoneLocationModel::listUpdating() const
145+{
146+ return m_listUpdating;
147+}
148+
149+void TimeZoneLocationModel::setListUpdating(bool listUpdating)
150+{
151+ if (m_listUpdating != listUpdating) {
152+ m_listUpdating = listUpdating;
153+ Q_EMIT listUpdatingChanged();
154+ }
155+}
156+
157+QString TimeZoneLocationModel::filter() const
158+{
159+ return m_filter;
160+}
161+
162+void TimeZoneLocationModel::setFilter(const QString &filter)
163+{
164+ if (filter != m_filter) {
165+ m_filter = filter;
166+ Q_EMIT filterChanged();
167+ }
168+
169+ setListUpdating(true);
170+
171+ if (m_cancellable) {
172+ g_cancellable_cancel(m_cancellable);
173+ g_clear_object(&m_cancellable);
174+ }
175+
176+ setModel(QList<GeonamesCity *>());
177+
178+ if (filter.isEmpty()) {
179+ setListUpdating(false);
180+ return;
181+ }
182+
183+ m_cancellable = g_cancellable_new();
184+ geonames_query_cities(filter.toUtf8().data(),
185+ GEONAMES_QUERY_DEFAULT,
186+ m_cancellable,
187+ filterFinished,
188+ this);
189+}
190+
191+QString TimeZoneLocationModel::country() const
192+{
193+ return m_country;
194+}
195+
196+static bool citycmp(GeonamesCity *a, GeonamesCity *b)
197+{
198+ return geonames_city_get_population(b) < geonames_city_get_population(a);
199+}
200+
201+void TimeZoneLocationModel::setCountry(const QString &country)
202+{
203+ if (m_country == country)
204+ return;
205+
206+ m_country = country;
207+
208+ Q_FOREACH(GeonamesCity *city, m_countryLocations) {
209+ geonames_city_free(city);
210+ }
211+
212+ gint num_cities = geonames_get_n_cities();
213+ for (gint i = 0; i < num_cities; i++) {
214+ GeonamesCity *city = geonames_get_city(i);
215+ if (city && m_country == geonames_city_get_country_code(city)) {
216+ m_countryLocations.append(city);
217+ }
218+ }
219+
220+ std::sort(m_countryLocations.begin(), m_countryLocations.end(), citycmp);
221+
222+ Q_EMIT countryChanged(country);
223+}
224+
225+TimeZoneLocationModel::~TimeZoneLocationModel()
226+{
227+ if (m_cancellable) {
228+ g_cancellable_cancel(m_cancellable);
229+ g_clear_object(&m_cancellable);
230+ }
231+
232+ Q_FOREACH(GeonamesCity *city, m_countryLocations) {
233+ geonames_city_free(city);
234+ }
235+
236+ Q_FOREACH(GeonamesCity *city, m_locations) {
237+ geonames_city_free(city);
238+ }
239+}
plugins/Wizard/timezonemodel.hnew file+80
@@ -0,0 +1,80 @@
1+/*
2+ * Copyright (C) 2016 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU General Public License version 3, as published
6+ * by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranties of
10+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11+ * PURPOSE. See the GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License along
14+ * with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef TIMEZONEMODEL_H
18+#define TIMEZONEMODEL_H
19+
20+#include <geonames.h>
21+#include <glib.h>
22+#include <QAbstractListModel>
23+
24+class TimeZoneLocationModel: public QAbstractListModel
25+{
26+ Q_OBJECT
27+ Q_PROPERTY(bool listUpdating READ listUpdating NOTIFY listUpdatingChanged)
28+ Q_PROPERTY(QString filter READ filter WRITE setFilter NOTIFY filterChanged)
29+ Q_PROPERTY(QString country READ country WRITE setCountry NOTIFY countryChanged)
30+ Q_ENUMS(Roles)
31+
32+public:
33+ explicit TimeZoneLocationModel(QObject *parent = nullptr);
34+ ~TimeZoneLocationModel();
35+
36+ enum Roles {
37+ TimeZoneRole = Qt::UserRole + 1,
38+ CityRole,
39+ CountryRole,
40+ SimpleRole,
41+ OffsetRole,
42+ LatitudeRole,
43+ LongitudeRole
44+ };
45+
46+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
47+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
48+ QHash<int, QByteArray> roleNames() const override;
49+
50+ bool listUpdating() const;
51+
52+ QString filter() const;
53+ void setFilter(const QString &filter);
54+
55+ QString country() const;
56+ void setCountry(const QString &country);
57+
58+Q_SIGNALS:
59+ void listUpdatingChanged();
60+ void filterChanged();
61+ void countryChanged(const QString &country);
62+
63+private:
64+ void setModel(const QList<GeonamesCity *> &locations);
65+ void setListUpdating(bool listUpdating);
66+ static void filterFinished(GObject *source_object,
67+ GAsyncResult *res,
68+ gpointer user_data);
69+
70+
71+ bool m_listUpdating;
72+ QString m_filter;
73+ QString m_country;
74+ GCancellable *m_cancellable;
75+ QHash<int, QByteArray> m_roleNames;
76+ QList<GeonamesCity *> m_locations;
77+ QList<GeonamesCity *> m_countryLocations;
78+};
79+
80+#endif
qml/Shell.qml−1
@@ -628,7 +628,6 @@ Item {
628 id: wizard
628 id: wizard
629 objectName: "wizard"
629 objectName: "wizard"
630 anchors.fill: parent
630 anchors.fill: parent
631− background: wallpaperResolver.background
632
631
633 function unlockWhenDoneWithWizard() {
632 function unlockWhenDoneWithWizard() {
634 if (!active) {
633 if (!active) {
qml/Wizard/CheckableSetting.qml+10−2
@@ -31,9 +31,11 @@ ListItem.Empty {
31 signal linkActivated(string link)
31 signal linkActivated(string link)
32
32
33 implicitHeight: Math.max(label.height, checkBox.height)
33 implicitHeight: Math.max(label.height, checkBox.height)
34+ highlightWhenPressed: false
34
35
35− Item {
36+ FocusScope {
36 anchors.fill: parent
37 anchors.fill: parent
38+ focus: true
37
39
38 CheckBox {
40 CheckBox {
39 id: checkBox
41 id: checkBox
@@ -77,8 +79,14 @@ ListItem.Empty {
77 rightMargin: listItem.rightMargin
79 rightMargin: listItem.rightMargin
78 }
80 }
79 wrapMode: Text.Wrap
81 wrapMode: Text.Wrap
80− linkColor: theme.palette.normal.foregroundText
82+ linkColor: UbuntuColors.orange
83+ color: textColor
84+ font.weight: Font.Light
85+ fontSize: "small"
86+ lineHeight: 1.2
81 onLinkActivated: listItem.linkActivated(link)
87 onLinkActivated: listItem.linkActivated(link)
82 }
88 }
89+
90+ Keys.onSpacePressed: checkBox.trigger()
83 }
91 }
84}
92}
qml/Wizard/Page.qml+260−44
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2013,2015 Canonical, Ltd.
2+ * Copyright (C) 2013-2016 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
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
5 * it under the terms of the GNU General Public License as published by
@@ -16,14 +16,33 @@
16
16
17import QtQuick 2.4
17import QtQuick 2.4
18import Ubuntu.Components 1.3
18import Ubuntu.Components 1.3
19+import Wizard 0.1
19
20
20Item {
21Item {
22+ readonly property real maximumContentWidth: units.gu(50)
23+ readonly property bool wideMode: width > units.gu(90) && width > height
24+ readonly property bool contentAnimationRunning: contentAnimation.running
25+
21− readonly property real buttonMargin: units.gu(2)
26+ readonly property real buttonMargin: units.gu(3)
22 readonly property real buttonWidth: (width - buttonMargin * 2) / 2 -
27 readonly property real buttonWidth: (width - buttonMargin * 2) / 2 -
23 buttonMargin / 2
28 buttonMargin / 2
24− readonly property real topMargin: units.gu(8)
29+ readonly property real buttonBarHeight: units.gu(5)
30+ readonly property real titleRectHeight: customTitle ? units.gu(10) : units.gu(16)
31+
32+ readonly property real topMargin: units.gu(11)
33+ readonly property real bottomMargin: units.gu(3)
25− readonly property real leftMargin: units.gu(2)
34+ readonly property real leftMargin: Math.max(units.gu(3), (width - maximumContentWidth) / 3)
26− readonly property real rightMargin: units.gu(2)
35+ readonly property real rightMargin: leftMargin
36+ readonly property real customMargin: wideMode ? units.gu(8) : units.gu(4) // margin for the content
37+ readonly property real staticMargin: units.gu(3)
38+
39+ // colors
40+ readonly property color backgroundColor: "#fdfdfd"
41+ readonly property color dividerColor: UbuntuColors.silk
42+ readonly property color textColor: UbuntuColors.slate
43+ readonly property color errorColor: theme.palette.normal.negative
44+ readonly property color okColor: theme.palette.normal.positive
45+ readonly property color whiteColor: "white" // workaround for a UITK bug
27
46
28 // If you want to skip a page, mark skipValid false while you figure out
47 // If you want to skip a page, mark skipValid false while you figure out
29 // whether to skip, then set it to true once you've determined the value
48 // whether to skip, then set it to true once you've determined the value
@@ -32,9 +51,13 @@ Item {
32 property bool skip: false
51 property bool skip: false
33
52
34 property bool hasBackButton: true
53 property bool hasBackButton: true
54+ property string backButtonText: i18n.ctr("Button: Go back one page in the Wizard", "Back")
35 property bool customBack: false
55 property bool customBack: false
56+ property bool customTitle: false
36 property alias forwardButtonSourceComponent: forwardButton.sourceComponent
57 property alias forwardButtonSourceComponent: forwardButton.sourceComponent
37 property alias content: contentHolder
58 property alias content: contentHolder
59+ property bool lastPage: false
60+ property bool buttonBarVisible: true
38
61
39 property string title: ""
62 property string title: ""
40
63
@@ -43,66 +66,259 @@ Item {
43 visible: false
66 visible: false
44 anchors.fill: parent
67 anchors.fill: parent
45
68
46− // We want larger than even fontSize: "x-large", so we use a Text instead
69+ Timer {
47− // of a Label.
70+ id: indicatorTimer
48− Text {
71+ interval: 1000
49− id: titleLabel
72+ triggeredOnStart: true
73+ repeat: true
74+ running: System.wizardEnabled
75+ onTriggered: {
76+ indicatorTime.text = Qt.formatTime(new Date(), "h:mm")
77+ }
78+ }
79+
80+ // page header
81+ Image {
82+ id: titleRect
83+ visible: !lastPage
50 anchors {
84 anchors {
51 top: parent.top
85 top: parent.top
52 left: parent.left
86 left: parent.left
53 right: parent.right
87 right: parent.right
54− topMargin: topMargin
55− leftMargin: leftMargin
56− rightMargin: rightMargin
57 }
88 }
58− wrapMode: Text.Wrap
89+ source: customTitle ? "" : (wideMode ? "Pages/data/Desktop_header_bkg.png" : "Pages/data/Phone_header_bkg.png")
90+ height: titleRectHeight
91+ clip: true
92+
93+ // page title
94+ Label {
95+ id: titleLabel
96+ property real animatedTopMargin: 0
97+ anchors {
98+ left: parent.left
99+ right: parent.right
100+ bottom: parent.bottom
101+ bottomMargin: bottomMargin
102+ leftMargin: staticMargin
103+ rightMargin: rightMargin
104+ topMargin: titleLabel.animatedTopMargin
105+ }
59− text: title
106+ text: title
60− color: theme.palette.normal.baseText
107+ color: customTitle ? textColor : backgroundColor
61− font.pixelSize: units.gu(4)
108+ fontSize: customTitle ? "large" : "x-large"
109+ font.weight: Font.Light
110+ wrapMode: Text.WordWrap
111+ maximumLineCount: 2
112+ elide: Text.ElideRight
113+ }
114+
115+ // indicators
116+ Row {
117+ id: indicatorRow
118+ visible: !customTitle
119+ anchors {
120+ top: parent.top
121+ right: parent.right
122+ topMargin: units.gu(.5)
123+ rightMargin: units.gu(.5)
124+ }
125+ height: units.gu(2)
126+ spacing: units.gu(1)
127+
128+ Icon {
129+ id: indicatorSim
130+ anchors.verticalCenter: parent.verticalCenter
131+ name: "no-simcard"
132+ height: parent.height
133+ width: height
134+ visible: !(root.simManager0.present || root.simManager1.present) && root.modemManager.modems.length > 0
135+ color: "white"
136+ }
137+
138+ Icon {
139+ id: indicatorNet
140+ anchors.verticalCenter: parent.verticalCenter
141+ name: Status.networkIcon
142+ height: parent.height
143+ width: height
144+ color: "white"
145+ }
146+
147+ Icon {
148+ id: indicatorBattery
149+ anchors.verticalCenter: parent.verticalCenter
150+ name: Status.batteryIcon
151+ height: parent.height
152+ width: height * 1.4 // the battery icon is not rectangular :/
153+ color: "white"
154+ }
155+
156+ Label {
157+ id: indicatorTime
158+ anchors.verticalCenter: parent.verticalCenter
159+ color: whiteColor
160+ fontSize: "small"
161+ }
162+ }
62 }
163 }
63
164
165+ // content
64 Item {
166 Item {
65 id: contentHolder
167 id: contentHolder
168+ property real animatedMargin: 0
169+ property real animatedTopMargin: 0
66 anchors {
170 anchors {
67− top: titleLabel.bottom
171+ top: titleRect.bottom
68 left: parent.left
172 left: parent.left
69 right: parent.right
173 right: parent.right
70− bottom: backButton.top
174+ bottom: buttonBarVisible ? buttonRect.top : parent.bottom
71− topMargin: units.gu(4)
175+ leftMargin: content.animatedMargin
72− leftMargin: leftMargin
176+ rightMargin: -content.animatedMargin
73− rightMargin: rightMargin
177+ topMargin: content.animatedTopMargin
74− bottomMargin: buttonMargin
75 }
178 }
179+ visible: opacity > 0
76 }
180 }
77
181
78− StackButton {
182+ // button bar
79− id: backButton
183+ Rectangle {
80− objectName: "backButton"
184+ id: buttonRect
81− width: buttonWidth
185+ visible: buttonBarVisible
82 anchors {
186 anchors {
83− left: parent.left
84 bottom: parent.bottom
187 bottom: parent.bottom
85− leftMargin: buttonMargin
188+ bottomMargin: Qt.inputMethod.visible ? Qt.inputMethod.keyboardRectangle.height : 0
86− bottomMargin: buttonMargin
189+ left: parent.left
190+ right: parent.right
87 }
191 }
88− z: 1
192+ height: buttonBarHeight
89− text: i18n.ctr("Button: Go back one page in the Wizard", "Back")
193+ color: "#f5f5f5"
90− visible: pageStack.depth > 1 && hasBackButton
194+ z: content.z + 1
91− backArrow: true
92
195
196+ StackButton {
197+ id: backButton
198+ objectName: "backButton"
199+ width: buttonWidth
200+ anchors {
201+ left: parent.left
202+ bottom: parent.bottom
203+ leftMargin: staticMargin
204+ verticalCenter: parent.verticalCenter
205+ }
206+ text: backButtonText
207+ visible: pageStack.depth > 1 && hasBackButton
208+ backArrow: true
209+
93− onClicked: customBack ? backClicked() : pageStack.prev()
210+ onClicked: customBack ? backClicked() : pageStack.prev()
211+ }
212+
213+ Loader {
214+ id: forwardButton
215+ objectName: "forwardButton"
216+ width: buttonWidth
217+ anchors {
218+ right: parent.right
219+ bottom: parent.bottom
220+ rightMargin: staticMargin
221+ verticalCenter: parent.verticalCenter
222+ }
223+ }
94 }
224 }
95
225
96− Loader {
226+ // transitions
97− id: forwardButton
227+ function aboutToShow(duration, direction) {
98− objectName: "forwardButton"
228+ startContentAnimation(duration, direction)
99− width: buttonWidth
229+ startControlsAnimation(duration)
100− anchors {
230+ }
101− right: parent.right
231+
102− bottom: parent.bottom
232+ function aboutToShowSecondary(duration) {
103− rightMargin: buttonMargin
233+ secondaryAnimation.restart()
104− bottomMargin: buttonMargin
234+ startControlsAnimation(duration)
235+ }
236+
237+ function startContentAnimation(duration, direction) {
238+ contentAnimation.animationDurationBase = duration
239+ contentAnimation.direction = direction
240+ contentAnimation.restart()
241+ }
242+
243+ function startControlsAnimation(showDuration) {
244+ actionsShowAnimation.showDuration = showDuration
245+ actionsShowAnimation.restart()
246+ }
247+
248+ SequentialAnimation { // animation for the button bar
249+ id: actionsShowAnimation
250+ property int showDuration: 0
251+ PropertyAction {
252+ target: buttonRect
253+ property: 'opacity'
254+ value: 0
255+ }
256+ PauseAnimation { duration: Math.max(0, actionsShowAnimation.showDuration - UbuntuAnimation.SnapDuration) }
257+ NumberAnimation {
258+ target: buttonRect
259+ property: 'opacity'
260+ to: 1
261+ duration: UbuntuAnimation.SnapDuration
262+ }
263+ }
264+
265+ SequentialAnimation { // animations for the content
266+ id: contentAnimation
267+ property int animationDurationBase: UbuntuAnimation.BriskDuration
268+ readonly property int additionalDuration: 200
269+ property int direction: Qt.LeftToRight
270+ ScriptAction { // direction of the effect
271+ script: {
272+ if (contentAnimation.direction === Qt.LeftToRight) {
273+ content.animatedMargin = -content.width;
274+ } else {
275+ content.animatedMargin = content.width;
276+ }
277+ }
278+ }
279+ ParallelAnimation {
280+ NumberAnimation { // the slide-in animation
281+ targets: content
282+ property: 'animatedMargin'
283+ to: 0
284+ duration: contentAnimation.animationDurationBase + contentAnimation.additionalDuration
285+ easing.type: Easing.OutCubic
286+ }
287+ NumberAnimation { // opacity animation
288+ targets: [titleLabel,content]
289+ property: 'opacity'
290+ from: 0
291+ to: 1
292+ duration: contentAnimation.animationDurationBase
293+ }
294+ }
295+ }
296+
297+ ParallelAnimation { // animation for the secondary pages
298+ id: secondaryAnimation
299+
300+ NumberAnimation { // the slide-up animation
301+ target: titleLabel
302+ property: 'animatedTopMargin'
303+ from: content.height
304+ to: customMargin
305+ duration: UbuntuAnimation.BriskDuration
306+ easing: UbuntuAnimation.StandardEasing
307+ }
308+ NumberAnimation {
309+ target: content
310+ property: 'animatedTopMargin'
311+ from: content.height
312+ to: 0
313+ duration: UbuntuAnimation.BriskDuration
314+ easing: UbuntuAnimation.StandardEasing
315+ }
316+ NumberAnimation { // opacity animation
317+ target: content
318+ property: 'opacity'
319+ from: 0
320+ to: 1
321+ duration: UbuntuAnimation.BriskDuration
105 }
322 }
106− z: 1
107 }
323 }
108}
324}
qml/Wizard/Pages.qml+75−31
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2013,2014,2015 Canonical, Ltd.
2+ * Copyright (C) 2013-2016 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
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
5 * it under the terms of the GNU General Public License as published by
@@ -15,40 +15,77 @@
15 */
15 */
16
16
17import QtQuick 2.4
17import QtQuick 2.4
18+import MeeGo.QOfono 0.2
18import Ubuntu.Components 1.3
19import Ubuntu.Components 1.3
19import Ubuntu.SystemSettings.SecurityPrivacy 1.0
20import Ubuntu.SystemSettings.SecurityPrivacy 1.0
21+import Ubuntu.SystemSettings.Diagnostics 1.0
20import Wizard 0.1
22import Wizard 0.1
21import "../Components"
23import "../Components"
22
24
23−Item {
25+StyledItem {
24 id: root
26 id: root
25 objectName: "wizardPages"
27 objectName: "wizardPages"
26 focus: true
28 focus: true
27
29
28− // The background wallpaper to use
29− property string background
30−
31 signal quit()
30 signal quit()
32
31
33 // These should be set by a security page and we apply the settings when
32 // These should be set by a security page and we apply the settings when
34 // the user exits the wizard.
33 // the user exits the wizard.
35− property int passwordMethod: UbuntuSecurityPrivacyPanel.Passcode
34+ property int passwordMethod: UbuntuSecurityPrivacyPanel.Passphrase
36 property string password: ""
35 property string password: ""
37
36
37+ property bool seenSIMPage: false // we want to see the SIM page at most once
38+
39+ property alias modemManager: modemManager
40+ property alias simManager0: simManager0
41+ property alias simManager1: simManager1
42+
43+ theme: ThemeSettings {
44+ name: "Ubuntu.Components.Themes.Ambiance"
45+ }
46+
38 UbuntuSecurityPrivacyPanel {
47 UbuntuSecurityPrivacyPanel {
39 id: securityPrivacy
48 id: securityPrivacy
40 objectName: "securityPrivacy"
49 objectName: "securityPrivacy"
41 }
50 }
42
51
52+ UbuntuDiagnostics {
53+ id: diagnostics
54+ objectName: "diagnostics"
55+ }
56+
57+ OfonoManager { // need it here for the language and country detection
58+ id: modemManager
59+ readonly property bool gotSimCard: available && ((simManager0.ready && simManager0.present) || (simManager1.ready && simManager1.present))
60+ property bool ready: false
61+ onModemsChanged: {
62+ ready = true;
63+ }
64+ }
65+
66+ // Ideally we would query the system more cleverly than hardcoding two
67+ // sims. But we don't yet have a more clever way. :(
68+ OfonoSimManager {
69+ id: simManager0
70+ modemPath: modemManager.modems.length >= 1 ? modemManager.modems[0] : ""
71+ }
72+
73+ OfonoSimManager {
74+ id: simManager1
75+ modemPath: modemManager.modems.length >= 2 ? modemManager.modems[1] : ""
76+ }
77+
43 function quitWizard() {
78 function quitWizard() {
44 pageStack.currentPage.enabled = false;
79 pageStack.currentPage.enabled = false;
45
80
81+ if (password != "") {
46− var errorMsg = securityPrivacy.setSecurity("", password, passwordMethod)
82+ var errorMsg = securityPrivacy.setSecurity("", password, passwordMethod)
47− if (errorMsg !== "") {
83+ if (errorMsg !== "") {
48− // Ignore (but log) any errors, since we're past where the user set
84+ // Ignore (but log) any errors, since we're past where the user set
49− // the method. Worst case, we just leave the user with a swipe
85+ // the method. Worst case, we just leave the user with a swipe
50− // security method and they fix it in the system settings.
86+ // security method and they fix it in the system settings.
51− console.log("Error setting security method:", errorMsg)
87+ console.log("Error setting security method:", errorMsg)
88+ }
52 }
89 }
53
90
54 quit();
91 quit();
@@ -58,19 +95,10 @@ Item {
58 anchors.fill: parent
95 anchors.fill: parent
59 }
96 }
60
97
61− Image {
98+ Rectangle {
62− id: image
63− // Use x/y/height/width instead of anchors so that we don't adjust
64− // the image when the OSK appears.
65− x: 0
66− y: 0
67− height: root.height
68− width: root.width
69− sourceSize.height: height
70− sourceSize.width: width
71− source: root.background
99+ id: background
72− fillMode: Image.PreserveAspectCrop
100+ anchors.fill: root
73− visible: status === Image.Ready
101+ color: "#fdfdfd"
74 }
102 }
75
103
76 PageList {
104 PageList {
@@ -86,18 +114,26 @@ Item {
86 // If we've opened any extra (non-main) pages, pop them before
114 // If we've opened any extra (non-main) pages, pop them before
87 // continuing so back button returns to the previous main page.
115 // continuing so back button returns to the previous main page.
88 while (pageList.index < pageStack.depth - 1)
116 while (pageList.index < pageStack.depth - 1)
89− pop()
117+ pop();
90− load(pageList.next())
118+ load(pageList.next());
91 }
119 }
92
120
93 function prev() {
121 function prev() {
122+ var isPrimaryPage = currentPage && !currentPage.customTitle;
94− if (pageList.index >= pageStack.depth - 1)
123+ if (pageList.index >= pageStack.depth - 1) {
95− pageList.prev() // update pageList.index, but not for extra pages
124+ pageList.prev(); // update pageList.index, but not for extra pages
125+ }
96 pop()
126 pop()
97 if (!currentPage || currentPage.opacity === 0) { // undo skipped pages
127 if (!currentPage || currentPage.opacity === 0) { // undo skipped pages
98− prev()
128+ prev();
99 } else {
129 } else {
100− currentPage.enabled = true
130+ currentPage.enabled = true;
131+ }
132+
133+ if (isPrimaryPage) {
134+ currentPage.aboutToShow(UbuntuAnimation.BriskDuration, Qt.LeftToRight);
135+ } else {
136+ currentPage.aboutToShowSecondary(UbuntuAnimation.BriskDuration);
101 }
137 }
102 }
138 }
103
139
@@ -115,6 +151,13 @@ Item {
115 // Check for immediate skip or not. We may have to wait for
151 // Check for immediate skip or not. We may have to wait for
116 // skipValid to be assigned (see Connections object below)
152 // skipValid to be assigned (see Connections object below)
117 checkSkip()
153 checkSkip()
154+
155+ var isPrimaryPage = !currentPage.customTitle;
156+ if (isPrimaryPage) {
157+ currentPage.aboutToShow(UbuntuAnimation.BriskDuration, Qt.RightToLeft);
158+ } else {
159+ currentPage.aboutToShowSecondary(UbuntuAnimation.BriskDuration);
160+ }
118 }
161 }
119
162
120 function checkSkip() {
163 function checkSkip() {
@@ -136,6 +179,7 @@ Item {
136 objectName: "timeout"
179 objectName: "timeout"
137 interval: 2000 // wizard pages shouldn't take long
180 interval: 2000 // wizard pages shouldn't take long
138 onTriggered: {
181 onTriggered: {
182+ console.warn("Wizard page " + pageStack.currentPage.objectName + " skipped due to taking too long!!!");
139 pageStack.currentPage.skip = true;
183 pageStack.currentPage.skip = true;
140 pageStack.currentPage.skipValid = true;
184 pageStack.currentPage.skipValid = true;
141 }
185 }
qml/Wizard/Pages/10-welcome.qml+121−48
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2013 Canonical, Ltd.
2+ * Copyright (C) 2013-2015 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
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
5 * it under the terms of the GNU General Public License as published by
@@ -24,60 +24,124 @@ import ".." as LocalComponents
24LocalComponents.Page {
24LocalComponents.Page {
25 objectName: "languagePage"
25 objectName: "languagePage"
26
26
27− title: i18n.tr("Hi!")
27+ title: i18n.tr("Language")
28 forwardButtonSourceComponent: forwardButton
28 forwardButtonSourceComponent: forwardButton
29
29
30 UbuntuLanguagePlugin {
30 UbuntuLanguagePlugin {
31 id: plugin
31 id: plugin
32 }
32 }
33
33
34− Column {
34+ function init()
35− id: column
35+ {
36− anchors.fill: content
36+ var detectedLang = "";
37− spacing: units.gu(1)
37+ // try to detect the language+country from the SIM card
38−
38+ if (root.simManager0.present && root.simManager0.preferredLanguages.length > 0) {
39− Label {
39+ detectedLang = root.simManager0.preferredLanguages[0] + "_" + LocalePlugin.mccToCountryCode(root.simManager0.mobileCountryCode);
40− id: label1
40+ } else if (root.simManager1.present && root.simManager1.preferredLanguages.length > 0) {
41− anchors.left: parent.left
41+ detectedLang = root.simManager1.preferredLanguages[0] + "_" + LocalePlugin.mccToCountryCode(root.simManager1.mobileCountryCode);
42− anchors.right: parent.right
42+ } else if (plugin.currentLanguage != -1) {
43− wrapMode: Text.Wrap
43+ detectedLang = plugin.languageCodes[plugin.currentLanguage].split(".")[0]; // remove the encoding part, after dot (en_US.utf8 -> en_US)
44− text: i18n.tr("Welcome to your Ubuntu device.")
44+ } else {
45+ detectedLang = "en_US"; // fallback to default lang
45 }
46 }
46
47
47− Label {
48+ // preselect the detected language
48− id: label2
49+ for (var i = 0; i < plugin.languageCodes.length; i++) {
49− anchors.left: parent.left
50+ var code = plugin.languageCodes[i].split(".")[0]; // remove the encoding part, after dot (en_US.utf8 -> en_US)
50− anchors.right: parent.right
51+ if (detectedLang === code) {
51− wrapMode: Text.Wrap
52+ languagesListView.currentIndex = i;
52− text: i18n.tr("Let’s get started.")
53+ languagesListView.positionViewAtIndex(i, ListView.Center);
54+ i18n.language = plugin.languageCodes[i];
55+ break;
56+ }
57+ }
58+ }
59+
60+ // splash screen (this has to be on the first page)
61+ Image {
62+ id: splashImage
63+ anchors.top: parent.top
64+ anchors.left: parent.left
65+ anchors.right: parent.right
66+ height: parent.height
67+ source: wideMode ? "data/Desktop_splash_screen_bkg.png" : "data/Phone_splash_screen_bkg.png"
68+ fillMode: Image.PreserveAspectCrop
69+ z: 2
70+ visible: opacity > 0
71+ Component.onCompleted: splashAnimation.start()
72+ }
73+
74+ SequentialAnimation {
75+ id: splashAnimation
76+ PauseAnimation { duration: UbuntuAnimation.BriskDuration }
77+ SmoothedAnimation {
78+ target: splashImage
79+ property: "height"
80+ to: units.gu(16)
81+ duration: UbuntuAnimation.BriskDuration
53 }
82 }
83+ NumberAnimation {
84+ target: splashImage
85+ property: 'opacity'
86+ from: 1
87+ to: 0
88+ }
89+ onStopped: init();
90+ }
91+
92+ ListView {
93+ id: languagesListView
94+ clip: true
95+ snapMode: ListView.SnapToItem
54
96
55− Item { // spacer
97+ anchors {
56− height: units.gu(2)
98+ fill: content
57− width: units.gu(1) // needed else it will be ignored
99+ leftMargin: wideMode ? parent.leftMargin : 0
100+ rightMargin: wideMode ? parent.rightMargin : 0
101+ topMargin: wideMode ? parent.customMargin : 0
58 }
102 }
59
103
60− ComboButton {
61− id: combo
62− objectName: "languageCombo"
63− anchors.left: parent.left
64− anchors.right: parent.right
65− text: listview.currentItem.text
66− onClicked: expanded = !expanded
67− expandedHeight: column.height - combo.y
68− UbuntuListView {
69− id: listview
70− model: plugin.languageNames
104+ model: plugin.languageNames
71− currentIndex: plugin.currentLanguage
105+
72− delegate: Standard {
106+ delegate: ListItem {
107+ id: itemDelegate
73− objectName: "languageDelegate" + index
108+ objectName: "languageDelegate" + index
109+ highlightColor: backgroundColor
110+ divider.colorFrom: dividerColor
111+ divider.colorTo: backgroundColor
112+ readonly property bool isCurrent: index === ListView.view.currentIndex
113+
114+ Label {
115+ id: langLabel
74− text: modelData
116+ text: modelData
75− onClicked: {
117+
76− listview.currentIndex = index
118+ anchors {
77− combo.expanded = false
119+ left: parent.left
78− i18n.language = plugin.languageCodes[index]
120+ verticalCenter: parent.verticalCenter
79− }
121+ leftMargin: languagesListView.anchors.leftMargin == 0 ? staticMargin : 0
80 }
122 }
123+
124+ fontSize: "medium"
125+ font.weight: itemDelegate.isCurrent ? Font.Normal : Font.Light
126+ color: textColor
127+ }
128+
129+ Image {
130+ anchors {
131+ right: parent.right;
132+ verticalCenter: parent.verticalCenter;
133+ rightMargin: languagesListView.anchors.rightMargin == 0 ? staticMargin : 0
134+ }
135+ fillMode: Image.PreserveAspectFit
136+ height: units.gu(1.5)
137+
138+ source: "data/Tick@30.png"
139+ visible: itemDelegate.isCurrent
140+ }
141+
142+ onClicked: {
143+ languagesListView.currentIndex = index;
144+ i18n.language = plugin.languageCodes[index];
81 }
145 }
82 }
146 }
83 }
147 }
@@ -85,14 +149,23 @@ LocalComponents.Page {
85 Component {
149 Component {
86 id: forwardButton
150 id: forwardButton
87 LocalComponents.StackButton {
151 LocalComponents.StackButton {
88− text: i18n.tr("Continue")
152+ text: i18n.tr("Next")
153+ enabled: languagesListView.currentIndex != -1
89 onClicked: {
154 onClicked: {
90− if (plugin.currentLanguage !== listview.currentIndex) {
155+ if (plugin.currentLanguage !== languagesListView.currentIndex) {
91− plugin.currentLanguage = listview.currentIndex;
156+ plugin.currentLanguage = languagesListView.currentIndex;
92− System.updateSessionLanguage(plugin.languageCodes[listview.currentIndex]);
157+ System.updateSessionLocale(plugin.languageCodes[plugin.currentLanguage]);
158+ }
93− i18n.language = i18n.language; // re-notify of change after above call (for qlocale change)
159+ i18n.language = plugin.languageCodes[plugin.currentLanguage]; // re-notify of change after above call (for qlocale change)
160+
161+ if (!root.modemManager.available || !root.modemManager.ready || root.modemManager.modems.length === 0 ||
162+ (root.simManager0.present && root.simManager0.ready) || (root.simManager1.present && root.simManager1.ready) ||
163+ root.seenSIMPage) { // go to next page
164+ pageStack.next();
165+ }
166+ else {
167+ pageStack.load(Qt.resolvedUrl("sim.qml")); // show the SIM page
94 }
168 }
95− pageStack.next()
96 }
169 }
97 }
170 }
98 }
171 }
qml/Wizard/Pages/20-sim.qmldeleted−77
@@ -1,77 +0,0 @@
1−/*
2− * Copyright (C) 2013 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 MeeGo.QOfono 0.2
19−import Ubuntu.Components 1.3
20−import ".." as LocalComponents
21−
22−LocalComponents.Page {
23− objectName: "simPage"
24−
25− title: i18n.tr("Add a SIM card and restart your device")
26− forwardButtonSourceComponent: forwardButton
27−
28− skipValid: !manager.available ||
29− (manager.ready && (manager.modems.length < 1 || simManager0.ready)
30− && (manager.modems.length < 2 || simManager1.ready))
31− skip: !manager.available || manager.modems.length === 0 || simManager0.present || simManager1.present
32−
33− OfonoManager {
34− id: manager
35− property bool ready: false
36− onModemsChanged: ready = true
37− }
38−
39− // Ideally we would query the system more cleverly than hardcoding two
40− // modems. But we don't yet have a more clever way. :(
41− OfonoSimManager {
42− id: simManager0
43− modemPath: manager.modems.length >= 1 ? manager.modems[0] : ""
44− }
45−
46− OfonoSimManager {
47− id: simManager1
48− modemPath: manager.modems.length >= 2 ? manager.modems[1] : ""
49− }
50−
51− Column {
52− anchors.fill: content
53− spacing: units.gu(4)
54−
55− Label {
56− anchors.left: parent.left
57− anchors.right: parent.right
58− wrapMode: Text.Wrap
59− text: i18n.tr("Without it, you won’t be able to make calls or use text messaging.")
60− }
61−
62− Image {
63− id: image
64− source: "data/meet_ubuntu_simcard@30.png"
65− height: units.gu(6.5)
66− width: units.gu(9)
67− }
68− }
69−
70− Component {
71− id: forwardButton
72− LocalComponents.StackButton {
73− text: i18n.tr("Skip")
74− onClicked: pageStack.next()
75− }
76− }
77−}
qml/Wizard/Pages/30-passwd-type.qmldeleted−140
@@ -1,140 +0,0 @@
1−/*
2− * Copyright (C) 2014,2015 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.Components.ListItems 1.3
20−import Ubuntu.SystemSettings.SecurityPrivacy 1.0
21−import ".." as LocalComponents
22−
23−/**
24− * One quirk with this page: we don't actually set the password. We avoid
25− * doing it here because the user can come back to this page and change their
26− * answer. We don't run as root, so if we did set the password immediately,
27− * we'd need to prompt for their previous password when they came back and
28− * changed their answer. Which is silly UX. So instead, we just keep track
29− * of their choice and set the password at the end (see main.qml).
30− * Setting the password shouldn't fail, since Ubuntu Touch has loose password
31− * requirements, but we'll check what we can here. Ideally we'd be able to ask
32− * the system if a password is legal without actually setting that password.
33− */
34−
35−LocalComponents.Page {
36− id: passwdPage
37− objectName: "passwdPage"
38−
39− title: i18n.tr("Lock security")
40− forwardButtonSourceComponent: forwardButton
41−
42− // If the user has set a password some other way (via ubuntu-device-flash
43− // or this isn't the first time the wizard has been run, etc). We can't
44− // properly set the password again, so let's not pretend we can.
45− skip: securityPrivacy.securityType !== UbuntuSecurityPrivacyPanel.Swipe
46−
47− function indexToMethod(index) {
48− if (index === 0)
49− return UbuntuSecurityPrivacyPanel.Swipe
50− else if (index === 1)
51− return UbuntuSecurityPrivacyPanel.Passcode
52− else
53− return UbuntuSecurityPrivacyPanel.Passphrase
54− }
55−
56− function methodToIndex(method) {
57− if (method === UbuntuSecurityPrivacyPanel.Swipe)
58− return 0
59− else if (method === UbuntuSecurityPrivacyPanel.Passcode)
60− return 1
61− else
62− return 2
63− }
64−
65− Connections {
66− target: root
67− onPasswordMethodChanged: selector.selectedIndex = methodToIndex(root.passwordMethod)
68− }
69−
70− Column {
71− id: column
72− anchors.fill: content
73− spacing: units.gu(4)
74−
75− Label {
76− anchors.left: parent.left
77− anchors.right: parent.right
78− wrapMode: Text.Wrap
79− text: i18n.tr("Please select how you’d like to unlock your device.")
80− }
81−
82− ItemSelector {
83− id: selector
84− expanded: true
85− anchors.left: parent.left
86− anchors.right: parent.right
87− property color originalBackground
88−
89− model: ["", "", ""] // otherwise the delegate will show the text itself and we only want subText
90−
91− selectedIndex: methodToIndex(root.passwordMethod)
92−
93− delegate: OptionSelectorDelegate {
94− objectName: "passwdDelegate" + index
95−
96− // use subText because we want the text to be small, and we have no other way to control it
97− subText: {
98− var method = indexToMethod(index)
99− var name = ""
100− var desc = ""
101− if (method === UbuntuSecurityPrivacyPanel.Swipe) {
102− name = i18n.ctr("Label: Type of security method", "Swipe")
103− desc = i18n.ctr("Label: Description of security method", "No security")
104− } else if (method === UbuntuSecurityPrivacyPanel.Passcode) {
105− name = i18n.ctr("Label: Type of security method", "Passcode")
106− desc = i18n.ctr("Label: Description of security method", "4 digits only")
107− } else {
108− name = i18n.ctr("Label: Type of security method", "Passphrase")
109− desc = i18n.ctr("Label: Description of security method", "Numbers and letters")
110− }
111− return "<b>%1</b> (%2)".arg(name).arg(desc)
112− }
113− }
114−
115− style: Item {}
116−
117− Component.onCompleted: {
118− // A visible selected background looks bad in ListItem widgets with our theme
119− originalBackground = theme.palette.selected.background
120− theme.palette.selected.background = "transparent"
121− }
122−
123− Component.onDestruction: {
124− // Restore original theme background
125− theme.palette.selected.background = originalBackground
126− }
127− }
128− }
129−
130− Component {
131− id: forwardButton
132− LocalComponents.StackButton {
133− text: i18n.tr("Continue")
134− onClicked: {
135− root.passwordMethod = indexToMethod(selector.selectedIndex)
136− pageStack.load(Qt.resolvedUrl("passwd-set.qml"))
137− }
138− }
139− }
140−}
qml/Wizard/Pages/30-wifi.qmlnew file+210
@@ -0,0 +1,210 @@
1+/*
2+ * Copyright (C) 2013, 2015 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 QMenuModel 0.1 as QMenuModel
20+import Ubuntu.Components 1.3
21+import Wizard 0.1
22+import Ubuntu.Connectivity 1.0
23+import ".." as LocalComponents
24+
25+LocalComponents.Page {
26+ id: wifiPage
27+ objectName: "wifiPage"
28+
29+ title: i18n.tr("Connect to Wi‑Fi")
30+ forwardButtonSourceComponent: forwardButton
31+
32+ readonly property bool connected: Connectivity.online
33+
34+ function getExtendedProperty(object, propertyName, defaultValue) {
35+ if (object && object.hasOwnProperty(propertyName)) {
36+ return object[propertyName];
37+ }
38+ return defaultValue;
39+ }
40+
41+ function getAPIcon(adHoc, signalStrength, secure) {
42+ var imageName = "nm-no-connection";
43+
44+ if (adHoc) {
45+ imageName = "nm-adhoc";
46+ } else if (signalStrength == 0) {
47+ imageName = "nm-signal-00";
48+ } else if (signalStrength <= 25) {
49+ imageName = "nm-signal-25";
50+ } else if (signalStrength <= 50) {
51+ imageName = "nm-signal-50";
52+ } else if (signalStrength <= 75) {
53+ imageName = "nm-signal-75";
54+ } else if (signalStrength <= 100) {
55+ imageName = "nm-signal-100";
56+ }
57+
58+ if (secure) {
59+ imageName += "-secure";
60+ }
61+ return imageName;
62+ }
63+
64+ QMenuModel.UnityMenuModel {
65+ id: menuModel
66+ busName: "com.canonical.indicator.network"
67+ actions: { "indicator": "/com/canonical/indicator/network" }
68+ menuObjectPath: "/com/canonical/indicator/network/phone_wifi_settings"
69+ }
70+
71+ Component {
72+ id: accessPointComponent
73+ ListItem {
74+ id: accessPoint
75+ objectName: "accessPoint"
76+ highlightColor: backgroundColor
77+ enabled: menuData && menuData.sensitive || false
78+ divider.colorFrom: dividerColor
79+ divider.colorTo: backgroundColor
80+
81+ property QtObject menuData: null
82+ property var unityMenuModel: menuModel
83+ property var extendedData: menuData && menuData.ext || undefined
84+ property var strengthAction: QMenuModel.UnityMenuAction {
85+ model: unityMenuModel
86+ index: menuIndex
87+ name: getExtendedProperty(extendedData, "xCanonicalWifiApStrengthAction", "")
88+ }
89+ readonly property bool secure: getExtendedProperty(extendedData, "xCanonicalWifiApIsSecure", false)
90+ readonly property bool adHoc: getExtendedProperty(extendedData, "xCanonicalWifiApIsAdhoc", false)
91+ readonly property bool isConnected: menuData && menuData.actionState
92+ readonly property bool isEnterprise: getExtendedProperty(extendedData, "xCanonicalWifiApIsEnterprise", false)
93+ readonly property int signalStrength: strengthAction.valid ? strengthAction.state : 0
94+ property int menuIndex: -1
95+
96+ function loadAttributes() {
97+ if (!unityMenuModel || menuIndex == -1) return;
98+ unityMenuModel.loadExtendedAttributes(menuIndex, {'x-canonical-wifi-ap-is-adhoc': 'bool',
99+ 'x-canonical-wifi-ap-is-secure': 'bool',
100+ 'x-canonical-wifi-ap-is-enterprise': 'bool',
101+ 'x-canonical-wifi-ap-strength-action': 'string'});
102+ }
103+
104+ Icon {
105+ id: apIcon
106+ anchors {
107+ left: parent.left
108+ verticalCenter: parent.verticalCenter
109+ leftMargin: column.anchors.leftMargin == 0 ? staticMargin : 0
110+ }
111+ height: units.gu(2.5)
112+ width: height
113+ name: getAPIcon(accessPoint.adHoc, accessPoint.signalStrength, accessPoint.secure)
114+ color: textColor
115+ }
116+
117+ Column {
118+ anchors.verticalCenter: parent.verticalCenter
119+ anchors.left: apIcon.right
120+ anchors.leftMargin: units.gu(2)
121+ Label {
122+ id: apName
123+ text: menuData && menuData.label || ""
124+ font.weight: accessPoint.isConnected ? Font.Normal : Font.Light
125+ fontSize: "medium"
126+ color: textColor
127+ }
128+ Label {
129+ id: connectedLabel
130+ text: i18n.tr("Connected")
131+ font.weight: Font.Light
132+ fontSize: "small"
133+ color: okColor
134+ visible: accessPoint.isConnected
135+ }
136+ }
137+
138+ onClicked: {
139+ unityMenuModel.activate(menuIndex);
140+ listview.positionViewAtBeginning();
141+ }
142+ }
143+ }
144+
145+ ColumnLayout {
146+ id: column
147+ spacing: units.gu(2)
148+ anchors {
149+ fill: content
150+ topMargin: customMargin
151+ leftMargin: wideMode ? parent.leftMargin : 0
152+ rightMargin: wideMode ? parent.rightMargin : 0
153+ }
154+
155+ Label {
156+ id: label
157+ anchors.left: parent.left
158+ anchors.right: parent.right
159+ anchors.leftMargin: column.anchors.leftMargin == 0 ? staticMargin : 0
160+ font.weight: Font.Light
161+ color: "#68064d"
162+ wrapMode: Text.Wrap
163+ text: listview.count > 0 ? i18n.tr("Available Wi-Fi networks")
164+ : i18n.tr("No available Wi-Fi networks")
165+ }
166+
167+ ListView {
168+ id: listview
169+ anchors.left: parent.left
170+ anchors.right: parent.right
171+ clip: true
172+ model: menuModel
173+ Layout.fillHeight: true
174+
175+ delegate: Loader {
176+ id: loader
177+
178+ readonly property bool isAccessPoint: model.type === "unity.widgets.systemsettings.tablet.accesspoint"
179+ readonly property bool isConnected: item && item.menuData && item.menuData.actionState
180+ readonly property bool isEnterprise: item && item.isEnterprise
181+
182+ height: !!sourceComponent ? (isConnected ? units.gu(9) : units.gu(7)) : 0
183+ anchors.left: parent.left
184+ anchors.right: parent.right
185+
186+ asynchronous: true
187+ sourceComponent: {
188+ if (isAccessPoint && !isEnterprise) {
189+ return accessPointComponent;
190+ }
191+ return null;
192+ }
193+
194+ onLoaded: {
195+ item.menuData = Qt.binding(function() { return model; });
196+ item.menuIndex = Qt.binding(function() { return index; });
197+ item.loadAttributes();
198+ }
199+ }
200+ }
201+ }
202+
203+ Component {
204+ id: forwardButton
205+ LocalComponents.StackButton {
206+ text: (connected || listview.count === 0) ? i18n.tr("Next") : i18n.tr("Skip")
207+ onClicked: pageStack.next()
208+ }
209+ }
210+}
qml/Wizard/Pages/40-location.qmlnew file+291
@@ -0,0 +1,291 @@
1+/*
2+ * Copyright (C) 2013-2015 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") + " <a href='#'>" +
106+ // TRANSLATORS: "terms and conditions" is part of the sentence above
107+ i18n.tr("terms and conditions") + "</a>."
108+ Mouse.forwardTo: hereCheckArea // clicking on the link also selects this group
109+ Mouse.priority: Mouse.AfterItem
110+ onLinkActivated: {
111+ pageStack.load(Qt.resolvedUrl("here-terms.qml"));
112+ }
113+ }
114+
115+ Image {
116+ id: hereTermsCheck
117+ fillMode: Image.PreserveAspectFit
118+ height: units.gu(1.5)
119+ source: "data/Tick@30.png"
120+ opacity: hereCheckLabel.checked ? 1 : 0
121+ anchors.right: parent.right
122+ anchors.verticalCenter: hereCheckLabel.verticalCenter
123+ anchors.rightMargin: column.anchors.rightMargin == 0 ? staticMargin : 0
124+ }
125+
126+ MouseArea {
127+ id: hereCheckArea
128+ anchors.fill: parent
129+ z: hereCheckGroup.z - 1 // so that the link can be activated
130+ onClicked: {
131+ if (!hereCheckLabel.checked) {
132+ hereCheckLabel.checked = true;
133+ gpsCheckLabel.checked = false;
134+ nopeCheckLabel.checked = false;
135+ }
136+ }
137+ }
138+ }
139+
140+ Rectangle {
141+ id: divider
142+ anchors.left: parent.left
143+ anchors.right: parent.right
144+ anchors.top: hereCheckGroup.bottom
145+ anchors.topMargin: units.gu(3)
146+ height: units.dp(1)
147+ color: dividerColor
148+ }
149+
150+ Label {
151+ id: gpsCheckLabel
152+ objectName: "gpsCheckLabel"
153+ anchors {
154+ left: parent.left
155+ right: parent.right
156+ top: divider.bottom
157+ topMargin: units.gu(3)
158+ leftMargin: column.anchors.leftMargin == 0 ? staticMargin : 0
159+ rightMargin: units.gu(2)
160+ }
161+ text: i18n.tr("GPS only")
162+ wrapMode: Text.WordWrap
163+ color: textColor
164+ font.weight: checked ? Font.Normal : Font.Light
165+ width: content.width
166+ property bool checked: false
167+
168+ MouseArea {
169+ anchors.fill: parent
170+ onClicked: {
171+ if (!gpsCheckLabel.checked) {
172+ hereCheckLabel.checked = false;
173+ gpsCheckLabel.checked = true;
174+ nopeCheckLabel.checked = false;
175+ }
176+ }
177+ }
178+ }
179+
180+ Image {
181+ fillMode: Image.PreserveAspectFit
182+ height: units.gu(1.5)
183+ source: "data/Tick@30.png"
184+ opacity: gpsCheckLabel.checked ? 1 : 0
185+ anchors.right: parent.right
186+ anchors.verticalCenter: gpsCheckLabel.verticalCenter
187+ anchors.rightMargin: column.anchors.rightMargin == 0 ? staticMargin : 0
188+ }
189+
190+ Rectangle {
191+ id: divider2
192+ anchors.left: parent.left
193+ anchors.right: parent.right
194+ anchors.top: gpsCheckLabel.bottom
195+ anchors.topMargin: units.gu(3)
196+ height: units.dp(1)
197+ color: dividerColor
198+ }
199+
200+ Label {
201+ id: nopeCheckLabel
202+ objectName: "nopeCheckLabel"
203+ anchors {
204+ left: parent.left
205+ right: parent.right
206+ top: divider2.bottom
207+ topMargin: units.gu(3)
208+ leftMargin: column.anchors.leftMargin == 0 ? staticMargin : 0
209+ rightMargin: units.gu(2)
210+ }
211+ wrapMode: Text.WordWrap
212+ color: textColor
213+ font.weight: checked ? Font.Normal : Font.Light
214+ width: content.width
215+ text: i18n.tr("Don't use my location")
216+ property bool checked: false
217+
218+ MouseArea {
219+ anchors.fill: parent
220+ onClicked: {
221+ if (!nopeCheckLabel.checked) {
222+ hereCheckLabel.checked = false;
223+ gpsCheckLabel.checked = false;
224+ nopeCheckLabel.checked = true;
225+ }
226+ }
227+ }
228+ }
229+
230+ Image {
231+ fillMode: Image.PreserveAspectFit
232+ height: units.gu(1.5)
233+ source: "data/Tick@30.png"
234+ opacity: nopeCheckLabel.checked ? 1 : 0
235+ anchors.right: parent.right
236+ anchors.verticalCenter: nopeCheckLabel.verticalCenter
237+ anchors.rightMargin: column.anchors.rightMargin == 0 ? staticMargin : 0
238+ }
239+
240+ Rectangle {
241+ id: divider3
242+ anchors.left: parent.left
243+ anchors.right: parent.right
244+ anchors.top: nopeCheckLabel.bottom
245+ anchors.topMargin: units.gu(3)
246+ height: units.dp(1)
247+ color: dividerColor
248+ }
249+
250+ Label {
251+ id: infoLabel
252+ anchors {
253+ left: parent.left
254+ right: parent.right
255+ top: divider3.bottom
256+ topMargin: units.gu(4)
257+ leftMargin: column.anchors.leftMargin == 0 ? staticMargin : 0
258+ rightMargin: column.anchors.rightMargin == 0 ? staticMargin : 0
259+ }
260+ wrapMode: Text.Wrap
261+ text: i18n.tr("You can change it later in System Settings.")
262+ color: textColor
263+ fontSize: "small"
264+ font.weight: Font.Light
265+ width: content.width
266+ }
267+ }
268+
269+ Component {
270+ id: forwardButton
271+ LocalComponents.StackButton {
272+ text: i18n.tr("Next")
273+ onClicked: {
274+ var locationOn = gpsCheckLabel.checked || hereCheckLabel.checked;
275+ var gpsOn = gpsCheckLabel.checked || hereCheckLabel.checked;
276+ var hereOn = hereCheckLabel.checked;
277+
278+ // location service doesn't currently listen to updateState
279+ // requests, so we activate the actions if needed.
280+ if (locationActionGroup.location.state != locationOn) {
281+ locationActionGroup.location.activate();
282+ }
283+ if (locationActionGroup.gps.state != gpsOn) {
284+ locationActionGroup.gps.activate();
285+ }
286+ AccountsService.hereEnabled = hereOn;
287+ pageStack.next();
288+ }
289+ }
290+ }
291+}
qml/Wizard/Pages/40-wifi.qmldeleted−219
@@ -1,219 +0,0 @@
1−/*
2− * Copyright (C) 2013 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 QMenuModel 0.1 as QMenuModel
19−import QtSystemInfo 5.0
20−import Ubuntu.Components 1.3
21−import Ubuntu.Components.ListItems 1.3 as ListItem
22−import Ubuntu.Settings.Menus 0.1 as Menus
23−import ".." as LocalComponents
24−
25−LocalComponents.Page {
26− id: wifiPage
27− objectName: "wifiPage"
28−
29− title: i18n.tr("Connect to Wi‑Fi")
30− forwardButtonSourceComponent: forwardButton
31−
32− readonly property bool connected: networkInfo.accessPointName
33−
34− function getExtendedProperty(object, propertyName, defaultValue) {
35− if (object && object.hasOwnProperty(propertyName)) {
36− return object[propertyName];
37− }
38− return defaultValue;
39− }
40−
41− QMenuModel.UnityMenuModel {
42− id: menuModel
43− busName: "com.canonical.indicator.network"
44− actions: { "indicator": "/com/canonical/indicator/network" }
45− menuObjectPath: "/com/canonical/indicator/network/phone_wifi_settings"
46− }
47−
48− NetworkInfo {
49− id: networkInfo
50−
51− property string accessPointName
52−
53− monitorCurrentNetworkMode: true
54− monitorNetworkName: true
55− monitorNetworkStatus: true
56−
57− onCurrentNetworkModeChanged: getAccessPointName()
58− onNetworkNameChanged: getAccessPointName()
59− onNetworkStatusChanged: if (status !== NetworkInfo.HomeNetwork) accessPointName = ""
60−
61− Component.onCompleted: getAccessPointName()
62−
63− function getAccessPointName() {
64− // 0 is the interface
65− if (currentNetworkMode === NetworkInfo.WlanMode &&
66− networkStatus(NetworkInfo.WlanMode, 0) === NetworkInfo.HomeNetwork)
67− accessPointName = networkName(NetworkInfo.WlanMode, 0);
68− else
69− accessPointName = "";
70− }
71− }
72−
73− Component {
74− id: accessPointComponent
75− ListItem.Standard {
76− id: accessPoint
77− objectName: "accessPoint"
78−
79− property QtObject menuData: null
80− property var unityMenuModel: menuModel
81− property var extendedData: menuData && menuData.ext || undefined
82− property var strengthAction: QMenuModel.UnityMenuAction {
83− model: unityMenuModel
84− index: menuIndex
85− name: getExtendedProperty(extendedData, "xCanonicalWifiApStrengthAction", "")
86− }
87− property bool checked: menuData && menuData.isToggled || false
88− property bool secure: getExtendedProperty(extendedData, "xCanonicalWifiApIsSecure", false)
89− property bool adHoc: getExtendedProperty(extendedData, "xCanonicalWifiApIsAdhoc", false)
90− property int signalStrength: strengthAction.valid ? strengthAction.state : 0
91− property int menuIndex: -1
92−
93− function loadAttributes() {
94− if (!unityMenuModel || menuIndex == -1) return;
95− unityMenuModel.loadExtendedAttributes(menuIndex, {'x-canonical-wifi-ap-is-adhoc': 'bool',
96− 'x-canonical-wifi-ap-is-secure': 'bool',
97− 'x-canonical-wifi-ap-strength-action': 'string'});
98− }
99−
100− signal activate()
101−
102− text: menuData && menuData.label || ""
103− enabled: menuData && menuData.sensitive || false
104− iconName: {
105− var imageName = "nm-signal-100";
106−
107− if (adHoc) {
108− imageName = "nm-adhoc";
109− } else if (signalStrength == 0) {
110− imageName = "nm-signal-00";
111− } else if (signalStrength <= 25) {
112− imageName = "nm-signal-25";
113− } else if (signalStrength <= 50) {
114− imageName = "nm-signal-50";
115− } else if (signalStrength <= 75) {
116− imageName = "nm-signal-75";
117− }
118−
119− if (secure) {
120− imageName += "-secure";
121− }
122− return imageName;
123− }
124− iconFrame: false
125− control: CheckBox {
126− id: checkBoxActive
127−
128− onClicked: {
129− accessPoint.activate();
130− }
131− }
132− style: Rectangle {
133− color: "#4c000000"
134− }
135−
136− Component.onCompleted: {
137− loadAttributes();
138− }
139− onUnityMenuModelChanged: {
140− loadAttributes();
141− }
142− onMenuIndexChanged: {
143− loadAttributes();
144− }
145− onCheckedChanged: {
146− // Can't rely on binding. Checked is assigned on click.
147− checkBoxActive.checked = checked;
148− }
149− onActivate: unityMenuModel.activate(menuIndex);
150− }
151− }
152−
153− Column {
154− id: column
155− spacing: units.gu(2)
156− anchors.top: content.top
157− anchors.bottom: content.bottom
158− anchors.left: wifiPage.left
159− anchors.right: wifiPage.right
160−
161− Label {
162− id: label
163− anchors.left: parent.left
164− anchors.leftMargin: leftMargin
165− anchors.right: parent.right
166− anchors.rightMargin: rightMargin
167− fontSize: "small"
168− text: mainMenu.count > 0 ? i18n.tr("Available networks…")
169− : i18n.tr("No available networks.")
170− }
171−
172− Flickable {
173− anchors.left: parent.left
174− anchors.right: parent.right
175− height: column.height - label.height - column.spacing
176− contentHeight: contentItem.childrenRect.height
177− clip: true
178− flickDeceleration: 1500 * units.gridUnit / 8
179− maximumFlickVelocity: 2500 * units.gridUnit / 8
180− boundsBehavior: (contentHeight > height) ? Flickable.DragAndOvershootBounds : Flickable.StopAtBounds
181−
182− Column {
183− anchors.left: parent.left
184− anchors.right: parent.right
185−
186− Repeater {
187− id: mainMenu
188−
189− model: menuModel
190−
191− delegate: Loader {
192− id: loader
193−
194− readonly property bool isAccessPoint: model.type === "unity.widgets.systemsettings.tablet.accesspoint"
195−
196− anchors.left: parent.left
197− anchors.right: parent.right
198− height: isAccessPoint ? units.gu(6) : 0
199− asynchronous: true
200− sourceComponent: isAccessPoint ? accessPointComponent : null
201−
202− onLoaded: {
203− item.menuData = Qt.binding(function() { return model; });
204− item.menuIndex = Qt.binding(function() { return index; });
205− }
206− }
207− }
208− }
209− }
210− }
211−
212− Component {
213− id: forwardButton
214− LocalComponents.StackButton {
215− text: (connected || mainMenu.count === 0) ? i18n.tr("Continue") : i18n.tr("Skip")
216− onClicked: pageStack.next()
217− }
218− }
219−}
qml/Wizard/Pages/50-location.qmldeleted−150
@@ -1,150 +0,0 @@
1−/*
2− * Copyright (C) 2013-2015 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")
28− forwardButtonSourceComponent: forwardButton
29−
30− 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− Column {
54− id: column
55− anchors.fill: content
56− spacing: units.gu(3)
57−
58− Label {
59− anchors.left: parent.left
60− anchors.right: parent.right
61− wrapMode: Text.Wrap
62− text: i18n.tr("Let the phone detect your location:")
63− }
64−
65− LocalComponents.CheckableSetting {
66− id: gpsCheck
67− objectName: "gpsCheck"
68− showDivider: false
69− text: i18n.tr("Using GPS only (less accurate)")
70− onTriggered: {
71− gpsCheck.checked = true;
72− hereCheck.checked = false;
73− nopeCheck.checked = false;
74− }
75− }
76−
77− Column {
78− anchors.left: parent.left
79− anchors.right: parent.right
80− height: childrenRect.height
81−
82− LocalComponents.CheckableSetting {
83− id: hereCheck
84− objectName: "hereCheck"
85− showDivider: false
86− text: i18n.tr("Using GPS, anonymized Wi-Fi and cellular network info (recommended)")
87− checked: true
88− onTriggered: {
89− gpsCheck.checked = false;
90− hereCheck.checked = true;
91− nopeCheck.checked = false;
92− }
93− }
94−
95− Label {
96− objectName: "hereTermsLink"
97− anchors.left: parent.left
98− anchors.leftMargin: hereCheck.labelOffset
99− anchors.right: parent.right
100− wrapMode: Text.Wrap
101− linkColor: theme.palette.normal.foregroundText
102− // Translators: HERE is a trademark for Nokia's location service, you probably shouldn't translate it
103− text: i18n.tr("By selecting this option you agree to the Nokia HERE <a href='#'>terms and conditions</a>.")
104− onLinkActivated: pageStack.load(Qt.resolvedUrl("here-terms.qml"))
105− }
106− }
107−
108− LocalComponents.CheckableSetting {
109− id: nopeCheck
110− objectName: "nopeCheck"
111− showDivider: false
112− text: i18n.tr("Not at all")
113− onTriggered: {
114− gpsCheck.checked = false;
115− hereCheck.checked = false;
116− nopeCheck.checked = true;
117− }
118− }
119−
120− Label {
121− anchors.left: parent.left
122− anchors.right: parent.right
123− wrapMode: Text.Wrap
124− text: i18n.tr("You can change your mind later in <b>System Settings</b>.")
125− }
126− }
127−
128− Component {
129− id: forwardButton
130− LocalComponents.StackButton {
131− text: i18n.tr("Continue")
132− onClicked: {
133− var locationOn = gpsCheck.checked || hereCheck.checked;
134− var gpsOn = gpsCheck.checked || hereCheck.checked;
135− var hereOn = hereCheck.checked;
136−
137− // location service doesn't currently listen to updateState
138− // requests, so we activate the actions if needed.
139− if (locationActionGroup.location.state != locationOn) {
140− locationActionGroup.location.activate();
141− }
142− if (locationActionGroup.gps.state != gpsOn) {
143− locationActionGroup.gps.activate();
144− }
145− AccountsService.hereEnabled = hereOn;
146− pageStack.next()
147− }
148− }
149− }
150−}
qml/Wizard/Pages/50-timezone.qmlnew file+275
@@ -0,0 +1,275 @@
1+/*
2+ * Copyright (C) 2015 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 Wizard 0.1
21+import Ubuntu.SystemSettings.TimeDate 1.0
22+import Utils 0.1 as Utils
23+import ".." as LocalComponents
24+
25+LocalComponents.Page {
26+ id: tzPage
27+ objectName: "tzPage"
28+
29+ title: i18n.tr("Time Zone")
30+ forwardButtonSourceComponent: forwardButton
31+
32+ property string selectedTimeZone: ""
33+ readonly property bool showingMap: wideMode && width >= units.gu(110)
34+
35+ // for testing
36+ readonly property alias tdModule: timeDatePanel
37+
38+ function highlightTimezone(offset) {
39+ highlightImage.source = "data/timezonemap/timezone_" + offset + ".png";
40+ }
41+
42+ // geo coords conversion functions (adapted from libtimezonemap)
43+ function radians(degrees) {
44+ return degrees * Math.PI / 180;
45+ }
46+
47+ function longitudeToX(longitude, map_width) {
48+ const xdeg_offset = -6;
49+ const x = (map_width * (180.0 + longitude) / 360.0) + (map_width * xdeg_offset / 180.0);
50+ return x;
51+ }
52+
53+ function latitudeToY(latitude, map_height) {
54+ const bottom_lat = -59;
55+ const top_lat = 81;
56+ const top_per = top_lat / 180.0;
57+
58+ var y = 1.25 * Math.log(Math.tan(0.25*Math.PI + 0.4 * radians(latitude)));
59+ const full_range = 4.6068250867599998;
60+ const top_offset = full_range * top_per;
61+ const map_range = Math.abs(1.25 * Math.log(Math.tan(0.25*Math.PI + 0.4 * radians(bottom_lat))) - top_offset);
62+ y = Math.abs(y - top_offset);
63+ y = y / map_range;
64+ y = y * map_height;
65+ return y;
66+ }
67+
68+ function resetViews() {
69+ selectedTimeZone = ""
70+ tzList.currentIndex = -1
71+ highlightImage.source = ""
72+ pinImage.x = 0;
73+ pinImage.y = 0;
74+ }
75+
76+ UbuntuTimeDatePanel {
77+ id: timeDatePanel
78+ }
79+
80+ onContentAnimationRunningChanged: {
81+ if (!contentAnimationRunning) {
82+ if (tzList.count == 1) { // preselect the first (and only) TZ
83+ var tz = tzList.itemAt(0,0);
84+ if (!!tz) {
85+ tz.clicked();
86+ }
87+ }
88+
89+ resetViews();
90+ searchField.forceActiveFocus();
91+ }
92+ }
93+
94+ Component {
95+ id: tzComponent
96+ ListItem {
97+ id: tz
98+ objectName: "tz" + index
99+ highlightColor: backgroundColor
100+ divider.colorFrom: dividerColor
101+ divider.colorTo: backgroundColor
102+ readonly property bool currentTz: ListView.view.currentIndex === index
103+
104+ Column {
105+ anchors.verticalCenter: parent.verticalCenter
106+ anchors.left: parent.left
107+ anchors.leftMargin: !wideMode ? staticMargin : 0
108+ anchors.right: image.left
109+ anchors.rightMargin: units.gu(2)
110+
111+ Label {
112+ id: cityLabel
113+ text: displayName
114+ font.weight: tz.currentTz ? Font.Normal : Font.Light
115+ fontSize: "medium"
116+ color: textColor
117+ elide: Text.ElideMiddle
118+ maximumLineCount: 1
119+ width: parent.width
120+ }
121+ Label {
122+ id: timeLabel
123+ text: Utils.TimezoneFormatter.currentTimeInTimezoneWithAbbrev(timeZone)
124+ font.weight: tz.currentTz ? Font.Normal : Font.Light
125+ fontSize: "small"
126+ color: textColor
127+ }
128+ }
129+ Image {
130+ id: image
131+ anchors {
132+ right: parent.right
133+ verticalCenter: parent.verticalCenter
134+ rightMargin: !wideMode ? staticMargin : 0
135+ }
136+ fillMode: Image.PreserveAspectFit
137+ height: units.gu(1.5)
138+
139+ source: "data/Tick@30.png"
140+ visible: tz.currentTz
141+ }
142+
143+ onClicked: {
144+ highlightTimezone(offset);
145+ ListView.view.currentIndex = index;
146+ selectedTimeZone = timeZone;
147+ //print("Clicked at city with coords:", longitude, latitude);
148+ //print("Clicked on TZ:", timeZone);
149+ //print("Highlight at (x,y):", longitudeToX(longitude, map.width), latitudeToY(latitude, map.height));
150+ pinImage.x = Qt.binding(function() { return longitudeToX(longitude, map.width) - pinImage.width; });
151+ pinImage.y = Qt.binding(function() { return latitudeToY(latitude, map.height) - pinImage.height; });
152+ }
153+ }
154+ }
155+
156+
157+ ColumnLayout {
158+ id: leftColumn
159+ anchors {
160+ left: content.left
161+ top: content.top
162+ bottom: content.bottom
163+ right: !showingMap ? content.right : undefined
164+ leftMargin: showingMap ? staticMargin : (wideMode ? tzPage.leftMargin : 0)
165+ rightMargin: showingMap ? staticMargin : (wideMode ? tzPage.rightMargin : 0)
166+ topMargin: customMargin
167+ }
168+
169+ width: Math.min(parent.width, units.gu(34))
170+
171+ LocalComponents.WizardTextField {
172+ id: searchField
173+ objectName: "tzFilter"
174+ anchors.left: parent.left
175+ anchors.right: parent.right
176+ anchors.leftMargin: !showingMap && !wideMode ? staticMargin : undefined
177+ anchors.rightMargin: !showingMap && !wideMode ? staticMargin : undefined
178+ placeholderText: i18n.tr("Enter your city")
179+ inputMethodHints: Qt.ImhNoPredictiveText
180+ onTextChanged: resetViews();
181+ }
182+
183+ ListView {
184+ Layout.fillHeight: true
185+ id: tzList
186+ objectName: "tzList"
187+ clip: true
188+ anchors.left: parent.left
189+ anchors.right: parent.right
190+ currentIndex: -1
191+ model: TimeZoneModel {
192+ id: timeZoneModel
193+ filter: searchField.text
194+ country: i18n.language.split('_')[1].split('.')[0]
195+ }
196+ delegate: tzComponent
197+ }
198+
199+ ActivityIndicator {
200+ anchors.centerIn: tzList
201+ running: tzList.count == 0 &&
202+ searchField.length > 0 &&
203+ timeZoneModel.listUpdating
204+ visible: running
205+ }
206+ }
207+
208+ Item {
209+ id: mapContainer
210+ visible: showingMap && !contentAnimationRunning
211+ enabled: visible
212+
213+ anchors {
214+ left: leftColumn.right
215+ leftMargin: units.gu(4)
216+ right: content.right
217+ rightMargin: staticMargin
218+ top: content.top
219+ topMargin: customMargin
220+ bottom: parent.bottom
221+ bottomMargin: buttonBarHeight
222+ }
223+
224+ Item {
225+ id: map
226+ width: Math.min(parent.width, height * 1.95) // keep our aspect ratio
227+ height: parent.height
228+ anchors {
229+ centerIn: parent
230+ }
231+
232+ Image {
233+ id: backgroundImage
234+ source: "data/timezonemap/map.png"
235+ sourceSize: Qt.size(map.width, map.height)
236+ fillMode: Image.PreserveAspectFit
237+ smooth: false
238+ visible: mapContainer.visible
239+ asynchronous: true
240+ anchors.fill: parent
241+ }
242+
243+ Image {
244+ id: highlightImage
245+ sourceSize: Qt.size(map.width, map.height)
246+ fillMode: Image.PreserveAspectFit
247+ smooth: false
248+ visible: selectedTimeZone != ""
249+ asynchronous: true
250+ anchors.fill: backgroundImage
251+ }
252+
253+ Image {
254+ id: pinImage
255+ source: "data/timezonemap/pin.png"
256+ visible: x != 0 && y != 0
257+ width: units.dp(12)
258+ height: units.dp(20)
259+ z: map.z + 1
260+ }
261+ }
262+ }
263+
264+ Component {
265+ id: forwardButton
266+ LocalComponents.StackButton {
267+ text: i18n.tr("Next")
268+ enabled: selectedTimeZone != ""
269+ onClicked: {
270+ timeDatePanel.timeZone = selectedTimeZone;
271+ pageStack.next();
272+ }
273+ }
274+ }
275+}
qml/Wizard/Pages/60-reporting.qml → qml/Wizard/Pages/60-account.qmlrenamed+30−20
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2013,2014 Canonical, Ltd.
2+ * Copyright (C) 2015-2016 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
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
5 * it under the terms of the GNU General Public License as published by
@@ -16,49 +16,59 @@
16
16
17import QtQuick 2.4
17import QtQuick 2.4
18import Ubuntu.Components 1.3
18import Ubuntu.Components 1.3
19−import Ubuntu.SystemSettings.Diagnostics 1.0
19+import AccountsService 0.1
20import ".." as LocalComponents
20import ".." as LocalComponents
21
21
22LocalComponents.Page {
22LocalComponents.Page {
23− id: reportingPage
23+ objectName: "accountPage"
24− objectName: "reportingPage"
24+ title: i18n.tr("Personalize Your Device")
25
25
26− title: i18n.tr("Improving your experience")
27 forwardButtonSourceComponent: forwardButton
26 forwardButtonSourceComponent: forwardButton
28
27
29− skipValid: false
28+ QtObject {
30− skip: !diagnostics.reportCrashes // skip the page when the system is configured not to report crashes
29+ id: d
31−
30+ readonly property string validName: nameInput.text.trim()
32− UbuntuDiagnostics {
33− id: diagnostics
34− Component.onCompleted: reportingPage.skipValid = true;
35 }
31 }
36
32
37 Column {
33 Column {
38 id: column
34 id: column
39− anchors.fill: content
40− spacing: units.gu(2)
35+ spacing: units.gu(1)
36+ anchors {
37+ fill: content
38+ leftMargin: parent.leftMargin
39+ rightMargin: parent.rightMargin
40+ topMargin: customMargin
41+ }
41
42
43+ // name
42 Label {
44 Label {
45+ id: nameLabel
43 anchors.left: parent.left
46 anchors.left: parent.left
44 anchors.right: parent.right
47 anchors.right: parent.right
45− wrapMode: Text.Wrap
48+ text: i18n.tr("Preferred Name")
46− text: i18n.tr("Your phone is set up to automatically report errors to Canonical and its partners, the makers of the operating system.")
49+ color: textColor
50+ font.weight: Font.Light
47 }
51 }
48
52
49− Label {
53+ LocalComponents.WizardTextField {
54+ id: nameInput
55+ objectName: "nameInput"
50 anchors.left: parent.left
56 anchors.left: parent.left
51 anchors.right: parent.right
57 anchors.right: parent.right
52− wrapMode: Text.Wrap
58+ inputMethodHints: Qt.ImhNoPredictiveText
53− text: i18n.tr("This can be disabled in <b>System Settings</b> under <b>Security &amp; Privacy</b>")
54 }
59 }
55 }
60 }
56
61
57 Component {
62 Component {
58 id: forwardButton
63 id: forwardButton
59 LocalComponents.StackButton {
64 LocalComponents.StackButton {
60− text: i18n.tr("Continue")
65+ text: d.validName ? i18n.tr("Next") : i18n.tr("Skip")
66+ onClicked: {
67+ if (d.validName) {
68+ AccountsService.realName = d.validName;
69+ }
61− onClicked: pageStack.next()
70+ pageStack.next();
71+ }
62 }
72 }
63 }
73 }
64}
74}
qml/Wizard/Pages/70-passwd-type.qmlnew file+166
@@ -0,0 +1,166 @@
1+/*
2+ * Copyright (C) 2014-2015 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.Components.ListItems 1.3
20+import Ubuntu.SystemSettings.SecurityPrivacy 1.0
21+import ".." as LocalComponents
22+
23+/**
24+ * One quirk with this page: we don't actually set the password. We avoid
25+ * doing it here because the user can come back to this page and change their
26+ * answer. We don't run as root, so if we did set the password immediately,
27+ * we'd need to prompt for their previous password when they came back and
28+ * changed their answer. Which is silly UX. So instead, we just keep track
29+ * of their choice and set the password at the end (see Pages.qml).
30+ * Setting the password shouldn't fail, since Ubuntu Touch has loose password
31+ * requirements, but we'll check what we can here. Ideally we'd be able to ask
32+ * the system if a password is legal without actually setting that password.
33+ */
34+
35+LocalComponents.Page {
36+ id: passwdPage
37+ objectName: "passwdPage"
38+
39+ title: i18n.tr("Lock Screen")
40+ forwardButtonSourceComponent: forwardButton
41+
42+ // If the user has set a password some other way (via ubuntu-device-flash
43+ // or this isn't the first time the wizard has been run, etc). We can't
44+ // properly set the password again, so let's not pretend we can.
45+ skip: securityPrivacy.securityType !== UbuntuSecurityPrivacyPanel.Swipe
46+
47+ function indexToMethod(index) {
48+ if (index === 0/* || index === 1*/)
49+ return UbuntuSecurityPrivacyPanel.Passphrase;
50+ else if (index === 1/*2*/)
51+ return UbuntuSecurityPrivacyPanel.Passcode;
52+ else
53+ return UbuntuSecurityPrivacyPanel.Swipe;
54+ }
55+
56+// Component.onCompleted: {
57+// if (root.password !== "") // the user has set a password as part of the previous page
58+// selector.currentIndex = 0;
59+// else
60+// selector.currentIndex = 1;
61+// }
62+
63+ Item {
64+ id: column
65+ anchors.fill: content
66+ anchors.topMargin: customMargin
67+ anchors.leftMargin: wideMode ? parent.leftMargin : 0
68+ anchors.rightMargin: wideMode ? parent.rightMargin : 0
69+
70+ ListView {
71+ id: selector
72+ anchors.left: parent.left
73+ anchors.right: parent.right
74+ boundsBehavior: Flickable.StopAtBounds
75+ clip: true
76+ height: childrenRect.height
77+
78+ // this is the order we want to display it; cf indexToMethod()
79+ model: [/*UbuntuSecurityPrivacyPanel.Passphrase, */UbuntuSecurityPrivacyPanel.Passphrase,
80+ UbuntuSecurityPrivacyPanel.Passcode, UbuntuSecurityPrivacyPanel.Swipe]
81+
82+ delegate: ListItem {
83+ id: itemDelegate
84+ objectName: "passwdDelegate" + index
85+ readonly property bool isCurrent: index === ListView.view.currentIndex
86+ highlightColor: backgroundColor
87+ divider.colorFrom: dividerColor
88+ divider.colorTo: backgroundColor
89+ Label {
90+ anchors.verticalCenter: parent.verticalCenter;
91+ anchors.left: parent.left
92+ anchors.leftMargin: column.anchors.leftMargin == 0 ? staticMargin : 0
93+ fontSize: "medium"
94+ color: textColor
95+ font.weight: itemDelegate.isCurrent ? Font.Normal : Font.Light
96+ text: {
97+ switch (index) {
98+// case 0:
99+// return i18n.ctr("Label: Type of security method", "Ubuntu administrator password");
100+ case 0:
101+ return i18n.ctr("Label: Type of security method", "Create new password");
102+ case 1:
103+ return i18n.ctr("Label: Type of security method", "Create passcode (numbers only)");
104+ case 2:
105+ return i18n.ctr("Label: Type of security method", "No lock code");
106+ }
107+ }
108+ width: parent.width
109+ wrapMode: Text.WordWrap
110+ }
111+
112+ Image {
113+ anchors {
114+ right: parent.right
115+ verticalCenter: parent.verticalCenter
116+ rightMargin: column.anchors.rightMargin == 0 ? staticMargin : 0
117+ }
118+ fillMode: Image.PreserveAspectFit
119+ height: units.gu(1.5)
120+
121+ source: "data/Tick@30.png"
122+ visible: itemDelegate.isCurrent
123+ }
124+
125+ onClicked: {
126+ selector.currentIndex = index;
127+ }
128+ }
129+ }
130+
131+ Rectangle {
132+ id: divider2
133+ anchors.left: parent.left
134+ anchors.right: parent.right
135+ anchors.top: selector.bottom
136+ height: units.dp(1)
137+ color: dividerColor
138+ }
139+ }
140+
141+ Component {
142+ id: forwardButton
143+ LocalComponents.StackButton {
144+ text: i18n.tr("Next")
145+ onClicked: {
146+ var method = indexToMethod(selector.currentIndex);
147+ root.passwordMethod = method;
148+
149+ if (method === UbuntuSecurityPrivacyPanel.Passphrase) { // any password
150+ if (selector.currentIndex == 0/*1*/)
151+ pageStack.load(Qt.resolvedUrl("password-set.qml")); // let the user choose a new password
152+ else
153+ pageStack.next(); // got the password already, go next page
154+ } else if (method === UbuntuSecurityPrivacyPanel.Passcode) { // passcode
155+ if (wideMode) {
156+ pageStack.load(Qt.resolvedUrl("passcode-desktop.qml"));
157+ } else {
158+ pageStack.load(Qt.resolvedUrl("passcode-set.qml"));
159+ }
160+ } else { //swipe
161+ pageStack.next();
162+ }
163+ }
164+ }
165+ }
166+}
qml/Wizard/Pages/75-report-check.qmlnew file+91
@@ -0,0 +1,91 @@
1+/*
2+ * Copyright (C) 2015 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/80-finished.qml+94−16
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2013,2014 Canonical, Ltd.
2+ * Copyright (C) 2013-2015 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
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
5 * it under the terms of the GNU General Public License as published by
@@ -21,37 +21,115 @@ import ".." as LocalComponents
21LocalComponents.Page {
21LocalComponents.Page {
22 objectName: "finishedPage"
22 objectName: "finishedPage"
23
23
24− title: i18n.tr("All done")
25− forwardButtonSourceComponent: forwardButton
26 hasBackButton: false
24 hasBackButton: false
25+ customTitle: true
26+ lastPage: true
27+ buttonBarVisible: false
27
28
28− Column {
29+ Component.onCompleted: {
30+ state = "reanchored";
31+ }
32+
33+ states: State {
34+ name: "reanchored"
35+ AnchorChanges { target: bgImage; anchors.top: parent.top; anchors.bottom: parent.bottom }
36+ AnchorChanges { target: column;
37+ anchors.verticalCenter: parent.verticalCenter;
38+ anchors.top: undefined
39+ }
40+ }
41+
42+ transitions: Transition {
43+ ParallelAnimation {
44+ AnchorAnimation {
45+ targets: [bgImage, column]
46+ duration: UbuntuAnimation.SlowDuration
47+ easing.type: Easing.OutCirc
48+ }
49+ NumberAnimation {
50+ targets: [bgImage,column]
51+ property: "opacity"
52+ from: 0
53+ to: 1
54+ duration: UbuntuAnimation.SlowDuration
55+ easing.type: Easing.OutCirc
56+ }
57+ }
58+ }
59+
60+ Image {
61+ id: bgImage
62+ source: wideMode ? "data/Desktop_splash_screen_bkg.png" : "data/Phone_splash_screen_bkg.png"
63+ scale: Image.PreserveAspectFit
64+ anchors.left: parent.left
65+ anchors.right: parent.right
66+ anchors.bottom: parent.top // outside to let it slide down
67+ visible: opacity > 0
68+ }
69+
70+ Item {
29 id: column
71 id: column
30− anchors.fill: content
72+ anchors.leftMargin: leftMargin
31− spacing: units.gu(1)
73+ anchors.rightMargin: rightMargin
74+ anchors.left: parent.left
75+ anchors.right: parent.right
76+ anchors.top: parent.bottom // outside to let it slide in
77+ height: childrenRect.height
78+ visible: opacity > 0
32
79
33 Label {
80 Label {
81+ id: welcomeLabel
34 anchors.left: parent.left
82 anchors.left: parent.left
35 anchors.right: parent.right
83 anchors.right: parent.right
84+ horizontalAlignment: Text.AlignHCenter
36 wrapMode: Text.Wrap
85 wrapMode: Text.Wrap
37− fontSize: "large"
86+ fontSize: "x-large"
38− font.bold: true
87+ font.weight: Font.Light
88+ lineHeight: 1.2
39− text: i18n.tr("Nice work!")
89+ text: i18n.tr("Welcome to Ubuntu")
90+ color: whiteColor
40 }
91 }
41
92
42 Label {
93 Label {
94+ id: welcomeText
43 anchors.left: parent.left
95 anchors.left: parent.left
44 anchors.right: parent.right
96 anchors.right: parent.right
97+ anchors.top: welcomeLabel.bottom
98+ anchors.topMargin: units.gu(2)
99+ horizontalAlignment: Text.AlignHCenter
45 wrapMode: Text.Wrap
100 wrapMode: Text.Wrap
101+ fontSize: "large"
102+ font.weight: Font.Light
103+ lineHeight: 1.2
46− text: i18n.tr("Your device is now ready to use.")
104+ text: i18n.tr("You are ready to use your device now")
105+ color: whiteColor
47 }
106 }
48− }
49
107
50− Component {
108+ Rectangle {
51− id: forwardButton
109+ anchors {
52− LocalComponents.StackButton {
110+ top: welcomeText.bottom
111+ horizontalCenter: parent.horizontalCenter
112+ topMargin: units.gu(4)
113+ }
114+ color: "transparent"
115+ border.width: units.dp(1)
116+ border.color: whiteColor
117+ radius: units.dp(4)
118+ width: buttonLabel.paintedWidth + units.gu(6)
119+ height: buttonLabel.paintedHeight + units.gu(1.8)
120+
121+ Label {
122+ id: buttonLabel
123+ color: whiteColor
53− text: i18n.tr("Finish")
124+ text: i18n.tr("Get Started")
125+ fontSize: "medium"
126+ anchors.centerIn: parent
127+ }
128+ AbstractButton {
129+ objectName: "finishButton"
130+ anchors.fill: parent
54− onClicked: root.quitWizard()
131+ onClicked: root.quitWizard()
132+ }
55 }
133 }
56 }
134 }
57}
135}
qml/Wizard/Pages/data/Desktop_header_bkg.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/Desktop_splash_screen_bkg.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/Phone_header_bkg.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/Phone_splash_screen_bkg.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/Tick@30.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/meet_ubuntu_simcard@30.pngdeleted

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/map.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/pin.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_-1.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_-10.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_-11.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_-2.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_-3.5.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_-3.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_-4.5.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_-4.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_-5.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_-6.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_-7.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_-8.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_-9.5.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_-9.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_0.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_1.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_10.5.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_10.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_11.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_12.75.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_12.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_13.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_2.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_3.5.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_3.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_4.5.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_4.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_5.5.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_5.75.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_5.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_6.5.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_6.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_7.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_8.5.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_8.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_9.5.pngnew file

Binary file not shown.

qml/Wizard/Pages/data/timezonemap/timezone_9.pngnew file

Binary file not shown.

qml/Wizard/Pages/here-terms.qml+72−65
@@ -15,8 +15,6 @@
15 */
15 */
16
16
17import QtQuick 2.4
17import QtQuick 2.4
18−import AccountsService 0.1
19−import Qt.labs.folderlistmodel 2.1
20import Ubuntu.Components 1.3
18import Ubuntu.Components 1.3
21import Ubuntu.Web 0.2
19import Ubuntu.Web 0.2
22import ".." as LocalComponents
20import ".." as LocalComponents
@@ -26,86 +24,93 @@ LocalComponents.Page {
26
24
27 title: i18n.tr("Terms & Conditions")
25 title: i18n.tr("Terms & Conditions")
28 customBack: true
26 customBack: true
27+ customTitle: true
29
28
30− FolderListModel {
29+ onBackClicked: {
31− id: termsModel
30+ if (webview.visible) {
32− folder: AccountsService.hereLicensePath
31+ showBrowser(false);
33− nameFilters: ["*.html"]
34− showDirs: false
35− showOnlyReadable: true
36− onCountChanged: loadFileContent()
37− }
38−
39− function makeFileName(lang, country) {
40− return lang + "_" + country + ".html"
41− }
42−
43− function defaultCountryForLanguage(lang) {
44− if (lang === "da") return "DK"
45− if (lang === "en") return "US"
46− if (lang === "ko") return "KR"
47− if (lang === "zh") return "CN"
48− return lang.toUpperCase()
49− }
50−
51− function determineFileName() {
52− var codes = i18n.language.split(".")[0].split("_")
53− var defaultCountry = defaultCountryForLanguage(codes[0])
54− if (codes.count === 1)
55− codes = [codes[0], defaultCountry]
56− var perfectMatch = makeFileName(codes[0], codes[1])
57− var nearMatch = makeFileName(codes[0], defaultCountry)
58− var nearMatchExists = false
59−
60− for (var i = 0; i < termsModel.count; i++) {
61− var fileName = termsModel.get(i, "fileName")
62− if (fileName == perfectMatch) {
63− return perfectMatch
64− } else if (fileName == nearMatch) {
65− nearMatchExists = true
66− }
67− }
68−
69− if (nearMatchExists) {
70− return nearMatch
71 } else {
32 } else {
72− return makeFileName("en", "US")
33+ pageStack.prev();
73 }
34 }
74 }
35 }
75
36
76− function loadFileContent() {
37+ function showBrowser(show) {
77− var xhr = new XMLHttpRequest
38+ if (show) {
78− xhr.open("GET", AccountsService.hereLicensePath + "/" + determineFileName())
39+ label1.visible = false;
79− xhr.onreadystatechange = function() {
40+ label2.visible = false;
80− if (xhr.readyState == XMLHttpRequest.DONE) {
41+ label3.visible = false;
81− termsLabel.text = xhr.responseText
42+ label4.visible = false;
82− }
83− }
84− xhr.send()
85− }
86−
87− onBackClicked: {
88− if (webview.visible) {
89− termsLabel.visible = true
43+ webview.visible = true;
90 } else {
44 } else {
91− pageStack.prev()
45+ webview.visible = false;
46+ label1.visible = true;
47+ label2.visible = true;
48+ label3.visible = true;
49+ label4.visible = true;
92 }
50 }
93 }
51 }
94
52
95 Column {
53 Column {
96 id: column
54 id: column
97 anchors.fill: content
55 anchors.fill: content
56+ anchors.leftMargin: staticMargin
57+ anchors.rightMargin: wideMode ? parent.rightMargin : staticMargin
58+ spacing: units.gu(3)
59+
60+ Label {
61+ id: label1
62+ anchors.left: parent.left
63+ anchors.right: parent.right
64+ wrapMode: Text.Wrap
65+ color: textColor
66+ fontSize: "small"
67+ font.weight: Font.Light
68+ lineHeight: 1.2
69+ text: i18n.tr("Your device uses positioning technologies provided by HERE.")
70+ }
71+
72+ Label {
73+ id: label2
74+ anchors.left: parent.left
75+ anchors.right: parent.right
76+ wrapMode: Text.Wrap
77+ color: textColor
78+ fontSize: "small"
79+ font.weight: Font.Light
80+ lineHeight: 1.2
81+ text: i18n.tr("To provide you with positioning services and to improve their quality, HERE collects " +
82+ "information about nearby cell towers and Wi-Fi hotspots around your current location " +
83+ "whenever your position is being found.")
84+ }
85+
86+ Label {
87+ id: label3
88+ anchors.left: parent.left
89+ anchors.right: parent.right
90+ wrapMode: Text.Wrap
91+ color: textColor
92+ fontSize: "small"
93+ font.weight: Font.Light
94+ lineHeight: 1.2
95+ text: i18n.tr("The information collected is used to analyze the service and to " +
96+ "improve the use of service, but not to identify you personally.")
97+ }
98
98
99 Label {
99 Label {
100− id: termsLabel
100+ id: label4
101− objectName: "termsLabel"
102 anchors.left: parent.left
101 anchors.left: parent.left
103 anchors.right: parent.right
102 anchors.right: parent.right
104 wrapMode: Text.Wrap
103 wrapMode: Text.Wrap
105− linkColor: theme.palette.normal.foregroundText
104+ color: textColor
105+ fontSize: "small"
106+ font.weight: Font.Light
107+ lineHeight: 1.2
108+ linkColor: UbuntuColors.orange
109+ text: i18n.tr("By continuing, you agree to the HERE platform <a href=\"http://here.com/terms/service-terms\">Service Terms</a> " +
110+ "and <a href=\"http://here.com/privacy/privacy-policy\">Privacy Policy</a>.");
106 onLinkActivated: {
111 onLinkActivated: {
112+ showBrowser(true);
107− webview.url = link
113+ webview.url = link;
108− termsLabel.visible = false
109 }
114 }
110 }
115 }
111
116
@@ -114,8 +119,10 @@ LocalComponents.Page {
114 objectName: "webview"
119 objectName: "webview"
115 anchors.left: parent.left
120 anchors.left: parent.left
116 anchors.right: parent.right
121 anchors.right: parent.right
122+ anchors.leftMargin: -leftMargin
123+ anchors.rightMargin: -rightMargin
117 height: parent.height
124 height: parent.height
118− visible: !termsLabel.visible
125+ visible: false
119 }
126 }
120 }
127 }
121}
128}
qml/Wizard/Pages/passwd-confirm.qml → qml/Wizard/Pages/passcode-confirm.qmlrenamed+12−29
@@ -26,11 +26,10 @@ import "../../Components" as UnityComponents
26 */
26 */
27
27
28LocalComponents.Page {
28LocalComponents.Page {
29− id: passwdConfirmPage
29+ id: passcodeConfirmPage
30− objectName: "passwdConfirmPage"
30+ objectName: "passcodeConfirmPage"
31− forwardButtonSourceComponent: forwardButton
31+ customTitle: true
32−
32+ backButtonText: i18n.tr("Cancel")
33− skip: root.passwordMethod === UbuntuSecurityPrivacyPanel.Swipe
34
33
35 // If we are entering this page, clear any saved password and get focus
34 // If we are entering this page, clear any saved password and get focus
36 onEnabledChanged: if (enabled) lockscreen.clear(false)
35 onEnabledChanged: if (enabled) lockscreen.clear(false)
@@ -38,32 +37,26 @@ LocalComponents.Page {
38 UnityComponents.Lockscreen {
37 UnityComponents.Lockscreen {
39 id: lockscreen
38 id: lockscreen
40 anchors {
39 anchors {
41− fill: parent
40+ fill: content
42− topMargin: topMargin
43− leftMargin: leftMargin
44− rightMargin: rightMargin
45− bottomMargin: buttonMargin
46 }
41 }
47
42
48− infoText: root.passwordMethod === UbuntuSecurityPrivacyPanel.Passphrase ?
43+ infoText: i18n.tr("Confirm passcode")
49− i18n.tr("Confirm passphrase") :
44+
50− i18n.tr("Confirm passcode")
45+ errorText: i18n.tr("Incorrect passcode.") + "\n" + i18n.ctr("Enter the passcode again", "Please re-enter.")
51
46
52− errorText: root.passwordMethod === UbuntuSecurityPrivacyPanel.Passphrase ?
47+ foregroundColor: textColor
53− i18n.tr("Sorry, incorrect passphrase.") + "\n" + i18n.tr("Please try again.") :
54− i18n.tr("Sorry, incorrect passcode.") + "\n" + i18n.tr("Please try again.")
55
48
56 showEmergencyCallButton: false
49 showEmergencyCallButton: false
57 showCancelButton: false
50 showCancelButton: false
58− alphaNumeric: root.passwordMethod === UbuntuSecurityPrivacyPanel.Passphrase
51+ alphaNumeric: false
59 minPinLength: 4
52 minPinLength: 4
60 maxPinLength: 4
53 maxPinLength: 4
61
54
62 onEntered: {
55 onEntered: {
63 if (passphrase === root.password) {
56 if (passphrase === root.password) {
64− confirmTimer.start()
57+ confirmTimer.start();
65 } else {
58 } else {
66− clear(true)
59+ clear(true);
67 }
60 }
68 }
61 }
69
62
@@ -73,14 +66,4 @@ LocalComponents.Page {
73 onTriggered: pageStack.next()
66 onTriggered: pageStack.next()
74 }
67 }
75 }
68 }
76−
77− Component {
78− id: forwardButton
79− LocalComponents.StackButton {
80− visible: root.passwordMethod === UbuntuSecurityPrivacyPanel.Passphrase
81− enabled: root.password === lockscreen.passphrase
82− text: i18n.tr("Continue")
83− onClicked: pageStack.next()
84− }
85− }
86}
69}
qml/Wizard/Pages/passcode-desktop.qmlnew file+132
@@ -0,0 +1,132 @@
1+/*
2+ * Copyright (C) 2015 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 ".." as LocalComponents
21+
22+/**
23+ * See the main passwd-type page for an explanation of why we don't actually
24+ * directly set the password here.
25+ */
26+
27+LocalComponents.Page {
28+ id: passwdSetPage
29+ objectName: "passcodeDesktopPage"
30+ title: i18n.tr("Lock Screen Passcode")
31+ forwardButtonSourceComponent: forwardButton
32+
33+ readonly property alias password: passwordField.text
34+ readonly property alias password2: password2Field.text
35+
36+ GridLayout {
37+ id: column
38+ columns: 1
39+ rows: 3
40+ anchors.fill: content
41+ anchors.leftMargin: leftMargin
42+ anchors.rightMargin: rightMargin
43+ anchors.topMargin: customMargin
44+ rowSpacing: units.gu(3)
45+
46+ Label {
47+ id: infoLabel
48+ objectName: "infoLabel"
49+ anchors {
50+ left: parent.left
51+ right: parent.right
52+ }
53+ wrapMode: Text.Wrap
54+ font.weight: Font.Light
55+ color: textColor
56+ text: i18n.tr("Enter 4 numbers to setup your passcode")
57+ }
58+
59+ GridLayout {
60+ columns: 2
61+ columnSpacing: units.gu(2)
62+ rowSpacing: units.gu(2)
63+
64+ Label {
65+ text: i18n.tr("Choose passcode")
66+ color: textColor
67+ }
68+ LocalComponents.WizardTextField {
69+ Layout.fillWidth: true
70+ id: passwordField
71+ objectName: "passwordField"
72+ echoMode: TextInput.Password
73+ inputMethodHints: Qt.ImhDigitsOnly
74+ validator: RegExpValidator { regExp: /^\d{4}$/ }
75+ maximumLength: 4
76+ onAccepted: password2Field.forceActiveFocus()
77+ }
78+
79+ Label {
80+ text: i18n.tr("Confirm passcode")
81+ color: textColor
82+ }
83+ LocalComponents.WizardTextField {
84+ Layout.fillWidth: true
85+ id: password2Field
86+ objectName: "password2Field"
87+ echoMode: TextInput.Password
88+ inputMethodHints: Qt.ImhDigitsOnly
89+ validator: RegExpValidator { regExp: /^\d{4}$/ }
90+ maximumLength: 4
91+ }
92+
93+ Label {
94+ Layout.row: 2
95+ Layout.column: 1
96+ id: errorLabel
97+ property bool hasError: password && password != password2
98+ wrapMode: Text.Wrap
99+ color: hasError ? errorColor : UbuntuColors.ash
100+ visible: password && password2
101+ fontSize: "small"
102+ text: {
103+ if (password) {
104+ if (password2.length < password2Field.maximumLength)
105+ return i18n.tr("Passcode too short");
106+ else if (password == password2)
107+ return i18n.tr("Passcodes match");
108+ else if (password2)
109+ return i18n.tr("Passcodes do not match");
110+ }
111+ return "";
112+ }
113+ }
114+ }
115+
116+ Item { // spacer
117+ Layout.fillHeight: true
118+ }
119+ }
120+
121+ Component {
122+ id: forwardButton
123+ LocalComponents.StackButton {
124+ text: i18n.tr("Next")
125+ enabled: password != "" && password == password2
126+ onClicked: {
127+ root.password = password;
128+ pageStack.next();
129+ }
130+ }
131+ }
132+}
qml/Wizard/Pages/passwd-set.qml → qml/Wizard/Pages/passcode-set.qmlrenamed+12−28
@@ -26,11 +26,10 @@ import "../../Components" as UnityComponents
26 */
26 */
27
27
28LocalComponents.Page {
28LocalComponents.Page {
29− id: passwdSetPage
29+ id: passcodeSetPage
30− objectName: "passwdSetPage"
30+ objectName: "passcodeSetPage"
31− forwardButtonSourceComponent: forwardButton
31+ customTitle: true
32−
32+ backButtonText: i18n.tr("Cancel")
33− skip: root.passwordMethod === UbuntuSecurityPrivacyPanel.Swipe
34
33
35 // If we are entering this page, clear any saved password and get focus
34 // If we are entering this page, clear any saved password and get focus
36 onEnabledChanged: if (enabled) lockscreen.clear(false)
35 onEnabledChanged: if (enabled) lockscreen.clear(false)
@@ -43,52 +42,37 @@ LocalComponents.Page {
43 Timer {
42 Timer {
44 id: confirmTimer
43 id: confirmTimer
45 interval: UbuntuAnimation.SnapDuration
44 interval: UbuntuAnimation.SnapDuration
46− onTriggered: pageStack.load(Qt.resolvedUrl("passwd-confirm.qml"));
45+ onTriggered: pageStack.load(Qt.resolvedUrl("passcode-confirm.qml"));
47 }
46 }
48
47
49 UnityComponents.Lockscreen {
48 UnityComponents.Lockscreen {
50 id: lockscreen
49 id: lockscreen
51 anchors {
50 anchors {
52− fill: parent
51+ fill: content
53− topMargin: topMargin
54− leftMargin: leftMargin
55− rightMargin: rightMargin
56− bottomMargin: buttonMargin
57 }
52 }
58
53
59− infoText: root.passwordMethod === UbuntuSecurityPrivacyPanel.Passphrase ?
60− i18n.tr("Enter passphrase") :
61− i18n.tr("Choose your passcode")
54+ infoText: i18n.tr("Choose passcode")
55+ foregroundColor: textColor
62
56
63 // Note that the number four comes from PAM settings,
57 // Note that the number four comes from PAM settings,
64 // which we don't have a good way to interrogate. We
58 // which we don't have a good way to interrogate. We
65 // only do this matching instead of PAM because we want
59 // only do this matching instead of PAM because we want
66 // to set the password via PAM in a different place
60 // to set the password via PAM in a different place
67 // than this page. See comments at top of passwd-type file.
61 // than this page. See comments at top of passwd-type file.
68− errorText: i18n.tr("Passphrase must be 4 characters long")
62+ errorText: i18n.tr("Passcode must be 4 characters long")
69
63
70 showEmergencyCallButton: false
64 showEmergencyCallButton: false
71 showCancelButton: false
65 showCancelButton: false
72− alphaNumeric: root.passwordMethod === UbuntuSecurityPrivacyPanel.Passphrase
66+ alphaNumeric: false
73 minPinLength: 4
67 minPinLength: 4
74 maxPinLength: 4
68 maxPinLength: 4
75
69
76 onEntered: {
70 onEntered: {
77 if (passphrase.length >= 4) {
71 if (passphrase.length >= 4) {
78− passwdSetPage.confirm();
72+ passcodeSetPage.confirm();
79 } else {
73 } else {
80− lockscreen.clear(true)
74+ lockscreen.clear(true);
81 }
75 }
82 }
76 }
83 }
77 }
84−
85− Component {
86− id: forwardButton
87− LocalComponents.StackButton {
88− visible: root.passwordMethod === UbuntuSecurityPrivacyPanel.Passphrase
89− enabled: lockscreen.passphrase.length >= 4
90− text: i18n.tr("Continue")
91− onClicked: passwdSetPage.confirm()
92− }
93− }
94}
78}
qml/Wizard/Pages/password-set.qmlnew file+149
@@ -0,0 +1,149 @@
1+/*
2+ * Copyright (C) 2015 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 ".." as LocalComponents
21+
22+/**
23+ * See the main passwd-type page for an explanation of why we don't actually
24+ * directly set the password here.
25+ */
26+
27+LocalComponents.Page {
28+ id: passwdSetPage
29+ objectName: "passwdSetPage"
30+ title: i18n.tr("Lock Screen Password")
31+ forwardButtonSourceComponent: forwardButton
32+
33+ readonly property alias password: passwordField.text
34+ readonly property alias password2: password2Field.text
35+ readonly property bool passwordsMatching: password == password2 && password.trim().length > 7
36+
37+ Flickable {
38+ id: column
39+ clip: true
40+ flickableDirection: Flickable.VerticalFlick
41+ anchors.fill: content
42+ anchors.leftMargin: parent.leftMargin
43+ anchors.rightMargin: parent.rightMargin
44+ anchors.topMargin: customMargin
45+
46+ bottomMargin: Qt.inputMethod.keyboardRectangle.height - height
47+
48+ Behavior on contentY { UbuntuNumberAnimation {} }
49+
50+ // info label
51+ Label {
52+ id: infoLabel
53+ objectName: "infoLabel"
54+ anchors {
55+ left: parent.left
56+ right: parent.right
57+ }
58+ wrapMode: Text.Wrap
59+ font.weight: Font.Light
60+ color: textColor
61+ text: i18n.tr("Enter at least 8 characters")
62+ }
63+
64+ // password
65+ Label {
66+ id: pass1Label
67+ anchors {
68+ left: parent.left
69+ right: parent.right
70+ top: infoLabel.bottom
71+ topMargin: units.gu(3)
72+ }
73+ text: i18n.tr("Choose password")
74+ color: textColor
75+ }
76+ LocalComponents.WizardTextField {
77+ id: passwordField
78+ anchors {
79+ left: parent.left
80+ right: parent.right
81+ top: pass1Label.bottom
82+ topMargin: units.gu(1)
83+ }
84+ objectName: "passwordField"
85+ echoMode: TextInput.Password
86+ onAccepted: password2Field.forceActiveFocus()
87+ onActiveFocusChanged: {
88+ if (activeFocus) {
89+ column.contentY = pass1Label.y
90+ }
91+ }
92+ }
93+
94+ // password 2
95+ Label {
96+ id: pass2Label
97+ anchors {
98+ left: parent.left
99+ right: parent.right
100+ top: passwordField.bottom
101+ topMargin: units.gu(3)
102+ }
103+ text: i18n.tr("Confirm password")
104+ color: textColor
105+ }
106+ LocalComponents.WizardTextField {
107+ anchors {
108+ left: parent.left
109+ right: parent.right
110+ top: pass2Label.bottom
111+ topMargin: units.gu(1)
112+ }
113+ id: password2Field
114+ objectName: "password2Field"
115+ echoMode: TextInput.Password
116+ onActiveFocusChanged: {
117+ if (activeFocus) {
118+ column.contentY = pass2Label.y
119+ }
120+ }
121+ }
122+
123+ // password meter
124+ LocalComponents.PasswordMeter {
125+ id: passMeter
126+ anchors {
127+ left: parent.left
128+ right: parent.right
129+ top: password2Field.bottom
130+ topMargin: units.gu(1)
131+ }
132+
133+ password: passwordField.text
134+ matching: passwordsMatching ? true : (password2.trim().length > 0 ? false : undefined)
135+ }
136+ }
137+
138+ Component {
139+ id: forwardButton
140+ LocalComponents.StackButton {
141+ text: i18n.tr("Next")
142+ enabled: passwordsMatching
143+ onClicked: {
144+ root.password = password;
145+ pageStack.next();
146+ }
147+ }
148+ }
149+}
qml/Wizard/Pages/sim.qmlnew file+108
@@ -0,0 +1,108 @@
1+/*
2+ * Copyright (C) 2013-2015 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 MeeGo.QOfono 0.2
19+import Ubuntu.Components 1.3
20+import Ubuntu.Components.Popups 1.3
21+import Unity.Session 0.1
22+import ".." as LocalComponents
23+
24+LocalComponents.Page {
25+ objectName: "simPage"
26+
27+ title: i18n.tr("No SIM card installed")
28+ forwardButtonSourceComponent: forwardButton
29+ customTitle: true
30+ hasBackButton: false
31+
32+ property bool hadSIM: root.simManager0.present || root.simManager1.present
33+
34+ Timer {
35+ id: timer
36+ interval: 300
37+ running: true
38+ onTriggered: {
39+ hadSIM = root.simManager0.present || root.simManager1.present;
40+ }
41+ }
42+
43+ Connections {
44+ target: root.modemManager
45+ onGotSimCardChanged: {
46+ if (!hadSIM && root.modemManager.gotSimCard) { // show the restart dialog in case a SIM gets inserted
47+ restartDialog.visible = true;
48+ }
49+ }
50+ }
51+
52+ Dialog {
53+ id: restartDialog
54+ title: i18n.tr("SIM card added")
55+ text: i18n.tr("You must restart the device to access the mobile network.")
56+
57+ Button {
58+ id: restartButton
59+ text: i18n.tr("Restart")
60+ onClicked: {
61+ DBusUnitySessionService.reboot();
62+ }
63+ }
64+ }
65+
66+ Column {
67+ anchors {
68+ fill: content
69+ leftMargin: staticMargin
70+ rightMargin: staticMargin
71+ }
72+ spacing: units.gu(3)
73+
74+ Label {
75+ anchors.left: parent.left
76+ anchors.right: parent.right
77+ wrapMode: Text.Wrap
78+ text: i18n.tr("You won’t be able to make calls or use text messaging without a SIM.")
79+ fontSize: "small"
80+ font.weight: Font.Light
81+ lineHeight: 1.2
82+ color: restartDialog.visible ? theme.palette.normal.backgroundText : textColor
83+ }
84+
85+ Label {
86+ anchors.left: parent.left
87+ anchors.right: parent.right
88+ wrapMode: Text.Wrap
89+ textFormat: Text.RichText
90+ text: i18n.tr("To proceed with no SIM tap Skip.")
91+ fontSize: "small"
92+ font.weight: Font.Light
93+ lineHeight: 1.2
94+ color: restartDialog.visible ? theme.palette.normal.backgroundText : textColor
95+ }
96+ }
97+
98+ Component {
99+ id: forwardButton
100+ LocalComponents.StackButton {
101+ text: i18n.tr("Skip")
102+ onClicked: {
103+ seenSIMPage = true;
104+ pageStack.next();
105+ }
106+ }
107+ }
108+}
qml/Wizard/PasswordMeter.qmlnew file+106
@@ -0,0 +1,106 @@
1+/*
2+ * Copyright (C) 2015 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+
20+Item {
21+ property string password: ""
22+ readonly property int passwordScore: scorePassword(password)
23+ property var matching
24+
25+ function scorePassword(pass) {
26+ var score = 0;
27+ if (!pass)
28+ return score;
29+
30+ // award every unique letter until 5 repetitions
31+ var letters = Object();
32+ for (var i=0; i<pass.length; i++) {
33+ letters[pass[i]] = (letters[pass[i]] || 0) + 1;
34+ score += 5.0 / letters[pass[i]];
35+ }
36+
37+ // bonus points for mixing it up
38+ var variations = {
39+ digits: /\d/.test(pass),
40+ lower: /[a-z]/.test(pass),
41+ upper: /[A-Z]/.test(pass),
42+ nonWords: /\W/.test(pass),
43+ }
44+
45+ var variationCount = 0;
46+ for (var check in variations) {
47+ variationCount += (variations[check] === true) ? 1 : 0;
48+ }
49+ score += (variationCount - 1) * 10;
50+
51+ return parseInt(score);
52+ }
53+
54+ Rectangle {
55+ id: passwordStrengthMeter
56+ anchors {
57+ left: parent.left
58+ right: parent.right
59+ }
60+ width: parent.width
61+ height: units.gu(0.5)
62+ color: {
63+ if (passwordScore > 80)
64+ return okColor;
65+ else if (passwordScore > 60)
66+ return "#f9c00f";
67+ else if (passwordScore >= 30)
68+ return errorColor;
69+
70+ return errorColor;
71+ }
72+ visible: password.length > 0
73+ }
74+
75+ Label {
76+ id: passwordStrengthInfo
77+ anchors {
78+ left: parent.left
79+ right: parent.right
80+ top: passwordStrengthMeter.bottom
81+ topMargin: units.gu(.5)
82+ }
83+ wrapMode: Text.Wrap
84+ text: {
85+ if (matching !== undefined) {
86+ if (matching)
87+ return i18n.tr("Passwords match");
88+ else if (!matching)
89+ return i18n.tr("Passwords do not match");
90+ }
91+
92+ if (passwordScore > 80)
93+ return i18n.tr("Strong password");
94+ else if (passwordScore > 60)
95+ return i18n.tr("Fair password");
96+ else if (passwordScore >= 30)
97+ return i18n.tr("Weak password");
98+
99+ return i18n.tr("Very weak password");
100+ }
101+ color: UbuntuColors.ash
102+ fontSize: "small"
103+ font.weight: Font.Light
104+ visible: password.length > 0
105+ }
106+}
qml/Wizard/StackButton.qml+6−11
@@ -25,23 +25,18 @@ AbstractButton {
25 property bool backArrow: false
25 property bool backArrow: false
26
26
27 width: label.width
27 width: label.width
28− height: label.height + units.gu(4)
28+ height: units.gu(5)
29
29
30 Label {
30 Label {
31 id: label
31 id: label
32 anchors.verticalCenter: parent.verticalCenter
32 anchors.verticalCenter: parent.verticalCenter
33 anchors.left: parent.left
33 anchors.left: parent.left
34 anchors.right: parent.right
34 anchors.right: parent.right
35− color: enabled ? theme.palette.normal.backgroundText : Qt.darker(theme.palette.normal.backgroundText, 1.5)
35+ color: "#333333"
36− text: {
36+ opacity: enabled ? 1.0 : 0.5
37− if (backArrow) {
37+ fontSize: "medium"
38− // Translators: This is the arrow for "Back" buttons
38+ font.weight: backArrow ? Font.Light : Font.DemiBold
39− return i18n.tr("〈 %1".arg(stackButton.text))
40− } else {
41− // Translators: This is the arrow for "Forward" buttons
42− return i18n.tr("%1 〉".arg(stackButton.text))
39+ text: stackButton.text
43− }
44− }
45 horizontalAlignment: backArrow ? Text.AlignLeft : Text.AlignRight
40 horizontalAlignment: backArrow ? Text.AlignLeft : Text.AlignRight
46 }
41 }
47}
42}
qml/Wizard/Wizard.qml−9
@@ -22,9 +22,6 @@ import "../Components"
22Showable {
22Showable {
23 id: root
23 id: root
24
24
25− // The background wallpaper to use
26− property string background
27−
28 // This is a bool instead of an alias because Loader classes like to emit
25 // This is a bool instead of an alias because Loader classes like to emit
29 // changed signals for 'active' during startup even if they aren't actually
26 // changed signals for 'active' during startup even if they aren't actually
30 // changing values. Having it cached as a proper Qml bool property prevents
27 // changing values. Having it cached as a proper Qml bool property prevents
@@ -46,12 +43,6 @@ Showable {
46 active: System.wizardEnabled
43 active: System.wizardEnabled
47 source: "Pages.qml"
44 source: "Pages.qml"
48
45
49− Binding {
50− target: loader.item
51− property: "background"
52− value: root.background
53− }
54−
55 Connections {
46 Connections {
56 target: loader.item
47 target: loader.item
57 onQuit: root.hide()
48 onQuit: root.hide()
qml/Wizard/WizardTextField.qmlnew file+25
@@ -0,0 +1,25 @@
1+/*
2+ * Copyright (C) 2015 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.Components.Themes.Ambiance 1.3
20+
21+TextField {
22+ id: styledItem
23+ style: TextFieldStyle {
24+ }
25+}
tests/mocks/AccountsService/AccountsService.cpp+23−3
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2013 Canonical, Ltd.
2+ * Copyright (C) 2013, 2015 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
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
5 * it under the terms of the GNU General Public License as published by
@@ -12,8 +12,6 @@
12 *
12 *
13 * You should have received a copy of the GNU General Public License
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/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− * Author: Michael Terry <michael.terry@canonical.com>
17 */
15 */
18
16
19#include "AccountsService.h"
17#include "AccountsService.h"
@@ -152,3 +150,25 @@ bool AccountsService::hereLicensePathValid() const
152{
150{
153 return !m_hereLicensePath.isNull();
151 return !m_hereLicensePath.isNull();
154}
152}
153+
154+QString AccountsService::realName() const
155+{
156+ return m_realName;
157+}
158+
159+void AccountsService::setRealName(const QString &realName)
160+{
161+ m_realName = realName;
162+ Q_EMIT realNameChanged();
163+}
164+
165+QString AccountsService::email() const
166+{
167+ return m_email;
168+}
169+
170+void AccountsService::setEmail(const QString &email)
171+{
172+ m_email = email;
173+ Q_EMIT emailChanged();
174+}
tests/mocks/AccountsService/AccountsService.h+12−5
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2013 Canonical, Ltd.
2+ * Copyright (C) 2013, 2015 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
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
5 * it under the terms of the GNU General Public License as published by
@@ -12,9 +12,6 @@
12 *
12 *
13 * You should have received a copy of the GNU General Public License
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/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− * Authors: Gerry Boland <gerry.boland@canonical.com>
17− * Michael Terry <michael.terry@canonical.com>
18 */
15 */
19
16
20#ifndef UNITY_MOCK_ACCOUNTSSERVICE_H
17#ifndef UNITY_MOCK_ACCOUNTSSERVICE_H
@@ -70,11 +67,13 @@ class AccountsService: public QObject
70 Q_PROPERTY(bool hereLicensePathValid // qml sees a null string as "", so we use proxy setting for that
67 Q_PROPERTY(bool hereLicensePathValid // qml sees a null string as "", so we use proxy setting for that
71 READ hereLicensePathValid
68 READ hereLicensePathValid
72 NOTIFY hereLicensePathChanged)
69 NOTIFY hereLicensePathChanged)
70+ Q_PROPERTY(QString realName READ realName WRITE setRealName NOTIFY realNameChanged)
71+ Q_PROPERTY(QString email READ email WRITE setEmail NOTIFY emailChanged)
73
72
74public:
73public:
75 enum PasswordDisplayHint {
74 enum PasswordDisplayHint {
76 Keyboard,
75 Keyboard,
77− Numeric,
76+ Numeric
78 };
77 };
79
78
80 explicit AccountsService(QObject *parent = 0);
79 explicit AccountsService(QObject *parent = 0);
@@ -99,6 +98,10 @@ public:
99 QString hereLicensePath() const;
98 QString hereLicensePath() const;
100 void setHereLicensePath(const QString &path);
99 void setHereLicensePath(const QString &path);
101 bool hereLicensePathValid() const;
100 bool hereLicensePathValid() const;
101+ QString realName() const;
102+ void setRealName(const QString &realName);
103+ QString email() const;
104+ void setEmail(const QString &email);
102
105
103Q_SIGNALS:
106Q_SIGNALS:
104 void userChanged();
107 void userChanged();
@@ -111,6 +114,8 @@ Q_SIGNALS:
111 void failedLoginsChanged();
114 void failedLoginsChanged();
112 void hereEnabledChanged();
115 void hereEnabledChanged();
113 void hereLicensePathChanged();
116 void hereLicensePathChanged();
117+ void realNameChanged();
118+ void emailChanged();
114
119
115private:
120private:
116 bool m_enableLauncherWhileLocked;
121 bool m_enableLauncherWhileLocked;
@@ -122,6 +127,8 @@ private:
122 bool m_demoEdges;
127 bool m_demoEdges;
123 bool m_hereEnabled;
128 bool m_hereEnabled;
124 QString m_hereLicensePath;
129 QString m_hereLicensePath;
130+ QString m_realName;
131+ QString m_email;
125};
132};
126
133
127#endif
134#endif
tests/mocks/MeeGo/QOfono/MockOfonoSimManager.qml+1
@@ -23,6 +23,7 @@ Item {
23 property string modemPath
23 property string modemPath
24 readonly property alias present: d.present
24 readonly property alias present: d.present
25 readonly property alias ready: d.ready
25 readonly property alias ready: d.ready
26+ readonly property var preferredLanguages: ["de", "fr", "it", "en"]
26
27
27 QtObject {
28 QtObject {
28 id: d
29 id: d
tests/mocks/Ubuntu/Connectivity/plugin.cpp+1
@@ -36,6 +36,7 @@ QmlConnectivityNetworkingPlugin::registerTypes(const char *uri)
36{
36{
37 // @uri Ubuntu.Connectivity
37 // @uri Ubuntu.Connectivity
38 qmlRegisterSingletonType<NetworkingStatus>(uri, 1, 0, "NetworkingStatus", networkingStatusSingletonProvider);
38 qmlRegisterSingletonType<NetworkingStatus>(uri, 1, 0, "NetworkingStatus", networkingStatusSingletonProvider);
39+ qmlRegisterSingletonType<NetworkingStatus>(uri, 1, 0, "Connectivity", networkingStatusSingletonProvider);
39}
40}
40
41
41void
42void
tests/mocks/Ubuntu/SystemSettings/CMakeLists.txt+2
@@ -1,2 +1,4 @@
1add_subdirectory(LanguagePlugin)
1add_subdirectory(LanguagePlugin)
2add_subdirectory(SecurityPrivacy)
2add_subdirectory(SecurityPrivacy)
3+add_subdirectory(TimeDate)
4+add_subdirectory(Diagnostics)
tests/mocks/Ubuntu/SystemSettings/Diagnostics/CMakeLists.txtnew file+1
@@ -0,0 +1 @@
1+add_unity8_mock(Ubuntu.SystemSettings.Diagnostics 1.0 Ubuntu/SystemSettings/Diagnostics)
tests/mocks/Ubuntu/SystemSettings/Diagnostics/MockDiagnostics.qmlnew file+24
@@ -0,0 +1,24 @@
1+/*
2+ * Copyright (C) 2015 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+
19+Item {
20+ property bool reportCrashes: true
21+ function setReportCrashes(report) {
22+ reportCrashes = report;
23+ }
24+}
tests/mocks/Ubuntu/SystemSettings/Diagnostics/qmldirnew file+2
@@ -0,0 +1,2 @@
1+module Ubuntu.SystemSettings.Diagnostics
2+UbuntuDiagnostics 1.0 MockDiagnostics.qml
tests/mocks/Ubuntu/SystemSettings/LanguagePlugin/MockLanguagePlugin.qml+2−2
@@ -17,7 +17,7 @@
17import QtQuick 2.4
17import QtQuick 2.4
18
18
19Item {
19Item {
20− property var languageNames: ["English", "French", "Spanish"]
20+ property var languageNames: ["English (United States)", "French (France)", "Spanish (Spain)"]
21− property var languageCodes: ["en", "fr", "es"]
21+ property var languageCodes: ["en_US", "fr_FR", "es_ES"]
22 property int currentLanguage: 0
22 property int currentLanguage: 0
23}
23}
tests/mocks/Ubuntu/SystemSettings/SecurityPrivacy/MockSecurityPrivacy.cpp+1−1
@@ -31,5 +31,5 @@ QString MockSecurityPrivacy::setSecurity(const QString &oldPasswd, const QString
31{
31{
32 m_type = newType;
32 m_type = newType;
33 Q_EMIT setSecurityCalled(oldPasswd, newPasswd, newType);
33 Q_EMIT setSecurityCalled(oldPasswd, newPasswd, newType);
34− return "";
34+ return QString();
35}
35}
tests/mocks/Ubuntu/SystemSettings/TimeDate/CMakeLists.txtnew file+1
@@ -0,0 +1 @@
1+add_unity8_mock(Ubuntu.SystemSettings.TimeDate 1.0 Ubuntu/SystemSettings/TimeDate)
tests/mocks/Ubuntu/SystemSettings/TimeDate/MockTimeDate.qmlnew file+25
@@ -0,0 +1,25 @@
1+/*
2+ * Copyright (C) 2015 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+
19+Item {
20+ id: root
21+ property string timeZone: "Europe/Prague"
22+ onTimeZoneChanged: root.timeZoneChangedCalled(root.timeZone);
23+
24+ signal timeZoneChangedCalled(string tz);
25+}
tests/mocks/Ubuntu/SystemSettings/TimeDate/qmldirnew file+2
@@ -0,0 +1,2 @@
1+module Ubuntu.SystemSettings.TimeDate
2+UbuntuTimeDatePanel 1.0 MockTimeDate.qml
tests/mocks/Utils/CMakeLists.txt+1−1
@@ -16,6 +16,7 @@ set(QMLPLUGIN_SRC
16 ${CMAKE_SOURCE_DIR}/plugins/Utils/windowscreenshotprovider.cpp
16 ${CMAKE_SOURCE_DIR}/plugins/Utils/windowscreenshotprovider.cpp
17 ${CMAKE_SOURCE_DIR}/plugins/Utils/easingcurve.cpp
17 ${CMAKE_SOURCE_DIR}/plugins/Utils/easingcurve.cpp
18 ${CMAKE_SOURCE_DIR}/plugins/Utils/inputwatcher.cpp
18 ${CMAKE_SOURCE_DIR}/plugins/Utils/inputwatcher.cpp
19+ ${CMAKE_SOURCE_DIR}/plugins/Utils/timezoneFormatter.cpp
19 ${CMAKE_SOURCE_DIR}/plugins/Utils/applicationsfiltermodel.cpp
20 ${CMAKE_SOURCE_DIR}/plugins/Utils/applicationsfiltermodel.cpp
20 ${CMAKE_SOURCE_DIR}/plugins/Utils/inputeventgenerator.cpp
21 ${CMAKE_SOURCE_DIR}/plugins/Utils/inputeventgenerator.cpp
21 ${CMAKE_SOURCE_DIR}/plugins/Utils/deviceconfigparser.cpp
22 ${CMAKE_SOURCE_DIR}/plugins/Utils/deviceconfigparser.cpp
@@ -24,7 +25,6 @@ set(QMLPLUGIN_SRC
24 constants.cpp
25 constants.cpp
25 plugin.cpp
26 plugin.cpp
26 windowstatestorage.cpp
27 windowstatestorage.cpp
27− plugin.cpp
28 )
28 )
29
29
30add_library(FakeUtils-qml SHARED
30add_library(FakeUtils-qml SHARED
tests/mocks/Utils/plugin.cpp+3
@@ -35,6 +35,7 @@
35#include <windowkeysfilter.h>
35#include <windowkeysfilter.h>
36#include <windowscreenshotprovider.h>
36#include <windowscreenshotprovider.h>
37#include <easingcurve.h>
37#include <easingcurve.h>
38+#include <timezoneFormatter.h>
38#include <applicationsfiltermodel.h>
39#include <applicationsfiltermodel.h>
39#include <inputeventgenerator.h>
40#include <inputeventgenerator.h>
40#include <deviceconfigparser.h>
41#include <deviceconfigparser.h>
@@ -73,6 +74,8 @@ void FakeUtilsPlugin::registerTypes(const char *uri)
73 qmlRegisterSingletonType<WindowStateStorage>(uri, 0, 1, "WindowStateStorage", createWindowStateStorage);
74 qmlRegisterSingletonType<WindowStateStorage>(uri, 0, 1, "WindowStateStorage", createWindowStateStorage);
74 qmlRegisterType<InputWatcher>(uri, 0, 1, "InputWatcher");
75 qmlRegisterType<InputWatcher>(uri, 0, 1, "InputWatcher");
75 qmlRegisterSingletonType<Constants>(uri, 0, 1, "Constants", createConstants);
76 qmlRegisterSingletonType<Constants>(uri, 0, 1, "Constants", createConstants);
77+ qmlRegisterSingletonType<TimezoneFormatter>(uri, 0, 1, "TimezoneFormatter",
78+ [](QQmlEngine*, QJSEngine*) -> QObject* { return new TimezoneFormatter; });
76 qmlRegisterType<ActiveFocusLogger>(uri, 0, 1, "ActiveFocusLogger");
79 qmlRegisterType<ActiveFocusLogger>(uri, 0, 1, "ActiveFocusLogger");
77 qmlRegisterType<ApplicationsFilterModel>(uri, 0, 1, "ApplicationsFilterModel");
80 qmlRegisterType<ApplicationsFilterModel>(uri, 0, 1, "ApplicationsFilterModel");
78 qmlRegisterType<InputEventGenerator>(uri, 0, 1, "InputEventGenerator");
81 qmlRegisterType<InputEventGenerator>(uri, 0, 1, "InputEventGenerator");
tests/mocks/Wizard/CMakeLists.txt+6−1
@@ -1,4 +1,5 @@
1include_directories(
1include_directories(
2+ ${GLIB_INCLUDE_DIRS} ${GEONAMES_INCLUDE_DIRS}
2 ${CMAKE_SOURCE_DIR}/plugins/Wizard
3 ${CMAKE_SOURCE_DIR}/plugins/Wizard
3)
4)
4
5
@@ -6,7 +7,11 @@ add_library(MockWizard-qml MODULE
6 mockplugin.cpp
7 mockplugin.cpp
7 MockSystem.cpp
8 MockSystem.cpp
8 ${CMAKE_SOURCE_DIR}/plugins/Wizard/PageList.cpp
9 ${CMAKE_SOURCE_DIR}/plugins/Wizard/PageList.cpp
10+ ${CMAKE_SOURCE_DIR}/plugins/Wizard/timezonemodel.cpp
11+ ${CMAKE_SOURCE_DIR}/plugins/Wizard/LocalePlugin.cpp
12+ ${CMAKE_SOURCE_DIR}/plugins/Wizard/Status.cpp
9)
13)
10
14
11−qt5_use_modules(MockWizard-qml Qml)
15+qt5_use_modules(MockWizard-qml DBus Qml Concurrent)
16+target_link_libraries(MockWizard-qml ${GLIB_LDFLAGS} ${GEONAMES_LDFLAGS})
12add_unity8_mock(Wizard 0.1 Wizard TARGETS MockWizard-qml)
17add_unity8_mock(Wizard 0.1 Wizard TARGETS MockWizard-qml)
tests/mocks/Wizard/MockSystem.cpp+4−2
@@ -14,6 +14,8 @@
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
15 */
16
16
17+#include <QDebug>
18+
17#include "MockSystem.h"
19#include "MockSystem.h"
18
20
19MockSystem::MockSystem()
21MockSystem::MockSystem()
@@ -33,7 +35,7 @@ void MockSystem::setWizardEnabled(bool enabled)
33 Q_EMIT wizardEnabledChanged();
35 Q_EMIT wizardEnabledChanged();
34}
36}
35
37
36−void MockSystem::updateSessionLanguage(const QString &locale)
38+void MockSystem::updateSessionLocale(const QString &locale)
37{
39{
38− Q_EMIT updateSessionLanguageCalled(locale);
40+ Q_EMIT updateSessionLocaleCalled(locale);
39}
41}
tests/mocks/Wizard/MockSystem.h+2−2
@@ -32,11 +32,11 @@ public:
32 void setWizardEnabled(bool enabled);
32 void setWizardEnabled(bool enabled);
33
33
34public Q_SLOTS:
34public Q_SLOTS:
35− void updateSessionLanguage(const QString &locale);
35+ void updateSessionLocale(const QString &locale);
36
36
37Q_SIGNALS:
37Q_SIGNALS:
38 void wizardEnabledChanged();
38 void wizardEnabledChanged();
39− void updateSessionLanguageCalled(const QString &locale); // only in mock
39+ void updateSessionLocaleCalled(const QString &locale); // only in mock
40
40
41private:
41private:
42 Q_DISABLE_COPY(MockSystem)
42 Q_DISABLE_COPY(MockSystem)
tests/mocks/Wizard/mockplugin.cpp+7−8
@@ -17,19 +17,18 @@
17#include "mockplugin.h"
17#include "mockplugin.h"
18#include "MockSystem.h"
18#include "MockSystem.h"
19#include "PageList.h"
19#include "PageList.h"
20+#include "timezonemodel.h"
21+#include "LocalePlugin.h"
22+#include "Status.h"
20
23
21#include <QtQml/qqml.h>
24#include <QtQml/qqml.h>
22
25
23−static QObject *system_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
24−{
25− Q_UNUSED(engine)
26− Q_UNUSED(scriptEngine)
27− return new MockSystem();
28−}
29−
30void MockWizardPlugin::registerTypes(const char *uri)
26void MockWizardPlugin::registerTypes(const char *uri)
31{
27{
32 Q_ASSERT(uri == QLatin1String("Wizard"));
28 Q_ASSERT(uri == QLatin1String("Wizard"));
33 qmlRegisterType<PageList>(uri, 0, 1, "PageList");
29 qmlRegisterType<PageList>(uri, 0, 1, "PageList");
34− qmlRegisterSingletonType<MockSystem>(uri, 0, 1, "System", system_provider);
30+ qmlRegisterSingletonType<MockSystem>(uri, 0, 1, "System", [](QQmlEngine*, QJSEngine*) -> QObject* { return new MockSystem; });
31+ qmlRegisterSingletonType<Status>(uri, 0, 1, "Status", [](QQmlEngine*, QJSEngine*) -> QObject* { return new Status; });
32+ qmlRegisterType<TimeZoneLocationModel>(uri, 0, 1, "TimeZoneModel");
33+ qmlRegisterType<LocalePlugin>(uri, 0, 1, "LocalePlugin");
35}
34}
tests/qmltests/Wizard/tst_Wizard.qml+170−199
@@ -21,6 +21,7 @@ import MeeGo.QOfono 0.2
21import QMenuModel 0.1
21import QMenuModel 0.1
22import Ubuntu.Components 1.3
22import Ubuntu.Components 1.3
23import Ubuntu.SystemSettings.SecurityPrivacy 1.0
23import Ubuntu.SystemSettings.SecurityPrivacy 1.0
24+import Ubuntu.SystemSettings.TimeDate 1.0
24import Unity.Test 0.1 as UT
25import Unity.Test 0.1 as UT
25import Wizard 0.1
26import Wizard 0.1
26import "../../../qml/Wizard"
27import "../../../qml/Wizard"
@@ -39,7 +40,6 @@ Item {
39 Wizard {
40 Wizard {
40 id: wizard
41 id: wizard
41 anchors.fill: parent
42 anchors.fill: parent
42− background: Qt.resolvedUrl("../../../qml/graphics/phone_background.jpg")
43
43
44 Component.onDestruction: {
44 Component.onDestruction: {
45 wizardLoader.itemDestroyed = true;
45 wizardLoader.itemDestroyed = true;
@@ -51,7 +51,7 @@ Item {
51 SignalSpy {
51 SignalSpy {
52 id: updateSessionLanguageSpy
52 id: updateSessionLanguageSpy
53 target: System
53 target: System
54− signalName: "updateSessionLanguageCalled"
54+ signalName: "updateSessionLocaleCalled"
55 }
55 }
56
56
57 SignalSpy {
57 SignalSpy {
@@ -69,6 +69,11 @@ Item {
69 signalName: "activated"
69 signalName: "activated"
70 }
70 }
71
71
72+ SignalSpy {
73+ id: timezoneSpy
74+ signalName: "timeZoneChangedCalled"
75+ }
76+
72 function setup() {
77 function setup() {
73 AccountsService.hereEnabled = false;
78 AccountsService.hereEnabled = false;
74 AccountsService.hereLicensePath = Qt.resolvedUrl("licenses");
79 AccountsService.hereLicensePath = Qt.resolvedUrl("licenses");
@@ -82,6 +87,7 @@ Item {
82 setSecuritySpy.clear();
87 setSecuritySpy.clear();
83 activateLocationSpy.clear();
88 activateLocationSpy.clear();
84 activateGPSSpy.clear();
89 activateGPSSpy.clear();
90+ timezoneSpy.clear();
85
91
86 ActionData.data = {
92 ActionData.data = {
87 "location-detection-enabled": {
93 "location-detection-enabled": {
@@ -180,11 +186,6 @@ Item {
180 tap(findChild(page, "forwardButton"));
186 tap(findChild(page, "forwardButton"));
181 }
187 }
182
188
183− page = waitForPage("passwdPage");
184− if (name === page.objectName) return page;
185− tap(findChild(page, "passwdDelegate0"));
186− tap(findChild(page, "forwardButton"));
187−
188 page = waitForPage("wifiPage");
189 page = waitForPage("wifiPage");
189 if (name === page.objectName) return page;
190 if (name === page.objectName) return page;
190 tap(findChild(page, "forwardButton"));
191 tap(findChild(page, "forwardButton"));
@@ -195,6 +196,31 @@ Item {
195 tap(findChild(page, "forwardButton"));
196 tap(findChild(page, "forwardButton"));
196 }
197 }
197
198
199+ page = waitForPage("tzPage");
200+ if (name === page.objectName) return page;
201+ var tzList = findChild(page, "tzList");
202+ verify(tzList);
203+ waitForRendering(tzList);
204+ page.selectedTimeZone = "Pacific/Honolulu";
205+ tap(findChild(page, "forwardButton"));
206+
207+ page = waitForPage("accountPage");
208+ if (name === page.objectName) return page;
209+ tap(findChild(page, "nameInput"));
210+ typeString("foobar");
211+ tap(findChild(page, "passInput"));
212+ typeString("12345678");
213+ var pass2Input = findChild(page, "pass2Input");
214+ // give it a bit of time to finish the scroll-into-view animation
215+ tryCompareFunction(function() { return pass2Input !== null; }, true);
216+ tap(pass2Input);
217+ typeString("12345678");
218+ tap(findChild(page, "forwardButton"));
219+
220+ page = waitForPage("passwdPage");
221+ if (name === page.objectName) return page;
222+ tap(findChild(page, "forwardButton"));
223+
198 if (!skipReporting) {
224 if (!skipReporting) {
199 page = waitForPage("reportingPage");
225 page = waitForPage("reportingPage");
200 if (name === page.objectName) return page;
226 if (name === page.objectName) return page;
@@ -203,7 +229,8 @@ Item {
203
229
204 page = waitForPage("finishedPage");
230 page = waitForPage("finishedPage");
205 if (name === page.objectName) return page;
231 if (name === page.objectName) return page;
232+ waitUntilTransitionsEnd(page);
206− tap(findChild(page, "forwardButton"));
233+ tap(findChild(page, "finishButton"));
207
234
208 tryCompare(wizard, "shown", false);
235 tryCompare(wizard, "shown", false);
209 compare(name, null);
236 compare(name, null);
@@ -212,100 +239,43 @@ Item {
212
239
213 function test_languageChange() {
240 function test_languageChange() {
214 var page = goToPage("languagePage");
241 var page = goToPage("languagePage");
215− tap(findChild(page, "languageCombo"));
242+ tap(findChild(page, "languageDelegate1")); // should invoke "fr" lang
216− waitForRendering(findChild(page, "languageDelegate1"));
243+
217−
218− // For some reason, the delegate *sometimes* (like 1 in 10 maybe)
219− // needs more time before it can process a tap() call. I can't
220− // find a rhyme or reason, its properties all seem the same in
221− // cases where it works and does not. This failure to receive a
222− // tap() call below does *not* happen when running in xvfb, so
223− // jenkins is unaffected (and we don't have to worry about 100 not
224− // being enough time in its slow environment). This wait() call is
225− // just to help local runs not trip up.
226− wait(100);
227− tap(findChild(page, "languageDelegate1"));
228−
229− tryCompare(i18n, "language", "fr");
244+ tryCompare(i18n, "language", "fr_FR");
230 tap(findChild(page, "forwardButton"));
245 tap(findChild(page, "forwardButton"));
231 tryCompare(updateSessionLanguageSpy, "count", 1);
246 tryCompare(updateSessionLanguageSpy, "count", 1);
232− compare(updateSessionLanguageSpy.signalArguments[0][0], "fr");
247+ compare(updateSessionLanguageSpy.signalArguments[0][0], "fr_FR");
233 }
248 }
234
249
235 function test_languageNoChange() {
250 function test_languageNoChange() {
236− goToPage("simPage"); // one past language page
251+ var page = goToPage("languagePage");
252+ tap(findChild(page, "forwardButton"));
237 compare(updateSessionLanguageSpy.count, 0);
253 compare(updateSessionLanguageSpy.count, 0);
238 }
254 }
239
255
240 function test_simUnavailableSkip() {
256 function test_simUnavailableSkip() {
241 MockQOfono.available = false;
257 MockQOfono.available = false;
242− goToPage("passwdPage", true);
258+ goToPage("wifiPage", true);
243 }
259 }
244
260
245 function test_simNoModemsSkip() {
261 function test_simNoModemsSkip() {
246 MockQOfono.setModems([], [], []);
262 MockQOfono.setModems([], [], []);
247− goToPage("passwdPage", true);
263+ goToPage("wifiPage", true);
248 }
264 }
249
265
250 function test_simFirstSkip() {
266 function test_simFirstSkip() {
251 MockQOfono.setModems(["a", "b"], [true, false], []);
267 MockQOfono.setModems(["a", "b"], [true, false], []);
252− goToPage("passwdPage", true);
268+ goToPage("wifiPage", true);
253 }
269 }
254
270
255 function test_simSecondSkip() {
271 function test_simSecondSkip() {
256 MockQOfono.setModems(["a", "b"], [false, true], []);
272 MockQOfono.setModems(["a", "b"], [false, true], []);
257− goToPage("passwdPage", true);
273+ goToPage("wifiPage", true);
258 }
274 }
259
275
260 function test_simBothSkip() {
276 function test_simBothSkip() {
261 MockQOfono.setModems(["a", "b"], [true, true], []);
277 MockQOfono.setModems(["a", "b"], [true, true], []);
262− goToPage("passwdPage", true);
278+ goToPage("wifiPage", true);
263− }
264−
265− function test_simWaitOnManagerAsync() {
266− MockQOfono.ready = false;
267− MockQOfono.setModems(["a"], [false], []);
268−
269− // Go to SIM page, which will be waiting for skip to be valid
270− var page = goToPage("languagePage");
271− tap(findChild(page, "forwardButton"));
272− verifyPageIsBlocked("simPage");
273−
274− // Now release QOfono from blocking the page
275− MockQOfono.ready = true;
276−
277− waitForPage("simPage");
278− }
279−
280− function test_simWaitOnCardAsync() {
281− MockQOfono.setModems(["a"], [false], [false]);
282−
283− // Go to SIM page, which will be waiting for skip to be valid
284− var page = goToPage("languagePage");
285− tap(findChild(page, "forwardButton"));
286− verifyPageIsBlocked("simPage");
287−
288− // Now release QOfono from blocking the page
289− MockQOfono.setModems(["a"], [false], [true]);
290−
291− waitForPage("simPage");
292− }
293−
294− function test_simWaitTimeout() {
295− MockQOfono.setModems(["a"], [false], [false]);
296−
297− // Go to SIM page, which will be waiting for skip to be valid
298− var page = goToPage("languagePage");
299− tap(findChild(page, "forwardButton"));
300− verifyPageIsBlocked("simPage");
301−
302− var timeout = findInvisibleChild(wizard, "timeout");
303− timeout.interval = 100; // reduce our delay
304−
305− // Now just wait for timeout
306− compare(timeout.running, true);
307− waitForPage("passwdPage");
308− compare(timeout.running, false);
309 }
279 }
310
280
311 function enterPasscode(passcode) {
281 function enterPasscode(passcode) {
@@ -332,33 +302,32 @@ Item {
332
302
333 function test_passwdPasscode() {
303 function test_passwdPasscode() {
334 var page = goToPage("passwdPage");
304 var page = goToPage("passwdPage");
335−
305+ tap(findChild(page, "passwdDelegate2")); // passcode option
336 tap(findChild(page, "forwardButton"));
306 tap(findChild(page, "forwardButton"));
337− page = waitForPage("passwdSetPage");
307+ page = waitForPage("passcodeSetPage");
338
308
339 enterPasscode("1111");
309 enterPasscode("1111");
340− page = waitForPage("passwdConfirmPage");
310+ page = waitForPage("passcodeConfirmPage");
341
311
342 // make sure we go back to 'set' page not 'type' page
312 // make sure we go back to 'set' page not 'type' page
343 tap(findChild(page, "backButton"));
313 tap(findChild(page, "backButton"));
344− page = waitForPage("passwdSetPage");
314+ page = waitForPage("passcodeSetPage");
345
315
346 enterPasscode("1111");
316 enterPasscode("1111");
347− page = waitForPage("passwdConfirmPage");
317+ page = waitForPage("passcodeConfirmPage");
348
318
349 enterPasscode("1112");
319 enterPasscode("1112");
350 var error = findChild(page, "wrongNoticeLabel");
320 var error = findChild(page, "wrongNoticeLabel");
351 tryCompareFunction(function() { return error.text !== ""; }, true);
321 tryCompareFunction(function() { return error.text !== ""; }, true);
352
322
353 enterPasscode("1111");
323 enterPasscode("1111");
354− page = waitForPage("wifiPage");
355
324
356 // now finish up
325 // now finish up
357− tap(findChild(page, "forwardButton"));
358− page = waitForPage("locationPage");
326+ page = waitForPage("reportingPage");
359 tap(findChild(page, "forwardButton"));
327 tap(findChild(page, "forwardButton"));
360 page = waitForPage("finishedPage");
328 page = waitForPage("finishedPage");
329+ waitUntilTransitionsEnd(page);
361− tap(findChild(page, "forwardButton"));
330+ tap(findChild(page, "finishButton"));
362
331
363 tryCompare(setSecuritySpy, "count", 1);
332 tryCompare(setSecuritySpy, "count", 1);
364 compare(setSecuritySpy.signalArguments[0][0], "");
333 compare(setSecuritySpy.signalArguments[0][0], "");
@@ -368,96 +337,85 @@ Item {
368
337
369 function test_passwdPassphrase() {
338 function test_passwdPassphrase() {
370 var page = goToPage("passwdPage");
339 var page = goToPage("passwdPage");
371− tap(findChild(page, "passwdDelegate2"));
340+ tap(findChild(page, "passwdDelegate1")); // password option
372−
373 tap(findChild(page, "forwardButton"));
341 tap(findChild(page, "forwardButton"));
374 page = waitForPage("passwdSetPage");
342 page = waitForPage("passwdSetPage");
375
343
344+ var passwdField = findChild(page, "passwordField");
345+ verify(passwdField);
346+ tap(passwdField);
376 typeString("aaa");
347 typeString("aaa");
377− var continueButton = findChild(page, "forwardButton");
348+ var continueButton = findChild(page, "okButton");
378− tryCompare(continueButton.item, "enabled", false);
349+ tryCompare(continueButton, "enabled", false);
379− keyClick(Qt.Key_Enter);
380− var error = findChild(page, "wrongNoticeLabel");
381− tryCompareFunction(function() { return error.text !== ""; }, true);
382
350
351+ tap(passwdField);
352+ passwdField.selectAll(); // overwrite the text
383− typeString("aaaa");
353+ typeString("12345678");
384 tap(continueButton);
354 tap(continueButton);
385− page = waitForPage("passwdConfirmPage");
355+ wait(200);
386
356
387 // make sure we go back to 'set' page not 'type' page
357 // make sure we go back to 'set' page not 'type' page
388− var back = findChild(page, "backButton");
358+ var back = findChild(page, "cancelButton");
389 tap(back);
359 tap(back);
390− page = waitForPage("passwdSetPage");
360+ wait(200);
391−
392− typeString("aaaa");
393− keyClick(Qt.Key_Enter);
394− page = waitForPage("passwdConfirmPage");
395
361
396− continueButton = findChild(page, "forwardButton");
362+ passwdField = findChild(page, "passwordField");
363+ tryCompareFunction(function() {return !!passwdField}, true);
364+ tap(passwdField);
397 typeString("aaab");
365 typeString("aaab");
366+
367+ continueButton = findChild(page, "okButton");
398− tryCompare(continueButton.item, "enabled", false);
368+ tryCompare(continueButton, "enabled", false);
399− keyClick(Qt.Key_Enter);
400− var error = findChild(page, "wrongNoticeLabel");
369+ var error = findChild(page, "infoLabel");
401 tryCompareFunction(function() { return error.text !== ""; }, true);
370 tryCompareFunction(function() { return error.text !== ""; }, true);
402
371
372+ tap(passwdField);
373+ passwdField.selectAll(); // overwrite the text
374+ typeString("12345678");
375+ tap(continueButton);
376+ wait(200);
377+
378+ tap(passwdField);
379+ passwdField.selectAll(); // overwrite the text
403− typeString("aaaa");
380+ typeString("12345678");
404 tap(continueButton);
381 tap(continueButton);
405− page = waitForPage("wifiPage");
406
382
407 // now finish up
383 // now finish up
408− tap(findChild(page, "forwardButton"));
409− page = waitForPage("locationPage");
384+ page = waitForPage("reportingPage");
410 tap(findChild(page, "forwardButton"));
385 tap(findChild(page, "forwardButton"));
411 page = waitForPage("finishedPage");
386 page = waitForPage("finishedPage");
387+ waitUntilTransitionsEnd(page);
412− tap(findChild(page, "forwardButton"));
388+ tap(findChild(page, "finishButton"));
413
389
414 tryCompare(setSecuritySpy, "count", 1);
390 tryCompare(setSecuritySpy, "count", 1);
415 compare(setSecuritySpy.signalArguments[0][0], "");
391 compare(setSecuritySpy.signalArguments[0][0], "");
416− compare(setSecuritySpy.signalArguments[0][1], "aaaa");
392+ compare(setSecuritySpy.signalArguments[0][1], "12345678");
417 compare(setSecuritySpy.signalArguments[0][2], UbuntuSecurityPrivacyPanel.Passphrase);
393 compare(setSecuritySpy.signalArguments[0][2], UbuntuSecurityPrivacyPanel.Passphrase);
418 }
394 }
419
395
420 function test_passwdSwipe() {
396 function test_passwdSwipe() {
421− goToPage(null, false, false, true);
397+ var page = goToPage("passwdPage");
422−
398+ tap(findChild(page, "passwdDelegate3")); // swipe option
423− tryCompare(setSecuritySpy, "count", 1);
424− compare(setSecuritySpy.signalArguments[0][0], "");
425− compare(setSecuritySpy.signalArguments[0][1], "");
426− compare(setSecuritySpy.signalArguments[0][2], UbuntuSecurityPrivacyPanel.Swipe);
427− }
428−
429− function test_locationSkipNoPath() {
430− AccountsService.hereLicensePath = "";
431− goToPage("finishedPage", false, true, true);
432− }
433−
434− function test_locationSkipNoFiles() {
435− AccountsService.hereLicensePath = Qt.resolvedUrl("nolicenses");
436− goToPage("finishedPage", false, true, true);
437− }
438−
439− function test_locationWaitOnPath() {
440− AccountsService.hereLicensePath = " "; // means we're still getting the path from dbus
441−
442− var page = goToPage("wifiPage");
443
399
444− var pages = findChild(wizard, "wizardPages");
400+ // now finish up
445− var stack = findChild(pages, "pageStack");
446 tap(findChild(page, "forwardButton"));
401 tap(findChild(page, "forwardButton"));
447− // don't simply call tryCompare here, because stack.currentPage will be swapped out itself
402+ page = waitForPage("reportingPage");
448− tryCompareFunction(function() { return stack.currentPage.objectName; }, "locationPage");
403+ tap(findChild(page, "forwardButton"));
449− compare(stack.currentPage.enabled, false);
404+ page = waitForPage("finishedPage");
450− compare(stack.currentPage.skipValid, false);
405+ waitUntilTransitionsEnd(page);
406+ tap(findChild(page, "finishButton"));
451
407
452− AccountsService.hereLicensePath = "";
408+ tryCompare(setSecuritySpy, "count", 1);
453− waitForPage("finishedPage", false, false, true);
409+ //compare(setSecuritySpy.signalArguments[0][0], ""); // FIXME the swipe method collides with the account password
410+ //compare(setSecuritySpy.signalArguments[0][1], "");
411+ compare(setSecuritySpy.signalArguments[0][2], UbuntuSecurityPrivacyPanel.Swipe);
454 }
412 }
455
413
456 function test_locationGpsOnly() {
414 function test_locationGpsOnly() {
457 var page = goToPage("locationPage");
415 var page = goToPage("locationPage");
458− var gpsCheck = findChild(page, "gpsCheck");
416+ var gpsCheck = findChild(page, "gpsCheckLabel");
459− var hereCheck = findChild(page, "hereCheck");
417+ var hereCheck = findChild(page, "hereCheckLabel");
460− var nopeCheck = findChild(page, "nopeCheck");
418+ var nopeCheck = findChild(page, "nopeCheckLabel");
461
419
462 var locationActionGroup = findInvisibleChild(page, "locationActionGroup");
420 var locationActionGroup = findInvisibleChild(page, "locationActionGroup");
463 activateLocationSpy.target = locationActionGroup.location;
421 activateLocationSpy.target = locationActionGroup.location;
@@ -476,9 +434,9 @@ Item {
476
434
477 function test_locationNope() {
435 function test_locationNope() {
478 var page = goToPage("locationPage");
436 var page = goToPage("locationPage");
479− var gpsCheck = findChild(page, "gpsCheck");
437+ var gpsCheck = findChild(page, "gpsCheckLabel");
480− var hereCheck = findChild(page, "hereCheck");
438+ var hereCheck = findChild(page, "hereCheckLabel");
481− var nopeCheck = findChild(page, "nopeCheck");
439+ var nopeCheck = findChild(page, "nopeCheckLabel");
482
440
483 var locationActionGroup = findInvisibleChild(page, "locationActionGroup");
441 var locationActionGroup = findInvisibleChild(page, "locationActionGroup");
484 activateLocationSpy.target = locationActionGroup.location;
442 activateLocationSpy.target = locationActionGroup.location;
@@ -491,15 +449,15 @@ Item {
491
449
492 tap(findChild(page, "forwardButton"));
450 tap(findChild(page, "forwardButton"));
493 tryCompare(AccountsService, "hereEnabled", false);
451 tryCompare(AccountsService, "hereEnabled", false);
494− tryCompare(activateLocationSpy, "count", 0)
452+ tryCompare(activateLocationSpy, "count", 0);
495− tryCompare(activateGPSSpy, "count", 0)
453+ tryCompare(activateGPSSpy, "count", 0);
496 }
454 }
497
455
498 function test_locationHere() {
456 function test_locationHere() {
499 var page = goToPage("locationPage");
457 var page = goToPage("locationPage");
500− var gpsCheck = findChild(page, "gpsCheck");
458+ var gpsCheck = findChild(page, "gpsCheckLabel");
501− var hereCheck = findChild(page, "hereCheck");
459+ var hereCheck = findChild(page, "hereCheckLabel");
502− var nopeCheck = findChild(page, "nopeCheck");
460+ var nopeCheck = findChild(page, "nopeCheckLabel");
503
461
504 var locationActionGroup = findInvisibleChild(page, "locationActionGroup");
462 var locationActionGroup = findInvisibleChild(page, "locationActionGroup");
505 activateLocationSpy.target = locationActionGroup.location;
463 activateLocationSpy.target = locationActionGroup.location;
@@ -512,68 +470,81 @@ Item {
512
470
513 tap(findChild(page, "forwardButton"));
471 tap(findChild(page, "forwardButton"));
514 tryCompare(AccountsService, "hereEnabled", true);
472 tryCompare(AccountsService, "hereEnabled", true);
515− tryCompare(activateLocationSpy, "count", 1)
473+ tryCompare(activateLocationSpy, "count", 1);
516− tryCompare(activateGPSSpy, "count", 1)
474+ tryCompare(activateGPSSpy, "count", 1);
517 }
475 }
518
476
519− function test_locationHereTerms() {
477+ function test_timezonePage() {
520− var page = goToPage("locationPage");
478+ var page = goToPage("tzPage");
479+ verify(page);
480+ timezoneSpy.target = page.tdModule;
521
481
522− var link = findChild(page, "hereTermsLink");
482+ var tzFilter = findChild(page, "tzFilter");
483+ verify(tzFilter);
484+ tap(tzFilter);
485+ typeString("London");
523
486
524− // Test our language lookup code a bit
487+ var tzList = findChild(page, "tzList");
488+ verify(tzList);
525
489
526− i18n.language = "fr_FR.UTF-8";
490+ // test filtering works and returns some results
527− link.linkActivated("not-used");
491+ tryCompareFunction(function() { return tzList.count > 0; }, true);
528− page = waitForPage("hereTermsPage");
529− tryCompare(findChild(page, "termsLabel"), "text", "fr_FR\n");
530− tap(findChild(page, "backButton"));
531− waitForPage("locationPage");
532
492
533− i18n.language = "fr_CA";
493+ // just tap the first one
534− link.linkActivated("not-used");
535− page = waitForPage("hereTermsPage");
536− tryCompare(findChild(page, "termsLabel"), "text", "fr_CA\n");
537− tap(findChild(page, "backButton"));
494+ tap(findChild(page, "tz0"));
538− waitForPage("locationPage");
539
495
540− i18n.language = "fr_US";
496+ // go next and verify the (mock) signal got fired
541− link.linkActivated("not-used");
542− page = waitForPage("hereTermsPage");
543− tryCompare(findChild(page, "termsLabel"), "text", "fr_FR\n");
544− tap(findChild(page, "backButton"));
497+ tap(findChild(page, "forwardButton"));
545− waitForPage("locationPage");
498+ tryCompare(timezoneSpy, "count", 1);
499+ tryCompare(page.tdModule, "timeZone", timezoneSpy.signalArguments[0][0]);
500+ }
546
501
547− i18n.language = "fr.utf8";
502+ function test_accountPage() {
548− link.linkActivated("not-used");
503+ var page = goToPage("accountPage");
549− page = waitForPage("hereTermsPage");
504+ var password1 = findChild(page, "passInput");
550− tryCompare(findChild(page, "termsLabel"), "text", "fr_FR\n");
551− tap(findChild(page, "backButton"));
505+ var password2 = findChild(page, "pass2Input");
552− waitForPage("locationPage");
506+ var forwardButton = findChild(page, "forwardButton");
553
507
554− i18n.language = "es"; // will not be found
508+ tap(findChild(page, "nameInput"));
555− link.linkActivated("not-used");
509+ typeString("foobar");
556− page = waitForPage("hereTermsPage");
557− tryCompare(findChild(page, "termsLabel"), "text", "en_US\n");
558
510
559− // OK, done with languages, back to actual page
511+ verify(forwardButton.enabled, false); // no passwords yet
560
512
561− var label = findChild(page, "termsLabel");
513+ tap(password1);
562− label.linkActivated(Qt.resolvedUrl("licenses/en_US.html"));
514+ typeString("12345");
563− tryCompare(label, "visible", false);
564
515
565− var webview = findChild(page, "webview");
516+ verify(forwardButton.enabled, false); // password too short
566− tryCompare(webview, "visible", true);
567− tryCompare(webview, "url", Qt.resolvedUrl("licenses/en_US.html"));
568− tryCompare(webview, "loadProgress", 100);
569
517
570− tap(findChild(page, "backButton"));
518+ tap(password2);
571− waitForPage("hereTermsPage"); // confirm we're on same page
519+ typeString("12345678");
572− tryCompare(webview, "visible", false);
573− tryCompare(label, "visible", true);
574
520
575− tap(findChild(page, "backButton"));
521+ verify(forwardButton.enabled, false); // passwords don't match
522+
523+ tap(password1);
524+ password1.selectAll();
525+ typeString("12345678");
526+
527+ verify(forwardButton.enabled, true); // now they match
528+
529+ var pages = findChild(wizard, "wizardPages");
530+ var security = findInvisibleChild(pages, "securityPrivacy");
531+ setSecuritySpy.target = security;
532+
533+ // now finish up
534+ tap(forwardButton);
535+ page = waitForPage("passwdPage");
536+ tap(findChild(page, "passwdDelegate0")); // account option
537+ tap(findChild(page, "forwardButton"));
576− waitForPage("locationPage");
538+ page = waitForPage("reportingPage");
539+ tap(findChild(page, "forwardButton"));
540+ page = waitForPage("finishedPage");
541+ waitUntilTransitionsEnd(page);
542+ tap(findChild(page, "finishButton"));
543+
544+ tryCompare(setSecuritySpy, "count", 1);
545+ compare(setSecuritySpy.signalArguments[0][0], "");
546+ compare(setSecuritySpy.signalArguments[0][1], "12345678");
547+ compare(setSecuritySpy.signalArguments[0][2], UbuntuSecurityPrivacyPanel.Passphrase);
577 }
548 }
578 }
549 }
579}
550}