on xenial help sign in
implement logic for the Language page
8131d9cLukáš Tinkl
plugins/Wizard/CMakeLists.txt+1
@@ -2,6 +2,7 @@ add_library(Wizard-qml MODULE
2 plugin.cpp
2 plugin.cpp
3 PageList.cpp
3 PageList.cpp
4 System.cpp
4 System.cpp
5+ LocalePlugin.cpp
5 timezonemodel.cpp
6 timezonemodel.cpp
6)
7)
7
8
plugins/Wizard/LocalePlugin.cppnew file+74
@@ -0,0 +1,74 @@
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 "LocalePlugin.h"
21+
22+LocaleAttached::LocaleAttached(QObject* parent)
23+ : QObject(parent)
24+{
25+}
26+
27+QJsonObject LocaleAttached::languages() const
28+{
29+ QJsonObject result;
30+ for (int i = QLocale::C + 1; i < QLocale::LastLanguage; ++i) {
31+ QLocale loc(static_cast<QLocale::Language>(i));
32+ result.insert(loc.name().split('_').first(), QLocale::languageToString(loc.language()));
33+ }
34+
35+ return result;
36+}
37+
38+QJsonObject LocaleAttached::localesForLanguage(const QString &code) const
39+{
40+ QLocale tmp(code);
41+ const QList<QLocale> allLocales = QLocale::matchingLocales(tmp.language(), QLocale::AnyScript, QLocale::AnyCountry);
42+ QJsonObject result;
43+ for(const QLocale &loc: allLocales) {
44+ //qDebug() << "Matching locale:" << loc.name();
45+ result.insert(loc.name(), QStringLiteral("%1 (%2)").arg(QLocale::languageToString(loc.language())).arg(QLocale::countryToString(loc.country())));
46+ }
47+ return result;
48+}
49+
50+QJsonObject LocaleAttached::countries() const
51+{
52+ const QList<QLocale> allLocales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript, QLocale::AnyCountry);
53+ QJsonObject result;
54+
55+ for(const QLocale &loc: allLocales) {
56+ const QString countryCode = loc.name().section('_', 1, 1);
57+ if (!countryCode.isEmpty() && countryCode.length() == 2) {
58+ result.insert(countryCode, QLocale::countryToString(loc.country()));
59+ }
60+ }
61+
62+ return result;
63+}
64+
65+
66+LocalePlugin::LocalePlugin(QObject* parent)
67+ : QObject(parent)
68+{
69+}
70+
71+LocaleAttached* LocalePlugin::qmlAttachedProperties(QObject* parent)
72+{
73+ return new LocaleAttached(parent);
74+}
plugins/Wizard/LocalePlugin.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 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 QJsonObject languages() const;
33+ Q_INVOKABLE QJsonObject localesForLanguage(const QString &code) const;
34+ Q_INVOKABLE QJsonObject countries() const;
35+
36+ friend class LocalePlugin;
37+};
38+
39+/**
40+ * A simplified wrapper around QLocale.
41+ *
42+ * The wrapper is implemented as an attached property, which makes it possible
43+ * to use it as if its methods were static:
44+ *
45+ * @code
46+ * var langs = LocalePlugin.languages();
47+ * @endcode
48+ */
49+class LocalePlugin: public QObject
50+{
51+ Q_OBJECT
52+public:
53+ explicit LocalePlugin(QObject *parent = 0);
54+
55+ static LocaleAttached* qmlAttachedProperties(QObject *parent);
56+};
57+
58+QML_DECLARE_TYPEINFO(LocalePlugin, QML_HAS_ATTACHED_PROPERTIES)
59+
60+#endif // LOCALE_PLUGIN_H
plugins/Wizard/plugin.cpp+2
@@ -18,6 +18,7 @@
18#include "PageList.h"
18#include "PageList.h"
19#include "System.h"
19#include "System.h"
20#include "timezonemodel.h"
20#include "timezonemodel.h"
21+#include "LocalePlugin.h"
21
22
22#include <QtQml/qqml.h>
23#include <QtQml/qqml.h>
23
24
@@ -35,4 +36,5 @@ void WizardPlugin::registerTypes(const char *uri)
35 qmlRegisterSingletonType<System>(uri, 0, 1, "System", system_provider);
36 qmlRegisterSingletonType<System>(uri, 0, 1, "System", system_provider);
36 qmlRegisterType<TimeZoneModel>(uri, 0, 1, "TimeZoneModel");
37 qmlRegisterType<TimeZoneModel>(uri, 0, 1, "TimeZoneModel");
37 qmlRegisterType<TimeZoneFilterModel>(uri, 0, 1, "TimeZoneFilterModel");
38 qmlRegisterType<TimeZoneFilterModel>(uri, 0, 1, "TimeZoneFilterModel");
39+ qmlRegisterType<LocalePlugin>(uri, 0, 1, "LocalePlugin");
38}
40}
qml/Wizard/Page.qml+7−9
@@ -18,12 +18,12 @@ import QtQuick 2.3
18import Ubuntu.Components 1.1
18import Ubuntu.Components 1.1
19
19
20Item {
20Item {
21− readonly property real buttonMargin: units.gu(2)
21+ readonly property real buttonMargin: units.gu(3)
22 readonly property real buttonWidth: (width - buttonMargin * 2) / 2 -
22 readonly property real buttonWidth: (width - buttonMargin * 2) / 2 -
23 buttonMargin / 2
23 buttonMargin / 2
24− readonly property real topMargin: units.gu(8)
24+ readonly property real topMargin: units.gu(11)
25− readonly property real leftMargin: units.gu(2)
25+ readonly property real leftMargin: units.gu(3)
26− readonly property real rightMargin: units.gu(2)
26+ readonly property real rightMargin: units.gu(3)
27
27
28 // If you want to skip a page, mark skipValid false while you figure out
28 // 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
29 // whether to skip, then set it to true once you've determined the value
@@ -43,9 +43,7 @@ Item {
43 visible: false
43 visible: false
44 anchors.fill: parent
44 anchors.fill: parent
45
45
46− // We want larger than even fontSize: "x-large", so we use a Text instead
47− // of a Label.
46+ Label {
48− Text {
49 id: titleLabel
47 id: titleLabel
50 anchors {
48 anchors {
51 top: parent.top
49 top: parent.top
@@ -58,7 +56,7 @@ Item {
58 wrapMode: Text.Wrap
56 wrapMode: Text.Wrap
59 text: title
57 text: title
60 color: Theme.palette.normal.baseText
58 color: Theme.palette.normal.baseText
61− font.pixelSize: units.gu(4)
59+ fontSize: "x-large"
62 }
60 }
63
61
64 Item {
62 Item {
@@ -82,7 +80,7 @@ Item {
82 anchors {
80 anchors {
83 left: parent.left
81 left: parent.left
84 bottom: parent.bottom
82 bottom: parent.bottom
85− leftMargin: buttonMargin
83+ leftMargin: leftMargin
86 bottomMargin: buttonMargin
84 bottomMargin: buttonMargin
87 }
85 }
88 z: 1
86 z: 1
qml/Wizard/Pages/10-language.qmlnew file+153
@@ -0,0 +1,153 @@
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.3
18+import Ubuntu.Components 1.2
19+import Ubuntu.SystemSettings.LanguagePlugin 1.0
20+import Wizard 0.1
21+import ".." as LocalComponents
22+
23+LocalComponents.Page {
24+ objectName: "languagePage"
25+
26+ title: i18n.tr("Language")
27+ forwardButtonSourceComponent: forwardButton
28+
29+ property string selectedLanguage: ""
30+
31+ UbuntuLanguagePlugin {
32+ id: plugin
33+ }
34+
35+ Component.onCompleted: {
36+ populateModel(); // FIXME pass a list of detected languages here
37+ }
38+
39+ function populateModel(detectedLangs)
40+ {
41+ console.log("LanguagePage::populateModel: detected languages:" + detectedLangs);
42+ var allLangs = LocalePlugin.languages();
43+ if (!!detectedLangs) {
44+ addLanguagesToModel(detectedLangs);
45+ var remainingLangs = Object.keys(allLangs).filter(function(lang) {
46+ return (detectedLangs.indexOf(lang) === -1);
47+ });
48+ addLanguagesToModel(remainingLangs); // FIXME this assumes an array
49+ } else {
50+ addLanguagesToModel(allLangs);
51+ }
52+
53+ busyIndicator.running = false;
54+ busyIndicator.visible = false;
55+ }
56+
57+ function addLanguagesToModel(langs)
58+ {
59+ Object.keys(langs).map(function(code) { // prepare the object
60+ return { "code": code, "name": langs[code] };
61+ })
62+ .sort(function(a, b) { // sort by language name, not code
63+ return a.name.localeCompare(b.name);
64+ })
65+ .forEach(function(language) { // build the model
66+ model.append(
67+ { "language": language.name,
68+ "code": language.code
69+ }
70+ );
71+ });
72+ }
73+
74+ ActivityIndicator {
75+ id: busyIndicator;
76+
77+ anchors.centerIn: parent;
78+ running: true;
79+ }
80+
81+ Column {
82+ id: column
83+ anchors.fill: content
84+ spacing: units.gu(1)
85+
86+ ListView {
87+ id: languagesListView;
88+
89+ boundsBehavior: Flickable.StopAtBounds;
90+ clip: true;
91+ currentIndex: -1
92+
93+ anchors {
94+ left: parent.left;
95+ right: parent.right;
96+ topMargin: topMargin;
97+ }
98+
99+ height: column.height - column.spacing - topMargin
100+
101+ section {
102+ property: "language";
103+ criteria: ViewSection.FirstCharacter;
104+ }
105+
106+ model: ListModel {
107+ id: model;
108+ }
109+
110+ delegate: ListItem {
111+ id: itemDelegate;
112+
113+ readonly property bool isCurrent: index === ListView.view.currentIndex
114+
115+ Label {
116+ text: language;
117+
118+ anchors {
119+ left: parent.left;
120+ right: parent.right;
121+ verticalCenter: parent.verticalCenter;
122+ }
123+
124+ fontSize: "medium"
125+ font.weight: itemDelegate.isCurrent ? Font.Normal : Font.Light
126+ }
127+
128+ onClicked: {
129+ selectedLanguage = code
130+ ListView.view.currentIndex = index
131+ print("Selected language: " + selectedLanguage)
132+ print("Current index: " + ListView.view.currentIndex)
133+ }
134+ }
135+ }
136+ }
137+
138+ Component {
139+ id: forwardButton
140+ LocalComponents.StackButton {
141+ text: i18n.tr("Next")
142+ enabled: selectedLanguage !== ""
143+ onClicked: {
144+ if (selectedLanguage !== plugin.languageCodes[plugin.currentLanguage]) {
145+ //plugin.currentLanguage = listview.currentIndex; // setting system language by some magic index? wtf
146+ //System.updateSessionLanguage(selectedLanguage); // TODO
147+ i18n.language = i18n.language; // re-notify of change after above call (for qlocale change)
148+ }
149+ pageStack.next()
150+ }
151+ }
152+ }
153+}
qml/Wizard/Pages/10-welcome.qmldeleted−99
@@ -1,99 +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.3
18−import Ubuntu.Components 1.1
19−import Ubuntu.Components.ListItems 0.1
20−import Ubuntu.SystemSettings.LanguagePlugin 1.0
21−import Wizard 0.1
22−import ".." as LocalComponents
23−
24−LocalComponents.Page {
25− objectName: "languagePage"
26−
27− title: i18n.tr("Hi!")
28− forwardButtonSourceComponent: forwardButton
29−
30− UbuntuLanguagePlugin {
31− id: plugin
32− }
33−
34− Column {
35− id: column
36− anchors.fill: content
37− spacing: units.gu(1)
38−
39− Label {
40− id: label1
41− anchors.left: parent.left
42− anchors.right: parent.right
43− wrapMode: Text.Wrap
44− text: i18n.tr("Welcome to your Ubuntu phone.")
45− }
46−
47− Label {
48− id: label2
49− anchors.left: parent.left
50− anchors.right: parent.right
51− wrapMode: Text.Wrap
52− text: i18n.tr("Let’s get started.")
53− }
54−
55− Item { // spacer
56− height: units.gu(2)
57− width: units.gu(1) // needed else it will be ignored
58− }
59−
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
71− currentIndex: plugin.currentLanguage
72− delegate: Standard {
73− objectName: "languageDelegate" + index
74− text: modelData
75− onClicked: {
76− listview.currentIndex = index
77− combo.expanded = false
78− i18n.language = plugin.languageCodes[index]
79− }
80− }
81− }
82− }
83− }
84−
85− Component {
86− id: forwardButton
87− LocalComponents.StackButton {
88− text: i18n.tr("Continue")
89− onClicked: {
90− if (plugin.currentLanguage !== listview.currentIndex) {
91− plugin.currentLanguage = listview.currentIndex;
92− System.updateSessionLanguage(plugin.languageCodes[listview.currentIndex]);
93− i18n.language = i18n.language; // re-notify of change after above call (for qlocale change)
94− }
95− pageStack.next()
96− }
97− }
98− }
99−}
qml/Wizard/StackButton.qml+2−1
@@ -15,7 +15,7 @@
15 */
15 */
16
16
17import QtQuick 2.3
17import QtQuick 2.3
18−import Ubuntu.Components 1.1
18+import Ubuntu.Components 1.2
19
19
20AbstractButton {
20AbstractButton {
21 id: stackButton
21 id: stackButton
@@ -33,6 +33,7 @@ AbstractButton {
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.selected.backgroundText : Qt.darker(Theme.palette.selected.backgroundText, 1.5)
35 color: enabled ? Theme.palette.selected.backgroundText : Qt.darker(Theme.palette.selected.backgroundText, 1.5)
36+ font.weight: Font.DemiBold
36 text: {
37 text: {
37 if (backArrow) {
38 if (backArrow) {
38 // Translators: This is the arrow for "Back" buttons
39 // Translators: This is the arrow for "Back" buttons
tests/mocks/Ubuntu/SystemSettings/CMakeLists.txt+1−1
@@ -1,2 +1,2 @@
1−add_subdirectory(LanguagePlugin)
1+#add_subdirectory(LanguagePlugin)
2add_subdirectory(SecurityPrivacy)
2add_subdirectory(SecurityPrivacy)
tests/mocks/Wizard/CMakeLists.txt+1
@@ -7,6 +7,7 @@ add_library(MockWizard-qml MODULE
7 MockSystem.cpp
7 MockSystem.cpp
8 ${CMAKE_SOURCE_DIR}/plugins/Wizard/PageList.cpp
8 ${CMAKE_SOURCE_DIR}/plugins/Wizard/PageList.cpp
9 ${CMAKE_SOURCE_DIR}/plugins/Wizard/timezonemodel.cpp
9 ${CMAKE_SOURCE_DIR}/plugins/Wizard/timezonemodel.cpp
10+ ${CMAKE_SOURCE_DIR}/plugins/Wizard/LocalePlugin.cpp
10)
11)
11
12
12qt5_use_modules(MockWizard-qml Qml)
13qt5_use_modules(MockWizard-qml Qml)
tests/mocks/Wizard/mockplugin.cpp+2
@@ -18,6 +18,7 @@
18#include "MockSystem.h"
18#include "MockSystem.h"
19#include "PageList.h"
19#include "PageList.h"
20#include "timezonemodel.h"
20#include "timezonemodel.h"
21+#include "LocalePlugin.h"
21
22
22#include <QtQml/qqml.h>
23#include <QtQml/qqml.h>
23
24
@@ -35,4 +36,5 @@ void MockWizardPlugin::registerTypes(const char *uri)
35 qmlRegisterSingletonType<MockSystem>(uri, 0, 1, "System", system_provider);
36 qmlRegisterSingletonType<MockSystem>(uri, 0, 1, "System", system_provider);
36 qmlRegisterType<TimeZoneModel>(uri, 0, 1, "TimeZoneModel");
37 qmlRegisterType<TimeZoneModel>(uri, 0, 1, "TimeZoneModel");
37 qmlRegisterType<TimeZoneFilterModel>(uri, 0, 1, "TimeZoneFilterModel");
38 qmlRegisterType<TimeZoneFilterModel>(uri, 0, 1, "TimeZoneFilterModel");
39+ qmlRegisterType<LocalePlugin>(uri, 0, 1, "LocalePlugin");
38}
40}