on xenial help sign in
41 files changed+2462−2388
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+9−11 po/hu.po+9−11 po/it.po+6−6 po/km.po+11−14 po/nb.po+2−4 po/pt.po+4−4 po/sc.po+6−6 po/sv.po+25−52 po/th.po+20−20 po/ur.po+31−28 qml/Greeter/CoverPage.qml+26−36 qml/Greeter/Greeter.qml+21−2 qml/Greeter/GreeterPrompt.qml+3−3 qml/Greeter/GreeterView.qml+534 qml/Greeter/LoginList.qml+4−2 qml/Greeter/NarrowView.qml−277 qml/Greeter/PinPrompt.qml+1−1 qml/Greeter/PromptList.qml+16−19 qml/Greeter/WideView.qml−281 qml/Launcher/BackgroundBlur.qml+81 qml/Launcher/Drawer.qml+8−2 qml/Launcher/Launcher.qml+23−1 qml/OrientedShell.qml+1 qml/Panel/Indicators/IndicatorItem.qml+6 qml/Rotation/RotationStates.qml−3 qml/Shell.qml+7−2 src/ApplicationArguments.h+5 src/ShellApplication.cpp+6 tests/qmltests/CMakeLists.txt+1−2 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+1−38 tests/qmltests/tst_Shell.qml+38−8
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.json](clickable.json). For example:
25+Now you can use the full suite of tools provided by this repository's [clickable.yaml](clickable.yaml). 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 --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...
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...
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.jsondeleted−158
@@ -1,158 +0,0 @@
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.yamlnew file+153
@@ -0,0 +1,153 @@
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-03 05:18+0000\n"
11+"PO-Revision-Date: 2021-10-12 07:49+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-08-21 07:57+0000\n"
11+"PO-Revision-Date: 2021-12-05 18:44+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 sekundy"
485−msgstr[2] "%1 sekund"
484+msgstr[1] "%1 sekund"
485+msgstr[2] ""
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-03-31 05:24+0000\n"
12−"Last-Translator: Josué <j2g2rp@gmail.com>\n"
11+"PO-Revision-Date: 2021-10-04 12:20+0000\n"
12+"Last-Translator: Adolfo Jayme Barrientos <fitojb@ubuntu.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, por favor, inténtelo de nuevo"
37+msgstr "Contraseña incorrecta; inténtelo de nuevo"
3838
3939#: plugins/LightDM/Greeter.cpp:270
4040msgid "Log In"
41−msgstr "Iniciar sesión"
41+msgstr "Acceder"
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 "Iniciar sesión"
49+msgstr "Acceder"
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 la sesión"
71+msgstr "Cerrar 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 la sesión"
85+msgstr "Cerrar 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 siguiente disposición de teclado."
167+msgstr "Cambia a la disposición de teclado siguiente."
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 anterior disposición de teclado."
175+msgstr "Cambia a la disposición de teclado anterior."
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 "Lanzador"
187+msgstr "Iniciador"
188188
189189#: qml/Components/KeyboardShortcutsOverlay.qml:138
190190msgid "Super (Hold)"
191−msgstr "Super (Mantener)"
191+msgstr "Súper (mantener)"
192192
193193#: qml/Components/KeyboardShortcutsOverlay.qml:143
194194msgid "Opens the launcher, displays shortcuts."
195−msgstr "Abre el lanzador y muestra los atajos."
195+msgstr "Abre el iniciador 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 Lanzador en modo de navegación de teclado."
203+msgstr "Abre el iniciador 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 "Recorre las aplicaciones del Lanzador."
211+msgstr "Cambia de aplicación mediante el iniciador."
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 hacer clic en un icono del Lanzador."
219+msgstr "Lo mismo que pulsar en un icono del iniciador."
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 "Semi-maximiza la ventana actual."
291+msgstr "Semimaximiza 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 mas ajustes en la configuración del sistema."
376+msgstr "Encuentre más ajustes en 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 "Deslizar un poco desde el borde izquierdo para abrir el lanzador"
552+msgstr "Deslice un poco desde el borde izquierdo para abrir el iniciador"
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 empuja el ratón contra el borde derecho"
557+"Para ver las aplicaciones abiertas empuje 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 "Deslizar desde el borde derecho para ver las aplis abiertas"
561+msgstr "Deslice desde el borde derecho para ver las aplicaciones abiertas"
562562
563563#: qml/Tutorial/TutorialTop.qml:53
564564msgid "Swipe from the top edge to access notifications and quick settings"
565565msgstr ""
566−"Deslizar desde el borde superior para acceder a las notificaciones y "
566+"Deslice 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 "Siguiente"
586+msgstr "Sig."
587587
588588#: qml/Wizard/Pages/10-welcome-update.qml:91
589589msgid "Welcome to "
po/he.po+9−11
@@ -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: 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/"
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/"
1414"he/>\n"
1515"Language: he\n"
1616"MIME-Version: 1.0\n"
@@ -129,10 +129,8 @@ msgid "Restart"
129129msgstr "הפעלה מחדש"
130130
131131#: qml/Components/Dialogs.qml:276
132−#, fuzzy
133−#| msgid "Takes a screenshot."
134132msgid "Screenshot"
135−msgstr "מצלם מסך."
133+msgstr "צילום מסך"
136134
137135#: qml/Components/KeyboardShortcutsOverlay.qml:41
138136msgid "Keyboard Shortcuts"
@@ -140,7 +138,7 @@ msgstr "קיצורי דרך במקלדת"
140138
141139#: qml/Components/KeyboardShortcutsOverlay.qml:55
142140msgid "Lomiri"
143−msgstr ""
141+msgstr "Lomiri"
144142
145143#: qml/Components/KeyboardShortcutsOverlay.qml:62
146144msgid "PrtScr"
@@ -458,13 +456,13 @@ msgstr "שום דבר לא מתנגן"
458456msgid "%1 hour"
459457msgid_plural "%1 hours"
460458msgstr[0] "%1 שעה"
461−msgstr[1] "%1 שעות"
459+msgstr[1] "%1 שעת"
462460
463461#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:1001
464462#, qt-format
465463msgid "%1 minute"
466464msgid_plural "%1 minutes"
467−msgstr[0] "דקה %1"
465+msgstr[0] "%1 דקה"
468466msgstr[1] "%1 דקות"
469467
470468#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:1006
@@ -526,7 +524,7 @@ msgstr "התקשר חזרה"
526524
527525#: qml/Panel/PanelMenuPage.qml:92
528526msgid "Back"
529−msgstr "חזור"
527+msgstr "חזרה"
530528
531529#: qml/Stage/SideStage.qml:76
532530msgid "Drag using 3 fingers any application from one window to the other"
@@ -559,7 +557,7 @@ msgstr "החלק מהקצה העליון כדי לגשת להתראות ולהג
559557#: qml/Wizard/Page.qml:59
560558msgctxt "Button: Go back one page in the Wizard"
561559msgid "Back"
562−msgstr "חזור"
560+msgstr "חזרה"
563561
564562#: qml/Wizard/Pages/10-welcome.qml:29
565563msgid "Language"
po/hu.po+9−11
@@ -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-03-17 10:43+0000\n"
12−"Last-Translator: David Farkas <dvdfrks@gmail.com>\n"
11+"PO-Revision-Date: 2022-02-06 00:18+0000\n"
12+"Last-Translator: Lundrin <berenyi.vilmos@tutanota.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égsem"
91+msgstr "Mégse"
9292
9393#: qml/Components/Dialogs.qml:211
9494msgctxt "Title: Reboot dialog"
@@ -131,10 +131,8 @@ msgid "Restart"
131131msgstr "Újraindítás"
132132
133133#: qml/Components/Dialogs.qml:276
134−#, fuzzy
135−#| msgid "Takes a screenshot."
136134msgid "Screenshot"
137−msgstr "Képernyőkép készítése."
135+msgstr "Képernyőmentés"
138136
139137#: qml/Components/KeyboardShortcutsOverlay.qml:41
140138msgid "Keyboard Shortcuts"
@@ -142,7 +140,7 @@ msgstr "Gyorsbillentyűk"
142140
143141#: qml/Components/KeyboardShortcutsOverlay.qml:55
144142msgid "Lomiri"
145−msgstr ""
143+msgstr "Lomiri"
146144
147145#: qml/Components/KeyboardShortcutsOverlay.qml:62
148146msgid "PrtScr"
@@ -506,7 +504,7 @@ msgstr "Megszakítva"
506504
507505#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:1027
508506msgid "Finished"
509−msgstr "Befejeződött"
507+msgstr "Kész"
510508
511509#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:1029
512510msgid "Failed, tap to retry"
@@ -578,7 +576,7 @@ msgstr "Nyelv"
578576#: qml/Wizard/Pages/passcode-desktop.qml:154
579577#: qml/Wizard/Pages/password-set.qml:153
580578msgid "Next"
581−msgstr "Következő"
579+msgstr "Köv."
582580
583581#: qml/Wizard/Pages/10-welcome-update.qml:91
584582msgid "Welcome to "
@@ -620,7 +618,7 @@ msgstr "Csatlakozás Wi-Fi hálózathoz"
620618
621619#: qml/Wizard/Pages/30-wifi.qml:139
622620msgid "Connected"
623−msgstr "Kapcsolódva"
621+msgstr "Csatlakozva"
624622
625623#: qml/Wizard/Pages/30-wifi.qml:172
626624msgid "Available Wi-Fi networks"
@@ -741,7 +739,7 @@ msgstr "Adjon meg egy 4 számjegyű jelkódot"
741739#: qml/Wizard/Pages/passcode-desktop.qml:84
742740#: qml/Wizard/Pages/passcode-set.qml:54
743741msgid "Choose passcode"
744−msgstr "Jelkód megadása"
742+msgstr "Válasszon jelkódot"
745743
746744#: qml/Wizard/Pages/passcode-desktop.qml:139
747745msgid "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: 2021-07-18 22:26+0000\n"
12−"Last-Translator: Mike <miguel2000@livecom.it>\n"
11+"PO-Revision-Date: 2022-01-22 21:58+0000\n"
12+"Last-Translator: Matteo <mattbel10@hotmail.com>\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 passphrase per sbloccare"
412+msgstr "Inserire parola chiave 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 "Passphrase"
424+msgstr "Parola chiave"
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 "Nessun applicazione in esecuzione"
543+msgstr "Nessuna 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 Drawer delle "
548+"Scorrere lentamente dal bordo sinistro per aprire il Cassetto delle "
549549"Applicazioni"
550550
551551#: qml/Tutorial/TutorialLeft.qml:47
po/km.po+11−14
@@ -8,16 +8,17 @@ 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: 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"
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"
1516"MIME-Version: 1.0\n"
1617"Content-Type: text/plain; charset=UTF-8\n"
1718"Content-Transfer-Encoding: 8bit\n"
1819"Plural-Forms: nplurals=1; plural=0;\n"
20+"X-Generator: Weblate 3.11.3\n"
1921"X-Launchpad-Export-Date: 2016-11-23 06:35+0000\n"
20−"X-Generator: Launchpad (build 18269)\n"
2122
2223#: plugins/LightDM/Greeter.cpp:199
2324msgid "Password: "
@@ -25,7 +26,7 @@ msgstr "ពាក្យសម្ងាត់៖ "
2526
2627#: plugins/LightDM/Greeter.cpp:214
2728msgid "Username"
28−msgstr ""
29+msgstr "អត្ថនាម"
2930
3031#: plugins/LightDM/Greeter.cpp:258
3132msgid "Failed to authenticate"
@@ -375,7 +376,7 @@ msgstr ""
375376
376377#: qml/Greeter/CoverPage.qml:127
377378msgid "Unlock"
378−msgstr "ដោះ​សោ"
379+msgstr "ដោះសោ"
379380
380381#: qml/Greeter/DelayedLockscreen.qml:43
381382msgid "Device Locked"
@@ -523,11 +524,8 @@ msgid "Call back"
523524msgstr "ហៅ​មកវិញ"
524525
525526#: qml/Panel/PanelMenuPage.qml:92
526−#, fuzzy
527−#| msgctxt "Button: Go back one page in the Wizard"
528−#| msgid "Back"
529527msgid "Back"
530−msgstr "ថយក្រោយ"
528+msgstr "បកក្រោយ"
531529
532530#: qml/Stage/SideStage.qml:76
533531msgid "Drag using 3 fingers any application from one window to the other"
@@ -592,9 +590,8 @@ msgid "What's new"
592590msgstr ""
593591
594592#: qml/Wizard/Pages/11-changelog.qml:74
595−#, fuzzy
596593msgid "Loading..."
597−msgstr "កំពុង​និយាយ..."
594+msgstr "កំពុងផ្ទុក…"
598595
599596#: qml/Wizard/Pages/20-keyboard.qml:31
600597msgid "Select Keyboard"
@@ -606,7 +603,7 @@ msgstr ""
606603
607604#: qml/Wizard/Pages/20-keyboard.qml:93
608605msgid "Keyboard layout"
609−msgstr ""
606+msgstr "ប្លង់ក្ដារចុច"
610607
611608#: qml/Wizard/Pages/20-keyboard.qml:152 qml/Wizard/Pages/30-wifi.qml:214
612609#: qml/Wizard/Pages/60-account.qml:72 qml/Wizard/Pages/79-system-update.qml:144
po/nb.po+2−4
@@ -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-07-22 23:44+0000\n"
11+"PO-Revision-Date: 2021-10-15 10:11+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,10 +131,8 @@ msgid "Restart"
131131msgstr "Start på nytt"
132132
133133#: qml/Components/Dialogs.qml:276
134−#, fuzzy
135−#| msgid "Takes a screenshot."
136134msgid "Screenshot"
137−msgstr "Tar bilde av skjermen."
135+msgstr "Skjermavbildning"
138136
139137#: qml/Components/KeyboardShortcutsOverlay.qml:41
140138msgid "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-06-01 14:51+0000\n"
12−"Last-Translator: Ivo Xavier <ivofernandes12@gmail.com>\n"
11+"PO-Revision-Date: 2021-11-19 22:39+0000\n"
12+"Last-Translator: Hugo Carvalho <hugokarvalho@hotmail.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 "Retroceder"
534+msgstr "Voltar"
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 "Avançar"
715+msgstr "Continuar"
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-04-22 10:44+0000\n"
11+"PO-Revision-Date: 2021-11-21 15:09+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 "Peruna aplicatzione ativa"
542+msgstr "Nissuna 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 "Peruna rete Wi-Fi a disponimentu"
637+msgstr "Nissuna 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 "Perunu còdighe de blocu"
672+msgstr "Nissunu 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 "B'at a pònnere carchi minutu..."
699+msgstr "Podet trigare calicunu 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 "Peruna SIM installada"
786+msgstr "Nissuna SIM installada"
787787
788788#: qml/Wizard/Pages/sim.qml:54
789789msgid "SIM card added"
po/sv.po+25−52
@@ -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-07-26 20:33+0000\n"
12−"Last-Translator: Rondy Andersson <rondarius@vivaldi.net>\n"
11+"PO-Revision-Date: 2021-10-19 20:55+0000\n"
12+"Last-Translator: Jakob Fridesjö <jakob.fridesjo@tuta.io>\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 ""
29+msgstr "Användarnamn"
3030
3131#: plugins/LightDM/Greeter.cpp:258
3232msgid "Failed to authenticate"
33−msgstr ""
33+msgstr "Misslyckades att autentisera"
3434
3535#: plugins/LightDM/Greeter.cpp:260
3636msgid "Invalid password, please try again"
37−msgstr ""
37+msgstr "Felaktigt lösenord, vänligen försök igen"
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 ""
49+msgstr "Inloggning"
5050
5151#: plugins/LightDM/UsersModel.cpp:165
5252msgid "Guest Session"
53−msgstr ""
53+msgstr "Gästsession"
5454
5555#: plugins/Unity/Launcher/launcheritem.cpp:48
5656#: plugins/Unity/Launcher/launcheritem.cpp:122
@@ -131,10 +131,8 @@ msgid "Restart"
131131msgstr "Starta om"
132132
133133#: qml/Components/Dialogs.qml:276
134−#, fuzzy
135−#| msgid "Takes a screenshot."
136134msgid "Screenshot"
137−msgstr "Tar en skärmbild."
135+msgstr "Skärmdump"
138136
139137#: qml/Components/KeyboardShortcutsOverlay.qml:41
140138msgid "Keyboard Shortcuts"
@@ -142,7 +140,7 @@ msgstr "Tangentbordsgenvägar"
142140
143141#: qml/Components/KeyboardShortcutsOverlay.qml:55
144142msgid "Lomiri"
145−msgstr ""
143+msgstr "Lomiri"
146144
147145#: qml/Components/KeyboardShortcutsOverlay.qml:62
148146msgid "PrtScr"
@@ -157,10 +155,8 @@ msgid "Alt + PrtScr"
157155msgstr "Alt + PrtScr"
158156
159157#: qml/Components/KeyboardShortcutsOverlay.qml:80
160−#, fuzzy
161−#| msgid "Takes a screenshot of a window."
162158msgid "Takes a screenshot of the current window."
163−msgstr "Tar en skärmbild av ett fönster."
159+msgstr "Tar en skärmdump av det nuvarande fönstret."
164160
165161#: qml/Components/KeyboardShortcutsOverlay.qml:88
166162msgid "Super + Space"
@@ -179,16 +175,12 @@ msgid "Switches to previous keyboard layout."
179175msgstr "Byter till tidigare tangentbordslayout."
180176
181177#: qml/Components/KeyboardShortcutsOverlay.qml:114
182−#, fuzzy
183−#| msgid "Ctrl + Super + D"
184178msgid "Ctrl + Alt + T"
185−msgstr "Ctrl + Super + D"
179+msgstr "Ctrl + Alt + T"
186180
187181#: qml/Components/KeyboardShortcutsOverlay.qml:119
188−#, fuzzy
189−#| msgid "Switches between applications."
190182msgid "Starts the Terminal application."
191−msgstr "Växlar mellan program."
183+msgstr "Startar terminalen."
192184
193185#: qml/Components/KeyboardShortcutsOverlay.qml:131
194186msgid "Launcher"
@@ -219,26 +211,20 @@ msgid "Switches applications via the launcher."
219211msgstr "Byter program via Programstartaren."
220212
221213#: qml/Components/KeyboardShortcutsOverlay.qml:177
222−#, fuzzy
223−#| msgid "Super + 0 to 9"
224214msgid "Super + 1 to 0"
225−msgstr "Super + 0 till 9"
215+msgstr "Super + 1 till 0"
226216
227217#: qml/Components/KeyboardShortcutsOverlay.qml:182
228218msgid "Same as clicking on a launcher icon."
229219msgstr "Samma som att klicka på en ikon i Programstartaren."
230220
231221#: qml/Components/KeyboardShortcutsOverlay.qml:190
232−#, fuzzy
233−#| msgid "Super + W"
234222msgid "Super + A"
235−msgstr "Super + W"
223+msgstr "Super + A"
236224
237225#: qml/Components/KeyboardShortcutsOverlay.qml:195
238−#, fuzzy
239−#| msgid "Open the launcher"
240226msgid "Opens the Application Drawer."
241−msgstr "Öppna programstartaren"
227+msgstr "Öppnar programstartaren."
242228
243229#: qml/Components/KeyboardShortcutsOverlay.qml:235
244230msgid "Switching"
@@ -374,22 +360,20 @@ msgstr ""
374360"styrplatta för att interagera med pekaren."
375361
376362#: qml/Components/VirtualTouchPad.qml:327
377−#, fuzzy
378−#| msgid "Tap to return to call..."
379363msgid "Tap left button to click."
380−msgstr "Tryck för att återgå till samtal…"
364+msgstr "Tryck på vänster knapp för att klicka."
381365
382366#: qml/Components/VirtualTouchPad.qml:339
383367msgid "Tap right button to right click."
384−msgstr ""
368+msgstr "Tryck på höger knapp för att högerklicka."
385369
386370#: qml/Components/VirtualTouchPad.qml:351
387371msgid "Swipe with two fingers to scroll."
388−msgstr ""
372+msgstr "Svep med två fingrar för att scrolla."
389373
390374#: qml/Components/VirtualTouchPad.qml:396
391375msgid "Find more settings in the system settings."
392−msgstr ""
376+msgstr "Hitta fler inställningar i systeminställningarna."
393377
394378#: qml/Greeter/CoverPage.qml:127
395379msgid "Unlock"
@@ -419,16 +403,12 @@ msgid "Try again"
419403msgstr "Försök igen"
420404
421405#: qml/Greeter/Greeter.qml:551
422−#, fuzzy
423−#| msgid "Enter passphrase"
424406msgid "Enter passphrase to unlock"
425−msgstr "Ange lösenfras"
407+msgstr "Ange lösefras för att låsa upp"
426408
427409#: qml/Greeter/Greeter.qml:552
428−#, fuzzy
429−#| msgid "Enter passcode"
430410msgid "Enter passcode to unlock"
431−msgstr "Ange lösenkod"
411+msgstr "Ange lösenkod för att låsa upp"
432412
433413#: qml/Greeter/NarrowView.qml:235
434414msgid "Emergency"
@@ -447,10 +427,8 @@ msgid "Select desktop environment"
447427msgstr "Välj skrivbordsmiljö"
448428
449429#: qml/Launcher/Drawer.qml:250
450−#, fuzzy
451−#| msgid "Search"
452430msgid "Search…"
453−msgstr "Sök"
431+msgstr "Sök…"
454432
455433#: qml/Launcher/PullToRefreshScopeStyle.qml:56
456434msgid "Pull to refresh…"
@@ -557,13 +535,11 @@ msgstr "Dra ett program från ett fönster till det andra med tre fingrar"
557535
558536#: qml/Stage/Stage.qml:671
559537msgid "No running apps"
560−msgstr ""
538+msgstr "Inga appar körs"
561539
562540#: qml/Tutorial/TutorialLeftLong.qml:49
563−#, fuzzy
564−#| msgid "Long swipe from the left edge to open the Today scope"
565541msgid "Long swipe from the left edge to open the Application Drawer"
566−msgstr "Gör ett lång svep från vänstra kanten för öppna vyn Idag"
542+msgstr "Gör ett långt svep från vänstra kanten för öppna applikationsstartaren"
567543
568544#: qml/Tutorial/TutorialLeft.qml:47
569545msgid "Short swipe from the left edge to open the launcher"
@@ -699,12 +675,9 @@ msgstr ""
699675"kommer enheten att startas om automatiskt."
700676
701677#: qml/Wizard/Pages/79-system-update.qml:76
702−#, fuzzy
703−#| msgctxt "string identifying name of the update"
704−#| msgid "Ubuntu system"
705678msgctxt "string identifying name of the update"
706679msgid "Ubuntu Touch system"
707−msgstr "Ubuntusystem"
680+msgstr "Ubuntu Touch system"
708681
709682#: qml/Wizard/Pages/79-system-update.qml:83
710683#, 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-05-23 05:10+0000\n"
11+"PO-Revision-Date: 2021-10-14 16:02+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 ""
141+msgstr "Lomiri"
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+31−28
@@ -8,99 +8,100 @@ 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: 2015-05-05 03:12+0000\n"
12−"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13−"Language-Team: Urdu <ur@li.org>\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"
1415"Language: ur\n"
1516"MIME-Version: 1.0\n"
1617"Content-Type: text/plain; charset=UTF-8\n"
1718"Content-Transfer-Encoding: 8bit\n"
1819"Plural-Forms: nplurals=2; plural=n != 1;\n"
20+"X-Generator: Weblate 3.11.3\n"
1921"X-Launchpad-Export-Date: 2016-11-23 06:36+0000\n"
20−"X-Generator: Launchpad (build 18269)\n"
2122
2223#: plugins/LightDM/Greeter.cpp:199
2324msgid "Password: "
24−msgstr ""
25+msgstr "پاسورڈ "
2526
2627#: plugins/LightDM/Greeter.cpp:214
2728msgid "Username"
28−msgstr ""
29+msgstr "یوزر نیم"
2930
3031#: plugins/LightDM/Greeter.cpp:258
3132msgid "Failed to authenticate"
32−msgstr ""
33+msgstr "تصدیق میں ناکامی"
3334
3435#: plugins/LightDM/Greeter.cpp:260
3536msgid "Invalid password, please try again"
36−msgstr ""
37+msgstr "پاسورڈ غلط ھے، دوبارا کوشش کریں"
3738
3839#: plugins/LightDM/Greeter.cpp:270
3940msgid "Log In"
40−msgstr ""
41+msgstr "لاگ ان کریں"
4142
4243#: plugins/LightDM/Greeter.cpp:270
4344msgid "Retry"
44−msgstr ""
45+msgstr "دوبارا کوشش کریں"
4546
4647#: plugins/LightDM/UsersModel.cpp:157
4748msgid "Login"
48−msgstr ""
49+msgstr "لاگ ان کریں"
4950
5051#: plugins/LightDM/UsersModel.cpp:165
5152msgid "Guest Session"
52−msgstr ""
53+msgstr "مہمان سیشن"
5354
5455#: plugins/Unity/Launcher/launcheritem.cpp:48
5556#: plugins/Unity/Launcher/launcheritem.cpp:122
5657msgid "Pin shortcut"
57−msgstr ""
58+msgstr "شورت کٹ پن کیجیے"
5859
5960#: plugins/Unity/Launcher/launcheritem.cpp:54
6061msgid "Quit"
61−msgstr ""
62+msgstr "چھوڑیں"
6263
6364#: plugins/Unity/Launcher/launcheritem.cpp:122
6465msgid "Unpin shortcut"
65−msgstr ""
66+msgstr "شورت کٹ انپن کیجیے"
6667
6768#: qml/Components/Dialogs.qml:176
6869msgctxt "Title: Lock/Log out dialog"
6970msgid "Log out"
70−msgstr ""
71+msgstr "لاگ آؤٹ کیجیے"
7172
7273#: qml/Components/Dialogs.qml:177
7374msgid "Are you sure you want to log out?"
74−msgstr ""
75+msgstr "کیا آپ لاگ آؤٹ کرنا چاہتے ہیں؟"
7576
7677#: qml/Components/Dialogs.qml:180
7778msgctxt "Button: Lock the system"
7879msgid "Lock"
79−msgstr ""
80+msgstr "بند"
8081
8182#: qml/Components/Dialogs.qml:191
8283msgctxt "Button: Log out from the system"
8384msgid "Log Out"
84−msgstr ""
85+msgstr "لاگ آؤٹ"
8586
8687#: qml/Components/Dialogs.qml:199 qml/Components/Dialogs.qml:284
8788#: qml/Greeter/NarrowView.qml:215 qml/Wizard/Pages/passcode-confirm.qml:32
8889#: qml/Wizard/Pages/passcode-set.qml:32
8990msgid "Cancel"
90−msgstr ""
91+msgstr "نہیں"
9192
9293#: qml/Components/Dialogs.qml:211
9394msgctxt "Title: Reboot dialog"
9495msgid "Reboot"
95−msgstr ""
96+msgstr "ریبوٹ"
9697
9798#: qml/Components/Dialogs.qml:212
9899msgid "Are you sure you want to reboot?"
99−msgstr ""
100+msgstr "کیا آپ ریبوٹ کرنا چاہتے ہیں؟"
100101
101102#: qml/Components/Dialogs.qml:215
102103msgid "No"
103−msgstr ""
104+msgstr "نہیں"
104105
105106#: qml/Components/Dialogs.qml:223
106107msgid "Yes"
@@ -116,20 +117,22 @@ msgid ""
116117"Are you sure you would like\n"
117118"to power off?"
118119msgstr ""
120+"کیا آپ موبائل کو\n"
121+" بند کرنا چاہتے ہیں؟"
119122
120123#: qml/Components/Dialogs.qml:248
121124msgctxt "Button: Power off the system"
122125msgid "Power off"
123−msgstr ""
126+msgstr "بند"
124127
125128#: qml/Components/Dialogs.qml:263
126129msgctxt "Button: Restart the system"
127130msgid "Restart"
128−msgstr ""
131+msgstr "ریسارٹ"
129132
130133#: qml/Components/Dialogs.qml:276
131134msgid "Screenshot"
132−msgstr ""
135+msgstr "سکرین کی تصویر"
133136
134137#: qml/Components/KeyboardShortcutsOverlay.qml:41
135138msgid "Keyboard Shortcuts"
@@ -521,7 +524,7 @@ msgstr ""
521524
522525#: qml/Panel/PanelMenuPage.qml:92
523526msgid "Back"
524−msgstr ""
527+msgstr "پیچھے"
525528
526529#: qml/Stage/SideStage.qml:76
527530msgid "Drag using 3 fingers any application from one window to the other"
@@ -777,7 +780,7 @@ msgstr ""
777780
778781#: qml/Wizard/Pages/sim.qml:59
779782msgid "Restart"
780−msgstr ""
783+msgstr "دوباره شروع"
781784
782785#: qml/Wizard/Pages/sim.qml:78
783786msgid "You won’t be able to make calls or use text messaging without a SIM."
qml/Greeter/CoverPage.qml+26−36
@@ -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
3233 property real panelHeight
3334 property var infographicModel
3435 property bool draggable: true
3536
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
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
4242
4343 readonly property real showProgress: MathUtils.clamp((width - Math.abs(x + launcherOffset)) / width, 0, 1)
4444
@@ -99,47 +99,23 @@ 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−
125102 // Darkens wallpaper so that we can read text on it and see infographic
126103 Rectangle {
127104 id: backgroundShade
128105 objectName: "backgroundShade"
129106 anchors.fill: parent
130107 color: "black"
131− opacity: 0.4
132108 visible: false
133109 }
134110
135− Infographics {
136− id: infographics
137− objectName: "infographics"
138− model: root.infographicModel
139− clip: true // clip large data bubbles
111+ Item {
112+ id: infographicsArea
140113
141114 anchors {
142− topMargin: root.panelHeight
115+ leftMargin: root.infographicsLeftMargin
116+ topMargin: root.infographicsTopMargin ? root.infographicsTopMargin : root.panelHeight
117+ rightMargin: root.infographicsRightMargin
118+ bottomMargin: root.infographicsBottomMargin
143119 top: parent.top
144120 bottom: parent.bottom
145121 left: parent.left
@@ -147,6 +123,20 @@ Showable {
147123 }
148124 }
149125
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+
150140 Label {
151141 id: swipeHint
152142 objectName: "swipeHint"
qml/Greeter/Greeter.qml+21−2
@@ -58,6 +58,7 @@ Showable {
5858 readonly property bool locked: LightDMService.greeter.active && !LightDMService.greeter.authenticated && !forcedUnlock
5959
6060 property bool tabletMode
61+ property string usageMode
6162 property url viewSource // only used for testing
6263
6364 property int failedLoginsDelayAttempts: 7 // number of failed logins
@@ -69,6 +70,7 @@ Showable {
6970 property rect inputMethodRect
7071
7172 property bool hasKeyboard: false
73+ property int orientation
7274
7375 signal tease()
7476 signal sessionStarted()
@@ -356,8 +358,7 @@ Showable {
356358 anchors.fill: parent
357359
358360 active: root.required
359− source: root.viewSource.toString() ? root.viewSource :
360− (d.multiUser || root.tabletMode) ? "WideView.qml" : "NarrowView.qml"
361+ source: root.viewSource.toString() ? root.viewSource : "GreeterView.qml"
361362
362363 onLoaded: {
363364 root.lockedApp = "";
@@ -476,6 +477,24 @@ Showable {
476477 property: "hasKeyboard"
477478 value: root.hasKeyboard
478479 }
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+ }
479498 }
480499
481500 Connections {
qml/Greeter/GreeterPrompt.qml+3−3
@@ -25,7 +25,7 @@ FocusScope {
2525 focus: true
2626
2727 property bool isPrompt
28− property bool isAlphanumeric
28+ property bool isPinPrompt
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.isPrompt && !root.isAlphanumeric && root.isSecret
118+ when: root.isPinPrompt
119119 PropertyChanges { target: loader; source: "PinPrompt.qml" }
120120 },
121121 State {
122122 name: "TextPrompt"
123− when: root.isPrompt
123+ when: !root.isPinPrompt
124124 PropertyChanges { target: loader; source: "TextPrompt.qml" }
125125 }
126126 ]
qml/Greeter/GreeterView.qmlnew file+534
@@ -0,0 +1,534 @@
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+4−2
@@ -122,6 +122,8 @@ StyledItem {
122122 moveTimer.start();
123123 }
124124
125+ onCountChanged: if (root.currentIndex >= count) root.selected(0)
126+
125127 delegate: Item {
126128 width: userList.width
127129 height: root.cellHeight
@@ -130,7 +132,7 @@ StyledItem {
130132 readonly property bool aboveCurrent: (userList.currentIndex > 0 && index < 0) || (userList.currentIndex >= 0 && index < userList.currentIndex)
131133 readonly property int belowOffset: root.highlightedHeight - root.cellHeight
132134 readonly property string userSession: session
133− readonly property string username: name
135+ readonly property string username: name ? name : ""
134136
135137 opacity: {
136138 // The goal here is to make names less and less opaque as they
@@ -191,7 +193,7 @@ StyledItem {
191193 text: userList.currentIndex === index
192194 && name === "*other"
193195 && LightDMService.greeter.authenticationUser !== ""
194− ? LightDMService.greeter.authenticationUser : realName
196+ ? LightDMService.greeter.authenticationUser : realName ? realName : ""
195197 color: userList.currentIndex !== index ? theme.palette.normal.raised
196198 : theme.palette.normal.raisedSecondaryText
197199 font.weight: userList.currentIndex === index ? Font.Normal : Font.Light
qml/Greeter/NarrowView.qmldeleted−277
@@ -1,277 +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−
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− FadingLabel {
169+ Label {
170170 id: fakeLabel
171171 anchors.verticalCenter: extraIcons ? extraIcons.verticalCenter : undefined
172172 anchors.left: extraIcons ? extraIcons.left : undefined
qml/Greeter/PromptList.qml+16−19
@@ -67,10 +67,14 @@ FocusScope {
6767
6868 readonly property bool isLabel: model.type == LightDMService.prompts.Message ||
6969 model.type == LightDMService.prompts.Error
70− readonly property var modelData: model
70+ readonly property var modelText: model.text
71+ readonly property var modelType: model.type
72+ readonly property var modelIndex: model.index
7173
7274 sourceComponent: isLabel ? infoLabel : greeterPrompt
7375
76+ active: root.visible
77+
7478 onLoaded: {
7579 for (var i = 0; i < repeater.count; i++) {
7680 var item = repeater.itemAt(i);
@@ -81,12 +85,6 @@ FocusScope {
8185 }
8286 loader.item.opacity = 1;
8387 }
84−
85− Binding {
86− target: loader.item
87− property: "model"
88− value: loader.modelData
89− }
9088 }
9189 }
9290 }
@@ -95,19 +93,18 @@ FocusScope {
9593 id: infoLabel
9694
9795 FadingLabel {
98− objectName: "infoLabel" + model.index
96+ objectName: "infoLabel" + modelIndex
9997 width: root.width
10098
101− property var model
10299 readonly property bool isPrompt: false
103100
104− color: model.type === LightDMService.prompts.Message ? theme.palette.normal.raisedSecondaryText
101+ color: modelType === LightDMService.prompts.Message ? theme.palette.normal.raisedSecondaryText
105102 : theme.palette.normal.negative
106103 fontSize: "small"
107104 textFormat: Text.PlainText
108− text: model.text
105+ text: modelText
109106
110− visible: model.type === LightDMService.prompts.Message
107+ visible: modelType === LightDMService.prompts.Message
111108
112109 Behavior on opacity { UbuntuNumberAnimation {} }
113110 opacity: 0
@@ -118,23 +115,23 @@ FocusScope {
118115 id: greeterPrompt
119116
120117 GreeterPrompt {
121− objectName: "greeterPrompt" + model.index
118+ objectName: "greeterPrompt" + modelIndex
122119 width: root.width
123120
124− property var model
121+ property bool isAlphanumeric: modelText !== "" || root.alphanumeric
125122
126123 interactive: root.interactive
127− isAlphanumeric: model.text !== "" || root.alphanumeric
128− isPrompt: model.type !== LightDMService.prompts.Button
129− isSecret: model.type === LightDMService.prompts.Secret
124+ isPrompt: modelType !== LightDMService.prompts.Button
125+ isSecret: modelType === LightDMService.prompts.Secret
126+ isPinPrompt: isPrompt && !isAlphanumeric && isSecret
130127 loginError: root.loginError
131128 hasKeyboard: root.hasKeyboard
132− text: model.text ? model.text : (isAlphanumeric ? i18n.tr("Passphrase") : i18n.tr("Passcode"))
129+ text: modelText ? modelText : (isAlphanumeric ? i18n.tr("Passphrase") : i18n.tr("Passcode"))
133130
134131 onClicked: root.clicked()
135132 onAccepted: {
136133 // If there is another GreeterPrompt, focus it.
137− for (var i = model.index + 1; i < repeater.count; i++) {
134+ for (var i = modelIndex + 1; i < repeater.count; i++) {
138135 var item = repeater.itemAt(i).item;
139136 if (item.isPrompt) {
140137 item.forceActiveFocus();
qml/Greeter/WideView.qmldeleted−281
@@ -1,281 +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 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.qmlnew file+81
@@ -0,0 +1,81 @@
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+8−2
@@ -34,6 +34,7 @@ FocusScope {
3434 readonly property real delegateWidth: units.gu(10)
3535 property url background
3636 property alias backgroundSourceSize: background.sourceSize
37+ property bool staticBlurEnabled : true
3738 visible: x > -width
3839 property var fullyOpen: x === 0
3940 property var fullyClosed: x === -width
@@ -155,18 +156,21 @@ FocusScope {
155156
156157 Rectangle {
157158 anchors.fill: parent
158− color: "#111111"
159− opacity: 0.99
159+ color: "#BF000000"
160160
161161 Wallpaper {
162162 id: background
163163 objectName: "drawerBackground"
164+ visible: staticBlurEnabled
165+ enabled: staticBlurEnabled
164166 anchors.fill: parent
165167 source: root.background
166168 }
167169
168170 FastBlur {
169171 anchors.fill: background
172+ visible: staticBlurEnabled
173+ enabled: staticBlurEnabled
170174 source: background
171175 radius: 64
172176 cached: true
@@ -175,6 +179,8 @@ FocusScope {
175179 // Images with fastblur can't use opacity, so we'll put this on top
176180 Rectangle {
177181 anchors.fill: background
182+ visible: staticBlurEnabled
183+ enabled: staticBlurEnabled
178184 color: parent.color
179185 opacity: 0.67
180186 }
qml/Launcher/Launcher.qml+23−1
@@ -31,6 +31,8 @@ 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
3436 property int topPanelHeight: 0
3537 property bool drawerEnabled: true
3638 property alias privateMode: panel.privateMode
@@ -364,6 +366,20 @@ FocusScope {
364366 }
365367 }
366368
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+
367383 Drawer {
368384 id: drawer
369385 objectName: "drawer"
@@ -377,6 +393,7 @@ FocusScope {
377393 width: Math.min(root.width, units.gu(81))
378394 panelWidth: panel.width
379395 allowSlidingAnimation: !dragArea.dragging && !launcherDragArea.drag.active && panel.animate
396+ staticBlurEnabled: !root.interactiveBlur
380397
381398 onApplicationSelected: {
382399 root.launcherApplicationSelected(appId)
@@ -410,7 +427,7 @@ FocusScope {
410427 Connections {
411428 target: panel.dismissTimer
412429 onTriggered: {
413− if (root.autohideEnabled && !root.lockedVisible) {
430+ if (root.state !== "drawer" && root.autohideEnabled && !root.lockedVisible) {
414431 if (!edgeBarrier.containsMouse && !panel.preventHiding) {
415432 root.state = ""
416433 } else {
@@ -592,6 +609,11 @@ FocusScope {
592609 anchors.rightMargin: 0
593610 focus: false
594611 }
612+ PropertyChanges {
613+ target: root
614+ restoreEntryValues: false
615+ autohideEnabled: false
616+ }
595617 },
596618 State {
597619 name: "drawer"
qml/OrientedShell.qml+1
@@ -273,6 +273,7 @@ Item {
273273 nativeWidth: root.width
274274 nativeHeight: root.height
275275 mode: applicationArguments.mode
276+ interactiveBlur: applicationArguments.interactiveBlur
276277 hasMouse: pointerInputDevices > 0
277278 hasKeyboard: keyboardsModel.count > 0
278279 hasTouchscreen: touchScreensModel.count > 0
qml/Panel/Indicators/IndicatorItem.qml+6
@@ -117,6 +117,12 @@ 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+ }
120126 }
121127 }
122128 }
qml/Rotation/RotationStates.qml−3
@@ -139,9 +139,6 @@ 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;
145142 } else {
146143 if (!root.shell.mainApp) {
147144 // shouldn't happen but, anyway
qml/Shell.qml+7−2
@@ -59,6 +59,7 @@ 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
6263 property alias oskEnabled: inputMethod.enabled
6364 function updateFocusedAppOrientation() {
6465 stage.updateFocusedAppOrientation();
@@ -93,7 +94,7 @@ StyledItem {
9394
9495 readonly property bool orientationChangesEnabled: panel.indicators.fullyClosed
9596 && stage.orientationChangesEnabled
96− && (!greeter || !greeter.animating)
97+ && (!greeter.animating)
9798
9899 readonly property bool showingGreeter: greeter && greeter.shown
99100
@@ -104,7 +105,7 @@ StyledItem {
104105 if (startingUp) {
105106 // Ensure we don't rotate during start up
106107 return Qt.PrimaryOrientation;
107− } else if (showingGreeter || notifications.topmostIsFullscreen) {
108+ } else if (notifications.topmostIsFullscreen) {
108109 return Qt.PrimaryOrientation;
109110 } else {
110111 return shell.orientations ? shell.orientations.map(stage.supportedOrientations) : Qt.PrimaryOrientation;
@@ -436,6 +437,8 @@ StyledItem {
436437 enabled: panel.indicators.fullyClosed // hides OSK when panel is open
437438 hides: [launcher, panel.indicators, panel.applicationMenus]
438439 tabletMode: shell.usageScenario != "phone"
440+ usageMode: shell.usageScenario
441+ orientation: shell.orientation
439442 forcedUnlock: wizard.active || shell.mode === "full-shell"
440443 background: wallpaperResolver.background
441444 backgroundSourceSize: shell.largestScreenDimension
@@ -602,6 +605,8 @@ StyledItem {
602605 superTabPressed: physicalKeysMapper.superTabPressed
603606 panelWidth: units.gu(settings.launcherWidth)
604607 lockedVisible: (lockedByUser || shell.atDesktop) && lockAllowed
608+ blurSource: greeter.shown ? greeter : stages
609+ interactiveBlur: shell.interactiveBlur
605610 topPanelHeight: panel.panelHeight
606611 drawerEnabled: !greeter.active && tutorial.launcherLongSwipeEnabled
607612 privateMode: greeter.active
src/ApplicationArguments.h+5
@@ -28,6 +28,7 @@ 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)
3132public:
3233 ApplicationArguments(QObject *parent = nullptr);
3334
@@ -42,12 +43,16 @@ public:
4243 void setMode(const QString &mode) { m_mode = mode; }
4344 QString mode() const { return m_mode; }
4445
46+ void setInteractiveBlur(const bool &value) { m_interactiveBlur = value; }
47+ bool interactiveBlur() { return m_interactiveBlur; }
48+
4549Q_SIGNALS:
4650 void deviceNameChanged(const QString&);
4751
4852private:
4953 QString m_deviceName;
5054 QString m_mode;
55+ bool m_interactiveBlur;
5156};
5257
5358#endif // APPLICATION_ARGUMENTS_H
src/ShellApplication.cpp+6
@@ -58,6 +58,12 @@ 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+
6167 // The testability driver is only loaded by QApplication but not by QGuiApplication.
6268 // However, QApplication depends on QWidget which would add some unneeded overhead => Let's load the testability driver on our own.
6369 if (parser.hasTestability() || getenv("QT_LOAD_TESTABILITY")) {
tests/qmltests/CMakeLists.txt+1−2
@@ -29,8 +29,7 @@ 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 NarrowView)
33−add_unity8_qmltest(Greeter WideView)
32+add_unity8_qmltest(Greeter GreeterView)
3433add_unity8_qmltest_data(Greeter TestView)
3534add_unity8_qmltest(Launcher Launcher)
3635add_unity8_qmltest(Launcher Drawer)
tests/qmltests/Greeter/TestView.qml+7
@@ -38,6 +38,13 @@ 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+
4148 property bool _fullyShown: true
4249 property bool _required: true
4350 property bool _animating: true
tests/qmltests/Greeter/tst_GreeterView.qmlnew file+1366
@@ -0,0 +1,1366 @@
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.qmldeleted−565
@@ -1,565 +0,0 @@
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.qmldeleted−801
@@ -1,801 +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 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+1−38
@@ -619,43 +619,6 @@ 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−
659622 function test_appRotatesWindowContents_data() {
660623 return [
661624 {tag: "mako", deviceName: "mako", orientationAngleAfterRotation: 90},
@@ -1247,7 +1210,7 @@ Rectangle {
12471210
12481211 showGreeter(orientedShell);
12491212
1250− tryCompare(shell, "transformRotationAngle", root.primaryOrientationAngle);
1213+ tryCompare(shell, "transformRotationAngle", root.primaryOrientationAngle + 90);
12511214 }
12521215
12531216 /*
tests/qmltests/tst_Shell.qml+38−8
@@ -703,6 +703,32 @@ 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+
706732 function swipeAwayGreeter() {
707733 var greeter = findChild(shell, "greeter");
708734
@@ -996,14 +1022,13 @@ Rectangle {
9961022 }
9971023
9981024 function test_greeterStartsCorrectSession() {
999− loadShell("desktop");
10001025 setLightDMMockMode("full");
1026+ loadShell("desktop");
10011027
10021028 LightDMController.sessionMode = "full"
10031029 LightDMController.numSessions = LightDMController.numAvailableSessions;
10041030 var greeter = findChild(shell, "greeter");
1005− var view = findChild(greeter, "WideView");
1006− verify(view, "This test requires WideView to be loaded");
1031+ var view = findChild(greeter, "GreeterView");
10071032
10081033 var loginList = findChild(view, "loginList");
10091034
@@ -1403,8 +1428,9 @@ Rectangle {
14031428 }
14041429
14051430 function test_tabletLogin(data) {
1406− loadShell("tablet");
14071431 setLightDMMockMode("full");
1432+ loadShell("tablet");
1433+ swipeAwayGreeterCover();
14081434
14091435 selectUser(data.user);
14101436
@@ -1427,8 +1453,10 @@ Rectangle {
14271453 }
14281454
14291455 function test_appLaunchDuringGreeter(data) {
1430− loadShell("tablet");
14311456 setLightDMMockMode("full");
1457+ loadShell("tablet");
1458+
1459+ swipeAwayGreeterCover();
14321460
14331461 selectUser(data.user)
14341462
@@ -1444,9 +1472,11 @@ Rectangle {
14441472 }
14451473
14461474 function test_manualLoginFlow() {
1447− loadShell("desktop");
1448− LightDMController.showManualLoginHint = true;
14491475 setLightDMMockMode("full");
1476+ LightDMController.showManualLoginHint = true;
1477+ loadShell("desktop");
1478+
1479+ swipeAwayGreeterCover();
14501480
14511481 var i = selectUser("*other");
14521482 var greeter = findChild(shell, "greeter");
@@ -2583,8 +2613,8 @@ Rectangle {
25832613
25842614 function test_fullShellModeHasNoInitialGreeter() {
25852615 shellRect.mode = "full-shell";
2586− loadShell("phone");
25872616 setLightDMMockMode("single-pin");
2617+ loadShell("phone");
25882618 waitForRendering(shell);
25892619
25902620 var greeter = findChild(shell, "greeter");