on 4eca819 help sign in
41 files changed+2388−2462
since splitsnapshots
unifiedsplit
README.md+3−3 clickable.json+158 clickable.yaml−153 po/ar.po+3−3 po/cs.po+3−3 po/es.po+22−22 po/he.po+11−9 po/hu.po+11−9 po/it.po+6−6 po/km.po+14−11 po/nb.po+4−2 po/pt.po+4−4 po/sc.po+6−6 po/sv.po+52−25 po/th.po+20−20 po/ur.po+28−31 qml/Greeter/CoverPage.qml+36−26 qml/Greeter/Greeter.qml+2−21 qml/Greeter/GreeterPrompt.qml+3−3 qml/Greeter/GreeterView.qml−534 qml/Greeter/LoginList.qml+2−4 qml/Greeter/NarrowView.qml+277 qml/Greeter/PinPrompt.qml+1−1 qml/Greeter/PromptList.qml+19−16 qml/Greeter/WideView.qml+281 qml/Launcher/BackgroundBlur.qml−81 qml/Launcher/Drawer.qml+2−8 qml/Launcher/Launcher.qml+1−23 qml/OrientedShell.qml−1 qml/Panel/Indicators/IndicatorItem.qml−6 qml/Rotation/RotationStates.qml+3 qml/Shell.qml+2−7 src/ApplicationArguments.h−5 src/ShellApplication.cpp−6 tests/qmltests/CMakeLists.txt+2−1 tests/qmltests/Greeter/TestView.qml−7 tests/qmltests/Greeter/tst_GreeterView.qml−1366 tests/qmltests/Greeter/tst_NarrowView.qml+565 tests/qmltests/Greeter/tst_WideView.qml+801 tests/qmltests/tst_OrientedShell.qml+38−1 tests/qmltests/tst_Shell.qml+8−38
README.md+3−3
@@ -22,10 +22,10 @@ Now, clone this repository to your computer: `git clone https://github.com/ubpor
2222
2323Move into this directory: `cd unity8`
2424
25−Now you can use the full suite of tools provided by this repository's [clickable.yaml](clickable.yaml). For example:
25+Now you can use the full suite of tools provided by this repository's [clickable.json](clickable.json). For example:
2626
2727* `clickable ide qtcreator` will open QtCreator with this repository open as a project. You can edit and build the project this way, but running the tests will be a bit difficult.
28−* `clickable build --libs --verbose` will build Lomiri in the same environment as it would receive in Ubuntu Touch.
29−* `clickable test --libs` will run the entire Lomiri test suite. This test suite includes graphical tests (which are run on a virtual, invisible desktop) and non-graphical unit tests. These tests make sure Lomiri functions as prescribed and prevents new bugs from being added. You should run them before you create a PR on this repository. This command takes about 7 minutes on an Intel i7-8550U, so plan your time accordingly and use the next two options to reduce the number of times you need to run the whole test suite...
28+* `clickable build-libs --debug` will build Lomiri in the same environment as it would receive in Ubuntu Touch.
29+* `clickable test-libs` will run the entire Lomiri test suite. This test suite includes graphical tests (which are run on a virtual, invisible desktop) and non-graphical unit tests. These tests make sure Lomiri functions as prescribed and prevents new bugs from being added. You should run them before you create a PR on this repository. This command takes about 7 minutes on an Intel i7-8550U, so plan your time accordingly and use the next two options to reduce the number of times you need to run the whole test suite...
3030* `clickable ide 'cd build/x86_64-linux-gnu/unity8/ && make tryShell'` and similar commands that replace the `Shell` with another test target defined in [tests/qmltests/CMakeLists.txt](tests/qmltests/CMakeLists.txt) allow trying out some Lomiri components in a mock environment. You can use this to try out your changes to Lomiri as you develop.
3131* `clickable ide 'cd build/x86_64-linux-gnu/unity8/ && make xvfbtestShell'` and similar commands that replace the `Shell` with another test target defined in [tests/qmltests/CMakeLists.txt](tests/qmltests/CMakeLists.txt) allow running a single TestCase. You can remove the `xvfb` part of the make target to run the test case graphically, which might help you see what is causing the test to fail.
clickable.jsonnew file+158
@@ -0,0 +1,158 @@
1+{
2+ "builder": "custom",
3+ "build": "echo Run \\'clickable build-libs --debug\\' to build && false",
4+ "restrict_arch": "amd64",
5+ "libraries": {
6+ "unity8": {
7+ "builder": "cmake",
8+ "src_dir": "${ROOT}",
9+ "test": "make xvfballtests -j${NUM_PROCS}",
10+ "dependencies_host": [
11+ "android-headers",
12+ "cmake",
13+ "cmake-extras",
14+ "dbus-test-runner",
15+ "debhelper",
16+ "dh-apparmor",
17+ "doxyqml",
18+ "g++:native",
19+ "gdb",
20+ "graphviz",
21+ "gsettings-ubuntu-schemas",
22+ "libandroid-properties-dev",
23+ "libconnectivity-qt1-dev",
24+ "libevdev-dev",
25+ "libgeonames-dev",
26+ "libgl1-mesa-dev",
27+ "libgl1-mesa-dri",
28+ "libgles2-mesa-dev",
29+ "libglib2.0-dev",
30+ "libgnome-desktop-3-12",
31+ "libgnome-desktop-3-dev",
32+ "libgsettings-qt-dev",
33+ "libhardware-dev",
34+ "liblightdm-qt5-3-dev",
35+ "libpam0g-dev",
36+ "libpulse-dev",
37+ "libqmenumodel-dev",
38+ "libqt5sql5-sqlite",
39+ "libqt5svg5-dev",
40+ "libqt5xmlpatterns5-dev",
41+ "libqtdbusmock1-dev",
42+ "libqtdbustest1-dev",
43+ "libsystemsettings-dev",
44+ "libubuntu-app-launch2-dev",
45+ "libubuntu-download-manager-common-dev",
46+ "libubuntugestures5-dev",
47+ "libubuntugestures5-private-dev",
48+ "libudev-dev",
49+ "libudm-common-dev",
50+ "libunity-api-dev",
51+ "libusermetricsoutput1-dev",
52+ "libx11-dev",
53+ "libxcb1-dev",
54+ "libxi-dev",
55+ "pkg-config",
56+ "python3-all:any",
57+ "python3-setuptools:native",
58+ "qml-module-qt-labs-folderlistmodel",
59+ "qml-module-qt-labs-settings",
60+ "qml-module-qtmultimedia",
61+ "qml-module-qtqml-statemachine",
62+ "qml-module-qtquick-layouts",
63+ "qml-module-qtquick-xmllistmodel",
64+ "qml-module-qtquick2",
65+ "qml-module-qtsysteminfo",
66+ "qml-module-qttest",
67+ "qml-module-ubuntu-components",
68+ "qml-module-ubuntu-layouts",
69+ "qml-module-ubuntu-settings-components",
70+ "qml-module-ubuntu-test",
71+ "qtbase5-dev",
72+ "qtbase5-dev-tools",
73+ "qtbase5-private-dev",
74+ "qtdbustest-runner",
75+ "qtdeclarative5-dev",
76+ "qtdeclarative5-dev-tools",
77+ "qtdeclarative5-private-dev",
78+ "qtdeclarative5-ubuntu-content1",
79+ "ttf-ubuntu-font-family",
80+ "ubports-wallpapers",
81+ "xvfb"
82+ ]
83+ }
84+ },
85+ "dependencies_target": [
86+ "android-headers",
87+ "cmake",
88+ "cmake-extras",
89+ "dbus-test-runner",
90+ "debhelper",
91+ "dh-apparmor",
92+ "doxyqml",
93+ "g++:native",
94+ "gdb",
95+ "graphviz",
96+ "gsettings-ubuntu-schemas",
97+ "libandroid-properties-dev",
98+ "libconnectivity-qt1-dev",
99+ "libevdev-dev",
100+ "libgeonames-dev",
101+ "libgl1-mesa-dev",
102+ "libgl1-mesa-dri",
103+ "libgles2-mesa-dev",
104+ "libglib2.0-dev",
105+ "libgnome-desktop-3-12",
106+ "libgnome-desktop-3-dev",
107+ "libgsettings-qt-dev",
108+ "libhardware-dev",
109+ "liblightdm-qt5-3-dev",
110+ "libpam0g-dev",
111+ "libpulse-dev",
112+ "libqmenumodel-dev",
113+ "libqt5sql5-sqlite",
114+ "libqt5svg5-dev",
115+ "libqt5xmlpatterns5-dev",
116+ "libqtdbusmock1-dev",
117+ "libqtdbustest1-dev",
118+ "libsystemsettings-dev",
119+ "libubuntu-app-launch2-dev",
120+ "libubuntu-download-manager-common-dev",
121+ "libubuntugestures5-dev",
122+ "libubuntugestures5-private-dev",
123+ "libudev-dev",
124+ "libudm-common-dev",
125+ "libunity-api-dev",
126+ "libusermetricsoutput1-dev",
127+ "libx11-dev",
128+ "libxcb1-dev",
129+ "libxi-dev",
130+ "pkg-config",
131+ "python3-all:any",
132+ "python3-setuptools:native",
133+ "qml-module-qt-labs-folderlistmodel",
134+ "qml-module-qt-labs-settings",
135+ "qml-module-qtmultimedia",
136+ "qml-module-qtqml-statemachine",
137+ "qml-module-qtquick-layouts",
138+ "qml-module-qtquick-xmllistmodel",
139+ "qml-module-qtquick2",
140+ "qml-module-qtsysteminfo",
141+ "qml-module-qttest",
142+ "qml-module-ubuntu-components",
143+ "qml-module-ubuntu-layouts",
144+ "qml-module-ubuntu-settings-components",
145+ "qml-module-ubuntu-test",
146+ "qtbase5-dev",
147+ "qtbase5-dev-tools",
148+ "qtbase5-private-dev",
149+ "qtdbustest-runner",
150+ "qtdeclarative5-dev",
151+ "qtdeclarative5-dev-tools",
152+ "qtdeclarative5-private-dev",
153+ "qtdeclarative5-ubuntu-content1",
154+ "ttf-ubuntu-font-family",
155+ "ubports-wallpapers",
156+ "xvfb"
157+ ]
158+ }
clickable.yamldeleted−153
@@ -1,153 +0,0 @@
1−clickable_minimum_required: '7'
2−builder: custom
3−build: echo Run \'clickable build --libs --verbose\' to build && false
4−restrict_arch: amd64
5−libraries:
6− unity8:
7− builder: cmake
8− src_dir: "${ROOT}"
9− test: make xvfballtests -j${NUM_PROCS}
10− dependencies_host:
11− - android-headers
12− - cmake
13− - cmake-extras
14− - dbus-test-runner
15− - debhelper
16− - dh-apparmor
17− - doxyqml
18− - g++:native
19− - gdb
20− - graphviz
21− - gsettings-ubuntu-schemas
22− - libandroid-properties-dev
23− - libconnectivity-qt1-dev
24− - libevdev-dev
25− - libgeonames-dev
26− - libgl1-mesa-dev
27− - libgl1-mesa-dri
28− - libgles2-mesa-dev
29− - libglib2.0-dev
30− - libgnome-desktop-3-12
31− - libgnome-desktop-3-dev
32− - libgsettings-qt-dev
33− - libhardware-dev
34− - liblightdm-qt5-3-dev
35− - libpam0g-dev
36− - libpulse-dev
37− - libqmenumodel-dev
38− - libqt5sql5-sqlite
39− - libqt5svg5-dev
40− - libqt5xmlpatterns5-dev
41− - libqtdbusmock1-dev
42− - libqtdbustest1-dev
43− - libsystemsettings-dev
44− - libubuntu-app-launch2-dev
45− - libubuntu-download-manager-common-dev
46− - libubuntugestures5-dev
47− - libubuntugestures5-private-dev
48− - libudev-dev
49− - libudm-common-dev
50− - libunity-api-dev
51− - libusermetricsoutput1-dev
52− - libx11-dev
53− - libxcb1-dev
54− - libxi-dev
55− - pkg-config
56− - python3-all:any
57− - python3-setuptools:native
58− - qml-module-qt-labs-folderlistmodel
59− - qml-module-qt-labs-settings
60− - qml-module-qtmultimedia
61− - qml-module-qtqml-statemachine
62− - qml-module-qtquick-layouts
63− - qml-module-qtquick-xmllistmodel
64− - qml-module-qtquick2
65− - qml-module-qtsysteminfo
66− - qml-module-qttest
67− - qml-module-ubuntu-components
68− - qml-module-ubuntu-layouts
69− - qml-module-ubuntu-settings-components
70− - qml-module-ubuntu-test
71− - qtbase5-dev
72− - qtbase5-dev-tools
73− - qtbase5-private-dev
74− - qtdbustest-runner
75− - qtdeclarative5-dev
76− - qtdeclarative5-dev-tools
77− - qtdeclarative5-private-dev
78− - qtdeclarative5-ubuntu-content1
79− - ttf-ubuntu-font-family
80− - ubports-wallpapers
81− - xvfb
82−dependencies_target:
83− - android-headers
84− - cmake
85− - cmake-extras
86− - dbus-test-runner
87− - debhelper
88− - dh-apparmor
89− - doxyqml
90− - g++:native
91− - gdb
92− - graphviz
93− - gsettings-ubuntu-schemas
94− - libandroid-properties-dev
95− - libconnectivity-qt1-dev
96− - libevdev-dev
97− - libgeonames-dev
98− - libgl1-mesa-dev
99− - libgl1-mesa-dri
100− - libgles2-mesa-dev
101− - libglib2.0-dev
102− - libgnome-desktop-3-12
103− - libgnome-desktop-3-dev
104− - libgsettings-qt-dev
105− - libhardware-dev
106− - liblightdm-qt5-3-dev
107− - libpam0g-dev
108− - libpulse-dev
109− - libqmenumodel-dev
110− - libqt5sql5-sqlite
111− - libqt5svg5-dev
112− - libqt5xmlpatterns5-dev
113− - libqtdbusmock1-dev
114− - libqtdbustest1-dev
115− - libsystemsettings-dev
116− - libubuntu-app-launch2-dev
117− - libubuntu-download-manager-common-dev
118− - libubuntugestures5-dev
119− - libubuntugestures5-private-dev
120− - libudev-dev
121− - libudm-common-dev
122− - libunity-api-dev
123− - libusermetricsoutput1-dev
124− - libx11-dev
125− - libxcb1-dev
126− - libxi-dev
127− - pkg-config
128− - python3-all:any
129− - python3-setuptools:native
130− - qml-module-qt-labs-folderlistmodel
131− - qml-module-qt-labs-settings
132− - qml-module-qtmultimedia
133− - qml-module-qtqml-statemachine
134− - qml-module-qtquick-layouts
135− - qml-module-qtquick-xmllistmodel
136− - qml-module-qtquick2
137− - qml-module-qtsysteminfo
138− - qml-module-qttest
139− - qml-module-ubuntu-components
140− - qml-module-ubuntu-layouts
141− - qml-module-ubuntu-settings-components
142− - qml-module-ubuntu-test
143− - qtbase5-dev
144− - qtbase5-dev-tools
145− - qtbase5-private-dev
146− - qtdbustest-runner
147− - qtdeclarative5-dev
148− - qtdeclarative5-dev-tools
149− - qtdeclarative5-private-dev
150− - qtdeclarative5-ubuntu-content1
151− - ttf-ubuntu-font-family
152− - ubports-wallpapers
153− - xvfb
po/ar.po+3−3
@@ -8,7 +8,7 @@ msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: \n"
1010"POT-Creation-Date: 2021-01-29 11:42-0600\n"
11−"PO-Revision-Date: 2021-10-12 07:49+0000\n"
11+"PO-Revision-Date: 2021-10-03 05:18+0000\n"
1212"Last-Translator: HEROBRINE7GAMER <tapermeerkat77@gmail.com>\n"
1313"Language-Team: Arabic <https://translate.ubports.com/projects/ubports/lomiri/"
1414"ar/>\n"
@@ -73,7 +73,7 @@ msgstr "اخرج"
7373
7474#: qml/Components/Dialogs.qml:177
7575msgid "Are you sure you want to log out?"
76−msgstr "أمتأكد أنك تريد تسجيل الخروج ؟"
76+msgstr "أمتأكد أنك تريد الخروج ؟"
7777
7878#: qml/Components/Dialogs.qml:180
7979msgctxt "Button: Lock the system"
@@ -625,7 +625,7 @@ msgstr "تخطيط لوحة المفاتيح"
625625#: qml/Wizard/Pages/60-account.qml:72 qml/Wizard/Pages/79-system-update.qml:144
626626#: qml/Wizard/Pages/sim.qml:101
627627msgid "Skip"
628−msgstr "تخط"
628+msgstr "تخطى"
629629
630630#: qml/Wizard/Pages/30-wifi.qml:31
631631msgid "Connect to Wi‑Fi"
po/cs.po+3−3
@@ -8,7 +8,7 @@ msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: \n"
1010"POT-Creation-Date: 2021-01-29 11:42-0600\n"
11−"PO-Revision-Date: 2021-12-05 18:44+0000\n"
11+"PO-Revision-Date: 2021-08-21 07:57+0000\n"
1212"Last-Translator: Milan Korecký <milan.korecky@gmail.com>\n"
1313"Language-Team: Czech <https://translate.ubports.com/projects/ubports/lomiri/"
1414"cs/>\n"
@@ -481,8 +481,8 @@ msgstr[2] "%1 minuty"
481481msgid "%1 second"
482482msgid_plural "%1 seconds"
483483msgstr[0] "%1 sekunda"
484−msgstr[1] "%1 sekund"
485−msgstr[2] ""
484+msgstr[1] "%1 sekundy"
485+msgstr[2] "%1 sekund"
486486
487487#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:1009
488488msgid "0 seconds"
po/es.po+22−22
@@ -8,8 +8,8 @@ msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: \n"
1010"POT-Creation-Date: 2021-01-29 11:42-0600\n"
11−"PO-Revision-Date: 2021-10-04 12:20+0000\n"
12−"Last-Translator: Adolfo Jayme Barrientos <fitojb@ubuntu.com>\n"
11+"PO-Revision-Date: 2021-03-31 05:24+0000\n"
12+"Last-Translator: Josué <j2g2rp@gmail.com>\n"
1313"Language-Team: Spanish <https://translate.ubports.com/projects/ubports/"
1414"lomiri/es/>\n"
1515"Language: es\n"
@@ -34,11 +34,11 @@ msgstr "Fallo al autenticar"
3434
3535#: plugins/LightDM/Greeter.cpp:260
3636msgid "Invalid password, please try again"
37−msgstr "Contraseña incorrecta; inténtelo de nuevo"
37+msgstr "Contraseña incorrecta, por favor, inténtelo de nuevo"
3838
3939#: plugins/LightDM/Greeter.cpp:270
4040msgid "Log In"
41−msgstr "Acceder"
41+msgstr "Iniciar sesión"
4242
4343#: plugins/LightDM/Greeter.cpp:270
4444msgid "Retry"
@@ -46,7 +46,7 @@ msgstr "Reintentar"
4646
4747#: plugins/LightDM/UsersModel.cpp:157
4848msgid "Login"
49−msgstr "Acceder"
49+msgstr "Iniciar sesión"
5050
5151#: plugins/LightDM/UsersModel.cpp:165
5252msgid "Guest Session"
@@ -68,7 +68,7 @@ msgstr "Desanclar atajo"
6868#: qml/Components/Dialogs.qml:176
6969msgctxt "Title: Lock/Log out dialog"
7070msgid "Log out"
71−msgstr "Cerrar sesión"
71+msgstr "Cerrar la sesión"
7272
7373#: qml/Components/Dialogs.qml:177
7474msgid "Are you sure you want to log out?"
@@ -82,7 +82,7 @@ msgstr "Bloquear"
8282#: qml/Components/Dialogs.qml:191
8383msgctxt "Button: Log out from the system"
8484msgid "Log Out"
85−msgstr "Cerrar sesión"
85+msgstr "Cerrar la sesión"
8686
8787#: qml/Components/Dialogs.qml:199 qml/Components/Dialogs.qml:284
8888#: qml/Greeter/NarrowView.qml:215 qml/Wizard/Pages/passcode-confirm.qml:32
@@ -164,7 +164,7 @@ msgstr "Super + Espacio"
164164
165165#: qml/Components/KeyboardShortcutsOverlay.qml:93
166166msgid "Switches to next keyboard layout."
167−msgstr "Cambia a la disposición de teclado siguiente."
167+msgstr "Cambia a la siguiente disposición de teclado."
168168
169169#: qml/Components/KeyboardShortcutsOverlay.qml:101
170170msgid "Super + Shift + Space"
@@ -172,7 +172,7 @@ msgstr "Super + Mayús + Espacio"
172172
173173#: qml/Components/KeyboardShortcutsOverlay.qml:106
174174msgid "Switches to previous keyboard layout."
175−msgstr "Cambia a la disposición de teclado anterior."
175+msgstr "Cambia a la anterior disposición de teclado."
176176
177177#: qml/Components/KeyboardShortcutsOverlay.qml:114
178178msgid "Ctrl + Alt + T"
@@ -184,15 +184,15 @@ msgstr "Abre la aplicación Terminal."
184184
185185#: qml/Components/KeyboardShortcutsOverlay.qml:131
186186msgid "Launcher"
187−msgstr "Iniciador"
187+msgstr "Lanzador"
188188
189189#: qml/Components/KeyboardShortcutsOverlay.qml:138
190190msgid "Super (Hold)"
191−msgstr "Súper (mantener)"
191+msgstr "Super (Mantener)"
192192
193193#: qml/Components/KeyboardShortcutsOverlay.qml:143
194194msgid "Opens the launcher, displays shortcuts."
195−msgstr "Abre el iniciador y muestra los atajos."
195+msgstr "Abre el lanzador y muestra los atajos."
196196
197197#: qml/Components/KeyboardShortcutsOverlay.qml:151
198198msgid "Alt + F1"
@@ -200,7 +200,7 @@ msgstr "Alt + F1"
200200
201201#: qml/Components/KeyboardShortcutsOverlay.qml:156
202202msgid "Opens launcher keyboard navigation mode."
203−msgstr "Abre el iniciador en modo de navegación de teclado."
203+msgstr "Abre el Lanzador en modo de navegación de teclado."
204204
205205#: qml/Components/KeyboardShortcutsOverlay.qml:164
206206msgid "Super + Tab"
@@ -208,7 +208,7 @@ msgstr "Super + Tab"
208208
209209#: qml/Components/KeyboardShortcutsOverlay.qml:169
210210msgid "Switches applications via the launcher."
211−msgstr "Cambia de aplicación mediante el iniciador."
211+msgstr "Recorre las aplicaciones del Lanzador."
212212
213213#: qml/Components/KeyboardShortcutsOverlay.qml:177
214214msgid "Super + 1 to 0"
@@ -216,7 +216,7 @@ msgstr "Súper + 1 a 0"
216216
217217#: qml/Components/KeyboardShortcutsOverlay.qml:182
218218msgid "Same as clicking on a launcher icon."
219−msgstr "Lo mismo que pulsar en un icono del iniciador."
219+msgstr "Lo mismo que hacer clic en un icono del Lanzador."
220220
221221#: qml/Components/KeyboardShortcutsOverlay.qml:190
222222msgid "Super + A"
@@ -288,7 +288,7 @@ msgstr "Ctrl + Super + Arriba o Derecha"
288288
289289#: qml/Components/KeyboardShortcutsOverlay.qml:336
290290msgid "Semi-maximizes the current window."
291−msgstr "Semimaximiza la ventana actual."
291+msgstr "Semi-maximiza la ventana actual."
292292
293293#: qml/Components/KeyboardShortcutsOverlay.qml:344
294294msgid "Alt + F4"
@@ -373,7 +373,7 @@ msgstr "Deslice con dos dedos para desplazarse."
373373
374374#: qml/Components/VirtualTouchPad.qml:396
375375msgid "Find more settings in the system settings."
376−msgstr "Encuentre más ajustes en Configuración del sistema."
376+msgstr "Encuentre mas ajustes en la configuración del sistema."
377377
378378#: qml/Greeter/CoverPage.qml:127
379379msgid "Unlock"
@@ -549,21 +549,21 @@ msgstr ""
549549
550550#: qml/Tutorial/TutorialLeft.qml:47
551551msgid "Short swipe from the left edge to open the launcher"
552−msgstr "Deslice un poco desde el borde izquierdo para abrir el iniciador"
552+msgstr "Deslizar un poco desde el borde izquierdo para abrir el lanzador"
553553
554554#: qml/Tutorial/TutorialRight.qml:54
555555msgid "Push your mouse against the right edge to view your open apps"
556556msgstr ""
557−"Para ver las aplicaciones abiertas empuje el ratón contra el borde derecho"
557+"Para ver las aplicaciones abiertas empuja el ratón contra el borde derecho"
558558
559559#: qml/Tutorial/TutorialRight.qml:55
560560msgid "Swipe from the right edge to view your open apps"
561−msgstr "Deslice desde el borde derecho para ver las aplicaciones abiertas"
561+msgstr "Deslizar desde el borde derecho para ver las aplis abiertas"
562562
563563#: qml/Tutorial/TutorialTop.qml:53
564564msgid "Swipe from the top edge to access notifications and quick settings"
565565msgstr ""
566−"Deslice desde el borde superior para acceder a las notificaciones y "
566+"Deslizar desde el borde superior para acceder a las notificaciones y "
567567"configuración"
568568
569569#: qml/Wizard/Page.qml:59
@@ -583,7 +583,7 @@ msgstr "Idioma"
583583#: qml/Wizard/Pages/passcode-desktop.qml:154
584584#: qml/Wizard/Pages/password-set.qml:153
585585msgid "Next"
586−msgstr "Sig."
586+msgstr "Siguiente"
587587
588588#: qml/Wizard/Pages/10-welcome-update.qml:91
589589msgid "Welcome to "
po/he.po+11−9
@@ -8,9 +8,9 @@ msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: \n"
1010"POT-Creation-Date: 2021-01-29 11:42-0600\n"
11−"PO-Revision-Date: 2022-02-07 20:15+0000\n"
12−"Last-Translator: anonymous <noreply@weblate.org>\n"
13−"Language-Team: Hebrew <https://translate.ubports.com/projects/ubports/lomiri/"
11+"PO-Revision-Date: 2020-09-05 22:10+0000\n"
12+"Last-Translator: tamer dab <dabsantamer@yahoo.com>\n"
13+"Language-Team: Hebrew <https://translate.ubports.com/projects/unity8/unity8/"
1414"he/>\n"
1515"Language: he\n"
1616"MIME-Version: 1.0\n"
@@ -129,8 +129,10 @@ msgid "Restart"
129129msgstr "הפעלה מחדש"
130130
131131#: qml/Components/Dialogs.qml:276
132+#, fuzzy
133+#| msgid "Takes a screenshot."
132134msgid "Screenshot"
133−msgstr "צילום מסך"
135+msgstr "מצלם מסך."
134136
135137#: qml/Components/KeyboardShortcutsOverlay.qml:41
136138msgid "Keyboard Shortcuts"
@@ -138,7 +140,7 @@ msgstr "קיצורי דרך במקלדת"
138140
139141#: qml/Components/KeyboardShortcutsOverlay.qml:55
140142msgid "Lomiri"
141−msgstr "Lomiri"
143+msgstr ""
142144
143145#: qml/Components/KeyboardShortcutsOverlay.qml:62
144146msgid "PrtScr"
@@ -456,13 +458,13 @@ msgstr "שום דבר לא מתנגן"
456458msgid "%1 hour"
457459msgid_plural "%1 hours"
458460msgstr[0] "%1 שעה"
459−msgstr[1] "%1 שעת"
461+msgstr[1] "%1 שעות"
460462
461463#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:1001
462464#, qt-format
463465msgid "%1 minute"
464466msgid_plural "%1 minutes"
465−msgstr[0] "%1 דקה"
467+msgstr[0] "דקה %1"
466468msgstr[1] "%1 דקות"
467469
468470#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:1006
@@ -524,7 +526,7 @@ msgstr "התקשר חזרה"
524526
525527#: qml/Panel/PanelMenuPage.qml:92
526528msgid "Back"
527−msgstr "חזרה"
529+msgstr "חזור"
528530
529531#: qml/Stage/SideStage.qml:76
530532msgid "Drag using 3 fingers any application from one window to the other"
@@ -557,7 +559,7 @@ msgstr "החלק מהקצה העליון כדי לגשת להתראות ולהג
557559#: qml/Wizard/Page.qml:59
558560msgctxt "Button: Go back one page in the Wizard"
559561msgid "Back"
560−msgstr "חזרה"
562+msgstr "חזור"
561563
562564#: qml/Wizard/Pages/10-welcome.qml:29
563565msgid "Language"
po/hu.po+11−9
@@ -8,8 +8,8 @@ msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: \n"
1010"POT-Creation-Date: 2021-01-29 11:42-0600\n"
11−"PO-Revision-Date: 2022-02-06 00:18+0000\n"
12−"Last-Translator: Lundrin <berenyi.vilmos@tutanota.com>\n"
11+"PO-Revision-Date: 2021-03-17 10:43+0000\n"
12+"Last-Translator: David Farkas <dvdfrks@gmail.com>\n"
1313"Language-Team: Hungarian <https://translate.ubports.com/projects/ubports/"
1414"lomiri/hu/>\n"
1515"Language: hu\n"
@@ -88,7 +88,7 @@ msgstr "Kijelentkezés"
8888#: qml/Greeter/NarrowView.qml:215 qml/Wizard/Pages/passcode-confirm.qml:32
8989#: qml/Wizard/Pages/passcode-set.qml:32
9090msgid "Cancel"
91−msgstr "Mégse"
91+msgstr "Mégsem"
9292
9393#: qml/Components/Dialogs.qml:211
9494msgctxt "Title: Reboot dialog"
@@ -131,8 +131,10 @@ msgid "Restart"
131131msgstr "Újraindítás"
132132
133133#: qml/Components/Dialogs.qml:276
134+#, fuzzy
135+#| msgid "Takes a screenshot."
134136msgid "Screenshot"
135−msgstr "Képernyőmentés"
137+msgstr "Képernyőkép készítése."
136138
137139#: qml/Components/KeyboardShortcutsOverlay.qml:41
138140msgid "Keyboard Shortcuts"
@@ -140,7 +142,7 @@ msgstr "Gyorsbillentyűk"
140142
141143#: qml/Components/KeyboardShortcutsOverlay.qml:55
142144msgid "Lomiri"
143−msgstr "Lomiri"
145+msgstr ""
144146
145147#: qml/Components/KeyboardShortcutsOverlay.qml:62
146148msgid "PrtScr"
@@ -504,7 +506,7 @@ msgstr "Megszakítva"
504506
505507#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:1027
506508msgid "Finished"
507−msgstr "Kész"
509+msgstr "Befejeződött"
508510
509511#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:1029
510512msgid "Failed, tap to retry"
@@ -576,7 +578,7 @@ msgstr "Nyelv"
576578#: qml/Wizard/Pages/passcode-desktop.qml:154
577579#: qml/Wizard/Pages/password-set.qml:153
578580msgid "Next"
579−msgstr "Köv."
581+msgstr "Következő"
580582
581583#: qml/Wizard/Pages/10-welcome-update.qml:91
582584msgid "Welcome to "
@@ -618,7 +620,7 @@ msgstr "Csatlakozás Wi-Fi hálózathoz"
618620
619621#: qml/Wizard/Pages/30-wifi.qml:139
620622msgid "Connected"
621−msgstr "Csatlakozva"
623+msgstr "Kapcsolódva"
622624
623625#: qml/Wizard/Pages/30-wifi.qml:172
624626msgid "Available Wi-Fi networks"
@@ -739,7 +741,7 @@ msgstr "Adjon meg egy 4 számjegyű jelkódot"
739741#: qml/Wizard/Pages/passcode-desktop.qml:84
740742#: qml/Wizard/Pages/passcode-set.qml:54
741743msgid "Choose passcode"
742−msgstr "Válasszon jelkódot"
744+msgstr "Jelkód megadása"
743745
744746#: qml/Wizard/Pages/passcode-desktop.qml:139
745747msgid "Passcode too short"
po/it.po+6−6
@@ -8,8 +8,8 @@ msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: \n"
1010"POT-Creation-Date: 2021-01-29 11:42-0600\n"
11−"PO-Revision-Date: 2022-01-22 21:58+0000\n"
12−"Last-Translator: Matteo <mattbel10@hotmail.com>\n"
11+"PO-Revision-Date: 2021-07-18 22:26+0000\n"
12+"Last-Translator: Mike <miguel2000@livecom.it>\n"
1313"Language-Team: Italian <https://translate.ubports.com/projects/ubports/"
1414"lomiri/it/>\n"
1515"Language: it\n"
@@ -409,7 +409,7 @@ msgstr "Riprova"
409409
410410#: qml/Greeter/Greeter.qml:551
411411msgid "Enter passphrase to unlock"
412−msgstr "Inserire parola chiave per sbloccare"
412+msgstr "Inserire passphrase per sbloccare"
413413
414414#: qml/Greeter/Greeter.qml:552
415415msgid "Enter passcode to unlock"
@@ -421,7 +421,7 @@ msgstr "Emergenza"
421421
422422#: qml/Greeter/PromptList.qml:126
423423msgid "Passphrase"
424−msgstr "Parola chiave"
424+msgstr "Passphrase"
425425
426426#: qml/Greeter/PromptList.qml:126
427427msgid "Passcode"
@@ -540,12 +540,12 @@ msgstr "Trascinare con 3 dita qualsiasi applicazione da una finestra all'altra"
540540
541541#: qml/Stage/Stage.qml:671
542542msgid "No running apps"
543−msgstr "Nessuna applicazione in esecuzione"
543+msgstr "Nessun applicazione in esecuzione"
544544
545545#: qml/Tutorial/TutorialLeftLong.qml:49
546546msgid "Long swipe from the left edge to open the Application Drawer"
547547msgstr ""
548−"Scorrere lentamente dal bordo sinistro per aprire il Cassetto delle "
548+"Scorrere lentamente dal bordo sinistro per aprire il Drawer delle "
549549"Applicazioni"
550550
551551#: qml/Tutorial/TutorialLeft.qml:47
po/km.po+14−11
@@ -8,17 +8,16 @@ msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: \n"
1010"POT-Creation-Date: 2021-01-29 11:42-0600\n"
11−"PO-Revision-Date: 2022-03-14 13:38+0000\n"
12−"Last-Translator: ប៉ុកណូ រ៉ូយ៉ាល់ <poknoroyal@outlook.com>\n"
13−"Language-Team: Central Khmer <https://translate.ubports.com/projects/ubports/"
14−"lomiri/km/>\n"
15−"Language: km\n"
11+"PO-Revision-Date: 2014-08-20 02:48+0000\n"
12+"Last-Translator: Sophea Sok <sksophea@gmail.com>\n"
13+"Language-Team: Khmer <km@li.org>\n"
14+"Language: \n"
1615"MIME-Version: 1.0\n"
1716"Content-Type: text/plain; charset=UTF-8\n"
1817"Content-Transfer-Encoding: 8bit\n"
1918"Plural-Forms: nplurals=1; plural=0;\n"
20−"X-Generator: Weblate 3.11.3\n"
2119"X-Launchpad-Export-Date: 2016-11-23 06:35+0000\n"
20+"X-Generator: Launchpad (build 18269)\n"
2221
2322#: plugins/LightDM/Greeter.cpp:199
2423msgid "Password: "
@@ -26,7 +25,7 @@ msgstr "ពាក្យសម្ងាត់៖ "
2625
2726#: plugins/LightDM/Greeter.cpp:214
2827msgid "Username"
29−msgstr "អត្ថនាម"
28+msgstr ""
3029
3130#: plugins/LightDM/Greeter.cpp:258
3231msgid "Failed to authenticate"
@@ -376,7 +375,7 @@ msgstr ""
376375
377376#: qml/Greeter/CoverPage.qml:127
378377msgid "Unlock"
379−msgstr "ដោះសោ"
378+msgstr "ដោះ​សោ"
380379
381380#: qml/Greeter/DelayedLockscreen.qml:43
382381msgid "Device Locked"
@@ -524,8 +523,11 @@ msgid "Call back"
524523msgstr "ហៅ​មកវិញ"
525524
526525#: qml/Panel/PanelMenuPage.qml:92
526+#, fuzzy
527+#| msgctxt "Button: Go back one page in the Wizard"
528+#| msgid "Back"
527529msgid "Back"
528−msgstr "បកក្រោយ"
530+msgstr "ថយក្រោយ"
529531
530532#: qml/Stage/SideStage.qml:76
531533msgid "Drag using 3 fingers any application from one window to the other"
@@ -590,8 +592,9 @@ msgid "What's new"
590592msgstr ""
591593
592594#: qml/Wizard/Pages/11-changelog.qml:74
595+#, fuzzy
593596msgid "Loading..."
594−msgstr "កំពុងផ្ទុក…"
597+msgstr "កំពុង​និយាយ..."
595598
596599#: qml/Wizard/Pages/20-keyboard.qml:31
597600msgid "Select Keyboard"
@@ -603,7 +606,7 @@ msgstr ""
603606
604607#: qml/Wizard/Pages/20-keyboard.qml:93
605608msgid "Keyboard layout"
606−msgstr "ប្លង់ក្ដារចុច"
609+msgstr ""
607610
608611#: qml/Wizard/Pages/20-keyboard.qml:152 qml/Wizard/Pages/30-wifi.qml:214
609612#: qml/Wizard/Pages/60-account.qml:72 qml/Wizard/Pages/79-system-update.qml:144
po/nb.po+4−2
@@ -8,7 +8,7 @@ msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: \n"
1010"POT-Creation-Date: 2021-01-29 11:42-0600\n"
11−"PO-Revision-Date: 2021-10-15 10:11+0000\n"
11+"PO-Revision-Date: 2021-07-22 23:44+0000\n"
1212"Last-Translator: Allan Nordhøy <epost@anotheragency.no>\n"
1313"Language-Team: Norwegian Bokmål <https://translate.ubports.com/projects/"
1414"ubports/lomiri/nb/>\n"
@@ -131,8 +131,10 @@ msgid "Restart"
131131msgstr "Start på nytt"
132132
133133#: qml/Components/Dialogs.qml:276
134+#, fuzzy
135+#| msgid "Takes a screenshot."
134136msgid "Screenshot"
135−msgstr "Skjermavbildning"
137+msgstr "Tar bilde av skjermen."
136138
137139#: qml/Components/KeyboardShortcutsOverlay.qml:41
138140msgid "Keyboard Shortcuts"
po/pt.po+4−4
@@ -8,8 +8,8 @@ msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: \n"
1010"POT-Creation-Date: 2021-01-29 11:42-0600\n"
11−"PO-Revision-Date: 2021-11-19 22:39+0000\n"
12−"Last-Translator: Hugo Carvalho <hugokarvalho@hotmail.com>\n"
11+"PO-Revision-Date: 2021-06-01 14:51+0000\n"
12+"Last-Translator: Ivo Xavier <ivofernandes12@gmail.com>\n"
1313"Language-Team: Portuguese <https://translate.ubports.com/projects/ubports/"
1414"lomiri/pt/>\n"
1515"Language: pt\n"
@@ -531,7 +531,7 @@ msgstr "Ligar de volta"
531531
532532#: qml/Panel/PanelMenuPage.qml:92
533533msgid "Back"
534−msgstr "Voltar"
534+msgstr "Retroceder"
535535
536536#: qml/Stage/SideStage.qml:76
537537msgid "Drag using 3 fingers any application from one window to the other"
@@ -712,7 +712,7 @@ msgstr "Está pronto/a para usar o seu dispositivo"
712712
713713#: qml/Wizard/Pages/80-finished.qml:126
714714msgid "Continue"
715−msgstr "Continuar"
715+msgstr "Avançar"
716716
717717#: qml/Wizard/Pages/80-finished.qml:126
718718msgid "Get Started"
po/sc.po+6−6
@@ -8,7 +8,7 @@ msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: \n"
1010"POT-Creation-Date: 2021-01-29 11:42-0600\n"
11−"PO-Revision-Date: 2021-11-21 15:09+0000\n"
11+"PO-Revision-Date: 2021-04-22 10:44+0000\n"
1212"Last-Translator: Adria <adriamartinmor@gmail.com>\n"
1313"Language-Team: Sardinian <https://translate.ubports.com/projects/ubports/"
1414"lomiri/sc/>\n"
@@ -539,7 +539,7 @@ msgstr "Traga cun 3 ditos is aplicatziones dae una ventana a s'àtera"
539539
540540#: qml/Stage/Stage.qml:671
541541msgid "No running apps"
542−msgstr "Nissuna aplicatzione ativa"
542+msgstr "Peruna aplicatzione ativa"
543543
544544#: qml/Tutorial/TutorialLeftLong.qml:49
545545msgid "Long swipe from the left edge to open the Application Drawer"
@@ -634,7 +634,7 @@ msgstr "Retes Wi-Fi a disponimentu"
634634
635635#: qml/Wizard/Pages/30-wifi.qml:173
636636msgid "No available Wi-Fi networks"
637−msgstr "Nissuna rete Wi-Fi a disponimentu"
637+msgstr "Peruna rete Wi-Fi a disponimentu"
638638
639639#: qml/Wizard/Pages/50-timezone.qml:30
640640msgid "Time Zone"
@@ -669,7 +669,7 @@ msgstr "Crea unu còdighe de atzessu (nùmeros isceti)"
669669#: qml/Wizard/Pages/70-passwd-type.qml:107
670670msgctxt "Label: Type of security method"
671671msgid "No lock code"
672−msgstr "Nissunu còdighe de blocu"
672+msgstr "Perunu còdighe de blocu"
673673
674674#: qml/Wizard/Pages/79-system-update.qml:28
675675msgid "Update Device"
@@ -696,7 +696,7 @@ msgstr "Versione %1"
696696
697697#: qml/Wizard/Pages/79-system-update.qml:95
698698msgid "This could take a few minutes..."
699−msgstr "Podet trigare calicunu minutu..."
699+msgstr "B'at a pònnere carchi minutu..."
700700
701701#: qml/Wizard/Pages/79-system-update.qml:109
702702msgid "Install and restart now"
@@ -783,7 +783,7 @@ msgstr "Cunfirma sa crae"
783783
784784#: qml/Wizard/Pages/sim.qml:27
785785msgid "No SIM card installed"
786−msgstr "Nissuna SIM installada"
786+msgstr "Peruna SIM installada"
787787
788788#: qml/Wizard/Pages/sim.qml:54
789789msgid "SIM card added"
po/sv.po+52−25
@@ -8,8 +8,8 @@ msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: \n"
1010"POT-Creation-Date: 2021-01-29 11:42-0600\n"
11−"PO-Revision-Date: 2021-10-19 20:55+0000\n"
12−"Last-Translator: Jakob Fridesjö <jakob.fridesjo@tuta.io>\n"
11+"PO-Revision-Date: 2021-07-26 20:33+0000\n"
12+"Last-Translator: Rondy Andersson <rondarius@vivaldi.net>\n"
1313"Language-Team: Swedish <https://translate.ubports.com/projects/ubports/"
1414"lomiri/sv/>\n"
1515"Language: sv\n"
@@ -26,15 +26,15 @@ msgstr "Lösenord: "
2626
2727#: plugins/LightDM/Greeter.cpp:214
2828msgid "Username"
29−msgstr "Användarnamn"
29+msgstr ""
3030
3131#: plugins/LightDM/Greeter.cpp:258
3232msgid "Failed to authenticate"
33−msgstr "Misslyckades att autentisera"
33+msgstr ""
3434
3535#: plugins/LightDM/Greeter.cpp:260
3636msgid "Invalid password, please try again"
37−msgstr "Felaktigt lösenord, vänligen försök igen"
37+msgstr ""
3838
3939#: plugins/LightDM/Greeter.cpp:270
4040msgid "Log In"
@@ -46,11 +46,11 @@ msgstr "Försök igen"
4646
4747#: plugins/LightDM/UsersModel.cpp:157
4848msgid "Login"
49−msgstr "Inloggning"
49+msgstr ""
5050
5151#: plugins/LightDM/UsersModel.cpp:165
5252msgid "Guest Session"
53−msgstr "Gästsession"
53+msgstr ""
5454
5555#: plugins/Unity/Launcher/launcheritem.cpp:48
5656#: plugins/Unity/Launcher/launcheritem.cpp:122
@@ -131,8 +131,10 @@ msgid "Restart"
131131msgstr "Starta om"
132132
133133#: qml/Components/Dialogs.qml:276
134+#, fuzzy
135+#| msgid "Takes a screenshot."
134136msgid "Screenshot"
135−msgstr "Skärmdump"
137+msgstr "Tar en skärmbild."
136138
137139#: qml/Components/KeyboardShortcutsOverlay.qml:41
138140msgid "Keyboard Shortcuts"
@@ -140,7 +142,7 @@ msgstr "Tangentbordsgenvägar"
140142
141143#: qml/Components/KeyboardShortcutsOverlay.qml:55
142144msgid "Lomiri"
143−msgstr "Lomiri"
145+msgstr ""
144146
145147#: qml/Components/KeyboardShortcutsOverlay.qml:62
146148msgid "PrtScr"
@@ -155,8 +157,10 @@ msgid "Alt + PrtScr"
155157msgstr "Alt + PrtScr"
156158
157159#: qml/Components/KeyboardShortcutsOverlay.qml:80
160+#, fuzzy
161+#| msgid "Takes a screenshot of a window."
158162msgid "Takes a screenshot of the current window."
159−msgstr "Tar en skärmdump av det nuvarande fönstret."
163+msgstr "Tar en skärmbild av ett fönster."
160164
161165#: qml/Components/KeyboardShortcutsOverlay.qml:88
162166msgid "Super + Space"
@@ -175,12 +179,16 @@ msgid "Switches to previous keyboard layout."
175179msgstr "Byter till tidigare tangentbordslayout."
176180
177181#: qml/Components/KeyboardShortcutsOverlay.qml:114
182+#, fuzzy
183+#| msgid "Ctrl + Super + D"
178184msgid "Ctrl + Alt + T"
179−msgstr "Ctrl + Alt + T"
185+msgstr "Ctrl + Super + D"
180186
181187#: qml/Components/KeyboardShortcutsOverlay.qml:119
188+#, fuzzy
189+#| msgid "Switches between applications."
182190msgid "Starts the Terminal application."
183−msgstr "Startar terminalen."
191+msgstr "Växlar mellan program."
184192
185193#: qml/Components/KeyboardShortcutsOverlay.qml:131
186194msgid "Launcher"
@@ -211,20 +219,26 @@ msgid "Switches applications via the launcher."
211219msgstr "Byter program via Programstartaren."
212220
213221#: qml/Components/KeyboardShortcutsOverlay.qml:177
222+#, fuzzy
223+#| msgid "Super + 0 to 9"
214224msgid "Super + 1 to 0"
215−msgstr "Super + 1 till 0"
225+msgstr "Super + 0 till 9"
216226
217227#: qml/Components/KeyboardShortcutsOverlay.qml:182
218228msgid "Same as clicking on a launcher icon."
219229msgstr "Samma som att klicka på en ikon i Programstartaren."
220230
221231#: qml/Components/KeyboardShortcutsOverlay.qml:190
232+#, fuzzy
233+#| msgid "Super + W"
222234msgid "Super + A"
223−msgstr "Super + A"
235+msgstr "Super + W"
224236
225237#: qml/Components/KeyboardShortcutsOverlay.qml:195
238+#, fuzzy
239+#| msgid "Open the launcher"
226240msgid "Opens the Application Drawer."
227−msgstr "Öppnar programstartaren."
241+msgstr "Öppna programstartaren"
228242
229243#: qml/Components/KeyboardShortcutsOverlay.qml:235
230244msgid "Switching"
@@ -360,20 +374,22 @@ msgstr ""
360374"styrplatta för att interagera med pekaren."
361375
362376#: qml/Components/VirtualTouchPad.qml:327
377+#, fuzzy
378+#| msgid "Tap to return to call..."
363379msgid "Tap left button to click."
364−msgstr "Tryck på vänster knapp för att klicka."
380+msgstr "Tryck för att återgå till samtal…"
365381
366382#: qml/Components/VirtualTouchPad.qml:339
367383msgid "Tap right button to right click."
368−msgstr "Tryck på höger knapp för att högerklicka."
384+msgstr ""
369385
370386#: qml/Components/VirtualTouchPad.qml:351
371387msgid "Swipe with two fingers to scroll."
372−msgstr "Svep med två fingrar för att scrolla."
388+msgstr ""
373389
374390#: qml/Components/VirtualTouchPad.qml:396
375391msgid "Find more settings in the system settings."
376−msgstr "Hitta fler inställningar i systeminställningarna."
392+msgstr ""
377393
378394#: qml/Greeter/CoverPage.qml:127
379395msgid "Unlock"
@@ -403,12 +419,16 @@ msgid "Try again"
403419msgstr "Försök igen"
404420
405421#: qml/Greeter/Greeter.qml:551
422+#, fuzzy
423+#| msgid "Enter passphrase"
406424msgid "Enter passphrase to unlock"
407−msgstr "Ange lösefras för att låsa upp"
425+msgstr "Ange lösenfras"
408426
409427#: qml/Greeter/Greeter.qml:552
428+#, fuzzy
429+#| msgid "Enter passcode"
410430msgid "Enter passcode to unlock"
411−msgstr "Ange lösenkod för att låsa upp"
431+msgstr "Ange lösenkod"
412432
413433#: qml/Greeter/NarrowView.qml:235
414434msgid "Emergency"
@@ -427,8 +447,10 @@ msgid "Select desktop environment"
427447msgstr "Välj skrivbordsmiljö"
428448
429449#: qml/Launcher/Drawer.qml:250
450+#, fuzzy
451+#| msgid "Search"
430452msgid "Search…"
431−msgstr "Sök…"
453+msgstr "Sök"
432454
433455#: qml/Launcher/PullToRefreshScopeStyle.qml:56
434456msgid "Pull to refresh…"
@@ -535,11 +557,13 @@ msgstr "Dra ett program från ett fönster till det andra med tre fingrar"
535557
536558#: qml/Stage/Stage.qml:671
537559msgid "No running apps"
538−msgstr "Inga appar körs"
560+msgstr ""
539561
540562#: qml/Tutorial/TutorialLeftLong.qml:49
563+#, fuzzy
564+#| msgid "Long swipe from the left edge to open the Today scope"
541565msgid "Long swipe from the left edge to open the Application Drawer"
542−msgstr "Gör ett långt svep från vänstra kanten för öppna applikationsstartaren"
566+msgstr "Gör ett lång svep från vänstra kanten för öppna vyn Idag"
543567
544568#: qml/Tutorial/TutorialLeft.qml:47
545569msgid "Short swipe from the left edge to open the launcher"
@@ -675,9 +699,12 @@ msgstr ""
675699"kommer enheten att startas om automatiskt."
676700
677701#: qml/Wizard/Pages/79-system-update.qml:76
702+#, fuzzy
703+#| msgctxt "string identifying name of the update"
704+#| msgid "Ubuntu system"
678705msgctxt "string identifying name of the update"
679706msgid "Ubuntu Touch system"
680−msgstr "Ubuntu Touch system"
707+msgstr "Ubuntusystem"
681708
682709#: qml/Wizard/Pages/79-system-update.qml:83
683710#, qt-format
po/th.po+20−20
@@ -8,7 +8,7 @@ msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: \n"
1010"POT-Creation-Date: 2021-01-29 11:42-0600\n"
11−"PO-Revision-Date: 2021-10-14 16:02+0000\n"
11+"PO-Revision-Date: 2021-05-23 05:10+0000\n"
1212"Last-Translator: Wannaphong Phatthiyaphaibun <wannaphong@yahoo.com>\n"
1313"Language-Team: Thai <https://translate.ubports.com/projects/ubports/lomiri/"
1414"th/>\n"
@@ -22,31 +22,31 @@ msgstr ""
2222
2323#: plugins/LightDM/Greeter.cpp:199
2424msgid "Password: "
25−msgstr "รหัสผ่าน: "
25+msgstr ""
2626
2727#: plugins/LightDM/Greeter.cpp:214
2828msgid "Username"
29−msgstr "ชื่อผู้ใช้"
29+msgstr ""
3030
3131#: plugins/LightDM/Greeter.cpp:258
3232msgid "Failed to authenticate"
33−msgstr "ไม่สามารถตรวจสอบสิทธิ์ได้"
33+msgstr ""
3434
3535#: plugins/LightDM/Greeter.cpp:260
3636msgid "Invalid password, please try again"
37−msgstr "รหัสผ่านไม่ถูกต้อง กรุณาลองอีกครั้ง"
37+msgstr ""
3838
3939#: plugins/LightDM/Greeter.cpp:270
4040msgid "Log In"
41−msgstr "เข้าสู่ระบบ"
41+msgstr ""
4242
4343#: plugins/LightDM/Greeter.cpp:270
4444msgid "Retry"
45−msgstr "ลองอีกครั้ง"
45+msgstr ""
4646
4747#: plugins/LightDM/UsersModel.cpp:157
4848msgid "Login"
49−msgstr "เข้าสู่ระบบ"
49+msgstr ""
5050
5151#: plugins/LightDM/UsersModel.cpp:165
5252msgid "Guest Session"
@@ -68,7 +68,7 @@ msgstr ""
6868#: qml/Components/Dialogs.qml:176
6969msgctxt "Title: Lock/Log out dialog"
7070msgid "Log out"
71−msgstr "ลงชื่อออก"
71+msgstr ""
7272
7373#: qml/Components/Dialogs.qml:177
7474msgid "Are you sure you want to log out?"
@@ -77,7 +77,7 @@ msgstr ""
7777#: qml/Components/Dialogs.qml:180
7878msgctxt "Button: Lock the system"
7979msgid "Lock"
80−msgstr "ล็อก"
80+msgstr ""
8181
8282#: qml/Components/Dialogs.qml:191
8383msgctxt "Button: Log out from the system"
@@ -101,16 +101,16 @@ msgstr ""
101101
102102#: qml/Components/Dialogs.qml:215
103103msgid "No"
104−msgstr "ไม่"
104+msgstr ""
105105
106106#: qml/Components/Dialogs.qml:223
107107msgid "Yes"
108−msgstr "ใช่"
108+msgstr ""
109109
110110#: qml/Components/Dialogs.qml:243
111111msgctxt "Title: Power off/Restart dialog"
112112msgid "Power"
113−msgstr "พลังงาน"
113+msgstr ""
114114
115115#: qml/Components/Dialogs.qml:244
116116msgid ""
@@ -121,7 +121,7 @@ msgstr ""
121121#: qml/Components/Dialogs.qml:248
122122msgctxt "Button: Power off the system"
123123msgid "Power off"
124−msgstr "ปิดเครื่อง"
124+msgstr ""
125125
126126#: qml/Components/Dialogs.qml:263
127127msgctxt "Button: Restart the system"
@@ -138,7 +138,7 @@ msgstr ""
138138
139139#: qml/Components/KeyboardShortcutsOverlay.qml:55
140140msgid "Lomiri"
141−msgstr "Lomiri"
141+msgstr ""
142142
143143#: qml/Components/KeyboardShortcutsOverlay.qml:62
144144msgid "PrtScr"
@@ -395,7 +395,7 @@ msgstr[1] ""
395395
396396#: qml/Greeter/Greeter.qml:550
397397msgid "Try again"
398−msgstr "ลองอีกครั้ง"
398+msgstr ""
399399
400400#: qml/Greeter/Greeter.qml:551
401401msgid "Enter passphrase to unlock"
@@ -407,7 +407,7 @@ msgstr ""
407407
408408#: qml/Greeter/NarrowView.qml:235
409409msgid "Emergency"
410−msgstr "เหตุฉุกเฉิน"
410+msgstr ""
411411
412412#: qml/Greeter/PromptList.qml:126
413413msgid "Passphrase"
@@ -423,7 +423,7 @@ msgstr ""
423423
424424#: qml/Launcher/Drawer.qml:250
425425msgid "Search…"
426−msgstr "ค้นหา…"
426+msgstr ""
427427
428428#: qml/Launcher/PullToRefreshScopeStyle.qml:56
429429msgid "Pull to refresh…"
@@ -435,7 +435,7 @@ msgstr ""
435435
436436#: qml/Notifications/NotificationMenuItemFactory.qml:124
437437msgid "Show password"
438−msgstr "แสดงรหัสผ่าน"
438+msgstr ""
439439
440440#: qml/Panel/ActiveCallHint.qml:79
441441msgid "Tap to return to call..."
@@ -699,7 +699,7 @@ msgstr ""
699699
700700#: qml/Wizard/Pages/80-finished.qml:126
701701msgid "Continue"
702−msgstr "ดำเนินการต่อ"
702+msgstr ""
703703
704704#: qml/Wizard/Pages/80-finished.qml:126
705705msgid "Get Started"
po/ur.po+28−31
@@ -8,100 +8,99 @@ msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: \n"
1010"POT-Creation-Date: 2021-01-29 11:42-0600\n"
11−"PO-Revision-Date: 2022-02-11 14:14+0000\n"
12−"Last-Translator: Muhammad <alimuhammad42620@gmail.com>\n"
13−"Language-Team: Urdu <https://translate.ubports.com/projects/ubports/lomiri/"
14−"ur/>\n"
11+"PO-Revision-Date: 2015-05-05 03:12+0000\n"
12+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13+"Language-Team: Urdu <ur@li.org>\n"
1514"Language: ur\n"
1615"MIME-Version: 1.0\n"
1716"Content-Type: text/plain; charset=UTF-8\n"
1817"Content-Transfer-Encoding: 8bit\n"
1918"Plural-Forms: nplurals=2; plural=n != 1;\n"
20−"X-Generator: Weblate 3.11.3\n"
2119"X-Launchpad-Export-Date: 2016-11-23 06:36+0000\n"
20+"X-Generator: Launchpad (build 18269)\n"
2221
2322#: plugins/LightDM/Greeter.cpp:199
2423msgid "Password: "
25−msgstr "پاسورڈ "
24+msgstr ""
2625
2726#: plugins/LightDM/Greeter.cpp:214
2827msgid "Username"
29−msgstr "یوزر نیم"
28+msgstr ""
3029
3130#: plugins/LightDM/Greeter.cpp:258
3231msgid "Failed to authenticate"
33−msgstr "تصدیق میں ناکامی"
32+msgstr ""
3433
3534#: plugins/LightDM/Greeter.cpp:260
3635msgid "Invalid password, please try again"
37−msgstr "پاسورڈ غلط ھے، دوبارا کوشش کریں"
36+msgstr ""
3837
3938#: plugins/LightDM/Greeter.cpp:270
4039msgid "Log In"
41−msgstr "لاگ ان کریں"
40+msgstr ""
4241
4342#: plugins/LightDM/Greeter.cpp:270
4443msgid "Retry"
45−msgstr "دوبارا کوشش کریں"
44+msgstr ""
4645
4746#: plugins/LightDM/UsersModel.cpp:157
4847msgid "Login"
49−msgstr "لاگ ان کریں"
48+msgstr ""
5049
5150#: plugins/LightDM/UsersModel.cpp:165
5251msgid "Guest Session"
53−msgstr "مہمان سیشن"
52+msgstr ""
5453
5554#: plugins/Unity/Launcher/launcheritem.cpp:48
5655#: plugins/Unity/Launcher/launcheritem.cpp:122
5756msgid "Pin shortcut"
58−msgstr "شورت کٹ پن کیجیے"
57+msgstr ""
5958
6059#: plugins/Unity/Launcher/launcheritem.cpp:54
6160msgid "Quit"
62−msgstr "چھوڑیں"
61+msgstr ""
6362
6463#: plugins/Unity/Launcher/launcheritem.cpp:122
6564msgid "Unpin shortcut"
66−msgstr "شورت کٹ انپن کیجیے"
65+msgstr ""
6766
6867#: qml/Components/Dialogs.qml:176
6968msgctxt "Title: Lock/Log out dialog"
7069msgid "Log out"
71−msgstr "لاگ آؤٹ کیجیے"
70+msgstr ""
7271
7372#: qml/Components/Dialogs.qml:177
7473msgid "Are you sure you want to log out?"
75−msgstr "کیا آپ لاگ آؤٹ کرنا چاہتے ہیں؟"
74+msgstr ""
7675
7776#: qml/Components/Dialogs.qml:180
7877msgctxt "Button: Lock the system"
7978msgid "Lock"
80−msgstr "بند"
79+msgstr ""
8180
8281#: qml/Components/Dialogs.qml:191
8382msgctxt "Button: Log out from the system"
8483msgid "Log Out"
85−msgstr "لاگ آؤٹ"
84+msgstr ""
8685
8786#: qml/Components/Dialogs.qml:199 qml/Components/Dialogs.qml:284
8887#: qml/Greeter/NarrowView.qml:215 qml/Wizard/Pages/passcode-confirm.qml:32
8988#: qml/Wizard/Pages/passcode-set.qml:32
9089msgid "Cancel"
91−msgstr "نہیں"
90+msgstr ""
9291
9392#: qml/Components/Dialogs.qml:211
9493msgctxt "Title: Reboot dialog"
9594msgid "Reboot"
96−msgstr "ریبوٹ"
95+msgstr ""
9796
9897#: qml/Components/Dialogs.qml:212
9998msgid "Are you sure you want to reboot?"
100−msgstr "کیا آپ ریبوٹ کرنا چاہتے ہیں؟"
99+msgstr ""
101100
102101#: qml/Components/Dialogs.qml:215
103102msgid "No"
104−msgstr "نہیں"
103+msgstr ""
105104
106105#: qml/Components/Dialogs.qml:223
107106msgid "Yes"
@@ -117,22 +116,20 @@ msgid ""
117116"Are you sure you would like\n"
118117"to power off?"
119118msgstr ""
120−"کیا آپ موبائل کو\n"
121−" بند کرنا چاہتے ہیں؟"
122119
123120#: qml/Components/Dialogs.qml:248
124121msgctxt "Button: Power off the system"
125122msgid "Power off"
126−msgstr "بند"
123+msgstr ""
127124
128125#: qml/Components/Dialogs.qml:263
129126msgctxt "Button: Restart the system"
130127msgid "Restart"
131−msgstr "ریسارٹ"
128+msgstr ""
132129
133130#: qml/Components/Dialogs.qml:276
134131msgid "Screenshot"
135−msgstr "سکرین کی تصویر"
132+msgstr ""
136133
137134#: qml/Components/KeyboardShortcutsOverlay.qml:41
138135msgid "Keyboard Shortcuts"
@@ -524,7 +521,7 @@ msgstr ""
524521
525522#: qml/Panel/PanelMenuPage.qml:92
526523msgid "Back"
527−msgstr "پیچھے"
524+msgstr ""
528525
529526#: qml/Stage/SideStage.qml:76
530527msgid "Drag using 3 fingers any application from one window to the other"
@@ -780,7 +777,7 @@ msgstr ""
780777
781778#: qml/Wizard/Pages/sim.qml:59
782779msgid "Restart"
783−msgstr "دوباره شروع"
780+msgstr ""
784781
785782#: qml/Wizard/Pages/sim.qml:78
786783msgid "You won’t be able to make calls or use text messaging without a SIM."
qml/Greeter/CoverPage.qml+36−26
@@ -29,16 +29,16 @@ Showable {
2929 property alias background: greeterBackground.source
3030 property alias backgroundSourceSize: greeterBackground.sourceSize
3131 property alias hasCustomBackground: backgroundShade.visible
32− property alias backgroundShadeOpacity: backgroundShade.opacity
3332 property real panelHeight
3433 property var infographicModel
3534 property bool draggable: true
3635
37− property bool showInfographic: false
38− property real infographicsLeftMargin: 0
39− property real infographicsTopMargin: 0
40− property real infographicsRightMargin: 0
41− property real infographicsBottomMargin: 0
36+ property alias infographics: infographics
37+
38+ property alias blurAreaHeight: loginBoxEffects.height
39+ property alias blurAreaWidth: loginBoxEffects.width
40+ property alias blurAreaX: loginBoxEffects.x
41+ property alias blurAreaY: loginBoxEffects.y
4242
4343 readonly property real showProgress: MathUtils.clamp((width - Math.abs(x + launcherOffset)) / width, 0, 1)
4444
@@ -99,23 +99,47 @@ Showable {
9999 }
100100 }
101101
102+ Rectangle {
103+ id: loginBoxEffects
104+ color: "transparent"
105+ }
106+
107+ ShaderEffectSource {
108+ id: effectSource
109+
110+ sourceItem: greeterBackground
111+ anchors.centerIn: loginBoxEffects
112+ width: loginBoxEffects.width
113+ height: loginBoxEffects.height
114+ sourceRect: Qt.rect(x,y, width, height)
115+ }
116+
117+ FastBlur {
118+ visible: !draggable
119+ anchors.fill: effectSource
120+ source: effectSource
121+ radius: 64
122+ transparentBorder: true
123+ }
124+
102125 // Darkens wallpaper so that we can read text on it and see infographic
103126 Rectangle {
104127 id: backgroundShade
105128 objectName: "backgroundShade"
106129 anchors.fill: parent
107130 color: "black"
131+ opacity: 0.4
108132 visible: false
109133 }
110134
111− Item {
112− id: infographicsArea
135+ Infographics {
136+ id: infographics
137+ objectName: "infographics"
138+ model: root.infographicModel
139+ clip: true // clip large data bubbles
113140
114141 anchors {
115− leftMargin: root.infographicsLeftMargin
116− topMargin: root.infographicsTopMargin ? root.infographicsTopMargin : root.panelHeight
117− rightMargin: root.infographicsRightMargin
118− bottomMargin: root.infographicsBottomMargin
142+ topMargin: root.panelHeight
119143 top: parent.top
120144 bottom: parent.bottom
121145 left: parent.left
@@ -123,20 +147,6 @@ Showable {
123147 }
124148 }
125149
126− Loader {
127− id: infographicsLoader
128− objectName: "infographicsLoader"
129− active: root.showInfographic && infographicsArea.width > units.gu(32)
130− anchors.fill: infographicsArea
131−
132− sourceComponent:Infographics {
133− id: infographics
134− objectName: "infographics"
135− model: root.infographicModel
136− clip: true // clip large data bubbles
137− }
138− }
139−
140150 Label {
141151 id: swipeHint
142152 objectName: "swipeHint"
qml/Greeter/Greeter.qml+2−21
@@ -58,7 +58,6 @@ Showable {
5858 readonly property bool locked: LightDMService.greeter.active && !LightDMService.greeter.authenticated && !forcedUnlock
5959
6060 property bool tabletMode
61− property string usageMode
6261 property url viewSource // only used for testing
6362
6463 property int failedLoginsDelayAttempts: 7 // number of failed logins
@@ -70,7 +69,6 @@ Showable {
7069 property rect inputMethodRect
7170
7271 property bool hasKeyboard: false
73− property int orientation
7472
7573 signal tease()
7674 signal sessionStarted()
@@ -358,7 +356,8 @@ Showable {
358356 anchors.fill: parent
359357
360358 active: root.required
361− source: root.viewSource.toString() ? root.viewSource : "GreeterView.qml"
359+ source: root.viewSource.toString() ? root.viewSource :
360+ (d.multiUser || root.tabletMode) ? "WideView.qml" : "NarrowView.qml"
362361
363362 onLoaded: {
364363 root.lockedApp = "";
@@ -477,24 +476,6 @@ Showable {
477476 property: "hasKeyboard"
478477 value: root.hasKeyboard
479478 }
480−
481− Binding {
482− target: loader.item
483− property: "usageMode"
484− value: root.usageMode
485− }
486−
487− Binding {
488− target: loader.item
489− property: "multiUser"
490− value: d.multiUser
491− }
492−
493− Binding {
494− target: loader.item
495− property: "orientation"
496− value: root.orientation
497− }
498479 }
499480
500481 Connections {
qml/Greeter/GreeterPrompt.qml+3−3
@@ -25,7 +25,7 @@ FocusScope {
2525 focus: true
2626
2727 property bool isPrompt
28− property bool isPinPrompt
28+ property bool isAlphanumeric
2929 property string text
3030 property bool isSecret
3131 property bool interactive: true
@@ -115,12 +115,12 @@ FocusScope {
115115 },
116116 State {
117117 name: "PinPrompt"
118− when: root.isPinPrompt
118+ when: root.isPrompt && !root.isAlphanumeric && root.isSecret
119119 PropertyChanges { target: loader; source: "PinPrompt.qml" }
120120 },
121121 State {
122122 name: "TextPrompt"
123− when: !root.isPinPrompt
123+ when: root.isPrompt
124124 PropertyChanges { target: loader; source: "TextPrompt.qml" }
125125 }
126126 ]
qml/Greeter/GreeterView.qmldeleted−534
@@ -1,534 +0,0 @@
1−/*
2− * Copyright (C) 2015-2016 Canonical, Ltd.
3− * Copyright (C) 2021 UBports Foundation
4− *
5− * This program is free software; you can redistribute it and/or modify
6− * it under the terms of the GNU General Public License as published by
7− * the Free Software Foundation; version 3.
8− *
9− * This program is distributed in the hope that it will be useful,
10− * but WITHOUT ANY WARRANTY; without even the implied warranty of
11− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12− * GNU General Public License for more details.
13− *
14− * You should have received a copy of the GNU General Public License
15− * along with this program. If not, see <http://www.gnu.org/licenses/>.
16− */
17−
18−import QtQuick 2.4
19−import QtQuick.Window 2.2
20−import QtGraphicalEffects 1.12
21−import Ubuntu.Components 1.3
22−import Ubuntu.Telephony 0.1 as Telephony
23−import "../Components"
24−
25−FocusScope {
26− id: root
27− objectName: "GreeterView"
28−
29− focus: true
30−
31− property url background
32− property real backgroundSourceSize
33− property real panelHeight
34− property bool hasCustomBackground
35− property alias dragHandleLeftMargin: coverPage.dragHandleLeftMargin
36− property var infographicModel
37− property alias launcherOffset: coverPage.launcherOffset
38− property alias currentIndex: loginList.currentIndex
39− property alias delayMinutes: delayedLockscreen.delayMinutes // TODO
40− property alias alphanumeric: loginList.alphanumeric
41− property alias hasKeyboard: loginList.hasKeyboard
42− property bool locked
43− property bool waiting
44− property var userModel // Set from outside
45− property bool multiUser: false
46− property int orientation
47− property bool isLandscape: root.orientation == Qt.LandscapeOrientation ||
48− root.orientation == Qt.InvertedLandscapeOrientation ||
49− usageMode == "desktop"
50− property bool isPortrait: (root.orientation == Qt.PortraitOrientation ||
51− root.orientation == Qt.InvertedPortraitOrientation) &&
52− usageMode != "desktop"
53−
54− property string usageMode
55−
56− readonly property bool animating: coverPage.showAnimation.running || coverPage.hideAnimation.running
57− readonly property bool fullyShown: coverPage.showProgress === 1 || lockscreen.shown
58− readonly property bool required: coverPage.required || lockscreen.required
59− readonly property alias sessionToStart: loginList.currentSession
60−
61− property rect inputMethodRect
62−
63− signal selected(int index)
64− signal responded(string response)
65− signal tease()
66− signal emergencyCall() // unused
67−
68− function notifyAuthenticationFailed() {
69− loginList.showError();
70− }
71−
72− function forceShow() {
73− coverPage.show();
74− }
75−
76− function tryToUnlock(toTheRight) {
77− var coverChanged = coverPage.shown;
78− if (toTheRight) {
79− coverPage.hideRight();
80− } else {
81− coverPage.hide();
82− }
83− if (root.locked) {
84− lockscreen.show();
85− loginList.tryToUnlock();
86− return false;
87− } else {
88− root.responded("");
89− return coverChanged;
90− }
91− }
92−
93− function hide() {
94− lockscreen.hide();
95− coverPage.hide();
96− }
97−
98− function showFakePassword() {
99− loginList.showFakePassword();
100− }
101−
102− function showErrorMessage(msg) {
103− coverPage.showErrorMessage(msg);
104− }
105−
106− onLockedChanged: changeLockscreenState()
107− onMultiUserChanged: changeLockscreenState()
108−
109− function changeLockscreenState() {
110− if (locked || multiUser) {
111− lockscreen.maybeShow();
112− } else {
113− lockscreen.hide();
114− }
115− }
116−
117− Keys.onSpacePressed: coverPage.hide();
118− Keys.onReturnPressed: coverPage.hide();
119− Keys.onEnterPressed: coverPage.hide();
120−
121− Rectangle {
122− anchors.fill: parent
123− color: "black"
124− opacity: lockscreen.showProgress * 0.8
125− }
126−
127− CoverPage {
128− id: lockscreen
129− objectName: "lockscreen"
130− height: parent.height
131− width: parent.width
132− draggable: false
133− state: "LoginList"
134−
135− background: root.background
136− backgroundSourceSize: root.backgroundSourceSize
137− panelHeight: root.panelHeight
138− hasCustomBackground: root.hasCustomBackground
139− backgroundShadeOpacity: 0.6
140−
141− showInfographic: isLandscape && root.usageMode != "phone" && (root.usageMode != "tablet" || root.multiUser) && !delayedLockscreen.visible
142− infographicModel: root.infographicModel
143−
144− shown: false
145− opacity: 0
146−
147− showAnimation: StandardAnimation { property: "opacity"; to: 1 }
148− hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
149−
150− infographicsTopMargin: parent.height * 0.125
151− infographicsBottomMargin: parent.height * 0.125
152− infographicsLeftMargin: loginList.x + loginList.width
153−
154− onTease: root.tease()
155−
156− onShowProgressChanged: {
157− if (showProgress === 0 && !root.locked) {
158− root.responded("");
159− }
160− }
161−
162− LoginList {
163− id: loginList
164− objectName: "loginList"
165−
166− width: units.gu(40)
167− anchors {
168− top: parent.top
169− bottom: parent.bottom
170− }
171−
172− boxVerticalOffset: (height - highlightedHeight -
173− inputMethodRect.height) / 2
174− Behavior on boxVerticalOffset { UbuntuNumberAnimation {} }
175−
176− enabled: !coverPage.shown && visible
177− visible: !delayedLockscreen.visible
178−
179− model: root.userModel
180− onResponded: root.responded(response)
181− onSelected: root.selected(index)
182− onSessionChooserButtonClicked: parent.state = "SessionsList"
183− onCurrentIndexChanged: setCurrentSession()
184−
185− locked: root.locked
186− waiting: root.waiting
187−
188− Keys.forwardTo: [sessionChooserLoader.item]
189−
190− Component.onCompleted: setCurrentSession()
191−
192− function setCurrentSession() {
193− currentSession = LightDMService.users.data(currentIndex, LightDMService.userRoles.SessionRole);
194− }
195− }
196−
197− DelayedLockscreen {
198− id: delayedLockscreen
199− objectName: "delayedLockscreen"
200− anchors.fill: parent
201− visible: delayMinutes > 0
202− alphaNumeric: loginList.alphanumeric
203− }
204−
205− function maybeShow() {
206− if ((root.locked || root.multiUser) && !shown) {
207− showNow();
208− }
209− }
210−
211− Loader {
212− id: sessionChooserLoader
213−
214− height: loginList.height
215− width: loginList.width
216−
217− anchors {
218− left: parent.left
219− leftMargin: Math.min(parent.width * 0.16, units.gu(20))
220− top: parent.top
221− }
222−
223− active: false
224−
225− onLoaded: sessionChooserLoader.item.forceActiveFocus();
226− onActiveChanged: {
227− if (!active) return;
228− item.updateHighlight(loginList.currentSession);
229− }
230−
231− Connections {
232− target: sessionChooserLoader.item
233− onSessionSelected: loginList.currentSession = sessionKey
234− onShowLoginList: {
235− lockscreen.state = "LoginList"
236− loginList.tryToUnlock();
237− }
238− ignoreUnknownSignals: true
239− }
240− }
241−
242− // Use an AbstractButton due to icon limitations with Button
243− AbstractButton {
244− id: sessionChooser
245− objectName: "sessionChooserButton"
246−
247− readonly property url icon: LightDMService.sessions.iconUrl(loginList.currentSession)
248−
249− visible: LightDMService.sessions.count > 1 &&
250− !LightDMService.users.data(loginList.currentUserIndex, LightDMService.userRoles.LoggedInRole)
251−
252− height: units.gu(3.5)
253− width: units.gu(3.5)
254−
255− activeFocusOnTab: true
256− anchors {
257− right: parent.right
258− rightMargin: units.gu(2)
259−
260− bottom: parent.bottom
261− bottomMargin: units.gu(1.5)
262− }
263−
264− Rectangle {
265− id: badgeHighlight
266−
267− anchors.fill: parent
268− visible: parent.activeFocus
269− color: "transparent"
270− border.color: theme.palette.normal.focus
271− border.width: units.dp(1)
272− radius: 3
273− }
274−
275− Icon {
276− id: badge
277− anchors.fill: parent
278− anchors.margins: units.dp(3)
279− keyColor: "#ffffff" // icon providers give us white icons
280− color: theme.palette.normal.raisedSecondaryText
281− source: sessionChooser.icon
282− }
283−
284− Keys.onReturnPressed: {
285− parent.state = "SessionsList";
286− }
287−
288− onClicked: {
289− parent.state = "SessionsList";
290− }
291−
292− // Refresh the icon path if looking at different places at runtime
293− // this is mainly for testing
294− Connections {
295− target: LightDMService.sessions
296− onIconSearchDirectoriesChanged: {
297− badge.source = LightDMService.sessions.iconUrl(root.currentSession)
298− }
299− }
300− }
301−
302− states: [
303− State {
304− name: "SessionsList"
305− PropertyChanges { target: loginList; opacity: 0 }
306− PropertyChanges { target: sessionChooserLoader;
307− active: true;
308− opacity: 1
309− source: "SessionsList.qml"
310− }
311− },
312−
313− State {
314− name: "LoginList"
315− PropertyChanges { target: loginList; opacity: 1 }
316− PropertyChanges { target: sessionChooserLoader;
317− active: false;
318− opacity: 0
319− source: "";
320− }
321− }
322− ]
323−
324− transitions: [
325− Transition {
326− from: "*"
327− to: "*"
328− UbuntuNumberAnimation {
329− property: "opacity";
330− }
331− }
332− ]
333−
334− Component.onCompleted: if (root.multiUser) showNow()
335− }
336−
337− Rectangle {
338− anchors.fill: parent
339− color: "black"
340− opacity: coverPage.showProgress * 0.8
341− }
342−
343− CoverPage {
344− id: coverPage
345− objectName: "coverPage"
346− height: parent.height
347− width: parent.width
348− background: root.background
349− hasCustomBackground: root.hasCustomBackground
350− backgroundShadeOpacity: 0.4
351− panelHeight: root.panelHeight
352− draggable: !root.waiting
353− onTease: root.tease()
354− onClicked: hide()
355− backgroundSourceSize: root.backgroundSourceSize
356− infographicModel: root.infographicModel
357−
358− showInfographic: !root.multiUser && root.usageMode != "desktop"
359−
360− onShowProgressChanged: {
361− if (showProgress === 0) {
362− if (lockscreen.shown) {
363− loginList.tryToUnlock();
364− } else {
365− root.responded("");
366− }
367− }
368− }
369−
370− Clock {
371− id: clock
372− anchors.centerIn: parent
373− }
374−
375− states: [
376− State {
377− name: "landscape-with-infographics"
378− when: isLandscape && coverPage.showInfographic
379− AnchorChanges {
380− target: clock
381− anchors.top: undefined
382− anchors.horizontalCenter: undefined
383− anchors.verticalCenter: undefined
384− }
385− PropertyChanges {
386− target: clock;
387− anchors.topMargin: undefined
388− anchors.centerIn: coverPage
389− anchors.horizontalCenterOffset: - coverPage.width / 2 + clock.width / 2 + units.gu(8)
390− }
391− PropertyChanges {
392− target: coverPage
393− infographicsLeftMargin: clock.width + units.gu(8)
394− }
395− },
396− State {
397− name: "portrait"
398− when: isPortrait && coverPage.showInfographic
399− AnchorChanges {
400− target: clock;
401− anchors.top: coverPage.top
402− anchors.horizontalCenter: coverPage.horizontalCenter
403− anchors.verticalCenter: undefined
404− }
405− PropertyChanges {
406− target: clock;
407− anchors.topMargin: units.gu(2) + panelHeight
408− anchors.centerIn: undefined
409− anchors.horizontalCenterOffset: 0
410− }
411− PropertyChanges {
412− target: coverPage
413− infographicsLeftMargin: 0
414− }
415− },
416− State {
417− name: "without-infographics"
418− when: !coverPage.showInfographic
419− AnchorChanges {
420− target: clock
421− anchors.top: undefined
422− anchors.horizontalCenter: coverPage.horizontalCenter
423− anchors.verticalCenter: coverPage.verticalCenter
424− }
425− PropertyChanges {
426− target: clock;
427− anchors.topMargin: 0
428− anchors.centerIn: undefined
429− anchors.horizontalCenterOffset: 0
430− }
431− PropertyChanges {
432− target: coverPage
433− infographicsLeftMargin: 0
434− }
435− }
436− ]
437− }
438−
439− StyledItem {
440− id: bottomBar
441− visible: usageMode == "phone" && lockscreen.shown
442− height: units.gu(4)
443−
444− anchors.left: parent.left
445− anchors.right: parent.right
446− anchors.top: parent.bottom
447− anchors.topMargin: - height * (1 - coverPage.showProgress)
448− - ( inputMethodRect.height )
449−
450− Label {
451− text: i18n.tr("Cancel")
452− anchors.left: parent.left
453− anchors.leftMargin: units.gu(2)
454− anchors.top: parent.top
455− anchors.bottom: parent.bottom
456− verticalAlignment: Text.AlignVCenter
457− font.weight: Font.Light
458− fontSize: "small"
459− color: theme.palette.normal.raisedSecondaryText
460−
461− AbstractButton {
462− anchors.fill: parent
463− anchors.leftMargin: -units.gu(2)
464− anchors.rightMargin: -units.gu(2)
465− onClicked: coverPage.show()
466− }
467− }
468−
469− Label {
470− objectName: "emergencyCallLabel"
471− text: callManager.hasCalls ? i18n.tr("Return to Call") : i18n.tr("Emergency")
472− anchors.right: parent.right
473− anchors.rightMargin: units.gu(2)
474− anchors.top: parent.top
475− anchors.bottom: parent.bottom
476− verticalAlignment: Text.AlignVCenter
477− font.weight: Font.Light
478− fontSize: "small"
479− color: theme.palette.normal.raisedSecondaryText
480− // TODO: uncomment once bug 1616538 is fixed
481− // visible: telepathyHelper.ready && telepathyHelper.emergencyCallsAvailable
482− enabled: visible
483−
484− AbstractButton {
485− anchors.fill: parent
486− anchors.leftMargin: -units.gu(2)
487− anchors.rightMargin: -units.gu(2)
488− onClicked: root.emergencyCall()
489− }
490− }
491− }
492−
493− states: [
494− State {
495− name: "phone"
496− when: root.usageMode == "phone" || (root.usageMode == "tablet" && isPortrait)
497− AnchorChanges {
498− target: loginList;
499− anchors.horizontalCenter: lockscreen.horizontalCenter;
500− anchors.left: undefined;
501− }
502− PropertyChanges {
503− target: loginList;
504− anchors.leftMargin: 0;
505− }
506− },
507− State {
508− name: "tablet"
509− when: root.usageMode == "tablet" && isLandscape
510− AnchorChanges {
511− target: loginList;
512− anchors.horizontalCenter: undefined;
513− anchors.left: lockscreen.left;
514− }
515− PropertyChanges {
516− target: loginList;
517− anchors.leftMargin: Math.min(lockscreen.width * 0.16, units.gu(8));
518− }
519− },
520− State {
521− name: "desktop"
522− when: root.usageMode == "desktop"
523− AnchorChanges {
524− target: loginList;
525− anchors.horizontalCenter: undefined;
526− anchors.left: lockscreen.left;
527− }
528− PropertyChanges {
529− target: loginList;
530− anchors.leftMargin: Math.min(lockscreen.width * 0.16, units.gu(20));
531− }
532− }
533− ]
534−}
qml/Greeter/LoginList.qml+2−4
@@ -122,8 +122,6 @@ StyledItem {
122122 moveTimer.start();
123123 }
124124
125− onCountChanged: if (root.currentIndex >= count) root.selected(0)
126−
127125 delegate: Item {
128126 width: userList.width
129127 height: root.cellHeight
@@ -132,7 +130,7 @@ StyledItem {
132130 readonly property bool aboveCurrent: (userList.currentIndex > 0 && index < 0) || (userList.currentIndex >= 0 && index < userList.currentIndex)
133131 readonly property int belowOffset: root.highlightedHeight - root.cellHeight
134132 readonly property string userSession: session
135− readonly property string username: name ? name : ""
133+ readonly property string username: name
136134
137135 opacity: {
138136 // The goal here is to make names less and less opaque as they
@@ -193,7 +191,7 @@ StyledItem {
193191 text: userList.currentIndex === index
194192 && name === "*other"
195193 && LightDMService.greeter.authenticationUser !== ""
196− ? LightDMService.greeter.authenticationUser : realName ? realName : ""
194+ ? LightDMService.greeter.authenticationUser : realName
197195 color: userList.currentIndex !== index ? theme.palette.normal.raised
198196 : theme.palette.normal.raisedSecondaryText
199197 font.weight: userList.currentIndex === index ? Font.Normal : Font.Light
qml/Greeter/NarrowView.qmlnew file+277
@@ -0,0 +1,277 @@
1+/*
2+ * Copyright (C) 2015-2016 Canonical, Ltd.
3+ * Copyright (C) 2021 UBports Foundation
4+ *
5+ * This program is free software; you can redistribute it and/or modify
6+ * it under the terms of the GNU General Public License as published by
7+ * the Free Software Foundation; version 3.
8+ *
9+ * This program is distributed in the hope that it will be useful,
10+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+ * GNU General Public License for more details.
13+ *
14+ * You should have received a copy of the GNU General Public License
15+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
16+ */
17+
18+import QtQuick 2.4
19+import QtQuick.Window 2.2
20+import QtGraphicalEffects 1.12
21+import Ubuntu.Components 1.3
22+import Ubuntu.Telephony 0.1 as Telephony
23+import "../Components"
24+
25+FocusScope {
26+ id: root
27+
28+ property alias dragHandleLeftMargin: coverPage.dragHandleLeftMargin
29+ property alias launcherOffset: coverPage.launcherOffset
30+ property alias currentIndex: loginList.currentIndex
31+ property alias delayMinutes: delayedLockscreen.delayMinutes
32+ property real panelHeight
33+ property url background
34+ property real backgroundSourceSize
35+ property bool hasCustomBackground
36+ property bool locked
37+ property alias alphanumeric: loginList.alphanumeric
38+ property alias hasKeyboard: loginList.hasKeyboard
39+ property alias userModel: loginList.model
40+ property alias infographicModel: coverPage.infographicModel
41+ property string sessionToStart
42+ property bool waiting
43+ readonly property bool fullyShown: coverPage.showProgress === 1 || lockscreen.shown
44+ readonly property bool required: coverPage.required || lockscreen.required
45+ readonly property bool animating: coverPage.showAnimation.running || coverPage.hideAnimation.running
46+
47+ property rect inputMethodRect
48+
49+ signal selected(int index)
50+ signal responded(string response)
51+ signal tease()
52+ signal emergencyCall()
53+
54+ function hide() {
55+ lockscreen.hide();
56+ coverPage.hide();
57+ }
58+
59+ function showFakePassword() {
60+ loginList.showFakePassword();
61+ }
62+
63+ function notifyAuthenticationFailed() {
64+ loginList.showError();
65+ }
66+
67+ function showErrorMessage(msg) {
68+ coverPage.showErrorMessage(msg);
69+ }
70+
71+ function forceShow() {
72+ coverPage.show();
73+ }
74+
75+ function tryToUnlock(toTheRight) {
76+ var coverChanged = coverPage.shown;
77+ lockscreen.maybeShow();
78+ if (toTheRight) {
79+ coverPage.hideRight();
80+ } else {
81+ coverPage.hide();
82+ }
83+ return coverChanged;
84+ }
85+
86+ onLockedChanged: {
87+ if (locked) {
88+ lockscreen.maybeShow();
89+ } else {
90+ lockscreen.hide();
91+ }
92+ }
93+
94+ Keys.onSpacePressed: coverPage.hide();
95+ Keys.onReturnPressed: coverPage.hide();
96+ Keys.onEnterPressed: coverPage.hide();
97+
98+ Showable {
99+ id: lockscreen
100+ objectName: "lockscreen"
101+ anchors.fill: parent
102+ shown: false
103+ opacity: 0
104+
105+ showAnimation: StandardAnimation { property: "opacity"; to: 1 }
106+ hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
107+
108+ Rectangle {
109+ // In case background fails to load or doesn't cover the whole screen
110+ id: backgroundBackup
111+ anchors.fill: parent
112+ color: "black"
113+ }
114+
115+ Wallpaper {
116+ id: lockscreenBackground
117+ objectName: "lockscreenBackground"
118+ anchors {
119+ fill: parent
120+ }
121+ source: root.background
122+ sourceSize: root.backgroundSourceSize
123+ }
124+
125+ // Darken background to match CoverPage
126+ Rectangle {
127+ objectName: "lockscreenShade"
128+ anchors.fill: parent
129+ color: "black"
130+ opacity: root.hasCustomBackground ? 0.4 : 0
131+ }
132+
133+ LoginList {
134+ id: loginList
135+ objectName: "loginList"
136+
137+ anchors {
138+ horizontalCenter: parent.horizontalCenter
139+ top: parent.top
140+ bottom: parent.bottom
141+ }
142+ width: units.gu(40)
143+ boxVerticalOffset: units.gu(14)
144+ enabled: !coverPage.shown && visible
145+ visible: !delayedLockscreen.visible
146+
147+ locked: root.locked
148+
149+ onSelected: if (enabled) root.selected(index)
150+ onResponded: root.responded(response)
151+ }
152+
153+ DelayedLockscreen {
154+ id: delayedLockscreen
155+ objectName: "delayedLockscreen"
156+ anchors.fill: parent
157+ visible: delayMinutes > 0
158+ alphaNumeric: loginList.alphanumeric
159+ }
160+
161+ function maybeShow() {
162+ if (root.locked && !shown) {
163+ showNow();
164+ }
165+ }
166+ }
167+
168+ Rectangle {
169+ anchors.fill: parent
170+ color: "black"
171+ opacity: coverPage.showProgress * 0.8
172+ }
173+
174+ CoverPage {
175+ id: coverPage
176+ objectName: "coverPage"
177+ height: parent.height
178+ width: parent.width
179+ background: root.background
180+ hasCustomBackground: root.hasCustomBackground
181+ panelHeight: root.panelHeight
182+ draggable: !root.waiting
183+ onTease: root.tease()
184+ onClicked: hide()
185+ backgroundSourceSize: root.backgroundSourceSize
186+
187+ onShowProgressChanged: {
188+ if (showProgress === 0) {
189+ if (lockscreen.shown) {
190+ loginList.tryToUnlock();
191+ } else {
192+ root.responded("");
193+ }
194+ }
195+ }
196+
197+ Clock {
198+ anchors {
199+ top: parent.top
200+ topMargin: units.gu(2) + panelHeight
201+ horizontalCenter: parent.horizontalCenter
202+ }
203+ }
204+ }
205+
206+ StyledItem {
207+ id: bottomBar
208+ visible: lockscreen.shown
209+ height: units.gu(4)
210+
211+ anchors.left: parent.left
212+ anchors.right: parent.right
213+ anchors.top: parent.bottom
214+ anchors.topMargin: - height * (1 - coverPage.showProgress)
215+ - ( inputMethodRect.height )
216+
217+ Rectangle {
218+ color: UbuntuColors.porcelain // matches OSK background
219+ anchors.fill: parent
220+ }
221+
222+ Label {
223+ text: i18n.tr("Cancel")
224+ anchors.left: parent.left
225+ anchors.leftMargin: units.gu(2)
226+ anchors.top: parent.top
227+ anchors.bottom: parent.bottom
228+ verticalAlignment: Text.AlignVCenter
229+ font.weight: Font.Light
230+ fontSize: "small"
231+ color: UbuntuColors.slate
232+
233+ AbstractButton {
234+ anchors.fill: parent
235+ anchors.leftMargin: -units.gu(2)
236+ anchors.rightMargin: -units.gu(2)
237+ onClicked: coverPage.show()
238+ }
239+ }
240+
241+ Label {
242+ objectName: "emergencyCallLabel"
243+ text: callManager.hasCalls ? i18n.tr("Return to Call") : i18n.tr("Emergency")
244+ anchors.right: parent.right
245+ anchors.rightMargin: units.gu(2)
246+ anchors.top: parent.top
247+ anchors.bottom: parent.bottom
248+ verticalAlignment: Text.AlignVCenter
249+ font.weight: Font.Light
250+ fontSize: "small"
251+ color: UbuntuColors.slate
252+ // TODO: uncomment once bug 1616538 is fixed
253+ // visible: telepathyHelper.ready && telepathyHelper.emergencyCallsAvailable
254+ enabled: visible
255+
256+ AbstractButton {
257+ anchors.fill: parent
258+ anchors.leftMargin: -units.gu(2)
259+ anchors.rightMargin: -units.gu(2)
260+ onClicked: root.emergencyCall()
261+ }
262+ }
263+ }
264+
265+ // FIXME: It's difficult to keep something tied closely to the OSK (bug
266+ // 1616163). But as a hack to avoid the background peeking out,
267+ // we add an extra Rectangle that just serves to hide the background
268+ // during OSK animations.
269+ Rectangle {
270+ visible: bottomBar.visible
271+ height: inputMethodRect.height
272+ anchors.bottom: parent.bottom
273+ anchors.left: parent.left
274+ anchors.right: parent.right
275+ color: UbuntuColors.porcelain
276+ }
277+}
qml/Greeter/PinPrompt.qml+1−1
@@ -166,7 +166,7 @@ FocusScope {
166166 // the user to be able to edit the field (simply because it would look
167167 // weird if we allowed that). But until we have such a disabled mode,
168168 // we'll fake it by covering the real text field with a label.
169− Label {
169+ FadingLabel {
170170 id: fakeLabel
171171 anchors.verticalCenter: extraIcons ? extraIcons.verticalCenter : undefined
172172 anchors.left: extraIcons ? extraIcons.left : undefined
qml/Greeter/PromptList.qml+19−16
@@ -67,14 +67,10 @@ FocusScope {
6767
6868 readonly property bool isLabel: model.type == LightDMService.prompts.Message ||
6969 model.type == LightDMService.prompts.Error
70− readonly property var modelText: model.text
71− readonly property var modelType: model.type
72− readonly property var modelIndex: model.index
70+ readonly property var modelData: model
7371
7472 sourceComponent: isLabel ? infoLabel : greeterPrompt
7573
76− active: root.visible
77−
7874 onLoaded: {
7975 for (var i = 0; i < repeater.count; i++) {
8076 var item = repeater.itemAt(i);
@@ -85,6 +81,12 @@ FocusScope {
8581 }
8682 loader.item.opacity = 1;
8783 }
84+
85+ Binding {
86+ target: loader.item
87+ property: "model"
88+ value: loader.modelData
89+ }
8890 }
8991 }
9092 }
@@ -93,18 +95,19 @@ FocusScope {
9395 id: infoLabel
9496
9597 FadingLabel {
96− objectName: "infoLabel" + modelIndex
98+ objectName: "infoLabel" + model.index
9799 width: root.width
98100
101+ property var model
99102 readonly property bool isPrompt: false
100103
101− color: modelType === LightDMService.prompts.Message ? theme.palette.normal.raisedSecondaryText
104+ color: model.type === LightDMService.prompts.Message ? theme.palette.normal.raisedSecondaryText
102105 : theme.palette.normal.negative
103106 fontSize: "small"
104107 textFormat: Text.PlainText
105− text: modelText
108+ text: model.text
106109
107− visible: modelType === LightDMService.prompts.Message
110+ visible: model.type === LightDMService.prompts.Message
108111
109112 Behavior on opacity { UbuntuNumberAnimation {} }
110113 opacity: 0
@@ -115,23 +118,23 @@ FocusScope {
115118 id: greeterPrompt
116119
117120 GreeterPrompt {
118− objectName: "greeterPrompt" + modelIndex
121+ objectName: "greeterPrompt" + model.index
119122 width: root.width
120123
121− property bool isAlphanumeric: modelText !== "" || root.alphanumeric
124+ property var model
122125
123126 interactive: root.interactive
124− isPrompt: modelType !== LightDMService.prompts.Button
125− isSecret: modelType === LightDMService.prompts.Secret
126− isPinPrompt: isPrompt && !isAlphanumeric && isSecret
127+ isAlphanumeric: model.text !== "" || root.alphanumeric
128+ isPrompt: model.type !== LightDMService.prompts.Button
129+ isSecret: model.type === LightDMService.prompts.Secret
127130 loginError: root.loginError
128131 hasKeyboard: root.hasKeyboard
129− text: modelText ? modelText : (isAlphanumeric ? i18n.tr("Passphrase") : i18n.tr("Passcode"))
132+ text: model.text ? model.text : (isAlphanumeric ? i18n.tr("Passphrase") : i18n.tr("Passcode"))
130133
131134 onClicked: root.clicked()
132135 onAccepted: {
133136 // If there is another GreeterPrompt, focus it.
134− for (var i = modelIndex + 1; i < repeater.count; i++) {
137+ for (var i = model.index + 1; i < repeater.count; i++) {
135138 var item = repeater.itemAt(i).item;
136139 if (item.isPrompt) {
137140 item.forceActiveFocus();
qml/Greeter/WideView.qmlnew file+281
@@ -0,0 +1,281 @@
1+/*
2+ * Copyright (C) 2015-2016 Canonical, Ltd.
3+ * Copyright (C) 2021 UBports Foundation
4+ *
5+ * This program is free software; you can redistribute it and/or modify
6+ * it under the terms of the GNU General Public License as published by
7+ * the Free Software Foundation; version 3.
8+ *
9+ * This program is distributed in the hope that it will be useful,
10+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+ * GNU General Public License for more details.
13+ *
14+ * You should have received a copy of the GNU General Public License
15+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
16+ */
17+
18+import QtQuick 2.4
19+import Ubuntu.Components 1.3
20+import "." 0.1
21+
22+FocusScope {
23+ id: root
24+ objectName: "WideView"
25+
26+ focus: true
27+
28+ property alias background: coverPage.background
29+ property alias backgroundSourceSize: coverPage.backgroundSourceSize
30+ property alias panelHeight: coverPage.panelHeight
31+ property alias hasCustomBackground: coverPage.hasCustomBackground
32+ property alias dragHandleLeftMargin: coverPage.dragHandleLeftMargin
33+ property alias infographicModel: coverPage.infographicModel
34+ property alias launcherOffset: coverPage.launcherOffset
35+ property alias currentIndex: loginList.currentIndex
36+ property int delayMinutes // TODO
37+ property alias alphanumeric: loginList.alphanumeric
38+ property alias hasKeyboard: loginList.hasKeyboard
39+ property alias locked: loginList.locked
40+ property alias waiting: loginList.waiting
41+ property var userModel // Set from outside
42+
43+ readonly property bool animating: coverPage.showAnimation.running || coverPage.hideAnimation.running
44+ readonly property bool fullyShown: coverPage.showProgress === 1
45+ readonly property bool required: coverPage.required
46+ readonly property alias sessionToStart: loginList.currentSession
47+
48+ property rect inputMethodRect
49+
50+ signal selected(int index)
51+ signal responded(string response)
52+ signal tease()
53+ signal emergencyCall() // unused
54+
55+ function notifyAuthenticationFailed() {
56+ loginList.showError();
57+ }
58+
59+ function forceShow() {
60+ // Nothing to do, we are always fully shown
61+ }
62+
63+ function tryToUnlock(toTheRight) {
64+ if (root.locked) {
65+ coverPage.show();
66+ loginList.tryToUnlock();
67+ return false;
68+ } else {
69+ var coverChanged = coverPage.shown;
70+ if (toTheRight) {
71+ coverPage.hideRight();
72+ } else {
73+ coverPage.hide();
74+ }
75+ return coverChanged;
76+ }
77+ }
78+
79+ function hide() {
80+ coverPage.hide();
81+ }
82+
83+ function showFakePassword() {
84+ loginList.showFakePassword();
85+ }
86+
87+ Rectangle {
88+ anchors.fill: parent
89+ color: "black"
90+ opacity: coverPage.showProgress * 0.8
91+ }
92+
93+ CoverPage {
94+ id: coverPage
95+ objectName: "coverPage"
96+ height: parent.height
97+ width: parent.width
98+ draggable: !root.locked && !root.waiting
99+ state: "LoginList"
100+ blurAreaHeight: loginList.highlightedHeight + units.gu(4.5)
101+ blurAreaWidth: loginList.width + units.gu(3)
102+ blurAreaX: loginList.x - units.gu(1.5)
103+ blurAreaY: loginList.boxVerticalOffset + loginList.y - units.gu(3)
104+
105+ // Darken background to match CoverPage
106+ Rectangle {
107+ objectName: "lockscreenShade"
108+ anchors.fill: parent
109+ color: "black"
110+ opacity: root.hasCustomBackground ? 0.1 : 0
111+ }
112+
113+ infographics {
114+ anchors.topMargin: parent.height * 0.125
115+ anchors.bottomMargin: parent.height * 0.125
116+ anchors.leftMargin: loginList.x + loginList.width
117+ }
118+
119+ onTease: root.tease()
120+
121+ onShowProgressChanged: {
122+ if (showProgress === 0 && !root.locked) {
123+ root.responded("");
124+ }
125+ }
126+
127+ LoginList {
128+ id: loginList
129+ objectName: "loginList"
130+
131+ width: units.gu(40)
132+ anchors {
133+ left: parent.left
134+ leftMargin: Math.min(parent.width * 0.16, units.gu(20))
135+ top: parent.top
136+ bottom: parent.bottom
137+ }
138+
139+ boxVerticalOffset: (height - highlightedHeight -
140+ inputMethodRect.height) / 2
141+ Behavior on boxVerticalOffset { UbuntuNumberAnimation {} }
142+
143+ model: root.userModel
144+ onResponded: root.responded(response)
145+ onSelected: root.selected(index)
146+ onSessionChooserButtonClicked: parent.state = "SessionsList"
147+ onCurrentIndexChanged: setCurrentSession()
148+
149+ Keys.forwardTo: [sessionChooserLoader.item]
150+
151+ Component.onCompleted: setCurrentSession()
152+
153+ function setCurrentSession() {
154+ currentSession = LightDMService.users.data(currentIndex, LightDMService.userRoles.SessionRole);
155+ }
156+ }
157+
158+ Loader {
159+ id: sessionChooserLoader
160+
161+ height: loginList.height
162+ width: loginList.width
163+
164+ anchors {
165+ left: parent.left
166+ leftMargin: Math.min(parent.width * 0.16, units.gu(20))
167+ top: parent.top
168+ }
169+
170+ active: false
171+
172+ onLoaded: sessionChooserLoader.item.forceActiveFocus();
173+ onActiveChanged: {
174+ if (!active) return;
175+ item.updateHighlight(loginList.currentSession);
176+ }
177+
178+ Connections {
179+ target: sessionChooserLoader.item
180+ onSessionSelected: loginList.currentSession = sessionKey
181+ onShowLoginList: {
182+ coverPage.state = "LoginList"
183+ loginList.tryToUnlock();
184+ }
185+ ignoreUnknownSignals: true
186+ }
187+ }
188+
189+ // Use an AbstractButton due to icon limitations with Button
190+ AbstractButton {
191+ id: sessionChooser
192+ objectName: "sessionChooserButton"
193+
194+ readonly property url icon: LightDMService.sessions.iconUrl(loginList.currentSession)
195+
196+ visible: LightDMService.sessions.count > 1 &&
197+ !LightDMService.users.data(loginList.currentUserIndex, LightDMService.userRoles.LoggedInRole)
198+
199+ height: units.gu(3.5)
200+ width: units.gu(3.5)
201+
202+ activeFocusOnTab: true
203+ anchors {
204+ right: parent.right
205+ rightMargin: units.gu(2)
206+
207+ bottom: parent.bottom
208+ bottomMargin: units.gu(1.5)
209+ }
210+
211+ Rectangle {
212+ id: badgeHighlight
213+
214+ anchors.fill: parent
215+ visible: parent.activeFocus
216+ color: "transparent"
217+ border.color: theme.palette.normal.focus
218+ border.width: units.dp(1)
219+ radius: 3
220+ }
221+
222+ Icon {
223+ id: badge
224+ anchors.fill: parent
225+ anchors.margins: units.dp(3)
226+ keyColor: "#ffffff" // icon providers give us white icons
227+ color: theme.palette.normal.raisedSecondaryText
228+ source: sessionChooser.icon
229+ }
230+
231+ Keys.onReturnPressed: {
232+ parent.state = "SessionsList";
233+ }
234+
235+ onClicked: {
236+ parent.state = "SessionsList";
237+ }
238+
239+ // Refresh the icon path if looking at different places at runtime
240+ // this is mainly for testing
241+ Connections {
242+ target: LightDMService.sessions
243+ onIconSearchDirectoriesChanged: {
244+ badge.source = LightDMService.sessions.iconUrl(root.currentSession)
245+ }
246+ }
247+ }
248+
249+ states: [
250+ State {
251+ name: "SessionsList"
252+ PropertyChanges { target: loginList; opacity: 0 }
253+ PropertyChanges { target: sessionChooserLoader;
254+ active: true;
255+ opacity: 1
256+ source: "SessionsList.qml"
257+ }
258+ },
259+
260+ State {
261+ name: "LoginList"
262+ PropertyChanges { target: loginList; opacity: 1 }
263+ PropertyChanges { target: sessionChooserLoader;
264+ active: false;
265+ opacity: 0
266+ source: "";
267+ }
268+ }
269+ ]
270+
271+ transitions: [
272+ Transition {
273+ from: "*"
274+ to: "*"
275+ UbuntuNumberAnimation {
276+ property: "opacity";
277+ }
278+ }
279+ ]
280+ }
281+}
qml/Launcher/BackgroundBlur.qmldeleted−81
@@ -1,81 +0,0 @@
1−/*
2− * Copyright (C) 2016 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.4
18−import Ubuntu.Components 1.3
19−import QtGraphicalEffects 1.0
20−
21−Item {
22− id: root
23−
24− property int blurAmount: 32
25− property Item sourceItem
26− property rect blurRect: Qt.rect(0,0,0,0)
27− property alias cached: fastBlur.cached
28−
29− Rectangle {
30− id: blurMask
31− color: "yellow"
32− x: blurRect.x
33− y: blurRect.y
34− width: blurRect.width
35− height: blurRect.height
36− }
37−
38− ShaderEffect {
39− id: maskedBlurEffect
40− x: blurRect.x
41− y: blurRect.y
42− width: blurRect.width
43− height: blurRect.height
44−
45− property variant source: ShaderEffectSource {
46− id: shaderEffectSource
47− sourceItem: root.sourceItem
48− hideSource: false
49− sourceRect: root.blurRect
50− }
51−
52− property var mask: ShaderEffectSource {
53− sourceItem: blurMask
54− hideSource: true
55− }
56−
57− fragmentShader: "
58− varying highp vec2 qt_TexCoord0;
59− uniform sampler2D source;
60− uniform sampler2D mask;
61− void main(void)
62− {
63− highp vec4 sourceColor = texture2D(source, qt_TexCoord0);
64− highp vec4 maskColor = texture2D(mask, qt_TexCoord0);
65−
66− sourceColor *= maskColor.a;
67−
68− gl_FragColor = sourceColor;
69− }"
70− }
71−
72− FastBlur {
73− id: fastBlur
74− x: blurRect.x
75− y: blurRect.y
76− width: blurRect.width
77− height: blurRect.height
78− source: maskedBlurEffect
79− radius: Math.min(blurAmount, 128)
80− }
81− }
qml/Launcher/Drawer.qml+2−8
@@ -34,7 +34,6 @@ FocusScope {
3434 readonly property real delegateWidth: units.gu(10)
3535 property url background
3636 property alias backgroundSourceSize: background.sourceSize
37− property bool staticBlurEnabled : true
3837 visible: x > -width
3938 property var fullyOpen: x === 0
4039 property var fullyClosed: x === -width
@@ -156,21 +155,18 @@ FocusScope {
156155
157156 Rectangle {
158157 anchors.fill: parent
159− color: "#BF000000"
158+ color: "#111111"
159+ opacity: 0.99
160160
161161 Wallpaper {
162162 id: background
163163 objectName: "drawerBackground"
164− visible: staticBlurEnabled
165− enabled: staticBlurEnabled
166164 anchors.fill: parent
167165 source: root.background
168166 }
169167
170168 FastBlur {
171169 anchors.fill: background
172− visible: staticBlurEnabled
173− enabled: staticBlurEnabled
174170 source: background
175171 radius: 64
176172 cached: true
@@ -179,8 +175,6 @@ FocusScope {
179175 // Images with fastblur can't use opacity, so we'll put this on top
180176 Rectangle {
181177 anchors.fill: background
182− visible: staticBlurEnabled
183− enabled: staticBlurEnabled
184178 color: parent.color
185179 opacity: 0.67
186180 }
qml/Launcher/Launcher.qml+1−23
@@ -31,8 +31,6 @@ FocusScope {
3131 property bool lockedVisible: false
3232 property bool available: true // can be used to disable all interactions
3333 property alias inverted: panel.inverted
34− property Item blurSource: null
35− property bool interactiveBlur: false
3634 property int topPanelHeight: 0
3735 property bool drawerEnabled: true
3836 property alias privateMode: panel.privateMode
@@ -366,20 +364,6 @@ FocusScope {
366364 }
367365 }
368366
369− BackgroundBlur {
370− id: backgroundBlur
371− anchors.fill: parent
372− anchors.topMargin: root.inverted ? 0 : -root.topPanelHeight
373− visible: root.interactiveBlur && root.blurSource && drawer.x > -drawer.width
374− blurAmount: units.gu(6)
375− sourceItem: root.blurSource
376− blurRect: Qt.rect(panel.width,
377− root.topPanelHeight,
378− drawer.width + drawer.x - panel.width,
379− height - root.topPanelHeight)
380− cached: drawer.moving
381− }
382−
383367 Drawer {
384368 id: drawer
385369 objectName: "drawer"
@@ -393,7 +377,6 @@ FocusScope {
393377 width: Math.min(root.width, units.gu(81))
394378 panelWidth: panel.width
395379 allowSlidingAnimation: !dragArea.dragging && !launcherDragArea.drag.active && panel.animate
396− staticBlurEnabled: !root.interactiveBlur
397380
398381 onApplicationSelected: {
399382 root.launcherApplicationSelected(appId)
@@ -427,7 +410,7 @@ FocusScope {
427410 Connections {
428411 target: panel.dismissTimer
429412 onTriggered: {
430− if (root.state !== "drawer" && root.autohideEnabled && !root.lockedVisible) {
413+ if (root.autohideEnabled && !root.lockedVisible) {
431414 if (!edgeBarrier.containsMouse && !panel.preventHiding) {
432415 root.state = ""
433416 } else {
@@ -609,11 +592,6 @@ FocusScope {
609592 anchors.rightMargin: 0
610593 focus: false
611594 }
612− PropertyChanges {
613− target: root
614− restoreEntryValues: false
615− autohideEnabled: false
616− }
617595 },
618596 State {
619597 name: "drawer"
qml/OrientedShell.qml−1
@@ -273,7 +273,6 @@ Item {
273273 nativeWidth: root.width
274274 nativeHeight: root.height
275275 mode: applicationArguments.mode
276− interactiveBlur: applicationArguments.interactiveBlur
277276 hasMouse: pointerInputDevices > 0
278277 hasKeyboard: keyboardsModel.count > 0
279278 hasTouchscreen: touchScreensModel.count > 0
qml/Panel/Indicators/IndicatorItem.qml−6
@@ -117,12 +117,6 @@ IndicatorDelegate {
117117 source: modelData
118118 color: root.color
119119 Behavior on color { ColorAnimation { duration: UbuntuAnimation.FastDuration; easing: UbuntuAnimation.StandardEasing } }
120−
121− // Workaround indicators getting stretched/squished when (un)plugging external/virtual monitor
122− onHeightChanged: {
123− source = ""
124− source = modelData
125− }
126120 }
127121 }
128122 }
qml/Rotation/RotationStates.qml+3
@@ -139,6 +139,9 @@ StateGroup {
139139 } else if (Powerd.status === Powerd.Off) {
140140 // There's no point in animating if the user can't see it (display is off).
141141 d.animationType = d.noAnimation;
142+ } else if (root.shell.showingGreeter) {
143+ // A rotating greeter looks weird.
144+ d.animationType = d.noAnimation;
142145 } else {
143146 if (!root.shell.mainApp) {
144147 // shouldn't happen but, anyway
qml/Shell.qml+2−7
@@ -59,7 +59,6 @@ StyledItem {
5959 property alias panelAreaShowProgress: panel.panelAreaShowProgress
6060 property string usageScenario: "phone" // supported values: "phone", "tablet" or "desktop"
6161 property string mode: "full-greeter"
62− property bool interactiveBlur: false
6362 property alias oskEnabled: inputMethod.enabled
6463 function updateFocusedAppOrientation() {
6564 stage.updateFocusedAppOrientation();
@@ -94,7 +93,7 @@ StyledItem {
9493
9594 readonly property bool orientationChangesEnabled: panel.indicators.fullyClosed
9695 && stage.orientationChangesEnabled
97− && (!greeter.animating)
96+ && (!greeter || !greeter.animating)
9897
9998 readonly property bool showingGreeter: greeter && greeter.shown
10099
@@ -105,7 +104,7 @@ StyledItem {
105104 if (startingUp) {
106105 // Ensure we don't rotate during start up
107106 return Qt.PrimaryOrientation;
108− } else if (notifications.topmostIsFullscreen) {
107+ } else if (showingGreeter || notifications.topmostIsFullscreen) {
109108 return Qt.PrimaryOrientation;
110109 } else {
111110 return shell.orientations ? shell.orientations.map(stage.supportedOrientations) : Qt.PrimaryOrientation;
@@ -437,8 +436,6 @@ StyledItem {
437436 enabled: panel.indicators.fullyClosed // hides OSK when panel is open
438437 hides: [launcher, panel.indicators, panel.applicationMenus]
439438 tabletMode: shell.usageScenario != "phone"
440− usageMode: shell.usageScenario
441− orientation: shell.orientation
442439 forcedUnlock: wizard.active || shell.mode === "full-shell"
443440 background: wallpaperResolver.background
444441 backgroundSourceSize: shell.largestScreenDimension
@@ -605,8 +602,6 @@ StyledItem {
605602 superTabPressed: physicalKeysMapper.superTabPressed
606603 panelWidth: units.gu(settings.launcherWidth)
607604 lockedVisible: (lockedByUser || shell.atDesktop) && lockAllowed
608− blurSource: greeter.shown ? greeter : stages
609− interactiveBlur: shell.interactiveBlur
610605 topPanelHeight: panel.panelHeight
611606 drawerEnabled: !greeter.active && tutorial.launcherLongSwipeEnabled
612607 privateMode: greeter.active
src/ApplicationArguments.h−5
@@ -28,7 +28,6 @@ class ApplicationArguments : public QObject
2828 Q_OBJECT
2929 Q_PROPERTY(QString deviceName READ deviceName NOTIFY deviceNameChanged)
3030 Q_PROPERTY(QString mode READ mode CONSTANT)
31− Q_PROPERTY(bool interactiveBlur READ interactiveBlur CONSTANT)
3231public:
3332 ApplicationArguments(QObject *parent = nullptr);
3433
@@ -43,16 +42,12 @@ public:
4342 void setMode(const QString &mode) { m_mode = mode; }
4443 QString mode() const { return m_mode; }
4544
46− void setInteractiveBlur(const bool &value) { m_interactiveBlur = value; }
47− bool interactiveBlur() { return m_interactiveBlur; }
48−
4945Q_SIGNALS:
5046 void deviceNameChanged(const QString&);
5147
5248private:
5349 QString m_deviceName;
5450 QString m_mode;
55− bool m_interactiveBlur;
5651};
5752
5853#endif // APPLICATION_ARGUMENTS_H
src/ShellApplication.cpp−6
@@ -58,12 +58,6 @@ ShellApplication::ShellApplication(int & argc, char ** argv, bool isMirServer)
5858
5959 m_qmlArgs.setMode(parser.mode());
6060
61− {
62− char buffer[200];
63− property_get("ubuntu.unity8.interactive_blur", buffer, "false");
64− m_qmlArgs.setInteractiveBlur(QString(buffer) == QStringLiteral("true"));
65− }
66−
6761 // The testability driver is only loaded by QApplication but not by QGuiApplication.
6862 // However, QApplication depends on QWidget which would add some unneeded overhead => Let's load the testability driver on our own.
6963 if (parser.hasTestability() || getenv("QT_LOAD_TESTABILITY")) {
tests/qmltests/CMakeLists.txt+2−1
@@ -29,7 +29,8 @@ add_unity8_qmltest(Components ZoomableImage)
2929add_unity8_qmltest(Greeter Clock)
3030add_unity8_qmltest(Greeter Greeter)
3131add_unity8_qmltest(Greeter Infographics)
32−add_unity8_qmltest(Greeter GreeterView)
32+add_unity8_qmltest(Greeter NarrowView)
33+add_unity8_qmltest(Greeter WideView)
3334add_unity8_qmltest_data(Greeter TestView)
3435add_unity8_qmltest(Launcher Launcher)
3536add_unity8_qmltest(Launcher Drawer)
tests/qmltests/Greeter/TestView.qml−7
@@ -38,13 +38,6 @@ Item {
3838 readonly property bool required: _required
3939 readonly property bool animating: _animating
4040
41− property bool multiUser
42− property int orientation
43− property string usageMode
44− property bool hasKeyboard
45− property real backgroundSourceSize
46− property rect inputMethodRect
47−
4841 property bool _fullyShown: true
4942 property bool _required: true
5043 property bool _animating: true
tests/qmltests/Greeter/tst_GreeterView.qmldeleted−1366
@@ -1,1366 +0,0 @@
1−/*
2− * Copyright 2014-2016 Canonical Ltd.
3− * Copyright 2021 UBports Foundation
4− *
5− * This program is free software; you can redistribute it and/or modify
6− * it under the terms of the GNU General Public License as published by
7− * the Free Software Foundation; version 3.
8− *
9− * This program is distributed in the hope that it will be useful,
10− * but WITHOUT ANY WARRANTY; without even the implied warranty of
11− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12− * GNU General Public License for more details.
13− *
14− * You should have received a copy of the GNU General Public License
15− * along with this program. If not, see <http://www.gnu.org/licenses/>.
16− */
17−
18−import QtQuick 2.4
19−import QtQuick.Window 2.2
20−import QtTest 1.0
21−import ".."
22−import "../../../qml/Greeter"
23−import LightDMController 0.1
24−import LightDM.FullLightDM 0.1 as LightDM
25−import Ubuntu.Components 1.3
26−import Ubuntu.Components.ListItems 1.3 as ListItem
27−import Ubuntu.Telephony 0.1 as Telephony
28−import Unity.Test 0.1 as UT
29−
30−StyledItem {
31− id: root
32−
33− width: units.gu(160)
34− height: units.gu(80)
35− focus: true
36−
37− theme.name: "Ubuntu.Components.Themes.Ambiance"
38−
39− Component.onCompleted: {
40− // must set the mock mode before loading the Shell
41− LightDMController.userMode = "single";
42− }
43−
44− Row {
45− anchors.fill: parent
46− Rectangle {
47− width: root.width - controls.width
48− height: parent.height
49− color: "grey"
50−
51− Rectangle {
52− id: viewContainer
53− anchors.horizontalCenter: parent.horizontalCenter
54− anchors.verticalCenter: parent.verticalCenter
55− focus: true
56−
57− Loader {
58− id: loader
59− width: parent.width
60− height: parent.height
61− focus: true
62−
63− property bool itemDestroyed: false
64− sourceComponent: Component {
65− GreeterView {
66− id: view
67−
68− background: "/usr/share/backgrounds/warty-final-ubuntu.png"
69− backgroundSourceSize: width
70− userModel: LightDM.Users
71− infographicModel: LightDM.Infographic
72−
73− launcherOffset: parseFloat(launcherOffsetField.text)
74− currentIndex: parseInt(currentIndexField.text, 10)
75− delayMinutes: parseInt(delayMinutesField.text, 10)
76− panelHeight: parseFloat(panelHeightField.text)
77− locked: lockedCheckBox.checked
78− inputMethodRect: fakeKeyboard.childrenRect
79− property var testKeyboard: fakeKeyboard
80−
81− usageMode: usageScenarioSelector.model[usageScenarioSelector.selectedIndex]
82− multiUser: multiUserCheckBox.checked
83− orientation: orientationSelector.model[orientationSelector.selectedIndex] == "landscape" ? Qt.LandscapeOrientation : Qt.PortraitOrientation
84−
85− Component.onDestruction: {
86− loader.itemDestroyed = true
87− }
88−
89− onSelected: {
90− if (index >= 0)
91− currentIndexField.text = index;
92− }
93−
94− Rectangle {
95− id: fakeKeyboard
96− color: "green"
97− opacity: 0.7
98− anchors.bottom: view.bottom
99− width: view.width
100− height: visible ? view.height * 0.6 : 0
101− visible: keyboardVisibleCheckBox.checked
102− Text {
103− text: "Keyboard Rectangle"
104− color: "yellow"
105− font.bold: true
106− fontSizeMode: Text.Fit
107− minimumPixelSize: 10; font.pixelSize: 200
108− verticalAlignment: Text.AlignVCenter
109− x: (parent.width - width) / 2
110− y: (parent.height - height) / 2
111− width: parent.width
112− height: parent.height
113− }
114− }
115− }
116− }
117− }
118−
119− state: loader.item ? loader.item.usageMode + "-" + (loader.item.isLandscape ? "landscape" : "portrait") : "phone-portrait"
120−
121− states: [
122− State {
123− name: "phone-portrait"
124− PropertyChanges {
125− target: viewContainer
126− width: units.gu(40)
127− height: units.gu(71)
128− }
129− },
130− State {
131− name: "phone-landscape"
132− PropertyChanges {
133− target: viewContainer
134− width: units.gu(71)
135− height: units.gu(40)
136− }
137− },
138− State {
139− name: "tablet-landscape"
140− PropertyChanges {
141− target: viewContainer
142− width: units.gu(100)
143− height: units.gu(71)
144− }
145− },
146− State {
147− name: "tablet-portrait"
148− PropertyChanges {
149− target: viewContainer
150− width: units.gu(71)
151− height: units.gu(100)
152− }
153− },
154− State {
155− name: "desktop-portrait"
156− PropertyChanges {
157− target: viewContainer
158− width: parent.width
159− height: parent.height
160− }
161− },
162− State {
163− name: "desktop-landscape"
164− PropertyChanges {
165− target: viewContainer
166− width: parent.width
167− height: parent.height
168− }
169− }
170− ]
171− }
172− }
173−
174− Rectangle {
175− id: controls
176− color: theme.palette.normal.background
177− width: units.gu(40)
178− height: parent.height
179− Column {
180− anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) }
181− spacing: units.gu(1)
182− Row {
183− Button {
184− text: "Hide"
185− onClicked: loader.item.hide()
186− }
187− }
188− Row {
189− Button {
190− text: "Show Message"
191− onClicked: LightDMService.prompts.append(messageField.text, LightDMService.prompts.Message)
192− }
193− TextField {
194− id: messageField
195− width: units.gu(10)
196− text: ""
197− }
198− }
199− Row {
200− Button {
201− text: "Show Prompt"
202− onClicked: LightDMService.prompts.append(promptField.text, isSecretCheckBox.checked ? LightDMService.prompts.Secret : LightDMService.prompts.Question)
203− }
204− TextField {
205− id: promptField
206− width: units.gu(10)
207− text: ""
208− }
209− CheckBox {
210− id: isSecretCheckBox
211− }
212− Label {
213− text: "secret"
214− }
215− }
216− Row {
217− Button {
218− text: "Notify Auth Failure"
219− onClicked: {
220− loader.item.notifyAuthenticationFailed();
221− }
222− }
223− }
224− Row {
225− Button {
226− text: "Try To Unlock"
227− onClicked: loader.item.tryToUnlock(toTheRightCheckBox.checked)
228− }
229− CheckBox {
230− id: toTheRightCheckBox
231− }
232− Label {
233− text: "toTheRight"
234− }
235− }
236− Label {
237− text: "Usage scenario"
238− }
239−
240− ListItem.ItemSelector {
241− id: usageScenarioSelector
242− anchors { left: parent.left; right: parent.right }
243− activeFocusOnPress: false
244− model: ["phone", "tablet", "desktop"]
245− }
246− Label {
247− text: "Orientation"
248− }
249−
250− ListItem.ItemSelector {
251− id: orientationSelector
252− anchors { left: parent.left; right: parent.right }
253− activeFocusOnPress: false
254− model: ["portrait", "landscape"]
255− }
256− Row {
257− TextField {
258− id: launcherOffsetField
259− width: units.gu(10)
260− text: "0"
261− }
262− Label {
263− text: "launcherOffset"
264− }
265− }
266− Row {
267− TextField {
268− id: currentIndexField
269− width: units.gu(10)
270− text: "0"
271− }
272− Label {
273− text: "currentIndex"
274− }
275− }
276− Row {
277− TextField {
278− id: delayMinutesField
279− width: units.gu(10)
280− text: "0"
281− }
282− Label {
283− text: "delayMinutes"
284− }
285− }
286− Row {
287− TextField {
288− id: panelHeightField
289− width: units.gu(10)
290− text: "0"
291− }
292− Label {
293− text: "panelHeight"
294− }
295− }
296− Row {
297− CheckBox {
298− id: lockedCheckBox
299− }
300− Label {
301− text: "locked"
302− }
303− }
304− Row {
305− CheckBox {
306− id: multiUserCheckBox
307− onClicked: {
308− if (checked) {
309− LightDMController.userMode = "full";
310− } else {
311− LightDMController.userMode = "single";
312− }
313− }
314− Connections {
315− target: LightDMController
316− onSessionModeChanged: {
317− if (LightDMController.userMode === "full") {
318− multipleSessionsCheckbox.checked = true;
319− } else {
320− multipleSessionsCheckbox.checked = false;
321− }
322− }
323− }
324− }
325− Label {
326− text: "multi user"
327− }
328− }
329− Row {
330− CheckBox {
331− id: alphanumericCheckBox
332− checked: true
333− }
334− Label {
335− text: "alphanumeric"
336− }
337− }
338− Row {
339− Label {
340− text: "selected: " + selectedSpy.count
341− }
342− }
343− Row {
344− Label {
345− text: "responded: " + respondedSpy.count
346− }
347− }
348− Row {
349− Label {
350− text: "teased: " + teaseSpy.count
351− }
352− }
353− Row {
354− Label {
355− text: "emergency: " + emergencySpy.count
356− }
357− }
358− Row {
359− Label {
360− text: "infographics: " + infographicDataChangedSpy.count
361− }
362− }
363− Row {
364− id: multipleSessions
365− CheckBox {
366− id: multipleSessionsCheckbox
367− onClicked: {
368− if (checked) {
369− LightDMController.sessionMode = "full";
370− } else {
371− LightDMController.sessionMode = "single";
372− }
373− }
374− Connections {
375− target: LightDMController
376− onSessionModeChanged: {
377− if (LightDMController.sessionMode === "full") {
378− multipleSessionsCheckbox.checked = true;
379− } else {
380− multipleSessionsCheckbox.checked = false;
381− }
382− }
383− }
384− }
385− Label {
386− text: "Multiple Sessions"
387− }
388− }
389− Row {
390− Slider {
391− id: numSessionsSlider
392−
393− width: units.gu(10)
394− minimumValue: 0
395− maximumValue: LightDMController.numAvailableSessions
396− value: LightDMController.numSessions
397− visible: LightDMController.sessionMode === "full"
398− Binding {
399− target: LightDMController
400− property: "numSessions"
401− value: numSessionsSlider.value
402− }
403− }
404− Label {
405− text: "Available Sessions"
406− }
407− }
408− Row {
409− Button {
410− text: "Reload View"
411− onClicked: {
412− loader.active = false;
413− loader.active = true;
414− }
415− }
416− }
417− Row {
418− CheckBox {
419− id: keyboardVisibleCheckBox
420− }
421− Label {
422− text: "Keyboard Visible"
423− }
424− }
425− }
426− }
427− }
428−
429−/* FIXME: infographic user is hardcoded to "has-password",
430− * needs to be set to current user to test in multiUser mode
431− */
432− Binding {
433− target: LightDM.Infographic
434− property: "username"
435− value: "has-password"
436− }
437−
438− SignalSpy {
439− id: selectedSpy
440− target: loader.item
441− signalName: "selected"
442− }
443−
444− SignalSpy {
445− id: respondedSpy
446− target: loader.item
447− signalName: "responded"
448− }
449−
450− SignalSpy {
451− id: teaseSpy
452− target: loader.item
453− signalName: "tease"
454− }
455−
456− SignalSpy {
457− id: emergencySpy
458− target: loader.item
459− signalName: "emergencyCall"
460− }
461−
462− SignalSpy {
463− id: infographicDataChangedSpy
464− target: LightDM.Infographic
465− signalName: "dataChanged"
466− }
467−
468− UT.UnityTestCase {
469− name: "GreeterView"
470− when: windowShown
471−
472− property Item view: loader.status === Loader.Ready ? loader.item : null
473− property url testIconDirectory: Qt.resolvedUrl("../../../qml/Greeter/graphics/session_icons")
474−
475− function init() {
476− selectIndex(0); // break binding with text field
477− tryCompare(LightDMService.prompts, "count", 1);
478− selectedSpy.clear();
479− respondedSpy.clear();
480− teaseSpy.clear();
481− emergencySpy.clear();
482− infographicDataChangedSpy.clear();
483− LightDMController.reset();
484− LightDM.Sessions.iconSearchDirectories = [testIconDirectory];
485−
486− waitForRendering(view);
487− var userList = findChild(view, "userList");
488− tryCompare(userList, "movingInternally", false);
489− }
490−
491− function cleanup() {
492− keyboardVisibleCheckBox.checked = false;
493−
494− loader.itemDestroyed = false;
495− loader.active = false;
496− tryCompare(loader, "status", Loader.Null);
497− tryCompare(loader, "item", null);
498− tryCompare(loader, "itemDestroyed", true);
499− loader.active = true;
500− tryCompare(loader, "status", Loader.Ready);
501− removeTimeConstraintsFromSwipeAreas(loader.item);
502− LightDMController.sessionMode = "single";
503− }
504−
505− function setLightDMMockMode(mode) {
506− LightDMController.userMode = mode;
507− waitForRendering(root);
508− }
509−
510− function setUsageMode(usageMode) {
511− view.usageMode = usageMode;
512− if (usageMode == "desktop") {
513− view.multiUser = true;
514− setLightDMMockMode("full");
515− view.orientation = Qt.LandscapeOrientation;
516− } else if (usageMode == "phone") {
517− view.multiUser = false;
518− setLightDMMockMode("single");
519− view.orientation = Qt.PortraitOrientation;
520− telepathyHelper.ready = true;
521− telepathyHelper.emergencyCallsAvailable = true;
522− LightDM.Greeter.authenticate("no-password");
523− tryCompare(LightDMService.prompts, "count", 1);
524− }
525− }
526−
527− function swipeAwayCover(toTheRight) {
528− if (toTheRight === undefined) {
529− toTheRight = false;
530− }
531−
532− tryCompare(view, "fullyShown", true);
533− var touchY = view.height / 2;
534− if (toTheRight) {
535− touchFlick(view, 0, touchY, view.width, touchY);
536− } else {
537− touchFlick(view, view.width, touchY, 0, touchY);
538− }
539− var coverPage = findChild(view, "coverPage");
540− tryCompare(coverPage, "showProgress", 0);
541− waitForRendering(view);
542− }
543−
544− function getIndexOf(name) {
545− for (var i = 0; i < LightDM.Users.count; i++) {
546− if (name === LightDM.Users.data(i, LightDM.UserRoles.NameRole)) {
547− return i;
548− }
549− }
550− fail("Didn't find name")
551− return -1;
552− }
553−
554− function selectIndex(i) {
555− var user = LightDM.Users.data(i, LightDM.UserRoles.NameRole);
556− LightDM.Greeter.authenticate(user);
557−
558− var userList = findChild(view, "userList");
559− var promptList = findChild(view, "promptList");
560−
561− view.currentIndex = i;
562− tryCompare(promptList, "opacity", 1);
563− tryCompare(userList, "movingInternally", false);
564− }
565−
566− function selectUser(name) {
567− var i = getIndexOf(name);
568− selectIndex(i);
569− return i;
570− }
571−
572−/* Desktop view tests (multiuser) */
573− function test_sessionless_user_is_still_valid() {
574− setUsageMode("desktop");
575− var loginList = findChild(view, "loginList")
576−
577− /*
578− * If a user has never logged in before, or, for some reason
579− * has no sessionHint, ensure that the model returns the default
580− * session and that the view respects this
581− */
582− selectUser("no-session");
583− compare(LightDM.Users.data(loginList.currentIndex, LightDM.UserRoles.SessionRole), LightDM.Greeter.defaultSession);
584−
585− tryCompare(loginList, "currentSession", LightDM.Greeter.defaultSession);
586− }
587−
588− function test_changingSessionSticksToUser() {
589− setUsageMode("desktop");
590− var loginList = findChild(view, "loginList");
591−
592− selectUser("invalid-session");
593− tryCompare(loginList, "currentSession", "invalid");
594−
595− selectUser("has-password");
596− tryCompare(loginList, "currentSession", "ubuntu");
597−
598− selectUser("invalid-session")
599− tryCompare(loginList, "currentSession", "invalid");
600− }
601−
602− function test_sessionIconsAreValid() {
603− setUsageMode("desktop");
604− LightDMController.sessionMode = "full";
605− selectUser("has-password");
606−
607− // Test the login list icon is valid
608− var sessionChooserButton = findChild(view, "sessionChooserButton");
609− compare(sessionChooserButton.visible, true);
610−
611− var loginList = findChild(view, "loginList");
612− var session = String(loginList.currentSession).toLowerCase();
613− var icon = String(sessionChooserButton.icon);
614− compare(icon.indexOf(session) > -1, true);
615−
616− // Test the session list icons are valid
617− var lockscreen = findChild(view, "lockscreen");
618− lockscreen.state = "SessionsList"
619− var sessionsList = findChild(view, "sessionsList");
620− tryCompare(sessionsList, "visible", true);
621− }
622−
623− function test_choosingNewSessionChangesLoginListIcon() {
624− // Ensure the default session is selected (Ubuntu)
625− cleanup();
626− setUsageMode("desktop");
627− swipeAwayCover();
628−
629− LightDMController.sessionMode = "full";
630− selectUser("has-password");
631−
632− var sessionChooserButton = findChild(view, "sessionChooserButton");
633− var icon = String(sessionChooserButton.icon);
634− compare(icon.indexOf("ubuntu") > -1, true);
635−
636− tap(sessionChooserButton)
637− for(var i = 0; i < LightDM.Sessions.count; i++) {
638− var delegateName = "sessionDelegate" + String(i);
639− var currentDelegate = findChild(view, delegateName);
640− verify(currentDelegate);
641− var sessionKey = LightDM.Sessions.data(i,LightDM.SessionRoles.KeyRole);
642− if (sessionKey === "gnome-classic") {
643− waitForRendering(currentDelegate);
644− tap(currentDelegate);
645− waitForRendering(sessionChooserButton);
646− break;
647− }
648− }
649−
650− icon = String(sessionChooserButton.icon);
651− compare(icon.indexOf("gnome") > -1, true,
652− "Expected icon to contain gnome but it was " + icon);
653− }
654−
655− function test_noSessionsDoesntBreakView() {
656− setUsageMode("desktop");
657− LightDMController.sessionMode = "none";
658− compare(LightDM.Sessions.count, 0)
659− }
660−
661− function test_sessionIconNotShownWithOneSession() {
662− setUsageMode("desktop");
663− LightDMController.sessionMode = "single";
664− compare(LightDM.Sessions.count, 1);
665−
666− var sessionChooserButton = findChild(view, "sessionChooserButton");
667− tryCompare(sessionChooserButton, "visible", false);
668− }
669−
670− function test_sessionIconNotShownWithActiveUser() {
671− setUsageMode("desktop");
672− selectUser("active");
673−
674− var sessionChooserButton = findChild(view, "sessionChooserButton");
675− tryCompare(sessionChooserButton, "visible", false);
676− }
677−
678− function test_sessionIconShownWithMultipleSessions() {
679− setUsageMode("desktop");
680− LightDMController.sessionMode = "full";
681− selectUser("has-password");
682−
683− var sessionChooserButton = findChild(view, "sessionChooserButton");
684− tryCompare(sessionChooserButton, "visible", true);
685− }
686−
687− function test_selected() {
688− setUsageMode("desktop");
689− swipeAwayCover();
690− var delegate = findChild(view, "username2");
691− tap(delegate);
692− compare(selectedSpy.count, 1);
693− compare(selectedSpy.signalArguments[0][0], 2);
694− compare(view.currentIndex, 0); // confirm we didn't change
695− }
696−
697− function test_customBackground() {
698− setUsageMode("desktop");
699− var lockscreen = findChild(view, "lockscreen");
700− var backgroundShade = findChild(lockscreen, "backgroundShade");
701−
702− verify(!view.hasCustomBackground);
703− verify(!backgroundShade.visible);
704−
705− view.hasCustomBackground = true;
706− verify(backgroundShade.visible);
707− }
708−
709− function test_respondedWithPassword() {
710− setUsageMode("desktop");
711− swipeAwayCover();
712− selectUser("has-password");
713− var greeterPrompt = findChild(view, "greeterPrompt0");
714− verify(greeterPrompt.isSecret);
715− typeString("password");
716− keyClick(Qt.Key_Enter);
717− compare(respondedSpy.count, 1);
718− compare(respondedSpy.signalArguments[0][0], "password");
719− }
720−
721− function test_respondedWithNonSecret() {
722− setUsageMode("desktop");
723− swipeAwayCover();
724− selectUser("question-prompt");
725− var greeterPrompt = findChild(view, "greeterPrompt0");
726− verify(!greeterPrompt.isSecret);
727− typeString("foo");
728− keyClick(Qt.Key_Enter);
729− compare(respondedSpy.count, 1);
730− compare(respondedSpy.signalArguments[0][0], "foo");
731− }
732−
733− function test_fullyShown_data() {
734− return [
735− {tag: "multiuser", multiUser: true, usageMode: "desktop", results: [true, true, true, true]},
736− {tag: "singleuser", multiUser: false, usageMode: "desktop", results: [true, false, true, false]},
737− {tag: "multiuser", multiUser: true, usageMode: "phone", results: [true, true, true, true]},
738− {tag: "singleuser", multiUser: false, usageMode: "phone", results: [true, false, true, false]}
739− ]
740− }
741−
742− function test_fullyShown(data) {
743− setUsageMode(data.usageMode);
744− view.multiUser = data.multiUser;
745− tryCompare(view, "fullyShown", data.results[0]);
746− tryCompare(view, "required", data.results[0]);
747− swipeAwayCover();
748− tryCompare(view, "fullyShown", data.results[1]);
749− tryCompare(view, "required", data.results[1]);
750− view.locked = true;
751− tryCompare(view, "fullyShown", data.results[2]);
752− tryCompare(view, "required", data.results[2]);
753− view.locked = false;
754− tryCompare(view, "fullyShown", data.results[3]);
755− tryCompare(view, "required", data.results[3]);
756− }
757−
758− function test_infoPrompt() {
759− setUsageMode("desktop");
760− selectUser("info-prompt");
761−
762− var infoLabel = findChild(view, "infoLabel0");
763− compare(infoLabel.text, "Welcome to Unity Greeter");
764− compare(infoLabel.textFormat, Text.PlainText);
765−
766− verify(findChild(view, "greeterPrompt1") != null);
767− }
768−
769− function test_longInfoPrompt() {
770− setUsageMode("desktop");
771− selectUser("long-info-prompt");
772−
773− var infoLabel = findChild(view, "infoLabel0");
774− compare(infoLabel.text, "Welcome to Unity Greeter\n\nWe like to annoy you with super ridiculously long messages.\nLike this one\n\nThis is the last line of a multiple line message.");
775− verify(infoLabel.contentWidth > infoLabel.width);
776−
777− verify(findChild(view, "greeterPrompt1") != null);
778− }
779−
780− function test_multiInfoPrompt() {
781− setUsageMode("desktop");
782− selectUser("multi-info-prompt");
783−
784− var infoLabel0 = findChild(view, "infoLabel0");
785− compare(infoLabel0.text, "Welcome to Unity Greeter");
786−
787− var infoLabel1 = findChild(view, "infoLabel1");
788− compare(infoLabel1.text, "This is an error");
789− compare(infoLabel1.color, theme.palette.normal.negative);
790−
791− var infoLabel2 = findChild(view, "infoLabel2");
792− compare(infoLabel2.text, "You should have seen three messages");
793−
794− verify(findChild(view, "greeterPrompt3") != null);
795− }
796−
797− // Escape is used to reset the authentication, especially if PAM is unresponsive
798− function test_escape() {
799− setUsageMode("desktop");
800− swipeAwayCover();
801− var index = selectUser("has-password");
802− selectedSpy.clear();
803− view.locked = true;
804− var promptField = findChild(view, "promptField");
805− tap(promptField);
806− verify(promptField.activeFocus);
807− compare(promptField.opacity, 1);
808−
809− typeString("password");
810− keyClick(Qt.Key_Enter);
811− verify(promptField.activeFocus);
812− compare(promptField.opacity, 0); // hidden by fakeLabel
813−
814− compare(selectedSpy.count, 0);
815− keyClick(Qt.Key_Escape);
816− compare(selectedSpy.count, 1);
817− compare(selectedSpy.signalArguments[0][0], index);
818−
819− selectIndex(index);
820− var promptField = findChild(view, "promptField");
821− verify(promptField.activeFocus);
822− compare(promptField.opacity, 1);
823− }
824−
825− function test_unicode() {
826− setUsageMode("desktop");
827− var index = selectUser("unicode");
828− var label = findChild(view, "username" + index);
829− tryCompare(label, "text", "가나다라마");
830− }
831−
832− function test_authError() {
833− setUsageMode("desktop");
834− swipeAwayCover();
835− var index = selectUser("auth-error");
836− var greeterPrompt = findChild(view, "greeterPrompt1"); // after error message
837− view.locked = true;
838− compare(greeterPrompt.text, "Retry");
839− tap(greeterPrompt);
840− compare(respondedSpy.count, 0);
841− compare(selectedSpy.count, 1);
842− compare(selectedSpy.signalArguments[0][0], index);
843− }
844−
845− function test_noPassword() {
846− setUsageMode("desktop");
847− swipeAwayCover();
848− selectUser("no-password");
849− var greeterPrompt = findChild(view, "greeterPrompt0");
850− compare(greeterPrompt.text, "Log In");
851− tap(greeterPrompt);
852− compare(selectedSpy.count, 0);
853− compare(respondedSpy.count, 1);
854− compare(respondedSpy.signalArguments[0][0], "");
855− }
856−
857− function test_loginListNotCoveredByKeyboard() {
858− setUsageMode("desktop");
859− var loginList = findChild(view, "loginList");
860− compare(loginList.height, view.height);
861−
862− // when the vkb shows up, loginList is moved up to remain fully uncovered
863−
864− keyboardVisibleCheckBox.checked = true;
865−
866− var halfway = (view.height - loginList.highlightedHeight) / 2;
867− var halfwayWithOsk = halfway - view.inputMethodRect.height / 2;
868− tryCompare(loginList, "boxVerticalOffset", halfwayWithOsk);
869−
870− var highlightItem = findChild(loginList, "highlightItem");
871− tryCompareFunction( function() {
872− var highlightRect = highlightItem.mapToItem(view, 0, 0, highlightItem.width, highlightItem.height);
873− return highlightRect.y + highlightRect.height <= view.testKeyboard.y;
874− }, true);
875−
876− // once the vkb goes away, loginList goes back to its full height
877−
878− keyboardVisibleCheckBox.checked = false;
879−
880− tryCompare(loginList, "boxVerticalOffset", halfway);
881− }
882−
883− function test_passphrase() {
884− setUsageMode("desktop");
885− swipeAwayCover();
886− var index = selectUser("has-password");
887− var promptField = findChild(view, "promptField");
888−
889− verify(view.alphanumeric);
890− compare(promptField.inputMethodHints & Qt.ImhDigitsOnly, 0);
891−
892− keyClick(Qt.Key_D);
893− compare(promptField.text, "d");
894− }
895−
896− function test_passcode() {
897− setUsageMode("desktop");
898− swipeAwayCover();
899− var index = selectUser("has-pin");
900− view.alphanumeric = false;
901−
902− var promptField = findChild(view, "promptField");
903− compare(promptField.inputMethodHints & Qt.ImhDigitsOnly, Qt.ImhDigitsOnly);
904−
905− keyClick(Qt.Key_D);
906− compare(promptField.text, "");
907−
908− keyClick(Qt.Key_0);
909− keyClick(Qt.Key_0);
910− keyClick(Qt.Key_0);
911− keyClick(Qt.Key_0);
912− compare(promptField.text, "0000");
913−
914− compare(respondedSpy.count, 1);
915− compare(respondedSpy.signalArguments[0][0], "0000");
916−
917− compare(promptField.opacity, 0);
918− }
919−
920− function test_loginListMovement_data() {
921− return [
922− {tag: "up", key: Qt.Key_Up, result: 1},
923− {tag: "down", key: Qt.Key_Down, result: 3},
924− ]
925− }
926−
927− function test_loginListMovement(data) {
928− setUsageMode("desktop");
929− swipeAwayCover();
930− selectIndex(2);
931− selectedSpy.clear();
932−
933− keyClick(data.key);
934− compare(selectedSpy.count, 1);
935− compare(selectedSpy.signalArguments[0][0], data.result);
936− }
937−
938− function test_focusStaysActive() {
939− setUsageMode("desktop");
940− swipeAwayCover();
941− selectUser("no-password");
942− var greeterPrompt = findChild(view, "greeterPrompt0");
943− verify(greeterPrompt.activeFocus);
944− keyClick(Qt.Key_Enter);
945− compare(selectedSpy.count, 0);
946− compare(respondedSpy.count, 1);
947− compare(respondedSpy.signalArguments[0][0], "");
948− verify(greeterPrompt.activeFocus);
949− keyClick(Qt.Key_Enter);
950− compare(respondedSpy.count, 1);
951−
952− selectUser("has-password");
953− var greeterPrompt = findChild(view, "greeterPrompt0");
954− verify(greeterPrompt.activeFocus);
955− keyClick(Qt.Key_D);
956− keyClick(Qt.Key_Enter);
957− compare(selectedSpy.count, 0);
958− compare(respondedSpy.count, 2);
959− compare(respondedSpy.signalArguments[1][0], "d");
960− verify(greeterPrompt.activeFocus);
961− keyClick(Qt.Key_Enter);
962− compare(respondedSpy.count, 2);
963−
964− var index = selectUser("no-password");
965− var greeterPrompt = findChild(view, "greeterPrompt0");
966− view.locked = true;
967− verify(greeterPrompt.activeFocus);
968− keyClick(Qt.Key_Enter);
969− compare(respondedSpy.count, 2);
970− compare(selectedSpy.count, 1);
971− compare(selectedSpy.signalArguments[0][0], index);
972− verify(greeterPrompt.activeFocus);
973− keyClick(Qt.Key_Enter);
974− compare(selectedSpy.count, 1);
975−
976− selectUser("no-password");
977− var greeterPrompt = findChild(view, "greeterPrompt0");
978− verify(greeterPrompt.activeFocus);
979− }
980−
981− function test_scrollChangesIndex() {
982− /* Check if the index of the current user gets changed
983− * if we scroll through the list.
984− * Expected result: the list has moved at least by one
985− * user and the index of the user is reported using the
986− * selected signal in LoginList.qml
987− * https://github.com/ubports/unity8/issues/397
988− */
989− setUsageMode("desktop");
990− swipeAwayCover();
991− var loginList = findChild(view, "loginList");
992− // FIXME: Fix scrolling sensitivity (scrolling by -1 shouldn't move more than one user down)
993− mouseWheel( loginList, loginList.width / 2, loginList.height / 2, 0, -1, null );
994− selectedSpy.wait();
995− tryVerify(function(){ return selectedSpy.signalArguments[0][0] > 0 });
996− }
997−
998−// function test_dragChangesIndex() {
999−// /* Check if the index of the current user gets changed
1000−// * if we drag the list or swipe.on it.
1001−// * Expected result: the list has moved at least by one
1002−// * user and the index of the user is reported using the
1003−// * selected signal in LoginList.qml
1004−// * https://github.com/ubports/unity8/issues/397
1005−// */
1006−// setUsageMode("desktop");
1007−// swipeAwayCover();
1008−// var loginList = findChild(view, "loginList");
1009−// // FIXME: Fix scrolling sensitivity (the number of scrolled users is randomly changing)
1010−// touchFlick(loginList, loginList.width/2, loginList.height/3, loginList.width/2, loginList.height/3 -units.gu(2.1));
1011−// selectedSpy.wait();
1012−// tryVerify(function(){ return selectedSpy.signalArguments[0][0] > 0 });
1013−// }
1014−
1015−/* Mobile view tests */
1016− function test_tease_data() {
1017− return [
1018− {tag: "left", x: 0, offset: 0, count: 1},
1019− {tag: "leftWithOffsetPass", x: 10, offset: 10, count: 1},
1020− {tag: "leftWithOffsetFail", x: 9, offset: 10, count: 0},
1021− {tag: "right", x: view.width, offset: 0, count: 1},
1022− ]
1023− }
1024− function test_tease(data) {
1025− view.dragHandleLeftMargin = data.offset;
1026− tap(view, data.x, 0);
1027− tryCompare(teaseSpy, "count", data.count);
1028− }
1029−
1030− function test_respondedWithPin() {
1031− LightDM.Greeter.authenticate("has-pin");
1032− view.locked = true;
1033− view.alphanumeric = false;
1034− swipeAwayCover();
1035− typeString("1234");
1036− respondedSpy.wait();
1037− compare(respondedSpy.signalArguments[0][0], "1234");
1038− }
1039−
1040− function test_respondedWithPassphrase() {
1041− LightDM.Greeter.authenticate("has-password");
1042− view.locked = true;
1043− swipeAwayCover();
1044− typeString("test");
1045− keyClick(Qt.Key_Enter);
1046− compare(respondedSpy.count, 1);
1047− compare(respondedSpy.signalArguments[0][0], "test");
1048− }
1049−
1050− function test_respondedWithSwipe_data() {
1051− return [
1052− {tag: "left", toTheRight: false, hiddenX: -view.width},
1053− {tag: "right", toTheRight: true, hiddenX: view.width},
1054− ];
1055− }
1056− function test_respondedWithSwipe(data) {
1057− swipeAwayCover(data.toTheRight);
1058− var coverPage = findChild(view, "coverPage");
1059− compare(coverPage.x, data.hiddenX);
1060− compare(respondedSpy.count, 1);
1061− compare(respondedSpy.signalArguments[0][0], "");
1062− }
1063−
1064− function test_emergencyCall_data() {
1065− return [
1066− {tag: "phone", available: true},
1067− {tag: "desktop", available: false},
1068− ];
1069− }
1070− function test_emergencyCall(data) {
1071− telepathyHelper.emergencyCallsAvailable = data.available;
1072− view.locked = true;
1073− swipeAwayCover();
1074− var emergencyCallLabel = findChild(view, "emergencyCallLabel");
1075− tap(emergencyCallLabel);
1076− if (!data.available) {
1077− expectFail("", "Bug 1616538 prevents us supporting conditional emergency button support");
1078− }
1079− compare(emergencyCallLabel.visible, data.available ? true : false);
1080− compare(emergencySpy.count, data.available ? 1 : 0);
1081− }
1082−
1083− function test_emergencyCallAvailability() {
1084− view.locked = true;
1085− var emergencyCallLabel = findChild(view, "emergencyCallLabel");
1086− verify(emergencyCallLabel.visible);
1087−
1088− telepathyHelper.emergencyCallsAvailable = false;
1089− telepathyHelper.ready = true;
1090− expectFail("", "Bug 1616538 prevents us supporting conditional emergency button support");
1091− verify(!emergencyCallLabel.visible);
1092−
1093− telepathyHelper.emergencyCallsAvailable = true;
1094− telepathyHelper.ready = false;
1095− verify(!emergencyCallLabel.visible);
1096− }
1097−
1098− function test_tryToUnlock() {
1099− var coverPage = findChild(view, "coverPage");
1100− tryCompare(coverPage, "showProgress", 1);
1101− compare(view.tryToUnlock(false), true);
1102− tryCompare(coverPage, "showProgress", 0);
1103− compare(view.tryToUnlock(false), false);
1104− }
1105−
1106− /*
1107− Regression test for https://bugs.launchpad.net/ubuntu/+source/unity8/+bug/1388359
1108− "User metrics can no longer be changed by double tap"
1109− */
1110− function test_doubleTapSwitchesToNextInfographic() {
1111− setUsageMode("phone");
1112− infographicDataChangedSpy.clear();
1113− var coverPage = findChild(view, "coverPage");
1114− verify(coverPage);
1115−
1116− var infographicPrivate = findInvisibleChild(coverPage, "infographicPrivate");
1117− verify(infographicPrivate);
1118−
1119− // wait for the UI to settle down before double tapping it
1120− tryCompare(infographicPrivate, "animating", false);
1121−
1122− var dataCircle = findChild(coverPage, "dataCircle");
1123− verify(dataCircle);
1124−
1125− mouseDoubleClickSequence(dataCircle);
1126−
1127− tryCompare(infographicDataChangedSpy, "count", 1);
1128− }
1129−
1130− function test_movesBackIntoPlaceWhenNotDraggedFarEnough() {
1131− var coverPage = findChild(view, "coverPage");
1132−
1133− var dragEvaluator = findInvisibleChild(coverPage, "edgeDragEvaluator");
1134− verify(dragEvaluator);
1135−
1136− // Make it easier to get a rejection/rollback. Otherwise would have to inject
1137− // a fake timer into dragEvaluator.
1138− // Afterall, we are testing if the CoverPage indeed moves back on a
1139− // rollback decision, not the drag evaluation itself.
1140− dragEvaluator.minDragDistance = dragEvaluator.maxDragDistance / 2;
1141−
1142− // it starts as fully shown
1143− compare(coverPage.x, 0);
1144−
1145− // then we drag it a bit
1146− var startX = coverPage.width - 1;
1147− var touchY = coverPage.height / 2;
1148− var dragXDelta = -(dragEvaluator.minDragDistance * 0.3);
1149− touchFlick(coverPage,
1150− startX , touchY, // start pos
1151− startX + dragXDelta, touchY, // end pos
1152− true /* beginTouch */, false /* endTouch */);
1153−
1154− // which should make it move a bit
1155− tryCompareFunction(function() {return coverPage.x < 0;}, true);
1156−
1157− // then we release it
1158− touchRelease(coverPage, startX + dragXDelta, touchY);
1159−
1160− // which should make it move back into its original position as it didn't move
1161− // far enough to have it hidden
1162− tryCompare(coverPage, "x", 0);
1163− }
1164−
1165− function test_dragToHide_data() {
1166− return [
1167− {tag: "left", startX: view.width * 0.95, endX: view.width * 0.1, hiddenX: -view.width},
1168− {tag: "right", startX: view.width * 0.1, endX: view.width * 0.95, hiddenX: view.width},
1169− ];
1170− }
1171− function test_dragToHide(data) {
1172− var coverPage = findChild(view, "coverPage");
1173− compare(coverPage.x, 0);
1174− compare(coverPage.visible, true);
1175− compare(coverPage.shown, true);
1176− compare(coverPage.showProgress, 1);
1177− compare(view.fullyShown, true);
1178−
1179− touchFlick(view,
1180− data.startX, view.height / 2, // start pos
1181− data.endX, view.height / 2); // end pos
1182−
1183− tryCompare(coverPage, "x", data.hiddenX);
1184− tryCompare(coverPage, "visible", false);
1185− tryCompare(coverPage, "shown", false);
1186− tryCompare(coverPage, "showProgress", 0);
1187− compare(view.fullyShown, false);
1188− }
1189−
1190− function test_hiddenViewRemainsHiddenAfterResize_data() {
1191− return [
1192− {tag: "left", startX: view.width * 0.95, endX: view.width * 0.1},
1193− {tag: "right", startX: view.width * 0.1, endX: view.width * 0.95},
1194− ];
1195− }
1196− function test_hiddenViewRemainsHiddenAfterResize(data) {
1197− touchFlick(view,
1198− data.startX, view.height / 2, // start pos
1199− data.endX, view.height / 2); // end pos
1200−
1201− var coverPage = findChild(view, "coverPage");
1202− tryCompare(coverPage, "x", data.tag == "left" ? -view.width : view.width);
1203− tryCompare(coverPage, "visible", false);
1204− tryCompare(coverPage, "shown", false);
1205− tryCompare(coverPage, "showProgress", 0);
1206−
1207− // flip dimensions to simulate an orientation change
1208− view.width = loader.height;
1209− view.height = loader.width;
1210−
1211− // All properties should remain consistent
1212− tryCompare(coverPage, "x", data.tag == "left" ? -view.width : view.width);
1213− tryCompare(coverPage, "visible", false);
1214− tryCompare(coverPage, "shown", false);
1215− tryCompare(coverPage, "showProgress", 0);
1216− }
1217−
1218− // Make sure that if user has a mouse, they can still get rid of cover page
1219− function test_mouseClickHidesCoverPage() {
1220− var coverPage = findChild(view, "coverPage");
1221−
1222− verify(coverPage.shown);
1223− mouseClick(coverPage, coverPage.width/2, coverPage.height - units.gu(2));
1224− verify(!coverPage.shown);
1225− }
1226−
1227− function test_showErrorMessage() {
1228− var coverPage = findChild(view, "coverPage");
1229− var swipeHint = findChild(coverPage, "swipeHint");
1230− var errorMessageAnimation = findInvisibleChild(coverPage, "errorMessageAnimation");
1231−
1232− view.showErrorMessage("hello");
1233− compare(swipeHint.text, "《 hello 》");
1234− verify(errorMessageAnimation.running);
1235− verify(swipeHint.opacityAnimation.running);
1236−
1237− errorMessageAnimation.complete();
1238− swipeHint.opacityAnimation.complete();
1239− tryCompare(swipeHint, "text", "《 " + i18n.tr("Unlock") + " 》");
1240− }
1241−
1242− function test_keepPasswordOnRotation() {
1243− /* Check if the password is kept when rotating
1244− * the screen from portrait to landscape in mobile.
1245− */
1246− setUsageMode("phone");
1247− LightDM.Greeter.authenticate("has-password");
1248− view.locked = true;
1249− swipeAwayCover();
1250−
1251− let greeterPrompt = findChild(view, "greeterPrompt0");
1252− tryCompare(greeterPrompt, "enteredText", "");
1253− typeString("test");
1254− tryCompare(greeterPrompt, "enteredText", "test");
1255− view.orientation = Qt.LandscapeOrientation;
1256− tryCompare(greeterPrompt, "enteredText", "test");
1257− }
1258−
1259− function test_infographicsShownOnRotation_data() {
1260− return [
1261− {
1262− tag: "phone-portrait-singleuser",
1263− multiUser: false,
1264− usageMode: "phone",
1265− orientation: Qt.PortraitOrientation,
1266− coverPage: true,
1267− lockscreen: false
1268− },
1269− {
1270− tag: "phone-portrait-multiuser",
1271− multiUser: true,
1272− usageMode: "phone",
1273− orientation: Qt.PortraitOrientation,
1274− coverPage: false,
1275− lockscreen: false
1276− },
1277− {
1278− tag: "phone-landscape-singleuser",
1279− multiUser: false,
1280− usageMode: "phone",
1281− orientation: Qt.LandscapeOrientation,
1282− coverPage: true,
1283− lockscreen: false
1284− },
1285− {
1286− tag: "phone-landscape-multiuser",
1287− multiUser: true,
1288− usageMode: "phone",
1289− orientation: Qt.LandscapeOrientation,
1290− coverPage: false,
1291− lockscreen: false
1292− },
1293− {
1294− tag: "tablet-landscape-singleuser",
1295− multiUser: false,
1296− usageMode: "tablet",
1297− orientation: Qt.LandscapeOrientation,
1298− coverPage: true,
1299− lockscreen: false
1300− },
1301− {
1302− tag: "tablet-landscape-multiuser",
1303− multiUser: true,
1304− usageMode: "tablet",
1305− orientation: Qt.LandscapeOrientation,
1306− coverPage: false,
1307− lockscreen: true
1308− },
1309− {
1310− tag: "tablet-portrait-singleuser",
1311− multiUser: false,
1312− usageMode: "tablet",
1313− orientation: Qt.PortraitOrientation,
1314− coverPage: true,
1315− lockscreen: false
1316− },
1317− {
1318− tag: "tablet-portrait-multiuser",
1319− multiUser: true,
1320− usageMode: "tablet",
1321− orientation: Qt.PortraitOrientation,
1322− coverPage: false,
1323− lockscreen: false
1324− },
1325− {
1326− tag: "desktop-singleuser",
1327− multiUser: false,
1328− usageMode: "desktop",
1329− orientation: Qt.LandscapeOrientation,
1330− coverPage: false,
1331− lockscreen: true
1332− },
1333− {
1334− tag: "desktop-multiuser",
1335− multiUser: true,
1336− usageMode: "desktop",
1337− orientation: Qt.LandscapeOrientation,
1338− coverPage: false,
1339− lockscreen: true
1340− }
1341− ]
1342− }
1343−
1344− function test_infographicsShownOnRotation(data) {
1345− /* Check if infographics is shown in the correct
1346− * places. This test runs in all the combinations
1347− * of orientation and usage mode.
1348− */
1349− setUsageMode(data.usageMode);
1350− view.orientation = data.orientation;
1351− view.multiUser = data.multiUser;
1352− view.locked = true;
1353−
1354− let coverPage = findChild(view, "coverPage");
1355− let lockscreen = findChild(view, "lockscreen");
1356− let coverPageInfographics = findChild(coverPage, "infographicsLoader");
1357− let lockscreenInfographics = findChild(lockscreen, "infographicsLoader");
1358− verify(coverPageInfographics);
1359− verify(lockscreenInfographics);
1360−
1361− tryCompare(coverPageInfographics, "active", data.coverPage);
1362− swipeAwayCover();
1363− tryCompare(lockscreenInfographics, "active", data.lockscreen);
1364− }
1365− }
1366−}
tests/qmltests/Greeter/tst_NarrowView.qmlnew file+565
@@ -0,0 +1,565 @@
1+/*
2+ * Copyright 2014 Canonical Ltd.
3+ * Copyright 2021 UBports Foundation
4+ *
5+ * This program is free software; you can redistribute it and/or modify
6+ * it under the terms of the GNU General Public License as published by
7+ * the Free Software Foundation; version 3.
8+ *
9+ * This program is distributed in the hope that it will be useful,
10+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+ * GNU General Public License for more details.
13+ *
14+ * You should have received a copy of the GNU General Public License
15+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
16+ */
17+
18+import QtQuick 2.4
19+import QtTest 1.0
20+import ".."
21+import "../../../qml/Greeter"
22+import LightDMController 0.1
23+import LightDM.FullLightDM 0.1 as LightDM
24+import Ubuntu.Components 1.3
25+import Ubuntu.Telephony 0.1 as Telephony
26+import Unity.Test 0.1 as UT
27+
28+Item {
29+ id: root
30+ width: units.gu(90)
31+ height: units.gu(80)
32+
33+ Component.onCompleted: theme.name = "Ubuntu.Components.Themes.SuruDark" // use the same theme as the real shell
34+
35+ Binding {
36+ target: LightDMController
37+ property: "userMode"
38+ value: "single"
39+ }
40+
41+ Row {
42+ anchors.fill: parent
43+ Loader {
44+ id: loader
45+ width: root.width - controls.width
46+ height: parent.height
47+
48+ property bool itemDestroyed: false
49+ sourceComponent: Component {
50+ NarrowView {
51+ background: "/usr/share/backgrounds/warty-final-ubuntu.png"
52+ userModel: LightDM.Users
53+ infographicModel: LightDM.Infographic
54+
55+ launcherOffset: parseFloat(launcherOffsetField.text)
56+ currentIndex: parseInt(currentIndexField.text, 10)
57+ delayMinutes: parseInt(delayMinutesField.text, 10)
58+ panelHeight: parseFloat(panelHeightField.text)
59+ locked: lockedCheckBox.checked
60+ alphanumeric: alphanumericCheckBox.checked
61+
62+ Component.onDestruction: {
63+ loader.itemDestroyed = true
64+ }
65+
66+ onSelected: {
67+ currentIndexField.text = index;
68+ }
69+ }
70+ }
71+ }
72+
73+ Rectangle {
74+ id: controls
75+ color: theme.palette.normal.background
76+ width: units.gu(40)
77+ height: parent.height
78+
79+ Column {
80+ anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) }
81+ spacing: units.gu(1)
82+
83+ Row {
84+ Button {
85+ text: "Hide"
86+ onClicked: loader.item.hide()
87+ }
88+ }
89+ Row {
90+ Button {
91+ text: "Show Message"
92+ onClicked: LightDMService.prompts.append(messageField.text, LightDMService.prompts.Message)
93+ }
94+ TextField {
95+ id: messageField
96+ width: units.gu(10)
97+ text: ""
98+ }
99+ }
100+ Row {
101+ Button {
102+ text: "Show Prompt"
103+ onClicked: LightDMService.prompts.append(promptField.text, isSecretCheckBox.checked ? LightDMService.prompts.Secret : LightDMService.prompts.Question)
104+ }
105+ TextField {
106+ id: promptField
107+ width: units.gu(10)
108+ text: ""
109+ }
110+ CheckBox {
111+ id: isSecretCheckBox
112+ }
113+ Label {
114+ text: "secret"
115+ }
116+ }
117+ Row {
118+ Button {
119+ text: "Notify Auth Failure"
120+ onClicked: {
121+ loader.item.notifyAuthenticationFailed();
122+ }
123+ }
124+ }
125+ Row {
126+ Button {
127+ text: "Try To Unlock"
128+ onClicked: loader.item.tryToUnlock(toTheRightCheckBox.checked)
129+ }
130+ CheckBox {
131+ id: toTheRightCheckBox
132+ }
133+ Label {
134+ text: "toTheRight"
135+ }
136+ }
137+ Row {
138+ TextField {
139+ id: launcherOffsetField
140+ width: units.gu(10)
141+ text: "0"
142+ }
143+ Label {
144+ text: "launcherOffset"
145+ }
146+ }
147+ Row {
148+ TextField {
149+ id: currentIndexField
150+ width: units.gu(10)
151+ text: "0"
152+ }
153+ Label {
154+ text: "currentIndex"
155+ }
156+ }
157+ Row {
158+ TextField {
159+ id: delayMinutesField
160+ width: units.gu(10)
161+ text: "0"
162+ }
163+ Label {
164+ text: "delayMinutes"
165+ }
166+ }
167+ Row {
168+ TextField {
169+ id: panelHeightField
170+ width: units.gu(10)
171+ text: "0"
172+ }
173+ Label {
174+ text: "panelHeight"
175+ }
176+ }
177+ Row {
178+ CheckBox {
179+ id: lockedCheckBox
180+ }
181+ Label {
182+ text: "locked"
183+ }
184+ }
185+ Row {
186+ CheckBox {
187+ id: alphanumericCheckBox
188+ checked: true
189+ }
190+ Label {
191+ text: "alphanumeric"
192+ }
193+ }
194+ Row {
195+ Label {
196+ text: "selected: " + selectedSpy.count
197+ }
198+ }
199+ Row {
200+ Label {
201+ text: "responded: " + respondedSpy.count
202+ }
203+ }
204+ Row {
205+ Label {
206+ text: "teased: " + teaseSpy.count
207+ }
208+ }
209+ Row {
210+ Label {
211+ text: "emergency: " + emergencySpy.count
212+ }
213+ }
214+ Row {
215+ Button {
216+ text: "Reload View"
217+ onClicked: {
218+ loader.active = false;
219+ loader.active = true;
220+ }
221+ }
222+ }
223+ }
224+ }
225+ }
226+
227+ Binding {
228+ target: LightDM.Infographic
229+ property: "username"
230+ value: "has-password"
231+ }
232+
233+ SignalSpy {
234+ id: selectedSpy
235+ target: loader.item
236+ signalName: "selected"
237+ }
238+
239+ SignalSpy {
240+ id: respondedSpy
241+ target: loader.item
242+ signalName: "responded"
243+ }
244+
245+ SignalSpy {
246+ id: teaseSpy
247+ target: loader.item
248+ signalName: "tease"
249+ }
250+
251+ SignalSpy {
252+ id: emergencySpy
253+ target: loader.item
254+ signalName: "emergencyCall"
255+ }
256+
257+ SignalSpy {
258+ id: infographicDataChangedSpy
259+ target: LightDM.Infographic
260+ signalName: "dataChanged"
261+ }
262+
263+ UT.UnityTestCase {
264+ name: "NarrowView"
265+ when: windowShown
266+
267+ property Item view: loader.status === Loader.Ready ? loader.item : null
268+
269+ function init() {
270+ view.currentIndex = 0; // break binding with text field
271+
272+ LightDM.Greeter.authenticate("no-password");
273+ tryCompare(LightDMService.prompts, "count", 1);
274+
275+ telepathyHelper.ready = true;
276+ telepathyHelper.emergencyCallsAvailable = true;
277+ selectedSpy.clear();
278+ respondedSpy.clear();
279+ teaseSpy.clear();
280+ emergencySpy.clear();
281+ infographicDataChangedSpy.clear();
282+ }
283+
284+ function cleanup() {
285+ loader.itemDestroyed = false;
286+ loader.active = false;
287+ tryCompare(loader, "status", Loader.Null);
288+ tryCompare(loader, "item", null);
289+ tryCompare(loader, "itemDestroyed", true);
290+ loader.active = true;
291+ tryCompare(loader, "status", Loader.Ready);
292+ removeTimeConstraintsFromSwipeAreas(loader.item);
293+ }
294+
295+ function swipeAwayCover(toTheRight) {
296+ if (toTheRight === undefined) {
297+ toTheRight = false;
298+ }
299+
300+ tryCompare(view, "fullyShown", true);
301+ var touchY = view.height / 2;
302+ if (toTheRight) {
303+ touchFlick(view, 0, touchY, view.width, touchY);
304+ } else {
305+ touchFlick(view, view.width, touchY, 0, touchY);
306+ }
307+ var coverPage = findChild(view, "coverPage");
308+ tryCompare(coverPage, "showProgress", 0);
309+ waitForRendering(view);
310+ }
311+
312+ function test_tease_data() {
313+ return [
314+ {tag: "left", x: 0, offset: 0, count: 1},
315+ {tag: "leftWithOffsetPass", x: 10, offset: 10, count: 1},
316+ {tag: "leftWithOffsetFail", x: 9, offset: 10, count: 0},
317+ {tag: "right", x: view.width, offset: 0, count: 1},
318+ ]
319+ }
320+ function test_tease(data) {
321+ view.dragHandleLeftMargin = data.offset;
322+ tap(view, data.x, 0);
323+ tryCompare(teaseSpy, "count", data.count);
324+ }
325+
326+ function test_customBackground() {
327+ var lockscreenShade = findChild(view, "lockscreenShade");
328+ var backgroundShade = findChild(view, "backgroundShade");
329+
330+ compare(lockscreenShade.opacity, 0);
331+ verify(!backgroundShade.visible);
332+
333+ view.hasCustomBackground = true;
334+ compare(lockscreenShade.opacity, 0.4);
335+ verify(backgroundShade.visible);
336+ }
337+
338+ function test_respondedWithPin() {
339+ LightDM.Greeter.authenticate("has-pin");
340+ view.locked = true;
341+ view.alphanumeric = false;
342+ swipeAwayCover();
343+ typeString("1234");
344+ respondedSpy.wait();
345+ compare(respondedSpy.signalArguments[0][0], "1234");
346+ }
347+
348+ function test_respondedWithPassphrase() {
349+ LightDM.Greeter.authenticate("has-password");
350+ view.locked = true;
351+ swipeAwayCover();
352+ typeString("test");
353+ keyClick(Qt.Key_Enter);
354+ compare(respondedSpy.count, 1);
355+ compare(respondedSpy.signalArguments[0][0], "test");
356+ }
357+
358+ function test_respondedWithSwipe_data() {
359+ return [
360+ {tag: "left", toTheRight: false, hiddenX: -view.width},
361+ {tag: "right", toTheRight: true, hiddenX: view.width},
362+ ];
363+ }
364+ function test_respondedWithSwipe(data) {
365+ swipeAwayCover(data.toTheRight);
366+ var coverPage = findChild(view, "coverPage");
367+ compare(coverPage.x, data.hiddenX);
368+ compare(respondedSpy.count, 1);
369+ compare(respondedSpy.signalArguments[0][0], "");
370+ }
371+
372+ function test_emergencyCall_data() {
373+ return [
374+ {tag: "phone", available: true},
375+ {tag: "desktop", available: false},
376+ ];
377+ }
378+ function test_emergencyCall(data) {
379+ telepathyHelper.emergencyCallsAvailable = data.available;
380+ view.locked = true;
381+ swipeAwayCover();
382+ var emergencyCallLabel = findChild(view, "emergencyCallLabel");
383+ tap(emergencyCallLabel);
384+ if (!data.available) {
385+ expectFail("", "Bug 1616538 prevents us supporting conditional emergency button support");
386+ }
387+ compare(emergencyCallLabel.visible, data.available ? true : false);
388+ compare(emergencySpy.count, data.available ? 1 : 0);
389+ }
390+
391+ function test_emergencyCallAvailability() {
392+ view.locked = true;
393+ var emergencyCallLabel = findChild(view, "emergencyCallLabel");
394+ verify(emergencyCallLabel.visible);
395+
396+ telepathyHelper.emergencyCallsAvailable = false;
397+ telepathyHelper.ready = true;
398+ expectFail("", "Bug 1616538 prevents us supporting conditional emergency button support");
399+ verify(!emergencyCallLabel.visible);
400+
401+ telepathyHelper.emergencyCallsAvailable = true;
402+ telepathyHelper.ready = false;
403+ verify(!emergencyCallLabel.visible);
404+ }
405+
406+ function test_fullyShown() {
407+ tryCompare(view, "fullyShown", true);
408+ swipeAwayCover();
409+ tryCompare(view, "fullyShown", false);
410+ view.locked = true;
411+ tryCompare(view, "fullyShown", true);
412+ view.locked = false;
413+ tryCompare(view, "fullyShown", false);
414+ }
415+
416+ function test_required() {
417+ tryCompare(view, "required", true);
418+ swipeAwayCover();
419+ tryCompare(view, "required", false);
420+ view.locked = true;
421+ tryCompare(view, "required", true);
422+ view.locked = false;
423+ tryCompare(view, "required", false);
424+ }
425+
426+ function test_tryToUnlock() {
427+ var coverPage = findChild(view, "coverPage");
428+ tryCompare(coverPage, "showProgress", 1);
429+ compare(view.tryToUnlock(false), true);
430+ tryCompare(coverPage, "showProgress", 0);
431+ compare(view.tryToUnlock(false), false);
432+ }
433+
434+ /*
435+ Regression test for https://bugs.launchpad.net/ubuntu/+source/unity8/+bug/1388359
436+ "User metrics can no longer be changed by double tap"
437+ */
438+ function test_doubleTapSwitchesToNextInfographic() {
439+ var infographicPrivate = findInvisibleChild(view, "infographicPrivate");
440+ verify(infographicPrivate);
441+
442+ // wait for the UI to settle down before double tapping it
443+ tryCompare(infographicPrivate, "animating", false);
444+
445+ var dataCircle = findChild(view, "dataCircle");
446+ verify(dataCircle);
447+
448+ mouseDoubleClickSequence(dataCircle);
449+
450+ tryCompare(infographicDataChangedSpy, "count", 1);
451+ }
452+
453+ function test_movesBackIntoPlaceWhenNotDraggedFarEnough() {
454+ var coverPage = findChild(view, "coverPage");
455+
456+ var dragEvaluator = findInvisibleChild(coverPage, "edgeDragEvaluator");
457+ verify(dragEvaluator);
458+
459+ // Make it easier to get a rejection/rollback. Otherwise would have to inject
460+ // a fake timer into dragEvaluator.
461+ // Afterall, we are testing if the CoverPage indeed moves back on a
462+ // rollback decision, not the drag evaluation itself.
463+ dragEvaluator.minDragDistance = dragEvaluator.maxDragDistance / 2;
464+
465+ // it starts as fully shown
466+ compare(coverPage.x, 0);
467+
468+ // then we drag it a bit
469+ var startX = coverPage.width - 1;
470+ var touchY = coverPage.height / 2;
471+ var dragXDelta = -(dragEvaluator.minDragDistance * 0.3);
472+ touchFlick(coverPage,
473+ startX , touchY, // start pos
474+ startX + dragXDelta, touchY, // end pos
475+ true /* beginTouch */, false /* endTouch */);
476+
477+ // which should make it move a bit
478+ tryCompareFunction(function() {return coverPage.x < 0;}, true);
479+
480+ // then we release it
481+ touchRelease(coverPage, startX + dragXDelta, touchY);
482+
483+ // which should make it move back into its original position as it didn't move
484+ // far enough to have it hidden
485+ tryCompare(coverPage, "x", 0);
486+ }
487+
488+ function test_dragToHide_data() {
489+ return [
490+ {tag: "left", startX: view.width * 0.95, endX: view.width * 0.1, hiddenX: -view.width},
491+ {tag: "right", startX: view.width * 0.1, endX: view.width * 0.95, hiddenX: view.width},
492+ ];
493+ }
494+ function test_dragToHide(data) {
495+ var coverPage = findChild(view, "coverPage");
496+ compare(coverPage.x, 0);
497+ compare(coverPage.visible, true);
498+ compare(coverPage.shown, true);
499+ compare(coverPage.showProgress, 1);
500+ compare(view.fullyShown, true);
501+
502+ touchFlick(view,
503+ data.startX, view.height / 2, // start pos
504+ data.endX, view.height / 2); // end pos
505+
506+ tryCompare(coverPage, "x", data.hiddenX);
507+ tryCompare(coverPage, "visible", false);
508+ tryCompare(coverPage, "shown", false);
509+ tryCompare(coverPage, "showProgress", 0);
510+ compare(view.fullyShown, false);
511+ }
512+
513+ function test_hiddenViewRemainsHiddenAfterResize_data() {
514+ return [
515+ {tag: "left", startX: view.width * 0.95, endX: view.width * 0.1},
516+ {tag: "right", startX: view.width * 0.1, endX: view.width * 0.95},
517+ ];
518+ }
519+ function test_hiddenViewRemainsHiddenAfterResize(data) {
520+ touchFlick(view,
521+ data.startX, view.height / 2, // start pos
522+ data.endX, view.height / 2); // end pos
523+
524+ var coverPage = findChild(view, "coverPage");
525+ tryCompare(coverPage, "x", data.tag == "left" ? -view.width : view.width);
526+ tryCompare(coverPage, "visible", false);
527+ tryCompare(coverPage, "shown", false);
528+ tryCompare(coverPage, "showProgress", 0);
529+
530+ // flip dimensions to simulate an orientation change
531+ view.width = loader.height;
532+ view.height = loader.width;
533+
534+ // All properties should remain consistent
535+ tryCompare(coverPage, "x", data.tag == "left" ? -view.width : view.width);
536+ tryCompare(coverPage, "visible", false);
537+ tryCompare(coverPage, "shown", false);
538+ tryCompare(coverPage, "showProgress", 0);
539+ }
540+
541+ // Make sure that if user has a mouse, they can still get rid of cover page
542+ function test_mouseClickHidesCoverPage() {
543+ var coverPage = findChild(view, "coverPage");
544+
545+ verify(coverPage.shown);
546+ mouseClick(coverPage, coverPage.width/2, coverPage.height - units.gu(2));
547+ verify(!coverPage.shown);
548+ }
549+
550+ function test_showErrorMessage() {
551+ var coverPage = findChild(view, "coverPage");
552+ var swipeHint = findChild(coverPage, "swipeHint");
553+ var errorMessageAnimation = findInvisibleChild(coverPage, "errorMessageAnimation");
554+
555+ view.showErrorMessage("hello");
556+ compare(swipeHint.text, "《 hello 》");
557+ verify(errorMessageAnimation.running);
558+ verify(swipeHint.opacityAnimation.running);
559+
560+ errorMessageAnimation.complete();
561+ swipeHint.opacityAnimation.complete();
562+ tryCompare(swipeHint, "text", "《 " + i18n.tr("Unlock") + " 》");
563+ }
564+ }
565+}
tests/qmltests/Greeter/tst_WideView.qmlnew file+801
@@ -0,0 +1,801 @@
1+/*
2+ * Copyright 2014-2016 Canonical Ltd.
3+ * Copyright 2021 UBports Foundation
4+ *
5+ * This program is free software; you can redistribute it and/or modify
6+ * it under the terms of the GNU General Public License as published by
7+ * the Free Software Foundation; version 3.
8+ *
9+ * This program is distributed in the hope that it will be useful,
10+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+ * GNU General Public License for more details.
13+ *
14+ * You should have received a copy of the GNU General Public License
15+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
16+ */
17+
18+import QtQuick 2.4
19+import QtTest 1.0
20+import ".."
21+import "../../../qml/Greeter"
22+import LightDMController 0.1
23+import LightDM.FullLightDM 0.1 as LightDM
24+import Ubuntu.Components 1.3
25+import Unity.Test 0.1 as UT
26+
27+StyledItem {
28+ id: root
29+
30+ width: units.gu(120)
31+ height: units.gu(80)
32+ focus: true
33+
34+ theme.name: "Ubuntu.Components.Themes.Ambiance"
35+
36+ Row {
37+ anchors.fill: parent
38+ Loader {
39+ id: loader
40+ width: root.width - controls.width
41+ height: parent.height
42+ focus: true
43+
44+ property bool itemDestroyed: false
45+ sourceComponent: Component {
46+ WideView {
47+ id: view
48+
49+ background: "/usr/share/backgrounds/warty-final-ubuntu.png"
50+ userModel: LightDM.Users
51+ infographicModel: LightDM.Infographic
52+
53+ launcherOffset: parseFloat(launcherOffsetField.text)
54+ currentIndex: parseInt(currentIndexField.text, 10)
55+ delayMinutes: parseInt(delayMinutesField.text, 10)
56+ panelHeight: parseFloat(panelHeightField.text)
57+ locked: lockedCheckBox.checked
58+ inputMethodRect: fakeKeyboard.childrenRect
59+ property var testKeyboard: fakeKeyboard
60+
61+ Component.onDestruction: {
62+ loader.itemDestroyed = true
63+ }
64+
65+ onSelected: {
66+ if (index >= 0)
67+ currentIndexField.text = index;
68+ }
69+
70+ Rectangle {
71+ id: fakeKeyboard
72+ color: "green"
73+ opacity: 0.7
74+ anchors.bottom: view.bottom
75+ width: view.width
76+ height: visible ? view.height * 0.6 : 0
77+ visible: keyboardVisibleCheckBox.checked
78+ Text {
79+ text: "Keyboard Rectangle"
80+ color: "yellow"
81+ font.bold: true
82+ fontSizeMode: Text.Fit
83+ minimumPixelSize: 10; font.pixelSize: 200
84+ verticalAlignment: Text.AlignVCenter
85+ x: (parent.width - width) / 2
86+ y: (parent.height - height) / 2
87+ width: parent.width
88+ height: parent.height
89+ }
90+ }
91+
92+ }
93+ }
94+ }
95+
96+ Rectangle {
97+ id: controls
98+ color: theme.palette.normal.background
99+ width: units.gu(40)
100+ height: parent.height
101+ Column {
102+ anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) }
103+ spacing: units.gu(1)
104+ Row {
105+ Button {
106+ text: "Hide"
107+ onClicked: loader.item.hide()
108+ }
109+ }
110+ Row {
111+ Button {
112+ text: "Show Message"
113+ onClicked: LightDMService.prompts.append(messageField.text, LightDMService.prompts.Message)
114+ }
115+ TextField {
116+ id: messageField
117+ width: units.gu(10)
118+ text: ""
119+ }
120+ }
121+ Row {
122+ Button {
123+ text: "Show Prompt"
124+ onClicked: LightDMService.prompts.append(promptField.text, isSecretCheckBox.checked ? LightDMService.prompts.Secret : LightDMService.prompts.Question)
125+ }
126+ TextField {
127+ id: promptField
128+ width: units.gu(10)
129+ text: ""
130+ }
131+ CheckBox {
132+ id: isSecretCheckBox
133+ }
134+ Label {
135+ text: "secret"
136+ }
137+ }
138+ Row {
139+ Button {
140+ text: "Notify Auth Failure"
141+ onClicked: {
142+ loader.item.notifyAuthenticationFailed();
143+ }
144+ }
145+ }
146+ Row {
147+ Button {
148+ text: "Try To Unlock"
149+ onClicked: loader.item.tryToUnlock(toTheRightCheckBox.checked)
150+ }
151+ CheckBox {
152+ id: toTheRightCheckBox
153+ }
154+ Label {
155+ text: "toTheRight"
156+ }
157+ }
158+ Row {
159+ TextField {
160+ id: launcherOffsetField
161+ width: units.gu(10)
162+ text: "0"
163+ }
164+ Label {
165+ text: "launcherOffset"
166+ }
167+ }
168+ Row {
169+ TextField {
170+ id: currentIndexField
171+ width: units.gu(10)
172+ text: "0"
173+ }
174+ Label {
175+ text: "currentIndex"
176+ }
177+ }
178+ Row {
179+ TextField {
180+ id: delayMinutesField
181+ width: units.gu(10)
182+ text: "0"
183+ }
184+ Label {
185+ text: "delayMinutes"
186+ }
187+ }
188+ Row {
189+ TextField {
190+ id: panelHeightField
191+ width: units.gu(10)
192+ text: "0"
193+ }
194+ Label {
195+ text: "panelHeight"
196+ }
197+ }
198+ Row {
199+ CheckBox {
200+ id: lockedCheckBox
201+ }
202+ Label {
203+ text: "locked"
204+ }
205+ }
206+ Row {
207+ Label {
208+ text: "selected: " + selectedSpy.count
209+ }
210+ }
211+ Row {
212+ Label {
213+ text: "responded: " + respondedSpy.count
214+ }
215+ }
216+ Row {
217+ Label {
218+ text: "teased: " + teaseSpy.count
219+ }
220+ }
221+ Row {
222+ Label {
223+ text: "emergency: " + emergencySpy.count
224+ }
225+ }
226+ Row {
227+ id: multipleSessions
228+ CheckBox {
229+ id: multipleSessionsCheckbox
230+ onClicked: {
231+ if (checked) {
232+ LightDMController.sessionMode = "full";
233+ } else {
234+ LightDMController.sessionMode = "single";
235+ }
236+ }
237+ Connections {
238+ target: LightDMController
239+ onSessionModeChanged: {
240+ if (LightDMController.sessionMode === "full") {
241+ multipleSessionsCheckbox.checked = true;
242+ } else {
243+ multipleSessionsCheckbox.checked = false;
244+ }
245+ }
246+ }
247+ }
248+ Label {
249+ text: "Multiple Sessions"
250+ }
251+ }
252+ Row {
253+ Slider {
254+ id: numSessionsSlider
255+
256+ width: units.gu(10)
257+ minimumValue: 0
258+ maximumValue: LightDMController.numAvailableSessions
259+ value: LightDMController.numSessions
260+ visible: LightDMController.sessionMode === "full"
261+ Binding {
262+ target: LightDMController
263+ property: "numSessions"
264+ value: numSessionsSlider.value
265+ }
266+ }
267+ Label {
268+ text: "Available Sessions"
269+ }
270+ }
271+ Row {
272+ Button {
273+ text: "Reload View"
274+ onClicked: {
275+ loader.active = false;
276+ loader.active = true;
277+ }
278+ }
279+ }
280+ Row {
281+ CheckBox {
282+ id: keyboardVisibleCheckBox
283+ }
284+ Label {
285+ text: "Keyboard Visible"
286+ }
287+ }
288+ }
289+ }
290+ }
291+
292+ SignalSpy {
293+ id: selectedSpy
294+ target: loader.item
295+ signalName: "selected"
296+ }
297+
298+ SignalSpy {
299+ id: respondedSpy
300+ target: loader.item
301+ signalName: "responded"
302+ }
303+
304+ SignalSpy {
305+ id: teaseSpy
306+ target: loader.item
307+ signalName: "tease"
308+ }
309+
310+ SignalSpy {
311+ id: emergencySpy
312+ target: loader.item
313+ signalName: "emergencyCall"
314+ }
315+
316+ UT.UnityTestCase {
317+ name: "WideView"
318+ when: windowShown
319+
320+ property Item view: loader.status === Loader.Ready ? loader.item : null
321+ property url testIconDirectory: Qt.resolvedUrl("../../../qml/Greeter/graphics/session_icons")
322+
323+ function init() {
324+ selectIndex(0); // break binding with text field
325+ tryCompare(LightDMService.prompts, "count", 1);
326+ selectedSpy.clear();
327+ respondedSpy.clear();
328+ teaseSpy.clear();
329+ emergencySpy.clear();
330+ LightDMController.reset();
331+ LightDM.Sessions.iconSearchDirectories = [testIconDirectory];
332+
333+ waitForRendering(view);
334+ var userList = findChild(view, "userList");
335+ tryCompare(userList, "movingInternally", false);
336+ }
337+
338+ function cleanup() {
339+ keyboardVisibleCheckBox.checked = false;
340+
341+ loader.itemDestroyed = false;
342+ loader.active = false;
343+ tryCompare(loader, "status", Loader.Null);
344+ tryCompare(loader, "item", null);
345+ tryCompare(loader, "itemDestroyed", true);
346+ loader.active = true;
347+ tryCompare(loader, "status", Loader.Ready);
348+ removeTimeConstraintsFromSwipeAreas(loader.item);
349+ LightDMController.sessionMode = "single";
350+ }
351+
352+ function getIndexOf(name) {
353+ for (var i = 0; i < LightDM.Users.count; i++) {
354+ if (name === LightDM.Users.data(i, LightDM.UserRoles.NameRole)) {
355+ return i;
356+ }
357+ }
358+ fail("Didn't find name")
359+ return -1;
360+ }
361+
362+ function selectIndex(i) {
363+ var user = LightDM.Users.data(i, LightDM.UserRoles.NameRole);
364+ LightDM.Greeter.authenticate(user);
365+
366+ var userList = findChild(view, "userList");
367+ var promptList = findChild(view, "promptList");
368+
369+ view.currentIndex = i;
370+ tryCompare(promptList, "opacity", 1);
371+ tryCompare(userList, "movingInternally", false);
372+ }
373+
374+ function selectUser(name) {
375+ var i = getIndexOf(name);
376+ selectIndex(i);
377+ return i;
378+ }
379+
380+ function swipeAwayCover() {
381+ tryCompare(view, "fullyShown", true);
382+ var touchY = view.height / 2;
383+ touchFlick(view, view.width, touchY, 0, touchY);
384+ var coverPage = findChild(view, "coverPage");
385+ tryCompare(coverPage, "showProgress", 0);
386+ waitForRendering(view);
387+ }
388+
389+ function test_sessionless_user_is_still_valid() {
390+ var loginList = findChild(view, "loginList")
391+
392+ /*
393+ * If a user has never logged in before, or, for some reason
394+ * has no sessionHint, ensure that the model returns the default
395+ * session and that the view respects this
396+ */
397+ selectUser("no-session");
398+ compare(LightDM.Users.data(loginList.currentIndex, LightDM.UserRoles.SessionRole), LightDM.Greeter.defaultSession);
399+
400+ tryCompare(loginList, "currentSession", LightDM.Greeter.defaultSession);
401+ }
402+
403+ function test_changingSessionSticksToUser() {
404+ var loginList = findChild(view, "loginList");
405+
406+ selectUser("invalid-session");
407+ tryCompare(loginList, "currentSession", "invalid");
408+
409+ selectUser("has-password");
410+ tryCompare(loginList, "currentSession", "ubuntu");
411+
412+ selectUser("invalid-session")
413+ tryCompare(loginList, "currentSession", "invalid");
414+ }
415+
416+ function test_tease_data() {
417+ return [
418+ {tag: "locked", x: 0, offset: 0, count: 0, locked: true},
419+ {tag: "left", x: 0, offset: 0, count: 1, locked: false},
420+ {tag: "leftWithOffsetPass", x: 10, offset: 10, count: 1, locked: false},
421+ {tag: "leftWithOffsetFail", x: 9, offset: 10, count: 0, locked: false},
422+ {tag: "right", x: view.width, offset: 0, count: 1, locked: false},
423+ ]
424+ }
425+
426+ function test_sessionIconsAreValid() {
427+ LightDMController.sessionMode = "full";
428+ selectUser("has-password");
429+
430+ // Test the login list icon is valid
431+ var sessionChooserButton = findChild(view, "sessionChooserButton");
432+ compare(sessionChooserButton.visible, true);
433+
434+ var loginList = findChild(view, "loginList");
435+ var session = String(loginList.currentSession).toLowerCase();
436+ var icon = String(sessionChooserButton.icon);
437+ compare(icon.indexOf(session) > -1, true);
438+
439+ // Test the session list icons are valid
440+ var coverPage = findChild(view, "coverPage");
441+ coverPage.state = "SessionsList"
442+ var sessionsList = findChild(view, "sessionsList");
443+ tryCompare(sessionsList, "visible", true);
444+ }
445+
446+ function test_choosingNewSessionChangesLoginListIcon() {
447+ // Ensure the default session is selected (Ubuntu)
448+ cleanup();
449+
450+ LightDMController.sessionMode = "full";
451+ selectUser("has-password");
452+
453+ var sessionChooserButton = findChild(view, "sessionChooserButton");
454+ var icon = String(sessionChooserButton.icon);
455+ compare(icon.indexOf("ubuntu") > -1, true);
456+
457+ tap(sessionChooserButton)
458+ for(var i = 0; i < LightDM.Sessions.count; i++) {
459+ var delegateName = "sessionDelegate" + String(i);
460+ var currentDelegate = findChild(view, delegateName);
461+ var sessionKey = LightDM.Sessions.data(i,LightDM.SessionRoles.KeyRole);
462+ if (sessionKey === "gnome-classic") {
463+ waitForRendering(currentDelegate);
464+ tap(currentDelegate);
465+ waitForRendering(sessionChooserButton);
466+ break;
467+ }
468+ }
469+
470+ icon = String(sessionChooserButton.icon);
471+ compare(icon.indexOf("gnome") > -1, true,
472+ "Expected icon to contain gnome but it was " + icon);
473+ }
474+
475+ function test_noSessionsDoesntBreakView() {
476+ LightDMController.sessionMode = "none";
477+ compare(LightDM.Sessions.count, 0)
478+ }
479+
480+ function test_sessionIconNotShownWithOneSession() {
481+ LightDMController.sessionMode = "single";
482+ compare(LightDM.Sessions.count, 1);
483+
484+ var sessionChooserButton = findChild(view, "sessionChooserButton");
485+ tryCompare(sessionChooserButton, "visible", false);
486+ }
487+
488+ function test_sessionIconNotShownWithActiveUser() {
489+ selectUser("active");
490+
491+ var sessionChooserButton = findChild(view, "sessionChooserButton");
492+ tryCompare(sessionChooserButton, "visible", false);
493+ }
494+
495+ function test_sessionIconShownWithMultipleSessions() {
496+ LightDMController.sessionMode = "full";
497+ selectUser("has-password");
498+
499+ var sessionChooserButton = findChild(view, "sessionChooserButton");
500+ tryCompare(sessionChooserButton, "visible", true);
501+ }
502+
503+ function test_tease(data) {
504+ view.locked = data.locked;
505+ view.dragHandleLeftMargin = data.offset;
506+ tap(view, data.x, 0);
507+ compare(teaseSpy.count, data.count);
508+ }
509+
510+ function test_selected() {
511+ var delegate = findChild(view, "username2");
512+ tap(delegate);
513+ compare(selectedSpy.count, 1);
514+ compare(selectedSpy.signalArguments[0][0], 2);
515+ compare(view.currentIndex, 0); // confirm we didn't change
516+ }
517+
518+ function test_customBackground() {
519+ var coverPage = findChild(view, "coverPage");
520+ var backgroundShade = findChild(coverPage, "backgroundShade");
521+
522+ verify(!view.hasCustomBackground);
523+ verify(!backgroundShade.visible);
524+
525+ view.hasCustomBackground = true;
526+ verify(backgroundShade.visible);
527+ }
528+
529+ function test_respondedWithPassword() {
530+ selectUser("has-password");
531+ var greeterPrompt = findChild(view, "greeterPrompt0");
532+ verify(greeterPrompt.isSecret);
533+ typeString("password");
534+ keyClick(Qt.Key_Enter);
535+ compare(respondedSpy.count, 1);
536+ compare(respondedSpy.signalArguments[0][0], "password");
537+ }
538+
539+ function test_respondedWithNonSecret() {
540+ selectUser("question-prompt");
541+ var greeterPrompt = findChild(view, "greeterPrompt0");
542+ verify(!greeterPrompt.isSecret);
543+ typeString("foo");
544+ keyClick(Qt.Key_Enter);
545+ compare(respondedSpy.count, 1);
546+ compare(respondedSpy.signalArguments[0][0], "foo");
547+ }
548+
549+ function test_respondedWithSwipe() {
550+ swipeAwayCover();
551+ compare(respondedSpy.count, 1);
552+ compare(respondedSpy.signalArguments[0][0], "");
553+ }
554+
555+ function test_fullyShown() {
556+ tryCompare(view, "fullyShown", true);
557+ swipeAwayCover();
558+ tryCompare(view, "fullyShown", false);
559+ }
560+
561+ function test_required() {
562+ tryCompare(view, "required", true);
563+ swipeAwayCover();
564+ tryCompare(view, "required", false);
565+ }
566+
567+ function test_infoPrompt() {
568+ selectUser("info-prompt");
569+
570+ var infoLabel = findChild(view, "infoLabel0");
571+ compare(infoLabel.text, "Welcome to Unity Greeter");
572+ compare(infoLabel.textFormat, Text.PlainText);
573+
574+ verify(findChild(view, "greeterPrompt1") != null);
575+ }
576+
577+ function test_longInfoPrompt() {
578+ selectUser("long-info-prompt");
579+
580+ var infoLabel = findChild(view, "infoLabel0");
581+ compare(infoLabel.text, "Welcome to Unity Greeter\n\nWe like to annoy you with super ridiculously long messages.\nLike this one\n\nThis is the last line of a multiple line message.");
582+ verify(infoLabel.contentWidth > infoLabel.width);
583+
584+ verify(findChild(view, "greeterPrompt1") != null);
585+ }
586+
587+ function test_multiInfoPrompt() {
588+ selectUser("multi-info-prompt");
589+
590+ var infoLabel0 = findChild(view, "infoLabel0");
591+ compare(infoLabel0.text, "Welcome to Unity Greeter");
592+
593+ var infoLabel1 = findChild(view, "infoLabel1");
594+ compare(infoLabel1.text, "This is an error");
595+ compare(infoLabel1.color, theme.palette.normal.negative);
596+
597+ var infoLabel2 = findChild(view, "infoLabel2");
598+ compare(infoLabel2.text, "You should have seen three messages");
599+
600+ verify(findChild(view, "greeterPrompt3") != null);
601+ }
602+
603+ // Escape is used to reset the authentication, especially if PAM is unresponsive
604+ function test_escape() {
605+ var index = selectUser("has-password");
606+ selectedSpy.clear();
607+ view.locked = true;
608+ var promptField = findChild(view, "promptField");
609+ tap(promptField);
610+ verify(promptField.activeFocus);
611+ compare(promptField.opacity, 1);
612+
613+ typeString("password");
614+ keyClick(Qt.Key_Enter);
615+ verify(promptField.activeFocus);
616+ compare(promptField.opacity, 0); // hidden by fakeLabel
617+
618+ compare(selectedSpy.count, 0);
619+ keyClick(Qt.Key_Escape);
620+ compare(selectedSpy.count, 1);
621+ compare(selectedSpy.signalArguments[0][0], index);
622+
623+ selectIndex(index);
624+ var promptField = findChild(view, "promptField");
625+ verify(promptField.activeFocus);
626+ compare(promptField.opacity, 1);
627+ }
628+
629+ function test_unicode() {
630+ var index = selectUser("unicode");
631+ var label = findChild(view, "username" + index);
632+ tryCompare(label, "text", "가나다라마");
633+ }
634+
635+ function test_authError() {
636+ var index = selectUser("auth-error");
637+ var greeterPrompt = findChild(view, "greeterPrompt1"); // after error message
638+ view.locked = true;
639+ compare(greeterPrompt.text, "Retry");
640+ tap(greeterPrompt);
641+ compare(respondedSpy.count, 0);
642+ compare(selectedSpy.count, 1);
643+ compare(selectedSpy.signalArguments[0][0], index);
644+ }
645+
646+ function test_noPassword() {
647+ selectUser("no-password");
648+ var greeterPrompt = findChild(view, "greeterPrompt0");
649+ compare(greeterPrompt.text, "Log In");
650+ tap(greeterPrompt);
651+ compare(selectedSpy.count, 0);
652+ compare(respondedSpy.count, 1);
653+ compare(respondedSpy.signalArguments[0][0], "");
654+ }
655+
656+ function test_loginListNotCoveredByKeyboard() {
657+ var loginList = findChild(view, "loginList");
658+ compare(loginList.height, view.height);
659+
660+ // when the vkb shows up, loginList is moved up to remain fully uncovered
661+
662+ keyboardVisibleCheckBox.checked = true;
663+
664+ var halfway = (view.height - loginList.highlightedHeight) / 2;
665+ var halfwayWithOsk = halfway - view.inputMethodRect.height / 2;
666+ tryCompare(loginList, "boxVerticalOffset", halfwayWithOsk);
667+
668+ var highlightItem = findChild(loginList, "highlightItem");
669+ tryCompareFunction( function() {
670+ var highlightRect = highlightItem.mapToItem(view, 0, 0, highlightItem.width, highlightItem.height);
671+ return highlightRect.y + highlightRect.height <= view.testKeyboard.y;
672+ }, true);
673+
674+ // once the vkb goes away, loginList goes back to its full height
675+
676+ keyboardVisibleCheckBox.checked = false;
677+
678+ tryCompare(loginList, "boxVerticalOffset", halfway);
679+ }
680+
681+ function test_passphrase() {
682+ var index = selectUser("has-password");
683+ var promptField = findChild(view, "promptField");
684+
685+ verify(view.alphanumeric);
686+ compare(promptField.inputMethodHints & Qt.ImhDigitsOnly, 0);
687+
688+ keyClick(Qt.Key_D);
689+ compare(promptField.text, "d");
690+ }
691+
692+ function test_passcode() {
693+ var index = selectUser("has-pin");
694+ view.alphanumeric = false;
695+
696+ var promptField = findChild(view, "promptField");
697+ compare(promptField.inputMethodHints & Qt.ImhDigitsOnly, Qt.ImhDigitsOnly);
698+
699+ keyClick(Qt.Key_D);
700+ compare(promptField.text, "");
701+
702+ keyClick(Qt.Key_0);
703+ keyClick(Qt.Key_0);
704+ keyClick(Qt.Key_0);
705+ keyClick(Qt.Key_0);
706+ compare(promptField.text, "0000");
707+
708+ compare(respondedSpy.count, 1);
709+ compare(respondedSpy.signalArguments[0][0], "0000");
710+
711+ compare(promptField.opacity, 0);
712+ }
713+
714+ function test_loginListMovement_data() {
715+ return [
716+ {tag: "up", key: Qt.Key_Up, result: 1},
717+ {tag: "down", key: Qt.Key_Down, result: 3},
718+ ]
719+ }
720+
721+ function test_loginListMovement(data) {
722+ selectIndex(2);
723+ selectedSpy.clear();
724+
725+ keyClick(data.key);
726+ compare(selectedSpy.count, 1);
727+ compare(selectedSpy.signalArguments[0][0], data.result);
728+ }
729+
730+ function test_focusStaysActive() {
731+ selectUser("no-password");
732+ var greeterPrompt = findChild(view, "greeterPrompt0");
733+ verify(greeterPrompt.activeFocus);
734+ keyClick(Qt.Key_Enter);
735+ compare(selectedSpy.count, 0);
736+ compare(respondedSpy.count, 1);
737+ compare(respondedSpy.signalArguments[0][0], "");
738+ verify(greeterPrompt.activeFocus);
739+ keyClick(Qt.Key_Enter);
740+ compare(respondedSpy.count, 1);
741+
742+ selectUser("has-password");
743+ var greeterPrompt = findChild(view, "greeterPrompt0");
744+ verify(greeterPrompt.activeFocus);
745+ keyClick(Qt.Key_D);
746+ keyClick(Qt.Key_Enter);
747+ compare(selectedSpy.count, 0);
748+ compare(respondedSpy.count, 2);
749+ compare(respondedSpy.signalArguments[1][0], "d");
750+ verify(greeterPrompt.activeFocus);
751+ keyClick(Qt.Key_Enter);
752+ compare(respondedSpy.count, 2);
753+
754+ var index = selectUser("no-password");
755+ var greeterPrompt = findChild(view, "greeterPrompt0");
756+ view.locked = true;
757+ verify(greeterPrompt.activeFocus);
758+ keyClick(Qt.Key_Enter);
759+ compare(respondedSpy.count, 2);
760+ compare(selectedSpy.count, 1);
761+ compare(selectedSpy.signalArguments[0][0], index);
762+ verify(greeterPrompt.activeFocus);
763+ keyClick(Qt.Key_Enter);
764+ compare(selectedSpy.count, 1);
765+
766+ selectUser("no-password");
767+ var greeterPrompt = findChild(view, "greeterPrompt0");
768+ verify(greeterPrompt.activeFocus);
769+ }
770+
771+ function test_scrollChangesIndex() {
772+ /* Check if the index of the current user gets changed
773+ * if we scroll through the list.
774+ * Expected result: the list has moved at least by one
775+ * user and the index of the user is reported using the
776+ * selected signal in LoginList.qml
777+ * https://github.com/ubports/unity8/issues/397
778+ */
779+ var loginList = findChild(view, "loginList");
780+ // FIXME: Fix scrolling sensitivity (scrolling by -1 shouldn't move more than one user down)
781+ mouseWheel( loginList, loginList.width / 2, loginList.height / 2, 0, -1, null );
782+ selectedSpy.wait();
783+ tryVerify(function(){ return selectedSpy.signalArguments[0][0] > 0 });
784+ }
785+
786+ function test_dragChangesIndex() {
787+ /* Check if the index of the current user gets changed
788+ * if we drag the list or swipe.on it.
789+ * Expected result: the list has moved at least by one
790+ * user and the index of the user is reported using the
791+ * selected signal in LoginList.qml
792+ * https://github.com/ubports/unity8/issues/397
793+ */
794+ var loginList = findChild(view, "loginList");
795+ // FIXME: Fix scrolling sensitivity (the number of scrolled users is randomly changing)
796+ touchFlick(loginList, loginList.width/2, loginList.height/3, loginList.width/2, loginList.height/3 -units.gu(2.1));
797+ selectedSpy.wait();
798+ tryVerify(function(){ return selectedSpy.signalArguments[0][0] > 0 });
799+ }
800+ }
801+}
tests/qmltests/tst_OrientedShell.qml+38−1
@@ -619,6 +619,43 @@ Rectangle {
619619 compare(shell.transformRotationAngle, root.primaryOrientationAngle + 180);
620620 }
621621
622+ function test_greeterRemainsInPrimaryOrientation_data() {
623+ return [
624+ {tag: "mako", deviceName: "mako"},
625+ {tag: "manta", deviceName: "manta"},
626+ {tag: "flo", deviceName: "flo"}
627+ ];
628+ }
629+ function test_greeterRemainsInPrimaryOrientation(data) {
630+ var orientedShell = loadShell(data.deviceName);
631+ var shell = findChild(orientedShell, "shell");
632+
633+ var gmailApp = ApplicationManager.startApplication("gmail-webapp");
634+ verify(gmailApp);
635+
636+ // ensure the mock gmail-webapp is as we expect
637+ compare(gmailApp.rotatesWindowContents, false);
638+ compare(gmailApp.supportedOrientations, Qt.PortraitOrientation | Qt.LandscapeOrientation
639+ | Qt.InvertedPortraitOrientation | Qt.InvertedLandscapeOrientation);
640+
641+ // wait until it's able to rotate
642+ tryCompare(shell, "orientationChangesEnabled", true);
643+
644+ compare(shell.transformRotationAngle, root.primaryOrientationAngle);
645+ rotateTo(90, orientedShell);
646+ tryCompare(shell, "transformRotationAngle", root.primaryOrientationAngle + 90);
647+
648+ showGreeter(orientedShell);
649+
650+ tryCompare(shell, "transformRotationAngle", root.primaryOrientationAngle);
651+ rotateTo(180, orientedShell);
652+ compare(shell.transformRotationAngle, root.primaryOrientationAngle);
653+ rotateTo(270, orientedShell);
654+ compare(shell.transformRotationAngle, root.primaryOrientationAngle);
655+ rotateTo(0, orientedShell);
656+ compare(shell.transformRotationAngle, root.primaryOrientationAngle);
657+ }
658+
622659 function test_appRotatesWindowContents_data() {
623660 return [
624661 {tag: "mako", deviceName: "mako", orientationAngleAfterRotation: 90},
@@ -1210,7 +1247,7 @@ Rectangle {
12101247
12111248 showGreeter(orientedShell);
12121249
1213− tryCompare(shell, "transformRotationAngle", root.primaryOrientationAngle + 90);
1250+ tryCompare(shell, "transformRotationAngle", root.primaryOrientationAngle);
12141251 }
12151252
12161253 /*
tests/qmltests/tst_Shell.qml+8−38
@@ -703,32 +703,6 @@ Rectangle {
703703 mockNotificationsModel.append(n)
704704 }
705705
706− function swipeAwayGreeterCover() {
707− var greeter = findChild(shell, "greeter");
708−
709− if (!greeter.shown) {
710− console.log("Greeter not shown. Not swiping.");
711− return;
712− }
713−
714− var greeterView = findChild(greeter, "GreeterView");
715− var lockscreen = findChild(greeter, "lockscreen");
716−
717− tryCompare(lockscreen, "shown", true);
718−
719− tryCompare(greeter, "fullyShown", true);
720− waitForGreeterToStabilize();
721− removeTimeConstraintsFromSwipeAreas(greeter);
722−
723− var touchX = shell.width - (shell.edgeSize / 2);
724− var touchY = shell.height / 2;
725− touchFlick(shell, touchX, touchY, shell.width * 0.1, touchY);
726−
727− var coverPage = findChild(greeterView, "coverPage");
728− tryCompare(coverPage, "showProgress", 0);
729− waitForRendering(greeterView);
730− }
731−
732706 function swipeAwayGreeter() {
733707 var greeter = findChild(shell, "greeter");
734708
@@ -1022,13 +996,14 @@ Rectangle {
1022996 }
1023997
1024998 function test_greeterStartsCorrectSession() {
1025− setLightDMMockMode("full");
1026999 loadShell("desktop");
1000+ setLightDMMockMode("full");
10271001
10281002 LightDMController.sessionMode = "full"
10291003 LightDMController.numSessions = LightDMController.numAvailableSessions;
10301004 var greeter = findChild(shell, "greeter");
1031− var view = findChild(greeter, "GreeterView");
1005+ var view = findChild(greeter, "WideView");
1006+ verify(view, "This test requires WideView to be loaded");
10321007
10331008 var loginList = findChild(view, "loginList");
10341009
@@ -1428,9 +1403,8 @@ Rectangle {
14281403 }
14291404
14301405 function test_tabletLogin(data) {
1431− setLightDMMockMode("full");
14321406 loadShell("tablet");
1433− swipeAwayGreeterCover();
1407+ setLightDMMockMode("full");
14341408
14351409 selectUser(data.user);
14361410
@@ -1453,10 +1427,8 @@ Rectangle {
14531427 }
14541428
14551429 function test_appLaunchDuringGreeter(data) {
1456− setLightDMMockMode("full");
14571430 loadShell("tablet");
1458−
1459− swipeAwayGreeterCover();
1431+ setLightDMMockMode("full");
14601432
14611433 selectUser(data.user)
14621434
@@ -1472,11 +1444,9 @@ Rectangle {
14721444 }
14731445
14741446 function test_manualLoginFlow() {
1475− setLightDMMockMode("full");
1476− LightDMController.showManualLoginHint = true;
14771447 loadShell("desktop");
1478−
1479− swipeAwayGreeterCover();
1448+ LightDMController.showManualLoginHint = true;
1449+ setLightDMMockMode("full");
14801450
14811451 var i = selectUser("*other");
14821452 var greeter = findChild(shell, "greeter");
@@ -2613,8 +2583,8 @@ Rectangle {
26132583
26142584 function test_fullShellModeHasNoInitialGreeter() {
26152585 shellRect.mode = "full-shell";
2616− setLightDMMockMode("single-pin");
26172586 loadShell("phone");
2587+ setLightDMMockMode("single-pin");
26182588 waitForRendering(shell);
26192589
26202590 var greeter = findChild(shell, "greeter");