diff --git a/.clang-tidy b/.clang-tidy index bf5aaa901..b7ccb2fa6 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -15,6 +15,7 @@ Checks: ' ,-readability-convert-member-functions-to-static, ,-readability-redundant-member-init, ,-readability-implicit-bool-cast, + ,-llvmlibc-*, ' WarningsAsErrors: '' diff --git a/AUTHORS b/AUTHORS index e82341486..757f54940 100644 --- a/AUTHORS +++ b/AUTHORS @@ -12,3 +12,4 @@ Jan Möller Jan Niklas Hasse Mike Achtelik Julian Greilich +Timon Sassor diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e2bfb77d..6f46cf7ce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,52 +1,9 @@ -if(WIN32) - cmake_minimum_required(VERSION 3.19.0) -else() - cmake_minimum_required(VERSION 3.13.0) -endif() - -if(POLICY CMP0020) - cmake_policy(SET CMP0020 NEW) -endif() +cmake_minimum_required(VERSION 3.19.0) -if(POLICY CMP0023) - cmake_policy(SET CMP0023 NEW) -endif() - -if(POLICY CMP0046) - cmake_policy(SET CMP0046 NEW) -endif() - -if(POLICY CMP0048) - cmake_policy(SET CMP0048 NEW) -endif() - -if(POLICY CMP0054) - cmake_policy(SET CMP0054 NEW) -endif() - -if(POLICY CMP0063) - cmake_policy(SET CMP0063 NEW) -endif() - -if(POLICY CMP0071) - cmake_policy(SET CMP0071 NEW) -endif() - -if(POLICY CMP0072) - cmake_policy(SET CMP0072 NEW) -endif() - -if(POLICY CMP0074) - cmake_policy(SET CMP0074 NEW) -endif() - -if(POLICY CMP0076) - cmake_policy(SET CMP0076 NEW) -endif() +set(CMAKE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/cmake") +set(CMAKE_MODULE_PATH "${CMAKE_DIR}") -if(POLICY CMP0092) - cmake_policy(SET CMP0092 NEW) -endif() +include(Policies) # "tools.only" can be defined to disable the normal build and enable # cmdline "tools" only. For example: "make format" or "make package_source" @@ -57,10 +14,10 @@ else() endif() if(UNIX AND NOT IOS) - set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15 CACHE STRING "Required macOS version") + set(CMAKE_OSX_DEPLOYMENT_TARGET 11.0 CACHE STRING "Required macOS version") endif() -project(AusweisApp2 VERSION 1.26.7 LANGUAGES ${LANGUAGES}) +project(AusweisApp VERSION 2.0.0 LANGUAGES ${LANGUAGES}) # Set TWEAK if not defined in PROJECT_VERSION above to # have a valid tweak version without propagating it @@ -68,15 +25,14 @@ if(NOT PROJECT_VERSION_TWEAK) set(PROJECT_VERSION_TWEAK 0) endif() -if(APPLE AND CMAKE_VERSION VERSION_GREATER_EQUAL "3.16" AND NOT tools.only) +if(APPLE AND NOT tools.only) enable_language(OBJCXX) endif() if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT AND (IOS OR ANDROID)) set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/dist" CACHE PATH "default install path" FORCE) endif() -set(CMAKE_DIR "${PROJECT_SOURCE_DIR}/cmake") -set(CMAKE_MODULE_PATH "${CMAKE_DIR}") + option(BUILD_SHARED_LIBS "Enable build of shared libraries") option(INTEGRATED_SDK "Build platform specific SDK" OFF) option(CONTAINER_SDK "Build container specific SDK" OFF) @@ -93,7 +49,7 @@ if(NOT VENDOR) elseif(LINUX OR BSD) set(VENDOR "") # Qt uses Organization for paths else() - set(VENDOR AusweisApp2_CE) # CommunityEdition + set(VENDOR AusweisApp_CE) # CommunityEdition endif() endif() if(VENDOR MATCHES "Governikus") diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index e3381eba5..fae3fd85a 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -4,7 +4,7 @@ Contributing Patches ------- -Wir nehmen gerne Patches für die AusweisApp2 an. +Wir nehmen gerne Patches für die AusweisApp an. Bitte gehen Sie dafür wie folgt vor: #. Forken des `Repository`_ in das eigene GitHub-Konto. diff --git a/Dockerfile b/Dockerfile index ab32e67a4..afc3c56df 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,7 +6,7 @@ RUN apk --no-cache upgrade -a && \ apk --no-cache add patch cmake ccache make ninja g++ pkgconf pcsc-lite-dev binutils-gold eudev-libs perl python3 linux-headers # Use optional remote ccache -# redis://YOUR_SERVER:6379|share-hits=false +# redis://YOUR_SERVER:6379 ARG CCACHE_REMOTE_STORAGE="" ENV CCACHE_REMOTE_STORAGE=$CCACHE_REMOTE_STORAGE CCACHE_REMOTE_ONLY=true CCACHE_RESHARE=true CCACHE_DIR=/build/ccache @@ -21,7 +21,7 @@ RUN cmake /src/libs/ -B /build/libs \ cmake --build /build/libs && \ ccache -s -vv && rm -rf /build -# Build AusweisApp2 +# Build AusweisApp COPY docs/ /src/ausweisapp/docs/ COPY CMakeLists.txt /src/ausweisapp/ COPY cmake/ /src/ausweisapp/cmake/ @@ -39,7 +39,7 @@ RUN cmake /src/ausweisapp -B /build/app \ RUN find /usr/local/ -type d -empty -delete && \ find /usr/local/lib/ -type f -not -name "*.so*" -delete && \ find /usr/local/lib/ -type f -name "*.so*" -exec strip {} + && \ - strip /usr/local/bin/AusweisApp2 + strip /usr/local/bin/AusweisApp @@ -48,7 +48,7 @@ FROM alpine:$ALPINE_VERSION COPY --from=builder /usr/local/plugins /usr/local/plugins COPY --from=builder /usr/local/lib /usr/local/lib COPY --from=builder /usr/local/share /usr/local/share -COPY --from=builder /usr/local/bin/AusweisApp2 /usr/local/bin/AusweisApp2 +COPY --from=builder /usr/local/bin/AusweisApp /usr/local/bin/AusweisApp RUN apk --no-cache upgrade -a && \ apk --no-cache add tini pcsc-lite pcsc-lite-libs ccid pcsc-cyberjack acsccid eudev-libs doas && \ @@ -60,4 +60,4 @@ USER ausweisapp VOLUME ["/home/ausweisapp/.config"] ENTRYPOINT ["/sbin/tini", "--"] EXPOSE 24727 -CMD ["AusweisApp2", "--address", "0.0.0.0"] +CMD ["AusweisApp", "--address", "0.0.0.0"] diff --git a/Doxyfile.in b/Doxyfile.in index 2242bff28..7e03925b8 100644 --- a/Doxyfile.in +++ b/Doxyfile.in @@ -1,7 +1,7 @@ # Available options # http://www.stack.nl/~dimitri/doxygen/manual/config.html -PROJECT_NAME = AusweisApp2 +PROJECT_NAME = AusweisApp OUTPUT_DIRECTORY = @PROJECT_BINARY_DIR@/doc OUTPUT_LANGUAGE = German INPUT = @PROJECT_SOURCE_DIR@ diff --git a/LICENSE.officially.txt b/LICENSE.officially.txt index 8d9ac7218..788535120 100644 --- a/LICENSE.officially.txt +++ b/LICENSE.officially.txt @@ -1,6 +1,6 @@ Nutzungsbedingungen -Bitte lesen Sie zunächst die Lizenzbestimmungen und deren Ergänzungen für die Überlassung und Nutzung der AusweisApp2 durch. Nachdem Sie diesen zugestimmt haben, können Sie die Installation fortsetzen. Datenschutzrechtliche Hinweise sind unter https://www.ausweisapp.bund.de/aa2/privacy abrufbar. +Bitte lesen Sie zunächst die Lizenzbestimmungen und deren Ergänzungen für die Überlassung und Nutzung der AusweisApp durch. Nachdem Sie diesen zugestimmt haben, können Sie die Installation fortsetzen. Datenschutzrechtliche Hinweise sind unter https://www.ausweisapp.bund.de/aa2/privacy abrufbar. ÜBERSICHT @@ -8,7 +8,7 @@ Bitte lesen Sie zunächst die Lizenzbestimmungen und deren Ergänzungen für die A. Lizenzbedingungen EUPL Lizenztext Anlage: Kompatible Lizenzen - B. Zusatzvereinbarungen zur AusweisApp2 + B. Zusatzvereinbarungen zur AusweisApp C. Anhang Lizenztexte verwendeter OpenSource Bibliotheken LGPL v3 MIT License @@ -18,7 +18,7 @@ Bitte lesen Sie zunächst die Lizenzbestimmungen und deren Ergänzungen für die A. LIZENZBEDINGUNGEN -Der Quellcode der AusweisApp2 wird unter der EUPL v1.2 bereitgestellt. +Der Quellcode der AusweisApp wird unter der EUPL v1.2 bereitgestellt. @@ -314,29 +314,29 @@ Anlage B. ZUSATZVEREINBARUNGEN § 1 Nutzungsbedingungen -(1) Diese Allgemeine Geschäftsbedingungen (AGB) des Bundes, vertreten durch das Bundesministerium des Innern und für Heimat, vertreten durch das Bundesamt für Sicherheit in der Informationstechnik (nachfolgend "Bund") und dem Nutzer gelten für die Überlassung und Nutzung der Software AusweisApp2 (nachfolgend AusweisApp2) und deren neue Versionen, die auf der Grundlage dieser Bedingungen überlassen werden. +(1) Diese Allgemeine Geschäftsbedingungen (AGB) des Bundes, vertreten durch das Bundesministerium des Innern und für Heimat, vertreten durch das Bundesamt für Sicherheit in der Informationstechnik (nachfolgend "Bund") und dem Nutzer gelten für die Überlassung und Nutzung der Software AusweisApp (nachfolgend AusweisApp) und deren neue Versionen, die auf der Grundlage dieser Bedingungen überlassen werden. (2) "Nutzer" im Sinne dieses Vertrages sind natürliche Personen. (3) Diese Zusatzvereinbarungen lassen die Rechte und Pflichten aus der EUPL unberührt. § 2 Vertragsgegenstand und Unentgeltlichkeit -(1) Die AusweisApp2 wird regelmäßig hinsichtlich ihrer Konformität zu den Technischen Richtlinien des Bundesamtes für Sicherheit in der Informationstechnik [TR-03124-2] zertifiziert sowie hinsichtlich ihrer Nutzerfreundlichkeit [EN ISO 9241 Teil 110 Ergonomie Mensch-System-Integration zur Prüfung der Benutzbarkeit und Funktionalität und Trusted Design Guidelines zur Prüfung der Vertrauenswürdigkeit] und auf Barrierefreiheit [BITV 2.0] überprüft. -(2) Die AusweisApp2 wird in maschinenlesbarer Form unentgeltlich überlassen. Der Quellcode der AusweisApp2 wird ebenfalls unentgeltlich veröffentlicht. Eine Auflistung der verwendeten Open Source-Bestandteile der AusweisApp2 findet sich im Anhang. -(3) Die AusweisApp2 wird von der Governikus GmbH & Co. KG (Governikus) als Erfüllungsgehilfe des Bundes überlassen. +(1) Die AusweisApp wird regelmäßig hinsichtlich ihrer Konformität zu den Technischen Richtlinien des Bundesamtes für Sicherheit in der Informationstechnik [TR-03124-2] zertifiziert sowie hinsichtlich ihrer Nutzerfreundlichkeit [EN ISO 9241 Teil 110 Ergonomie Mensch-System-Integration zur Prüfung der Benutzbarkeit und Funktionalität und Trusted Design Guidelines zur Prüfung der Vertrauenswürdigkeit] und auf Barrierefreiheit [BITV 2.0] überprüft. +(2) Die AusweisApp wird in maschinenlesbarer Form unentgeltlich überlassen. Der Quellcode der AusweisApp wird ebenfalls unentgeltlich veröffentlicht. Eine Auflistung der verwendeten Open Source-Bestandteile der AusweisApp findet sich im Anhang. +(3) Die AusweisApp wird von der Governikus GmbH & Co. KG (Governikus) als Erfüllungsgehilfe des Bundes überlassen. § 3 Verwendungszweck -Die AusweisApp2 und alle ihre Bestandteile dienen ausschließlich dazu, im Zusammenhang mit der Nutzung der Online-Ausweisfunktion des Personalausweises, des elektronischen Aufenthaltstitels, der eID-Karte für Bürgerinnen und Bürger der EU und des EWR und der Übermittlung der damit verbundenen Daten gemäß den gesetzlichen Vorgaben verwendet zu werden. Ebenso dient die AusweisApp2 zur Einrichtung und Nutzung der Online-Ausweisfunktion mit einem mobilen Endgerät (Smart-eID) auf Basis eines der vorgenannten Dokumente. +Die AusweisApp und alle ihre Bestandteile dienen ausschließlich dazu, im Zusammenhang mit der Nutzung der Online-Ausweisfunktion des Personalausweises, des elektronischen Aufenthaltstitels, der eID-Karte für Bürgerinnen und Bürger der EU und des EWR und der Übermittlung der damit verbundenen Daten gemäß den gesetzlichen Vorgaben verwendet zu werden. Ebenso dient die AusweisApp zur Einrichtung und Nutzung der Online-Ausweisfunktion mit einem mobilen Endgerät (Smart-eID) auf Basis eines der vorgenannten Dokumente. § 4 Empfehlungen zum Einsatz -(1) Es liegt im Interesse des Nutzers, dass in Verbindung mit der AusweisApp2 genutzte Hard- und Software immer auf dem neuesten Stand der Sicherheitstechnik (System- und Firmware Update, Virenscanner, Firewall usw.) sind. -(2) Es liegt im Interesse des Nutzers aber auch des Bundes, dass stets nur die neueste Version der AusweisApp2 (siehe § 5) verwendet wird. +(1) Es liegt im Interesse des Nutzers, dass in Verbindung mit der AusweisApp genutzte Hard- und Software immer auf dem neuesten Stand der Sicherheitstechnik (System- und Firmware Update, Virenscanner, Firewall usw.) sind. +(2) Es liegt im Interesse des Nutzers aber auch des Bundes, dass stets nur die neueste Version der AusweisApp (siehe § 5) verwendet wird. § 5 Pflege und Support -(1) Der Bund bietet nach eigenem Ermessen und ohne hierzu verpflichtet zu sein für Teile der AusweisApp2 zusätzliche kostenfreie Supportleistungen in Form von Dokumentationen und online Hilfen auf dem AusweisApp2-Portal im Internet unter der Adresse https://www.ausweisapp.bund.de an, sowie über die Hotline des Herstellers Governikus unter der E-Mail-Adresse: support@ausweisapp.de und der Tel.-Nr.: +49 421 204 95-995. Auch stellt er verfügbare neue Versionen der AusweisApp2 zur Verfügung. Hieraus erwächst jedoch kein Anspruch auf Mängelbeseitigung, auf Zertifizierung, auf Beibehaltung der Supportleistungen oder der Hotline und auf Überlassung neuer Versionen. -(2) Verfügbare neue Versionen der AusweisApp2 können im Internet kostenfrei auf dem AusweisApp2-Portal unter der Adresse https://www.ausweisapp.bund.de sowie über allgemein zugängliche AppStore heruntergeladen werden. -(3) Eventuelle Mängel der AusweisApp2 werden grundsätzlich dadurch behoben, dass der Bund jeweils eine neue Version der AusweisApp2 zum Herunterladen zur Verfügung stellt (siehe § 5 Absatz 1). Eine Pflicht zur Bereitstellung von neuen Versionen ergibt sich daraus nicht. +(1) Der Bund bietet nach eigenem Ermessen und ohne hierzu verpflichtet zu sein für Teile der AusweisApp zusätzliche kostenfreie Supportleistungen in Form von Dokumentationen und online Hilfen auf dem AusweisApp-Portal im Internet unter der Adresse https://www.ausweisapp.bund.de an, sowie über die Hotline des Herstellers Governikus unter der E-Mail-Adresse: support@ausweisapp.de und der Tel.-Nr.: +49 421 204 95-995. Auch stellt er verfügbare neue Versionen der AusweisApp zur Verfügung. Hieraus erwächst jedoch kein Anspruch auf Mängelbeseitigung, auf Zertifizierung, auf Beibehaltung der Supportleistungen oder der Hotline und auf Überlassung neuer Versionen. +(2) Verfügbare neue Versionen der AusweisApp können im Internet kostenfrei auf dem AusweisApp-Portal unter der Adresse https://www.ausweisapp.bund.de sowie über allgemein zugängliche AppStore heruntergeladen werden. +(3) Eventuelle Mängel der AusweisApp werden grundsätzlich dadurch behoben, dass der Bund jeweils eine neue Version der AusweisApp zum Herunterladen zur Verfügung stellt (siehe § 5 Absatz 1). Eine Pflicht zur Bereitstellung von neuen Versionen ergibt sich daraus nicht. § 6 Hinweis auf gewerbliche und urheberrechtliche Schutzrechte -Die Zeichen AusweisApp2 und die entsprechenden Grafiken sowie das Signet zur Online-Ausweisfunktion sind für den Bund als Marken geschützt. +Die Zeichen AusweisApp und die entsprechenden Grafiken sowie das Signet zur Online-Ausweisfunktion sind für den Bund als Marken geschützt. § 7 Deutsches Recht Auf diese Nutzungsbedingungen ist ausschließlich deutsches Recht unter Ausschluss des Übereinkommens der Vereinten Nationen über Verträge über den internationalen Warenkauf (CISG) anwendbar. @@ -350,12 +350,12 @@ Die verwendeten Open-Source-Bibliotheken unterliegen den folgenden Nutzungsbedin OpenSSL Lizenz: Apache 2.0 - Version: 3.0.9 + Version: 3.1.4 Adresse: https://www.openssl.org/ Qt Lizenz: LGPL v3 - Version: 6.4.1 + Version: 6.5.3 Adresse: https://www.qt.io/ http_parser @@ -363,9 +363,9 @@ http_parser Version: 2.9.4 Adresse: https://github.com/nodejs/http-parser/ -AndroidX Support Library +AndroidX Core Library Lizenz: Apache 2.0 - Version: 1.1.0 + Version: 1.9.0 Adresse: https://developer.android.com/jetpack/androidx diff --git a/LICENSE.txt b/LICENSE.txt index 0da07e284..3367a1c08 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ Nutzungsbedingungen -Bitte lesen Sie zunächst die Lizenzbestimmungen und deren Ergänzungen für die Überlassung und Nutzung der AusweisApp2 durch. Nachdem Sie diesen zugestimmt haben, können Sie die Installation fortsetzen. Datenschutzrechtliche Hinweise sind unter https://www.ausweisapp.bund.de/aa2/privacy abrufbar. +Bitte lesen Sie zunächst die Lizenzbestimmungen und deren Ergänzungen für die Überlassung und Nutzung der AusweisApp durch. Nachdem Sie diesen zugestimmt haben, können Sie die Installation fortsetzen. Datenschutzrechtliche Hinweise sind unter https://www.ausweisapp.bund.de/aa2/privacy abrufbar. ÜBERSICHT @@ -17,7 +17,7 @@ Bitte lesen Sie zunächst die Lizenzbestimmungen und deren Ergänzungen für die A. LIZENZBEDINGUNGEN -Der Quellcode der AusweisApp2 wird unter der EUPL v1.2 bereitgestellt. +Der Quellcode der AusweisApp wird unter der EUPL v1.2 bereitgestellt. @@ -318,12 +318,12 @@ Die verwendeten Open-Source-Bibliotheken unterliegen den folgenden Nutzungsbedin OpenSSL Lizenz: Apache 2.0 - Version: 3.0.9 + Version: 3.1.4 Adresse: https://www.openssl.org/ Qt Lizenz: LGPL v3 - Version: 6.4.1 + Version: 6.5.3 Adresse: https://www.qt.io/ http_parser @@ -331,9 +331,9 @@ http_parser Version: 2.9.4 Adresse: https://github.com/nodejs/http-parser/ -AndroidX Support Library +AndroidX Core Library Lizenz: Apache 2.0 - Version: 1.1.0 + Version: 1.9.0 Adresse: https://developer.android.com/jetpack/androidx diff --git a/README.rst b/README.rst index dd3d5ba09..1cbde0aee 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -AusweisApp2 -=========== +AusweisApp +========== Kontakt ------- @@ -13,7 +13,7 @@ Lizenz ------ Der vorliegende Quellcode wird unter der EUPL v1.2 bereitgestellt. Die Datei ``LICENSE.officially.txt`` gilt ausschließlich für -die offizielle Version der AusweisApp2, welche von der Governikus GmbH & Co. KG +die offizielle Version der AusweisApp, welche von der Governikus GmbH & Co. KG im Auftrag des Bundes unter https://www.ausweisapp.bund.de bereitgestellt wird. @@ -30,7 +30,7 @@ notwendigen Bibliotheken mit den entsprechenden Patches. Build ----- -Um die AusweisApp2 zu bauen, ist es notwendig, ein Makefile mittels CMake zu +Um die AusweisApp zu bauen, ist es notwendig, ein Makefile mittels CMake zu generieren. Dazu kann CMake auf der Kommandozeile oder mit der von CMake mitgelieferten CMake-GUI ausgeführt werden. @@ -42,7 +42,7 @@ für den Build eingetragen wurden, über diesen Mechanismus an CMake übergeben Als Generator für Makefiles sollte unter Windows für MinGW "MinGW Makefiles" und für MSVC "NMake Makefiles" oder "Ninja" gewählt werden. -Beim Generieren des Makefiles ist zu beachten, dass die AusweisApp2 nur sogenannte +Beim Generieren des Makefiles ist zu beachten, dass die AusweisApp nur sogenannte "out of source tree"-Builds erlaubt. Daher ist die empfohlene Variante von CMake zwingend einzuhalten, und der Build-Ordner darf sich nicht im Source-Ordner befinden. @@ -51,14 +51,14 @@ Beispiel über die CLI: :: - C:/AusweisApp2/ + C:/AusweisApp/ C:/qt/ C:/build/ :: C:>cd C:/build - C:\build>cmake -G "MinGW Makefiles" -DCMAKE_PREFIX_PATH=C:/qt/dist C:/AusweisApp2 -DCMAKE_BUILD_TYPE=release + C:\build>cmake -G "MinGW Makefiles" -DCMAKE_PREFIX_PATH=C:/qt/dist C:/AusweisApp -DCMAKE_BUILD_TYPE=release -- The CXX compiler identification is GNU 11.2.0 -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done @@ -76,12 +76,12 @@ Beispiel über die CLI: -- DVCS phase: public -- DVCS revision: 283adbf18b4e+ -- No documentation will be generated - -- CMAKE_INSTALL_PREFIX: C:/Program Files (x86)/AusweisApp2 + -- CMAKE_INSTALL_PREFIX: C:/Program Files (x86)/AusweisApp -- CMAKE_BUILD_TYPE: RELEASE -- CMAKE_PREFIX_PATH: C:/qt/dist -- CMAKE_INCLUDE_PATH: -- CMAKE_LIBRARY_PATH: - -- CMAKE_SYSTEM_PREFIX_PATH: C:/Program Files;C:/Program Files (x86);C:/Program Files/CMake;C:/Program Files (x86)/AusweisApp2 + -- CMAKE_SYSTEM_PREFIX_PATH: C:/Program Files;C:/Program Files (x86);C:/Program Files/CMake;C:/Program Files (x86)/AusweisApp -- CMAKE_SYSTEM_INCLUDE_PATH: -- CMAKE_VERSION: 3.23.2 -- CMAKE_SYSTEM_PROCESSOR: AMD64 @@ -90,7 +90,7 @@ Beispiel über die CLI: [...] -Um die mobile Variante der AusweisApp2 zu bauen, benötigt man je nach Plattform zusätzliche +Um die mobile Variante der AusweisApp zu bauen, benötigt man je nach Plattform zusätzliche externe Komponenten, die in der README in ``./libs`` im Abschnitt Android / iOS beschrieben sind. @@ -103,19 +103,19 @@ Bei Android ist zu beachten, dass ein CMAKE_TOOLCHAIN_FILE angegeben werden muss :: $ cd build - $ cmake -DCMAKE_PREFIX_PATH=/home/governikus/Toolchain/dist -DCMAKE_TOOLCHAIN_FILE=../AusweisApp2/cmake/android.toolchain.cmake ../AusweisApp2 + $ cmake -DCMAKE_PREFIX_PATH=/home/governikus/Toolchain/dist -DCMAKE_TOOLCHAIN_FILE=../AusweisApp/cmake/android.toolchain.cmake ../AusweisApp $ make $ make install $ make apk -Unter dem Ordner "./dist/bin" ist nun ein "AusweisApp2...apk" erstellt worden. +Unter dem Ordner "./dist/bin" ist nun ein "AusweisApp...apk" erstellt worden. Sofern der Parameter *CMAKE_BUILD_TYPE* auf RELEASE gesetzt wird, sind folgende CMake Parameter notwendig um das APK zu signieren. :: - -DAPK_SIGN_KEYSTORE=/home/governikus/ausweisapp2.apk.keystore.jks + -DAPK_SIGN_KEYSTORE=/home/governikus/AusweisApp.apk.keystore.jks -DAPK_SIGN_KEYSTORE_ALIAS=ausweisapp -DAPK_SIGN_KEYSTORE_PSW=123456 @@ -137,14 +137,14 @@ freizuschalten bzw. den Schlüsselbund freizugeben. security unlock-keychain -pPASSWORD ${HOME}/Library/Keychains/login.keychain -Für iOS wird die AusweisApp2 mittels XCode gebaut! +Für iOS wird die AusweisApp mittels XCode gebaut! :: $ cd build - $ cmake -DCMAKE_PREFIX_PATH=/Users/governikus/Toolchain/dist -DCMAKE_TOOLCHAIN_FILE=../AusweisApp2/cmake/iOS.toolchain.cmake -DCMAKE_BUILD_TYPE=MinSizeRel ../AusweisApp2 -GXcode - $ xcodebuild -configuration MinSizeRel -archivePath AusweisApp2.xcarchive -scheme AusweisApp archive - $ xcodebuild -configuration MinSizeRel -archivePath AusweisApp2.xcarchive -exportArchive -exportOptionsPlist exportOptions.plist -exportPath . + $ cmake -DCMAKE_PREFIX_PATH=/Users/governikus/Toolchain/dist -DCMAKE_TOOLCHAIN_FILE=../AusweisApp/cmake/iOS.toolchain.cmake -DCMAKE_BUILD_TYPE=MinSizeRel ../AusweisApp -GXcode + $ xcodebuild -configuration MinSizeRel -archivePath AusweisApp.xcarchive -scheme AusweisAppBinary archive + $ xcodebuild -configuration MinSizeRel -archivePath AusweisApp.xcarchive -exportArchive -exportOptionsPlist exportOptions.plist -exportPath . Im Build-Ordner befindet sich nun ein *.ipa und ein *.xcarchive, welches jeweils das @@ -158,9 +158,9 @@ Nachdem die Build-Umgebung eingerichtet ist, kann je nach System ein Package ers - Unter Windows ist hierfür noch das WiX Toolset (http://wixtoolset.org/ Getestet: 3.8 bis 3.10) notwendig. - Mittels "mingw32-make package" wird die AusweisApp2 gebaut und ein MSI Paket bereitgestellt. + Mittels "mingw32-make package" wird die AusweisApp gebaut und ein MSI Paket bereitgestellt. -- Unter macOS wird mittels "make package" die AusweisApp2 gebaut und ein DMG bereitgestellt. +- Unter macOS wird mittels "make package" die AusweisApp gebaut und ein DMG bereitgestellt. - Um ein APK für Android zu bauen, sind zwei Schritte notwendig, da CMake das Format bisher nicht unterstützt. Daher sind nach der Konfiguration des Projektes folgende Befehle notwendig, @@ -175,7 +175,7 @@ Nachdem die Build-Umgebung eingerichtet ist, kann je nach System ein Package ers Reproduzierbarer Build ---------------------- -Wir sind stets bemüht, den Build des offiziellen Binaries der AusweisApp2 nachvollziehbar zu gestalten. +Wir sind stets bemüht, den Build des offiziellen Binaries der AusweisApp nachvollziehbar zu gestalten. Daher haben wir unter anderem eine README in dem Unterordner ``./libs`` hinterlegt, die den Aufbau der Buildumgebung und den Build der externen Bibliotheken beschreibt. Anhand dieser Anleitung können Sie nachvollziehen, wie unser internes Buildsystem aufgebaut ist und @@ -184,7 +184,7 @@ welche Compiler bzw. Compiler-Versionen wir verwenden. Im Unterordner ``./resources/jenkins/`` ist es möglich, unsere Konfiguration des CI-Servers einzusehen. Die Konfiguration besteht aus mehreren Dockerfiles und JobDSL-Dateien. -Anhand dieser Skripte ist es möglich, den Build der AusweisApp2 zu reproduzieren. +Anhand dieser Skripte ist es möglich, den Build der AusweisApp zu reproduzieren. Ein Unterschied zum offiziellen Binary sollte lediglich in eventuellen Pfaden, einem Datum bzw. Zeitstempel und Signaturen bestehen. diff --git a/cmake/Appcast.cmake b/cmake/Appcast.cmake index 6eea8e244..d8c3b0fe7 100644 --- a/cmake/Appcast.cmake +++ b/cmake/Appcast.cmake @@ -6,11 +6,7 @@ if(MAC OR LINUX OR WIN32) string(TIMESTAMP APPCAST_DATE "%Y-%m-%dT%H:%M:%S") foreach(filePath ${_files}) - if(CMAKE_VERSION VERSION_LESS "3.14") - FILE_SIZE(fileSize ${filePath}) - else() - file(SIZE ${filePath} fileSize) - endif() + file(SIZE ${filePath} fileSize) get_filename_component(file ${filePath} NAME) if(NOT DEFINED fileSize) diff --git a/cmake/Compat.cmake b/cmake/Compat.cmake deleted file mode 100644 index 14d4916dd..000000000 --- a/cmake/Compat.cmake +++ /dev/null @@ -1,37 +0,0 @@ -if(Qt STREQUAL "Qt5") - set(QT5 ON) - set(QT_VERSION "${Qt5Core_VERSION}") - -elseif(Qt STREQUAL "Qt6") - set(QT6 ON) - set(QT_VERSION "${Qt6Core_VERSION}") - -else() - message(FATAL_ERROR "Qt version not supported: ${Qt}") -endif() - -if(QT5) - if(NOT COMMAND qt_add_binary_resources) - macro(qt_add_binary_resources) - qt5_add_binary_resources(${ARGV}) - endmacro() - endif() - - if(NOT COMMAND qt_add_resources) - macro(qt_add_resources) - qt5_add_resources(${ARGV}) - endmacro() - endif() - - if(NOT COMMAND qt_add_translation) - macro(qt_add_translation) - qt5_add_translation(${ARGV}) - endmacro() - endif() - - if(NOT COMMAND qt_create_translation) - macro(qt_create_translation) - qt5_create_translation(${ARGV}) - endmacro() - endif() -endif() diff --git a/cmake/CompilerFlags.cmake b/cmake/CompilerFlags.cmake index 3892ac25b..1425cf547 100644 --- a/cmake/CompilerFlags.cmake +++ b/cmake/CompilerFlags.cmake @@ -15,7 +15,7 @@ add_compile_definitions($<$>:QT_NO_CAST_FROM_ASCII>) if(QT_VENDOR STREQUAL "Governikus") add_definitions(-DGOVERNIKUS_QT) - add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x060301) + add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x060502) endif() @@ -40,6 +40,7 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON) if(NOT DEFINED CMAKE_COMPILE_WARNING_AS_ERROR AND VENDOR_GOVERNIKUS) set(CMAKE_COMPILE_WARNING_AS_ERROR ON) + add_definitions(-DOPENSSL_NO_DEPRECATED) endif() @@ -55,10 +56,7 @@ if(MSVC) ADD_FLAG(/HIGHENTROPYVA) ADD_FLAG(/guard:cf) ADD_FLAG(/Qcf-protection) - - if (QT6) - ADD_FLAG(/Zc:__cplusplus) - endif() + ADD_FLAG(/Zc:__cplusplus) if(CMAKE_CXX_COMPILER_LAUNCHER MATCHES "ccache") string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") @@ -124,20 +122,12 @@ else() ADD_FLAG(-Wunused) ADD_FLAG(-Wunused-template) ADD_FLAG(-Wextra-semi) + ADD_FLAG(-Wextra-semi-stmt) ADD_FLAG(-Wempty-init-stmt) + ADD_FLAG(-Wuseless-cast) + ADD_FLAG(-Wconversion) ADD_FLAG(-Wno-gnu-zero-variadic-macro-arguments) # Qt (qDebug) is not compatible - if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.14") - ADD_FLAG(-Wextra-semi-stmt) - ADD_FLAG(-Wuseless-cast) - endif() - - if(QT6) - ADD_FLAG(-Wno-shorten-64-to-32) - else() - ADD_FLAG(-Wconversion) - endif() - if(ANDROID OR (INTEGRATED_SDK AND (NOT BUILD_SHARED_LIBS OR NOT BUILD_TESTING))) set(CMAKE_CXX_VISIBILITY_PRESET hidden) endif() @@ -188,6 +178,10 @@ else() if(CMAKE_CXX_FLAGS MATCHES "-Wuseless-cast") list(APPEND INCOMPATIBLE_QT_COMPILER_FLAGS "-Wno-useless-cast") endif() + + if(CMAKE_CXX_FLAGS MATCHES "-Wconversion" AND MAC) + list(APPEND INCOMPATIBLE_QT_COMPILER_FLAGS "-Wno-sign-conversion") + endif() endif() diff --git a/cmake/DVCS.cmake b/cmake/DVCS.cmake index f58307380..a294f343c 100644 --- a/cmake/DVCS.cmake +++ b/cmake/DVCS.cmake @@ -104,15 +104,13 @@ if(DVCS_FOUND) endif() function(CHECK_VERSION _out) - if(PROJECT_VERSION_MINOR) - math(EXPR _odd "${PROJECT_VERSION_MINOR} % 2") - if(_odd OR dvcs_revision) - set(${_out} TRUE PARENT_SCOPE) - return() - endif() + if(PROJECT_VERSION_MINOR GREATER_EQUAL 100 OR PROJECT_VERSION_PATCH GREATER_EQUAL 100 OR dvcs_revision) + set(${_out} TRUE PARENT_SCOPE) + return() endif() set(${_out} FALSE PARENT_SCOPE) endfunction() -CHECK_VERSION(IS_DEVELOPER_VERSION) +CHECK_VERSION(IS_BETA_VERSION) +message(STATUS "DVCS beta: ${IS_BETA_VERSION}") diff --git a/cmake/Helper.cmake b/cmake/Helper.cmake index 6438ba3a8..6b3d77371 100644 --- a/cmake/Helper.cmake +++ b/cmake/Helper.cmake @@ -263,9 +263,6 @@ function(ADD_PLATFORM_LIBRARY _name) endif() if(INCOMPATIBLE_QT_COMPILER_FLAGS) - if(CMAKE_VERSION VERSION_LESS "3.14") - message(WARNING "Compiler flags for mocs with 3.13.x and earlier leads to linker errors") - endif() set_source_files_properties("${_name}_autogen/mocs_compilation.cpp" PROPERTIES COMPILE_OPTIONS "${INCOMPATIBLE_QT_COMPILER_FLAGS}") endif() endfunction() @@ -327,28 +324,6 @@ if((WIN32 AND NOT WINDOWS_STORE) OR LINUX OR MAC OR CYGWIN OR BSD) endif() -if(CMAKE_VERSION VERSION_LESS "3.14") # Use file(SIZE) - function(FILE_SIZE _outSize _file) - if(LINUX) - set(SIZE_COMMAND stat -c "%s" "${_file}") - elseif(MAC) - set(SIZE_COMMAND stat -f "%z" "${_file}") - else() - return() - endif() - - execute_process(COMMAND ${SIZE_COMMAND} - OUTPUT_VARIABLE SIZE_OUTPUT - RESULT_VARIABLE SIZE_RESULT - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) - - if(${SIZE_RESULT} EQUAL 0) - set(${_outSize} ${SIZE_OUTPUT} PARENT_SCOPE) - endif() - endfunction() -endif() - if(NOT COMMAND FIND_HOST_PACKAGE) macro(FIND_HOST_PACKAGE) find_package(${ARGN}) @@ -448,7 +423,7 @@ if(WIN32) if(NOT WIN_SIGN_HASHALGO) set(WIN_SIGN_HASHALGO SHA256) endif() - set(SIGNTOOL_PARAMS sign /v /fd ${WIN_SIGN_HASHALGO} /d AusweisApp2 /du https://www.ausweisapp.bund.de) + set(SIGNTOOL_PARAMS sign /v /fd ${WIN_SIGN_HASHALGO} /d AusweisApp /du https://www.ausweisapp.bund.de) if(WIN_SIGN_SUBJECT_NAME) set(SIGNTOOL_PARAMS ${SIGNTOOL_PARAMS} /n ${WIN_SIGN_SUBJECT_NAME}) diff --git a/cmake/Install.cmake b/cmake/Install.cmake index 73dea883e..5ddcdcd21 100644 --- a/cmake/Install.cmake +++ b/cmake/Install.cmake @@ -46,9 +46,6 @@ set(DEPENDENCY_CHECK " # qt qml plugins (fixup_bundle needs to know this to fetch their dependencies) if((WIN32 OR MAC) AND TARGET ${Qt}::Qml) set(modules QtQuick QtQml Qt) - if (NOT QT6) - list(APPEND modules QtQuick.2) - endif() foreach(entry ${modules}) set(_lib_dir ${QT_INSTALL_ARCHDATA}/qml/${entry}) @@ -83,36 +80,22 @@ if(WIN32) endif() endif() - if (QT6) - if(QT_VERSION VERSION_LESS "6.4") - # Workaround for QTBUG-94066 - include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QSvgPluginTargets.cmake") - include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QGifPluginTargets.cmake") - include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QJpegPluginTargets.cmake") - include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QWindowsIntegrationPluginTargets.cmake") - include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Widgets/Qt6QWindowsVistaStylePluginTargets.cmake") - include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Network/Qt6QTlsBackendOpenSSLPluginTargets.cmake") - endif() - - FETCH_TARGET_LOCATION(openSslBackend "${Qt}::QTlsBackendOpenSSLPlugin") - install(FILES ${openSslBackend} DESTINATION tls COMPONENT Runtime) - list(APPEND LIBS ${openSslBackend}) - endif() + FETCH_TARGET_LOCATION(openSslBackend "${Qt}::QTlsBackendOpenSSLPlugin") + install(FILES ${openSslBackend} DESTINATION tls COMPONENT Runtime) + list(APPEND LIBS ${openSslBackend}) FETCH_TARGET_LOCATION(pluginSvg "${Qt}::QSvgPlugin") FETCH_TARGET_LOCATION(pluginGif "${Qt}::QGifPlugin") FETCH_TARGET_LOCATION(pluginJpeg "${Qt}::QJpegPlugin") - if(WINDOWS_STORE AND NOT QT6) - FETCH_TARGET_LOCATION(platformWin "${Qt}::QWinRTIntegrationPlugin") - else() - FETCH_TARGET_LOCATION(platformWin "${Qt}::QWindowsIntegrationPlugin") - endif() + FETCH_TARGET_LOCATION(pluginWebP "${Qt}::QWebpPlugin") + FETCH_TARGET_LOCATION(platformWin "${Qt}::QWindowsIntegrationPlugin") FETCH_TARGET_LOCATION(styleVista "${Qt}::QWindowsVistaStylePlugin") - install(TARGETS AusweisApp DESTINATION . COMPONENT Application) + install(TARGETS AusweisAppBinary DESTINATION . COMPONENT Application) install(FILES ${pluginSvg} DESTINATION imageformats COMPONENT Runtime) install(FILES ${pluginGif} DESTINATION imageformats COMPONENT Runtime) install(FILES ${pluginJpeg} DESTINATION imageformats COMPONENT Runtime) + install(FILES ${pluginWebP} DESTINATION imageformats COMPONENT Runtime) install(FILES ${platformWin} DESTINATION platforms COMPONENT Runtime) install(FILES ${styleVista} DESTINATION styles COMPONENT Runtime) list(APPEND LIBS ${pluginSvg} ${pluginGif} ${pluginJpeg} ${platformWin} ${styleVista}) @@ -134,8 +117,8 @@ elseif(MAC) set(MACOS_BUNDLE_RESOURCES_DIR ${DEFAULT_FILE_DESTINATION}/../Resources) set(MACOS_BUNDLE_LOGIN_ITEMS_DIR ${DEFAULT_FILE_DESTINATION}/../Library/LoginItems) - install(TARGETS AusweisApp BUNDLE DESTINATION . COMPONENT Application) - install(TARGETS AusweisApp2AutostartHelper BUNDLE DESTINATION ${MACOS_BUNDLE_LOGIN_ITEMS_DIR} COMPONENT Application) + install(TARGETS AusweisAppBinary BUNDLE DESTINATION . COMPONENT Application) + install(TARGETS AusweisAppAutostartHelper BUNDLE DESTINATION ${MACOS_BUNDLE_LOGIN_ITEMS_DIR} COMPONENT Application) function(install_mac_plugins plugins) foreach(plugin ${plugins}) @@ -159,28 +142,22 @@ elseif(MAC) # depend on to be loaded as well, thus resulting in two sets of Qt # libraries being loaded (ours from the bundle and the ones from the # installation) and the program misbehaving (crashing). - if (QT6) - # Workaround for QTBUG-94066 - include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QTuioTouchPluginTargets.cmake") - include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QSvgIconPluginTargets.cmake") - include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QGifPluginTargets.cmake") - include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QICNSPluginTargets.cmake") - include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QICOPluginTargets.cmake") - include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QJpegPluginTargets.cmake") - include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QMacHeifPluginTargets.cmake") - include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QMacJp2PluginTargets.cmake") - include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QSvgPluginTargets.cmake") - include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QCocoaIntegrationPluginTargets.cmake") - include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Widgets/Qt6QMacStylePluginTargets.cmake") - include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Network/Qt6QTlsBackendOpenSSLPluginTargets.cmake") - - set(plugins ${Qt}::QTuioTouchPlugin ${Qt}::QSvgIconPlugin ${Qt}::QGifPlugin ${Qt}::QICNSPlugin ${Qt}::QICOPlugin ${Qt}::QJpegPlugin ${Qt}::QMacHeifPlugin ${Qt}::QMacJp2Plugin ${Qt}::QSvgPlugin ${Qt}::QCocoaIntegrationPlugin ${Qt}::QMacStylePlugin ${Qt}::QTlsBackendOpenSSLPlugin) - install_mac_plugins("${plugins}") - else() - foreach (qtComponent QtCore ${Qt}::Gui ${Qt}::Network ${Qt}::Svg ${Qt}::Widgets) - install_mac_plugins("${${qtComponent}_PLUGINS}") - endforeach() - endif() + # Workaround for QTBUG-94066 + include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QTuioTouchPluginTargets.cmake") + include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QSvgIconPluginTargets.cmake") + include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QGifPluginTargets.cmake") + include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QICNSPluginTargets.cmake") + include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QICOPluginTargets.cmake") + include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QJpegPluginTargets.cmake") + include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QMacHeifPluginTargets.cmake") + include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QMacJp2PluginTargets.cmake") + include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QSvgPluginTargets.cmake") + include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QWebpPluginTargets.cmake") + include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QCocoaIntegrationPluginTargets.cmake") + include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Widgets/Qt6QMacStylePluginTargets.cmake") + include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Network/Qt6QTlsBackendOpenSSLPluginTargets.cmake") + set(plugins ${Qt}::QTuioTouchPlugin ${Qt}::QSvgIconPlugin ${Qt}::QGifPlugin ${Qt}::QICNSPlugin ${Qt}::QICOPlugin ${Qt}::QJpegPlugin ${Qt}::QMacHeifPlugin ${Qt}::QMacJp2Plugin ${Qt}::QSvgPlugin ${Qt}::QWebpPlugin ${Qt}::QCocoaIntegrationPlugin ${Qt}::QMacStylePlugin ${Qt}::QTlsBackendOpenSSLPlugin) + install_mac_plugins("${plugins}") if(TARGET ${Qt}::Qml) foreach(entry QtQuick QtQuick.2 QtQml Qt) @@ -213,13 +190,13 @@ elseif(ANDROID) set(ANDROID_PACKAGE_SRC_DIR ${PROJECT_BINARY_DIR}/package-src-dir) set(ANDROID_DEST libs/${CMAKE_ANDROID_ARCH_ABI}) set(PERMISSIONS PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) - install(TARGETS AusweisApp DESTINATION ${ANDROID_DEST} ${PERMISSIONS} COMPONENT Application) + install(TARGETS AusweisAppBinary DESTINATION ${ANDROID_DEST} ${PERMISSIONS} COMPONENT Application) set(RESOURCES_IMG_ANDROID_DIR ${RESOURCES_DIR}/images/android) if(BUILD_PREVIEW) set(ANDROID_LAUNCHER_ICON "npa_preview.png") set(ANDROID_SPLASH_SCREEN_ICON_NAME "splash_npa_preview.png") - elseif(IS_DEVELOPER_VERSION) + elseif(IS_BETA_VERSION) set(ANDROID_LAUNCHER_ICON "npa_beta.png") set(ANDROID_SPLASH_SCREEN_ICON_NAME "splash_npa_beta.png") else() @@ -229,7 +206,7 @@ elseif(ANDROID) if(INTEGRATED_SDK) set(ANDROID_MANIFEST AndroidManifest.xml.aar.in) - foreach(entry network/WifiInfo ui/aidl/AidlBinder android/LogHandler android/AusweisApp2Service android/AusweisApp2LocalIfdServiceConnection) + foreach(entry network/WifiInfo ui/aidl/AidlBinder android/LogHandler android/BootstrapHelper android/AusweisApp2Service android/AusweisApp2LocalIfdServiceConnection) set(_java_file "${SRC_DIR}/${entry}.java") if(NOT EXISTS "${_java_file}") message(FATAL_ERROR "Cannot find file: ${_java_file}") @@ -251,7 +228,6 @@ elseif(ANDROID) install(FILES ${RESOURCES_IMG_ANDROID_DIR}/${entry}/background_npa.png DESTINATION ${ANDROID_PACKAGE_SRC_DIR}/res/mipmap-${entry} COMPONENT Runtime RENAME npa_background.png) install(FILES ${RESOURCES_IMG_ANDROID_DIR}/${entry}/foreground_${ANDROID_LAUNCHER_ICON} DESTINATION ${ANDROID_PACKAGE_SRC_DIR}/res/mipmap-${entry} COMPONENT Runtime RENAME npa_foreground.png) install(FILES ${RESOURCES_IMG_ANDROID_DIR}/${entry}/monochrome_${ANDROID_LAUNCHER_ICON} DESTINATION ${ANDROID_PACKAGE_SRC_DIR}/res/mipmap-${entry} COMPONENT Runtime RENAME npa_monochrome.png) - install(FILES ${RESOURCES_IMG_ANDROID_DIR}/${entry}/${ANDROID_LAUNCHER_ICON} DESTINATION ${ANDROID_PACKAGE_SRC_DIR}/res/mipmap-${entry} COMPONENT Runtime RENAME npa.png) install(FILES ${RESOURCES_IMG_ANDROID_DIR}/${entry}/${ANDROID_SPLASH_SCREEN_ICON_NAME} DESTINATION ${ANDROID_PACKAGE_SRC_DIR}/res/drawable-${entry} COMPONENT Runtime RENAME splash_npa.png) endforeach() @@ -277,7 +253,7 @@ elseif(ANDROID) configure_file(${PACKAGING_DIR}/android/data_extraction_rules.xml ${ANDROID_PACKAGE_SRC_DIR}/res/xml/data_extraction_rules.xml COPYONLY) endif() - set(ANDROID_SO_NAME libAusweisApp2_${CMAKE_ANDROID_ARCH_ABI}.so) + set(ANDROID_SO_NAME libAusweisApp_${CMAKE_ANDROID_ARCH_ABI}.so) set(ANDROID_APP_BINARY "${CMAKE_INSTALL_PREFIX}/${ANDROID_DEST}/${ANDROID_SO_NAME}") set(SYMBOL_FOLDER "${CMAKE_BINARY_DIR}/debug.symbols") set(ANDROID_APP_SYMBOLS "${SYMBOL_FOLDER}/${ANDROID_SO_NAME}") @@ -288,8 +264,8 @@ elseif(ANDROID) execute_process(COMMAND \"${CMAKE_OBJCOPY}\" \"--only-keep-debug\" \"${ANDROID_APP_BINARY}\" \"${ANDROID_APP_SYMBOLS}\") " COMPONENT Runtime) - set(ANDROID_DEPLOYMENT_SETTINGS ${PROJECT_BINARY_DIR}/libAusweisApp2.so-deployment-settings.json CACHE INTERNAL "apk deployment" FORCE) - configure_file(${PACKAGING_DIR}/android/libAusweisApp2.so-deployment-settings.json.in ${ANDROID_DEPLOYMENT_SETTINGS} @ONLY) + set(ANDROID_DEPLOYMENT_SETTINGS ${PROJECT_BINARY_DIR}/libAusweisApp.so-deployment-settings.json CACHE INTERNAL "apk deployment" FORCE) + configure_file(${PACKAGING_DIR}/android/libAusweisApp.so-deployment-settings.json.in ${ANDROID_DEPLOYMENT_SETTINGS} @ONLY) configure_file(${PACKAGING_DIR}/android/gradle.properties.in ${CMAKE_INSTALL_PREFIX}/gradle.properties @ONLY) set(DEFAULT_FILE_DESTINATION ${ANDROID_PACKAGE_SRC_DIR}/assets) @@ -299,21 +275,21 @@ elseif(UNIX) set(CMAKE_INSTALL_RPATH "\$ORIGIN") endif() - set(DEFAULT_FILE_DESTINATION ${CMAKE_INSTALL_DATADIR}/${VENDOR}/AusweisApp2) - install(TARGETS AusweisApp DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Application) + set(DEFAULT_FILE_DESTINATION ${CMAKE_INSTALL_DATADIR}/${VENDOR}/AusweisApp) + install(TARGETS AusweisAppBinary DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Application) if(NOT CONTAINER_SDK) configure_file(${PACKAGING_DIR}/linux/${BUNDLE_IDENTIFIER}.metainfo.xml.in ${CMAKE_CURRENT_BINARY_DIR}/${BUNDLE_IDENTIFIER}.metainfo.xml @ONLY) configure_file(${PACKAGING_DIR}/linux/${BUNDLE_IDENTIFIER}.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/${BUNDLE_IDENTIFIER}.desktop @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${BUNDLE_IDENTIFIER}.metainfo.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/metainfo COMPONENT Application) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${BUNDLE_IDENTIFIER}.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications COMPONENT Application) - install(FILES ${RESOURCES_DIR}/images/npa.svg DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/scalable/apps COMPONENT Application RENAME AusweisApp2.svg) - install(FILES ${RESOURCES_DIR}/images/npa.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/96x96/apps COMPONENT Application RENAME AusweisApp2.png) - install(FILES ${DOCS_DIR}/AusweisApp2.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 COMPONENT Application) + install(FILES ${RESOURCES_DIR}/images/npa.svg DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/scalable/apps COMPONENT Application RENAME AusweisApp.svg) + install(FILES ${RESOURCES_DIR}/images/npa.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/96x96/apps COMPONENT Application RENAME AusweisApp.png) + install(FILES ${DOCS_DIR}/AusweisApp.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 COMPONENT Application) endif() - # This is for internal use only! It is not recommended to split the AusweisApp2 into multiple libs! + # This is for internal use only! It is not recommended to split the AusweisApp into multiple libs! if(BUILD_SHARED_LIBS) - target_get_linked_libraries(AusweisApp libraries) + target_get_linked_libraries(AusweisAppBinary libraries) foreach(libTarget ${libraries}) install(TARGETS ${libTarget} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Application) endforeach() diff --git a/cmake/Libraries.cmake b/cmake/Libraries.cmake index 8e47744f2..6e28a9d42 100644 --- a/cmake/Libraries.cmake +++ b/cmake/Libraries.cmake @@ -1,13 +1,9 @@ # Set CMAKE_PREFIX_PATH with toolchain directory -if(MINGW AND CMAKE_VERSION VERSION_LESS 3.17.0) - set(CMAKE_FIND_LIBRARY_SUFFIXES ".dll.a" ".a" ".lib") -endif() - if(DESKTOP) - set(MIN_QT_VERSION 5.15) + set(MIN_QT_VERSION 6.4) else() - set(MIN_QT_VERSION 6.2) + set(MIN_QT_VERSION 6.5) endif() if(IOS OR ANDROID) @@ -29,41 +25,23 @@ if(IOS OR ANDROID) set(CMAKE_FIND_ROOT_PATH ${CMAKE_FIND_ROOT_PATH} ${QT_HOST_PATH} ) endif() -if(NOT DEFINED Qt) - find_package(Qt6 ${MIN_QT_VERSION} COMPONENTS Core CMAKE_FIND_ROOT_PATH_BOTH) - if(TARGET Qt6::Core) - set(Qt Qt6) - else() - set(Qt Qt5) - endif() -endif() -find_package(${Qt} ${MIN_QT_VERSION} COMPONENTS Core Concurrent Network REQUIRED CMAKE_FIND_ROOT_PATH_BOTH) -include(Compat) - -if(QT6) - list(APPEND QT_COMPONENTS StateMachine) -endif() +set(Qt Qt6) +find_package(${Qt} ${MIN_QT_VERSION} COMPONENTS Core Concurrent Network StateMachine REQUIRED CMAKE_FIND_ROOT_PATH_BOTH) +set(QT_VERSION "${Qt6Core_VERSION}") if(NOT CONTAINER_SDK) list(APPEND QT_COMPONENTS LinguistTools) endif() if(NOT INTEGRATED_SDK) - list(APPEND QT_COMPONENTS Svg WebSockets Qml Quick QuickControls2 QuickTemplates2 QmlWorkerScript) - - if(NOT DESKTOP AND NOT QT6) - list(APPEND QT_COMPONENTS QuickShapes) - endif() - if(QT6) - list(APPEND QT_COMPONENTS ShaderTools) - endif() + list(APPEND QT_COMPONENTS Svg WebSockets Qml Quick QuickControls2 QuickTemplates2 QmlWorkerScript ShaderTools) endif() if(DESKTOP AND NOT INTEGRATED_SDK) list(APPEND QT_COMPONENTS Widgets) endif() -if(ANDROID OR IOS OR WINDOWS_STORE OR (QT6 AND CMAKE_BUILD_TYPE STREQUAL "DEBUG")) +if(ANDROID OR IOS OR WINDOWS_STORE OR CMAKE_BUILD_TYPE STREQUAL "DEBUG") list(APPEND QT_COMPONENTS Nfc) endif() @@ -98,7 +76,7 @@ if(MINGW AND NOT CMAKE_CROSSCOMPILING) set(CMAKE_CROSSCOMPILING ON) endif() -set(MIN_OPENSSL_VERSION 1.1) +set(MIN_OPENSSL_VERSION 1.1.1) find_package(OpenSSL ${MIN_OPENSSL_VERSION} REQUIRED) if(tmp_crosscompile_enabled) diff --git a/cmake/Packaging.cmake b/cmake/Packaging.cmake index f2dfbe911..7cf02126b 100644 --- a/cmake/Packaging.cmake +++ b/cmake/Packaging.cmake @@ -27,6 +27,8 @@ if(ANDROID AND INTEGRATED_SDK) string(TOLOWER "${PROJECT_NAME}-" AAR_PROJECT_NAME) string(REGEX REPLACE "[0-9]*-" "-" AAR_PROJECT_NAME "${AAR_PROJECT_NAME}") set(FILENAME ${AAR_PROJECT_NAME}${PACKAGE_VERSION}) +elseif(IOS AND INTEGRATED_SDK) + set(FILENAME ${PROJECT_NAME}2-${PACKAGE_VERSION}) else() set(FILENAME ${PROJECT_NAME}-${PACKAGE_VERSION}) endif() @@ -39,7 +41,7 @@ set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH}) set(CPACK_PACKAGE_VERSION_TWEAK ${PROJECT_VERSION_TWEAK}) set(CPACK_PACKAGE_VENDOR "${VENDOR}") set(CPACK_PACKAGE_CONTACT "support@ausweisapp.de") -set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Governikus AusweisApp2") +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "AusweisApp") set(CPACK_PACKAGE_FILE_NAME ${FILENAME}) set(CPACK_PACKAGE_INSTALL_DIRECTORY ${PROJECT_NAME}) if(NOT CONTAINER_SDK) @@ -92,7 +94,7 @@ list(APPEND CPACK_SOURCE_IGNORE_FILES "\\\\.project") list(APPEND CPACK_SOURCE_IGNORE_FILES "\\\\.cproject") list(APPEND CPACK_SOURCE_IGNORE_FILES "\\\\.reviewboardrc") list(APPEND CPACK_SOURCE_IGNORE_FILES ".*\\\\.internal\\\\.cmake$") -list(APPEND CPACK_SOURCE_IGNORE_FILES "utils") +list(APPEND CPACK_SOURCE_IGNORE_FILES "${CMAKE_SOURCE_DIR}/utils/") set(CPACK_MONOLITHIC_INSTALL true) @@ -144,10 +146,7 @@ elseif(APPLE) set(CPACK_DMG_BACKGROUND_IMAGE ${RESOURCES_DIR}/images/macos/dmg_background.png) set(CPACK_DMG_SLA_DIR ${MACOS_PACKAGING_DIR}/sla) set(CPACK_DMG_SLA_LANGUAGES English German) - - # We can not generate the DS_STORE on each build since jenkins runs headless - #set(CPACK_DMG_DS_STORE_SETUP_SCRIPT ${MACOS_PACKAGING_DIR}/prepare-ds_store.applescript) - set(CPACK_DMG_DS_STORE ${MACOS_PACKAGING_DIR}/DS_Store) + set(CPACK_DMG_DS_STORE_SETUP_SCRIPT ${MACOS_PACKAGING_DIR}/prepare-ds_store.applescript) elseif(ANDROID) find_program(androiddeployqt androiddeployqt CMAKE_FIND_ROOT_PATH_BOTH) @@ -218,7 +217,7 @@ elseif(ANDROID) set(ANDROID_FILE dist-release.aar) elseif(APK_SIGN_KEYSTORE AND APK_SIGN_KEYSTORE_ALIAS AND APK_SIGN_KEYSTORE_PSW) message(STATUS "Release build will be signed using: ${APK_SIGN_KEYSTORE} | Alias: ${APK_SIGN_KEYSTORE_ALIAS}") - set(DEPLOY_CMD_SIGN --sign ${APK_SIGN_KEYSTORE} ${APK_SIGN_KEYSTORE_ALIAS} --storepass ${APK_SIGN_KEYSTORE_PSW} --digestalg SHA-256 --sigalg SHA256WithRSA) + set(DEPLOY_CMD_SIGN ${DEPLOY_CMD_SIGN} --sign ${APK_SIGN_KEYSTORE} ${APK_SIGN_KEYSTORE_ALIAS} --storepass ${APK_SIGN_KEYSTORE_PSW} --digestalg SHA-256 --sigalg SHA256WithRSA) set(ANDROID_FILE dist-release-signed.apk) else() set(ANDROID_FILE dist-release-unsigned.apk) @@ -226,7 +225,7 @@ elseif(ANDROID) endif() endif() - set(DEPLOY_CMD ${androiddeployqt} --verbose --gradle --input ${ANDROID_DEPLOYMENT_SETTINGS} --android-platform ${ANDROID_TARGET_SDK_VERSION} --output ${CMAKE_INSTALL_PREFIX} ${DEPLOY_CMD_SIGN}) + set(DEPLOY_CMD ${androiddeployqt} --verbose --gradle --input ${ANDROID_DEPLOYMENT_SETTINGS} --android-platform android-${ANDROID_TARGET_SDK_VERSION} --output ${CMAKE_INSTALL_PREFIX} ${DEPLOY_CMD_SIGN}) set(SOURCE_ANDROID_FILE ${CMAKE_INSTALL_PREFIX}/build/outputs/${ANDROID_FILE_EXT}) if(NOT INTEGRATED_SDK) diff --git a/cmake/Policies.cmake b/cmake/Policies.cmake new file mode 100644 index 000000000..c556daec6 --- /dev/null +++ b/cmake/Policies.cmake @@ -0,0 +1,47 @@ +if(POLICY CMP0020) + cmake_policy(SET CMP0020 NEW) +endif() + +if(POLICY CMP0023) + cmake_policy(SET CMP0023 NEW) +endif() + +if(POLICY CMP0046) + cmake_policy(SET CMP0046 NEW) +endif() + +if(POLICY CMP0048) + cmake_policy(SET CMP0048 NEW) +endif() + +if(POLICY CMP0054) + cmake_policy(SET CMP0054 NEW) +endif() + +if(POLICY CMP0063) + cmake_policy(SET CMP0063 NEW) +endif() + +if(POLICY CMP0071) + cmake_policy(SET CMP0071 NEW) +endif() + +if(POLICY CMP0072) + cmake_policy(SET CMP0072 NEW) +endif() + +if(POLICY CMP0074) + cmake_policy(SET CMP0074 NEW) +endif() + +if(POLICY CMP0076) + cmake_policy(SET CMP0076 NEW) +endif() + +if(POLICY CMP0092) + cmake_policy(SET CMP0092 NEW) +endif() + +if(POLICY CMP0099) + cmake_policy(SET CMP0099 NEW) +endif() \ No newline at end of file diff --git a/cmake/SignFiles.cmake.in b/cmake/SignFiles.cmake.in index ba32a7591..f9a2d3e25 100644 --- a/cmake/SignFiles.cmake.in +++ b/cmake/SignFiles.cmake.in @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1.0) +cmake_minimum_required(VERSION 3.19.0) if(APPLE AND NOT IOS) string(FIND "${CMAKE_BINARY_DIR}" "DragNDrop" IS_DMG) diff --git a/cmake/Tools.cmake b/cmake/Tools.cmake index 132bfddda..135ea668f 100644 --- a/cmake/Tools.cmake +++ b/cmake/Tools.cmake @@ -118,7 +118,7 @@ endif() find_program(PYTHON python CMAKE_FIND_ROOT_PATH_BOTH) if(PYTHON) list(APPEND GLOB_JSON ${RESOURCES_DIR}/updatable-files/*.json) - list(APPEND GLOB_JSON ${RESOURCES_DIR}/json-schemas/*.json) + list(APPEND GLOB_JSON ${TEST_DIR}/json/*.json) file(GLOB_RECURSE JSON_FILES ${GLOB_JSON}) foreach(JSON_FILE ${JSON_FILES}) @@ -154,7 +154,7 @@ endfunction() find_program(INKSCAPE inkscape CMAKE_FIND_ROOT_PATH_BOTH) if(INKSCAPE) - set(BACKGROUND_COLOR "#dcebf6") + set(BACKGROUND_COLOR "#ffffff") add_custom_target(npaicons.general COMMAND ${INKSCAPE} npa_release.svg -d 320 -y 0 -o npa.png @@ -165,33 +165,6 @@ if(INKSCAPE) COMMAND ${INKSCAPE} playstore_preview.svg -w 512 -h 512 -y 0 -o playstore_preview.png WORKING_DIRECTORY ${RESOURCES_DIR}/images/android) - add_custom_target(npaicons.android.legacy - COMMAND ${INKSCAPE} npa_release.svg -d 120 -y 0 -o android/ldpi/npa.png - COMMAND ${INKSCAPE} npa_release.svg -d 160 -y 0 -o android/mdpi/npa.png - COMMAND ${INKSCAPE} npa_release.svg -d 240 -y 0 -o android/hdpi/npa.png - COMMAND ${INKSCAPE} npa_release.svg -d 320 -y 0 -o android/xhdpi/npa.png - COMMAND ${INKSCAPE} npa_release.svg -d 480 -y 0 -o android/xxhdpi/npa.png - COMMAND ${INKSCAPE} npa_release.svg -d 640 -y 0 -o android/xxxhdpi/npa.png - WORKING_DIRECTORY ${RESOURCES_DIR}/images) - - add_custom_target(npaicons.android.legacy.beta - COMMAND ${INKSCAPE} npa_beta.svg -d 120 -y 0 -o android/ldpi/npa_beta.png - COMMAND ${INKSCAPE} npa_beta.svg -d 160 -y 0 -o android/mdpi/npa_beta.png - COMMAND ${INKSCAPE} npa_beta.svg -d 240 -y 0 -o android/hdpi/npa_beta.png - COMMAND ${INKSCAPE} npa_beta.svg -d 320 -y 0 -o android/xhdpi/npa_beta.png - COMMAND ${INKSCAPE} npa_beta.svg -d 480 -y 0 -o android/xxhdpi/npa_beta.png - COMMAND ${INKSCAPE} npa_beta.svg -d 640 -y 0 -o android/xxxhdpi/npa_beta.png - WORKING_DIRECTORY ${RESOURCES_DIR}/images) - - add_custom_target(npaicons.android.legacy.preview - COMMAND ${INKSCAPE} npa_preview.svg -d 120 -y 0 -o android/ldpi/npa_preview.png - COMMAND ${INKSCAPE} npa_preview.svg -d 160 -y 0 -o android/mdpi/npa_preview.png - COMMAND ${INKSCAPE} npa_preview.svg -d 240 -y 0 -o android/hdpi/npa_preview.png - COMMAND ${INKSCAPE} npa_preview.svg -d 320 -y 0 -o android/xhdpi/npa_preview.png - COMMAND ${INKSCAPE} npa_preview.svg -d 480 -y 0 -o android/xxhdpi/npa_preview.png - COMMAND ${INKSCAPE} npa_preview.svg -d 640 -y 0 -o android/xxxhdpi/npa_preview.png - WORKING_DIRECTORY ${RESOURCES_DIR}/images) - add_custom_target(npaicons.android.adaptive.background COMMAND ${INKSCAPE} adaptive_background.svg -d 120 -y 0 -o ldpi/background_npa.png COMMAND ${INKSCAPE} adaptive_background.svg -d 160 -y 0 -o mdpi/background_npa.png @@ -333,9 +306,6 @@ if(INKSCAPE) add_custom_target(npaicons DEPENDS npaicons.general npaicons.android.playstore - npaicons.android.legacy - npaicons.android.legacy.beta - npaicons.android.legacy.preview npaicons.android.adaptive.background npaicons.android.adaptive.foreground npaicons.android.adaptive.foreground.beta @@ -359,11 +329,6 @@ if(INKSCAPE) COMMAND ${INKSCAPE} img_Simulator.svg -w 512 -h 512 -y 0 -o ${RESOURCES_DIR}/updatable-files/reader/img_Simulator.png COMMAND ${INKSCAPE} img_Simulator_mit_ausweis.svg -w 512 -h 512 -y 0 -o ${RESOURCES_DIR}/updatable-files/reader/img_Simulator_mit_ausweis.png WORKING_DIRECTORY ${RESOURCES_DIR}/images/reader/src) - - add_custom_target(tutorialimages - COMMAND ${INKSCAPE} phone_screen_de.svg -w 585 -h 622 -y 0 -o ${RESOURCES_DIR}/images/tutorial/phone_screen_de.png - COMMAND ${INKSCAPE} phone_screen_en.svg -w 585 -h 622 -y 0 -o ${RESOURCES_DIR}/images/tutorial/phone_screen_en.png - WORKING_DIRECTORY ${RESOURCES_DIR}/images/tutorial/src) endif() find_program(PNGQUANT pngquant CMAKE_FIND_ROOT_PATH_BOTH) @@ -374,33 +339,6 @@ if(PNGQUANT) COMMAND ${PNGQUANT_CMD} npa.png -- npa.png WORKING_DIRECTORY ${RESOURCES_DIR}/images) - add_custom_target(pngquant.android.legacy - COMMAND ${PNGQUANT_CMD} ldpi/npa.png -- ldpi/npa.png - COMMAND ${PNGQUANT_CMD} mdpi/npa.png -- mdpi/npa.png - COMMAND ${PNGQUANT_CMD} hdpi/npa.png -- hdpi/npa.png - COMMAND ${PNGQUANT_CMD} xhdpi/npa.png -- xhdpi/npa.png - COMMAND ${PNGQUANT_CMD} xxhdpi/npa.png -- xxhdpi/npa.png - COMMAND ${PNGQUANT_CMD} xxxhdpi/npa.png -- xxxhdpi/npa.png - WORKING_DIRECTORY ${RESOURCES_DIR}/images/android) - - add_custom_target(pngquant.android.legacy.beta - COMMAND ${PNGQUANT_CMD} ldpi/npa_beta.png -- ldpi/npa_beta.png - COMMAND ${PNGQUANT_CMD} mdpi/npa_beta.png -- mdpi/npa_beta.png - COMMAND ${PNGQUANT_CMD} hdpi/npa_beta.png -- hdpi/npa_beta.png - COMMAND ${PNGQUANT_CMD} xhdpi/npa_beta.png -- xhdpi/npa_beta.png - COMMAND ${PNGQUANT_CMD} xxhdpi/npa_beta.png -- xxhdpi/npa_beta.png - COMMAND ${PNGQUANT_CMD} xxxhdpi/npa_beta.png -- xxxhdpi/npa_beta.png - WORKING_DIRECTORY ${RESOURCES_DIR}/images/android) - - add_custom_target(pngquant.android.legacy.preview - COMMAND ${PNGQUANT_CMD} ldpi/npa_preview.png -- ldpi/npa_preview.png - COMMAND ${PNGQUANT_CMD} mdpi/npa_preview.png -- mdpi/npa_preview.png - COMMAND ${PNGQUANT_CMD} hdpi/npa_preview.png -- hdpi/npa_preview.png - COMMAND ${PNGQUANT_CMD} xhdpi/npa_preview.png -- xhdpi/npa_preview.png - COMMAND ${PNGQUANT_CMD} xxhdpi/npa_preview.png -- xxhdpi/npa_preview.png - COMMAND ${PNGQUANT_CMD} xxxhdpi/npa_preview.png -- xxxhdpi/npa_preview.png - WORKING_DIRECTORY ${RESOURCES_DIR}/images/android) - add_custom_target(pngquant.android.adaptive.background COMMAND ${PNGQUANT_CMD} ldpi/background_npa.png -- ldpi/background_npa.png COMMAND ${PNGQUANT_CMD} mdpi/background_npa.png -- mdpi/background_npa.png @@ -541,9 +479,6 @@ if(PNGQUANT) add_custom_target(pngquant DEPENDS pngquant.general - pngquant.android.legacy - pngquant.android.legacy.beta - pngquant.android.legacy.preview pngquant.android.adaptive.background pngquant.android.adaptive.foreground pngquant.android.adaptive.foreground.beta @@ -567,11 +502,6 @@ if(PNGQUANT) COMMAND ${PNGQUANT_CMD} img_Simulator.png -- img_Simulator.png COMMAND ${PNGQUANT_CMD} img_Simulator_mit_ausweis.png -- img_Simulator_mit_ausweis.png WORKING_DIRECTORY ${RESOURCES_DIR}/updatable-files/reader) - - add_custom_target(pngquant.tutorialimages - COMMAND ${PNGQUANT_CMD} phone_screen_de.png -- phone_screen_de.png - COMMAND ${PNGQUANT_CMD} phone_screen_en.png -- phone_screen_en.png - WORKING_DIRECTORY ${RESOURCES_DIR}/images/tutorial) endif() find_program(CONVERT convert CMAKE_FIND_ROOT_PATH_BOTH) diff --git a/cmake/Translation.cmake.in b/cmake/Translation.cmake.in index 941cab92a..d276ead4d 100644 --- a/cmake/Translation.cmake.in +++ b/cmake/Translation.cmake.in @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1.0) +cmake_minimum_required(VERSION 3.5.0) foreach(file @TRANSLATION_FILES@) message(STATUS "Adding DvcsAttributes to ${file}") diff --git a/cmake/android.toolchain.cmake b/cmake/android.toolchain.cmake index a509852ae..51635da33 100644 --- a/cmake/android.toolchain.cmake +++ b/cmake/android.toolchain.cmake @@ -55,8 +55,8 @@ READ_REVISION(ANDROID_NDK_REVISION ".*Revision = ([0-9|\\.]+)" "${CMAKE_ANDROID_ set(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION clang) set(CMAKE_SYSTEM_NAME Android) -set(CMAKE_SYSTEM_VERSION 24) -set(ANDROID_TARGET_SDK_VERSION 33) +set(CMAKE_SYSTEM_VERSION 26) +set(ANDROID_TARGET_SDK_VERSION 34) set(CMAKE_ANDROID_STL_TYPE c++_shared) if(NOT CMAKE_ANDROID_ARCH_ABI) diff --git a/cmake/iOS.bundles.cmake.in b/cmake/iOS.bundles.cmake.in index 947166c48..59bf104c7 100644 --- a/cmake/iOS.bundles.cmake.in +++ b/cmake/iOS.bundles.cmake.in @@ -14,7 +14,7 @@ function(SELF_GENERATED) endfunction() if(INTEGRATED_SDK) - set(Bundle @PROJECT_NAME@.framework) + set(Bundle @PROJECT_NAME@2.framework) else() set(Bundle @PROJECT_NAME@.app) endif() diff --git a/cmake/iOS.toolchain.cmake b/cmake/iOS.toolchain.cmake index 8ff094fdb..86d66b092 100644 --- a/cmake/iOS.toolchain.cmake +++ b/cmake/iOS.toolchain.cmake @@ -6,7 +6,7 @@ if(NOT CMAKE_OSX_ARCHITECTURES) set(CMAKE_OSX_ARCHITECTURES arm64) endif() -set(CMAKE_OSX_DEPLOYMENT_TARGET 13.0) +set(CMAKE_OSX_DEPLOYMENT_TARGET 14.0) set(UNIX True) set(APPLE True) diff --git a/cmake/prepare_sonarqube_env.cmake b/cmake/prepare_sonarqube_env.cmake index cdda5c055..5ce9404d0 100644 --- a/cmake/prepare_sonarqube_env.cmake +++ b/cmake/prepare_sonarqube_env.cmake @@ -13,20 +13,20 @@ message(STATUS "Use PACKAGES_DIR: ${PACKAGES_DIR}") set(BUILDWRAPPER_ZIP_NAME build-wrapper-linux-x86.zip) set(BUILDWRAPPER_URL https://sonar.govkg.de/static/cpp/${BUILDWRAPPER_ZIP_NAME}) -set(SONARSCANNERCLI_VERSION 4.8.0.2856-linux) # https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/ +set(SONARSCANNERCLI_VERSION 5.0.1.3006-linux) # https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/ set(SONARSCANNERCLI_ZIP_NAME sonar-scanner-cli-${SONARSCANNERCLI_VERSION}.zip) set(SONARSCANNERCLI_URL https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/${SONARSCANNERCLI_ZIP_NAME}) -set(SONARSCANNERCLI_HASH 45a9a54dfe5f58b554e9b40ad3becbf9871a4eddb1c2892b67cf191cdd891754) +set(SONARSCANNERCLI_HASH 350dbdb517c10fcb3ce70425db95c415b313cad7296c407d416d88f3d50121f8) -set(DEPENDENCYCHECK_VERSION 8.1.0) # https://github.com/jeremylong/DependencyCheck/releases +set(DEPENDENCYCHECK_VERSION 8.4.0) # https://github.com/jeremylong/DependencyCheck/releases set(DEPENDENCYCHECK_ZIP_NAME dependency-check-${DEPENDENCYCHECK_VERSION}-release.zip) set(DEPENDENCYCHECK_URL https://github.com/jeremylong/DependencyCheck/releases/download/v${DEPENDENCYCHECK_VERSION}/${DEPENDENCYCHECK_ZIP_NAME}) -set(DEPENDENCYCHECK_HASH a87231139f7a3de8e9fec2fa4353a9b21bd0397a4540fa24e91a8716e9e6e74e) +set(DEPENDENCYCHECK_HASH 937a6bf8ced9d8494767082c1f588f26ea379324cb089dabb045321e8b0ab01a) -set(MARIADB_CONNECTOR_VERSION 3.1.2) +set(MARIADB_CONNECTOR_VERSION 3.2.0) set(MARIADB_CONNECTOR_ZIP_NAME mariadb-java-client-${MARIADB_CONNECTOR_VERSION}.jar) set(MARIADB_CONNECTOR_URL https://downloads.mariadb.com/Connectors/java/connector-java-${MARIADB_CONNECTOR_VERSION}/${MARIADB_CONNECTOR_ZIP_NAME}) -set(MARIADB_CONNECTOR_HASH aaec1ad348d030a65b25c93c65cdaf472bf8b4b6b314b965e5ba13aec81bc622) +set(MARIADB_CONNECTOR_HASH adf9df10bc9b2a137def36d6a495812258f430d4a8f7946727c61558e6c73941) set(SONARQUBETOOLS_DIR ${CMAKE_BINARY_DIR}/sonarqubetools) diff --git a/cmake/tests/openssl.cpp b/cmake/tests/openssl.cpp index 1eaeac01c..78d90ffa2 100644 --- a/cmake/tests/openssl.cpp +++ b/cmake/tests/openssl.cpp @@ -27,15 +27,15 @@ int main() { - // It is required that Qt and AusweisApp2 uses the library and the same version. + // It is required that Qt and AusweisApp uses the library and the same version. // Also this binary will crash if your libraries aren't binary compatible. For example - // this occurs if you link Qt against OpenSSL and the AusweisApp2 against LibreSSL. + // this occurs if you link Qt against OpenSSL and the AusweisApp against LibreSSL. if (QSslSocket::sslLibraryVersionString() != QLatin1String(OpenSSL_version(OPENSSL_VERSION))) { return 1; } - // The AusweisApp2 requires at least one of an RSA-PSK cipher. LibreSSL and OpenSSL <= 1.0.2 does not support that! + // The AusweisApp requires at least one of an RSA-PSK cipher. LibreSSL and OpenSSL <= 1.0.2 does not support that! const QStringList ciphers({"RSA-PSK-AES256-GCM-SHA384", "RSA-PSK-AES256-CBC-SHA384", "RSA-PSK-AES128-GCM-SHA256", "RSA-PSK-AES128-CBC-SHA256", "RSA-PSK-AES256-CBC-SHA"}); return std::any_of(ciphers.constBegin(), ciphers.constEnd(), [](const QString& pCipherName) { diff --git a/docs/AusweisApp2.1 b/docs/AusweisApp.1 similarity index 70% rename from docs/AusweisApp2.1 rename to docs/AusweisApp.1 index cb38aa42c..b3e585f9a 100644 --- a/docs/AusweisApp2.1 +++ b/docs/AusweisApp.1 @@ -1,17 +1,17 @@ -.TH AusweisApp2 1 +.TH AusweisApp 1 .SH NAME -AusweisApp2 \- Official authentication app for German ID cards and residence permits +AusweisApp \- Official authentication app for German ID cards and residence permits .SH SYNOPSIS -AusweisApp2 [-h|--help] +AusweisApp [-h|--help] .br -AusweisApp2 [--help-all] +AusweisApp [--help-all] .br -AusweisApp2 [-v|--version] +AusweisApp [-v|--version] .br -AusweisApp2 [--show] +AusweisApp [--show] .br -AusweisApp2 +AusweisApp [--keep] [--no-logfile] [--no-loghandler] @@ -22,7 +22,7 @@ AusweisApp2 [--address \fI\,ADDRESS\/\fR] .SH DESCRIPTION -AusweisApp2 allows you to authenticate yourself against websites via your German +AusweisApp allows you to authenticate yourself against websites via your German ID card and residence permits. You will need: @@ -32,13 +32,13 @@ You will need: * A compatible NFC device (most NFC readers should work, NFC-enabled phones can * also be used) .br -* AusweisApp2 +* AusweisApp .br * A browser .br * A website that supports authentication via German ID card -When you visit such a website, AusweisApp2 will be triggered and will ask you if +When you visit such a website, AusweisApp will be triggered and will ask you if you want to authenticate against the website. This program will provide a local webserver for your browser to interface against. @@ -60,13 +60,13 @@ Displays version information. .TP .B --keep .br -By default, AusweisApp2 writes a log to a file matching -${TMP}/AusweisApp2.*.log. When the program terminates, it will be deleted. This +By default, AusweisApp writes a log to a file matching +${TMP}/AusweisApp.*.log. When the program terminates, it will be deleted. This setting prevents deletion. .TP .B --no-logfile -Suppress writing a log file to ${TMP}/AusweisApp2.*.log. Logs will still be +Suppress writing a log file to ${TMP}/AusweisApp.*.log. Logs will still be written to STDOUT. .TP @@ -86,7 +86,7 @@ Disable system proxy. This option allows multiple values. - "qml" will start the program with a visible UI. - "websocket" will let it start in the background as an SDK. This is only useful when integrating -AusweisApp2 into other programs. +AusweisApp into other programs. - "webservice" starts listening on given port/address. Default is "qml,webservice,websocket". @@ -94,17 +94,17 @@ Default is "qml,webservice,websocket". .TP .B --port \fI\,PORT\/\fR Change the listening port for the WebSocket. Default is 24727. Selecting "0" is -a special case. AusweisApp2 will then select a random port and write the port -number to a file in ${TMP}/AusweisApp2..port. +a special case. AusweisApp will then select a random port and write the port +number to a file in ${TMP}/AusweisApp..port. .TP .B --address \fI\,ADDRESS\/\fR -Use given addresses for interface binding. Normally AusweisApp2 is bound to +Use given addresses for interface binding. Normally AusweisApp is bound to localhost only as it is a security requirement. Useful for testing only. This option allows multiple values. .SH "RETURN VALUE" -AusweisApp2 will return 0 when successfully terminated. +AusweisApp will return 0 when successfully terminated. .SH ENVIRONMENT .TP .B QT_QPA_PLATFORM={ wayland|X11 } @@ -113,7 +113,7 @@ debugging purposes. XDG_SESSION_TYPE will be ignored on gnome. .SH FILES -\fI~/.config/AusweisApp2_CE/AusweisApp2.conf\fR +\fI~/.config/AusweisApp_CE/AusweisApp2.conf\fR File path where the user config is saved. .SH CAVEATS diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index 926af3e29..c9b41e12c 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -3,9 +3,7 @@ if(SPHINX_FOUND) SPHINX_GEN("${CMAKE_CURRENT_SOURCE_DIR}/sdk" "sdk" BUILDER changes html latex DEFAULT_LANG en) - SPHINX_GEN("${CMAKE_CURRENT_SOURCE_DIR}/installation" "inst" BUILDER changes html latex) - - SPHINX_GEN("${CMAKE_CURRENT_SOURCE_DIR}/integration" "inte" BUILDER changes html latex) + SPHINX_GEN("${CMAKE_CURRENT_SOURCE_DIR}/installation" "installation_integration" BUILDER changes html latex) SPHINX_GEN("${CMAKE_CURRENT_SOURCE_DIR}/failurecodes" "failurecodes" BUILDER changes html latex DEFAULT_LANG en) else() diff --git a/docs/failurecodes/conf.py.in b/docs/failurecodes/conf.py.in index 712dafe44..cf14817dd 100644 --- a/docs/failurecodes/conf.py.in +++ b/docs/failurecodes/conf.py.in @@ -41,7 +41,7 @@ source_suffix = '.rst' master_doc = 'index' # General information about the project. -project = 'AusweisApp2 Failure Codes' +project = '@PROJECT_NAME@ Failure Codes' copyright = '2023, Governikus GmbH & Co. KG' author = 'Governikus GmbH & Co. KG' @@ -96,7 +96,7 @@ html_show_copyright = True html_scaled_image_link = False # Output file base name for HTML help builder. -htmlhelp_basename = 'AusweisApp2ReleaseNotes' +htmlhelp_basename = '@PROJECT_NAME@ReleaseNotes' html_context = { 'display_github': False, @@ -119,7 +119,7 @@ latex_elements = { # Additional stuff for the LaTeX preamble. 'preamble': ''' \hypersetup{pdfauthor={Governikus GmbH \& Co. KG}, - pdftitle={AusweisApp2}, + pdftitle={@PROJECT_NAME@}, pdfsubject={Failure_Codes}, pdfkeywords={failure, codes, sdk, api}, pdfproducer={LaTeX}, @@ -143,7 +143,7 @@ latex_elements = { # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'AusweisApp2-@VERSION_DVCS@-Failure-Codes-' + language + '.tex', 'AusweisApp2 Failure Codes', + (master_doc, '@PROJECT_NAME@-@VERSION_DVCS@-Failure-Codes-' + language + '.tex', '@PROJECT_NAME@ Failure Codes', 'Governikus GmbH \& Co. KG', 'howto'), ] @@ -166,3 +166,7 @@ latex_show_urls = 'footnote' # If false, no module index is generated. #latex_domain_indices = True + +rst_epilog = """ +.. |AppName| replace:: @PROJECT_NAME@ +""" \ No newline at end of file diff --git a/docs/failurecodes/failurecodes.rst b/docs/failurecodes/failurecodes.rst index 1e880d5e0..01d68899a 100644 --- a/docs/failurecodes/failurecodes.rst +++ b/docs/failurecodes/failurecodes.rst @@ -1,6 +1,6 @@ Failure Codes ============= -The AusweisApp2 will send failure codes indicating what went wrong and where it happened as well as +The |AppName| will send failure codes indicating what went wrong and where it happened as well as how to solve it. Helpful tips @@ -25,14 +25,14 @@ Contact support If the provided failure code did not help to resolve the issue, please contact the support (https://www.ausweisapp.bund.de/en/help-and-support), including the error code, situation description, and logfile, so that they can identify issues in your system configuration or -AusweisApp2. If you are using the AusweisApp2 you will find the logfile in the Help section. +|AppName|. If you are using the |AppName| you will find the logfile in the Help section. .. _failure_code_inform_service_provider: Inform service provider ^^^^^^^^^^^^^^^^^^^^^^^ Directly notify the service provider if the failure code contained an incorrect TLS or service -configuration. Usually the the service provider contact information are available on the website on +configuration. Usually the service provider contact information are available on the website on which you have started the authentication. .. _failure_code_fix_connections_problems: @@ -44,7 +44,7 @@ current connection. Verify an active internet connection, by opening e.g. https://www.ausweisapp.bund.de in the browser of your choice. This includes checking your firewall and antivirus configuration as well as your local network hardware. Ultimately the problem may be with your telecommunications provider, or the service provider. Please refer to the attached -\"Network_Error\" for details. If you are using the AusweisApp2, the diagnosis, which is located in +\"Network_Error\" for details. If you are using the |AppName|, the diagnosis, which is located in the help section, may assist you in finding issues. .. _failure_code_replace_card_or_card_reader: @@ -80,11 +80,6 @@ Codes | 3 The card reader has to be attached during the whole workflow | 4 You must not cancel the remote access during the whole workflow - - | **Processing_Send_Status_Failed** - | Occurs if the browser could not be told to wait longer to prevent a timeout. - | **Possible Solutions:** Change the browser. If the problem persists, - :ref:`failure_code_contact_support`. - - | **Parse_TcToken_Invalid_Url** | An authentication was started according to TR-03124-1 section 2.2.1.1. However, no valid tcTokenURL was transmitted. @@ -119,6 +114,18 @@ Codes forwarding. | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + - | **Get_TcToken_ServiceUnavailable** + | The server intended for providing the tcToken is temporarily unavailable. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **Get_TcToken_Server_Error** + | A server error 5xx occurred on requesting the tcToken. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **Get_TcToken_Client_Error** + | A client error 4xx occurred on requesting the tcToken. + | **Possible Solutions:** :ref:`failure_code_contact_support`. + - | **Get_TcToken_Empty_Data** | The server responded to the request for the tcToken with empty content. | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. @@ -158,13 +165,13 @@ Codes | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. - | **Pre_Verification_No_Test_Environment** - | Occurs when the development mode of AusweisApp2 is activated and a genuine ID card is used. + | Occurs when the development mode of |AppName| is activated and a genuine ID card is used. | **Possible Solutions:** Disable developer mode. The use of genuine ID cards is not permitted with activated developer mode, as this is only intended to facilitate the commissioning of services with test ID cards. - | **Pre_Verification_Invalid_Certificate_Chain** - | A certificate chain was sent from the server that is unknown to AusweisApp2. + | A certificate chain was sent from the server that is unknown to |AppName|. | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. - | **Pre_Verification_Invalid_Certificate_Signature** @@ -211,12 +218,6 @@ Codes | **Possible Solutions:** The PIN is permanently disabled after 3 failed attempts. Please set up your Smart-eID again. - - | **Establish_Pace_Channel_No_Active_Pin** - | An authentication was aborted by a card reader in order to replace the five-digit Transport PIN. - | **Possible Solutions:** The AusweisApp2 automatically leads the user to the PIN change to set - a six-digit PIN. If this error occurs in a third-party app, you have to start a PIN change on - your own. - - | **Establish_Pace_Channel_Basic_Reader_No_Pin** | An attempt was made to establish a PACE-channel with a basic reader. However the PIN, CAN, or PUK could not be taken over after the user-input. @@ -274,6 +275,10 @@ Codes certificate is incorrect. | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + - | **Generic_Send_Receive_Service_Unavailable** + | The server intended for the PAOS communication during authentication is temporarily unavailable. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + - | **Generic_Send_Receive_Server_Error** | A server error 5xx occurred in the PAOS communication during authentication. | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. @@ -314,7 +319,7 @@ Codes | **Possible Solutions:** :ref:`failure_code_contact_support`. - | **Start_Paos_Response_Error** - | The "StartPaosResponse" message from the server returned an error. The AusweisApp2 or the ID card + | The "StartPaosResponse" message from the server returned an error. The |AppName| or the ID card did not behave as expected by the server. | **Possible Solutions:** :ref:`failure_code_contact_support`. @@ -329,15 +334,23 @@ Codes | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. - | **Check_Refresh_Address_Service_Unavailable** - | The return address cannot be reached. + | The server providing the return address is temporarily unavailable. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **Check_Refresh_Address_Server_Error** + | A server error 5xx occurred on requesting the return address. | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + - | **Check_Refresh_Address_Client_Error** + | A client error 4xx occurred on requesting the return address. + | **Possible Solutions:** :ref:`failure_code_contact_support`. + - | **Check_Refresh_Address_Service_Timeout** | The call to the return address did not provide an answer within 30 seconds. | **Possible Solutions:** :ref:`failure_code_fix_connections_problems`. - | **Check_Refresh_Address_Proxy_Error** - | A proxy server was configured by the operating system or the settings of AusweisApp2. This + | A proxy server was configured by the operating system or the settings of |AppName|. This didn't work for checking the return address. | **Possible Solutions:** :ref:`failure_code_fix_connections_problems`. @@ -380,52 +393,55 @@ Codes provider certificate. | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. - - | **Redirect_Browser_Send_Error_Page_Failed** - | Like Redirect_Browser_Send_Redirect_Failed. However, this only applies to desktop systems, as - the AusweisApp2 only generates an error page there if no error address is available for - forwarding by the service provider. On mobile systems, the error details are displayed in the - AusweisApp2. - | **Possible Solutions:** If the problem occurs repeatedly and changing the browser does not - help, please :ref:`failure_code_contact_support`. - - - | **Redirect_Browser_Send_Redirect_Failed** - | On desktop systems, the web browser waits for a response from AusweisApp2 after starting - authentication. However, for unknown reasons, the web browser did not wait long enough for the - response to be sent. On mobile systems it was not possible to open the answer in a web - browser. + - | **Browser_Send_Failed** + | On desktop systems, the web browser waits for a response from |AppName| after starting + authentication. However, for unknown reasons, the web browser connection to the browser is + lost and the answer cannot be sent. | **Possible Solutions:** If the problem occurs repeatedly and changing the browser does not help, please :ref:`failure_code_contact_support`. - | **Generic_Provider_Communication_Network_Error** | A network error occurred while communicating with a service provider. This only applies to - services that are started from AusweisApp2, such as self-authentication. + services that are started from |AppName|, such as self-authentication. | **Possible Solutions:** :ref:`failure_code_fix_connections_problems`. - | **Generic_Provider_Communication_Invalid_Ephemeral_Key_Length** | When communicating with a service provider, the symmetric key generated by the TLS handshake - is not long enough. This only applies to services that are started from AusweisApp2, such as + is not long enough. This only applies to services that are started from |AppName|, such as self-authentication. | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. - | **Generic_Provider_Communication_Certificate_Error** | When communicating with a service provider, the TLS certificate uses key lengths that are - insufficient. This only applies to services that are started from AusweisApp2, such as + insufficient. This only applies to services that are started from |AppName|, such as self-authentication. | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. - | **Generic_Provider_Communication_Tls_Error** | An error occurred during the TLS handshake when communicating with a service provider. The TLS - certificate is incorrect. This only applies to services that are started from AusweisApp2, + certificate is incorrect. This only applies to services that are started from |AppName|, such as self-authentication. | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + - | **Generic_Provider_Communication_ServiceUnavailable** + | The server of the service provider is temporarily unavailable. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **Generic_Provider_Communication_Server_Error** + | A server error 5xx occurred in the communication with the service provider. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **Generic_Provider_Communication_Client_Error** + | A client error 4xx occurred in the communication with the service provider. + | **Possible Solutions:** :ref:`failure_code_contact_support`. + - | **Get_SelfAuthData_Invalid_Or_Empty** | The authentication for the self-authentication was completed successfully, but the server then did not transmit the read data correctly. | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. - | **Change_Pin_No_SetEidPinCommand_Response** - | The AusweisApp2 sent a PIN change command to its core, but received an answer for a + | The |AppName| sent a PIN change command to its core, but received an answer for a different command. | **Possible Solutions:** :ref:`failure_code_contact_support`. @@ -470,7 +486,7 @@ Codes - | **Start_Ifd_Service_Failed** | The IFD service according to TR-03112-6 appendix "IFD Service" could not be started. Either no suitable TLS certificate could be found/generated or the start of the TLS server failed. This - applies to both remote access and the local service of AusweisApp2 on Android that is used + applies to both remote access and the local service of |AppName| on Android that is used through the SDK. | **Possible Solutions:** :ref:`failure_code_contact_support`. @@ -496,79 +512,148 @@ Codes acting as a card reader with keyboard mode enabled. | **Possible Solutions:** :ref:`failure_code_contact_support`. - - | **Transmit_Personalization_Size_Mismatch** + - | **Check_Status_Unavailable** | Is not yet included in the product and will only be relevant with version 2.0.0. - - | **Start_Paos_Response_Personalization_Empty** + - | **Check_Applet_Internal_Error** | Is not yet included in the product and will only be relevant with version 2.0.0. - - | **Start_Paos_Response_Personalization_Invalid** + - | **Install_Smart_User_Cancelled** | Is not yet included in the product and will only be relevant with version 2.0.0. - - | **Prepare_Applet_User_Cancelled** + - | **Delete_Smart_User_Cancelled** | Is not yet included in the product and will only be relevant with version 2.0.0. - - | **Prepare_Applet_Status_Call_Failed** + - | **Delete_Personalization_User_Cancelled** | Is not yet included in the product and will only be relevant with version 2.0.0. - - | **Prepare_Applet_Installation_Loop** + - | **Update_Support_Info_User_Cancelled** | Is not yet included in the product and will only be relevant with version 2.0.0. - - | **Prepare_Applet_Installation_Failed** + - | **Install_Smart_Service_Response_Fail** | Is not yet included in the product and will only be relevant with version 2.0.0. - - | **Prepare_Applet_Unavailable** + - | **Install_Smart_Service_Response_Unsupported** | Is not yet included in the product and will only be relevant with version 2.0.0. - - | **Prepare_Applet_Delete_Personalization_Failed** + - | **Install_Smart_Service_Response_Overload** | Is not yet included in the product and will only be relevant with version 2.0.0. - - | **Prepare_Applet_UpdateInfo_Call_Failed** + - | **Install_Smart_Service_Response_Maintenance** | Is not yet included in the product and will only be relevant with version 2.0.0. - - | **Prepare_Applet_Delete_Smart_Failed** + - | **Install_Smart_Service_Response_Nfc_Disabled** | Is not yet included in the product and will only be relevant with version 2.0.0. - - | **Insert_Card_No_SmartReader** + - | **Install_Smart_Service_Response_Integrity_Check_Failed** | Is not yet included in the product and will only be relevant with version 2.0.0. - - | **Insert_Card_Multiple_SmartReader** + - | **Install_Smart_Service_Response_Not_Authenticated** | Is not yet included in the product and will only be relevant with version 2.0.0. - - | **Insert_Card_Unknown_Eid_Type** + - | **Install_Smart_Service_Response_Network_Connection_Error** | Is not yet included in the product and will only be relevant with version 2.0.0. - - | **Insert_Card_HW_Keystore** + - | **Update_Support_Info_Call_Failed** | Is not yet included in the product and will only be relevant with version 2.0.0. - - | **Insert_Card_Invalid_SmartReader** + - | **Update_Support_Info_Service_Response_Fail** | Is not yet included in the product and will only be relevant with version 2.0.0. - - | **Insert_Card_Missing_Card** + - | **Update_Support_Info_Service_Response_Unsupported** | Is not yet included in the product and will only be relevant with version 2.0.0. - - | **Initialize_Personalization_Failed** + - | **Update_Support_Info_Service_Response_Overload** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Update_Support_Info_Service_Response_Maintenance** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Update_Support_Info_Service_Response_Nfc_Disabled** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Update_Support_Info_Service_Response_Integrity_Check_Failed** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Update_Support_Info_Service_Response_Not_Authenticated** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Update_Support_Info_Service_Response_Network_Connection_Error** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Delete_Smart_Service_Response_Fail** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Delete_Smart_Service_Response_Unsupported** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Delete_Smart_Service_Response_Overload** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Delete_Smart_Service_Response_Maintenance** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Delete_Smart_Service_Response_Nfc_Disabled** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Delete_Smart_Service_Response_Integrity_Check_Failed** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Delete_Smart_Service_Response_Not_Authenticated** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Delete_Smart_Service_Response_Network_Connection_Error** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Delete_Personalization_Failed** | Is not yet included in the product and will only be relevant with version 2.0.0. - | **Get_Session_Id_Invalid** | Is not yet included in the product and will only be relevant with version 2.0.0. + - | **Smart_ServiceInformation_Query_Failed** + | Is not yet included in the product and will only be relevant with version 2.0.0. + - | **Get_Challenge_Invalid** | Is not yet included in the product and will only be relevant with version 2.0.0. + - | **Initialize_Personalization_Failed** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Smart_PrePersonalization_Wrong_Status** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Smart_PrePersonalization_Incomplete_Information** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Transmit_Personalization_Size_Mismatch** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Start_Paos_Response_Personalization_Empty** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Start_Paos_Response_Personalization_Invalid** + | Is not yet included in the product and will only be relevant with version 2.0.0. + - | **Finalize_Personalization_Failed** | Is not yet included in the product and will only be relevant with version 2.0.0. - - | **Change_Smart_Pin_Failed** + - | **Insert_Card_No_SmartReader** | Is not yet included in the product and will only be relevant with version 2.0.0. - - | **Check_Status_Unavailable** + - | **Insert_Card_Multiple_SmartReader** | Is not yet included in the product and will only be relevant with version 2.0.0. - - | **Check_Applet_Error** + - | **Insert_Card_Unknown_Eid_Type** | Is not yet included in the product and will only be relevant with version 2.0.0. - - | **Check_Applet_Unavailable** + - | **Insert_Card_Invalid_SmartReader** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Insert_Card_Missing_Card** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Change_Smart_Pin_Failed** | Is not yet included in the product and will only be relevant with version 2.0.0. .. _failure_code_solutions: diff --git a/docs/failurecodes/index.rst b/docs/failurecodes/index.rst index e0b04691b..2a5b880a0 100644 --- a/docs/failurecodes/index.rst +++ b/docs/failurecodes/index.rst @@ -1,7 +1,7 @@ .. only:: html - .. image:: ../sdk/Logo_AusweisApp2.png - :alt: AusweisApp2 + .. image:: ../sdk/AusweisApp_Logo.svg + :alt: AusweisApp :align: center :width: 200pt diff --git a/docs/failurecodes/intro.rst b/docs/failurecodes/intro.rst index 59c38b45e..8667a88d2 100644 --- a/docs/failurecodes/intro.rst +++ b/docs/failurecodes/intro.rst @@ -1,7 +1,7 @@ Introduction ============ -This documentation will list all failure codes that may occur while using the AusweisApp2 or the -AusweisApp2 SDK. +This documentation will list all failure codes that may occur while using the |AppName| or the +|AppName| SDK. In addition to detailed information on where and why an error occurred, possible solutions are provided as well. Furthermore there will be first guidance to prevent many of the causes that will be mentioned. diff --git a/docs/failurecodes/locales/de/LC_MESSAGES/failurecodes.po b/docs/failurecodes/locales/de/LC_MESSAGES/failurecodes.po index 6f1d212ec..4f0782622 100644 --- a/docs/failurecodes/locales/de/LC_MESSAGES/failurecodes.po +++ b/docs/failurecodes/locales/de/LC_MESSAGES/failurecodes.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: AusweisApp2 Failure Codes 1.26.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-29 14:12+0200\n" +"POT-Creation-Date: 2023-05-31 05:28+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: de\n" @@ -24,10 +24,10 @@ msgid "Failure Codes" msgstr "Fehlercodes" msgid "" -"The AusweisApp2 will send failure codes indicating what went wrong and " +"The |AppName| will send failure codes indicating what went wrong and " "where it happened as well as how to solve it." msgstr "" -"Die AusweisApp2 sendet Fehlercodes, um mitzuteilen, welche Fehler an " +"Die |AppName| sendet Fehlercodes, um mitzuteilen, welche Fehler an " "welcher Stelle aufgetreten sind und wie sie behoben werden können." msgid "Helpful tips" @@ -70,29 +70,31 @@ msgid "" "If the provided failure code did not help to resolve the issue, please " "contact the support (https://www.ausweisapp.bund.de/en/help-and-support)," " including the error code, situation description, and logfile, so that " -"they can identify issues in your system configuration or AusweisApp2. If " -"you are using the AusweisApp2 you will find the logfile in the Help " +"they can identify issues in your system configuration or |AppName|. If " +"you are using the |AppName| you will find the logfile in the Help " "section." msgstr "" -"Wenn der gezeigte Fehlercode Ihnen nicht hilft, das Problem eigenständig zu lösen, kontaktieren " -"Sie unseren Support (https://www.ausweisapp.bund.de/hilfe-und-support), inklusive dem " -"Fehlercode, einer Situationsbeschreibung und einer Protokolldatei, um Probleme in Ihrer " -"Systemkonfiguration oder der AusweisApp2 zu identifizieren. Wenn Sie die " -"AusweisApp2 verwenden, finden Sie die Protokolldatei im Hilfebereich." +"Wenn der gezeigte Fehlercode Ihnen nicht hilft, das Problem eigenständig " +"zu lösen, kontaktieren Sie unseren Support " +"(https://www.ausweisapp.bund.de/hilfe-und-support), inklusive dem " +"Fehlercode, einer Situationsbeschreibung und einer Protokolldatei, um " +"Probleme in Ihrer Systemkonfiguration oder der |AppName| zu " +"identifizieren. Wenn Sie die |AppName| verwenden, finden Sie die " +"Protokolldatei im Hilfebereich." msgid "Inform service provider" msgstr "Diensteanbieter informieren" msgid "" "Directly notify the service provider if the failure code contained an " -"incorrect TLS or service configuration. Usually the the service provider " +"incorrect TLS or service configuration. Usually the service provider " "contact information are available on the website on which you have " "started the authentication." msgstr "" -"Bitte wenden Sie sich für Fehlercodes, welche eine ungültige TLS- oder Dienstekonfiguration " -"beinhalten direkt an den jeweiligen Diensteanbieter. Sie finden die Kontaktinformationen zum " -"jeweiligen Diensteanbieter i.d.R. auf der Website, auf der Sie eine Authentisierung gestartet " -"haben." +"Bitte wenden Sie sich für Fehlercodes, welche eine ungültige TLS- oder " +"Dienstekonfiguration beinhalten direkt an den jeweiligen Diensteanbieter." +" Sie finden die Kontaktinformationen zum jeweiligen Diensteanbieter " +"i.d.R. auf der Website, auf der Sie eine Authentisierung gestartet haben." msgid "Fix connection problems" msgstr "Verbindungsprobleme beheben" @@ -105,17 +107,19 @@ msgid "" "configuration as well as your local network hardware. Ultimately the " "problem may be with your telecommunications provider, or the service " "provider. Please refer to the attached \\\"Network_Error\\\" for details." -" If you are using the AusweisApp2, the diagnosis, which is located in the" +" If you are using the |AppName|, the diagnosis, which is located in the" " help section, may assist you in finding issues." msgstr "" -"Bei sämtlichen Fehlercodes, welche Verbindungsprobleme als Ursache aufzeigen, empfiehlt sich " -"vorab eine Überprüfung der aktuellen Internetverbindung. Stellen Sie dazu eine aktive " -"Internetverbindung sicher, indem Sie z.B. https://www.ausweisapp.bund.de im Browser Ihrer Wahl " -"öffnen. Prüfen Sie auch Ihre Firewall- und Antivirus-Einstellungen, sowie Ihre lokale " -"Netzwerkhardware. Schlussendlich kann das Problem auch bei Ihrem " -"Telekommunikationsanbieter oder dem Diensteanbieter liegen. Details " -"entnehmen Sie bitte dem beiliegenden \"Network_Error\". Sofern Sie die AusweisApp2 verwenden, " -"können die Diagnosefunktionen im Hilfebereich bei der Problemfeststellung unterstützen." +"Bei sämtlichen Fehlercodes, welche Verbindungsprobleme als Ursache " +"aufzeigen, empfiehlt sich vorab eine Überprüfung der aktuellen " +"Internetverbindung. Stellen Sie dazu eine aktive Internetverbindung " +"sicher, indem Sie z.B. https://www.ausweisapp.bund.de im Browser Ihrer " +"Wahl öffnen. Prüfen Sie auch Ihre Firewall- und Antivirus-Einstellungen, " +"sowie Ihre lokale Netzwerkhardware. Schlussendlich kann das Problem auch " +"bei Ihrem Telekommunikationsanbieter oder dem Diensteanbieter liegen. " +"Details entnehmen Sie bitte dem beiliegenden \"Network_Error\". Sofern " +"Sie die |AppName| verwenden, können die Diagnosefunktionen im " +"Hilfebereich bei der Problemfeststellung unterstützen." msgid "Replace ID card of card reader" msgstr "Ausweis oder Kartenleser ersetzen" @@ -145,8 +149,8 @@ msgid "" "third-party application that has disconnected from the SDK." msgstr "" "Der Benutzer hat den Arbeitsablauf abgebrochen. Im SDK-Fall kann der " -"\"Benutzer\" auch eine Fremdanwendung sein, welche die Verbindung zum SDK " -"getrennt hat." +"\"Benutzer\" auch eine Fremdanwendung sein, welche die Verbindung zum SDK" +" getrennt hat." msgid "**Possible Solutions:** Complete the workflow without canceling." msgstr "**Mögliche Lösungen:** Den Vorgang ohne Abbruch durchführen." @@ -184,23 +188,6 @@ msgstr "3 Der Kartenleser muss während des gesamten Vorgangs angeschlossen sein msgid "4 You must not cancel the remote access during the whole workflow" msgstr "4 Sie dürfen den Fernzugriff nicht während des Vorgangs stoppen" -msgid "**Processing_Send_Status_Failed**" -msgstr "" - -msgid "" -"Occurs if the browser could not be told to wait longer to prevent a " -"timeout." -msgstr "" -"Tritt auf, wenn dem Browser nicht mitgeteilt werden kann, dass dieser " -"noch auf das Ergebnis warten muss um ein Timeout zu verhindern." - -msgid "" -"**Possible Solutions:** Change the browser. If the problem persists, " -":ref:`failure_code_contact_support`." -msgstr "" -"**Mögliche Lösungen:** Versuchen Sie einen anderen Browser. Falls das Problem bestehen bleibt, " -"beachten Sie :ref:`failure_code_contact_support`." - msgid "**Parse_TcToken_Invalid_Url**" msgstr "" @@ -275,6 +262,29 @@ msgstr "" "Der Server hat auf die Anfrage nach dem tcToken weder mit einem korrekten" " Inhalt noch mit einer Weiterleitung reagiert." +msgid "**Get_TcToken_ServiceUnavailable**" +msgstr "" + +msgid "The server intended for providing the tcToken is temporarily unavailable." +msgstr "" +"Der für das Bereitstellen des tcToken vorgesehene Server ist temporär " +"nicht verfügbar." + +msgid "**Get_TcToken_Server_Error**" +msgstr "" + +msgid "A server error 5xx occurred on requesting the tcToken." +msgstr "Bei dem Abruf des tcToken ist ein Serverfehler 5xx aufgetreten." + +msgid "**Get_TcToken_Client_Error**" +msgstr "" + +msgid "A client error 4xx occurred on requesting the tcToken." +msgstr "Bei dem Abruf des tcToken ist ein Clientfehler 4xx aufgetreten." + +msgid "**Possible Solutions:** :ref:`failure_code_contact_support`." +msgstr "**Mögliche Lösungen:** :ref:`failure_code_contact_support`." + msgid "**Get_TcToken_Empty_Data**" msgstr "" @@ -364,10 +374,10 @@ msgid "**Pre_Verification_No_Test_Environment**" msgstr "" msgid "" -"Occurs when the development mode of AusweisApp2 is activated and a " +"Occurs when the development mode of |AppName| is activated and a " "genuine ID card is used." msgstr "" -"Tritt auf, wenn der Entwicklermodus der AusweisApp2 aktiviert ist und ein" +"Tritt auf, wenn der Entwicklermodus der |AppName| aktiviert ist und ein" " Echtausweis verwendet wird." msgid "" @@ -385,9 +395,9 @@ msgstr "" msgid "" "A certificate chain was sent from the server that is unknown to " -"AusweisApp2." +"|AppName|." msgstr "" -"Vom Server wurde eine Zertifikatskette gesendet, die der AusweisApp2 " +"Vom Server wurde eine Zertifikatskette gesendet, die der |AppName| " "nicht bekannt ist." msgid "**Pre_Verification_Invalid_Certificate_Signature**" @@ -511,22 +521,12 @@ msgstr "" "Fehlversuchen nicht freigeschaltet werden. Bitte richten Sie Ihre Smart-" "eID erneut ein." -msgid "**Establish_Pace_Channel_No_Active_Pin**" -msgstr "" - msgid "" -"An authentication was aborted by a card reader in order to replace the " -"five-digit Transport PIN." -msgstr "" -"Eine Authentisierung wurde von einem Kartenleser abgebrochen, um die " -"fünfstellige Transport-PIN zu ersetzen." - -msgid "" -"**Possible Solutions:** The AusweisApp2 automatically leads the user to " +"**Possible Solutions:** The |AppName| automatically leads the user to " "the PIN change to set a six-digit PIN. If this error occurs in a third-" "party app, you have to start a PIN change on your own." msgstr "" -"**Mögliche Lösungen:** Die AusweisApp2 führt den Benutzer direkt zur PIN-" +"**Mögliche Lösungen:** Die |AppName| führt den Benutzer direkt zur PIN-" "Änderung, damit dieser eine sechsstellige PIN festlegen kann. Tritt der " "Fall im SDK auf, muss sich die Anwendung selbst darum kümmern." @@ -539,7 +539,8 @@ msgid "" "input." msgstr "" "Bei der Verwendung eines Basislesers wurde versucht ein PACE-Kanal " -"aufzubauen. Jedoch wurde die PIN, CAN oder PUK nach der Nutzereingabe nicht übernommen." +"aufzubauen. Jedoch wurde die PIN, CAN oder PUK nach der Nutzereingabe " +"nicht übernommen." msgid "**Possible Solutions:** :ref:`failure_code_contact_support`." msgstr "**Mögliche Lösungen:** :ref:`failure_code_contact_support`." @@ -665,6 +666,16 @@ msgstr "" "Bei einer Authentisierung ist während des TLS-Handshakes in der PAOS-" "Kommunikation ein Fehler aufgetreten. Das TLS-Zertifikat ist fehlerhaft." +msgid "**Generic_Send_Receive_Service_Unavailable**" +msgstr "" + +msgid "" +"The server intended for the PAOS communication during authentication is " +"temporarily unavailable." +msgstr "" +"Der für PAOS-Kommunikation vorgesehene Server ist temporär " +"nicht verfügbar." + msgid "**Generic_Send_Receive_Server_Error**" msgstr "" @@ -760,10 +771,10 @@ msgstr "" msgid "" "The \"StartPaosResponse\" message from the server returned an error. The " -"AusweisApp2 or the ID card did not behave as expected by the server." +"|AppName| or the ID card did not behave as expected by the server." msgstr "" "Die Nachricht \"StartPaosResponse\" vom Server hat einen Fehler " -"geliefert. Die AusweisApp2 oder die Karte hat sich nicht entsprechend der" +"geliefert. Die |AppName| oder die Karte hat sich nicht entsprechend der" " Erwartung des Servers verhalten." msgid "**Check_Refresh_Address_Fatal_Tls_Error_Before_Reply**" @@ -791,8 +802,24 @@ msgstr "" msgid "**Check_Refresh_Address_Service_Unavailable**" msgstr "" -msgid "The return address cannot be reached." -msgstr "Die Rücksprungadresse ist nicht erreichbar." +msgid "The server providing the return address is temporarily unavailable." +msgstr "" +"Der für das Bereitstellen der Rücksprungadresse vorgesehene Server ist temporär " +"nicht verfügbar." + +msgid "**Check_Refresh_Address_Server_Error**" +msgstr "" + +msgid "A server error 5xx occurred on requesting the return address." +msgstr "" +"Bei der Anfrage der Rücksprungadresse ist ein Serverfehler 5xx aufgetreten." + +msgid "**Check_Refresh_Address_Client_Error**" +msgstr "" + +msgid "A client error 4xx occurred on requesting the return address." +msgstr "" +"Bei der Anfrage der Rücksprungadresse ist ein Clientfehler 4xx aufgetreten." msgid "**Check_Refresh_Address_Service_Timeout**" msgstr "" @@ -809,9 +836,9 @@ msgstr "" msgid "" "A proxy server was configured by the operating system or the settings of " -"AusweisApp2. This didn't work for checking the return address." +"|AppName|. This didn't work for checking the return address." msgstr "" -"Durch das Betriebssystem oder die Einstellungen der AusweisApp2 wurde ein" +"Durch das Betriebssystem oder die Einstellungen der |AppName| wurde ein" " Proxyserver konfiguriert. Dieser hat für die Überprüfung der " "Rücksprungadresse nicht funktioniert." @@ -900,21 +927,6 @@ msgstr "" "Das Server-Zertifikat der Rücksprungadresse ist nicht in der Beschreibung" " des Diensteanbieterzertifikats enthalten." -msgid "**Redirect_Browser_Send_Error_Page_Failed**" -msgstr "" - -msgid "" -"Like Redirect_Browser_Send_Redirect_Failed. However, this only applies to" -" desktop systems, as the AusweisApp2 only generates an error page there " -"if no error address is available for forwarding by the service provider. " -"On mobile systems, the error details are displayed in the AusweisApp2." -msgstr "" -"Ähnlich wie Redirect_Browser_Send_Redirect_Failed. Gilt aber nur für " -"Desktop-Systeme, da nur dort eine Fehlerseite durch die AusweisApp2 " -"generiert wird, falls keine Fehleradresse für die Weiterleitung durch den" -" Diensteanbieter verfügbar ist. Auf mobilen Systemen werden die " -"Fehlerdetails in der AusweisApp2 dargestellt." - msgid "" "**Possible Solutions:** If the problem occurs repeatedly and changing the" " browser does not help, please :ref:`failure_code_contact_support`." @@ -923,31 +935,28 @@ msgstr "" "Problem bestehen bleibt, beachten Sie " ":ref:`failure_code_contact_support`." -msgid "**Redirect_Browser_Send_Redirect_Failed**" +msgid "**Browser_Send_Failed**" msgstr "" msgid "" -"On desktop systems, the web browser waits for a response from AusweisApp2" -" after starting authentication. However, for unknown reasons, the web " -"browser did not wait long enough for the response to be sent. On mobile " -"systems it was not possible to open the answer in a web browser." +"On desktop systems, the web browser waits for a response from |AppName| " +"after starting authentication. However, for unknown reasons, the web browser " +"connection to the browser is lost and the answer cannot be sent." msgstr "" -"Auf Desktop-Systemen wartet der Webbrowser nach Start einer " -"Authentisierung auf eine Antwort der AusweisApp2. Aus unbekannten Gründen" -" hat der Webbrowser aber nicht lange genug gewartet, sodass die Antwort " -"nicht mehr gesendet werden kann. Auf mobilen Systemen ist es nicht " -"gelungen die Antwort in einem Webbrowser zu öffnen." +"Auf Desktop-Systemen wartet der Webbrowser nach Start einer Authentisierung " +"auf eine Antwort der |AppName|. Aus unbekannten Gründen ist die Verbindung " +"zum Browser abgebrochen, sodass die Antwort nicht mehr gesendet werden kann." msgid "**Generic_Provider_Communication_Network_Error**" msgstr "" msgid "" "A network error occurred while communicating with a service provider. " -"This only applies to services that are started from AusweisApp2, such as " +"This only applies to services that are started from |AppName|, such as " "self-authentication." msgstr "" "Bei der Kommunikation mit einem Diensteanbieter ist ein Netzwerkfehler " -"aufgetreten. Das betrifft nur Dienste, die aus der AusweisApp2 heraus " +"aufgetreten. Das betrifft nur Dienste, die aus der |AppName| heraus " "gestartet werden, wie zum Beispiel die Selbstauskunft." msgid "**Generic_Provider_Communication_Invalid_Ephemeral_Key_Length**" @@ -956,11 +965,11 @@ msgstr "" msgid "" "When communicating with a service provider, the symmetric key generated " "by the TLS handshake is not long enough. This only applies to services " -"that are started from AusweisApp2, such as self-authentication." +"that are started from |AppName|, such as self-authentication." msgstr "" "Bei der Kommunikation mit einem Diensteanbieter ist der durch den TLS-" "Handshake generierte symmetrische Schlüssel nicht lang genug. Das " -"betrifft nur Dienste, die aus der AusweisApp2 heraus gestartet werden, " +"betrifft nur Dienste, die aus der |AppName| heraus gestartet werden, " "wie zum Beispiel die Selbstauskunft." msgid "**Generic_Provider_Communication_Certificate_Error**" @@ -969,11 +978,11 @@ msgstr "" msgid "" "When communicating with a service provider, the TLS certificate uses key " "lengths that are insufficient. This only applies to services that are " -"started from AusweisApp2, such as self-authentication." +"started from |AppName|, such as self-authentication." msgstr "" "Bei der Kommunikation mit einem Diensteanbieter verwendet das TLS-" "Zertifikat unzureichende Schlüssellängen. Das betrifft nur Dienste, die " -"aus der AusweisApp2 heraus gestartet werden, wie zum Beispiel die " +"aus der |AppName| heraus gestartet werden, wie zum Beispiel die " "Selbstauskunft." msgid "**Generic_Provider_Communication_Tls_Error**" @@ -982,13 +991,38 @@ msgstr "" msgid "" "An error occurred during the TLS handshake when communicating with a " "service provider. The TLS certificate is incorrect. This only applies to " -"services that are started from AusweisApp2, such as self-authentication." +"services that are started from |AppName|, such as self-authentication." msgstr "" "Bei der Kommunikation mit einem Diensteanbieter ist während des TLS-" "Handshakes ein Fehler aufgetreten. Das TLS-Zertifikat ist fehlerhaft. Das" -" betrifft nur Dienste, die aus der AusweisApp2 heraus gestartet werden, " +" betrifft nur Dienste, die aus der |AppName| heraus gestartet werden, " "wie zum Beispiel die Selbstauskunft." +msgid "**Generic_Provider_Communication_ServiceUnavailable**" +msgstr "" + +msgid "The server of the service provider is temporarily unavailable." +msgstr "" +"Der Server des Diensteanbieters ist temporär nicht verfügbar." + +msgid "**Generic_Provider_Communication_Server_Error**" +msgstr "" + +msgid "" +"A server error 5xx occurred in the communication with the service " +"provider." +msgstr "" +"Bei der Kommunikation mit dem Diensteanbieter ist ein Serverfehler 5xx aufgetreten." + +msgid "**Generic_Provider_Communication_Client_Error**" +msgstr "" + +msgid "" +"A client error 4xx occurred in the communication with the service " +"provider." +msgstr "" +"Bei der Kommunikation mit dem Diensteanbieter ist ein Clientfehler 4xx aufgetreten." + msgid "**Get_SelfAuthData_Invalid_Or_Empty**" msgstr "" @@ -1005,10 +1039,10 @@ msgid "**Change_Pin_No_SetEidPinCommand_Response**" msgstr "" msgid "" -"The AusweisApp2 sent a PIN change command to its core, but received an " +"The |AppName| sent a PIN change command to its core, but received an " "answer for a different command." msgstr "" -"Die AusweisApp2 hat ein Kommando zur Änderung der PIN an ihren Kern " +"Die |AppName| hat ein Kommando zur Änderung der PIN an ihren Kern " "gesendet, jedoch eine Antwort für ein anderes Kommando erhalten." msgid "**Change_Pin_Input_Timeout**" @@ -1103,14 +1137,14 @@ msgid "" "The IFD service according to TR-03112-6 appendix \"IFD Service\" could " "not be started. Either no suitable TLS certificate could be " "found/generated or the start of the TLS server failed. This applies to " -"both remote access and the local service of AusweisApp2 on Android that " +"both remote access and the local service of |AppName| on Android that " "is used through the SDK." msgstr "" "Der IFD-Service gemäß TR-03112-6 Anhang „IFD Service“ konnte nicht " "gestartet werden. Entweder konnte kein passendes TLS-Zertifikat " "gefunden/generiert werden oder der Start des TLS-Servers ist " "fehlgeschlagen. Das betrifft sowohl den Fernzugriff als auch den lokalen " -"Service der AusweisApp2 auf Android, der durch das SDK genutzt wird." +"Service der |AppName| auf Android, der durch das SDK genutzt wird." msgid "**Prepare_Pace_Ifd_Unknown**" msgstr "" @@ -1150,7 +1184,7 @@ msgstr "" "Änderung auf einem Smartphone als Kartenleser mit aktiviertem " "Tastaturmodus abgebrochen hat." -msgid "**Transmit_Personalization_Size_Mismatch**" +msgid "**Check_Status_Unavailable**" msgstr "" msgid "" @@ -1160,75 +1194,144 @@ msgstr "" "Ist noch nicht im Produkt enthalten und wird erst mit der Version 2.0.0 " "relevant." -msgid "**Start_Paos_Response_Personalization_Empty**" +msgid "**Check_Applet_Internal_Error**" msgstr "" -msgid "**Start_Paos_Response_Personalization_Invalid**" +msgid "**Install_Smart_User_Cancelled**" msgstr "" -msgid "**Prepare_Applet_User_Cancelled**" +msgid "**Delete_Smart_User_Cancelled**" msgstr "" -msgid "**Prepare_Applet_Status_Call_Failed**" +msgid "**Delete_Personalization_User_Cancelled**" msgstr "" -msgid "**Prepare_Applet_Installation_Loop**" +msgid "**Update_Support_Info_User_Cancelled**" msgstr "" -msgid "**Prepare_Applet_Installation_Failed**" +msgid "**Install_Smart_Service_Response_Fail**" msgstr "" -msgid "**Prepare_Applet_Unavailable**" +msgid "**Install_Smart_Service_Response_Unsupported**" msgstr "" -msgid "**Prepare_Applet_Delete_Personalization_Failed**" +msgid "**Install_Smart_Service_Response_Overload**" msgstr "" -msgid "**Prepare_Applet_UpdateInfo_Call_Failed**" +msgid "**Install_Smart_Service_Response_Maintenance**" msgstr "" -msgid "**Prepare_Applet_Delete_Smart_Failed**" +msgid "**Install_Smart_Service_Response_Nfc_Disabled**" msgstr "" -msgid "**Insert_Card_No_SmartReader**" +msgid "**Install_Smart_Service_Response_Integrity_Check_Failed**" msgstr "" -msgid "**Insert_Card_Multiple_SmartReader**" +msgid "**Install_Smart_Service_Response_Not_Authenticated**" msgstr "" -msgid "**Insert_Card_Unknown_Eid_Type**" +msgid "**Install_Smart_Service_Response_Network_Connection_Error**" msgstr "" -msgid "**Insert_Card_HW_Keystore**" +msgid "**Update_Support_Info_Call_Failed**" msgstr "" -msgid "**Insert_Card_Invalid_SmartReader**" +msgid "**Update_Support_Info_Service_Response_Fail**" msgstr "" -msgid "**Insert_Card_Missing_Card**" +msgid "**Update_Support_Info_Service_Response_Unsupported**" msgstr "" -msgid "**Initialize_Personalization_Failed**" +msgid "**Update_Support_Info_Service_Response_Overload**" +msgstr "" + +msgid "**Update_Support_Info_Service_Response_Maintenance**" +msgstr "" + +msgid "**Update_Support_Info_Service_Response_Nfc_Disabled**" +msgstr "" + +msgid "**Update_Support_Info_Service_Response_Integrity_Check_Failed**" +msgstr "" + +msgid "**Update_Support_Info_Service_Response_Not_Authenticated**" +msgstr "" + +msgid "**Update_Support_Info_Service_Response_Network_Connection_Error**" +msgstr "" + +msgid "**Delete_Smart_Service_Response_Fail**" +msgstr "" + +msgid "**Delete_Smart_Service_Response_Unsupported**" +msgstr "" + +msgid "**Delete_Smart_Service_Response_Overload**" +msgstr "" + +msgid "**Delete_Smart_Service_Response_Maintenance**" +msgstr "" + +msgid "**Delete_Smart_Service_Response_Nfc_Disabled**" +msgstr "" + +msgid "**Delete_Smart_Service_Response_Integrity_Check_Failed**" +msgstr "" + +msgid "**Delete_Smart_Service_Response_Not_Authenticated**" +msgstr "" + +msgid "**Delete_Smart_Service_Response_Network_Connection_Error**" +msgstr "" + +msgid "**Delete_Personalization_Failed**" msgstr "" msgid "**Get_Session_Id_Invalid**" msgstr "" +msgid "**Smart_ServiceInformation_Query_Failed**" +msgstr "" + msgid "**Get_Challenge_Invalid**" msgstr "" +msgid "**Initialize_Personalization_Failed**" +msgstr "" + +msgid "**Smart_PrePersonalization_Wrong_Status**" +msgstr "" + +msgid "**Smart_PrePersonalization_Incomplete_Information**" +msgstr "" + +msgid "**Transmit_Personalization_Size_Mismatch**" +msgstr "" + +msgid "**Start_Paos_Response_Personalization_Empty**" +msgstr "" + +msgid "**Start_Paos_Response_Personalization_Invalid**" +msgstr "" + msgid "**Finalize_Personalization_Failed**" msgstr "" -msgid "**Change_Smart_Pin_Failed**" +msgid "**Insert_Card_No_SmartReader**" msgstr "" -msgid "**Check_Status_Unavailable**" +msgid "**Insert_Card_Multiple_SmartReader**" msgstr "" -msgid "**Check_Applet_Error**" +msgid "**Insert_Card_Unknown_Eid_Type**" +msgstr "" + +msgid "**Insert_Card_Invalid_SmartReader**" msgstr "" -msgid "**Check_Applet_Unavailable**" +msgid "**Insert_Card_Missing_Card**" +msgstr "" + +msgid "**Change_Smart_Pin_Failed**" msgstr "" diff --git a/docs/failurecodes/locales/de/LC_MESSAGES/index.po b/docs/failurecodes/locales/de/LC_MESSAGES/index.po index f19d2921f..d791ceeec 100644 --- a/docs/failurecodes/locales/de/LC_MESSAGES/index.po +++ b/docs/failurecodes/locales/de/LC_MESSAGES/index.po @@ -19,16 +19,13 @@ msgstr "" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.12.1\n" - -msgid "AusweisApp2" + +msgid "AusweisApp" msgstr "" -msgid ".. image:: ../sdk/Logo_AusweisApp2.png" +msgid ".. image:: ../sdk/AusweisApp_Logo.svg" msgstr "" msgid "Table of contents" msgstr "Inhaltsverzeichnis" -#~ msgid ".. image:: Logo_AusweisApp2.png" -#~ msgstr "" - diff --git a/docs/failurecodes/locales/de/LC_MESSAGES/intro.po b/docs/failurecodes/locales/de/LC_MESSAGES/intro.po index a14d81f77..39fe7796e 100644 --- a/docs/failurecodes/locales/de/LC_MESSAGES/intro.po +++ b/docs/failurecodes/locales/de/LC_MESSAGES/intro.po @@ -25,13 +25,13 @@ msgstr "Einführung" msgid "" "This documentation will list all failure codes that may occur while using" -" the AusweisApp2 or the AusweisApp2 SDK. In addition to detailed " +" the |AppName| or the |AppName| SDK. In addition to detailed " "information on where and why an error occurred, possible solutions are " "provided as well. Furthermore there will be first guidance to prevent " "many of the causes that will be mentioned." msgstr "" "Diese Dokumentation listet alle Fehlercodes auf, die beim Verwenden der " -"AusweisApp2 oder des AusweisApp2-SDK auftreten können. Neben " +"|AppName| oder des |AppName|-SDK auftreten können. Neben " "detaillierten Informationen über das \"Wo\" und \"Warum\" bietet sie auch" " mögliche Lösungen an. Darüber hinaus gibt es vorab Hilfestellung zur " "Verhinderung einer Vielzahl der hier beschriebenen Ursachen." diff --git a/docs/installation/CommunicationModel_de.graphml b/docs/installation/CommunicationModel_de.graphml index 608b00778..458849b63 100644 --- a/docs/installation/CommunicationModel_de.graphml +++ b/docs/installation/CommunicationModel_de.graphml @@ -61,7 +61,7 @@ - AusweisApp2 + AusweisApp diff --git a/docs/installation/CommunicationModel_de.pdf b/docs/installation/CommunicationModel_de.pdf index fbb9b6488..a16e99255 100644 Binary files a/docs/installation/CommunicationModel_de.pdf and b/docs/installation/CommunicationModel_de.pdf differ diff --git a/docs/installation/CommunicationModel_en.graphml b/docs/installation/CommunicationModel_en.graphml index a5a755c18..40e38fdf9 100644 --- a/docs/installation/CommunicationModel_en.graphml +++ b/docs/installation/CommunicationModel_en.graphml @@ -61,7 +61,7 @@ - AusweisApp2 + AusweisApp diff --git a/docs/installation/CommunicationModel_en.pdf b/docs/installation/CommunicationModel_en.pdf index 792ff3a0b..2d0c3133f 100644 Binary files a/docs/installation/CommunicationModel_en.pdf and b/docs/installation/CommunicationModel_en.pdf differ diff --git a/docs/installation/README.de.rst b/docs/installation/README.de.rst index ae077291b..78d2c3118 100644 --- a/docs/installation/README.de.rst +++ b/docs/installation/README.de.rst @@ -1,10 +1,13 @@ Deutsch ======= +Installation +~~~~~~~~~~~~ + Windows ------- -Der Installer der AusweisApp2 kann über die Kommandozeile gestartet werden, um +Der Installer der |AppName| kann über die Kommandozeile gestartet werden, um den Installationsprozess zu konfigurieren und systemweite Standardeinstellungen vorzugeben. Der Rückgabewert von msiexec informiert über das Ergebnis der Installation [#msiexecreturnvalues]_. @@ -13,11 +16,11 @@ alle unterstützten Parameter, die im Anschluss erläutert werden. .. code-block:: winbatch - msiexec /i AusweisApp2-X.YY.Z.msi /quiet INSTALLDIR="C:\AusweisApp2" SYSTEMSETTINGS=false DESKTOPSHORTCUT=false PROXYSERVICE=false AUTOSTART=false AUTOHIDE=false REMINDTOCLOSE=false ASSISTANT=false TRANSPORTPINREMINDER=false CUSTOMPROXYTYPE="HTTP" CUSTOMPROXYHOST="proxy.example.org" CUSTOMPROXYPORT=1337 UPDATECHECK=false ONSCREENKEYBOARD=true SHUFFLESCREENKEYBOARD=true SECURESCREENKEYBOARD=true HISTORY=false ENABLECANALLOWED=true SKIPRIGHTSONCANALLOWED=true LAUNCH=true + msiexec /i AusweisApp-X.YY.Z.msi /quiet INSTALLDIR="C:\AusweisApp" SYSTEMSETTINGS=false DESKTOPSHORTCUT=false PROXYSERVICE=false AUTOSTART=false AUTOHIDE=false REMINDTOCLOSE=false ASSISTANT=false TRANSPORTPINREMINDER=false CUSTOMPROXYTYPE="HTTP" CUSTOMPROXYHOST="proxy.example.org" CUSTOMPROXYPORT=1337 UPDATECHECK=false ONSCREENKEYBOARD=true SHUFFLESCREENKEYBOARD=true SECURESCREENKEYBOARD=true ENABLECANALLOWED=true SKIPRIGHTSONCANALLOWED=true LAUNCH=true INSTALLDIR Gibt das Installationsverzeichnis an. Ohne Angabe wird der Ordner - "C:\\Programme\\AusweisApp2" genutzt. + "C:\\Programme\\AusweisApp" genutzt. SYSTEMSETTINGS Betrifft die Erstellung von Firewall-Regeln der Windows Firewall. Ohne Angabe @@ -30,10 +33,10 @@ DESKTOPSHORTCUT Desktop-Verknüpfung für alle Benutzer erstellt (true). PROXYSERVICE - Um den parallelen Betrieb mehrer Instanzen der AusweisApp2 zu ermöglichen, ist + Um den parallelen Betrieb mehrer Instanzen der |AppName| zu ermöglichen, ist der Proxy-Dienst notwendig. Der Proxy-Dienst übernimmt die Überwachung von Port 24727 (definiert in BSI TR-03124-1) und leitet Anfragen an die lokalen Instanzen - der AusweisApp2 weiter. Eine Weiterleitung der Discovery-Nachrichten (Ergänzung + der |AppName| weiter. Eine Weiterleitung der Discovery-Nachrichten (Ergänzung zu BSI TR-03112-6 - IFD Service - Kapitel 3) erfolgt nicht, so dass SaK-Geräte in diesem Betriebsmodus nicht erkannt bzw. genutzt werden können. Ohne Angabe des Parameters wird der Proxy-Dienst automatisch eingerichtet, wenn Terminaldienste @@ -41,10 +44,10 @@ PROXYSERVICE AUTOSTART Durch Angabe von AUTOSTART=true wird ein Autostart-Eintrag für alle Benutzer - erstellt. Die Deaktivierung des Autostarts ist den Benutzern in der AusweisApp2 + erstellt. Die Deaktivierung des Autostarts ist den Benutzern in der |AppName| dadurch nicht möglich. Ohne Angabe wird der Autostart-Eintrag nicht erstellt (false). In diesem Fall ist es jedoch jedem Benutzer möglich, die Autostart- - Funktion innerhalb der AusweisApp2 für sich zu aktivieren. + Funktion innerhalb der |AppName| für sich zu aktivieren. AUTOHIDE Betrifft die automatische Minimierung nach Abschluss einer erfolgreichen @@ -52,18 +55,18 @@ AUTOHIDE wird diese deaktiviert. Der Benutzer kann diese Einstellung anpassen. REMINDTOCLOSE - Wenn der Benutzer die AusweisApp2 per Klick auf das X schließt, wird er darauf + Wenn der Benutzer die |AppName| per Klick auf das X schließt, wird er darauf hingewiesen, dass nur die Benutzeroberfläche geschlossen wird und die - AusweisApp2 weiterhin im Infobereich zur Verfügung steht. Zu diesem Zeitpunkt + |AppName| weiterhin im Infobereich zur Verfügung steht. Zu diesem Zeitpunkt ist es möglich, den Hinweis zukünftig zu unterdrücken. Durch REMINDTOCLOSE=false kann dieser Hinweis von vornherein deaktiviert werden. Ohne Angabe ist er aktiviert (true). ASSISTANT - Startet der Benutzer die AusweisApp2 zum ersten Mal, wird die Benutzeroberfläche + Startet der Benutzer die |AppName| zum ersten Mal, wird die Benutzeroberfläche geöffnet und ein Einrichtungsassistent angezeigt. Bei jedem weiteren Start wird - die AusweisApp2 im Hintergrund gestartet und der Einrichtungsassistent erscheint - nicht. Durch ASSISTANT=false wird die AusweisApp2 auch beim ersten Start im + die |AppName| im Hintergrund gestartet und der Einrichtungsassistent erscheint + nicht. Durch ASSISTANT=false wird die |AppName| auch beim ersten Start im Hintergrund ohne Einrichtungsassistenten gestartet. Ohne Angabe ist der Einrichtungsassistent aktiviert (true). @@ -92,12 +95,12 @@ CUSTOMPROXYPORT der Installation über eine Checkbox in den Einstellungen deaktiviert werden. UPDATECHECK - Wird die Benutzeroberfläche der AusweisApp2 geöffnet, wird eine Überprüfung auf - eine neue Version der AusweisApp2 gestartet, falls seit der letzten Überprüfung + Wird die Benutzeroberfläche der |AppName| geöffnet, wird eine Überprüfung auf + eine neue Version der |AppName| gestartet, falls seit der letzten Überprüfung mindestens 24 Stunden vergangen sind. Liegt eine neue Version vor, wird der Benutzer darüber in einem Dialog informiert. Durch Setzen von UPDATECHECK auf false oder true kann diese Überprüfung deaktiviert bzw. aktiviert werden. - Die Einstellung kann dann durch den Benutzer in der AusweisApp2 nicht geändert + Die Einstellung kann dann durch den Benutzer in der |AppName| nicht geändert werden. Ohne Angabe ist die Überprüfung aktiviert, der Benutzer kann die Einstellung jedoch ändern. Der UPDATECHECK Parameter beeinflusst weder die Aktualisierung der Anbieterliste noch die Aktualisierung der @@ -118,13 +121,6 @@ SECURESCREENKEYBOARD werden. Durch Setzen von SECURESCREENKEYBOARD auf false oder true kann die Animation aktiviert bzw. deaktiviert werden. Der Benutzer kann diese Einstellung anpassen. -HISTORY - Jede Selbstauskunft oder Authentisierung wird im Verlauf gespeichert. Dabei - werden jedoch keine persönlichen Daten gespeichert, sondern nur der Zeitpunkt, - der Anbieter und die ausgelesenen Datenfelder (ohne Inhalt). Durch Setzen - von HISTORY auf false oder true kann der Verlauf deaktiviert bzw. aktiviert - werden. Der Benutzer kann diese Einstellung anpassen. - ENABLECANALLOWED Aktiviert die Unterstützung für den CAN-Allowed-Modus (Vor-Ort-Auslesen). Wenn ein entsprechendes Berechtigungszertifikat vorliegt, muss zum Auslesen die CAN anstelle der PIN eingegeben werden. @@ -134,7 +130,7 @@ SKIPRIGHTSONCANALLOWED CAN-Eingabe. LAUNCH - Startet die AusweisApp2 nach dem Ende der Installation. + Startet die |AppName| nach dem Ende der Installation. Alternativ kann mit Orca [#orca]_ eine MST-Datei erzeugt werden, die die oben genannten Parameter definiert. Die Parameter sind in den Tabellen "Directory" @@ -143,11 +139,11 @@ Kommando: .. code-block:: winbatch - msiexec /i AusweisApp2-X.YY.Z.msi /quiet TRANSFORMS=file.mst + msiexec /i AusweisApp-X.YY.Z.msi /quiet TRANSFORMS=file.mst -Um den Start der AusweisApp2 auf Systemen mit fehlender Grafikbeschleunigung +Um den Start der |AppName| auf Systemen mit fehlender Grafikbeschleunigung zu optimieren, kann die Systemvariable "QT_QUICK_BACKEND" auf den Wert -"software" gesetzt werden. In diesem Fall verzichtet die AusweisApp2 auf den +"software" gesetzt werden. In diesem Fall verzichtet die |AppName| auf den Versuch die Grafikbeschleunigung zu nutzen und startet direkt mit dem alternativen Softwarerenderer. @@ -158,7 +154,7 @@ Unter macOS ist keine Installation per Kommandozeile vorgesehen. Jedoch können einige der oben genannten Einstellung durch eine plist-Datei im Verzeichnis /Library/Preferences systemweit vorgegeben werden. Diese plist-Datei muss dabei manuell durch den Administrator des Systems hinterlegt werden und wird von allen -(zukünftigen) Installationen der AusweisApp2 verwendet. Alle nicht genannten +(zukünftigen) Installationen der |AppName| verwendet. Alle nicht genannten Einstellungen werden auf macOS nicht unterstützt. Der Name der Datei muss "com.governikus.AusweisApp2.plist" lauten. Der Inhalt wird im folgenden dargestellt: @@ -189,8 +185,6 @@ dargestellt: visualPrivacy - history.enable - enableCanAllowed skipRightsOnCanAllowed @@ -215,7 +209,6 @@ customProxyHost CUSTOMPROXYHOST keylessPassword ONSCREENKEYBOARD shuffleScreenKeyboard SHUFFLESCREENKEYBOARD visualPrivacy SECURESCREENKEYBOARD -history.enable HISTORY enableCanAllowed ENABLECANALLOWED skipRightsOnCanAllowed SKIPRIGHTSONCANALLOWED ======================= ======================= @@ -235,32 +228,32 @@ Anforderungen an die Einsatzumgebung Rechte für Installation und Ausführung '''''''''''''''''''''''''''''''''''''' -Für die Installation der AusweisApp2 sind Administratorrechte erforderlich. +Für die Installation der |AppName| sind Administratorrechte erforderlich. -Die Ausführung der AusweisApp2 erfordert keine Administratorrechte. +Die Ausführung der |AppName| erfordert keine Administratorrechte. Verwendete Netzwerk-Ports ''''''''''''''''''''''''' -In :numref:`porttable_de` werden alle von der AusweisApp2 genutzten Ports +In :numref:`porttable_de` werden alle von der |AppName| genutzten Ports aufgelistet. Eine schematische Darstellung der einzelnen Verbindungen, die von der -AusweisApp2 genutzt werden, ist in :numref:`communicationmodel_de` dargestellt. +|AppName| genutzt werden, ist in :numref:`communicationmodel_de` dargestellt. -Die AusweisApp2 startet einen HTTP-Server, der über Port 24727 erreichbar +Die |AppName| startet einen HTTP-Server, der über Port 24727 erreichbar ist. Der Server empfängt nur auf der localhost Netzwerkschnittstelle. Die Erreichbarkeit dieses lokalen Servers ist für die Onlineausweisfunktion notwendig, da Anbieter mit einem HTTP-Redirect auf den lokalen Server -umleiten um den Ausweisvorgang in der AusweisApp2 fortzuführen (eID1). -Außerdem wird über den Server die Verwendung der AusweisApp2 von anderen +umleiten um den Ausweisvorgang in der |AppName| fortzuführen (eID1). +Außerdem wird über den Server die Verwendung der |AppName| von anderen Anwendungen über eine Websocket-Schnittstelle angeboten (SDK-Funktion, eID-SDK). Daher müssen eingehende lokale Netzwerkverbindungen auf dem TCP Port 24727 ermöglicht werden. -Bei aktiviertem Proxy-Dienst übernimmt der AusweisApp2-Proxy die Serverfunktionen -der AusweisApp2 auf Port 24727. Die Instanzen der AusweisApp2 erkennen den Proxy +Bei aktiviertem Proxy-Dienst übernimmt der |AppName|-Proxy die Serverfunktionen +der |AppName| auf Port 24727. Die Instanzen der |AppName| erkennen den Proxy und benutzen in diesem Fall einen zufälligen freien Port auf den der Proxy die Anfragen weiterleitet. @@ -272,13 +265,13 @@ Hierzu muss eventuell die AP Isolation im Router deaktiviert werden. .. _communicationmodel_de: .. figure:: CommunicationModel_de.pdf - Kommunikationsmodell der AusweisApp2 + Kommunikationsmodell der |AppName| -Der Installer der AusweisApp2 bietet die Option, für alle angebotenen -Funktionen der AusweisApp2 die erforderlichen Firewall-Regeln in der +Der Installer der |AppName| bietet die Option, für alle angebotenen +Funktionen der |AppName| die erforderlichen Firewall-Regeln in der Windows-Firewall zu registrieren. Erfolgt die Registrierung der Firewall-Regeln nicht, wird der Benutzer bei -einem Verbindungsaufbau der AusweisApp2 mit einem Dialog der Windows-Firewall +einem Verbindungsaufbau der |AppName| mit einem Dialog der Windows-Firewall aufgefordert, die ausgehenden Datenverbindungen zuzulassen. Durch Registrierung der Firewall-Regeln während der Installation werden diese Aufforderungen unterbunden. @@ -294,7 +287,7 @@ aufgelistet. TLS-Verbindungen '''''''''''''''' -Es ist generell nicht möglich, die AusweisApp2 mit einem TLS-Termination-Proxy +Es ist generell nicht möglich, die |AppName| mit einem TLS-Termination-Proxy zu verwenden, da die übertragenen TLS-Zertifikate über eine Verschränkung mit dem Berechtigungszertifikat aus der Personalausweis-PKI validiert werden. CA-Zertifikate im Windows-Truststore werden daher ignoriert. @@ -304,7 +297,7 @@ CA-Zertifikate im Windows-Truststore werden daher ignoriert. \begin{landscape} .. _porttable_de: -.. csv-table:: Netzwerkverbindungen der AusweisApp2 +.. csv-table:: Netzwerkverbindungen der |AppName| :header: "Referenz", "Protokoll", "Port", "Richtung", "Optional", "Zweck", "Anmerkungen" :widths: 8, 8, 8, 8, 8, 35, 25 @@ -314,9 +307,9 @@ CA-Zertifikate im Windows-Truststore werden daher ignoriert. "eID-SDK", TCP, 24727 [#aa2proxy]_, "eingehend", "Nein", "Verwendung der SDK-Schnittstelle", "Nur erreichbar von localhost [#TR-03124]_" "SaK1", UDP, 24727 [#aa2proxy]_, "eingehend", "Ja", "Smartphone als Kartenleser, Erkennung [#TR-03112]_", "Broadcasts" "SaK2", TCP, , "ausgehend", "Ja", "Smartphone als Kartenleser, Verwendung [#TR-03112]_", "Verbindung im lokalen Subnetz" - "Update", TCP, 443, "ausgehend", "Ja", "Updates [#govurl]_ zu Anbietern und Kartenlesern sowie Informationen zu neuen AusweisApp2-Versionen [#updatecheck]_ .", "Die Zertifikate der TLS-Verbindung werden mit in der AusweisApp2 mitgelieferten CA-Zertifikaten validiert. Im Betriebssystem hinterlegte CA-Zertifikate werden ignoriert." + "Update", TCP, 443, "ausgehend", "Ja", "Updates [#govurl]_ zu Anbietern und Kartenlesern sowie Informationen zu neuen |AppName|-Versionen [#updatecheck]_ .", "Die Zertifikate der TLS-Verbindung werden mit in der |AppName| mitgelieferten CA-Zertifikaten validiert. Im Betriebssystem hinterlegte CA-Zertifikate werden ignoriert." -.. [#aa2proxy] Oder ein zufälliger Port bei Verwendung des AusweisApp2-Proxys. +.. [#aa2proxy] Oder ein zufälliger Port bei Verwendung des |AppName|-Proxys. .. [#TR-03124] Siehe TR-03124 des BSI .. [#eidports] Port 443 wird für die initiale Kontaktaufnahme zum Anbieter bzw. eID-Server verwendet. Durch die Konfiguration des Dienstes durch den @@ -324,18 +317,74 @@ CA-Zertifikate im Windows-Truststore werden daher ignoriert. Einsatz kommen. .. [#TR-03112] Siehe TR-03112-6 des BSI .. [#govurl] Erreichbar unter dem URL https://appl.governikus-asp.de/ausweisapp2/ -.. [#updatecheck] Die Überprüfung auf neue AusweisApp2-Versionen kann deaktiviert werden, siehe +.. [#updatecheck] Die Überprüfung auf neue |AppName|-Versionen kann deaktiviert werden, siehe Kommandozeilenparameter UPDATECHECK .. _firewalltable_de: -.. csv-table:: Firewallregeln der AusweisApp2 +.. csv-table:: Firewallregeln der |AppName| :header: "Name", "Protokoll", "Port", "Richtung", "Umgesetzte Verbindung" :widths: 25, 15, 15, 15, 30 :align: left - "AusweisApp2-Firewall-Rule", TCP, \*, "ausgehend", "eID2, eID3, SaK2, Update" - "AusweisApp2-SaC", UDP, 24727, "eingehend", "SaK1" + "AusweisApp-Firewall-Rule", TCP, \*, "ausgehend", "eID2, eID3, SaK2, Update" + "AusweisApp-SaC", UDP, 24727, "eingehend", "SaK1" .. raw:: latex \end{landscape} + +Entwickleroptionen +~~~~~~~~~~~~~~~~~~ + +Die |AppName| verfügt über sogenannte Entwickleroptionen. Diese sind +für die unterstützten Betriebssystem Windows und macOS verfügbar. Sie +unterstützen die Integration eines eID-Dienstes. + + +Windows & macOS +--------------- + +Das Aktivieren der Entwickleroptionen erfolgt sowohl für Windows als auch +für macOS über 10 Klicks auf die Versionsnummer im Bereich "Hilfe" -> +"Versionsinformationen". Nach der Aktivierung sind die Entwickleroptionen +über den Bereich "Einstellungen" erreichbar. + + +Android & iOS +------------- + +In den mobilen Versionen der |AppName| ist der Entwicklermodus nicht +verfügbar. Lediglich der Testmodus (Test-PKI) für die Selbstauskunft kann +durch 10 Klicks auf die Lupe auf der Startseite aktiviert und deaktiviert werden. + + +Einstellungen +------------- + +Die Entwickleroptionen bieten zwei Einstellungsmöglichkeiten: + +Testmodus für die Selbstauskunft (Test-PKI) +''''''''''''''''''''''''''''''''''''''''''' + +Die Selbstauskunft ist ein fest integrierter Dienst der |AppName| und kann +nur mit Echtausweisen genutzt werden. Wird der Testmodus (Test-PKI) aktiviert, +nutzt die |AppName| einen Test-Dienst, der es ermöglicht, eine Selbstauskunft +mit einem Testausweis durchzuführen. + +Entwicklermodus +''''''''''''''' + +Mit der Aktivierung des Entwicklermodus werden einige Sicherheitsabfragen +während einer Authentisierung ignoriert. In Entwicklungsszenarien, in denen +ohnehin mit Test-Diensten gearbeitet wird, führt das Ignorieren der +Sicherheitsabfragen dazu, dass eine Authentisierung erfolgreich durchgeführt +werden kann. Dazu gehört beispielweise, dass neben sicheren TLS-Verbindungen +(https) auch unsichere Verbindungen ohne TLS (http) akzeptiert werden. Auch +werden abgelaufene Zertifikate ignoriert. Auf jede Sicherheitsverletzung wird +in den internen Benachrichtigungen der |AppName| bzw. des Betriebssystems +hingewiesen. + + +**Wichtig:** Der Entwicklermodus kann nur für Test-Dienste verwendet werden, +eine Verwendung mit echten Berechtigungszertifikaten ist nicht möglich. + diff --git a/docs/installation/README.en.rst b/docs/installation/README.en.rst index 4ab2cd596..43dcfdece 100644 --- a/docs/installation/README.en.rst +++ b/docs/installation/README.en.rst @@ -1,10 +1,13 @@ English ======= +Installation +~~~~~~~~~~~~ + Windows ------- -Start the installer of AusweisApp2 using the command line to configure the +Start the installer of |AppName| using the command line to configure the installation process and preset system-wide default settings. The return value of msiexec indicates the result of the installation [#msiexecreturnvalues]_. In addition to the usual arguments [#standardarguments]_, the following command @@ -12,11 +15,11 @@ contains all supported arguments, which are explained below. .. code-block:: winbatch - msiexec /i AusweisApp2-X.YY.Z.msi /quiet INSTALLDIR="C:\AusweisApp2" SYSTEMSETTINGS=false DESKTOPSHORTCUT=false PROXYSERVICE=false AUTOSTART=false AUTOHIDE=false REMINDTOCLOSE=false ASSISTANT=false TRANSPORTPINREMINDER=false CUSTOMPROXYTYPE="HTTP" CUSTOMPROXYHOST="proxy.example.org" CUSTOMPROXYPORT=1337 UPDATECHECK=false ONSCREENKEYBOARD=true SHUFFLESCREENKEYBOARD=true SECURESCREENKEYBOARD=true HISTORY=false ENABLECANALLOWED=true SKIPRIGHTSONCANALLOWED=true LAUNCH=true + msiexec /i AusweisApp-X.YY.Z.msi /quiet INSTALLDIR="C:\AusweisApp" SYSTEMSETTINGS=false DESKTOPSHORTCUT=false PROXYSERVICE=false AUTOSTART=false AUTOHIDE=false REMINDTOCLOSE=false ASSISTANT=false TRANSPORTPINREMINDER=false CUSTOMPROXYTYPE="HTTP" CUSTOMPROXYHOST="proxy.example.org" CUSTOMPROXYPORT=1337 UPDATECHECK=false ONSCREENKEYBOARD=true SHUFFLESCREENKEYBOARD=true SECURESCREENKEYBOARD=true ENABLECANALLOWED=true SKIPRIGHTSONCANALLOWED=true LAUNCH=true INSTALLDIR States the installation directory. If not specified, the folder - "C:\\Program Files\\AusweisApp2" is used. + "C:\\Program Files\\AusweisApp" is used. SYSTEMSETTINGS Concerns the settings of firewall rules of the Windows Firewall. When not @@ -29,8 +32,8 @@ DESKTOPSHORTCUT PROXYSERVICE The proxy service is required to enable the parallel operation of several - entities of AusweisApp2. The proxy service monitors port 24727 (defined in - BSI TR-03124-1) and forwards requests to the local AusweisApp2 instances. + entities of |AppName|. The proxy service monitors port 24727 (defined in + BSI TR-03124-1) and forwards requests to the local |AppName| instances. The Discovery messages (amendment to BSI TR-03112-6 - IFD Service - Chapter 3) are not forwarded, so that SaC devices cannot be recognized or used in this operating mode. Not specified, the proxy service will be installed @@ -39,9 +42,9 @@ PROXYSERVICE AUTOSTART Setting AUTOSTART=true creates autostart entry for all users. Users are unable - to deactivate the autostart function in the AusweisApp2. Not specified, no + to deactivate the autostart function in the |AppName|. Not specified, no autostart entry is created (false). In that case, users are able to activate the - autostart function in the AusweisApp2. + autostart function in the |AppName|. AUTOHIDE Concerns the automatic minimization after a successful authentication. Not @@ -49,17 +52,17 @@ AUTOHIDE Users can adjust this setting to their preferences. REMINDTOCLOSE - Closing the AusweisApp2 by clicking on the X, the user is notified that only the - user interface is closed and that the AusweisApp2 is still available in the info + Closing the |AppName| by clicking on the X, the user is notified that only the + user interface is closed and that the |AppName| is still available in the info tray. At this point, it is possible to prevent future notifications. Setting REMINDTOCLOSE=false deactivates this notification from the outset. Not specified, it is activated (true). ASSISTANT - Starting the AusweisApp2 for the first time, the user interface is displayed and - the installation wizard is shown. With each subsequent start, the AusweisApp2 + Starting the |AppName| for the first time, the user interface is displayed and + the installation wizard is shown. With each subsequent start, the |AppName| is started in the background, without the installation wizard being shown. By - indicating ASSISTANT=false, the AusweisApp2 is started in the background without + indicating ASSISTANT=false, the |AppName| is started in the background without the installation wizard from the outset. Not specified, the installation wizard is activated (true). @@ -86,11 +89,11 @@ CUSTOMPROXYPORT with a checkbox in the settings. UPDATECHECK - Upon opening the user interface of the AusweisApp2, an update check is started, + Upon opening the user interface of the |AppName|, an update check is started, provided that at least 24 hours have elapsed since the last update check. If a newer version is available, the user is notified accordingly. Setting UPDATECHECK to false or true deactivates or activates the update check - respectively. Users are unable to change this setting in the AusweisApp2. Not + respectively. Users are unable to change this setting in the |AppName|. Not specified, the update check is activated, but users can adjust the settings. The UPDATECHECK parameter affects neither updates of the service provider list nor updates of card reader information. @@ -110,12 +113,6 @@ SECURESCREENKEYBOARD disabled. By setting SECURESCREENKEYBOARD to false or true, the animation can be activated or deactivated. Users are able to adjust the setting. -HISTORY - Each authentication is saved in the history. No personal data is saved, only the - time of authentication, the provider and the selected fields (without - content). Indicating HISTORY as false or true, the history function is - deactivated or activated. Users are able to adjust the settings. - ENABLECANALLOWED Enables support for the CAN allowed mode. If the provider got issued a corresponding authorization certificate the ID card can be read by entering the CAN instead of the PIN. @@ -125,7 +122,7 @@ SKIPRIGHTSONCANALLOWED the CAN. LAUNCH - Starts the AusweisApp2 after the installation has finished. + Starts the |AppName| after the installation has finished. Alternatively, Orca [#orca]_ can be used to create an MST file that defines the above arguments. The arguments are available in the "Directory" and "Property" @@ -133,11 +130,11 @@ tables. The MST file can be transferred with the following command: .. code-block:: winbatch - msiexec /i AusweisApp2-X.YY.Z.msi /quiet TRANSFORMS=file.mst + msiexec /i AusweisApp-X.YY.Z.msi /quiet TRANSFORMS=file.mst -In order to optimize the start of the AusweisApp2 on systems with no graphics +In order to optimize the start of the |AppName| on systems with no graphics acceleration, the system variable "QT_QUICK_BACKEND" can be set to the value -"software". In this case, the AusweisApp2 does not attempt to use graphics +"software". In this case, the |AppName| does not attempt to use graphics acceleration and starts directly with the alternative software renderer. macOS @@ -147,7 +144,7 @@ MacOS does not provide a command line installation. However, some of the above settings can be specified system-wide by a plist file in the /Library/Preferences directory. This plist file must be manually stored by the administrator of the system and will be used by all (future) installations of -AusweisApp2. All not mentioned settings are not supported on macOS. The name of +|AppName|. All not mentioned settings are not supported on macOS. The name of the file must be "com.governikus.AusweisApp2.plist". The content is shown below: .. code-block:: xml @@ -176,8 +173,6 @@ the file must be "com.governikus.AusweisApp2.plist". The content is shown below: visualPrivacy - history.enable - enableCanAllowed skipRightsOnCanAllowed @@ -201,7 +196,6 @@ customProxyHost CUSTOMPROXYHOST keylessPassword ONSCREENKEYBOARD shuffleScreenKeyboard SHUFFLESCREENKEYBOARD visualPrivacy SECURESCREENKEYBOARD -history.enable HISTORY enableCanAllowed ENABLECANALLOWED skipRightsOnCanAllowed SKIPRIGHTSONCANALLOWED ======================= ======================= @@ -220,45 +214,45 @@ Operational Environment Requirements Required authorization for installation and execution ''''''''''''''''''''''''''''''''''''''''''''''''''''' -Administrator privileges are required to install the AusweisApp2. +Administrator privileges are required to install the |AppName|. -The execution of the AusweisApp2 does not require administrator privileges. +The execution of the |AppName| does not require administrator privileges. Used network ports '''''''''''''''''' -All network ports used by the AusweisApp2 are listed in :numref:`porttable_en`. +All network ports used by the |AppName| are listed in :numref:`porttable_en`. :numref:`communicationmodel_en` shows a schematic representation of the -individual connections made by the AusweisApp2. +individual connections made by the |AppName|. -The AusweisApp2 starts a HTTP-Server on port 24727. +The |AppName| starts a HTTP-Server on port 24727. The server binds only to the localhost network interface. The availability of the local server is necessary for the online eID function, because providers will redirect the user with a HTTP redirect to the -local server to continue the authentication process in the AusweisApp2 (eID1). +local server to continue the authentication process in the |AppName| (eID1). The server is also used to offer other local applications to use the -AusweisApp2 via a websocket interface (SDK function, eID-SDK). +|AppName| via a websocket interface (SDK function, eID-SDK). Therefore local incoming network connections to TCP Port 24727 must be permitted. -If the proxy service is activated, the AusweisApp2 proxy takes over the server -functions of AusweisApp2 on port 24727. The entities of AusweisApp2 recognize +If the proxy service is activated, the |AppName| proxy takes over the server +functions of |AppName| on port 24727. The entities of |AppName| recognize the proxy and use a free random port in this case to which the proxy forwards the requests. Broadcast on UDP port 24727 in the local subnet have to be receivable by the -AusweisApp2 to use the "Smartphone as Card Reader" functionality. +|AppName| to use the "Smartphone as Card Reader" functionality. It may be necessary to deactivate AP isolation on your router. .. _communicationmodel_en: .. figure:: CommunicationModel_en.pdf - Communication model of the AusweisApp2 + Communication model of the |AppName| -The installer of the AusweisApp2 provides an option to register all needed +The installer of the |AppName| provides an option to register all needed firewall rules in the Windows Firewall. If the rules are not registered, the user will be prompted by the Windows -Firewall to allow the outgoing connections once the AusweisApp2 tries to +Firewall to allow the outgoing connections once the |AppName| tries to connect to a server. These prompts are suppressed by registering the firewall rules during installation. @@ -274,7 +268,7 @@ TLS connections Transmitted TLS certificates are solely validated via the interlacing with the authorization certificate issued by the german eID PKI. CA certificates in the Windows truststore are thus ignored. -It is therefore generally not possible to use the AusweisApp2 behind a +It is therefore generally not possible to use the |AppName| behind a TLS termination proxy. .. raw:: latex @@ -282,7 +276,7 @@ TLS termination proxy. \begin{landscape} .. _porttable_en: -.. csv-table:: Network connections of the AusweisApp2 +.. csv-table:: Network connections of the |AppName| :header: "Reference", "Protocol", "Port", "Direction", "Optional", "Purpose", "Note" :widths: 8, 8, 8, 8, 8, 35, 25 @@ -292,27 +286,80 @@ TLS termination proxy. "eID-SDK", TCP, 24727 [#aa2proxy]_, "incoming", "no", "Usage of the SDK functionality", "Only accessible from localhost [#TR-03124]_" "SaC1", UDP, 24727 [#aa2proxy]_, "incoming", "yes", "Smartphone as Card Reader, detection [#TR-03112]_", "Broadcasts" "SaC2", TCP, , "outgoing", "yes", "Smartphone as Card Reader, usage [#TR-03112]_", "Connection in local subnet" - "Update", TCP, 443, "outgoing", "yes", "Updates [#govurl]_ of provider and card reader information as well as information on new AusweisApp2 versions [#updatecheck]_ .", "TLS certificates will be validated against CA certificates included in the AusweisApp2. CA certificates provided by the OS are ignored." + "Update", TCP, 443, "outgoing", "yes", "Updates [#govurl]_ of provider and card reader information as well as information on new |AppName| versions [#updatecheck]_ .", "TLS certificates will be validated against CA certificates included in the |AppName|. CA certificates provided by the OS are ignored." -.. [#aa2proxy] Or a random port when using AusweisApp2 proxy. +.. [#aa2proxy] Or a random port when using |AppName| proxy. .. [#TR-03124] See TR-03124 specification from the BSI .. [#eidports] Port 443 is used for the initial contact with the provider or eID server. Due to configuration of the service on the service provider's behalf, any other port might be used by forwarding. .. [#TR-03112] See TR-03112-6 specifiaction from the BSI .. [#govurl] All updates are based on the URL https://appl.governikus-asp.de/ausweisapp2/ -.. [#updatecheck] Automatic checks for new AusweisApp2 versions can be deactivated, see commandline parameter +.. [#updatecheck] Automatic checks for new |AppName| versions can be deactivated, see commandline parameter UPDATECHECK. .. _firewalltable_en: -.. csv-table:: Firewall rules of the AusweisApp2 +.. csv-table:: Firewall rules of the |AppName| :header: "Name", "Protocol", "Port", "Direction", "Connection reference" :widths: 25, 15, 15, 15, 30 :align: left - "AusweisApp2-Firewall-Rule", TCP, \*, "outgoing", "eID2, eID3, SaC2, Update" - "AusweisApp2-SaC", UDP, 24727, "incoming", "SaC1" + "AusweisApp-Firewall-Rule", TCP, \*, "outgoing", "eID2, eID3, SaC2, Update" + "AusweisApp-SaC", UDP, 24727, "incoming", "SaC1" .. raw:: latex \end{landscape} + +Developer Options +~~~~~~~~~~~~~~~~~ + +|AppName| features so-called developer options, available for the +supported operating systems of Windows and macOS. They facilitate +the integration of eID services. + + +Windows & macOS +--------------- + +Developer options are activated by the version number accessible via +"Help" -> "Version Information" 10 times. This is applicable for both +Windows and macOS. Once activated, the developer options are accessible +via "Settings". + + +Android & iOS +------------- + +The mobile version of |AppName| does not feature the developer mode. Solely +the test mode (Test-PKI) for self-authentication may be activated and +deactivated by clicking the magnifying glass on the start screen 10 times. + + +Settings +-------- + +Developer options allow to adjust two different settings: + +Test mode for self-authentication (Test-PKI) +'''''''''''''''''''''''''''''''''''''''''''' + +In general, the self-authentication is a built-in service of |AppName| and +can only be used with genuine ID cards. However, when in test mode, |AppName| +uses a test service allowing for self-authentication with a test ID card. + +Developer mode +'''''''''''''' + +When the developer mode is activated, some safety measures during an +authentication process are ignored. Ignoring the safety measures with test +services usually employed in test scenarios, yields a successful authentication. +For example, secure TLS connections (https) as well as insecure connections +without TLS (http) are accepted. Invalid certificates will be ignored. Each +safety breach will be highlighted as an internal notification in |AppName| +or the operating system respectively. + + +**Please note:** +Developer mode can only be used for test services, usage with genuine provider +certificates is not possible. diff --git a/docs/installation/conf.py.in b/docs/installation/conf.py.in index 6ac8a5b1d..07425e7a9 100644 --- a/docs/installation/conf.py.in +++ b/docs/installation/conf.py.in @@ -41,7 +41,7 @@ source_suffix = '.rst' master_doc = 'index' # General information about the project. -project = 'AusweisApp2 Installation' +project = '@PROJECT_NAME@ Erweiterte Dokumentation für Administratoren und Entwickler' copyright = '2018-2023, Governikus GmbH & Co. KG' author = 'Governikus GmbH & Co. KG' @@ -98,7 +98,7 @@ html_show_copyright = True html_scaled_image_link = False # Output file base name for HTML help builder. -htmlhelp_basename = 'AusweisApp2Installation' +htmlhelp_basename = '@PROJECT_NAME@InstallationIntegration' html_context = { 'display_github': False, @@ -122,9 +122,9 @@ latex_elements = { 'preamble': ''' \\usepackage{lscape} \\hypersetup{pdfauthor={Governikus GmbH \& Co. KG}, - pdftitle={AusweisApp2}, - pdfsubject={Installation}, - pdfkeywords={installation}, + pdftitle={@PROJECT_NAME@}, + pdfsubject={Erweiterte Dokumentation für Administratoren und Entwickler}, + pdfkeywords={installation, integration}, pdfproducer={LaTeX}, pdfcreator={Sphinx} } @@ -132,7 +132,15 @@ latex_elements = { # Override tableofcontents 'tableofcontents': ''' -\\tableofcontents +% Remove header of tableofcontent +\\makeatletter +\\@starttoc{toc} +\\makeatother + +% Only show part title without "Part I" +\\renewcommand{\\thepart}{} +\\renewcommand{\\partname}{} + \\newpage \\pagestyle{plain} \\pagenumbering{arabic} @@ -146,7 +154,7 @@ latex_elements = { # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'AusweisApp2-@VERSION_DVCS@-NetInstallation.tex', 'AusweisApp2 Installation', + (master_doc, '@PROJECT_NAME@-@VERSION_DVCS@-NetInstallation_Integration.tex', '@PROJECT_NAME@ \\linebreak Erweiterte Dokumentation für Administratoren und Entwickler', 'Governikus GmbH \& Co. KG', 'howto'), ] @@ -169,3 +177,9 @@ latex_show_urls = 'footnote' # If false, no module index is generated. #latex_domain_indices = True + +latex_toplevel_sectioning = 'part' + +rst_epilog = """ +.. |AppName| replace:: @PROJECT_NAME@ +""" \ No newline at end of file diff --git a/docs/installation/index.rst b/docs/installation/index.rst index 44f046377..3f8c94d2b 100644 --- a/docs/installation/index.rst +++ b/docs/installation/index.rst @@ -6,8 +6,7 @@ Table of contents \clearpage .. toctree:: - :maxdepth: 3 - :caption: Installation + :maxdepth: 5 README.de README.en diff --git a/docs/integration/README.de.rst b/docs/integration/README.de.rst deleted file mode 100644 index 146dbf5af..000000000 --- a/docs/integration/README.de.rst +++ /dev/null @@ -1,54 +0,0 @@ -Deutsch - Entwickleroptionen -============================ - -Die AusweisApp2 verfügt über sogenannte Entwickleroptionen. Diese sind -für die unterstützten Betriebssystem Windows und macOS verfügbar. Sie -unterstützen die Integration eines eID-Dienstes. - - -Windows & macOS ---------------- - -Das Aktivieren der Entwickleroptionen erfolgt sowohl für Windows als auch -für macOS über 10 Klicks auf die Versionsnummer im Bereich "Hilfe" -> -"Versionsinformationen". Nach der Aktivierung sind die Entwickleroptionen -über den Bereich "Einstellungen" erreichbar. - - -Android & iOS -------------- - -In den mobilen Versionen der AusweisApp2 ist der Entwicklermodus nicht -verfügbar. Lediglich der Testmodus (Test-PKI) für die Selbstauskunft kann -durch 10 Klicks auf die Lupe auf der Startseite aktiviert und deaktiviert werden. - - -Einstellungen -------------- - -Die Entwickleroptionen bieten zwei Einstellungsmöglichkeiten: - -Testmodus für die Selbstauskunft (Test-PKI) -''''''''''''''''''''''''''''''''''''''''''' - -Die Selbstauskunft ist ein fest integrierter Dienst der AusweisApp2 und kann -nur mit Echtausweisen genutzt werden. Wird der Testmodus (Test-PKI) aktiviert, -nutzt die AusweisApp2 einen Test-Dienst, der es ermöglicht, eine Selbstauskunft -mit einem Testausweis durchzuführen. - -Entwicklermodus -''''''''''''''' - -Mit der Aktivierung des Entwicklermodus werden einige Sicherheitsabfragen -während einer Authentisierung ignoriert. In Entwicklungsszenarien, in denen -ohnehin mit Test-Diensten gearbeitet wird, führt das Ignorieren der -Sicherheitsabfragen dazu, dass eine Authentisierung erfolgreich durchgeführt -werden kann. Dazu gehört beispielweise, dass neben sicheren TLS-Verbindungen -(https) auch unsichere Verbindungen ohne TLS (http) akzeptiert werden. Auch -werden abgelaufene Zertifikate ignoriert. Auf jede Sicherheitsverletzung wird -in den internen Benachrichtigungen der AusweisApp2 bzw. des Betriebssystems -hingewiesen. - - -**Wichtig:** Der Entwicklermodus kann nur für Test-Dienste verwendet werden, -eine Verwendung mit echten Berechtigungszertifikaten ist nicht möglich. diff --git a/docs/integration/README.en.rst b/docs/integration/README.en.rst deleted file mode 100644 index 07f475c82..000000000 --- a/docs/integration/README.en.rst +++ /dev/null @@ -1,52 +0,0 @@ -English - Developer Options -=========================== - -AusweisApp2 features so-called developer options, available for the -supported operating systems of Windows and macOS. They facilitate -the integration of eID services. - - -Windows & macOS ---------------- - -Developer options are activated by the version number accessible via -"Help" -> "Version Information" 10 times. This is applicable for both -Windows and macOS. Once activated, the developer options are accessible -via "Settings". - - -Android & iOS -------------- - -The mobile version of AusweisApp2 does not feature the developer mode. Solely -the test mode (Test-PKI) for self-authentication may be activated and -deactivated by clicking the magnifying glass on the start screen 10 times. - - -Settings --------- - -Developer options allow to adjust two different settings: - -Test mode for self-authentication (Test-PKI) -'''''''''''''''''''''''''''''''''''''''''''' - -In general, the self-authentication is a built-in service of AusweisApp2 and -can only be used with genuine ID cards. However, when in test mode, AusweisApp2 -uses a test service allowing for self-authentication with a test ID card. - -Developer mode -'''''''''''''' - -When the developer mode is activated, some safety measures during an -authentication process are ignored. Ignoring the safety measures with test -services usually employed in test scenarios, yields a successful authentication. -For example, secure TLS connections (https) as well as insecure connections -without TLS (http) are accepted. Invalid certificates will be ignored. Each -safety breach will be highlighted as an internal notification in AusweisApp2 -or the operating system respectively. - - -**Please note:** -Developer mode can only be used for test services, usage with genuine provider -certificates is not possible. diff --git a/docs/integration/conf.py.in b/docs/integration/conf.py.in deleted file mode 100644 index d759cb84e..000000000 --- a/docs/integration/conf.py.in +++ /dev/null @@ -1,171 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -import sys -import os -import shlex - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -needs_sphinx = '1.4' - -# If true, figures, tables and code-blocks are automatically numbered -# if they has caption. For now, it works only with the HTML builder. -# Default is False. -numfig = True - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [] - -locale_dirs = ['@SPHINX_DOCS_DIR@/locales/'] - -gettext_additional_targets = ['image'] -gettext_location = False -gettext_compact = True - -# Add any paths that contain templates here, relative to this directory. -#templates_path = ['@SPHINX_DOCS_DIR@/_templates'] - -# The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: -# source_suffix = ['.rst', '.md'] -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = 'AusweisApp2 Integration' -copyright = '2019-2023, Governikus GmbH & Co. KG' -author = 'Governikus GmbH & Co. KG' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = '@PROJECT_VERSION@' -# The full version, including alpha/beta/rc tags. -release = '@VERSION_DVCS@' - -today = ' ' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# -# This is also used if you do content translation via gettext catalogs. -# Usually you set "language" from the command line for these cases. -language = '@SPHINX_LANG@' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -#exclude_patterns = [''] - - - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -html_favicon = '@SPHINX_DOCS_DIR@/../../resources/images/desktop/npa.ico' - -#html_theme_path = ['@SPHINX_DOCS_DIR@/_themes'] - -#html_theme = 'appcast' -html_theme = 'sphinx_rtd_theme' - -# If false, no module index is generated. -html_domain_indices = True - -# If false, no index is generated. -html_use_index = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -html_show_sphinx = False - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -html_show_copyright = True - -html_scaled_image_link = False - -# Output file base name for HTML help builder. -htmlhelp_basename = 'AusweisApp2Integration' - -html_context = { - 'display_github': False, - 'display_bitbucket': False, - 'show_source': False, - 'html_show_sourcelink': False, -} - -html_permalinks = True - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -'papersize': 'a4paper', - -# The font size ('10pt', '11pt' or '12pt'). -'pointsize': '11pt', - -# Additional stuff for the LaTeX preamble. -'preamble': ''' -\\usepackage{lscape} -\\hypersetup{pdfauthor={Governikus GmbH \& Co. KG}, - pdftitle={AusweisApp2}, - pdfsubject={Integration}, - pdfkeywords={Integration}, - pdfproducer={LaTeX}, - pdfcreator={Sphinx} -} -''', - -# Override tableofcontents -'tableofcontents': ''' -\\tableofcontents -\\newpage -\\pagestyle{plain} -\\pagenumbering{arabic} -''', - -# Latex figure (float) alignment -'figure_align': 'H', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - (master_doc, 'AusweisApp2-@VERSION_DVCS@-Integration.tex', 'AusweisApp2 Integration', - 'Governikus GmbH \& Co. KG', 'howto'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -latex_logo = '@SPHINX_DOCS_DIR@/../../resources/images/npa.png' - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# If true, show page references after internal links. -latex_show_pagerefs = True - -# If true, show URL addresses after external links. -latex_show_urls = 'footnote' - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_domain_indices = True diff --git a/docs/integration/index.rst b/docs/integration/index.rst deleted file mode 100644 index 5688de075..000000000 --- a/docs/integration/index.rst +++ /dev/null @@ -1,13 +0,0 @@ -Table of contents ------------------ - -.. raw:: latex - - \clearpage - -.. toctree:: - :maxdepth: 3 - :caption: Integration - - README.de - README.en diff --git a/docs/releasenotes/2.0.0.rst b/docs/releasenotes/2.0.0.rst new file mode 100644 index 000000000..5769215c2 --- /dev/null +++ b/docs/releasenotes/2.0.0.rst @@ -0,0 +1,36 @@ +AusweisApp 2.0.0 +^^^^^^^^^^^^^^^^ + +**Releasedatum:** 6. November 2023 + + +Anwender +"""""""" +- Umbenennung der AusweisApp2 zu AusweisApp. + +- Überarbeitung der grafischen Oberfläche. + +- Unterstützung des Dark-Modes. + +- Das Querformat wird nun automatisch unterstützt. + +- Berücksichtigung der Systemschriftgröße und Systemschriftart. + +- Optimierung der Bedienbarkeit der Titelleiste. + +- Online-Hilfe, Anbieterliste und Verlauf entfernt. + +- PDF-Export-Funktion der Selbstauskunft entfernt. + +- macOS Catalina 10.15 wird nicht mehr unterstützt. + +- Android 7 wird nicht mehr unterstützt. + +- iOS 13 wird nicht mehr unterstützt. + + +Entwickler +"""""""""" +- Aktualisierung von Qt auf die Version 6.5.3. + +- Aktualisierung von OpenSSL auf die Version 3.1.4. diff --git a/docs/releasenotes/_themes/appcast/layout.html b/docs/releasenotes/_themes/appcast/layout.html index d5ca21079..e53b7a3e6 100644 --- a/docs/releasenotes/_themes/appcast/layout.html +++ b/docs/releasenotes/_themes/appcast/layout.html @@ -2,7 +2,7 @@ - AusweisApp2 Release Notes + AusweisApp Release Notes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +AusweisApp + + + + + + + + + + + + + + + + + + + + + + + + + + +Anwendung eID-Client/App des Bundes + +AusweisApp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +AusweisApp + + + + + + + + + + + + + + + + + + + + + + + + + + +AusweisApp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +AusweisApp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +des Bundes + +Anwendung eID-Client + + + + + + + + + + + + + + + + + + + + + + + + + + +AusweisApp + +App des Bundes + +AusweisApp + +Anwendung eID-Client + +Anwendung eID-Client + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Ausweis + + + + + + +eID-Client + +CMYK + diff --git a/docs/sdk/Logo_AusweisApp2.png b/docs/sdk/Logo_AusweisApp2.png deleted file mode 100644 index 57a0e8086..000000000 Binary files a/docs/sdk/Logo_AusweisApp2.png and /dev/null differ diff --git a/docs/sdk/android.rst b/docs/sdk/android.rst index a47827177..4877f5ce6 100644 --- a/docs/sdk/android.rst +++ b/docs/sdk/android.rst @@ -1,15 +1,15 @@ Android ======= -This chapter deals with the Android specific properties of the AusweisApp2 SDK. -The AusweisApp2 core is encapsulated into an **Android service** which is +This chapter deals with the Android specific properties of the |AppName| SDK. +The |AppName| core is encapsulated into an **Android service** which is running in the background without a user interface. This service is interfaced via an Android specific interprocess communication (IPC) mechanism. The basics of this mechanism - the **Android Interface Definition Language** (AIDL) - are introduced in the following section. Subsequent sections deal with the SDK interface itself and explain which steps are necessary in order to -communicate with the AusweisApp2 SDK. +communicate with the |AppName| SDK. -The AusweisApp2 is available as an AAR package that can automatically +The |AppName| is available as an AAR package that can automatically be fetched by Android's default build system **gradle**. .. important:: @@ -22,14 +22,14 @@ be fetched by Android's default build system **gradle**. This can be checked via the Android API methods **getMaxTransceiveLength()** and **isExtendedLengthApduSupported()**. - https://developer.android.com/reference/android/nfc/tech/NfcA - https://developer.android.com/reference/android/nfc/tech/IsoDep + | https://developer.android.com/reference/android/nfc/tech/NfcA + | https://developer.android.com/reference/android/nfc/tech/IsoDep SDK --- -The AusweisApp2 SDK is distributed as an AAR package that contains +The |AppName| SDK is distributed as an AAR package that contains native **arm64-v8a** libraries only. The AAR package is available in the default repository of Android. The following listing shows the required **mavenCentral** in **build.gradle**. @@ -43,9 +43,9 @@ The following listing shows the required **mavenCentral** in **build.gradle**. } -The AusweisApp2 SDK will be fetched automatically as a dependency by +The |AppName| SDK will be fetched automatically as a dependency by your **app/build.gradle** file. -It is recommended to always use the latest version (|version|) of AusweisApp2. +It is recommended to always use the latest version (|version|) of |AppName|. .. code-block:: groovy @@ -71,7 +71,7 @@ It is recommended to always use the latest version (|version|) of AusweisApp2. App Bundle ^^^^^^^^^^ -The AusweisApp2 SDK uses native libraries which need to be extracted when +The |AppName| SDK uses native libraries which need to be extracted when used in an App Bundle, otherwise the SDK will not work correctly. Add the following statement to your app's build.gradle file: @@ -84,7 +84,7 @@ Add the following statement to your app's build.gradle file: Logging ^^^^^^^ -The AusweisApp2 SDK uses default logging of Android and has its own log file. +The |AppName| SDK uses default logging of Android and has its own log file. It is **recommended** to collect that log file if an error occurs in your application to receive better support. @@ -92,22 +92,22 @@ The log file is in your application path: .. code-block:: text - /data/data/your.application.name/files/AusweisApp2.XXXXXX.log + /data/data/your.application.name/files/AusweisApp.XXXXXX.log The *XXXXXX* characters will be replaced by an automatically generated portion of the filename to avoid conflicts with previous instances. -A new log file will be created for each new instance of the AusweisApp2 and +A new log file will be created for each new instance of the |AppName| and will be deleted after a correct shutdown. In case of old or multiple log files, it is highly probable that the previous instance crashed. -The AusweisApp2 deletes any log files that are older than 14 days. +The |AppName| deletes any log files that are older than 14 days. Initialization of the Android Application ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The AusweisApp2 SDK creates a fork of the Android "main" Application if started. +The |AppName| SDK creates a fork of the Android "main" Application if started. Due to this, the Application is instantiated a second time. Thus, it must ensure that any initialization (e.g. Firebase connections) is only carried out once. To do so the following snippet may prove useful: @@ -162,7 +162,7 @@ The Android SDK generates the necessary interface implementations from supplied AIDL files in order to perform IPC, as if this function had been called directly in the current process. -In order to interact with the AusweisApp2 SDK there are two AIDL interfaces. +In order to interact with the |AppName| SDK there are two AIDL interfaces. The first one is given to the client application by the SDK and allows the client to establish a session with the SDK, to send JSON commands to the SDK and to pass discovered NFC tags to the SDK. @@ -216,14 +216,14 @@ Callback Background service ------------------ -The AusweisApp2 SDK is an embedded background service in your own application. +The |AppName| SDK is an embedded background service in your own application. .. _android_binding_service: Binding to the service ^^^^^^^^^^^^^^^^^^^^^^ -In order to start the AusweisApp2 SDK it is necessary to bind to the +In order to start the |AppName| SDK it is necessary to bind to the Android service supplied by the SDK. This binding fulfils two purposes: @@ -280,13 +280,13 @@ methods are invoked by Android on service connection and disconnection. Bind service to raw connection """""""""""""""""""""""""""""" In order to perform the actual binding a directed Intent, which identifies -the AusweisApp2 SDK, is created. +the |AppName| SDK, is created. This Intent is sent to the Android API along with the ServiceConnection created above. This API call either starts up the SDK if it is the first client, or connects to the running SDK instance if there is already another client bound. -You need to pass your own package name as the AusweisApp2 SDK is a background +You need to pass your own package name as the |AppName| SDK is a background service of your application. @@ -315,7 +315,7 @@ service of your application. Initializing the AIDL connection """""""""""""""""""""""""""""""" -Once the Android service of the AusweisApp2 SDK is successfully started +Once the Android service of the |AppName| SDK is successfully started and bound to by the client, the Android system calls the onServiceConnected method of the ServiceConnection created and supplied above. @@ -369,9 +369,9 @@ The example below stores this instance in the member variable mSdk. .. _android_create_session: -Create session to AusweisApp2 -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Once your client is bound to the AusweisApp2 SDK service and you have initialized +Create session to |AppName| +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Once your client is bound to the |AppName| SDK service and you have initialized the AIDL IPC mechanism, you are ready to use the actual SDK API. Since the Android system does not allow to limit the number of clients which @@ -460,7 +460,7 @@ and establishing a session. Send command """""""""""" -In order to send a JSON command to the AusweisApp2 SDK, you need to invoke +In order to send a JSON command to the |AppName| SDK, you need to invoke the **send** function of your instance of **IAusweisApp2Sdk**. For this command to be processed by the SDK you need to supply the session ID which you have previously received. The listing below shows an example. @@ -487,7 +487,7 @@ previously received. The listing below shows an example. Receive message """"""""""""""" -Messages from the AusweisApp2 SDK are passed to you via the same instance of +Messages from the |AppName| SDK are passed to you via the same instance of **IAusweisApp2SdkCallback** in which you have received the session ID. The **receive** method is called each time the SDK sends a message. @@ -500,7 +500,7 @@ The **receive** method is called each time the SDK sends a message. Disconnect from SDK ^^^^^^^^^^^^^^^^^^^ -In order to disconnect from the AusweisApp2 SDK you need to invalidate your +In order to disconnect from the |AppName| SDK you need to invalidate your instance of **IBinder**. There are two possibilities to do this. The first one is to unbind from the SDK Android service to undo your binding, like shown in the code listing below. The second one is to return false in the @@ -583,7 +583,7 @@ As it is common on the Android platform, information is sent to applications encapsulated in instances of the **Intent** class. In order to process newly discovered NFC tags, Intents which are given to the application need to be checked for the parcelable NFC extra as shown in the code listing below. -Subsequently the client is required to send them to the AusweisApp2 SDK by +Subsequently the client is required to send them to the |AppName| SDK by calling the **updateNfcTag** method of the previously acquired **IAusweisApp2Sdk** instance. The listing below shows an example for the described process. @@ -625,7 +625,7 @@ for discovered NFC tags by Android if multiple applications which are able to dispatch NFC tags are installed. An application can suppress this App Chooser if it registers itself for **foreground dispatching** at runtime. This way NFC tags are handled directly by the application without a chooser being displayed. -Subsequently the client is required to send them to the AusweisApp2 SDK by +Subsequently the client is required to send them to the |AppName| SDK by calling the **updateNfcTag** method of the previously acquired **IAusweisApp2Sdk** instance. The required steps to handle NFC tags directly are shown in the code listing below diff --git a/docs/sdk/commands.rst b/docs/sdk/commands.rst index 8a7eda3b7..ef37759fa 100644 --- a/docs/sdk/commands.rst +++ b/docs/sdk/commands.rst @@ -1,7 +1,7 @@ Commands -------- Your application (client) can send some commands (**cmd**) to -control the AusweisApp2. The AusweisApp2 (server) will send +control the |AppName|. The |AppName| (server) will send some proper :doc:`messages` during the whole workflow or as an answer to your command. @@ -12,9 +12,9 @@ answer to your command. GET_INFO ^^^^^^^^ -Returns information about the current installation of AusweisApp2. +Returns information about the current installation of |AppName|. -The AusweisApp2 will send an :ref:`info` message as an answer. +The |AppName| will send an :ref:`info` message as an answer. .. code-block:: json @@ -28,9 +28,9 @@ The AusweisApp2 will send an :ref:`info` message as an answer. GET_STATUS ^^^^^^^^^^ -Returns information about the current workflow and state of AusweisApp2. +Returns information about the current workflow and state of |AppName|. -The AusweisApp2 will send a :ref:`status` message as an answer. +The |AppName| will send a :ref:`status` message as an answer. .. versionadded:: 1.24.0 Support of GET_STATUS command in :ref:`api_level` **2**. @@ -49,7 +49,7 @@ GET_API_LEVEL ^^^^^^^^^^^^^ Returns information about the available and current API level. -The AusweisApp2 will send an :ref:`api_level` message as an answer. +The |AppName| will send an :ref:`api_level` message as an answer. .. code-block:: json @@ -66,12 +66,12 @@ SET_API_LEVEL Set supported API level of your application. If you initially develop your application against the -AusweisApp2 SDK you should check with :ref:`get_api_level` +|AppName| SDK you should check with :ref:`get_api_level` the highest supported level and set this value with this command if you connect to the SDK. This will set the SDK to act with the defined level even if a newer level is available. -The AusweisApp2 will send an :ref:`api_level` message as an answer. +The |AppName| will send an :ref:`api_level` message as an answer. - **level**: @@ -96,7 +96,7 @@ Returns information about the requested reader. If you explicitly want to ask for information of a known reader name you can request it with this command. -The AusweisApp2 will send a :ref:`reader` message as an answer. +The |AppName| will send a :ref:`reader` message as an answer. - **name**: @@ -121,7 +121,7 @@ Returns information about all connected readers. If you explicitly want to ask for information of all connected readers you can request it with this command. -The AusweisApp2 will send a :ref:`reader_list` message as an answer. +The |AppName| will send a :ref:`reader_list` message as an answer. .. code-block:: json @@ -137,7 +137,7 @@ RUN_AUTH ^^^^^^^^ Starts an authentication. -The AusweisApp2 will send an :ref:`auth` message when the authentication is started. +The |AppName| will send an :ref:`auth` message when the authentication is started. The system dialog on iOS can be customized by **messages**. This dialog won't be stopped by default after an :ref:`enter_pin`, :ref:`enter_can` @@ -204,7 +204,7 @@ Command :ref:`interrupt` allows to stop the dialog manually, if needed. } .. note:: - This command is allowed only if the AusweisApp2 has no running + This command is allowed only if the |AppName| has no running authentication or other workflow. Otherwise you will get a :ref:`bad_state` message as an answer. @@ -217,7 +217,7 @@ RUN_CHANGE_PIN ^^^^^^^^^^^^^^ Starts a change PIN workflow. -The AusweisApp2 will send a :ref:`change_pin` message when the workflow is started. +The |AppName| will send a :ref:`change_pin` message when the workflow is started. The system dialog on iOS can be customized by **messages**. This dialog won't be stopped by default after an :ref:`enter_pin`, :ref:`enter_can`, @@ -275,7 +275,7 @@ Command :ref:`interrupt` allows to stop the dialog manually, if needed. } .. note:: - This command is allowed only if the AusweisApp2 has no running + This command is allowed only if the |AppName| has no running authentication or other workflow. Otherwise you will get a :ref:`bad_state` message as an answer. @@ -288,7 +288,7 @@ GET_ACCESS_RIGHTS ^^^^^^^^^^^^^^^^^ Returns information about the requested access rights. -The AusweisApp2 will send an :ref:`access_rights` message as an answer. +The |AppName| will send an :ref:`access_rights` message as an answer. .. code-block:: json @@ -296,7 +296,7 @@ The AusweisApp2 will send an :ref:`access_rights` message as an answer. {"cmd": "GET_ACCESS_RIGHTS"} .. note:: - This command is allowed only if the AusweisApp2 sends an initial + This command is allowed only if the |AppName| sends an initial :ref:`access_rights` message. Otherwise you will get a :ref:`bad_state` message as an answer. @@ -313,7 +313,7 @@ By default the **effective** access rights are **optional** + **required**. If you want to enable or disable some **optional** access rights you can send this command to modify the **effective** access rights. -The AusweisApp2 will send an :ref:`access_rights` message as an answer. +The |AppName| will send an :ref:`access_rights` message as an answer. - **chat**: @@ -335,7 +335,7 @@ The AusweisApp2 will send an :ref:`access_rights` message as an answer. } .. note:: - This command is allowed only if the AusweisApp2 sends an initial + This command is allowed only if the |AppName| sends an initial :ref:`access_rights` message. Otherwise you will get a :ref:`bad_state` message as an answer. @@ -384,7 +384,7 @@ in a :ref:`reader` message. } .. note:: - This command is allowed only if the AusweisApp2 sends an initial + This command is allowed only if the |AppName| sends an initial :ref:`insert_card` message. Otherwise you will get a :ref:`bad_state` message as an answer. @@ -397,7 +397,7 @@ GET_CERTIFICATE ^^^^^^^^^^^^^^^ Returns the certificate of current authentication. -The AusweisApp2 will send a :ref:`certificate` message as an answer. +The |AppName| will send a :ref:`certificate` message as an answer. .. code-block:: json @@ -405,7 +405,7 @@ The AusweisApp2 will send a :ref:`certificate` message as an answer. {"cmd": "GET_CERTIFICATE"} .. note:: - This command is allowed only if the AusweisApp2 sends an initial + This command is allowed only if the |AppName| sends an initial :ref:`access_rights` message. Otherwise you will get a :ref:`bad_state` message as an answer. @@ -418,7 +418,7 @@ CANCEL ^^^^^^ Cancel the whole workflow. -If your application sends this command the AusweisApp2 will cancel the +If your application sends this command the |AppName| will cancel the workflow. You can send this command in any state of a running workflow to abort it. @@ -428,7 +428,7 @@ to abort it. {"cmd": "CANCEL"} .. note:: - This command is allowed only if the AusweisApp2 started an authentication or + This command is allowed only if the |AppName| started an authentication or the :ref:`change_pin` workflow. Otherwise you will get a :ref:`bad_state` message as an answer. @@ -441,7 +441,7 @@ ACCEPT ^^^^^^ Accept the current state. -If the AusweisApp2 will send the message :ref:`access_rights` the user +If the |AppName| will send the message :ref:`access_rights` the user needs to **accept** or **cancel**. So the workflow is paused until your application sends this command to accept the requested information. @@ -449,7 +449,7 @@ If the user does not accept the requested information your application needs to send the command :ref:`cancel` to abort the whole workflow. This command will be used later for additional requested information -if the AusweisApp2 needs to pause the workflow. In :ref:`api_level` v1 +if the |AppName| needs to pause the workflow. In :ref:`api_level` v1 only :ref:`access_rights` needs to be accepted. @@ -458,7 +458,7 @@ only :ref:`access_rights` needs to be accepted. {"cmd": "ACCEPT"} .. note:: - This command is allowed only if the AusweisApp2 sends an initial + This command is allowed only if the |AppName| sends an initial :ref:`access_rights` message. Otherwise you will get a :ref:`bad_state` message as an answer. @@ -488,7 +488,7 @@ the iOS system dialog can be interrupted. {"cmd": "INTERRUPT"} .. note:: - This command is allowed only if the AusweisApp2 sends a :ref:`enter_pin`, + This command is allowed only if the |AppName| sends a :ref:`enter_pin`, :ref:`enter_can`, :ref:`enter_new_pin` or :ref:`enter_puk` message. Otherwise you will get a :ref:`bad_state` message as an answer. @@ -501,17 +501,17 @@ SET_PIN ^^^^^^^ Set PIN of inserted card. -If the AusweisApp2 sends message :ref:`enter_pin` you need +If the |AppName| sends message :ref:`enter_pin` you need to send this command to unblock the card with the PIN. -The AusweisApp2 will send an :ref:`enter_pin` message on error +The |AppName| will send an :ref:`enter_pin` message on error or message :ref:`enter_can` if the retryCounter of the card is decreased to **1**. For detailed information see message :ref:`enter_pin`. If the PIN was correct, the workflow will continue. -If the last attempt to enter the PIN failed, AusweisApp2 +If the last attempt to enter the PIN failed, |AppName| will send the message :ref:`enter_puk` as the retryCounter is decreased to **0**. @@ -534,7 +534,7 @@ is decreased to **0**. } .. note:: - This command is allowed only if the AusweisApp2 sends an initial + This command is allowed only if the |AppName| sends an initial :ref:`enter_pin` message. Otherwise you will get a :ref:`bad_state` message as an answer. @@ -547,7 +547,7 @@ SET_NEW_PIN ^^^^^^^^^^^ Set new PIN of inserted card. -If the AusweisApp2 sends message :ref:`enter_new_pin` you need +If the |AppName| sends message :ref:`enter_new_pin` you need to send this command to set the new PIN of the card. .. versionadded:: 1.22.0 @@ -566,7 +566,7 @@ to send this command to set the new PIN of the card. } .. note:: - This command is allowed only if the AusweisApp2 sends an initial + This command is allowed only if the |AppName| sends an initial :ref:`enter_new_pin` message. Otherwise you will get a :ref:`bad_state` message as an answer. @@ -579,10 +579,10 @@ SET_CAN ^^^^^^^ Set CAN of inserted card. -If the AusweisApp2 sends message :ref:`enter_can` you need +If the |AppName| sends message :ref:`enter_can` you need to send this command to unblock the last retry of :ref:`set_pin`. -The AusweisApp2 will send an :ref:`enter_can` message on error. +The |AppName| will send an :ref:`enter_can` message on error. Otherwise the workflow will continue with :ref:`enter_pin`. .. versionchanged:: 1.16.0 @@ -602,7 +602,7 @@ Otherwise the workflow will continue with :ref:`enter_pin`. } .. note:: - This command is allowed only if the AusweisApp2 sends an initial + This command is allowed only if the |AppName| sends an initial :ref:`enter_can` message. Otherwise you will get a :ref:`bad_state` message as an answer. @@ -615,10 +615,10 @@ SET_PUK ^^^^^^^ Set PUK of inserted card. -If the AusweisApp2 sends message :ref:`enter_puk` you need +If the |AppName| sends message :ref:`enter_puk` you need to send this command to unblock :ref:`set_pin`. -The AusweisApp2 will send an :ref:`enter_puk` message on error +The |AppName| will send an :ref:`enter_puk` message on error or if the PUK is operative. Otherwise the workflow will continue with :ref:`enter_pin`. For detailed information see message :ref:`enter_puk`. @@ -640,6 +640,6 @@ For detailed information see message :ref:`enter_puk`. } .. note:: - This command is allowed only if the AusweisApp2 sends an initial + This command is allowed only if the |AppName| sends an initial :ref:`enter_puk` message. Otherwise you will get a :ref:`bad_state` message as an answer. diff --git a/docs/sdk/conf.py.in b/docs/sdk/conf.py.in index a3d1a21a6..4b1b1661a 100644 --- a/docs/sdk/conf.py.in +++ b/docs/sdk/conf.py.in @@ -41,7 +41,7 @@ source_suffix = '.rst' master_doc = 'index' # General information about the project. -project = 'AusweisApp2 SDK' +project = '@PROJECT_NAME@ SDK' copyright = '2016-2023, Governikus GmbH & Co. KG' author = 'Governikus GmbH & Co. KG' @@ -96,7 +96,7 @@ html_show_copyright = True html_scaled_image_link = False # Output file base name for HTML help builder. -htmlhelp_basename = 'AusweisApp2ReleaseNotes' +htmlhelp_basename = '@PROJECT_NAME@ReleaseNotes' html_context = { 'display_github': False, @@ -119,7 +119,7 @@ latex_elements = { # Additional stuff for the LaTeX preamble. 'preamble': ''' \hypersetup{pdfauthor={Governikus GmbH \& Co. KG}, - pdftitle={AusweisApp2}, + pdftitle={@PROJECT_NAME@}, pdfsubject={SDK}, pdfkeywords={sdk, api}, pdfproducer={LaTeX}, @@ -143,7 +143,7 @@ latex_elements = { # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'AusweisApp2-@VERSION_DVCS@-SDK.tex', 'AusweisApp2 SDK', + (master_doc, '@PROJECT_NAME@-@VERSION_DVCS@-SDK.tex', '@PROJECT_NAME@ SDK', 'Governikus GmbH \& Co. KG', 'howto'), ] @@ -166,3 +166,7 @@ latex_show_urls = 'footnote' # If false, no module index is generated. #latex_domain_indices = True + +rst_epilog = """ +.. |AppName| replace:: @PROJECT_NAME@ +""" \ No newline at end of file diff --git a/docs/sdk/container.rst b/docs/sdk/container.rst index d921db7f2..e7bab0808 100644 --- a/docs/sdk/container.rst +++ b/docs/sdk/container.rst @@ -1,10 +1,10 @@ Container ========= -This chapter deals with the container specific properties of the AusweisApp2 SDK. -The AusweisApp2 core is reachable over a :ref:`websocket` like the :doc:`desktop` +This chapter deals with the container specific properties of the |AppName| SDK. +The |AppName| core is reachable over a :ref:`websocket` like the :doc:`desktop` variant and also enables the :ref:`automatic` mode by default. Subsequent sections deal with the container itself and explain which steps are -necessary in order to communicate with the AusweisApp2 SDK in the container. +necessary in order to communicate with the |AppName| SDK in the container. .. note:: @@ -22,7 +22,7 @@ If you need to restore the configuration you can add a .. code-block:: sh - docker run --rm -p 127.0.0.1:24727:24727 governikus/ausweisapp2 + docker run --rm -p 127.0.0.1:24727:24727 governikus/ausweisapp @@ -36,7 +36,7 @@ by ``docker run -e https_proxy=IP:PORT -e http_proxy=IP:PORT``. Behaviour --------- -The AusweisApp2 uses the :ref:`automatic` mode with the default :doc:`simulator` +The |AppName| uses the :ref:`automatic` mode with the default :doc:`simulator` if there is no connected :ref:`websocket` client. That mode will be disabled if a client is connected and enabled again after disconnection. If the client disconnects during an active workflow the workflow will be canceled. diff --git a/docs/sdk/desktop.rst b/docs/sdk/desktop.rst index f61d8ab19..cd07d4bc6 100644 --- a/docs/sdk/desktop.rst +++ b/docs/sdk/desktop.rst @@ -1,10 +1,10 @@ Desktop ======= -This chapter deals with the desktop specific properties of the AusweisApp2 SDK. -The AusweisApp2 core is reachable over a **WebSocket** which is running by -default since AusweisApp2 1.16.0. Subsequent sections deal with the SDK +This chapter deals with the desktop specific properties of the |AppName| SDK. +The |AppName| core is reachable over a **WebSocket** which is running by +default since |AppName| 1.16.0. Subsequent sections deal with the SDK interface itself and explain which steps are necessary in order to communicate -with the AusweisApp2 SDK. +with the |AppName| SDK. @@ -12,16 +12,16 @@ with the AusweisApp2 SDK. WebSocket --------- -The AusweisApp2 uses the same default port as defined in TR-03124-1. +The |AppName| uses the same default port as defined in TR-03124-1. Your application can connect to ``ws://localhost:24727/eID-Kernel`` to establish a bidirectional connection. -You can check the version of AusweisApp2 by the ``Server`` header of the HTTP +You can check the version of |AppName| by the ``Server`` header of the HTTP response or by an additional query to get the :ref:`client_status`. If the WebSocket handshake was successful your application can send :doc:`commands` and receive :doc:`messages`. -The AusweisApp2 will send an HTTP error 503 "Service Unavailable" if the WebSocket +The |AppName| will send an HTTP error 503 "Service Unavailable" if the WebSocket is disabled. .. seealso:: @@ -32,37 +32,37 @@ is disabled. User installed ^^^^^^^^^^^^^^ -Your application can connect to a user installed AusweisApp2. If the +Your application can connect to a user installed |AppName|. If the user already has an active workflow your request will be refused by an HTTP error ``409 Conflict``. Also it is not possible to connect multiple times to the WebSocket as only one connection is allowed and will be refused by an HTTP error ``429 Too Many Requests``. Once an application is connected to the WebSocket the graphical user interface -of the AusweisApp2 will be blocked and shows a hint that another -application uses the AusweisApp2. +of the |AppName| will be blocked and shows a hint that another +application uses the |AppName|. .. important:: - Please provide a ``User-Agent`` in your HTTP upgrade request! The AusweisApp2 - will show the content to the user as a hint which application uses the AusweisApp2. + Please provide a ``User-Agent`` in your HTTP upgrade request! The |AppName| + will show the content to the user as a hint which application uses the |AppName|. Integrated ^^^^^^^^^^ -You can deliver separate AusweisApp2 binaries inside your own application or -start an already installed AusweisApp2. +You can deliver separate |AppName| binaries inside your own application or +start an already installed |AppName|. If your application spawns a separate process you should provide the commandline -parameter ``--port 0`` to avoid conflicts with a user started AusweisApp2 and +parameter ``--port 0`` to avoid conflicts with a user started |AppName| and other processes that uses a specified port. -The AusweisApp2 will create a text file in the system temporary directory to provide +The |AppName| will create a text file in the system temporary directory to provide the selected port. The port filename contains the PID of the running process to allow multiple instances at the same time. -Example: **$TMPDIR/AusweisApp2.12345.port** +Example: **$TMPDIR/AusweisApp.12345.port** -Your application can avoid the graphical interface of AusweisApp2 by providing the +Your application can avoid the graphical interface of |AppName| by providing the commandline parameter ``--ui websocket``. @@ -90,7 +90,7 @@ on start up. * ``AUSWEISAPP2_AUTOMATIC_PUK`` The default value for the PIN is **123456**. If a value is not defined or the card -refuses a PIN, CAN or PUK the AusweisApp2 will cancel the whole workflow. +refuses a PIN, CAN or PUK the |AppName| will cancel the whole workflow. Also the workflow will be canceled if the card reader is not a basic reader as it is not possible to automatically enter the values. @@ -100,7 +100,7 @@ This will be evaluated if the automatic plugin takes control over the workflow. .. note:: - It is possible to pass multiple plugins to the AusweisApp2, e.g.: ``--ui websocket --ui automatic``. + It is possible to pass multiple plugins to the |AppName|, e.g.: ``--ui websocket --ui automatic``. .. seealso:: The :doc:`container` SDK is designed for scripted and automatic workflows and enables @@ -113,7 +113,7 @@ This will be evaluated if the automatic plugin takes control over the workflow. Status ------ TR-03124-1 defined a query for status information. This is useful to fetch current -version of installed AusweisApp2 to check if the version supports the WebSocket-API. +version of installed |AppName| to check if the version supports the WebSocket-API. You can get this by a HTTP GET query to ``http://localhost:24727/eID-Client?Status``. If you prefer the JSON syntax you can add it to the parameter ``?Status=json`` to get @@ -122,10 +122,10 @@ the following information. .. code-block:: json { - "Implementation-Title": "AusweisApp2", + "Implementation-Title": "AusweisApp", "Implementation-Vendor": "Governikus GmbH & Co. KG", "Implementation-Version": "1.16.0", - "Name": "AusweisApp2", + "Name": "AusweisApp", "Specification-Title": "TR-03124", "Specification-Vendor": "Federal Office for Information Security", "Specification-Version": "1.3" @@ -134,14 +134,14 @@ the following information. .. seealso:: - The AusweisApp2 SDK provides a :ref:`get_info` command and an :ref:`info` message - to fetch the same information to check the compatibility of used AusweisApp2. + The |AppName| SDK provides a :ref:`get_info` command and an :ref:`info` message + to fetch the same information to check the compatibility of used |AppName|. Reader ------ -The AusweisApp2 SDK uses PC/SC and paired Smartphones as card reader. If the +The |AppName| SDK uses PC/SC and paired Smartphones as card reader. If the user wants to use the "smartphone as card reader" feature it is necessary -to pair the devices by the graphical interface of AusweisApp2. The AusweisApp2 SDK +to pair the devices by the graphical interface of |AppName|. The |AppName| SDK provides no API to pair those devices. diff --git a/docs/sdk/index.rst b/docs/sdk/index.rst index 5da2c441f..9122767af 100644 --- a/docs/sdk/index.rst +++ b/docs/sdk/index.rst @@ -1,7 +1,7 @@ .. only:: html - .. image:: Logo_AusweisApp2.png - :alt: AusweisApp2 + .. image:: AusweisApp_Logo.svg + :alt: AusweisApp :align: center :width: 200pt diff --git a/docs/sdk/intro.rst b/docs/sdk/intro.rst index 2001a1b21..b198608d7 100644 --- a/docs/sdk/intro.rst +++ b/docs/sdk/intro.rst @@ -1,18 +1,18 @@ Introduction ============ This documentation will explain how to initialize and start up -the AusweisApp2 as an additional service. It distinguishes between +the |AppName| as an additional service. It distinguishes between a connection to the application and the communication between your -application and AusweisApp2. +application and |AppName|. The section :ref:`connection` will show you what you need to do to -set up a connection to AusweisApp2. Once you have established +set up a connection to |AppName|. Once you have established a connection you can send and receive JSON documents in a bi-directional manner. There are different commands and messages. These are listed and described in the section :ref:`protocol`. The protocol is split up in :doc:`commands` and :doc:`messages`. Commands -will be sent by your application to control AusweisApp2. +will be sent by your application to control |AppName|. Messages contain additional information to your command or will be sent as an event. @@ -21,10 +21,10 @@ show a possible communication. .. important:: - The AusweisApp2 does **not** provide any personal data to - your client application directly as AusweisApp2 does not + The |AppName| does **not** provide any personal data to + your client application directly as |AppName| does not have access to this data for security reasons. - AusweisApp2 facilitates a secure connection between the + |AppName| facilitates a secure connection between the eID server and the ID card, enabling the eID server to get those data from the card. @@ -32,7 +32,7 @@ show a possible communication. Since your client application runs in a user's environment, you could not be sure about the integrity of the data if your client application were to receive high sensitive - data from the AusweisApp2 directly as your backend does + data from the |AppName| directly as your backend does not have any possibility to verify the source of the data. Also this approach, recommended for compliance reasons by the diff --git a/docs/sdk/ios.rst b/docs/sdk/ios.rst index 5685448ba..bf1e49d34 100644 --- a/docs/sdk/ios.rst +++ b/docs/sdk/ios.rst @@ -1,11 +1,11 @@ iOS === -This chapter deals with the iOS specific properties of the AusweisApp2 SDK. -The AusweisApp2 core is encapsulated into an **XCFramework** which needs to +This chapter deals with the iOS specific properties of the |AppName| SDK. +The |AppName| core is encapsulated into an **XCFramework** which needs to be linked into your application. Subsequent sections deal with the SDK interface itself and explain which -steps are necessary in order to communicate with the AusweisApp2 SDK. +steps are necessary in order to communicate with the |AppName| SDK. .. important:: Apple released the necessary NFC API with iOS 13.0! @@ -18,9 +18,9 @@ Use XCFramework The interface ``AusweisApp2.h`` of the SDK for iOS is provided as **C-Header** that you need to import/include into your application. It grants access to start and shutdown a separate background thread with the integrated -AusweisApp2 core. +|AppName| core. -After you established a connection to the AusweisApp2 SDK your application +After you established a connection to the |AppName| SDK your application can send :doc:`commands` and receive :doc:`messages`. @@ -56,14 +56,14 @@ in Objective-C classes and call the functions of the ``AusweisApp2.h`` header. Added optional parameter ``pCmdline`` to function ``ausweisapp2_init``. -First, you need to define a callback function that will be called by the AusweisApp2 +First, you need to define a callback function that will be called by the |AppName| to request or provide additional information. If your application initializes the SDK you must pass that callback to ``ausweisapp2_init``. That function will return ``false`` if the callback is ``NULL`` or the SDK is already running. The Parameter ``pCmdline`` is optional and can be ``NULL``. This allows your application to provide additional commandline arguments like ``--no-loghandler``. -After you called that function the AusweisApp2 SDK will start up. If the +After you called that function the |AppName| SDK will start up. If the initialization is finished the SDK calls your callback function once with ``NULL`` as parameter to indicate that it is ready to accept :doc:`commands`. Do not call ``ausweisapp2_send`` until your callback received that message, otherwise @@ -72,17 +72,17 @@ that command will be ignored. Once the SDK is ready to go you can send :doc:`commands` by ``ausweisapp2_send``. Your callback will receive the :doc:`messages`. -If you call ``ausweisapp2_shutdown`` the AusweisApp2 SDK will be terminated. This -function joins the thread of the AusweisApp2 and blocks until the AusweisApp2 is +If you call ``ausweisapp2_shutdown`` the |AppName| SDK will be terminated. This +function joins the thread of the |AppName| and blocks until the |AppName| is finished. You should not call this function in your callback as it is called -by the AusweisApp2 thread. In that case ``ausweisapp2_shutdown`` cannot be a +by the |AppName| thread. In that case ``ausweisapp2_shutdown`` cannot be a blocking call to avoid a deadlock. If you call this function while a workflow is running the workflow will be canceled automatically before the shutdown. .. important:: - Your callback will be called by the separate AusweisApp2 thread. Do **not** + Your callback will be called by the separate |AppName| thread. Do **not** make long running or blocking calls! It is recommended to use an async dispatcher. Also, you should not call ``ausweisapp2_send`` or ``ausweisapp2_shutdown`` within @@ -104,7 +104,7 @@ a message why your application needs access to the NFC hardware. NFCReaderUsageDescription - AusweisApp2 needs NFC to access the ID card. + AusweisApp needs NFC to access the ID card. .. seealso:: @@ -141,7 +141,7 @@ of reader sessions. Logging ------- -The AusweisApp2 uses default logging of iOS and has its own log file. +The |AppName| uses default logging of iOS and has its own log file. It is **recommended** to collect that log file if an error occurs in your application to receive better support. @@ -149,14 +149,14 @@ The log file is in your application path: .. code-block:: text - NSTemporaryDirectory() + /AusweisApp2.XXXXXX.log + NSTemporaryDirectory() + /AusweisApp.XXXXXX.log The *XXXXXX* characters will be replaced by an automatically generated portion of the filename to avoid conflicts with previous instances. -A new log file will be created for each new instance of the AusweisApp2 and +A new log file will be created for each new instance of the |AppName| and will be deleted after a correct shutdown. In case of old or multiple log files, it is highly probable that the previous instance crashed. -The AusweisApp2 deletes any log files that are older than 14 days. +The |AppName| deletes any log files that are older than 14 days. diff --git a/docs/sdk/messages.rst b/docs/sdk/messages.rst index d091862e6..4c95f3bd9 100644 --- a/docs/sdk/messages.rst +++ b/docs/sdk/messages.rst @@ -1,6 +1,6 @@ Messages -------- -The AusweisApp2 (server) will send some proper +The |AppName| (server) will send some proper messages (**msg**) to your application (client) during the whole workflow or as an answer to your :doc:`commands`. @@ -12,8 +12,8 @@ your :doc:`commands`. ACCESS_RIGHTS ^^^^^^^^^^^^^ -This message will be sent by AusweisApp2 once the authentication is started -by :ref:`run_auth` and the AusweisApp2 got the certificate from the service. +This message will be sent by |AppName| once the authentication is started +by :ref:`run_auth` and the |AppName| got the certificate from the service. If your application receives this message you can call :ref:`set_access_rights` to change some optional access rights or you can call :ref:`get_access_rights` @@ -30,26 +30,27 @@ the whole workflow. - **error**: This optional parameter indicates an error of a :ref:`set_access_rights` call if the command contained invalid data. + - **chat**: Access rights of the provider. + + - **effective**: Indicates the enabled access rights of **optional** and **required**. + + - **optional**: These rights are optional and can be enabled or disabled by :ref:`set_access_rights`. + + - **required**: These rights are mandatory and cannot be disabled. + + - **transactionInfo**: Optional transaction information. + - **aux**: Optional auxiliary data of the provider. - **ageVerificationDate**: Optional required date of birth for AgeVerification as ISO 8601. - **requiredAge**: Optional required age for AgeVerification. It is calculated - by AusweisApp2 on the basis of ageVerificationDate and current date. + by |AppName| on the basis of ageVerificationDate and current date. - **validityDate**: Optional validity date as ISO 8601. - **communityId**: Optional id of community. - - **chat**: Access rights of the provider. - - - **effective**: Indicates the enabled access rights of **optional** and **required**. - - - **optional**: These rights are optional and can be enabled or disabled by :ref:`set_access_rights`. - - - **required**: These rights are mandatory and cannot be disabled. - - - **transactionInfo**: Optional transaction information. .. code-block:: json @@ -57,13 +58,6 @@ the whole workflow. { "msg": "ACCESS_RIGHTS", "error": "some optional error message", - "aux": - { - "ageVerificationDate": "1999-07-20", - "requiredAge": "18", - "validityDate": "2017-07-20", - "communityId": "02760400110000" - }, "chat": { "effective": ["Address", "FamilyName", "GivenNames", "AgeVerification", "CanAllowed"], @@ -71,6 +65,13 @@ the whole workflow. "required": ["Address", "FamilyName"] }, "transactionInfo": "this is an example", + "aux": + { + "ageVerificationDate": "1999-07-20", + "requiredAge": "18", + "validityDate": "2017-07-20", + "communityId": "02760400110000" + } } @@ -173,14 +174,14 @@ Also it indicates the **current** selected API level. "current": 4 } -Your application should always set the compatible API level. The AusweisApp2 +Your application should always set the compatible API level. The |AppName| will support multiple API levels to give you enough time to add support for the new API. Even if you added support for the new API, your application should still support the old API level in case the user updates your application but -does not update the AusweisApp2. Otherwise you need to show a message to the user -that they need to update the AusweisApp2. +does not update the |AppName|. Otherwise you need to show a message to the user +that they need to update the |AppName|. The API level will be increased for **incompatible** changes only. If we can add additional commands, messages or information without breaking the previous API @@ -202,7 +203,7 @@ This documentation will mark every API change with a flag like the following: AUTH ^^^^ -This message will be sent by AusweisApp2 if an authentication +This message will be sent by |AppName| if an authentication is initially started. The next message should be :ref:`access_rights` or :ref:`auth` again if the authentication immediately results in an error. @@ -223,7 +224,7 @@ started at all. -If the workflow is finished the AusweisApp2 will send a message with +If the workflow is finished the |AppName| will send a message with a result and an url parameter to indicate the end of an authentication. .. versionadded:: 1.26.3 @@ -358,7 +359,7 @@ Provides information about the used certificate. CHANGE_PIN ^^^^^^^^^^ -This message will be sent by AusweisApp2 if a change PIN workflow +This message will be sent by |AppName| if a change PIN workflow is initially started. If you receive a :ref:`change_pin` message with a parameter **success** @@ -405,12 +406,12 @@ ENTER_CAN ^^^^^^^^^ Indicates that a CAN is required to continue workflow. -If the AusweisApp2 sends this message, you will have to +If the |AppName| sends this message, you will have to provide the CAN of the inserted card with :ref:`set_can`. The CAN is required to enable the last attempt of PIN input if the retryCounter is **1**. The workflow continues automatically with -the correct CAN and the AusweisApp2 will send an :ref:`enter_pin` message. +the correct CAN and the |AppName| will send an :ref:`enter_pin` message. Despite the correct CAN being entered, the retryCounter remains at **1**. The CAN is also required, if the authentication terminal has an approved @@ -418,11 +419,11 @@ The CAN is also required, if the authentication terminal has an approved an additional PIN. If your application provides an invalid :ref:`set_can` command -the AusweisApp2 will send an :ref:`enter_can` message with an error +the |AppName| will send an :ref:`enter_can` message with an error parameter. If your application provides a valid :ref:`set_can` command -and the CAN was incorrect the AusweisApp2 will send :ref:`enter_can` +and the CAN was incorrect the |AppName| will send :ref:`enter_can` again but without an error parameter. .. versionadded:: 1.14.2 @@ -467,7 +468,7 @@ ENTER_PIN ^^^^^^^^^ Indicates that a PIN is required to continue the workflow. -If the AusweisApp2 sends this message, you will have to +If the |AppName| sends this message, you will have to provide the PIN of the inserted card with :ref:`set_pin`. The workflow will automatically continue if the PIN was correct. @@ -475,20 +476,20 @@ Otherwise you will receive another message :ref:`enter_pin`. If the correct PIN is entered the retryCounter will be set to **3**. If your application provides an invalid :ref:`set_pin` command -the AusweisApp2 will send an :ref:`enter_pin` message with an error +the |AppName| will send an :ref:`enter_pin` message with an error parameter and the retryCounter of the card is **not** decreased. If your application provides a valid :ref:`set_pin` command -and the PIN was incorrect the AusweisApp2 will send :ref:`enter_pin` +and the PIN was incorrect the |AppName| will send :ref:`enter_pin` again with a decreased retryCounter but without an error parameter. -If the value of retryCounter is **1** the AusweisApp2 will initially send an +If the value of retryCounter is **1** the |AppName| will initially send an :ref:`enter_can` message. Once your application provides a correct CAN the -AusweisApp2 will send an :ref:`enter_pin` again with a retryCounter of **1**. +|AppName| will send an :ref:`enter_pin` again with a retryCounter of **1**. -If the value of retryCounter is **0** the AusweisApp2 will initially send an +If the value of retryCounter is **0** the |AppName| will initially send an :ref:`enter_puk` message. Once your application provides a correct PUK the -AusweisApp2 will send an :ref:`enter_pin` again with a retryCounter of **3**. +|AppName| will send an :ref:`enter_pin` again with a retryCounter of **3**. - **error**: Optional error message if your command :ref:`set_pin` @@ -527,7 +528,7 @@ ENTER_NEW_PIN ^^^^^^^^^^^^^ Indicates that a new PIN is required to continue the workflow. -If the AusweisApp2 sends this message, you will have to +If the |AppName| sends this message, you will have to provide the new PIN of the inserted card with :ref:`set_new_pin`. @@ -571,23 +572,23 @@ ENTER_PUK ^^^^^^^^^ Indicates that a PUK is required to continue the workflow. -If the AusweisApp2 sends this message, you will have to +If the |AppName| sends this message, you will have to provide the PUK of the inserted card with :ref:`set_puk`. The workflow will automatically continue if the PUK was correct -and the AusweisApp2 will send an :ref:`enter_pin` message. +and the |AppName| will send an :ref:`enter_pin` message. Otherwise you will receive another message :ref:`enter_puk`. If the correct PUK is entered the retryCounter will be set to **3**. If your application provides an invalid :ref:`set_puk` command -the AusweisApp2 will send an :ref:`enter_puk` message with an error +the |AppName| will send an :ref:`enter_puk` message with an error parameter. If your application provides a valid :ref:`set_puk` command -and the PUK was incorrect the AusweisApp2 will send :ref:`enter_puk` +and the PUK was incorrect the |AppName| will send :ref:`enter_puk` again but without an error parameter. -If AusweisApp2 sends :ref:`enter_puk` with field "inoperative" of embedded +If |AppName| sends :ref:`enter_puk` with field "inoperative" of embedded :ref:`reader` message set true it is not possible to unblock the PIN. You will have to show a message to the user that the card is inoperative and the user should contact the authority responsible for issuing the @@ -626,7 +627,7 @@ Please see the note for more information. There is no retry limit for an incorrect PUK. But be aware that the PUK can only be used 10 times to unblock the PIN. There is no readable counter for this. - The AusweisApp2 is not able to provide any counter information + The |AppName| is not able to provide any counter information of PUK usage. If the PUK is used 10 times it is not possible to unblock the PIN anymore and the card will remain in PUK state. @@ -641,7 +642,7 @@ Please see the note for more information. INFO ^^^^ -Provides information about the AusweisApp2. +Provides information about the |AppName|. Especially if you want to get a specific **Implementation-Version** to check if the current installation supports some additional @@ -667,6 +668,20 @@ increased for **incompatible** changes. - **Specification-Version**: Version of specification. + - **AusweisApp**: Indicates the state of the connection to + the AusweisApp2 for integrated SDK (**Android only**). + The following states are possible. + + - **CONNECTED**: The SDK is connected. + + - **DISCONNECTED**: The SDK is not connected. + + - **INVALID_CERTIFICATE**: The certificate of LocalIfd is not valid. + + - **INCOMPATIBLE_VERSION**: The version of LocalIfd is not compatible. + + - **UNKNOWN**: The state could not be recognized. + .. code-block:: json { @@ -676,11 +691,12 @@ increased for **incompatible** changes. "Name": "AusweisApp2", "Implementation-Title": "AusweisApp2", "Implementation-Vendor": "Governikus GmbH & Co. KG", - "Implementation-Version": "1.10.0", - "Specification-Title": "TR-03124", + "Implementation-Version": "2.0.0", + "Specification-Title": "TR-03124-1", "Specification-Vendor": "Federal Office for Information Security", - "Specification-Version": "1.2" - } + "Specification-Version": "1.4" + }, + "AusweisApp": "CONNECTED" } @@ -690,9 +706,9 @@ increased for **incompatible** changes. INSERT_CARD ^^^^^^^^^^^ -Indicates that the AusweisApp2 requires a card to continue. +Indicates that the |AppName| requires a card to continue. -If the AusweisApp2 needs a card to continue the workflow +If the |AppName| needs a card to continue the workflow this message will be sent as a notification. If your application receives this message it should show a hint to the user. @@ -703,7 +719,7 @@ to provide a "virtual" card by calling :ref:`set_card`. After the user or your application inserted a card, the workflow will continue automatically, unless both the eID function and CAN allowed mode are disabled. -CAN allowed mode is enabled if the AusweisApp2 is used as SDK and the +CAN allowed mode is enabled if the |AppName| is used as SDK and the certificate contains the CAN allowed right. In this case, the workflow will be paused until another card is inserted. If the user already inserted a card this message will not be sent at all. @@ -752,7 +768,7 @@ INVALID Indicates a broken JSON message. If your application receives this message you -passed a broken JSON structure to the AusweisApp2. +passed a broken JSON structure to the |AppName|. Please fix your JSON document and send it again! @@ -776,7 +792,7 @@ READER ^^^^^^ Provides information about a connected or disconnected card reader. -This message will be sent by the AusweisApp2 if a card reader was added +This message will be sent by the |AppName| if a card reader was added or removed to the operating system. Also if a card was inserted into a card reader or removed from a card reader. @@ -886,7 +902,7 @@ STATUS ^^^^^^ Provides information about the current workflow and state. This message indicates if a workflow is in progress or the -workflow is paused. This can occur if the AusweisApp2 needs +workflow is paused. This can occur if the |AppName| needs additional data like :ref:`access_rights` or :ref:`insert_card`. The messages will be sent by default if not disabled in :ref:`run_auth` @@ -925,7 +941,7 @@ UNKNOWN_COMMAND Indicates that the command type is unknown. If your application receives this message you -passed a wrong command to the AusweisApp2. +passed a wrong command to the |AppName|. Please fix your command and send it again! diff --git a/docs/sdk/workflow.rst b/docs/sdk/workflow.rst index a55a97779..1b7ab51da 100644 --- a/docs/sdk/workflow.rst +++ b/docs/sdk/workflow.rst @@ -1,7 +1,7 @@ Workflow -------- This section shows some possible workflows as an example -communication between your application and the AusweisApp2. +communication between your application and the |AppName|. The JSON structure can be identified by parameter **cmd** or parameter **msg** as described in section :doc:`commands` @@ -9,7 +9,7 @@ and section :doc:`messages`. - **cmd**: Commands are sent by your application. -- **msg**: Messages are sent by the AusweisApp2. +- **msg**: Messages are sent by the |AppName|. diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt index 77505ba7f..201bcf8a3 100644 --- a/libs/CMakeLists.txt +++ b/libs/CMakeLists.txt @@ -147,9 +147,9 @@ set(ENABLED_TARGETS) list(APPEND ENABLED_TARGETS openssl) set(OPENSSL_CONFIGURE_FLAGS no-camellia no-bf no-aria no-seed no-poly1305 no-srp no-gost no-idea no-mdc2 no-rc2 no-rc4 no-rc5 no-srtp no-sm2 no-sm3 no-sm4) -set(OPENSSL_CONFIGURE_FLAGS ${OPENSSL_CONFIGURE_FLAGS} no-ct no-dgram no-cast no-chacha no-blake2 no-rmd160 no-scrypt no-siphash no-whirlpool no-md4 no-des) +set(OPENSSL_CONFIGURE_FLAGS ${OPENSSL_CONFIGURE_FLAGS} no-ct no-dgram no-cast no-chacha no-blake2 no-rmd160 no-scrypt no-siphash no-whirlpool no-md4 no-des no-ec2m) set(OPENSSL_CONFIGURE_FLAGS ${OPENSSL_CONFIGURE_FLAGS} no-tls1 no-tls1-method no-tls1_1 no-tls1_1-method no-tls1_3 no-ssl3 no-ssl3-method no-dtls no-dtls1-method no-dtls1_2-method) -set(OPENSSL_CONFIGURE_FLAGS ${OPENSSL_CONFIGURE_FLAGS} no-engine no-async no-dso no-comp no-ts no-makedepend no-tests no-legacy shared) +set(OPENSSL_CONFIGURE_FLAGS ${OPENSSL_CONFIGURE_FLAGS} no-deprecated no-engine no-async no-dso no-comp no-ts no-makedepend no-tests no-legacy shared) if(${CMAKE_BUILD_TYPE} STREQUAL "DEBUG") set(OPENSSL_CONFIGURE_FLAGS --debug ${OPENSSL_CONFIGURE_FLAGS}) @@ -280,9 +280,9 @@ ExternalProject_Add_Step(openssl configdata if(MAC) set(OPENSSL_FILE_VERSION 3) add_custom_command(TARGET openssl POST_BUILD - COMMAND install_name_tool -id libcrypto.${OPENSSL_FILE_VERSION}${CMAKE_SHARED_LIBRARY_SUFFIX} ${DESTINATION_DIR}/lib/libcrypto.${OPENSSL_FILE_VERSION}${CMAKE_SHARED_LIBRARY_SUFFIX} - COMMAND install_name_tool -id libssl.${OPENSSL_FILE_VERSION}${CMAKE_SHARED_LIBRARY_SUFFIX} ${DESTINATION_DIR}/lib/libssl.${OPENSSL_FILE_VERSION}${CMAKE_SHARED_LIBRARY_SUFFIX} - COMMAND install_name_tool -change ${DESTINATION_DIR}/lib/libcrypto.${OPENSSL_FILE_VERSION}${CMAKE_SHARED_LIBRARY_SUFFIX} libcrypto.${OPENSSL_FILE_VERSION}${CMAKE_SHARED_LIBRARY_SUFFIX} ${DESTINATION_DIR}/lib/libssl.${OPENSSL_FILE_VERSION}${CMAKE_SHARED_LIBRARY_SUFFIX}) + COMMAND install_name_tool -id @rpath/libcrypto.${OPENSSL_FILE_VERSION}${CMAKE_SHARED_LIBRARY_SUFFIX} ${DESTINATION_DIR}/lib/libcrypto.${OPENSSL_FILE_VERSION}${CMAKE_SHARED_LIBRARY_SUFFIX} + COMMAND install_name_tool -id @rpath/libssl.${OPENSSL_FILE_VERSION}${CMAKE_SHARED_LIBRARY_SUFFIX} ${DESTINATION_DIR}/lib/libssl.${OPENSSL_FILE_VERSION}${CMAKE_SHARED_LIBRARY_SUFFIX} + COMMAND install_name_tool -change ${DESTINATION_DIR}/lib/libcrypto.${OPENSSL_FILE_VERSION}${CMAKE_SHARED_LIBRARY_SUFFIX} @rpath/libcrypto.${OPENSSL_FILE_VERSION}${CMAKE_SHARED_LIBRARY_SUFFIX} ${DESTINATION_DIR}/lib/libssl.${OPENSSL_FILE_VERSION}${CMAKE_SHARED_LIBRARY_SUFFIX}) endif() if(IOS) @@ -345,9 +345,9 @@ list(APPEND NO_FEATURES_SHARED designer testlib_selfcover) list(APPEND NO_FEATURES_SHARED imageformat_bmp imageformat_ppm imageformat_xbm) list(APPEND NO_FEATURES_SHARED sharedmemory textodfwriter) list(APPEND NO_FEATURES_SHARED undocommand undogroup undostack) -list(APPEND NO_FEATURES_SHARED printsupport dtls dom sql xml) +list(APPEND NO_FEATURES_SHARED printsupport dtls dom sql xml pdf) if(CONTAINER_SDK) - list(APPEND NO_FEATURES_SHARED testlib) + list(APPEND NO_FEATURES_SHARED testlib androiddeployqt) endif() foreach(feature ${NO_FEATURES_SHARED}) set(QT_CONFIGURE_FLAGS_SHARED ${QT_CONFIGURE_FLAGS_SHARED} -no-feature-${feature}) @@ -363,18 +363,17 @@ foreach(feature ${NO_FEATURES}) endforeach() -list(APPEND SKIP_MODULES qtopcua qtwebchannel qtlanguageserver qtspeech) -list(APPEND SKIP_MODULES qtwebengine qtactiveqt qtserialbus qt5compat qtsensors) -list(APPEND SKIP_MODULES qtserialport qtvirtualkeyboard qtcharts) -list(APPEND SKIP_MODULES qtdatavis3d qt3d qtwayland qtremoteobjects) -list(APPEND SKIP_MODULES qtwebview qtmultimedia qtlottie qtquick3d qtquick3dphysics) -list(APPEND SKIP_MODULES qtnetworkauth qtmqtt qtcoap qtquicktimeline qtdoc qtpositioning) +set(QT_MODULES qtbase,qtwebsockets,qtscxml) +if(NOT INTEGRATED_SDK) + set(QT_MODULES ${QT_MODULES},qttranslations,qtdeclarative,qtimageformats,qttools,qtsvg,qtconnectivity,qtshadertools) +endif() +set(QT_CONFIGURE_FLAGS ${QT_CONFIGURE_FLAGS} -submodules ${QT_MODULES}) + +set(QT_MODULES_SKIP qtactiveqt,qtlanguageserver) # enabled by dependency but not necessary if(INTEGRATED_SDK) - list(APPEND SKIP_MODULES qttranslations qtsensors qtdeclarative qtquickcontrols2 qtgraphicaleffects qtimageformats qttools qtsvg qtconnectivity) + set(QT_MODULES_SKIP ${QT_MODULES_SKIP},qtdeclarative) # otherwise qtwebsockets and qtscxml enables it endif() -foreach(module ${SKIP_MODULES}) - set(QT_CONFIGURE_FLAGS_SHARED ${QT_CONFIGURE_FLAGS_SHARED} -skip ${module}) -endforeach() +set(QT_CONFIGURE_FLAGS_SHARED ${QT_CONFIGURE_FLAGS_SHARED} -skip ${QT_MODULES_SKIP}) set(QT_CONFIGURE_FLAGS_OTHER -no-journald -no-directfb -no-linuxfb) @@ -470,13 +469,8 @@ if (BUILD_HOST_QT AND (IOS OR ANDROID)) set(QT_HOST_CONFIGURE_FLAGS -prefix ${QT_HOST_PATH} -release -optimize-size -shared -no-widgets -no-openssl -no-zstd -no-opengl) set(QT_HOST_CONFIGURE_FLAGS ${QT_HOST_CONFIGURE_FLAGS} ${QT_CONFIGURE_FLAGS_SHARED}) - - set(QT_HOST_CMAKE_FLAGS ${QT_HOST_CMAKE_FLAGS} -DCMAKE_PREFIX_PATH=${QT_HOST_PATH}) - - list(APPEND SKIP_HOST_MODULES qtsvg qtimageformats qtconnectivity qttranslations qtwebsockets) - foreach(module ${SKIP_HOST_MODULES}) - set(QT_HOST_CONFIGURE_FLAGS ${QT_HOST_CONFIGURE_FLAGS} -skip ${module}) - endforeach() + set(QT_HOST_CMAKE_FLAGS ${QT_HOST_CMAKE_FLAGS} -DCMAKE_PREFIX_PATH=${QT_HOST_PATH}) + set(QT_HOST_CONFIGURE_FLAGS ${QT_HOST_CONFIGURE_FLAGS} -submodules qtbase,qtdeclarative,qtshadertools,qttools) ExternalProject_Add(qt-host URL ${QT_URLS} diff --git a/libs/README.rst b/libs/README.rst index ad1e028fd..720766ceb 100644 --- a/libs/README.rst +++ b/libs/README.rst @@ -1,7 +1,7 @@ Libraries ========= -Um die AusweisApp2 zu bauen ist eine Toolchain erforderlich, die die +Um die AusweisApp zu bauen ist eine Toolchain erforderlich, die die Abhängigkeiten und die Compilertools beinhaltet. Unterstützte C++17 Compiler: @@ -50,10 +50,10 @@ Der Build umfasst unter anderem das Qt-Framework, daher kann (je nach Rechenleis der Build einige Stunden dauern. Wichtig bei der Angabe in CMake ist der Verweis auf den Ordner "libs". Ein Verweis -direkt auf "AusweisApp2" würde den Build für die "AusweisApp2" konfigurieren. +direkt auf "AusweisApp" würde den Build für die "AusweisApp" konfigurieren. Nach dem Aufruf "nmake"/"mingw32-make"/"ninja" werden nun alle Bibliotheken gebaut und -in dem Ordner ./dist installiert. Dieser Ordner kann beim Build von der AusweisApp2 +in dem Ordner ./dist installiert. Dieser Ordner kann beim Build von der AusweisApp mittels -DCMAKE_PREFIX_PATH als Toolchain angegeben werden. Zusätzlich kann mit dem make Target "compress" der Inhalt der dist-Ordner bereinigt und ein Tarball aus den gebauten Bibliotheken erzeugt werden. @@ -78,14 +78,14 @@ macOS Unter MacOS ist die Einrichtung relativ einfach und bedarf nur der oben genannten Voreinstellungen. Es wird der von Apple ausgelieferte clang compiler verwendet. -Beispiel: Innerhalb von /Users/governikus/AusweisApp2 befindet sich der Quellcode. +Beispiel: Innerhalb von /Users/governikus/AusweisApp befindet sich der Quellcode. :: $ cd /Users/governikus $ mkdir build $ cd build - $ cmake -DCMAKE_BUILD_TYPE=release ../AusweisApp2/libs + $ cmake -DCMAKE_BUILD_TYPE=release ../AusweisApp/libs $ make @@ -248,7 +248,7 @@ Dabei wird Qt über Windows-CLI und OpenSSL unter MSYS2 gebaut. #. cd c:\msys64\home\user\qt -#. cmake -DCMAKE_BUILD_TYPE=release C:/AusweisApp2/libs -G "MinGW Makefiles" +#. cmake -DCMAKE_BUILD_TYPE=release C:/AusweisApp/libs -G "MinGW Makefiles" #. MSYS2 Shell starten ("msys2_shell.cmd -use-full-path") @@ -277,7 +277,7 @@ OpenSSL / Qt mit MSVC #. call vcvarsall.bat amd64 -#. cmake -DCMAKE_BUILD_TYPE=release C:/AusweisApp2/libs -G "NMake Makefiles" +#. cmake -DCMAKE_BUILD_TYPE=release C:/AusweisApp/libs -G "NMake Makefiles" #. nmake @@ -291,14 +291,14 @@ auf dem Mac vorhanden sein. Die folgende Anleitung wurde unter macOS 10.12 getes Ebenfalls muss für den Build-Vorgang von Qt ein iOS Developer-Zertifikat mit Wildcard (*) im Keystore von MacOS hinterlegt sein. -Beispiel: Innerhalb von /Users/governikus/AusweisApp2 befindet sich der Quellcode. +Beispiel: Innerhalb von /Users/governikus/AusweisApp befindet sich der Quellcode. :: $ cd /Users/governikus $ mkdir build $ cd build - $ cmake -DCMAKE_BUILD_TYPE=release -DCMAKE_TOOLCHAIN_FILE=../AusweisApp2/cmake/iOS.toolchain.cmake ../AusweisApp2/libs + $ cmake -DCMAKE_BUILD_TYPE=release -DCMAKE_TOOLCHAIN_FILE=../AusweisApp/cmake/iOS.toolchain.cmake ../AusweisApp/libs $ make @@ -340,14 +340,14 @@ Komponenten vorhanden sein: -Beispiel: Innerhalb von /home/governikus/AusweisApp2 befindet sich der Quellcode. +Beispiel: Innerhalb von /home/governikus/AusweisApp befindet sich der Quellcode. :: $ cd /home/governikus $ mkdir build $ cd build - $ cmake -DCMAKE_BUILD_TYPE=release -DCMAKE_TOOLCHAIN_FILE=../AusweisApp2/cmake/android.toolchain.cmake ../AusweisApp2/libs + $ cmake -DCMAKE_BUILD_TYPE=release -DCMAKE_TOOLCHAIN_FILE=../AusweisApp/cmake/android.toolchain.cmake ../AusweisApp/libs $ make Standardmäßig wird die Architektur "armeabi-v7a" gewählt. Um zum Beispiel die Toolchain für x86-Architektur diff --git a/libs/Versions.cmake b/libs/Versions.cmake index 56bc6c003..644bd3303 100644 --- a/libs/Versions.cmake +++ b/libs/Versions.cmake @@ -1,5 +1,5 @@ -set(QT 6.4.1) -set(QT_HASH e20b850b6134098a7f2e7701cfddfb213c6cf394b9e848e6fbc5b0e89dcfcc09) +set(QT 6.5.3) +set(QT_HASH 7cda4d119aad27a3887329cfc285f2aba5da85601212bcb0aea27bd6b7b544cb) -set(OPENSSL 3.0.9) -set(OPENSSL_HASH eb1ab04781474360f77c318ab89d8c5a03abc38e63d65a603cabbf1b00a1dc90) +set(OPENSSL 3.1.4) +set(OPENSSL_HASH 840af5366ab9b522bde525826be3ef0fb0af81c6a9ebd84caa600fea1731eee3) diff --git a/libs/patches.cmake b/libs/patches.cmake index fcedd53b2..64dd98b24 100644 --- a/libs/patches.cmake +++ b/libs/patches.cmake @@ -26,9 +26,10 @@ cmake_minimum_required(VERSION 3.19.0) # - Upgrade Qt or OpenSSL # 1. Apply all patches with this script and do the following on each repository. # The version is an example and should be adjusted! -# 2. git checkout ausweisapp_6.4.3 -b ausweisapp_6.6.0 +# 2. git checkout ausweisapp_6.4.3 # 3. git rebase --onto v6.6.0 v6.4.3 HEAD -# 4. Bump version in Versions.cmake and use this script to generate the patches. +# 4. git checkout -b ausweisapp_6.6.0 +# 5. Bump version in Versions.cmake and use this script to generate the patches. if(NOT CMAKE_SCRIPT_MODE_FILE OR NOT CMD) message(FATAL_ERROR "Usage: cmake -DCMD=apply|generate -P libs/patches.cmake") @@ -92,6 +93,9 @@ function(get_version_branch prefix _version _branch) set(tmp_branch ${tmp_branch}_${OPENSSL}) elseif(prefix MATCHES "qt") set(version v${QT}) + if(version MATCHES "-rc$") + set(version ${version}1) + endif() set(tmp_branch ${tmp_branch}_${QT}) endif() diff --git a/libs/patches/openssl-0001-Adjust-iOS-target.patch b/libs/patches/openssl-0001-Adjust-iOS-target.patch index 6f9fcdcc7..b2ba7f1b0 100644 --- a/libs/patches/openssl-0001-Adjust-iOS-target.patch +++ b/libs/patches/openssl-0001-Adjust-iOS-target.patch @@ -1,4 +1,4 @@ -From c97e9531a9da0ad5ae3bfb7cec90b03475a58a76 Mon Sep 17 00:00:00 2001 +From 89d4eab1163e8542e59c6c486a2546d20940663b Mon Sep 17 00:00:00 2001 From: Lars Schmertmann Date: Fri, 12 Feb 2021 13:15:00 +0100 Subject: Adjust iOS target diff --git a/libs/patches/openssl-0002-android-shlib_variant.patch b/libs/patches/openssl-0002-android-shlib_variant.patch index d562c1057..d92ed162e 100644 --- a/libs/patches/openssl-0002-android-shlib_variant.patch +++ b/libs/patches/openssl-0002-android-shlib_variant.patch @@ -1,4 +1,4 @@ -From 8353ce61f188109953e327b4bddf65c95e4baf92 Mon Sep 17 00:00:00 2001 +From 898564ac262e25b8b2aa67d541a819e6986fda62 Mon Sep 17 00:00:00 2001 From: Lars Schmertmann Date: Tue, 19 Jan 2021 17:07:51 +0100 Subject: android shlib_variant diff --git a/libs/patches/openssl-0003-Do-not-ignore-empty-associated-data-with-AES-SIV-mod.patch b/libs/patches/openssl-0003-Do-not-ignore-empty-associated-data-with-AES-SIV-mod.patch deleted file mode 100644 index 914498ed2..000000000 --- a/libs/patches/openssl-0003-Do-not-ignore-empty-associated-data-with-AES-SIV-mod.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 9faa80071777b8a0b9eca1ab59bf69adb4621d9f Mon Sep 17 00:00:00 2001 -From: Tomas Mraz -Date: Tue, 4 Jul 2023 17:30:35 +0200 -Subject: Do not ignore empty associated data with AES-SIV mode - -The AES-SIV mode allows for multiple associated data items -authenticated separately with any of these being 0 length. - -The provided implementation ignores such empty associated data -which is incorrect in regards to the RFC 5297 and is also -a security issue because such empty associated data then become -unauthenticated if an application expects to authenticate them. - -Fixes CVE-2023-2975 - -Reviewed-by: Matt Caswell -Reviewed-by: Paul Dale -(Merged from https://github.com/openssl/openssl/pull/21384) - -(cherry picked from commit c426c281cfc23ab182f7d7d7a35229e7db1494d9) -(cherry picked from commit 00e2f5eea29994d19293ec4e8c8775ba73678598) ---- - .../implementations/ciphers/cipher_aes_siv.c | 18 +++++++++++------- - 1 file changed, 11 insertions(+), 7 deletions(-) - -diff --git x/providers/implementations/ciphers/cipher_aes_siv.c y/providers/implementations/ciphers/cipher_aes_siv.c -index 45010b90db..b396c8651a 100644 ---- x/providers/implementations/ciphers/cipher_aes_siv.c -+++ y/providers/implementations/ciphers/cipher_aes_siv.c -@@ -120,14 +120,18 @@ static int siv_cipher(void *vctx, unsigned char *out, size_t *outl, - if (!ossl_prov_is_running()) - return 0; - -- if (inl == 0) { -- *outl = 0; -- return 1; -- } -+ /* Ignore just empty encryption/decryption call and not AAD. */ -+ if (out != NULL) { -+ if (inl == 0) { -+ if (outl != NULL) -+ *outl = 0; -+ return 1; -+ } - -- if (outsize < inl) { -- ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); -- return 0; -+ if (outsize < inl) { -+ ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); -+ return 0; -+ } - } - - if (ctx->hw->cipher(ctx, out, in, inl) <= 0) diff --git a/libs/patches/openssl-0004-Fix-DH_check-excessive-time-with-over-sized-modulus.patch b/libs/patches/openssl-0004-Fix-DH_check-excessive-time-with-over-sized-modulus.patch deleted file mode 100644 index 4582d5309..000000000 --- a/libs/patches/openssl-0004-Fix-DH_check-excessive-time-with-over-sized-modulus.patch +++ /dev/null @@ -1,72 +0,0 @@ -From c012334ed713416cc30d6b2ff4dbeca97d1503c3 Mon Sep 17 00:00:00 2001 -From: Matt Caswell -Date: Thu, 6 Jul 2023 16:36:35 +0100 -Subject: Fix DH_check() excessive time with over sized modulus - -The DH_check() function checks numerous aspects of the key or parameters -that have been supplied. Some of those checks use the supplied modulus -value even if it is excessively large. - -There is already a maximum DH modulus size (10,000 bits) over which -OpenSSL will not generate or derive keys. DH_check() will however still -perform various tests for validity on such a large modulus. We introduce a -new maximum (32,768) over which DH_check() will just fail. - -An application that calls DH_check() and supplies a key or parameters -obtained from an untrusted source could be vulnerable to a Denial of -Service attack. - -The function DH_check() is itself called by a number of other OpenSSL -functions. An application calling any of those other functions may -similarly be affected. The other functions affected by this are -DH_check_ex() and EVP_PKEY_param_check(). - -CVE-2023-3446 - -Reviewed-by: Paul Dale -Reviewed-by: Tom Cosgrove -Reviewed-by: Bernd Edlinger -Reviewed-by: Tomas Mraz -(Merged from https://github.com/openssl/openssl/pull/21451) - -(cherry picked from commit 9e0094e2aa1b3428a12d5095132f133c078d3c3d) -(cherry picked from commit 1fa20cf2f506113c761777127a38bce5068740eb) ---- - crypto/dh/dh_check.c | 6 ++++++ - include/openssl/dh.h | 6 +++++- - 2 files changed, 11 insertions(+), 1 deletion(-) - -diff --git x/crypto/dh/dh_check.c y/crypto/dh/dh_check.c -index 0b391910d6..84a926998e 100644 ---- x/crypto/dh/dh_check.c -+++ y/crypto/dh/dh_check.c -@@ -152,6 +152,12 @@ int DH_check(const DH *dh, int *ret) - if (nid != NID_undef) - return 1; - -+ /* Don't do any checks at all with an excessively large modulus */ -+ if (BN_num_bits(dh->params.p) > OPENSSL_DH_CHECK_MAX_MODULUS_BITS) { -+ ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE); -+ return 0; -+ } -+ - if (!DH_check_params(dh, ret)) - return 0; - -diff --git x/include/openssl/dh.h y/include/openssl/dh.h -index b97871eca7..36420f51d8 100644 ---- x/include/openssl/dh.h -+++ y/include/openssl/dh.h -@@ -89,7 +89,11 @@ int EVP_PKEY_CTX_get0_dh_kdf_ukm(EVP_PKEY_CTX *ctx, unsigned char **ukm); - # include - - # ifndef OPENSSL_DH_MAX_MODULUS_BITS --# define OPENSSL_DH_MAX_MODULUS_BITS 10000 -+# define OPENSSL_DH_MAX_MODULUS_BITS 10000 -+# endif -+ -+# ifndef OPENSSL_DH_CHECK_MAX_MODULUS_BITS -+# define OPENSSL_DH_CHECK_MAX_MODULUS_BITS 32768 - # endif - - # define OPENSSL_DH_FIPS_MIN_MODULUS_BITS 1024 diff --git a/libs/patches/qtbase-0001-Revert-Fix-usage-of-logging-category-on-Android.patch b/libs/patches/qtbase-0001-Revert-Fix-usage-of-logging-category-on-Android.patch index 8a73295e4..a4b9447bb 100644 --- a/libs/patches/qtbase-0001-Revert-Fix-usage-of-logging-category-on-Android.patch +++ b/libs/patches/qtbase-0001-Revert-Fix-usage-of-logging-category-on-Android.patch @@ -1,4 +1,4 @@ -From 68bc2e3fae6480d6315f524c2ee9acf3a33a435a Mon Sep 17 00:00:00 2001 +From 40410b9e2ba5d02b457bb37fc90663585573ca53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Klitzing?= Date: Mon, 25 Jul 2022 17:08:54 +0200 Subject: Revert "Fix usage of logging category on Android" @@ -11,10 +11,10 @@ Change-Id: If19a9d615e01d61c79955cda4789ba1646520ee1 1 file changed, 1 insertion(+), 8 deletions(-) diff --git x/qtbase/src/corelib/global/qlogging.cpp y/qtbase/src/corelib/global/qlogging.cpp -index 9ac70b3340..737a91dc6e 100644 +index 7e708c9c41..96c3bc5dc6 100644 --- x/qtbase/src/corelib/global/qlogging.cpp +++ y/qtbase/src/corelib/global/qlogging.cpp -@@ -1450,10 +1450,7 @@ QString qFormatLogMessage(QtMsgType type, const QMessageLogContext &context, con +@@ -1593,10 +1593,7 @@ QString qFormatLogMessage(QtMsgType type, const QMessageLogContext &context, con } else if (token == messageTokenC) { message.append(str); } else if (token == categoryTokenC) { @@ -25,7 +25,7 @@ index 9ac70b3340..737a91dc6e 100644 } else if (token == typeTokenC) { switch (type) { case QtDebugMsg: message.append("debug"_L1); break; -@@ -1701,11 +1698,7 @@ static bool android_default_message_handler(QtMsgType type, +@@ -1844,11 +1841,7 @@ static bool android_default_message_handler(QtMsgType type, break; }; diff --git a/libs/patches/qtbase-0002-Android-Restore-the-default-QSettings-path-to-the-.c.patch b/libs/patches/qtbase-0002-Android-Restore-the-default-QSettings-path-to-the-.c.patch deleted file mode 100644 index 13641dcee..000000000 --- a/libs/patches/qtbase-0002-Android-Restore-the-default-QSettings-path-to-the-.c.patch +++ /dev/null @@ -1,89 +0,0 @@ -From bdd9f0e3a243977858df6691b734b7f596a9729b Mon Sep 17 00:00:00 2001 -From: Bartlomiej Moskal -Date: Tue, 30 May 2023 14:17:19 +0200 -Subject: Android: Restore the default QSettings path to the .config directory - -After 140ca89a3c2b8d78889d27217f977cd4de10041b commit, the path of the -QSettings default file location changed. That caused the problem with -updating the app (old settings file is not used anymore). That is why we -should still use old (.config) directory for QSettings file if the file -exists. - -Pick-to: 6.2 6.5 6.6 -Fixes: QTBUG-109405 -Fixes: QTBUG-109369 -Change-Id: I8ce53e0a80e4c2d16802b27b000ab3fbed198628 -Reviewed-by: Assam Boudjelthia -(cherry picked from commit beaaa0bf02fee696b03f2839bea8e0e6bc685a62) ---- - src/corelib/io/qsettings.cpp | 40 +++++++++++++++++++++++++----------- - 1 file changed, 28 insertions(+), 12 deletions(-) - -diff --git x/qtbase/src/corelib/io/qsettings.cpp y/qtbase/src/corelib/io/qsettings.cpp -index 60622e3aaa..9fb2e0b522 100644 ---- x/qtbase/src/corelib/io/qsettings.cpp -+++ y/qtbase/src/corelib/io/qsettings.cpp -@@ -954,26 +954,43 @@ static inline int pathHashKey(QSettings::Format format, QSettings::Scope scope) - } - - #ifndef Q_OS_WIN --static QString make_user_path() -+static constexpr QChar sep = u'/'; -+ -+#if !defined(QSETTINGS_USE_QSTANDARDPATHS) || defined(Q_OS_ANDROID) -+static QString make_user_path_without_qstandard_paths() - { -- static constexpr QChar sep = u'/'; --#ifndef QSETTINGS_USE_QSTANDARDPATHS -- // Non XDG platforms (OS X, iOS, Android...) have used this code path erroneously -- // for some time now. Moving away from that would require migrating existing settings. - QByteArray env = qgetenv("XDG_CONFIG_HOME"); - if (env.isEmpty()) { - return QDir::homePath() + "/.config/"_L1; - } else if (env.startsWith('/')) { - return QFile::decodeName(env) + sep; -- } else { -- return QDir::homePath() + sep + QFile::decodeName(env) + sep; - } -+ -+ return QDir::homePath() + sep + QFile::decodeName(env) + sep; -+} -+#endif // !QSETTINGS_USE_QSTANDARDPATHS || Q_OS_ANDROID -+ -+static QString make_user_path() -+{ -+#ifndef QSETTINGS_USE_QSTANDARDPATHS -+ // Non XDG platforms (OS X, iOS, Android...) have used this code path erroneously -+ // for some time now. Moving away from that would require migrating existing settings. -+ // The migration has already been done for Android. -+ return make_user_path_without_qstandard_paths(); - #else -- // When using a proper XDG platform, use QStandardPaths rather than the above hand-written code; -- // it makes the use of test mode from unit tests possible. -+ -+#ifdef Q_OS_ANDROID -+ // If an old settings path exists, use it instead of creating a new one -+ QString ret = make_user_path_without_qstandard_paths(); -+ if (QFile(ret).exists()) -+ return ret; -+#endif // Q_OS_ANDROID -+ -+ // When using a proper XDG platform or Android platform, use QStandardPaths rather than the -+ // above hand-written code. It makes the use of test mode from unit tests possible. - // Ideally all platforms should use this, but see above for the migration issue. - return QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + sep; --#endif -+#endif // !QSETTINGS_USE_QSTANDARDPATHS - } - #endif // !Q_OS_WIN - -@@ -1338,8 +1355,7 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile) - // On android and if it is a content URL put the lock file in a - // writable location to prevent permissions issues and invalid paths. - if (confFile->name.startsWith("content:"_L1)) -- lockFileName = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) -- + QFileInfo(lockFileName).fileName(); -+ lockFileName = make_user_path() + QFileInfo(lockFileName).fileName(); - # endif - /* - Use a lockfile in order to protect us against other QSettings instances diff --git a/libs/patches/qtbase-0004-Fix-warning-in-q20algorithm.h-when-xcodebuild-is-use.patch b/libs/patches/qtbase-0002-Fix-warning-in-q20algorithm.h-when-xcodebuild-is-use.patch similarity index 96% rename from libs/patches/qtbase-0004-Fix-warning-in-q20algorithm.h-when-xcodebuild-is-use.patch rename to libs/patches/qtbase-0002-Fix-warning-in-q20algorithm.h-when-xcodebuild-is-use.patch index e9761b1d9..26a28e62b 100644 --- a/libs/patches/qtbase-0004-Fix-warning-in-q20algorithm.h-when-xcodebuild-is-use.patch +++ b/libs/patches/qtbase-0002-Fix-warning-in-q20algorithm.h-when-xcodebuild-is-use.patch @@ -1,4 +1,4 @@ -From 03485e0ca36c615b87b82c6711fbacf0493d02bc Mon Sep 17 00:00:00 2001 +From 0fa22a4be5abda44d34cf7c5d0352378c2f9fd54 Mon Sep 17 00:00:00 2001 From: Lars Schmertmann Date: Mon, 9 Jan 2023 06:54:53 +0100 Subject: Fix warning in q20algorithm.h when xcodebuild is used @@ -14,7 +14,7 @@ Change-Id: If5ccbfffd0b6a53f73f221b45033dab7e4775d89 1 file changed, 3 insertions(+), 3 deletions(-) diff --git x/qtbase/src/corelib/global/q20algorithm.h y/qtbase/src/corelib/global/q20algorithm.h -index 69dc2d2446..88e8ab08d2 100644 +index f670a5dbee..24d801b2cd 100644 --- x/qtbase/src/corelib/global/q20algorithm.h +++ y/qtbase/src/corelib/global/q20algorithm.h @@ -147,7 +147,7 @@ using std::ranges::none_of; diff --git a/libs/patches/qtbase-0003-Android-A11Y-Only-access-the-main-thread-when-it-is-.patch b/libs/patches/qtbase-0003-Android-A11Y-Only-access-the-main-thread-when-it-is-.patch deleted file mode 100644 index df111949d..000000000 --- a/libs/patches/qtbase-0003-Android-A11Y-Only-access-the-main-thread-when-it-is-.patch +++ /dev/null @@ -1,63 +0,0 @@ -From a7490023e8f11906b30013c93ff991d941efc622 Mon Sep 17 00:00:00 2001 -From: Julian Greilich -Date: Wed, 4 Jan 2023 16:32:28 +0100 -Subject: Android A11Y: Only access the main thread when it is not blocked - -When the qtMainLoopThread calls QSGThreadedRenderLoop::polishAndSync(), -it waits for the QSGRenderThread. - -In the QSGRenderThread, QAndroidPlatformOpenGLWindow::eglSurface() -calls QtAndroid::createSurface() and waits for the "android main -thread" to return a valid surface. -When the "android main thread" now calls "runInObjectContext" (e.g. by -calling QtAndroidAccessibility::childIdListForAccessibleObject()) it -waits for the qtMainLoopThread and the program is stuck in a deadlock. - -To prevent this, we protect all BlockedQueuedConnection from the -"android main thread" to the qtMainLoopThread by acquiring the -AndroidDeadlockProtector. -When QAndroidPlatformOpenGLWindow::eglSurface() already acquired the -AndroidDeadlockProtector we abort the current A11y call with an emtpy -or default value. - -Note: b8a95275440b8a143ee648466fd8b5401ee1e839 already tried to fix -this by checking "getSurfaceCount() != 0", but there are situations, -where a new surface is being created while an old surface is still -present. - -Task-number: QTBUG-105958 -Pick-to: 6.5 6.4 6.3 6.2 5.15 -Change-Id: Ie40e8654c99aace9e69b0b8412952fa22c89f071 -Reviewed-by: Assam Boudjelthia -(cherry picked from commit b832a5ac72c6015b6509d60b75b2ce5d5e570800) ---- - .../platforms/android/androidjniaccessibility.cpp | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git x/qtbase/src/plugins/platforms/android/androidjniaccessibility.cpp y/qtbase/src/plugins/platforms/android/androidjniaccessibility.cpp -index 3067cb178a..8990289dc4 100644 ---- x/qtbase/src/plugins/platforms/android/androidjniaccessibility.cpp -+++ y/qtbase/src/plugins/platforms/android/androidjniaccessibility.cpp -@@ -1,6 +1,7 @@ - // Copyright (C) 2021 The Qt Company Ltd. - // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only - -+#include "androiddeadlockprotector.h" - #include "androidjniaccessibility.h" - #include "androidjnimain.h" - #include "qandroidplatformintegration.h" -@@ -61,6 +62,14 @@ namespace QtAndroidAccessibility - template - void runInObjectContext(QObject *context, Func &&func, Ret *retVal) - { -+ AndroidDeadlockProtector protector; -+ if (!protector.acquire()) { -+ __android_log_print(ANDROID_LOG_WARN, m_qtTag, -+ "Could not run accessibility call in object context, accessing " -+ "main thread could lead to deadlock"); -+ return; -+ } -+ - if (!QtAndroid::blockEventLoopsWhenSuspended() - || QGuiApplication::applicationState() != Qt::ApplicationSuspended) { - QMetaObject::invokeMethod(context, func, Qt::BlockingQueuedConnection, retVal); diff --git a/libs/patches/qtbase-0003-Revert-iOS-Don-t-invalidate-a11y-whenever-UI-element.patch b/libs/patches/qtbase-0003-Revert-iOS-Don-t-invalidate-a11y-whenever-UI-element.patch new file mode 100644 index 000000000..988fe5d38 --- /dev/null +++ b/libs/patches/qtbase-0003-Revert-iOS-Don-t-invalidate-a11y-whenever-UI-element.patch @@ -0,0 +1,78 @@ +From 525b1bd08f9805685134f6f2272edff80fe4b023 Mon Sep 17 00:00:00 2001 +From: Andre Klitzing +Date: Mon, 24 Jul 2023 16:13:12 +0200 +Subject: Revert "iOS: Don't invalidate a11y whenever UI elements are added or + removed" + +This reverts commit 6eefbf74149164eac316cea59a00b45f70976ad2. +--- + .../platforms/ios/qiosplatformaccessibility.mm | 17 ++++------------- + src/plugins/platforms/ios/qioswindow.mm | 1 - + .../platforms/ios/quiview_accessibility.mm | 1 + + 3 files changed, 5 insertions(+), 14 deletions(-) + +diff --git x/qtbase/src/plugins/platforms/ios/qiosplatformaccessibility.mm y/qtbase/src/plugins/platforms/ios/qiosplatformaccessibility.mm +index f22782fb04..d54b7db57a 100644 +--- x/qtbase/src/plugins/platforms/ios/qiosplatformaccessibility.mm ++++ y/qtbase/src/plugins/platforms/ios/qiosplatformaccessibility.mm +@@ -25,6 +25,8 @@ void invalidateCache(QAccessibleInterface *iface) + // This will invalidate everything regardless of what window the + // interface belonged to. We might want to revisit this strategy later. + // (Therefore this function still takes the interface as argument) ++ // It is also responsible for the bug that focus gets temporary lost ++ // when items get added or removed from the screen + foreach (QWindow *win, QGuiApplication::topLevelWindows()) { + if (win && win->handle()) { + QT_PREPEND_NAMESPACE(QIOSWindow) *window = static_cast(win->handle()); +@@ -36,25 +38,14 @@ void invalidateCache(QAccessibleInterface *iface) + + void QIOSPlatformAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event) + { +- auto *accessibleInterface = event->accessibleInterface(); +- if (!isActive() || !accessibleInterface) ++ if (!isActive() || !event->accessibleInterface()) + return; + switch (event->type()) { + case QAccessible::ObjectCreated: + case QAccessible::ObjectShow: + case QAccessible::ObjectHide: + case QAccessible::ObjectDestroyed: +- invalidateCache(accessibleInterface); +- switch (accessibleInterface->role()) { +- case QAccessible::Window: +- case QAccessible::Dialog: +- // Bigger changes to the UI require a full reset of VoiceOver +- UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil); +- break; +- default: +- // While smaller changes can be handled by re-reading the layout +- UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil); +- } ++ invalidateCache(event->accessibleInterface()); + break; + default: + break; +diff --git x/qtbase/src/plugins/platforms/ios/qioswindow.mm y/qtbase/src/plugins/platforms/ios/qioswindow.mm +index 8de094533b..99f9e38846 100644 +--- x/qtbase/src/plugins/platforms/ios/qioswindow.mm ++++ y/qtbase/src/plugins/platforms/ios/qioswindow.mm +@@ -75,7 +75,6 @@ QIOSWindow::~QIOSWindow() + [m_view touchesCancelled:[NSSet set] withEvent:0]; + + clearAccessibleCache(); +- + m_view.platformWindow = 0; + [m_view removeFromSuperview]; + [m_view release]; +diff --git x/qtbase/src/plugins/platforms/ios/quiview_accessibility.mm y/qtbase/src/plugins/platforms/ios/quiview_accessibility.mm +index 04e1f8cfb3..366141ef81 100644 +--- x/qtbase/src/plugins/platforms/ios/quiview_accessibility.mm ++++ y/qtbase/src/plugins/platforms/ios/quiview_accessibility.mm +@@ -54,6 +54,7 @@ + - (void)clearAccessibleCache + { + [m_accessibleElements removeAllObjects]; ++ UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, @""); + } + + // this is a container, returning yes here means the functions below will never be called diff --git a/libs/patches/qtbase-0004-Fix-living-QLibProxyWrapper-after-shutdown-of-QCoreA.patch b/libs/patches/qtbase-0004-Fix-living-QLibProxyWrapper-after-shutdown-of-QCoreA.patch new file mode 100644 index 000000000..3586ddbcc --- /dev/null +++ b/libs/patches/qtbase-0004-Fix-living-QLibProxyWrapper-after-shutdown-of-QCoreA.patch @@ -0,0 +1,25 @@ +From 496b958b6c0026a681a9ee8871894a079dc2ea5c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Andr=C3=A9=20Klitzing?= +Date: Fri, 18 Aug 2023 14:32:57 +0200 +Subject: Fix living QLibProxyWrapper after shutdown of QCoreApplication + +Pick-to: 6.6 6.5 +Task-number: QTBUG-84234 +Change-Id: I8f5e2947b6529a0a8871d040050205934ee60354 +--- + src/network/kernel/qnetworkproxy_libproxy.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git x/qtbase/src/network/kernel/qnetworkproxy_libproxy.cpp y/qtbase/src/network/kernel/qnetworkproxy_libproxy.cpp +index 46066b86f7..6de7a7fb76 100644 +--- x/qtbase/src/network/kernel/qnetworkproxy_libproxy.cpp ++++ y/qtbase/src/network/kernel/qnetworkproxy_libproxy.cpp +@@ -72,7 +72,7 @@ private: + Data *request; + }; + +-Q_GLOBAL_STATIC(QLibProxyWrapper, libProxyWrapper); ++Q_APPLICATION_STATIC(QLibProxyWrapper, libProxyWrapper) + + QLibProxyWrapper::QLibProxyWrapper() + { diff --git a/libs/patches/qtbase-0005-Do-not-override-OPENSSL_API_COMPAT.patch b/libs/patches/qtbase-0005-Do-not-override-OPENSSL_API_COMPAT.patch new file mode 100644 index 000000000..c43c406dc --- /dev/null +++ b/libs/patches/qtbase-0005-Do-not-override-OPENSSL_API_COMPAT.patch @@ -0,0 +1,25 @@ +From 1d935cfe1de1a015561ee8755c67ec9c8a1bd121 Mon Sep 17 00:00:00 2001 +From: Klitzing +Date: Thu, 31 Aug 2023 13:19:55 +0200 +Subject: Do not override OPENSSL_API_COMPAT + +See QTBUG-83733 and AUTENTAPP-24481 + +Change-Id: Ied55e3d6ebd90fbbecb8c4d8d1638b1de3ba6969 +--- + src/plugins/tls/openssl/CMakeLists.txt | 2 -- + 1 file changed, 2 deletions(-) + +diff --git x/qtbase/src/plugins/tls/openssl/CMakeLists.txt y/qtbase/src/plugins/tls/openssl/CMakeLists.txt +index 0e0a7a1552..e176bbf9d5 100644 +--- x/qtbase/src/plugins/tls/openssl/CMakeLists.txt ++++ y/qtbase/src/plugins/tls/openssl/CMakeLists.txt +@@ -20,8 +20,6 @@ qt_internal_add_plugin(QTlsBackendOpenSSLPlugin + LIBRARIES + Qt::NetworkPrivate + Qt::CorePrivate +- DEFINES +- OPENSSL_API_COMPAT=0x10100000L + ) + + if (WIN32) # Windows header issues diff --git a/libs/patches/qtbase-0005-macOS-Use-NSStatusItem.menu-to-manage-system-tray-me.patch b/libs/patches/qtbase-0005-macOS-Use-NSStatusItem.menu-to-manage-system-tray-me.patch deleted file mode 100644 index 85819c91f..000000000 --- a/libs/patches/qtbase-0005-macOS-Use-NSStatusItem.menu-to-manage-system-tray-me.patch +++ /dev/null @@ -1,127 +0,0 @@ -From e2402debef95b7ccc2050f331ee9f5076332ae91 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= -Date: Mon, 12 Dec 2022 14:33:41 +0100 -Subject: macOS: Use NSStatusItem.menu to manage system tray menu - -Using [NSStatusItem popUpStatusItemMenu:] to manually show the menu is -deprecated, and was causing various issues when right clicking the menu, -such as not unhighlighting the menu item when dismissing the menu, or -worse, not quitting the application if a 'Quit' item was triggered from -a right click. - -The reason we were using popUpStatusItemMenu instead of the menu -property of NSStatusItem was that the latter prevented us from seeing -the action message of the NSStatusItem button, which we used to emit -the system tray's activated signal, but this can be solved by listing -for the menu's tracking state starting. - -Fixes: QTBUG-103515 -Pick-to: 6.4 -Change-Id: I686550ebac7d94d8d11b2e3c49ed16a8240cb214 -Reviewed-by: Volker Hilsheimer -(cherry picked from commit da754d5b6589c9877f0325edb3da5cbc64d966c7) ---- - .../platforms/cocoa/qcocoasystemtrayicon.h | 3 +- - .../platforms/cocoa/qcocoasystemtrayicon.mm | 36 ++++++++++++------- - 2 files changed, 24 insertions(+), 15 deletions(-) - -diff --git x/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h y/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h -index 414560e119..75c33cc5a3 100644 ---- x/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h -+++ y/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h -@@ -45,12 +45,11 @@ public: - bool isSystemTrayAvailable() const override; - bool supportsMessages() const override; - -- void statusItemClicked(); -+ void emitActivated(); - - private: - NSStatusItem *m_statusItem = nullptr; - QStatusItemDelegate *m_delegate = nullptr; -- QCocoaMenu *m_menu = nullptr; - }; - - QT_END_NAMESPACE -diff --git x/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm y/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm -index c004cd69b5..2f7f73b481 100644 ---- x/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm -+++ y/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm -@@ -64,6 +64,8 @@ void QCocoaSystemTrayIcon::init() - - m_delegate = [[QStatusItemDelegate alloc] initWithSysTray:this]; - -+ // In case the status item does not have a menu assigned to it -+ // we fall back to the item's button to detect activation. - m_statusItem.button.target = m_delegate; - m_statusItem.button.action = @selector(statusItemClicked); - [m_statusItem.button sendActionOn:NSEventMaskLeftMouseDown | NSEventMaskRightMouseDown | NSEventMaskOtherMouseDown]; -@@ -81,8 +83,6 @@ void QCocoaSystemTrayIcon::cleanup() - - [m_delegate release]; - m_delegate = nil; -- -- m_menu = nullptr; - } - - QRect QCocoaSystemTrayIcon::geometry() const -@@ -178,12 +178,20 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon) - - void QCocoaSystemTrayIcon::updateMenu(QPlatformMenu *menu) - { -- // We don't set the menu property of the NSStatusItem here, -- // as that would prevent us from receiving the action for the -- // click, and we wouldn't be able to emit the activated signal. -- // Instead we show the menu manually when the status item is -- // clicked. -- m_menu = static_cast(menu); -+ m_statusItem.menu = menu ? static_cast(menu)->nsMenu() : nil; -+ -+ if (m_statusItem.menu) { -+ // When a menu is assigned, NSStatusBarButtonCell will intercept the mouse -+ // down to pop up the menu, and we never see the NSStatusBarButton action. -+ // To ensure we emit the 'activated' signal in both cases we detect when -+ // menu starts tracking, which happens before the menu delegate is sent -+ // the menuWillOpen callback we use to emit aboutToShow for the menu. -+ [NSNotificationCenter.defaultCenter addObserver:m_delegate -+ selector:@selector(statusItemMenuBeganTracking:) -+ name:NSMenuDidBeginTrackingNotification -+ object:m_statusItem.menu -+ ]; -+ } - } - - void QCocoaSystemTrayIcon::updateToolTip(const QString &toolTip) -@@ -226,7 +234,7 @@ void QCocoaSystemTrayIcon::showMessage(const QString &title, const QString &mess - } - } - --void QCocoaSystemTrayIcon::statusItemClicked() -+void QCocoaSystemTrayIcon::emitActivated() - { - auto *mouseEvent = NSApp.currentEvent; - -@@ -245,9 +253,6 @@ void QCocoaSystemTrayIcon::statusItemClicked() - } - - emit activated(activationReason); -- -- if (NSMenu *menu = m_menu ? m_menu->nsMenu() : nil) -- QT_IGNORE_DEPRECATIONS([m_statusItem popUpStatusItemMenu:menu]); - } - - QT_END_NAMESPACE -@@ -270,7 +275,12 @@ QT_END_NAMESPACE - - - (void)statusItemClicked - { -- self.platformSystemTray->statusItemClicked(); -+ self.platformSystemTray->emitActivated(); -+} -+ -+- (void)statusItemMenuBeganTracking:(NSNotification*)notification -+{ -+ self.platformSystemTray->emitActivated(); - } - - - (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification diff --git a/libs/patches/qtbase-0006-iOS-Don-t-assume-screens-will-not-be-connected-befor.patch b/libs/patches/qtbase-0006-iOS-Don-t-assume-screens-will-not-be-connected-befor.patch deleted file mode 100644 index 63c2ce919..000000000 --- a/libs/patches/qtbase-0006-iOS-Don-t-assume-screens-will-not-be-connected-befor.patch +++ /dev/null @@ -1,41 +0,0 @@ -From d967022bcd7061771f10e4d36d38ab8ffe5aef98 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= -Date: Thu, 15 Dec 2022 16:40:34 +0100 -Subject: iOS: Don't assume screens will not be connected before - QIOSIntegration - -When an external screen is connected to an iPad, and the application is -starting up on that screen, we will get a connection notification about -that screen as part of the initial bootstrap of UIApplicationMain, -before we call the user's main(). - -Since we initialize and add all available screen on QIOSIntegration -creation, we can just ignore the early connection notification. - -This avoids a crash, but the window will not show anything on the -external screen, which is a separate issue. - -Pick-to: 6.5 6.4 6.2 -Fixes: QTBUG-106701 -Change-Id: I9e0a9736bf602277316bd004e0d01c640feaf319 -Reviewed-by: Volker Hilsheimer -(cherry picked from commit dd49793bc3b4dd3808f0f24b717c442a5095db14) ---- - src/plugins/platforms/ios/qiosscreen.mm | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git x/qtbase/src/plugins/platforms/ios/qiosscreen.mm y/qtbase/src/plugins/platforms/ios/qiosscreen.mm -index f144c00fb0..3d660189af 100644 ---- x/qtbase/src/plugins/platforms/ios/qiosscreen.mm -+++ y/qtbase/src/plugins/platforms/ios/qiosscreen.mm -@@ -72,8 +72,8 @@ static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen) - - + (void)screenConnected:(NSNotification*)notification - { -- Q_ASSERT_X(QIOSIntegration::instance(), Q_FUNC_INFO, -- "Screen connected before QIOSIntegration creation"); -+ if (!QIOSIntegration::instance()) -+ return; // Will be added when QIOSIntegration is created - - QWindowSystemInterface::handleScreenAdded(new QIOSScreen([notification object])); - } diff --git a/libs/patches/qtbase-0006-xkb-fix-build-with-libxkbcommon-1.6.0-and-later.patch b/libs/patches/qtbase-0006-xkb-fix-build-with-libxkbcommon-1.6.0-and-later.patch new file mode 100644 index 000000000..eb4425f18 --- /dev/null +++ b/libs/patches/qtbase-0006-xkb-fix-build-with-libxkbcommon-1.6.0-and-later.patch @@ -0,0 +1,40 @@ +From 62ae219de264975c0f7e7546b702471d70af4b40 Mon Sep 17 00:00:00 2001 +From: Liang Qi +Date: Tue, 10 Oct 2023 14:08:48 +0200 +Subject: xkb: fix build with libxkbcommon 1.6.0 and later +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +A few XKB_KEY_dead_* defines got removed from 1.6.0. See also +https://github.com/xkbcommon/libxkbcommon/blob/6073565903488cb5b9a8d37fdc4a7c2f9d7ad04d/NEWS#L9-L14 +https://gitlab.freedesktop.org/xorg/proto/xorgproto/-/merge_requests/70/diffs?commit_id=cb44799b72f611eb4c9d7cc185bc3b09e070be08 + +Pick-to: 6.6 6.5 6.2 5.15 +Fixes: QTBUG-117950 +Change-Id: I55861868f2bb29c553d68365fa9b9b6ed01c9aea +Reviewed-by: Tor Arne Vestbø +(cherry picked from commit 8af35d27e8f02bbb99aef4ac495ed406e50e3cca) +--- + src/gui/platform/unix/qxkbcommon.cpp | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git x/qtbase/src/gui/platform/unix/qxkbcommon.cpp y/qtbase/src/gui/platform/unix/qxkbcommon.cpp +index fc014b38e2..0de9e98fc7 100644 +--- x/qtbase/src/gui/platform/unix/qxkbcommon.cpp ++++ y/qtbase/src/gui/platform/unix/qxkbcommon.cpp +@@ -239,10 +239,14 @@ static constexpr const auto KeyTbl = qMakeArray( + Xkb2Qt, + Xkb2Qt, + Xkb2Qt, ++/* The following four XKB_KEY_dead keys got removed in libxkbcommon 1.6.0 ++ The define check is kind of version check here. */ ++#ifdef XKB_KEY_dead_lowline + Xkb2Qt, + Xkb2Qt, + Xkb2Qt, + Xkb2Qt, ++#endif + + // Special keys from X.org - This include multimedia keys, + // wireless/bluetooth/uwb keys, special launcher keys, etc. diff --git a/libs/patches/qtbase-0007-Ignore-removed-changed-screens-if-no-QIOSIntegration.patch b/libs/patches/qtbase-0007-Ignore-removed-changed-screens-if-no-QIOSIntegration.patch deleted file mode 100644 index ff423344e..000000000 --- a/libs/patches/qtbase-0007-Ignore-removed-changed-screens-if-no-QIOSIntegration.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 6d6832fc530c9296d92dd924f6f6bca0effa6412 Mon Sep 17 00:00:00 2001 -From: Jan Moeller -Date: Thu, 6 Apr 2023 09:27:16 +0200 -Subject: Ignore removed/changed screens if no QIOSIntegration instance exists - -QIOSTracker registers itself as handlers for system notifications about -changes of the screen environment. If no QIOSIntegration instance -exists, newly detected screens are not added to the list of known -screens (see screenConnected()). This, in turn, will result in a crash -if a screen is disconnected and removed in screenDisconnected() as it -is not known to qtPlatformScreenFor() and the function returns a -nullptr. - -Consider the QIOSIntegration also whenever a screen is "changed". This -is more of a safety measure do avoid crashes for unknown screens. - -This situation occurs if an iOS device is used to mirror the display -via AirPlay and no actual QGuiApplication exists, e.g. Qt is only -embedded in a Framework. - -Pick-to: 6.5 6.2 -Fixes: QTBUG-106701 -Change-Id: Id778fc5afa7c284b0536ee02b1ba2c10321cc5b1 -Reviewed-by: Volker Hilsheimer -Reviewed-by: Lars Schmertmann -(cherry picked from commit ffdfafc4b47b8267395370199073c292da33dd42) ---- - src/plugins/platforms/ios/qiosscreen.mm | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git x/qtbase/src/plugins/platforms/ios/qiosscreen.mm y/qtbase/src/plugins/platforms/ios/qiosscreen.mm -index 3d660189af..e0216ce652 100644 ---- x/qtbase/src/plugins/platforms/ios/qiosscreen.mm -+++ y/qtbase/src/plugins/platforms/ios/qiosscreen.mm -@@ -80,6 +80,9 @@ static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen) - - + (void)screenDisconnected:(NSNotification*)notification - { -+ if (!QIOSIntegration::instance()) -+ return; -+ - QIOSScreen *screen = qtPlatformScreenFor([notification object]); - Q_ASSERT_X(screen, Q_FUNC_INFO, "Screen disconnected that we didn't know about"); - -@@ -88,6 +91,9 @@ static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen) - - + (void)screenModeChanged:(NSNotification*)notification - { -+ if (!QIOSIntegration::instance()) -+ return; -+ - QIOSScreen *screen = qtPlatformScreenFor([notification object]); - Q_ASSERT_X(screen, Q_FUNC_INFO, "Screen changed that we didn't know about"); - diff --git a/libs/patches/qtbase-0007-Use-SSL_CTX_set_dh_auto-if-DHparam-is-empty.patch b/libs/patches/qtbase-0007-Use-SSL_CTX_set_dh_auto-if-DHparam-is-empty.patch new file mode 100644 index 000000000..37aa8776a --- /dev/null +++ b/libs/patches/qtbase-0007-Use-SSL_CTX_set_dh_auto-if-DHparam-is-empty.patch @@ -0,0 +1,120 @@ +From 3d86ffeac0beaab4ab183cf1c184a09313425efc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Andr=C3=A9=20Klitzing?= +Date: Fri, 29 Sep 2023 08:21:21 +0200 +Subject: Use SSL_CTX_set_dh_auto if DHparam is empty +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +[ChangeLog][QtNetwork][QSslDiffieHellmanParameters] An empty +Diffie-Hellmann parameter enables auto selection of openssl +backend. + +Fixes: QTBUG-117666 +Change-Id: Ic2e0529d48542752ca801bcb4d609988e5ddff25 +Reviewed-by: Mårten Nordheim +(cherry picked from commit fd9c567156830a21da3cd9e127a998ae90a8e564) +--- + src/network/ssl/qsslconfiguration.cpp | 3 +++ + src/plugins/tls/openssl/qsslcontext_openssl.cpp | 4 +++- + .../tls/openssl/qsslsocket_openssl_symbols_p.h | 1 + + .../network/ssl/qsslsocket/tst_qsslsocket.cpp | 16 ++++++++++------ + 4 files changed, 17 insertions(+), 7 deletions(-) + +diff --git x/qtbase/src/network/ssl/qsslconfiguration.cpp y/qtbase/src/network/ssl/qsslconfiguration.cpp +index 04a9db8521..c8be1ca202 100644 +--- x/qtbase/src/network/ssl/qsslconfiguration.cpp ++++ y/qtbase/src/network/ssl/qsslconfiguration.cpp +@@ -942,6 +942,9 @@ QSslDiffieHellmanParameters QSslConfiguration::diffieHellmanParameters() const + If no Diffie-Hellman parameters have been set, the QSslConfiguration object + defaults to using the 2048-bit MODP group from RFC 3526. + ++ Since 6.7 you can provide an empty Diffie-Hellman parameter to use auto selection ++ (see SSL_CTX_set_dh_auto of openssl) if the tls backend supports it. ++ + \note The default parameters may change in future Qt versions. + Please check the documentation of the \e{exact Qt version} that you + are using in order to know what defaults that version uses. +diff --git x/qtbase/src/plugins/tls/openssl/qsslcontext_openssl.cpp y/qtbase/src/plugins/tls/openssl/qsslcontext_openssl.cpp +index ef0e63911a..75c192bd01 100644 +--- x/qtbase/src/plugins/tls/openssl/qsslcontext_openssl.cpp ++++ y/qtbase/src/plugins/tls/openssl/qsslcontext_openssl.cpp +@@ -697,7 +697,9 @@ QT_WARNING_POP + return; + } + +- if (!dhparams.isEmpty()) { ++ if (dhparams.isEmpty()) { ++ q_SSL_CTX_set_dh_auto(sslContext->ctx, 1); ++ } else { + #ifndef OPENSSL_NO_DEPRECATED_3_0 + const QByteArray ¶ms = dhparams.d->derData; + const char *ptr = params.constData(); +diff --git x/qtbase/src/plugins/tls/openssl/qsslsocket_openssl_symbols_p.h y/qtbase/src/plugins/tls/openssl/qsslsocket_openssl_symbols_p.h +index 1f0d739210..1531564226 100644 +--- x/qtbase/src/plugins/tls/openssl/qsslsocket_openssl_symbols_p.h ++++ y/qtbase/src/plugins/tls/openssl/qsslsocket_openssl_symbols_p.h +@@ -516,6 +516,7 @@ DH *q_PEM_read_bio_DHparams(BIO *a, DH **b, pem_password_cb *c, void *d); + + BIGNUM *q_BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret); + #define q_SSL_CTX_set_tmp_dh(ctx, dh) q_SSL_CTX_ctrl((ctx), SSL_CTRL_SET_TMP_DH, 0, (char *)dh) ++#define q_SSL_CTX_set_dh_auto(ctx, onoff) q_SSL_CTX_ctrl(ctx,SSL_CTRL_SET_DH_AUTO,onoff,NULL) + + #ifndef OPENSSL_NO_EC + // EC Diffie-Hellman support +diff --git x/qtbase/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp y/qtbase/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp +index cfcff44a4d..2f3ad0547a 100644 +--- x/qtbase/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp ++++ y/qtbase/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp +@@ -3501,9 +3501,10 @@ void tst_QSslSocket::dhServerCustomParamsNull() + if (setProxy) + return; + ++ const QSslCipher cipherWithDH("DHE-RSA-AES256-SHA256"); + SslServer server; +- server.ciphers = {QSslCipher("DHE-RSA-AES256-SHA"), QSslCipher("DHE-DSS-AES256-SHA")}; +- server.protocol = Test::TlsV1_0; ++ server.ciphers = {cipherWithDH}; ++ server.protocol = QSsl::TlsV1_2; + + QSslConfiguration cfg = server.config; + cfg.setDiffieHellmanParameters(QSslDiffieHellmanParameters()); +@@ -3516,7 +3517,6 @@ void tst_QSslSocket::dhServerCustomParamsNull() + + QSslSocket client; + QSslConfiguration config = client.sslConfiguration(); +- config.setProtocol(Test::TlsV1_0); + client.setSslConfiguration(config); + socket = &client; + connect(socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), &loop, SLOT(quit())); +@@ -3527,7 +3527,8 @@ void tst_QSslSocket::dhServerCustomParamsNull() + + loop.exec(); + +- QVERIFY(client.state() != QAbstractSocket::ConnectedState); ++ QCOMPARE(client.state(), QAbstractSocket::ConnectedState); ++ QCOMPARE(client.sessionCipher(), cipherWithDH); + } + + void tst_QSslSocket::dhServerCustomParams() +@@ -3542,7 +3543,9 @@ void tst_QSslSocket::dhServerCustomParams() + return; + + SslServer server; +- server.ciphers = {QSslCipher("DHE-RSA-AES256-SHA"), QSslCipher("DHE-DSS-AES256-SHA")}; ++ const QSslCipher cipherWithDH("DHE-RSA-AES256-SHA256"); ++ server.ciphers = {cipherWithDH}; ++ server.protocol = QSsl::TlsV1_2; + + QSslConfiguration cfg = server.config; + +@@ -3572,7 +3575,8 @@ void tst_QSslSocket::dhServerCustomParams() + + loop.exec(); + +- QVERIFY(client.state() == QAbstractSocket::ConnectedState); ++ QCOMPARE(client.state(), QAbstractSocket::ConnectedState); ++ QCOMPARE(client.sessionCipher(), cipherWithDH); + } + #endif // QT_CONFIG(openssl) + diff --git a/libs/patches/qtbase-0008-Fix-specific-overflow-in-qtextlayout.patch b/libs/patches/qtbase-0008-Fix-specific-overflow-in-qtextlayout.patch deleted file mode 100644 index ba82d2414..000000000 --- a/libs/patches/qtbase-0008-Fix-specific-overflow-in-qtextlayout.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 25b9264bd6e5a547db3692032dd5c49cb2db0bfd Mon Sep 17 00:00:00 2001 -From: Allan Sandfeld Jensen -Date: Fri, 5 May 2023 09:51:32 +0200 -Subject: Fix specific overflow in qtextlayout - -Adds qAddOverflow and qMulOverflow definitions to QFixed - -Fixes: QTBUG-113337 -Pick-to: 6.5 6.5.1 6.2 5.15 -Change-Id: I13579306defceaccdc0fbb1ec0e9b77c6f8d1af9 -Reviewed-by: Eirik Aavitsland -Reviewed-by: Thiago Macieira -(cherry picked from commit 7b7a01c266b507636eab51a36328c7c72d82d93c) ---- - src/gui/painting/qfixed_p.h | 17 +++++++++++++++++ - src/gui/text/qtextlayout.cpp | 9 ++++++--- - 2 files changed, 23 insertions(+), 3 deletions(-) - -diff --git x/qtbase/src/gui/painting/qfixed_p.h y/qtbase/src/gui/painting/qfixed_p.h -index f3718a097e..c0a13d057f 100644 ---- x/qtbase/src/gui/painting/qfixed_p.h -+++ y/qtbase/src/gui/painting/qfixed_p.h -@@ -18,6 +18,7 @@ - #include - #include "QtCore/qdebug.h" - #include "QtCore/qpoint.h" -+#include "QtCore/qnumeric.h" - #include "QtCore/qsize.h" - - QT_BEGIN_NAMESPACE -@@ -136,6 +137,22 @@ constexpr inline QFixed operator+(uint i, QFixed d) { return d+i; } - constexpr inline QFixed operator-(uint i, QFixed d) { return -(d-i); } - // constexpr inline QFixed operator*(qreal d, QFixed d2) { return d2*d; } - -+inline bool qAddOverflow(QFixed v1, QFixed v2, QFixed *r) -+{ -+ int val; -+ bool result = qAddOverflow(v1.value(), v2.value(), &val); -+ r->setValue(val); -+ return result; -+} -+ -+inline bool qMulOverflow(QFixed v1, QFixed v2, QFixed *r) -+{ -+ int val; -+ bool result = qMulOverflow(v1.value(), v2.value(), &val); -+ r->setValue(val); -+ return result; -+} -+ - #ifndef QT_NO_DEBUG_STREAM - inline QDebug &operator<<(QDebug &dbg, QFixed f) - { return dbg << f.toReal(); } -diff --git x/qtbase/src/gui/text/qtextlayout.cpp y/qtbase/src/gui/text/qtextlayout.cpp -index 365131f508..6a36b2458a 100644 ---- x/qtbase/src/gui/text/qtextlayout.cpp -+++ y/qtbase/src/gui/text/qtextlayout.cpp -@@ -2105,11 +2105,14 @@ found: - eng->maxWidth = qMax(eng->maxWidth, line.textWidth); - } else { - eng->minWidth = qMax(eng->minWidth, lbh.minw); -- eng->maxWidth += line.textWidth; -+ if (qAddOverflow(eng->maxWidth, line.textWidth, &eng->maxWidth)) -+ eng->maxWidth = QFIXED_MAX; - } - -- if (line.textWidth > 0 && item < eng->layoutData->items.size()) -- eng->maxWidth += lbh.spaceData.textWidth; -+ if (line.textWidth > 0 && item < eng->layoutData->items.size()) { -+ if (qAddOverflow(eng->maxWidth, lbh.spaceData.textWidth, &eng->maxWidth)) -+ eng->maxWidth = QFIXED_MAX; -+ } - - line.textWidth += trailingSpace; - if (lbh.spaceData.length) { diff --git a/libs/patches/qtbase-0009-Schannel-Reject-certificate-not-signed-by-a-configur.patch b/libs/patches/qtbase-0009-Schannel-Reject-certificate-not-signed-by-a-configur.patch deleted file mode 100644 index 9f1a1ec5b..000000000 --- a/libs/patches/qtbase-0009-Schannel-Reject-certificate-not-signed-by-a-configur.patch +++ /dev/null @@ -1,289 +0,0 @@ -From 550172c8a2f5e7195e2255bc50cffb2a64b8701c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= -Date: Wed, 10 May 2023 16:43:41 +0200 -Subject: Schannel: Reject certificate not signed by a configured CA - certificate - -Not entirely clear why, but when building the certificate chain for a -peer the system certificate store is searched for root certificates. -General expectation is that after calling -`sslConfiguration.setCaCertificates()` the system certificates will -not be taken into consideration. - -To work around this behavior, we do a manual check that the root of the -chain is part of the configured CA certificates. - -Pick-to: 6.5 6.2 5.15 -Change-Id: I03666a4d9b0eac39ae97e150b4743120611a11b3 -Reviewed-by: Edward Welbourne -Reviewed-by: Volker Hilsheimer -(cherry picked from commit ada2c573c1a25f8d96577734968fe317ddfa292a) ---- - src/plugins/tls/schannel/qtls_schannel.cpp | 21 ++++ - .../network/ssl/client-auth/CMakeLists.txt | 24 ++++ - .../network/ssl/client-auth/certs/.gitignore | 4 + - .../client-auth/certs/accepted-client.conf | 14 +++ - .../network/ssl/client-auth/certs/generate.sh | 33 +++++ - .../tst_manual_ssl_client_auth.cpp | 118 ++++++++++++++++++ - 6 files changed, 214 insertions(+) - create mode 100644 tests/manual/network/ssl/client-auth/CMakeLists.txt - create mode 100644 tests/manual/network/ssl/client-auth/certs/.gitignore - create mode 100644 tests/manual/network/ssl/client-auth/certs/accepted-client.conf - create mode 100755 tests/manual/network/ssl/client-auth/certs/generate.sh - create mode 100644 tests/manual/network/ssl/client-auth/tst_manual_ssl_client_auth.cpp - -diff --git x/qtbase/src/plugins/tls/schannel/qtls_schannel.cpp y/qtbase/src/plugins/tls/schannel/qtls_schannel.cpp -index 58e74357d8..c15eab8796 100644 ---- x/qtbase/src/plugins/tls/schannel/qtls_schannel.cpp -+++ y/qtbase/src/plugins/tls/schannel/qtls_schannel.cpp -@@ -2106,6 +2106,27 @@ bool TlsCryptographSchannel::verifyCertContext(CERT_CONTEXT *certContext) - verifyDepth = DWORD(q->peerVerifyDepth()); - - const auto &caCertificates = q->sslConfiguration().caCertificates(); -+ -+ if (!rootCertOnDemandLoadingAllowed() -+ && !(chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_PARTIAL_CHAIN) -+ && (q->peerVerifyMode() == QSslSocket::VerifyPeer -+ || (isClient && q->peerVerifyMode() == QSslSocket::AutoVerifyPeer))) { -+ // When verifying a peer Windows "helpfully" builds a chain that -+ // may include roots from the system store. But we don't want that if -+ // the user has set their own CA certificates. -+ // Since Windows claims this is not a partial chain the root is included -+ // and we have to check that it is one of our configured CAs. -+ CERT_CHAIN_ELEMENT *element = chain->rgpElement[chain->cElement - 1]; -+ QSslCertificate certificate = getCertificateFromChainElement(element); -+ if (!caCertificates.contains(certificate)) { -+ auto error = QSslError(QSslError::CertificateUntrusted, certificate); -+ sslErrors += error; -+ emit q->peerVerifyError(error); -+ if (q->state() != QAbstractSocket::ConnectedState) -+ return false; -+ } -+ } -+ - QList peerCertificateChain; - for (DWORD i = 0; i < verifyDepth; i++) { - CERT_CHAIN_ELEMENT *element = chain->rgpElement[i]; -diff --git x/qtbase/tests/manual/network/ssl/client-auth/CMakeLists.txt y/qtbase/tests/manual/network/ssl/client-auth/CMakeLists.txt -new file mode 100644 -index 0000000000..67ecc20bf4 ---- /dev/null -+++ y/qtbase/tests/manual/network/ssl/client-auth/CMakeLists.txt -@@ -0,0 +1,24 @@ -+# Copyright (C) 2023 The Qt Company Ltd. -+# SPDX-License-Identifier: BSD-3-Clause -+ -+qt_internal_add_manual_test(tst_manual_ssl_client_auth -+ SOURCES -+ tst_manual_ssl_client_auth.cpp -+ LIBRARIES -+ Qt::Network -+) -+ -+qt_internal_add_resource(tst_manual_ssl_client_auth "tst_manual_ssl_client_auth" -+ PREFIX -+ "/" -+ FILES -+ "certs/127.0.0.1.pem" -+ "certs/127.0.0.1-key.pem" -+ "certs/127.0.0.1-client.pem" -+ "certs/127.0.0.1-client-key.pem" -+ "certs/accepted-client.pem" -+ "certs/accepted-client-key.pem" -+ "certs/rootCA.pem" -+ BASE -+ "certs" -+) -diff --git x/qtbase/tests/manual/network/ssl/client-auth/certs/.gitignore y/qtbase/tests/manual/network/ssl/client-auth/certs/.gitignore -new file mode 100644 -index 0000000000..5866f7b609 ---- /dev/null -+++ y/qtbase/tests/manual/network/ssl/client-auth/certs/.gitignore -@@ -0,0 +1,4 @@ -+* -+!/.gitignore -+!/generate.sh -+!/accepted-client.conf -diff --git x/qtbase/tests/manual/network/ssl/client-auth/certs/accepted-client.conf y/qtbase/tests/manual/network/ssl/client-auth/certs/accepted-client.conf -new file mode 100644 -index 0000000000..a88b276efe ---- /dev/null -+++ y/qtbase/tests/manual/network/ssl/client-auth/certs/accepted-client.conf -@@ -0,0 +1,14 @@ -+[req] -+default_md = sha512 -+basicConstraints = CA:FALSE -+extendedKeyUsage = clientAuth -+[req] -+distinguished_name = client_distinguished_name -+prompt = no -+[client_distinguished_name] -+C = NO -+ST = Oslo -+L = Oslo -+O = The Qt Project -+OU = The Qt Project -+CN = Fake Qt Project Client Certificate -diff --git x/qtbase/tests/manual/network/ssl/client-auth/certs/generate.sh y/qtbase/tests/manual/network/ssl/client-auth/certs/generate.sh -new file mode 100755 -index 0000000000..5dbe3b3712 ---- /dev/null -+++ y/qtbase/tests/manual/network/ssl/client-auth/certs/generate.sh -@@ -0,0 +1,33 @@ -+#!/bin/bash -+# Copyright (C) 2023 The Qt Company Ltd. -+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -+ -+# Requires mkcert and openssl -+ -+warn () { echo "$@" >&2; } -+die () { warn "$@"; exit 1; } -+ -+ -+command -v mkcert 1>/dev/null 2>&1 || die "Failed to find mkcert" -+command -v openssl 1>/dev/null 2>&1 || die "Failed to find openssl" -+ -+SCRIPT=$(realpath "$0") -+SCRIPTPATH=$(dirname "$SCRIPT") -+ -+pushd "$SCRIPTPATH" || die "Unable to pushd to $SCRIPTPATH" -+mkcert 127.0.0.1 -+mkcert -client 127.0.0.1 -+warn "Remember to run mkcert -install if you haven't already" -+ -+# Generate CA -+openssl genrsa -out ca-key.pem 2048 -+openssl req -new -x509 -noenc -days 365 -key ca-key.pem -out rootCA.pem -+ -+# Generate accepted client certificate -+openssl genrsa -out accepted-client-key.pem 2048 -+openssl req -new -sha512 -nodes -key accepted-client-key.pem -out accepted-client.csr -config accepted-client.conf -+openssl x509 -req -sha512 -days 45 -in accepted-client.csr -CA rootCA.pem -CAkey ca-key.pem -CAcreateserial -out accepted-client.pem -+rm accepted-client.csr -+rm rootCA.srl -+ -+popd || die "Unable to popd" -diff --git x/qtbase/tests/manual/network/ssl/client-auth/tst_manual_ssl_client_auth.cpp y/qtbase/tests/manual/network/ssl/client-auth/tst_manual_ssl_client_auth.cpp -new file mode 100644 -index 0000000000..2307cbb191 ---- /dev/null -+++ y/qtbase/tests/manual/network/ssl/client-auth/tst_manual_ssl_client_auth.cpp -@@ -0,0 +1,118 @@ -+// Copyright (C) 2023 The Qt Company Ltd. -+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -+ -+#include -+ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+// Client and/or server presents a certificate signed by a system-trusted CA -+// but the other side presents a certificate signed by a different CA. -+constexpr bool TestServerPresentsIncorrectCa = false; -+constexpr bool TestClientPresentsIncorrectCa = true; -+ -+class ServerThread : public QThread -+{ -+ Q_OBJECT -+public: -+ void run() override -+ { -+ QSslServer server; -+ -+ QSslConfiguration config = server.sslConfiguration(); -+ QList certs = QSslCertificate::fromPath(QStringLiteral(":/rootCA.pem")); -+ config.setCaCertificates(certs); -+ config.setLocalCertificate(QSslCertificate::fromPath(QStringLiteral(":/127.0.0.1.pem")) -+ .first()); -+ QFile keyFile(QStringLiteral(":/127.0.0.1-key.pem")); -+ if (!keyFile.open(QIODevice::ReadOnly)) -+ qFatal("Failed to open key file"); -+ config.setPrivateKey(QSslKey(&keyFile, QSsl::Rsa)); -+ config.setPeerVerifyMode(QSslSocket::VerifyPeer); -+ server.setSslConfiguration(config); -+ -+ connect(&server, &QSslServer::pendingConnectionAvailable, [&server]() { -+ QSslSocket *socket = static_cast(server.nextPendingConnection()); -+ qDebug() << "[s] newConnection" << socket->peerAddress() << socket->peerPort(); -+ socket->disconnectFromHost(); -+ qApp->quit(); -+ }); -+ connect(&server, &QSslServer::startedEncryptionHandshake, [](QSslSocket *socket) { -+ qDebug() << "[s] new handshake" << socket->peerAddress() << socket->peerPort(); -+ }); -+ connect(&server, &QSslServer::errorOccurred, -+ [](QSslSocket *socket, QAbstractSocket::SocketError error) { -+ qDebug() << "[s] errorOccurred" << socket->peerAddress() << socket->peerPort() -+ << error << socket->errorString(); -+ }); -+ connect(&server, &QSslServer::peerVerifyError, -+ [](QSslSocket *socket, const QSslError &error) { -+ qDebug() << "[s] peerVerifyError" << socket->peerAddress() << socket->peerPort() -+ << error; -+ }); -+ server.listen(QHostAddress::LocalHost, 24242); -+ -+ exec(); -+ -+ server.close(); -+ } -+}; -+ -+int main(int argc, char **argv) -+{ -+ QCoreApplication app(argc, argv); -+ -+ using namespace Qt::StringLiterals; -+ -+ if (!QFileInfo(u":/rootCA.pem"_s).exists()) -+ qFatal("rootCA.pem not found. Did you run generate.sh in the certs directory?"); -+ -+ ServerThread serverThread; -+ serverThread.start(); -+ -+ QSslSocket socket; -+ QSslConfiguration config = socket.sslConfiguration(); -+ QString certificatePath; -+ QString keyFileName; -+ if constexpr (TestClientPresentsIncorrectCa) { // true: Present cert signed with incorrect CA: should fail -+ certificatePath = u":/127.0.0.1-client.pem"_s; -+ keyFileName = u":/127.0.0.1-client-key.pem"_s; -+ } else { // false: Use correct CA: should succeed -+ certificatePath = u":/accepted-client.pem"_s; -+ keyFileName = u":/accepted-client-key.pem"_s; -+ } -+ config.setLocalCertificate(QSslCertificate::fromPath(certificatePath).first()); -+ if (TestServerPresentsIncorrectCa) // true: Verify server using incorrect CA: should fail -+ config.setCaCertificates(QSslCertificate::fromPath(u":/rootCA.pem"_s)); -+ QFile keyFile(keyFileName); -+ if (!keyFile.open(QIODevice::ReadOnly)) -+ qFatal("Failed to open key file"); -+ config.setPrivateKey(QSslKey(&keyFile, QSsl::Rsa)); -+ socket.setSslConfiguration(config); -+ -+ QObject::connect(&socket, &QSslSocket::encrypted, []() { qDebug() << "[c] encrypted"; }); -+ QObject::connect(&socket, &QSslSocket::errorOccurred, -+ [&socket](QAbstractSocket::SocketError error) { -+ qDebug() << "[c] errorOccurred" << error << socket.errorString(); -+ qApp->quit(); -+ }); -+ QObject::connect(&socket, &QSslSocket::sslErrors, [](const QList &errors) { -+ qDebug() << "[c] sslErrors" << errors; -+ }); -+ QObject::connect(&socket, &QSslSocket::connected, []() { qDebug() << "[c] connected"; }); -+ -+ socket.connectToHostEncrypted(QStringLiteral("127.0.0.1"), 24242); -+ -+ const int res = app.exec(); -+ serverThread.quit(); -+ serverThread.wait(); -+ return res; -+} -+ -+#include "tst_manual_ssl_client_auth.moc" diff --git a/libs/patches/qtbase-0010-Ssl-Copy-the-on-demand-cert-loading-bool-from-defaul.patch b/libs/patches/qtbase-0010-Ssl-Copy-the-on-demand-cert-loading-bool-from-defaul.patch deleted file mode 100644 index 84724d31b..000000000 --- a/libs/patches/qtbase-0010-Ssl-Copy-the-on-demand-cert-loading-bool-from-defaul.patch +++ /dev/null @@ -1,110 +0,0 @@ -From d13e70c1d56a94d64eb68d2f3cba670e58a1a73f Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= -Date: Thu, 25 May 2023 14:40:29 +0200 -Subject: Ssl: Copy the on-demand cert loading bool from default config - -Otherwise individual sockets will still load system certificates when -a chain doesn't match against the configured CA certificates. -That's not intended behavior, since specifically setting the CA -certificates means you don't want the system certificates to be used. - -Follow-up to/amends ada2c573c1a25f8d96577734968fe317ddfa292a - -This is potentially a breaking change because now, if you ever add a -CA to the default config, it will disable loading system certificates -on demand for all sockets. And the only way to re-enable it is to -create a null-QSslConfiguration and set it as the new default. - -Pick-to: 6.5 6.2 5.15 -Change-Id: Ic3b2ab125c0cdd58ad654af1cb36173960ce2d1e -Reviewed-by: Timur Pocheptsov -(cherry picked from commit 57ba6260c0801055b7188fdaa1818b940590f5f1) ---- - src/network/ssl/qsslsocket.cpp | 5 ++++ - .../tst_manual_ssl_client_auth.cpp | 24 ++++++++++++++++--- - 2 files changed, 26 insertions(+), 3 deletions(-) - -diff --git x/qtbase/src/network/ssl/qsslsocket.cpp y/qtbase/src/network/ssl/qsslsocket.cpp -index cd76517c25..a94f2b79c3 100644 ---- x/qtbase/src/network/ssl/qsslsocket.cpp -+++ y/qtbase/src/network/ssl/qsslsocket.cpp -@@ -1973,6 +1973,10 @@ QSslSocketPrivate::QSslSocketPrivate() - , flushTriggered(false) - { - QSslConfigurationPrivate::deepCopyDefaultConfiguration(&configuration); -+ // If the global configuration doesn't allow root certificates to be loaded -+ // on demand then we have to disable it for this socket as well. -+ if (!configuration.allowRootCertOnDemandLoading) -+ allowRootCertOnDemandLoading = false; - - const auto *tlsBackend = tlsBackendInUse(); - if (!tlsBackend) { -@@ -2281,6 +2285,7 @@ void QSslConfigurationPrivate::deepCopyDefaultConfiguration(QSslConfigurationPri - ptr->sessionProtocol = global->sessionProtocol; - ptr->ciphers = global->ciphers; - ptr->caCertificates = global->caCertificates; -+ ptr->allowRootCertOnDemandLoading = global->allowRootCertOnDemandLoading; - ptr->protocol = global->protocol; - ptr->peerVerifyMode = global->peerVerifyMode; - ptr->peerVerifyDepth = global->peerVerifyDepth; -diff --git x/qtbase/tests/manual/network/ssl/client-auth/tst_manual_ssl_client_auth.cpp y/qtbase/tests/manual/network/ssl/client-auth/tst_manual_ssl_client_auth.cpp -index 2307cbb191..4d4aaca7e3 100644 ---- x/qtbase/tests/manual/network/ssl/client-auth/tst_manual_ssl_client_auth.cpp -+++ y/qtbase/tests/manual/network/ssl/client-auth/tst_manual_ssl_client_auth.cpp -@@ -16,6 +16,9 @@ - // but the other side presents a certificate signed by a different CA. - constexpr bool TestServerPresentsIncorrectCa = false; - constexpr bool TestClientPresentsIncorrectCa = true; -+// Decides whether or not to put the root CA into the global ssl configuration -+// or into the socket's specific ssl configuration. -+constexpr bool UseGlobalConfiguration = true; - - class ServerThread : public QThread - { -@@ -26,8 +29,10 @@ public: - QSslServer server; - - QSslConfiguration config = server.sslConfiguration(); -- QList certs = QSslCertificate::fromPath(QStringLiteral(":/rootCA.pem")); -- config.setCaCertificates(certs); -+ if (!UseGlobalConfiguration) { -+ QList certs = QSslCertificate::fromPath(QStringLiteral(":/rootCA.pem")); -+ config.setCaCertificates(certs); -+ } - config.setLocalCertificate(QSslCertificate::fromPath(QStringLiteral(":/127.0.0.1.pem")) - .first()); - QFile keyFile(QStringLiteral(":/127.0.0.1-key.pem")); -@@ -73,6 +78,12 @@ int main(int argc, char **argv) - if (!QFileInfo(u":/rootCA.pem"_s).exists()) - qFatal("rootCA.pem not found. Did you run generate.sh in the certs directory?"); - -+ if (UseGlobalConfiguration) { -+ QSslConfiguration config = QSslConfiguration::defaultConfiguration(); -+ config.setCaCertificates(QSslCertificate::fromPath(u":/rootCA.pem"_s)); -+ QSslConfiguration::setDefaultConfiguration(config); -+ } -+ - ServerThread serverThread; - serverThread.start(); - -@@ -88,12 +99,19 @@ int main(int argc, char **argv) - keyFileName = u":/accepted-client-key.pem"_s; - } - config.setLocalCertificate(QSslCertificate::fromPath(certificatePath).first()); -- if (TestServerPresentsIncorrectCa) // true: Verify server using incorrect CA: should fail -+ if (!UseGlobalConfiguration && TestServerPresentsIncorrectCa) { -+ // Verify server using incorrect CA: should fail - config.setCaCertificates(QSslCertificate::fromPath(u":/rootCA.pem"_s)); -+ } else if (UseGlobalConfiguration && !TestServerPresentsIncorrectCa) { -+ // Verify server using correct CA, we need to explicitly set the -+ // system CAs when the global config is overridden. -+ config.setCaCertificates(QSslConfiguration::systemCaCertificates()); -+ } - QFile keyFile(keyFileName); - if (!keyFile.open(QIODevice::ReadOnly)) - qFatal("Failed to open key file"); - config.setPrivateKey(QSslKey(&keyFile, QSsl::Rsa)); -+ - socket.setSslConfiguration(config); - - QObject::connect(&socket, &QSslSocket::encrypted, []() { qDebug() << "[c] encrypted"; }); diff --git a/libs/patches/qtbase-0011-Improve-Intent-source-app-detection.patch b/libs/patches/qtbase-0011-Improve-Intent-source-app-detection.patch deleted file mode 100644 index b6a242503..000000000 --- a/libs/patches/qtbase-0011-Improve-Intent-source-app-detection.patch +++ /dev/null @@ -1,51 +0,0 @@ -From f0f55fda3a29ca4f53fcd9d93476e5658cf6f9f4 Mon Sep 17 00:00:00 2001 -From: Jens Trillmann -Date: Wed, 5 Jul 2023 09:33:03 +0200 -Subject: Improve Intent source app detection - -Activity.getReferrer does not only return app IDs but also URLs if -Intent.EXTRA_REFERRER is set on the Intent. In the case of Chrome the referrer -is set to the website triggering the Intent. To improve the detection of the -calling app we check first if the browser specific -Browser.EXTRAS_APPLICATION_ID is set. If it is not set we fall back to -Intent.getReferrer. - -Pick-to: 6.6 -Change-Id: I33d1edd52de98486d9616713e531ea20ada87bcb ---- - .../qtproject/qt/android/bindings/QtActivity.java | 15 ++++++++++++--- - 1 file changed, 12 insertions(+), 3 deletions(-) - -diff --git x/qtbase/src/android/java/src/org/qtproject/qt/android/bindings/QtActivity.java y/qtbase/src/android/java/src/org/qtproject/qt/android/bindings/QtActivity.java -index 9cef8146fd..c22a4f4278 100644 ---- x/qtbase/src/android/java/src/org/qtproject/qt/android/bindings/QtActivity.java -+++ y/qtbase/src/android/java/src/org/qtproject/qt/android/bindings/QtActivity.java -@@ -16,6 +16,7 @@ import android.graphics.Canvas; - import android.net.Uri; - import android.os.Build; - import android.os.Bundle; -+import android.provider.Browser; - import android.util.AttributeSet; - import android.view.ActionMode; - import android.view.ActionMode.Callback; -@@ -237,9 +238,17 @@ public class QtActivity extends Activity - return; - - String sourceInformation = ""; -- Uri referrer = getReferrer(); -- if (referrer != null) -- sourceInformation = referrer.toString().replaceFirst("android-app://", ""); -+ String browserApplicationId = intent.getExtras() == null ? "" : intent.getExtras().getString(Browser.EXTRA_APPLICATION_ID); -+ if (browserApplicationId != null && !browserApplicationId.isEmpty()) -+ { -+ sourceInformation = browserApplicationId; -+ } -+ else -+ { -+ Uri referrer = getReferrer(); -+ if (referrer != null) -+ sourceInformation = referrer.toString().replaceFirst("android-app://", ""); -+ } - - intent.putExtra(EXTRA_SOURCE_INFO, sourceInformation); - } diff --git a/libs/patches/qtbase-0012-QXmlStreamReader-change-fastScanName-to-take-a-Value.patch b/libs/patches/qtbase-0012-QXmlStreamReader-change-fastScanName-to-take-a-Value.patch deleted file mode 100644 index 519134038..000000000 --- a/libs/patches/qtbase-0012-QXmlStreamReader-change-fastScanName-to-take-a-Value.patch +++ /dev/null @@ -1,105 +0,0 @@ -From da582e1a6ca1ed0dbdb63f95749bef5c44ef401d Mon Sep 17 00:00:00 2001 -From: Ahmad Samir -Date: Wed, 12 Apr 2023 13:10:26 +0200 -Subject: QXmlStreamReader: change fastScanName() to take a Value* - -For easier debugging, e.g. to print out value.len and value.prefix. - -Pick-to: 6.6 6.5 6.5.2 6.2 5.15 -Change-Id: Ib0eed38772f899502962f578775d34ea2744fdde -Reviewed-by: Marc Mutz -(cherry picked from commit 1a423ce4372d18a779f3c0d746d5283d9a425839) ---- - src/corelib/serialization/qxmlstream.cpp | 16 ++++++++-------- - src/corelib/serialization/qxmlstream.g | 3 ++- - src/corelib/serialization/qxmlstream_p.h | 2 +- - src/corelib/serialization/qxmlstreamparser_p.h | 3 ++- - 4 files changed, 13 insertions(+), 11 deletions(-) - -diff --git x/qtbase/src/corelib/serialization/qxmlstream.cpp y/qtbase/src/corelib/serialization/qxmlstream.cpp -index a6a2bc41af..f64db47867 100644 ---- x/qtbase/src/corelib/serialization/qxmlstream.cpp -+++ y/qtbase/src/corelib/serialization/qxmlstream.cpp -@@ -1243,7 +1243,7 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanContentCharList() - return n; - } - --inline qsizetype QXmlStreamReaderPrivate::fastScanName(qint16 *prefix) -+inline qsizetype QXmlStreamReaderPrivate::fastScanName(Value *val) - { - qsizetype n = 0; - uint c; -@@ -1280,16 +1280,16 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanName(qint16 *prefix) - case '+': - case '*': - putChar(c); -- if (prefix && *prefix == n+1) { -- *prefix = 0; -+ if (val && val->prefix == n + 1) { -+ val->prefix = 0; - putChar(':'); - --n; - } - return n; - case ':': -- if (prefix) { -- if (*prefix == 0) { -- *prefix = qint16(n + 2); -+ if (val) { -+ if (val->prefix == 0) { -+ val->prefix = qint16(n + 2); - } else { // only one colon allowed according to the namespace spec. - putChar(c); - return n; -@@ -1305,8 +1305,8 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanName(qint16 *prefix) - } - } - -- if (prefix) -- *prefix = 0; -+ if (val) -+ val->prefix = 0; - qsizetype pos = textBuffer.size() - n; - putString(textBuffer, pos); - textBuffer.resize(pos); -diff --git x/qtbase/src/corelib/serialization/qxmlstream.g y/qtbase/src/corelib/serialization/qxmlstream.g -index d06c371eb8..f3152bff37 100644 ---- x/qtbase/src/corelib/serialization/qxmlstream.g -+++ y/qtbase/src/corelib/serialization/qxmlstream.g -@@ -1419,7 +1419,8 @@ space_opt ::= space; - qname ::= LETTER; - /. - case $rule_number: { -- sym(1).len += fastScanName(&sym(1).prefix); -+ Value &val = sym(1); -+ val.len += fastScanName(&val); - if (atEnd) { - resume($rule_number); - return false; -diff --git x/qtbase/src/corelib/serialization/qxmlstream_p.h y/qtbase/src/corelib/serialization/qxmlstream_p.h -index 8e523f9c67..5da1f4aa5a 100644 ---- x/qtbase/src/corelib/serialization/qxmlstream_p.h -+++ y/qtbase/src/corelib/serialization/qxmlstream_p.h -@@ -471,7 +471,7 @@ public: - qsizetype fastScanLiteralContent(); - qsizetype fastScanSpace(); - qsizetype fastScanContentCharList(); -- qsizetype fastScanName(qint16 *prefix = nullptr); -+ qsizetype fastScanName(Value *val = nullptr); - inline qsizetype fastScanNMTOKEN(); - - -diff --git x/qtbase/src/corelib/serialization/qxmlstreamparser_p.h y/qtbase/src/corelib/serialization/qxmlstreamparser_p.h -index e3ae6faa44..59370a9310 100644 ---- x/qtbase/src/corelib/serialization/qxmlstreamparser_p.h -+++ y/qtbase/src/corelib/serialization/qxmlstreamparser_p.h -@@ -947,7 +947,8 @@ bool QXmlStreamReaderPrivate::parse() - break; - - case 262: { -- sym(1).len += fastScanName(&sym(1).prefix); -+ Value &val = sym(1); -+ val.len += fastScanName(&val); - if (atEnd) { - resume(262); - return false; diff --git a/libs/patches/qtbase-0013-QXmlStreamReader-make-fastScanName-indicate-parsing-.patch b/libs/patches/qtbase-0013-QXmlStreamReader-make-fastScanName-indicate-parsing-.patch deleted file mode 100644 index 49137e9fb..000000000 --- a/libs/patches/qtbase-0013-QXmlStreamReader-make-fastScanName-indicate-parsing-.patch +++ /dev/null @@ -1,270 +0,0 @@ -From ecf9967e196afa80bb3117d794387aba8b536f32 Mon Sep 17 00:00:00 2001 -From: Ahmad Samir -Date: Thu, 22 Jun 2023 15:56:07 +0300 -Subject: QXmlStreamReader: make fastScanName() indicate parsing status to - callers - -This fixes a crash while parsing an XML file with garbage data, the file -starts with '<' then garbage data: -- The loop in the parse() keeps iterating until it hits "case 262:", - which calls fastScanName() -- fastScanName() iterates over the text buffer scanning for the - attribute name (e.g. "xml:lang"), until it finds ':' -- Consider a Value val, fastScanName() is called on it, it would set - val.prefix to a number > val.len, then it would hit the 4096 condition - and return (returned 0, now it returns the equivalent of - std::null_opt), which means that val.len doesn't get modified, making - it smaller than val.prefix -- The code would try constructing an XmlStringRef with negative length, - which would hit an assert in one of QStringView's constructors - -Add an assert to the XmlStringRef constructor. - -Add unittest based on the file from the bug report. - -Later on I will replace FastScanNameResult with std::optional -(std::optional is C++17, which isn't required by Qt 5.15, and we want to -backport this fix). - -Credit to OSS-Fuzz. - -Fixes: QTBUG-109781 -Fixes: QTBUG-114829 -Pick-to: 6.6 6.5 6.2 5.15 -Change-Id: I455a5eeb47870c2ac9ffd0cbcdcd99c1ae2dd374 -Reviewed-by: Allan Sandfeld Jensen -(cherry picked from commit 6326bec46a618c72feba4a2bb994c4d475050aed) ---- - src/corelib/serialization/qxmlstream.cpp | 23 ++++++++--- - src/corelib/serialization/qxmlstream.g | 12 +++++- - src/corelib/serialization/qxmlstream_p.h | 14 ++++++- - .../serialization/qxmlstreamparser_p.h | 12 +++++- - .../qxmlstream/tst_qxmlstream.cpp | 39 +++++++++++++++++++ - 5 files changed, 88 insertions(+), 12 deletions(-) - -diff --git x/qtbase/src/corelib/serialization/qxmlstream.cpp y/qtbase/src/corelib/serialization/qxmlstream.cpp -index f64db47867..34568b7351 100644 ---- x/qtbase/src/corelib/serialization/qxmlstream.cpp -+++ y/qtbase/src/corelib/serialization/qxmlstream.cpp -@@ -1243,7 +1243,9 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanContentCharList() - return n; - } - --inline qsizetype QXmlStreamReaderPrivate::fastScanName(Value *val) -+// Fast scan an XML attribute name (e.g. "xml:lang"). -+inline QXmlStreamReaderPrivate::FastScanNameResult -+QXmlStreamReaderPrivate::fastScanName(Value *val) - { - qsizetype n = 0; - uint c; -@@ -1251,7 +1253,8 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanName(Value *val) - if (n >= 4096) { - // This is too long to be a sensible name, and - // can exhaust memory, or the range of decltype(*prefix) -- return 0; -+ raiseNamePrefixTooLongError(); -+ return {}; - } - switch (c) { - case '\n': -@@ -1285,18 +1288,18 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanName(Value *val) - putChar(':'); - --n; - } -- return n; -+ return FastScanNameResult(n); - case ':': - if (val) { - if (val->prefix == 0) { - val->prefix = qint16(n + 2); - } else { // only one colon allowed according to the namespace spec. - putChar(c); -- return n; -+ return FastScanNameResult(n); - } - } else { - putChar(c); -- return n; -+ return FastScanNameResult(n); - } - Q_FALLTHROUGH(); - default: -@@ -1310,7 +1313,7 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanName(Value *val) - qsizetype pos = textBuffer.size() - n; - putString(textBuffer, pos); - textBuffer.resize(pos); -- return 0; -+ return FastScanNameResult(0); - } - - enum NameChar { NameBeginning, NameNotBeginning, NotName }; -@@ -1791,6 +1794,14 @@ void QXmlStreamReaderPrivate::raiseWellFormedError(const QString &message) - raiseError(QXmlStreamReader::NotWellFormedError, message); - } - -+void QXmlStreamReaderPrivate::raiseNamePrefixTooLongError() -+{ -+ // TODO: add a ImplementationLimitsExceededError and use it instead -+ raiseError(QXmlStreamReader::NotWellFormedError, -+ QXmlStream::tr("Length of XML attribute name exceeds implemnetation limits (4KiB " -+ "characters).")); -+} -+ - void QXmlStreamReaderPrivate::parseError() - { - -diff --git x/qtbase/src/corelib/serialization/qxmlstream.g y/qtbase/src/corelib/serialization/qxmlstream.g -index f3152bff37..fc122e6681 100644 ---- x/qtbase/src/corelib/serialization/qxmlstream.g -+++ y/qtbase/src/corelib/serialization/qxmlstream.g -@@ -1420,7 +1420,11 @@ qname ::= LETTER; - /. - case $rule_number: { - Value &val = sym(1); -- val.len += fastScanName(&val); -+ if (auto res = fastScanName(&val)) -+ val.len += *res; -+ else -+ return false; -+ - if (atEnd) { - resume($rule_number); - return false; -@@ -1431,7 +1435,11 @@ qname ::= LETTER; - name ::= LETTER; - /. - case $rule_number: -- sym(1).len += fastScanName(); -+ if (auto res = fastScanName()) -+ sym(1).len += *res; -+ else -+ return false; -+ - if (atEnd) { - resume($rule_number); - return false; -diff --git x/qtbase/src/corelib/serialization/qxmlstream_p.h y/qtbase/src/corelib/serialization/qxmlstream_p.h -index 5da1f4aa5a..7925e59014 100644 ---- x/qtbase/src/corelib/serialization/qxmlstream_p.h -+++ y/qtbase/src/corelib/serialization/qxmlstream_p.h -@@ -38,7 +38,7 @@ public: - - constexpr XmlStringRef() = default; - constexpr inline XmlStringRef(const QString *string, qsizetype pos, qsizetype length) -- : m_string(string), m_pos(pos), m_size(length) -+ : m_string(string), m_pos(pos), m_size((Q_ASSERT(length >= 0), length)) - { - } - XmlStringRef(const QString *string) -@@ -471,7 +471,16 @@ public: - qsizetype fastScanLiteralContent(); - qsizetype fastScanSpace(); - qsizetype fastScanContentCharList(); -- qsizetype fastScanName(Value *val = nullptr); -+ -+ struct FastScanNameResult { -+ FastScanNameResult() : ok(false) {} -+ explicit FastScanNameResult(qsizetype len) : addToLen(len), ok(true) { } -+ operator bool() { return ok; } -+ qsizetype operator*() { Q_ASSERT(ok); return addToLen; } -+ qsizetype addToLen; -+ bool ok; -+ }; -+ FastScanNameResult fastScanName(Value *val = nullptr); - inline qsizetype fastScanNMTOKEN(); - - -@@ -480,6 +489,7 @@ public: - - void raiseError(QXmlStreamReader::Error error, const QString& message = QString()); - void raiseWellFormedError(const QString &message); -+ void raiseNamePrefixTooLongError(); - - QXmlStreamEntityResolver *entityResolver; - -diff --git x/qtbase/src/corelib/serialization/qxmlstreamparser_p.h y/qtbase/src/corelib/serialization/qxmlstreamparser_p.h -index 59370a9310..afd83381b3 100644 ---- x/qtbase/src/corelib/serialization/qxmlstreamparser_p.h -+++ y/qtbase/src/corelib/serialization/qxmlstreamparser_p.h -@@ -948,7 +948,11 @@ bool QXmlStreamReaderPrivate::parse() - - case 262: { - Value &val = sym(1); -- val.len += fastScanName(&val); -+ if (auto res = fastScanName(&val)) -+ val.len += *res; -+ else -+ return false; -+ - if (atEnd) { - resume(262); - return false; -@@ -956,7 +960,11 @@ bool QXmlStreamReaderPrivate::parse() - } break; - - case 263: -- sym(1).len += fastScanName(); -+ if (auto res = fastScanName()) -+ sym(1).len += *res; -+ else -+ return false; -+ - if (atEnd) { - resume(263); - return false; -diff --git x/qtbase/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp y/qtbase/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp -index 2799e7a999..7eb0aac5cc 100644 ---- x/qtbase/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp -+++ y/qtbase/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp -@@ -581,6 +581,8 @@ private slots: - void readBack() const; - void roundTrip() const; - void roundTrip_data() const; -+ void test_fastScanName_data() const; -+ void test_fastScanName() const; - - void entityExpansionLimit() const; - -@@ -1753,5 +1755,42 @@ void tst_QXmlStream::roundTrip() const - QCOMPARE(out, in); - } - -+void tst_QXmlStream::test_fastScanName_data() const -+{ -+ QTest::addColumn("data"); -+ QTest::addColumn("errorType"); -+ -+ // 4096 is the limit in QXmlStreamReaderPrivate::fastScanName() -+ -+ QByteArray arr = " -Date: Fri, 2 Sep 2022 16:52:04 +0200 -Subject: QXmlStreamReader: use qOffsetStringArray for storing token types -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Change-Id: I9e58c17d97c44e1b13899d30396f65b452d8600f -Reviewed-by: Mårten Nordheim -(cherry picked from commit d674f3f5454fb39de9405484a8c01fb928523f67) ---- - src/corelib/serialization/qxmlstream.cpp | 67 ++++++------------------ - 1 file changed, 16 insertions(+), 51 deletions(-) - -diff --git x/qtbase/src/corelib/serialization/qxmlstream.cpp y/qtbase/src/corelib/serialization/qxmlstream.cpp -index 34568b7351..535f98a215 100644 ---- x/qtbase/src/corelib/serialization/qxmlstream.cpp -+++ y/qtbase/src/corelib/serialization/qxmlstream.cpp -@@ -15,6 +15,8 @@ - #include - #include - -+#include -+ - #include - #include "qxmlstream_p.h" - #include "qxmlstreamparser_p.h" -@@ -640,55 +642,19 @@ void QXmlStreamReader::skipCurrentElement() - } - } - --/* -- * Use the following Perl script to generate the error string index list: --===== PERL SCRIPT ==== --print "static const char QXmlStreamReader_tokenTypeString_string[] =\n"; --$counter = 0; --$i = 0; --while () { -- chomp; -- print " \"$_\\0\"\n"; -- $sizes[$i++] = $counter; -- $counter += length 1 + $_; --} --print " \"\\0\";\n\nstatic const short QXmlStreamReader_tokenTypeString_indices[] = {\n "; --for ($j = 0; $j < $i; ++$j) { -- printf "$sizes[$j], "; --} --print "0\n};\n"; --===== PERL SCRIPT ==== -- -- * The input data is as follows (copied from qxmlstream.h): --NoToken --Invalid --StartDocument --EndDocument --StartElement --EndElement --Characters --Comment --DTD --EntityReference --ProcessingInstruction --*/ --static const char QXmlStreamReader_tokenTypeString_string[] = -- "NoToken\0" -- "Invalid\0" -- "StartDocument\0" -- "EndDocument\0" -- "StartElement\0" -- "EndElement\0" -- "Characters\0" -- "Comment\0" -- "DTD\0" -- "EntityReference\0" -- "ProcessingInstruction\0"; -- --static const short QXmlStreamReader_tokenTypeString_indices[] = { -- 0, 8, 16, 30, 42, 55, 66, 77, 85, 89, 105, 0 --}; -- -+static constexpr auto QXmlStreamReader_tokenTypeString = qOffsetStringArray( -+ "NoToken", -+ "Invalid", -+ "StartDocument", -+ "EndDocument", -+ "StartElement", -+ "EndElement", -+ "Characters", -+ "Comment", -+ "DTD", -+ "EntityReference", -+ "ProcessingInstruction" -+); - - /*! - \property QXmlStreamReader::namespaceProcessing -@@ -721,8 +687,7 @@ bool QXmlStreamReader::namespaceProcessing() const - QString QXmlStreamReader::tokenString() const - { - Q_D(const QXmlStreamReader); -- return QLatin1StringView(QXmlStreamReader_tokenTypeString_string + -- QXmlStreamReader_tokenTypeString_indices[d->type]); -+ return QLatin1StringView(QXmlStreamReader_tokenTypeString.at(d->type)); - } - - #endif // QT_NO_XMLSTREAMREADER diff --git a/libs/patches/qtbase-0015-QXmlStreamReader-Raise-error-on-unexpected-tokens.patch b/libs/patches/qtbase-0015-QXmlStreamReader-Raise-error-on-unexpected-tokens.patch deleted file mode 100644 index 0fe420cef..000000000 --- a/libs/patches/qtbase-0015-QXmlStreamReader-Raise-error-on-unexpected-tokens.patch +++ /dev/null @@ -1,394 +0,0 @@ -From 625af289b43f8e665b83eb4c86aeef91140e59ab Mon Sep 17 00:00:00 2001 -From: Axel Spoerl -Date: Fri, 30 Jun 2023 12:43:59 +0200 -Subject: QXmlStreamReader: Raise error on unexpected tokens - -QXmlStreamReader accepted multiple DOCTYPE elements, containing DTD -fragments in the XML prolog, and in the XML body. -Well-formed but invalid XML files - with multiple DTD fragments in -prolog and body, combined with recursive entity expansions - have -caused infinite loops in QXmlStreamReader. - -This patch implements a token check in QXmlStreamReader. -A stream is allowed to start with an XML prolog. StartDocument -and DOCTYPE elements are only allowed in this prolog, which -may also contain ProcessingInstruction and Comment elements. -As soon as anything else is seen, the prolog ends. -After that, the prolog-specific elements are treated as unexpected. -Furthermore, the prolog can contain at most one DOCTYPE element. - -Update the documentation to reflect the new behavior. -Add an autotest that checks the new error cases are correctly detected, -and no error is raised for legitimate input. - -The original OSS-Fuzz files (see bug reports) are not included in this -patch for file size reasons. They have been tested manually. Each of -them has more than one DOCTYPE element, causing infinite loops in -recursive entity expansions. The newly implemented functionality -detects those invalid DTD fragments. By raising an error, it aborts -stream reading before an infinite loop occurs. - -Thanks to OSS-Fuzz for finding this. - -Fixes: QTBUG-92113 -Fixes: QTBUG-95188 -Change-Id: I0a082b9188b2eee50b396c4d5b1c9e1fd237bbdd -Reviewed-by: Volker Hilsheimer -(cherry picked from commit c4301be7d5f94852e1b17f2c2989d5ca807855d4) -(cherry picked from commit c216c3d9859a20b3aeec985512e89316423fc3a8) ---- - src/corelib/serialization/qxmlstream.cpp | 140 +++++++++++++++++- - src/corelib/serialization/qxmlstream_p.h | 11 ++ - .../qxmlstream/tokenError/dtdInBody.xml | 20 +++ - .../qxmlstream/tokenError/multipleDtd.xml | 20 +++ - .../qxmlstream/tokenError/wellFormed.xml | 15 ++ - .../qxmlstream/tst_qxmlstream.cpp | 39 +++++ - 6 files changed, 237 insertions(+), 8 deletions(-) - create mode 100644 tests/auto/corelib/serialization/qxmlstream/tokenError/dtdInBody.xml - create mode 100644 tests/auto/corelib/serialization/qxmlstream/tokenError/multipleDtd.xml - create mode 100644 tests/auto/corelib/serialization/qxmlstream/tokenError/wellFormed.xml - -diff --git x/qtbase/src/corelib/serialization/qxmlstream.cpp y/qtbase/src/corelib/serialization/qxmlstream.cpp -index 535f98a215..050556f463 100644 ---- x/qtbase/src/corelib/serialization/qxmlstream.cpp -+++ y/qtbase/src/corelib/serialization/qxmlstream.cpp -@@ -128,7 +128,7 @@ void reversed(const Range &&) = delete; - addData() or by waiting for it to arrive on the device(). - - \value UnexpectedElementError The parser encountered an element -- that was different to those it expected. -+ or token that was different to those it expected. - - */ - -@@ -263,13 +263,34 @@ QXmlStreamEntityResolver *QXmlStreamReader::entityResolver() const - - QXmlStreamReader is a well-formed XML 1.0 parser that does \e not - include external parsed entities. As long as no error occurs, the -- application code can thus be assured that the data provided by the -- stream reader satisfies the W3C's criteria for well-formed XML. For -- example, you can be certain that all tags are indeed nested and -- closed properly, that references to internal entities have been -- replaced with the correct replacement text, and that attributes have -- been normalized or added according to the internal subset of the -- DTD. -+ application code can thus be assured, that -+ \list -+ \li the data provided by the stream reader satisfies the W3C's -+ criteria for well-formed XML, -+ \li tokens are provided in a valid order. -+ \endlist -+ -+ Unless QXmlStreamReader raises an error, it guarantees the following: -+ \list -+ \li All tags are nested and closed properly. -+ \li References to internal entities have been replaced with the -+ correct replacement text. -+ \li Attributes have been normalized or added according to the -+ internal subset of the \l DTD. -+ \li Tokens of type \l StartDocument happen before all others, -+ aside from comments and processing instructions. -+ \li At most one DOCTYPE element (a token of type \l DTD) is present. -+ \li If present, the DOCTYPE appears before all other elements, -+ aside from StartDocument, comments and processing instructions. -+ \endlist -+ -+ In particular, once any token of type \l StartElement, \l EndElement, -+ \l Characters, \l EntityReference or \l EndDocument is seen, no -+ tokens of type StartDocument or DTD will be seen. If one is present in -+ the input stream, out of order, an error is raised. -+ -+ \note The token types \l Comment and \l ProcessingInstruction may appear -+ anywhere in the stream. - - If an error occurs while parsing, atEnd() and hasError() return - true, and error() returns the error that occurred. The functions -@@ -572,6 +593,7 @@ QXmlStreamReader::TokenType QXmlStreamReader::readNext() - d->token = -1; - return readNext(); - } -+ d->checkToken(); - return d->type; - } - -@@ -656,6 +678,11 @@ static constexpr auto QXmlStreamReader_tokenTypeString = qOffsetStringArray( - "ProcessingInstruction" - ); - -+static constexpr auto QXmlStreamReader_XmlContextString = qOffsetStringArray( -+ "Prolog", -+ "Body" -+); -+ - /*! - \property QXmlStreamReader::namespaceProcessing - \brief the namespace-processing flag of the stream reader. -@@ -690,6 +717,15 @@ QString QXmlStreamReader::tokenString() const - return QLatin1StringView(QXmlStreamReader_tokenTypeString.at(d->type)); - } - -+/*! -+ \internal -+ \return \param loc (Prolog/Body) as a string. -+ */ -+static constexpr QLatin1StringView contextString(QXmlStreamReaderPrivate::XmlContext ctxt) -+{ -+ return QLatin1StringView(QXmlStreamReader_XmlContextString.at(static_cast(ctxt))); -+} -+ - #endif // QT_NO_XMLSTREAMREADER - - QXmlStreamPrivateTagStack::QXmlStreamPrivateTagStack() -@@ -776,6 +812,8 @@ void QXmlStreamReaderPrivate::init() - - type = QXmlStreamReader::NoToken; - error = QXmlStreamReader::NoError; -+ currentContext = XmlContext::Prolog; -+ foundDTD = false; - } - - /* -@@ -3692,6 +3730,92 @@ void QXmlStreamWriter::writeCurrentToken(const QXmlStreamReader &reader) - } - } - -+static constexpr bool isTokenAllowedInContext(QXmlStreamReader::TokenType type, -+ QXmlStreamReaderPrivate::XmlContext loc) -+{ -+ switch (type) { -+ case QXmlStreamReader::StartDocument: -+ case QXmlStreamReader::DTD: -+ return loc == QXmlStreamReaderPrivate::XmlContext::Prolog; -+ -+ case QXmlStreamReader::StartElement: -+ case QXmlStreamReader::EndElement: -+ case QXmlStreamReader::Characters: -+ case QXmlStreamReader::EntityReference: -+ case QXmlStreamReader::EndDocument: -+ return loc == QXmlStreamReaderPrivate::XmlContext::Body; -+ -+ case QXmlStreamReader::Comment: -+ case QXmlStreamReader::ProcessingInstruction: -+ return true; -+ -+ case QXmlStreamReader::NoToken: -+ case QXmlStreamReader::Invalid: -+ return false; -+ } -+ -+ return false; -+} -+ -+/*! -+ \internal -+ \brief QXmlStreamReader::isValidToken -+ \return \c true if \param type is a valid token type. -+ \return \c false if \param type is an unexpected token, -+ which indicates a non-well-formed or invalid XML stream. -+ */ -+bool QXmlStreamReaderPrivate::isValidToken(QXmlStreamReader::TokenType type) -+{ -+ // Don't change currentContext, if Invalid or NoToken occur in the prolog -+ if (type == QXmlStreamReader::Invalid || type == QXmlStreamReader::NoToken) -+ return false; -+ -+ // If a token type gets rejected in the body, there is no recovery -+ const bool result = isTokenAllowedInContext(type, currentContext); -+ if (result || currentContext == XmlContext::Body) -+ return result; -+ -+ // First non-Prolog token observed => switch context to body and check again. -+ currentContext = XmlContext::Body; -+ return isTokenAllowedInContext(type, currentContext); -+} -+ -+/*! -+ \internal -+ Checks token type and raises an error, if it is invalid -+ in the current context (prolog/body). -+ */ -+void QXmlStreamReaderPrivate::checkToken() -+{ -+ Q_Q(QXmlStreamReader); -+ -+ // The token type must be consumed, to keep track if the body has been reached. -+ const XmlContext context = currentContext; -+ const bool ok = isValidToken(type); -+ -+ // Do nothing if an error has been raised already (going along with an unexpected token) -+ if (error != QXmlStreamReader::Error::NoError) -+ return; -+ -+ if (!ok) { -+ raiseError(QXmlStreamReader::UnexpectedElementError, -+ QObject::tr("Unexpected token type %1 in %2.") -+ .arg(q->tokenString(), contextString(context))); -+ return; -+ } -+ -+ if (type != QXmlStreamReader::DTD) -+ return; -+ -+ // Raise error on multiple DTD tokens -+ if (foundDTD) { -+ raiseError(QXmlStreamReader::UnexpectedElementError, -+ QObject::tr("Found second DTD token in %1.").arg(contextString(context))); -+ } else { -+ foundDTD = true; -+ } -+} -+ - /*! - \fn bool QXmlStreamAttributes::hasAttribute(const QString &qualifiedName) const - \since 4.5 -diff --git x/qtbase/src/corelib/serialization/qxmlstream_p.h y/qtbase/src/corelib/serialization/qxmlstream_p.h -index 7925e59014..c24c74d5c9 100644 ---- x/qtbase/src/corelib/serialization/qxmlstream_p.h -+++ y/qtbase/src/corelib/serialization/qxmlstream_p.h -@@ -270,6 +270,17 @@ public: - QStringDecoder decoder; - bool atEnd; - -+ enum class XmlContext -+ { -+ Prolog, -+ Body, -+ }; -+ -+ XmlContext currentContext = XmlContext::Prolog; -+ bool foundDTD = false; -+ bool isValidToken(QXmlStreamReader::TokenType type); -+ void checkToken(); -+ - /*! - \sa setType() - */ -diff --git x/qtbase/tests/auto/corelib/serialization/qxmlstream/tokenError/dtdInBody.xml y/qtbase/tests/auto/corelib/serialization/qxmlstream/tokenError/dtdInBody.xml -new file mode 100644 -index 0000000000..1c3ca4e271 ---- /dev/null -+++ y/qtbase/tests/auto/corelib/serialization/qxmlstream/tokenError/dtdInBody.xml -@@ -0,0 +1,20 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+]> -+ -+ -+ tst_QXmlStream -+ -+ -+ -+ -+ ]> -+ -diff --git x/qtbase/tests/auto/corelib/serialization/qxmlstream/tokenError/multipleDtd.xml y/qtbase/tests/auto/corelib/serialization/qxmlstream/tokenError/multipleDtd.xml -new file mode 100644 -index 0000000000..cd398c0f9f ---- /dev/null -+++ y/qtbase/tests/auto/corelib/serialization/qxmlstream/tokenError/multipleDtd.xml -@@ -0,0 +1,20 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+]> -+ -+ -+ -+]> -+ -+ -+ tst_QXmlStream -+ -+ -diff --git x/qtbase/tests/auto/corelib/serialization/qxmlstream/tokenError/wellFormed.xml y/qtbase/tests/auto/corelib/serialization/qxmlstream/tokenError/wellFormed.xml -new file mode 100644 -index 0000000000..1b61a3f062 ---- /dev/null -+++ y/qtbase/tests/auto/corelib/serialization/qxmlstream/tokenError/wellFormed.xml -@@ -0,0 +1,15 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+]> -+ -+ -+ tst_QXmlStream -+ -+ -diff --git x/qtbase/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp y/qtbase/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp -index 7eb0aac5cc..ee962d3870 100644 ---- x/qtbase/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp -+++ y/qtbase/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp -@@ -586,6 +586,9 @@ private slots: - - void entityExpansionLimit() const; - -+ void tokenErrorHandling_data() const; -+ void tokenErrorHandling() const; -+ - private: - static QByteArray readFile(const QString &filename); - -@@ -1792,5 +1795,41 @@ void tst_QXmlStream::test_fastScanName() const - QCOMPARE(reader.error(), errorType); - } - -+void tst_QXmlStream::tokenErrorHandling_data() const -+{ -+ QTest::addColumn("fileName"); -+ QTest::addColumn("expectedError"); -+ QTest::addColumn("errorKeyWord"); -+ -+ constexpr auto invalid = QXmlStreamReader::Error::UnexpectedElementError; -+ constexpr auto valid = QXmlStreamReader::Error::NoError; -+ QTest::newRow("DtdInBody") << "dtdInBody.xml" << invalid << "DTD"; -+ QTest::newRow("multipleDTD") << "multipleDtd.xml" << invalid << "second DTD"; -+ QTest::newRow("wellFormed") << "wellFormed.xml" << valid << ""; -+} -+ -+void tst_QXmlStream::tokenErrorHandling() const -+{ -+ QFETCH(const QString, fileName); -+ QFETCH(const QXmlStreamReader::Error, expectedError); -+ QFETCH(const QString, errorKeyWord); -+ -+ const QDir dir(QFINDTESTDATA("tokenError")); -+ QFile file(dir.absoluteFilePath(fileName)); -+ -+ // Cross-compiling: File will be on host only -+ if (!file.exists()) -+ QSKIP("Testfile not found."); -+ -+ file.open(QIODevice::ReadOnly); -+ QXmlStreamReader reader(&file); -+ while (!reader.atEnd()) -+ reader.readNext(); -+ -+ QCOMPARE(reader.error(), expectedError); -+ if (expectedError != QXmlStreamReader::Error::NoError) -+ QVERIFY(reader.errorString().contains(errorKeyWord)); -+} -+ - #include "tst_qxmlstream.moc" - // vim: et:ts=4:sw=4:sts=4 diff --git a/libs/patches/qtbase-0016-QOffsetStringArray-fix-ambiguous-qOffsetStringArray-.patch b/libs/patches/qtbase-0016-QOffsetStringArray-fix-ambiguous-qOffsetStringArray-.patch deleted file mode 100644 index 2d4a641f8..000000000 --- a/libs/patches/qtbase-0016-QOffsetStringArray-fix-ambiguous-qOffsetStringArray-.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 335a97b94afdfe8c0156ac3d3a0dab8ec784f00d Mon Sep 17 00:00:00 2001 -From: Marc Mutz -Date: Sun, 4 Sep 2022 12:31:10 +0200 -Subject: QOffsetStringArray: fix ambiguous qOffsetStringArray overloads - -There are two qOffsetStringArray overloads: one in QT_NAMESPACE, the -other in QT_PREPEND_NAMESPACE(QtPrivate). In TUs which use using -namespace QtPrivate, a call to qOffsetStringArray() may become -ambiguous. - -Fix by renaming the qOffsetStringArray() to makeOffsetStringArray(). - -Pick-to: 6.4 6.3 6.2 -Change-Id: I242a969f363e230d6a8dfb048601a0c024724f6a -Reviewed-by: Thiago Macieira -(cherry picked from commit 21c5eeba673694f865badfd137ee9fc474177ae0) ---- - src/corelib/tools/qoffsetstringarray_p.h | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git x/qtbase/src/corelib/tools/qoffsetstringarray_p.h y/qtbase/src/corelib/tools/qoffsetstringarray_p.h -index 3afb5cb731..68afef57d5 100644 ---- x/qtbase/src/corelib/tools/qoffsetstringarray_p.h -+++ y/qtbase/src/corelib/tools/qoffsetstringarray_p.h -@@ -116,7 +116,7 @@ template struct StaticMapEntry - }; - - template --constexpr auto qOffsetStringArray(StringExtractor extractString, const T &... entries) -+constexpr auto makeOffsetStringArray(StringExtractor extractString, const T &... entries) - { - constexpr size_t Count = sizeof...(T); - constexpr qsizetype StringLength = (sizeof(extractString(T{})) + ...); -@@ -140,7 +140,7 @@ template - constexpr auto qOffsetStringArray(const char (&...strings)[Nx]) noexcept - { - auto extractString = [](const auto &s) -> decltype(auto) { return s; }; -- return QtPrivate::qOffsetStringArray(extractString, QtPrivate::StaticString(strings)...); -+ return QtPrivate::makeOffsetStringArray(extractString, QtPrivate::StaticString(strings)...); - } - - QT_WARNING_POP diff --git a/libs/patches/qtbase-0017-QOffsetStringArray-fix-size_t-qsizetype-mismatch.patch b/libs/patches/qtbase-0017-QOffsetStringArray-fix-size_t-qsizetype-mismatch.patch deleted file mode 100644 index ac59adfde..000000000 --- a/libs/patches/qtbase-0017-QOffsetStringArray-fix-size_t-qsizetype-mismatch.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 5d3108ae7f32a0489833d358aced86cb27184d49 Mon Sep 17 00:00:00 2001 -From: Marc Mutz -Date: Mon, 5 Sep 2022 08:59:23 +0200 -Subject: QOffsetStringArray: fix size_t/qsizetype mismatch - -The sizeof operator returns, and both minifyValue and makeStaticString -accept, size_t. Don't funnel it through a qsizetype variable, then, -but maintain it as a size_t all the way. - -Pick-to: 6.4 6.3 6.2 -Task-number: QTBUG-103533 -Change-Id: I05c6a6c5da3d02daabbf1d25a15531c6f44a80ce -Reviewed-by: Sona Kurazyan -(cherry picked from commit 8932eee9a652d8a325410b147955c9939278f9ed) ---- - src/corelib/tools/qoffsetstringarray_p.h | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git x/qtbase/src/corelib/tools/qoffsetstringarray_p.h y/qtbase/src/corelib/tools/qoffsetstringarray_p.h -index 68afef57d5..fbe714aca6 100644 ---- x/qtbase/src/corelib/tools/qoffsetstringarray_p.h -+++ y/qtbase/src/corelib/tools/qoffsetstringarray_p.h -@@ -119,7 +119,7 @@ template - constexpr auto makeOffsetStringArray(StringExtractor extractString, const T &... entries) - { - constexpr size_t Count = sizeof...(T); -- constexpr qsizetype StringLength = (sizeof(extractString(T{})) + ...); -+ constexpr size_t StringLength = (sizeof(extractString(T{})) + ...); - using MinifiedOffsetType = decltype(QtPrivate::minifyValue()); - - size_t offset = 0; diff --git a/libs/patches/qtconnectivity-0001-Reset-status-of-isSessionScheduled-when-starting-a-i.patch b/libs/patches/qtconnectivity-0001-Reset-status-of-isSessionScheduled-when-starting-a-i.patch new file mode 100644 index 000000000..f408630b0 --- /dev/null +++ b/libs/patches/qtconnectivity-0001-Reset-status-of-isSessionScheduled-when-starting-a-i.patch @@ -0,0 +1,28 @@ +From 7436b286698ff67a1834fc1e8e6d4a8446ab7a5d Mon Sep 17 00:00:00 2001 +From: Jens Trillmann +Date: Thu, 5 Oct 2023 14:56:43 +0200 +Subject: Reset status of isSessionScheduled when starting a iOS NFC session + +If a user cancels the NFC popup and then starts a new session immediately +after then isSessionScheduled gets set to true. This value has to be reset +when the session gets started as isSessionScheduled==true leads to the +QTimer always triggering a new NFC session. + +Pick-to: 6.6 6.5 +Change-Id: I53d71d5c9b419d334ac6a229cff3e32aa81e9230 +--- + src/nfc/qnearfieldmanager_ios.mm | 1 + + 1 file changed, 1 insertion(+) + +diff --git x/qtconnectivity/src/nfc/qnearfieldmanager_ios.mm y/qtconnectivity/src/nfc/qnearfieldmanager_ios.mm +index 2709e2c7..259c3c17 100644 +--- x/qtconnectivity/src/nfc/qnearfieldmanager_ios.mm ++++ y/qtconnectivity/src/nfc/qnearfieldmanager_ios.mm +@@ -143,6 +143,7 @@ bool QNearFieldManagerPrivateImpl::scheduleSession(QNearFieldTarget::AccessMetho + isSessionScheduled = true; + return true; + } ++ isSessionScheduled = false; + + if (accessMethod == QNearFieldTarget::TagTypeSpecificAccess) { + startSession(); diff --git a/libs/patches/qtconnectivity-0001-iOS-NFC-Always-ensure-timeout-after-session-invalida.patch b/libs/patches/qtconnectivity-0001-iOS-NFC-Always-ensure-timeout-after-session-invalida.patch deleted file mode 100644 index c65a9aa3d..000000000 --- a/libs/patches/qtconnectivity-0001-iOS-NFC-Always-ensure-timeout-after-session-invalida.patch +++ /dev/null @@ -1,137 +0,0 @@ -From 37c9240e9d6d295118fcabedbaaf403310af8dba Mon Sep 17 00:00:00 2001 -From: Julian Greilich -Date: Thu, 26 Jan 2023 19:19:21 +0100 -Subject: iOS NFC: Always ensure timeout after session invalidation - -iOS needs some time after invalidating a session before a new session -can be started. Otherwise the NFC dialog of iOS will not show up. - -For restarting a session inside the iOS NearfieldManager, this was -already solved with a timeout of 2 seconds. - -This commit fixes the case, that a user of the Nearfieldmanager -restarts a session manually too fast. - -Change-Id: Ic91ad225a9cab13ba92523f33a19f44af68575a0 -Reviewed-by: Timur Pocheptsov -(cherry picked from commit 849ba86ba9a073a266219b6a39786e20f4f3ed7b) -(cherry picked from commit 5052cd14c28bbf0ff93c465a4e33bf1dbd48c7dd) ---- - src/nfc/qnearfieldmanager_ios.mm | 44 +++++++++++++++++++++---------- - src/nfc/qnearfieldmanager_ios_p.h | 5 +++- - 2 files changed, 34 insertions(+), 15 deletions(-) - -diff --git x/qtconnectivity/src/nfc/qnearfieldmanager_ios.mm y/qtconnectivity/src/nfc/qnearfieldmanager_ios.mm -index 6fd71451..a0651626 100644 ---- x/qtconnectivity/src/nfc/qnearfieldmanager_ios.mm -+++ y/qtconnectivity/src/nfc/qnearfieldmanager_ios.mm -@@ -25,6 +25,10 @@ QNearFieldManagerPrivateImpl::QNearFieldManagerPrivateImpl() - connect(this, &QNearFieldManagerPrivateImpl::didInvalidateWithError, - this, &QNearFieldManagerPrivateImpl::onDidInvalidateWithError, - Qt::QueuedConnection); -+ -+ sessionTimer.setInterval(2000); -+ sessionTimer.setSingleShot(true); -+ connect(&sessionTimer, &QTimer::timeout, this, &QNearFieldManagerPrivateImpl::onSessionTimer); - } - - QNearFieldManagerPrivateImpl::~QNearFieldManagerPrivateImpl() -@@ -62,7 +66,7 @@ bool QNearFieldManagerPrivateImpl::startTargetDetection(QNearFieldTarget::Access - if (@available(iOS 13, *)) - if (NFCTagReaderSession.readingAvailable) { - detectionRunning = true; -- startSession(); -+ scheduleSession(); - return true; - } - return false; -@@ -71,16 +75,28 @@ bool QNearFieldManagerPrivateImpl::startTargetDetection(QNearFieldTarget::Access - - void QNearFieldManagerPrivateImpl::stopTargetDetection(const QString &errorMessage) - { -- if (detectionRunning) { -- stopSession(errorMessage); -- detectionRunning = false; -- Q_EMIT targetDetectionStopped(); -- } -+ if (!detectionRunning) -+ return; -+ -+ isSessionScheduled = false; -+ stopSession(errorMessage); -+ detectionRunning = false; -+ Q_EMIT targetDetectionStopped(); - } - -+void QNearFieldManagerPrivateImpl::scheduleSession() -+{ -+ if (sessionTimer.isActive()) { -+ isSessionScheduled = true; -+ return; -+ } -+ -+ startSession(); -+} - - void QNearFieldManagerPrivateImpl::startSession() - { -+ isSessionScheduled = false; - if (detectionRunning) - if (@available(iOS 13, *)) - [delegate startSession]; -@@ -132,17 +148,11 @@ void QNearFieldManagerPrivateImpl::onTargetLost(QNearFieldTargetPrivateImpl *tar - void QNearFieldManagerPrivateImpl::onDidInvalidateWithError(bool doRestart) - { - clearTargets(); -+ sessionTimer.start(); - - if (detectionRunning && doRestart) - { -- if (!isRestarting) { -- isRestarting = true; -- using namespace std::chrono_literals; -- QTimer::singleShot(2s, this, [this](){ -- isRestarting = false; -- startSession(); -- }); -- } -+ scheduleSession(); - return; - } - -@@ -150,4 +160,10 @@ void QNearFieldManagerPrivateImpl::onDidInvalidateWithError(bool doRestart) - Q_EMIT targetDetectionStopped(); - } - -+void QNearFieldManagerPrivateImpl::onSessionTimer() -+{ -+ if (isSessionScheduled) -+ scheduleSession(); -+} -+ - QT_END_NAMESPACE -diff --git x/qtconnectivity/src/nfc/qnearfieldmanager_ios_p.h y/qtconnectivity/src/nfc/qnearfieldmanager_ios_p.h -index 6aa1574e..b3668ff6 100644 ---- x/qtconnectivity/src/nfc/qnearfieldmanager_ios_p.h -+++ y/qtconnectivity/src/nfc/qnearfieldmanager_ios_p.h -@@ -54,9 +54,11 @@ Q_SIGNALS: - private: - QT_MANGLE_NAMESPACE(QIosTagReaderDelegate) *delegate API_AVAILABLE(ios(13.0)) = nullptr; - bool detectionRunning = false; -- bool isRestarting = false; -+ bool isSessionScheduled = false; -+ QTimer sessionTimer; - QList detectedTargets; - -+ void scheduleSession(); - void startSession(); - void stopSession(const QString &error); - void clearTargets(); -@@ -65,6 +67,7 @@ private Q_SLOTS: - void onTagDiscovered(void *target); - void onTargetLost(QNearFieldTargetPrivateImpl *target); - void onDidInvalidateWithError(bool doRestart); -+ void onSessionTimer(); - }; - - diff --git a/libs/patches/qtdeclarative-0001-QtQml-Re-add-pthread_attr_init-to-stackPropertiesGen.patch b/libs/patches/qtdeclarative-0001-QtQml-Re-add-pthread_attr_init-to-stackPropertiesGen.patch new file mode 100644 index 000000000..974b7a1f9 --- /dev/null +++ b/libs/patches/qtdeclarative-0001-QtQml-Re-add-pthread_attr_init-to-stackPropertiesGen.patch @@ -0,0 +1,31 @@ +From 5bb3161566b3540e6909e585675eab225dcb994a Mon Sep 17 00:00:00 2001 +From: Ulf Hermann +Date: Tue, 26 Sep 2023 12:36:09 +0200 +Subject: QtQml: Re-add pthread_attr_init() to stackPropertiesGeneric() + +Before calling pthread_attr_get_np(), as opposed to +pthread_getattr_np(), we do need to call pthread_attr_init(). Both the +FreeBSD and the NetBSD manpages tell us to do so. + +Amends commit 9f4aeeabb982cfc4306c9d350dbb68f64914fb32. + +Pick-to: 6.6 6.5 +Fixes: QTBUG-117513 +Change-Id: Ic851ba2ffcf13d268b3a53d926cb92f7bed7a3d9 +(cherry picked from commit 94e0bb6de357cb5e1fca32a4107363d95346222e) +--- + src/qml/memory/qv4stacklimits.cpp | 1 + + 1 file changed, 1 insertion(+) + +diff --git x/qtdeclarative/src/qml/memory/qv4stacklimits.cpp y/qtdeclarative/src/qml/memory/qv4stacklimits.cpp +index 68ef7a366a..429520e527 100644 +--- x/qtdeclarative/src/qml/memory/qv4stacklimits.cpp ++++ y/qtdeclarative/src/qml/memory/qv4stacklimits.cpp +@@ -235,6 +235,7 @@ StackProperties stackPropertiesGeneric(qsizetype stackSize = 0) + pthread_t thread = pthread_self(); + pthread_attr_t sattr; + # if defined(PTHREAD_NP_H) || defined(_PTHREAD_NP_H_) || defined(Q_OS_NETBSD) ++ pthread_attr_init(&sattr); + pthread_attr_get_np(thread, &sattr); + # else + pthread_getattr_np(thread, &sattr); diff --git a/libs/patches/qtdeclarative-0001-qmlformat-fix-omitting-some-comments-while-reformatt.patch b/libs/patches/qtdeclarative-0001-qmlformat-fix-omitting-some-comments-while-reformatt.patch deleted file mode 100644 index b0a3983d0..000000000 --- a/libs/patches/qtdeclarative-0001-qmlformat-fix-omitting-some-comments-while-reformatt.patch +++ /dev/null @@ -1,99 +0,0 @@ -From 7785342c8d6fe223977958c59cd4102ed417d442 Mon Sep 17 00:00:00 2001 -From: Semih Yavuz -Date: Wed, 18 Jan 2023 15:36:23 +0100 -Subject: qmlformat: fix omitting some comments while reformatting - -We rewrite comments associated to a node on the preVisit call -(if they were marked as preComment), or postVisit( if comments were -marked as postComments) of the reformatter. If the comment -associated with a patternProperty kind of node, neither of these -functions are called. Add missing call to previsit/postVist -in the pattern property node visit. - -Pick-to: 6.4 6.5 -Fixes: QTBUG-109074 -Change-Id: If57968b3f5dbd83aa23dc2cd2bca3608ee841d49 -Reviewed-by: Sami Shalayel -Reviewed-by: Ulf Hermann -(cherry picked from commit 444d4f1f3f27a81996d9cbcc0642040b68728260) ---- - src/qmldom/qqmldomreformatter.cpp | 2 ++ - .../qmlformat/data/dontRemoveComments.formatted.qml | 13 +++++++++++++ - .../auto/qml/qmlformat/data/dontRemoveComments.qml | 13 +++++++++++++ - tests/auto/qml/qmlformat/tst_qmlformat.cpp | 3 +++ - 4 files changed, 31 insertions(+) - create mode 100644 tests/auto/qml/qmlformat/data/dontRemoveComments.formatted.qml - create mode 100644 tests/auto/qml/qmlformat/data/dontRemoveComments.qml - -diff --git x/qtdeclarative/src/qmldom/qqmldomreformatter.cpp y/qtdeclarative/src/qmldom/qqmldomreformatter.cpp -index bb76f8f772..3dfacfc84e 100644 ---- x/qtdeclarative/src/qmldom/qqmldomreformatter.cpp -+++ y/qtdeclarative/src/qmldom/qqmldomreformatter.cpp -@@ -301,6 +301,7 @@ protected: - for (PatternPropertyList *it = ast; it; it = it->next) { - PatternProperty *assignment = AST::cast(it->property); - if (assignment) { -+ preVisit(assignment); - bool isStringLike = AST::cast(assignment->name) - || cast(assignment->name); - if (isStringLike) -@@ -316,6 +317,7 @@ protected: - accept(assignment->initializer); - if (it->next) - newLine(); -+ postVisit(assignment); - continue; - } - PatternPropertyList *getterSetter = AST::cast(it->next); -diff --git x/qtdeclarative/tests/auto/qml/qmlformat/data/dontRemoveComments.formatted.qml y/qtdeclarative/tests/auto/qml/qmlformat/data/dontRemoveComments.formatted.qml -new file mode 100644 -index 0000000000..0c7a2829c9 ---- /dev/null -+++ y/qtdeclarative/tests/auto/qml/qmlformat/data/dontRemoveComments.formatted.qml -@@ -0,0 +1,13 @@ -+Item { -+ property var test: [{ -+ // Testing -+ "foo": "bar" -+ }] -+ -+ onTestChanged: { -+ fooBar(test, { -+ // Testing -+ "foo": "bar" -+ }); -+ } -+} -diff --git x/qtdeclarative/tests/auto/qml/qmlformat/data/dontRemoveComments.qml y/qtdeclarative/tests/auto/qml/qmlformat/data/dontRemoveComments.qml -new file mode 100644 -index 0000000000..1797834879 ---- /dev/null -+++ y/qtdeclarative/tests/auto/qml/qmlformat/data/dontRemoveComments.qml -@@ -0,0 +1,13 @@ -+Item { -+ property var test: [{ -+// Testing -+ "foo": "bar" -+ }] -+ -+ onTestChanged: { -+ fooBar(test, { -+ // Testing -+ "foo": "bar" -+ }); -+ } -+} -diff --git x/qtdeclarative/tests/auto/qml/qmlformat/tst_qmlformat.cpp y/qtdeclarative/tests/auto/qml/qmlformat/tst_qmlformat.cpp -index 9d7beb23a7..7755095acd 100644 ---- x/qtdeclarative/tests/auto/qml/qmlformat/tst_qmlformat.cpp -+++ y/qtdeclarative/tests/auto/qml/qmlformat/tst_qmlformat.cpp -@@ -276,6 +276,9 @@ void TestQmlformat::testFormat_data() - QTest::newRow("forWithLet") - << "forWithLet.qml" - << "forWithLet.formatted.qml" << QStringList {} << RunOption::OnCopy; -+ QTest::newRow("dontRemoveComments") -+ << "dontRemoveComments.qml" -+ << "dontRemoveComments.formatted.qml" << QStringList {} << RunOption::OnCopy; - } - - void TestQmlformat::testFormat() diff --git a/libs/patches/qtdeclarative-0002-QQuickItem-item-stays-pressed-after-DoubleClicks.patch b/libs/patches/qtdeclarative-0002-QQuickItem-item-stays-pressed-after-DoubleClicks.patch deleted file mode 100644 index fb4f59031..000000000 --- a/libs/patches/qtdeclarative-0002-QQuickItem-item-stays-pressed-after-DoubleClicks.patch +++ /dev/null @@ -1,119 +0,0 @@ -From 26cac8dada39c83cfcebd8b0bbcacf92f1ce9e9f Mon Sep 17 00:00:00 2001 -From: Sami Shalayel -Date: Mon, 17 Apr 2023 18:03:09 +0200 -Subject: QQuickItem: item stays pressed after DoubleClicks - -Amends 72651a50f83aa72998822312c7b5c6235d28978f. -This commit decided to ignore double clicks in the virtual -QQuickItem::mouseDoubleClickEvent(). -If a subclass inheriting from QQuickItem wants to not ignore -a double click, it should override mouseDoubleClickEvent() -and handle the double click event accordingly. - -Fix QQuickMouseArea::mouseDoubleClickEvent(QMouseEvent *event) to *not* -call the base implementation in QQuickItem after handling a double -click, because QQuickItem sets that double-click MouseEvent back to -the ignored state. - -This was leading to weird behavior on platforms with touch -screens like Android or IOS where buttons "got stuck" after -a double click. - -Fixes: QTBUG-112434 -Fixes: QTBUG-109393 -Pick-to: 6.5 -Change-Id: I774189fbcb356b07336f35f053e05a12c34ce602 -Reviewed-by: Qt CI Bot -Reviewed-by: Ivan Solovev -(cherry picked from commit d7fac6923a6d4e4ac7dc22458256366968acbdb3) ---- - src/quick/items/qquickmousearea.cpp | 5 ++++ - .../data/doubleClickInMouseArea.qml | 23 +++++++++++++++++++ - .../tst_mousearea_interop.cpp | 21 +++++++++++++++++ - 3 files changed, 49 insertions(+) - create mode 100644 tests/auto/quick/pointerhandlers/mousearea_interop/data/doubleClickInMouseArea.qml - -diff --git x/qtdeclarative/src/quick/items/qquickmousearea.cpp y/qtdeclarative/src/quick/items/qquickmousearea.cpp -index 75b67d01e3..db338c7ae5 100644 ---- x/qtdeclarative/src/quick/items/qquickmousearea.cpp -+++ y/qtdeclarative/src/quick/items/qquickmousearea.cpp -@@ -795,6 +795,11 @@ void QQuickMouseArea::mouseDoubleClickEvent(QMouseEvent *event) - d->propagate(&me, QQuickMouseAreaPrivate::DoubleClick); - if (d->pressed) - d->doubleClick = d->isDoubleClickConnected() || me.isAccepted(); -+ -+ // do not call the base implementation if the event is accepted -+ // because it will revert the event back to ignored state -+ if (me.isAccepted()) -+ return; - } - QQuickItem::mouseDoubleClickEvent(event); - } -diff --git x/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/data/doubleClickInMouseArea.qml y/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/data/doubleClickInMouseArea.qml -new file mode 100644 -index 0000000000..e43a2f3160 ---- /dev/null -+++ y/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/data/doubleClickInMouseArea.qml -@@ -0,0 +1,23 @@ -+import QtQuick -+import QtQuick.Controls -+import QtQuick.Window -+ -+Rectangle { -+ width: 200; height: 200 -+ color: mouseArea.pressed ? "red" : "orange" -+ -+ Popup { -+ visible: true -+ closePolicy: Popup.NoAutoClose -+ width: 100 -+ height: 100 -+ contentItem: MouseArea { -+ id: mouseArea -+ -+ anchors.fill: parent -+ } -+ background: Rectangle { -+ color: "green" -+ } -+ } -+} -diff --git x/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp y/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp -index c4059a1fbd..bc0dfbc736 100644 ---- x/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp -+++ y/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp -@@ -31,6 +31,7 @@ private slots: - void dragHandlerInSiblingStealingGrabFromMouseAreaViaTouch(); - void hoverHandlerDoesntHoverOnPress(); - void doubleClickInMouseAreaWithDragHandlerInGrandparent(); -+ void doubleClickInMouseArea(); - - private: - void createView(QScopedPointer &window, const char *fileName); -@@ -203,6 +204,26 @@ void tst_MouseAreaInterop::doubleClickInMouseAreaWithDragHandlerInGrandparent() - QCOMPARE(dragActiveSpy.count(), 0); - } - -+void tst_MouseAreaInterop::doubleClickInMouseArea() -+{ -+ QQuickView window; -+ QVERIFY(QQuickTest::showView(window, testFileUrl("doubleClickInMouseArea.qml"))); -+ -+ auto *ma = window.rootObject()->findChild(); -+ QVERIFY(ma); -+ QSignalSpy doubleClickSpy(ma, &QQuickMouseArea::doubleClicked); -+ QSignalSpy longPressSpy(ma, &QQuickMouseArea::pressAndHold); -+ QPoint p = ma->mapToScene(ma->boundingRect().center()).toPoint(); -+ -+ // check with normal double click -+ QTest::mouseDClick(&window, Qt::LeftButton, Qt::NoModifier, p); -+ QCOMPARE(doubleClickSpy.count(), 1); -+ -+ // wait enough time for a wrong long press to happen -+ QTest::qWait(QGuiApplication::styleHints()->mousePressAndHoldInterval() + 10); -+ QCOMPARE(longPressSpy.count(), 0); -+} -+ - QTEST_MAIN(tst_MouseAreaInterop) - - #include "tst_mousearea_interop.moc" diff --git a/libs/patches/qtdeclarative-0002-Remove-warnings-about-polish-and-binding-loops.patch b/libs/patches/qtdeclarative-0002-Remove-warnings-about-polish-and-binding-loops.patch new file mode 100644 index 000000000..d8d8a6d88 --- /dev/null +++ b/libs/patches/qtdeclarative-0002-Remove-warnings-about-polish-and-binding-loops.patch @@ -0,0 +1,57 @@ +From acf5a10d344f9e711a3c7c6d7d6629077c1ce1fc Mon Sep 17 00:00:00 2001 +From: Julian Greilich +Date: Fri, 27 Oct 2023 11:34:09 +0200 +Subject: Remove warnings about polish and binding loops + +Since the polish and binding loops are known problems we don't want +them to spam into the log files. + +Change-Id: I72b73ed0652c3b2b6fff1def264c812add4377f6 +--- + src/qml/qml/qqmlabstractbinding.cpp | 2 +- + src/qml/qml/qqmlpropertybinding.cpp | 1 - + src/quicklayouts/qquicklayout.cpp | 3 --- + 3 files changed, 1 insertion(+), 5 deletions(-) + +diff --git x/qtdeclarative/src/qml/qml/qqmlabstractbinding.cpp y/qtdeclarative/src/qml/qml/qqmlabstractbinding.cpp +index 78d1d68f55..87348a97e5 100644 +--- x/qtdeclarative/src/qml/qml/qqmlabstractbinding.cpp ++++ y/qtdeclarative/src/qml/qml/qqmlabstractbinding.cpp +@@ -157,7 +157,7 @@ void QQmlAbstractBinding::removeFromObject() + + void QQmlAbstractBinding::printBindingLoopError(const QQmlProperty &prop) + { +- qmlWarning(prop.object()) << QString(QLatin1String("Binding loop detected for property \"%1\"")).arg(prop.name()); ++ Q_UNUSED(prop) + } + + void QQmlAbstractBinding::getPropertyData( +diff --git x/qtdeclarative/src/qml/qml/qqmlpropertybinding.cpp y/qtdeclarative/src/qml/qml/qqmlpropertybinding.cpp +index 5f646b62de..7219cb0a0e 100644 +--- x/qtdeclarative/src/qml/qml/qqmlpropertybinding.cpp ++++ y/qtdeclarative/src/qml/qml/qqmlpropertybinding.cpp +@@ -148,7 +148,6 @@ void QQmlPropertyBindingJS::expressionChanged() + else + err.setDescription(QString::fromLatin1("Binding loop detected")); + err.setObject(asBinding()->target()); +- qmlWarning(this->scopeObject(), err); + return; + } + m_error.setTag(InEvaluationLoop); +diff --git x/qtdeclarative/src/quicklayouts/qquicklayout.cpp y/qtdeclarative/src/quicklayouts/qquicklayout.cpp +index fc2bcc130c..193f014f58 100644 +--- x/qtdeclarative/src/quicklayouts/qquicklayout.cpp ++++ y/qtdeclarative/src/quicklayouts/qquicklayout.cpp +@@ -840,9 +840,6 @@ void QQuickLayout::invalidate(QQuickItem * /*childItem*/) + // (e.g QQuickText changes implicitHeight when its width gets changed) + qCDebug(lcQuickLayouts) << "QQuickLayout::invalidate(), polish()"; + polish(); +- } else { +- qmlWarning(this).nospace() << "Layout polish loop detected for " << this +- << ". Aborting after two iterations."; + } + } + } +-- +2.42.0 + diff --git a/libs/patches/qtdeclarative-0003-MouseArea-don-t-ignore-double-click-events.patch b/libs/patches/qtdeclarative-0003-MouseArea-don-t-ignore-double-click-events.patch deleted file mode 100644 index c35b19150..000000000 --- a/libs/patches/qtdeclarative-0003-MouseArea-don-t-ignore-double-click-events.patch +++ /dev/null @@ -1,283 +0,0 @@ -From 65fd0af4aece6028e82e018c50583aed706dd525 Mon Sep 17 00:00:00 2001 -From: Shawn Rutledge -Date: Mon, 12 Jun 2023 22:53:23 +0200 -Subject: MouseArea: don't ignore double-click events - -In 72651a50f83aa72998822312c7b5c6235d28978f -QQuickItem::mouseDoubleClickEvent() started to ignore double-clicks by -default, which is consistent with the fact that it ignores the other -pointer event types. But now we have to worry about subclasses that -override mouseDoubleClickEvent() and call the base class implementation. - -d7fac6923a6d4e4ac7dc22458256366968acbdb3 tried to fix it but neglected -the case when the MouseArea does not have an onDoubleClicked signal -handling script. Since the QQuickMouseEvent object that we emit to QML -won't be accepted if isDoubleClickConnected() is false, and since the -code before 72651a50f83aa72998822312c7b5c6235d28978f was leaving the -event accepted regardless of whether QQuickMouseEvent was accepted, we -should not need to check it now either. Perhaps we should care about the -case when onDoubleClicked sets accepted to false, but so far that -doesn't seem very useful either: if you accept the press, a parent -MouseArea will not see either the press or the double-click; if you -ignore the press, you won't see the double-click, and a parent MouseArea -will see both by default. tst_QQuickMouseArea::clickThrough() tests -accepted = false in onDoubleClicked but not onPressed, and only with -mouse, not touch. - -Added tst_QQuickMouseArea::doubleTap(); also moved the autotest from -d7fac6923a6d4e4ac7dc22458256366968acbdb3 which has nothing to do with -pointer handlers. - -Fixes: QTBUG-112434 -Fixes: QTBUG-109393 -Pick-to: 6.6 6.5 6.5.2 -Change-Id: I426827c20cdb2373e77744987dffba59cd941edc -Reviewed-by: Fabian Kosmale -Reviewed-by: Doris Verria -(cherry picked from commit 35b5511189f0f9dbb8cfd8b3ec97cca2c65b3e2e) ---- - src/quick/items/qquickmousearea.cpp | 6 +- - .../data/doubleClickInMouseArea.qml | 23 -------- - .../tst_mousearea_interop.cpp | 21 ------- - .../qquickmousearea/tst_qquickmousearea.cpp | 56 +++++++++++++++++++ - .../data/doubleClickInMouseArea.qml | 23 ++++++++ - .../qquickpopup/tst_qquickpopup.cpp | 22 ++++++++ - 6 files changed, 103 insertions(+), 48 deletions(-) - delete mode 100644 tests/auto/quick/pointerhandlers/mousearea_interop/data/doubleClickInMouseArea.qml - create mode 100644 tests/auto/quickcontrols2/qquickpopup/data/doubleClickInMouseArea.qml - -diff --git x/qtdeclarative/src/quick/items/qquickmousearea.cpp y/qtdeclarative/src/quick/items/qquickmousearea.cpp -index db338c7ae5..de283672cc 100644 ---- x/qtdeclarative/src/quick/items/qquickmousearea.cpp -+++ y/qtdeclarative/src/quick/items/qquickmousearea.cpp -@@ -796,10 +796,8 @@ void QQuickMouseArea::mouseDoubleClickEvent(QMouseEvent *event) - if (d->pressed) - d->doubleClick = d->isDoubleClickConnected() || me.isAccepted(); - -- // do not call the base implementation if the event is accepted -- // because it will revert the event back to ignored state -- if (me.isAccepted()) -- return; -+ // Do not call the base implementation: we don't want to call event->ignore(). -+ return; - } - QQuickItem::mouseDoubleClickEvent(event); - } -diff --git x/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/data/doubleClickInMouseArea.qml y/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/data/doubleClickInMouseArea.qml -deleted file mode 100644 -index e43a2f3160..0000000000 ---- x/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/data/doubleClickInMouseArea.qml -+++ /dev/null -@@ -1,23 +0,0 @@ --import QtQuick --import QtQuick.Controls --import QtQuick.Window -- --Rectangle { -- width: 200; height: 200 -- color: mouseArea.pressed ? "red" : "orange" -- -- Popup { -- visible: true -- closePolicy: Popup.NoAutoClose -- width: 100 -- height: 100 -- contentItem: MouseArea { -- id: mouseArea -- -- anchors.fill: parent -- } -- background: Rectangle { -- color: "green" -- } -- } --} -diff --git x/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp y/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp -index bc0dfbc736..c4059a1fbd 100644 ---- x/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp -+++ y/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp -@@ -31,7 +31,6 @@ private slots: - void dragHandlerInSiblingStealingGrabFromMouseAreaViaTouch(); - void hoverHandlerDoesntHoverOnPress(); - void doubleClickInMouseAreaWithDragHandlerInGrandparent(); -- void doubleClickInMouseArea(); - - private: - void createView(QScopedPointer &window, const char *fileName); -@@ -204,26 +203,6 @@ void tst_MouseAreaInterop::doubleClickInMouseAreaWithDragHandlerInGrandparent() - QCOMPARE(dragActiveSpy.count(), 0); - } - --void tst_MouseAreaInterop::doubleClickInMouseArea() --{ -- QQuickView window; -- QVERIFY(QQuickTest::showView(window, testFileUrl("doubleClickInMouseArea.qml"))); -- -- auto *ma = window.rootObject()->findChild(); -- QVERIFY(ma); -- QSignalSpy doubleClickSpy(ma, &QQuickMouseArea::doubleClicked); -- QSignalSpy longPressSpy(ma, &QQuickMouseArea::pressAndHold); -- QPoint p = ma->mapToScene(ma->boundingRect().center()).toPoint(); -- -- // check with normal double click -- QTest::mouseDClick(&window, Qt::LeftButton, Qt::NoModifier, p); -- QCOMPARE(doubleClickSpy.count(), 1); -- -- // wait enough time for a wrong long press to happen -- QTest::qWait(QGuiApplication::styleHints()->mousePressAndHoldInterval() + 10); -- QCOMPARE(longPressSpy.count(), 0); --} -- - QTEST_MAIN(tst_MouseAreaInterop) - - #include "tst_mousearea_interop.moc" -diff --git x/qtdeclarative/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp y/qtdeclarative/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp -index 7da0913e0c..0c7528320e 100644 ---- x/qtdeclarative/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp -+++ y/qtdeclarative/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp -@@ -95,6 +95,7 @@ private slots: - void pressedCanceledOnWindowDeactivate(); - void doubleClick_data() { acceptedButton_data(); } - void doubleClick(); -+ void doubleTap(); - void clickTwice_data() { acceptedButton_data(); } - void clickTwice(); - void invalidClick_data() { rejectedButton_data(); } -@@ -929,6 +930,61 @@ void tst_QQuickMouseArea::doubleClick() - QCOMPARE(window.rootObject()->property("released").toInt(), 2); - } - -+void tst_QQuickMouseArea::doubleTap() // QTBUG-112434 -+{ -+ QQuickView window; -+ QVERIFY(QQuickTest::showView(window, testFileUrl("doubleclick.qml"))); -+ -+ QQuickMouseArea *mouseArea = window.rootObject()->findChild("mousearea"); -+ QVERIFY(mouseArea); -+ QPoint p1 = mouseArea->mapToScene(mouseArea->boundingRect().center()).toPoint(); -+ -+ QTest::touchEvent(&window, device).press(0, p1); -+ QQuickTouchUtils::flush(&window); -+ QTest::touchEvent(&window, device).release(0, p1); -+ QQuickTouchUtils::flush(&window); -+ QCOMPARE(window.rootObject()->property("released").toInt(), 1); -+ QCOMPARE(window.rootObject()->property("clicked").toInt(), 1); -+ -+ p1 += QPoint(1, -1); // movement less than QPlatformTheme::TouchDoubleTapDistance -+ QTest::touchEvent(&window, device).press(1, p1); // touchpoint ID is different the second time -+ QQuickTouchUtils::flush(&window); -+ QCOMPARE(mouseArea->isPressed(), true); -+ // at this time QQuickDeliveryAgentPrivate::deliverTouchAsMouse() synthesizes the double-click event -+ QCOMPARE(window.rootObject()->property("doubleClicked").toInt(), 1); -+ -+ QTest::touchEvent(&window, device).release(1, p1); -+ QQuickTouchUtils::flush(&window); -+ QCOMPARE(window.rootObject()->property("released").toInt(), 2); -+ QCOMPARE(mouseArea->isPressed(), false); -+ QCOMPARE(window.rootObject()->property("clicked").toInt(), 1); -+ -+ // now tap with two fingers simultaneously: only one of them generates synth-mouse -+ QPoint p2 = p1 + QPoint(50, 5); -+ QTest::touchEvent(&window, device).press(2, p1).press(3, p2); -+ QQuickTouchUtils::flush(&window); -+ QCOMPARE(mouseArea->isPressed(), true); -+ QTest::touchEvent(&window, device).release(2, p1).release(3, p2); -+ QQuickTouchUtils::flush(&window); -+ QCOMPARE(window.rootObject()->property("released").toInt(), 3); -+ QCOMPARE(window.rootObject()->property("clicked").toInt(), 2); -+ QCOMPARE(window.rootObject()->property("doubleClicked").toInt(), 1); -+ QCOMPARE(mouseArea->isPressed(), false); -+ -+ // tap with two fingers simultaneously again: get another double-click from one point -+ p1 -= QPoint(1, -1); -+ p2 += QPoint(1, -1); -+ QTest::touchEvent(&window, device).press(4, p1).press(5, p2); -+ QQuickTouchUtils::flush(&window); -+ QCOMPARE(mouseArea->isPressed(), true); -+ QTest::touchEvent(&window, device).release(4, p1).release(5, p2); -+ QQuickTouchUtils::flush(&window); -+ QCOMPARE(window.rootObject()->property("released").toInt(), 4); -+ QCOMPARE(window.rootObject()->property("clicked").toInt(), 2); -+ QCOMPARE(window.rootObject()->property("doubleClicked").toInt(), 2); -+ QCOMPARE(mouseArea->isPressed(), false); // make sure it doesn't get stuck -+} -+ - // QTBUG-14832 - void tst_QQuickMouseArea::clickTwice() - { -diff --git x/qtdeclarative/tests/auto/quickcontrols2/qquickpopup/data/doubleClickInMouseArea.qml y/qtdeclarative/tests/auto/quickcontrols2/qquickpopup/data/doubleClickInMouseArea.qml -new file mode 100644 -index 0000000000..e43a2f3160 ---- /dev/null -+++ y/qtdeclarative/tests/auto/quickcontrols2/qquickpopup/data/doubleClickInMouseArea.qml -@@ -0,0 +1,23 @@ -+import QtQuick -+import QtQuick.Controls -+import QtQuick.Window -+ -+Rectangle { -+ width: 200; height: 200 -+ color: mouseArea.pressed ? "red" : "orange" -+ -+ Popup { -+ visible: true -+ closePolicy: Popup.NoAutoClose -+ width: 100 -+ height: 100 -+ contentItem: MouseArea { -+ id: mouseArea -+ -+ anchors.fill: parent -+ } -+ background: Rectangle { -+ color: "green" -+ } -+ } -+} -diff --git x/qtdeclarative/tests/auto/quickcontrols2/qquickpopup/tst_qquickpopup.cpp y/qtdeclarative/tests/auto/quickcontrols2/qquickpopup/tst_qquickpopup.cpp -index ab20bd71b4..0e8ee05725 100644 ---- x/qtdeclarative/tests/auto/quickcontrols2/qquickpopup/tst_qquickpopup.cpp -+++ y/qtdeclarative/tests/auto/quickcontrols2/qquickpopup/tst_qquickpopup.cpp -@@ -10,6 +10,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -89,6 +90,7 @@ private slots: - void dimmerContainmentMask(); - void shrinkPopupThatWasLargerThanWindow_data(); - void shrinkPopupThatWasLargerThanWindow(); -+ void doubleClickInMouseArea(); - - private: - static bool hasWindowActivation(); -@@ -1928,6 +1930,26 @@ void tst_QQuickPopup::shrinkPopupThatWasLargerThanWindow() - .arg(popup->height()).arg(window->height()))); - } - -+void tst_QQuickPopup::doubleClickInMouseArea() -+{ -+ QQuickView window; -+ QVERIFY(QQuickTest::showView(window, testFileUrl("doubleClickInMouseArea.qml"))); -+ -+ auto *ma = window.rootObject()->findChild(); -+ QVERIFY(ma); -+ QSignalSpy doubleClickSpy(ma, &QQuickMouseArea::doubleClicked); -+ QSignalSpy longPressSpy(ma, &QQuickMouseArea::pressAndHold); -+ QPoint p = ma->mapToScene(ma->boundingRect().center()).toPoint(); -+ -+ // check with normal double click -+ QTest::mouseDClick(&window, Qt::LeftButton, Qt::NoModifier, p); -+ QCOMPARE(doubleClickSpy.count(), 1); -+ -+ // wait enough time for a wrong long press to happen -+ QTest::qWait(QGuiApplication::styleHints()->mousePressAndHoldInterval() + 10); -+ QCOMPARE(longPressSpy.count(), 0); -+} -+ - QTEST_QUICKCONTROLS_MAIN(tst_QQuickPopup) - - #include "tst_qquickpopup.moc" diff --git a/libs/patches/qtscxml-0002-Disable-qtscxml-library.patch b/libs/patches/qtscxml-0001-Build-statemachine-only.patch similarity index 55% rename from libs/patches/qtscxml-0002-Disable-qtscxml-library.patch rename to libs/patches/qtscxml-0001-Build-statemachine-only.patch index 864deee26..7476d8b75 100644 --- a/libs/patches/qtscxml-0002-Disable-qtscxml-library.patch +++ b/libs/patches/qtscxml-0001-Build-statemachine-only.patch @@ -1,33 +1,38 @@ -From 2fa2cbc5c55e862cee7fc495edc444c46d4193ee Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Andr=C3=A9=20Klitzing?= +From 4766db9f067c4121e77d5e80767bbe83ecf59ffc Mon Sep 17 00:00:00 2001 +From: Andre Klitzing Date: Tue, 12 Apr 2022 11:39:12 +0200 -Subject: Disable qtscxml library +Subject: Build statemachine only --- - src/CMakeLists.txt | 4 ++-- + src/CMakeLists.txt | 8 ++++---- tools/CMakeLists.txt | 2 +- - 2 files changed, 3 insertions(+), 3 deletions(-) + 2 files changed, 5 insertions(+), 5 deletions(-) diff --git x/qtscxml/src/CMakeLists.txt y/qtscxml/src/CMakeLists.txt -index f1b7c2b9..7e28acc2 100644 +index 5fbfbd9d..2f94949d 100644 --- x/qtscxml/src/CMakeLists.txt +++ y/qtscxml/src/CMakeLists.txt -@@ -1,8 +1,8 @@ +@@ -2,10 +2,10 @@ + # SPDX-License-Identifier: BSD-3-Clause + -add_subdirectory(scxml) +#add_subdirectory(scxml) add_subdirectory(statemachine) if(TARGET Qt::Qml) - add_subdirectory(statemachineqml) +- add_subdirectory(statemachineqml) - add_subdirectory(scxmlqml) ++# add_subdirectory(statemachineqml) +# add_subdirectory(scxmlqml) endif() - add_subdirectory(plugins) +-add_subdirectory(plugins) ++#add_subdirectory(plugins) diff --git x/qtscxml/tools/CMakeLists.txt y/qtscxml/tools/CMakeLists.txt -index 9726a783..956f9048 100644 +index c5831a40..234fa606 100644 --- x/qtscxml/tools/CMakeLists.txt +++ y/qtscxml/tools/CMakeLists.txt -@@ -1,4 +1,4 @@ +@@ -3,5 +3,5 @@ + if(QT_FEATURE_commandlineparser) - add_subdirectory(qscxmlc) diff --git a/libs/patches/qtscxml-0001-Make-qtdeclarative-optional-for-CONTAINER_SDK.patch b/libs/patches/qtscxml-0001-Make-qtdeclarative-optional-for-CONTAINER_SDK.patch deleted file mode 100644 index 362eba137..000000000 --- a/libs/patches/qtscxml-0001-Make-qtdeclarative-optional-for-CONTAINER_SDK.patch +++ /dev/null @@ -1,20 +0,0 @@ -From abe6296550b5531a129b7d4a21466cdc50dbb2e0 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Andr=C3=A9=20Klitzing?= -Date: Tue, 12 Apr 2022 10:21:19 +0200 -Subject: Make qtdeclarative optional for CONTAINER_SDK - -Change-Id: Ia25b91ea5e3716aef4cb096de1052267b70e343d ---- - dependencies.yaml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git x/qtscxml/dependencies.yaml y/qtscxml/dependencies.yaml -index ee6f92e0..73755512 100644 ---- x/qtscxml/dependencies.yaml -+++ y/qtscxml/dependencies.yaml -@@ -4,4 +4,4 @@ dependencies: - required: true - ../qtdeclarative: - ref: a514640b2a38391fceaaac3ca01b390ad3d62f31 -- required: true -+ required: false diff --git a/libs/patches/qtsvg-0001-QSvgFont-Initialize-used-member-remove-unused.patch b/libs/patches/qtsvg-0001-QSvgFont-Initialize-used-member-remove-unused.patch deleted file mode 100644 index e8f0d75e6..000000000 --- a/libs/patches/qtsvg-0001-QSvgFont-Initialize-used-member-remove-unused.patch +++ /dev/null @@ -1,56 +0,0 @@ -From c3b8e687ca723262f15f31b181a3e5db847afb68 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Robert=20L=C3=B6hning?= -Date: Mon, 24 Apr 2023 15:27:17 +0200 -Subject: QSvgFont: Initialize used member, remove unused - -Credit to OSS-Fuzz - -[ChangeLog][QtSvg] Fixed undefined behavior from using uninitialized -variable. - -Pick-to: 6.5 6.2 5.15 -Coverity-Id: 22618 -Change-Id: Id52277bb0e2845f4d342e187dbb8093e9276b70c -Reviewed-by: Eskil Abrahamsen Blomfeldt -(cherry picked from commit ff22c3ccf8ccf813fdcfda23f7740ba73ba5ce0a) ---- - src/svg/qsvgfont_p.h | 5 ++--- - src/svg/qsvghandler.cpp | 2 +- - 2 files changed, 3 insertions(+), 4 deletions(-) - -diff --git x/qtsvg/src/svg/qsvgfont_p.h y/qtsvg/src/svg/qsvgfont_p.h -index a7cc98b..9cf3dfe 100644 ---- x/qtsvg/src/svg/qsvgfont_p.h -+++ y/qtsvg/src/svg/qsvgfont_p.h -@@ -38,6 +38,7 @@ public: - class Q_SVG_PRIVATE_EXPORT QSvgFont : public QSvgRefCounted - { - public: -+ static constexpr qreal DEFAULT_UNITS_PER_EM = 1000; - QSvgFont(qreal horizAdvX); - - void setFamilyName(const QString &name); -@@ -50,9 +51,7 @@ public: - void draw(QPainter *p, const QPointF &point, const QString &str, qreal pixelSize, Qt::Alignment alignment) const; - public: - QString m_familyName; -- qreal m_unitsPerEm; -- qreal m_ascent; -- qreal m_descent; -+ qreal m_unitsPerEm = DEFAULT_UNITS_PER_EM; - qreal m_horizAdvX; - QHash m_glyphs; - }; -diff --git x/qtsvg/src/svg/qsvghandler.cpp y/qtsvg/src/svg/qsvghandler.cpp -index e88e83b..1e2b2fc 100644 ---- x/qtsvg/src/svg/qsvghandler.cpp -+++ y/qtsvg/src/svg/qsvghandler.cpp -@@ -2622,7 +2622,7 @@ static bool parseFontFaceNode(QSvgStyleProperty *parent, - - qreal unitsPerEm = toDouble(unitsPerEmStr); - if (!unitsPerEm) -- unitsPerEm = 1000; -+ unitsPerEm = QSvgFont::DEFAULT_UNITS_PER_EM; - - if (!name.isEmpty()) - font->setFamilyName(name); diff --git a/libs/patches/qttools-0001-Disable-linguist-but-keep-translation-tools.patch b/libs/patches/qttools-0001-Disable-linguist-but-keep-translation-tools.patch index 0f8e56d70..3715343c9 100644 --- a/libs/patches/qttools-0001-Disable-linguist-but-keep-translation-tools.patch +++ b/libs/patches/qttools-0001-Disable-linguist-but-keep-translation-tools.patch @@ -1,4 +1,4 @@ -From d52894c2b13954d13ff940ba6b36e5cab7fbf3ac Mon Sep 17 00:00:00 2001 +From e00687d94bec135898675ffd87f1037c9234b0c4 Mon Sep 17 00:00:00 2001 From: Jan Moeller Date: Mon, 14 Feb 2022 13:46:46 +0100 Subject: Disable linguist but keep translation tools @@ -9,7 +9,7 @@ Change-Id: I1c54eb0e7bb86ec0861b54b5abe753c86bb57dd9 1 file changed, 3 deletions(-) diff --git x/qttools/src/linguist/CMakeLists.txt y/qttools/src/linguist/CMakeLists.txt -index 16ff9f559..fde23b0c4 100644 +index d85254b32..dfcfe7271 100644 --- x/qttools/src/linguist/CMakeLists.txt +++ y/qttools/src/linguist/CMakeLists.txt @@ -14,9 +14,6 @@ add_subdirectory(lrelease) @@ -20,5 +20,5 @@ index 16ff9f559..fde23b0c4 100644 - add_subdirectory(linguist) -endif() - # special case begin # Create a fake module that would emulate the Qt5::LinguistTools CMake Config package + qt_internal_add_module(Linguist NO_MODULE_HEADERS HEADER_MODULE) diff --git a/libs/patches/qttools-0002-Disable-designer-and-uitools.patch b/libs/patches/qttools-0002-Disable-designer-and-uitools.patch new file mode 100644 index 000000000..910f7ae5a --- /dev/null +++ b/libs/patches/qttools-0002-Disable-designer-and-uitools.patch @@ -0,0 +1,34 @@ +From 9852f44ab2b6c6e30d8c6ec4a5d45025bc13c2f4 Mon Sep 17 00:00:00 2001 +From: Andre Klitzing +Date: Wed, 21 Jun 2023 12:22:46 +0200 +Subject: Disable designer and uitools + +See https://bugreports.qt.io/browse/QTBUG-95236 +--- + src/CMakeLists.txt | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git x/qttools/src/CMakeLists.txt y/qttools/src/CMakeLists.txt +index 014e4c874..1574b1b20 100644 +--- x/qttools/src/CMakeLists.txt ++++ y/qttools/src/CMakeLists.txt +@@ -18,8 +18,8 @@ qt_exclude_tool_directories_from_default_target( + qt_feature_evaluate_features("${CMAKE_CURRENT_SOURCE_DIR}/../configure.cmake") + + if(TARGET Qt::Widgets) +- add_subdirectory(uiplugin) +- add_subdirectory(uitools) ++# add_subdirectory(uiplugin) ++# add_subdirectory(uitools) + endif() + + add_subdirectory(global) # special case add as first directory +@@ -28,7 +28,7 @@ if(QT_FEATURE_linguist) + endif() + # add_subdirectory(global) # special case remove + if(QT_FEATURE_designer) +- add_subdirectory(designer) ++# add_subdirectory(designer) + endif() + if(QT_FEATURE_pixeltool) + add_subdirectory(pixeltool) diff --git a/libs/patches/qttools-0002-Revert-Move-UiTools-and-UiPlugin-modules-to-a-upper-.patch b/libs/patches/qttools-0002-Revert-Move-UiTools-and-UiPlugin-modules-to-a-upper-.patch deleted file mode 100644 index 618650497..000000000 --- a/libs/patches/qttools-0002-Revert-Move-UiTools-and-UiPlugin-modules-to-a-upper-.patch +++ /dev/null @@ -1,3230 +0,0 @@ -From 2cbc188e4facb12153f37a501f14384ec733c944 Mon Sep 17 00:00:00 2001 -From: Lars Schmertmann -Date: Wed, 9 Nov 2022 09:49:38 +0100 -Subject: Revert "Move UiTools and UiPlugin modules to a upper level - sub-directory" - -This partially reverts commit 6af882fa2f45f73ec2ba4066d5ae3ad072d0c5ee. - -Change-Id: I247e2189577b74d813a210ace0b49d672a90975e ---- - src/CMakeLists.txt | 5 - - src/designer/src/CMakeLists.txt | 2 + - .../src/designer/doc/qtdesigner.qdocconf | 4 +- - src/designer/src/uiplugin/CMakeLists.txt | 27 + - src/designer/src/uiplugin/customwidget.h | 62 ++ - src/designer/src/uiplugin/customwidget.qdoc | 269 ++++++ - .../src/uiplugin/qdesignerexportwidget.h | 24 + - src/designer/src/uitools/CMakeLists.txt | 46 + - src/designer/src/uitools/qtuitoolsglobal.h | 23 + - src/designer/src/uitools/quiloader.cpp | 914 ++++++++++++++++++ - src/designer/src/uitools/quiloader.h | 61 ++ - src/designer/src/uitools/quiloader_p.h | 77 ++ - src/uiplugin/CMakeLists.txt | 27 - - src/uiplugin/customwidget.h | 62 -- - src/uiplugin/customwidget.qdoc | 269 ------ - src/uiplugin/qdesignerexportwidget.h | 24 - - src/uitools/CMakeLists.txt | 47 - - src/uitools/qtuitoolsglobal.h | 24 - - src/uitools/quiloader.cpp | 914 ------------------ - src/uitools/quiloader.h | 61 -- - src/uitools/quiloader_p.h | 77 -- - sync.profile | 4 +- - 22 files changed, 1509 insertions(+), 1514 deletions(-) - create mode 100644 src/designer/src/uiplugin/CMakeLists.txt - create mode 100644 src/designer/src/uiplugin/customwidget.h - create mode 100644 src/designer/src/uiplugin/customwidget.qdoc - create mode 100644 src/designer/src/uiplugin/qdesignerexportwidget.h - create mode 100644 src/designer/src/uitools/CMakeLists.txt - create mode 100644 src/designer/src/uitools/qtuitoolsglobal.h - create mode 100644 src/designer/src/uitools/quiloader.cpp - create mode 100644 src/designer/src/uitools/quiloader.h - create mode 100644 src/designer/src/uitools/quiloader_p.h - delete mode 100644 src/uiplugin/CMakeLists.txt - delete mode 100644 src/uiplugin/customwidget.h - delete mode 100644 src/uiplugin/customwidget.qdoc - delete mode 100644 src/uiplugin/qdesignerexportwidget.h - delete mode 100644 src/uitools/CMakeLists.txt - delete mode 100644 src/uitools/qtuitoolsglobal.h - delete mode 100644 src/uitools/quiloader.cpp - delete mode 100644 src/uitools/quiloader.h - delete mode 100644 src/uitools/quiloader_p.h - -diff --git x/qttools/src/CMakeLists.txt y/qttools/src/CMakeLists.txt -index b42cd4946..cb0c21a70 100644 ---- x/qttools/src/CMakeLists.txt -+++ y/qttools/src/CMakeLists.txt -@@ -21,11 +21,6 @@ qt_exclude_tool_directories_from_default_target( - qt_feature_evaluate_features("${CMAKE_CURRENT_SOURCE_DIR}/../configure.cmake") - # special case end - --if(TARGET Qt::Widgets) -- add_subdirectory(uiplugin) -- add_subdirectory(uitools) --endif() -- - add_subdirectory(global) # special case add as first directory - if(QT_FEATURE_linguist) - add_subdirectory(linguist) -diff --git x/qttools/src/designer/src/CMakeLists.txt y/qttools/src/designer/src/CMakeLists.txt -index 31fc1734e..32fb45160 100644 ---- x/qttools/src/designer/src/CMakeLists.txt -+++ y/qttools/src/designer/src/CMakeLists.txt -@@ -8,6 +8,8 @@ qt_exclude_tool_directories_from_default_target( - plugins - ) - -+add_subdirectory(uiplugin) -+add_subdirectory(uitools) - if(QT_FEATURE_process) - add_subdirectory(lib) - add_subdirectory(components) -diff --git x/qttools/src/designer/src/designer/doc/qtdesigner.qdocconf y/qttools/src/designer/src/designer/doc/qtdesigner.qdocconf -index 75c8c78dd..964fb47ed 100644 ---- x/qttools/src/designer/src/designer/doc/qtdesigner.qdocconf -+++ y/qttools/src/designer/src/designer/doc/qtdesigner.qdocconf -@@ -28,11 +28,11 @@ qhp.QtDesigner.subprojects.classes.sortPages = true - language = Cpp - - headerdirs += .. \ -- ../../../../uiplugin \ -+ ../../uiplugin \ - ../../lib - - sourcedirs = .. \ -- ../../../../uiplugin \ -+ ../../uiplugin \ - ../../lib - - exampledirs = ../../../../../examples/designer \ -diff --git x/qttools/src/designer/src/uiplugin/CMakeLists.txt y/qttools/src/designer/src/uiplugin/CMakeLists.txt -new file mode 100644 -index 000000000..4fedf8e33 ---- /dev/null -+++ y/qttools/src/designer/src/uiplugin/CMakeLists.txt -@@ -0,0 +1,27 @@ -+# Generated from uiplugin.pro. -+ -+##################################################################### -+## UiPlugin Module: -+##################################################################### -+ -+qt_internal_add_module(UiPlugin -+ NO_PRIVATE_MODULE -+ HEADER_MODULE -+ QMAKE_MODULE_CONFIG designer_defines -+ PUBLIC_LIBRARIES -+ Qt::Core -+ Qt::Gui -+ Qt::Widgets -+) -+ -+# special case begin -+set(is_plugin "$") -+target_compile_definitions( -+ UiPlugin -+ INTERFACE -+ $<$:QDESIGNER_EXPORT_WIDGETS> -+) -+# special case end -+ -+#### Keys ignored in scope 1:.:.:uiplugin.pro:: -+# MODULE_CONFIG = "designer_defines" -diff --git x/qttools/src/designer/src/uiplugin/customwidget.h y/qttools/src/designer/src/uiplugin/customwidget.h -new file mode 100644 -index 000000000..2a47a32f8 ---- /dev/null -+++ y/qttools/src/designer/src/uiplugin/customwidget.h -@@ -0,0 +1,62 @@ -+// Copyright (C) 2016 The Qt Company Ltd. -+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -+ -+#ifndef CUSTOMWIDGET_H -+#define CUSTOMWIDGET_H -+ -+#include -+#include -+#include -+ -+QT_BEGIN_NAMESPACE -+ -+class QWidget; -+class QDesignerFormEditorInterface; -+ -+class QDesignerCustomWidgetInterface -+{ -+public: -+ virtual ~QDesignerCustomWidgetInterface() = default; // ### FIXME: weak vtable -+ -+ virtual QString name() const = 0; -+ virtual QString group() const = 0; -+ virtual QString toolTip() const = 0; -+ virtual QString whatsThis() const = 0; -+ virtual QString includeFile() const = 0; -+ virtual QIcon icon() const = 0; -+ -+ virtual bool isContainer() const = 0; -+ -+ virtual QWidget *createWidget(QWidget *parent) = 0; -+ -+ virtual bool isInitialized() const { return false; } -+ virtual void initialize(QDesignerFormEditorInterface *core) { Q_UNUSED(core); } -+ -+ virtual QString domXml() const -+ { -+ return QString::fromUtf8("") -+ .arg(name()).arg(name().toLower()); -+ } -+ -+ virtual QString codeTemplate() const { return QString(); } -+}; -+ -+#define QDesignerCustomWidgetInterface_iid "org.qt-project.QDesignerCustomWidgetInterface" -+ -+Q_DECLARE_INTERFACE(QDesignerCustomWidgetInterface, QDesignerCustomWidgetInterface_iid) -+ -+class QDesignerCustomWidgetCollectionInterface -+{ -+public: -+ virtual ~QDesignerCustomWidgetCollectionInterface() = default; // ### FIXME: weak vtable -+ -+ virtual QList customWidgets() const = 0; -+}; -+ -+#define QDesignerCustomWidgetCollectionInterface_iid "org.qt-project.Qt.QDesignerCustomWidgetCollectionInterface" -+ -+Q_DECLARE_INTERFACE(QDesignerCustomWidgetCollectionInterface, QDesignerCustomWidgetCollectionInterface_iid) -+ -+QT_END_NAMESPACE -+ -+#endif // CUSTOMWIDGET_H -diff --git x/qttools/src/designer/src/uiplugin/customwidget.qdoc y/qttools/src/designer/src/uiplugin/customwidget.qdoc -new file mode 100644 -index 000000000..557e9a454 ---- /dev/null -+++ y/qttools/src/designer/src/uiplugin/customwidget.qdoc -@@ -0,0 +1,269 @@ -+// Copyright (C) 2016 The Qt Company Ltd. -+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only -+ -+/*! -+ \class QDesignerCustomWidgetInterface -+ -+ \brief The QDesignerCustomWidgetInterface class enables Qt Designer -+ to access and construct custom widgets. -+ -+ \inmodule QtDesigner -+ -+ QDesignerCustomWidgetInterface provides a custom widget with an -+ interface. The class contains a set of functions that must be subclassed -+ to return basic information about the widget, such as its class name and -+ the name of its header file. Other functions must be implemented to -+ initialize the plugin when it is loaded, and to construct instances of -+ the custom widget for \QD to use. -+ -+ When implementing a custom widget you must subclass -+ QDesignerCustomWidgetInterface to expose your widget to \QD. For -+ example, this is the declaration for the plugin used in the -+ \l{Custom Widget Plugin Example}{Custom Widget Plugin example} that -+ enables an analog clock custom widget to be used by \QD: -+ -+ \snippet customwidgetplugin/customwidgetplugin.h 0 -+ -+ Note that the only part of the class definition that is specific -+ to this particular custom widget is the class name. In addition, -+ since we are implementing an interface, we must ensure that it's -+ made known to the meta object system using the Q_INTERFACES() -+ macro. This enables \QD to use the qobject_cast() function to -+ query for supported interfaces using nothing but a QObject -+ pointer. -+ -+ After \QD loads a custom widget plugin, it calls the interface's -+ initialize() function to enable it to set up any resources that it -+ may need. This function is called with a QDesignerFormEditorInterface -+ parameter that provides the plugin with a gateway to all of \QD's API. -+ -+ \QD constructs instances of the custom widget by calling the plugin's -+ createWidget() function with a suitable parent widget. Plugins must -+ construct and return an instance of a custom widget with the specified -+ parent widget. -+ -+ Exporting your custom widget plugin to \QD using the Q_PLUGIN_METADATA() -+ macro. For example, if a library called \c libcustomwidgetplugin.so -+ (on Unix) or \c libcustomwidget.dll (on Windows) contains a widget -+ class called \c MyCustomWidget, we can export it by adding the -+ following line to the file containing the plugin header: -+ -+ \snippet plugins/doc_src_qtdesigner.cpp 14 -+ -+ This macro ensures that \QD can access and construct the custom widget. -+ Without this macro, there is no way for \QD to use it. -+ -+ When implementing a custom widget plugin, you build it as a -+ separate library. If you want to include several custom widget -+ plugins in the same library, you must in addition subclass -+ QDesignerCustomWidgetCollectionInterface. -+ -+ \warning If your custom widget plugin contains QVariant -+ properties, be aware that only the following \l -+ {QVariant::Type}{types} are supported: -+ -+ \list -+ \li QVariant::ByteArray -+ \li QVariant::Bool -+ \li QVariant::Color -+ \li QVariant::Cursor -+ \li QVariant::Date -+ \li QVariant::DateTime -+ \li QVariant::Double -+ \li QVariant::Int -+ \li QVariant::Point -+ \li QVariant::Rect -+ \li QVariant::Size -+ \li QVariant::SizePolicy -+ \li QVariant::String -+ \li QVariant::Time -+ \li QVariant::UInt -+ \endlist -+ -+ For a complete example using the QDesignerCustomWidgetInterface -+ class, see the \l {customwidgetplugin}{Custom Widget -+ Example}. The example shows how to create a custom widget plugin -+ for \QD. -+ -+ \sa QDesignerCustomWidgetCollectionInterface, {Creating Custom Widgets for Qt Designer} -+*/ -+ -+/*! -+ \fn QDesignerCustomWidgetInterface::~QDesignerCustomWidgetInterface() -+ -+ Destroys the custom widget interface. -+*/ -+ -+/*! -+ \fn QString QDesignerCustomWidgetInterface::name() const -+ -+ Returns the class name of the custom widget supplied by the interface. -+ -+ The name returned \e must be identical to the class name used for the -+ custom widget. -+*/ -+ -+/*! -+ \fn QString QDesignerCustomWidgetInterface::group() const -+ -+ Returns the name of the group to which the custom widget belongs. -+*/ -+ -+/*! -+ \fn QString QDesignerCustomWidgetInterface::toolTip() const -+ -+ Returns a short description of the widget that can be used by \QD -+ in a tool tip. -+*/ -+ -+/*! -+ \fn QString QDesignerCustomWidgetInterface::whatsThis() const -+ -+ Returns a description of the widget that can be used by \QD in -+ "What's This?" help for the widget. -+*/ -+ -+/*! -+ \fn QString QDesignerCustomWidgetInterface::includeFile() const -+ -+ Returns the path to the include file that \l uic uses when -+ creating code for the custom widget. -+*/ -+ -+/*! -+ \fn QIcon QDesignerCustomWidgetInterface::icon() const -+ -+ Returns the icon used to represent the custom widget in \QD's -+ widget box. -+*/ -+ -+/*! -+ \fn bool QDesignerCustomWidgetInterface::isContainer() const -+ -+ Returns true if the custom widget is intended to be used as a -+ container; otherwise returns false. -+ -+ Most custom widgets are not used to hold other widgets, so their -+ implementations of this function will return false, but custom -+ containers will return true to ensure that they behave correctly -+ in \QD. -+*/ -+ -+/*! -+ \fn QWidget *QDesignerCustomWidgetInterface::createWidget(QWidget *parent) -+ -+ Returns a new instance of the custom widget, with the given \a -+ parent. -+*/ -+ -+/*! -+ \fn bool QDesignerCustomWidgetInterface::isInitialized() const -+ -+ Returns true if the widget has been initialized; otherwise returns -+ false. -+ -+ \sa initialize() -+*/ -+ -+/*! -+ \fn void QDesignerCustomWidgetInterface::initialize(QDesignerFormEditorInterface *formEditor) -+ -+ Initializes the widget for use with the specified \a formEditor -+ interface. -+ -+ \sa isInitialized() -+*/ -+ -+/*! -+ \fn QString QDesignerCustomWidgetInterface::domXml() const -+ -+ Returns the XML that is used to describe the custom widget's -+ properties to \QD. -+*/ -+ -+/*! -+ \fn QString QDesignerCustomWidgetInterface::codeTemplate() const -+ -+ This function is reserved for future use by \QD. -+ -+ \omit -+ Returns the code template that \QD includes in forms that contain -+ the custom widget when they are saved. -+ \endomit -+*/ -+ -+/*! -+ \macro QDESIGNER_WIDGET_EXPORT -+ \relates QDesignerCustomWidgetInterface -+ \since 4.1 -+ -+ This macro is used when defining custom widgets to ensure that they are -+ correctly exported from plugins for use with \QD. -+ -+ On some platforms, the symbols required by \QD to create new widgets -+ are removed from plugins by the build system, making them unusable. -+ Using this macro ensures that the symbols are retained on those platforms, -+ and has no side effects on other platforms. -+ -+ For example, the \l{worldtimeclockplugin}{World Time Clock Plugin} -+ example exports a custom widget class with the following declaration: -+ -+ \snippet worldtimeclockplugin/worldtimeclock.h 0 -+ \dots -+ \snippet worldtimeclockplugin/worldtimeclock.h 2 -+ -+ \sa {Creating Custom Widgets for Qt Designer} -+*/ -+ -+ -+ -+ -+ -+/*! -+ \class QDesignerCustomWidgetCollectionInterface -+ -+ \brief The QDesignerCustomWidgetCollectionInterface class allows -+ you to include several custom widgets in one single library. -+ -+ \inmodule QtDesigner -+ -+ When implementing a custom widget plugin, you build it as a -+ separate library. If you want to include several custom widget -+ plugins in the same library, you must in addition subclass -+ QDesignerCustomWidgetCollectionInterface. -+ -+ QDesignerCustomWidgetCollectionInterface contains one single -+ function returning a list of the collection's -+ QDesignerCustomWidgetInterface objects. For example, if you have -+ several custom widgets \c CustomWidgetOne, \c CustomWidgetTwo and -+ \c CustomWidgetThree, the class definition may look like this: -+ -+ \snippet plugins/doc_src_qtdesigner.cpp 12 -+ -+ In the class constructor you add the interfaces to your custom -+ widgets to the list which you return in the customWidgets() -+ function: -+ -+ \snippet plugins/doc_src_qtdesigner.cpp 13 -+ -+ Note that instead of exporting each custom widget plugin using the -+ Q_PLUGIN_METADATA() macro, you export the entire collection. The -+ Q_PLUGIN_METADATA() macro ensures that \QD can access and construct -+ the custom widgets. Without this macro, there is no way for \QD to -+ use them. -+ -+ \sa QDesignerCustomWidgetInterface, {Creating Custom Widgets for -+ Qt Designer} -+*/ -+ -+/*! -+ \fn QDesignerCustomWidgetCollectionInterface::~QDesignerCustomWidgetCollectionInterface() { -+ -+ Destroys the custom widget collection interface. -+*/ -+ -+/*! -+ \fn QList QDesignerCustomWidgetCollectionInterface::customWidgets() const -+ -+ Returns a list of interfaces to the collection's custom widgets. -+*/ -diff --git x/qttools/src/designer/src/uiplugin/qdesignerexportwidget.h y/qttools/src/designer/src/uiplugin/qdesignerexportwidget.h -new file mode 100644 -index 000000000..d90e9b217 ---- /dev/null -+++ y/qttools/src/designer/src/uiplugin/qdesignerexportwidget.h -@@ -0,0 +1,24 @@ -+// Copyright (C) 2016 The Qt Company Ltd. -+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -+ -+#ifndef QDESIGNEREXPORTWIDGET_H -+#define QDESIGNEREXPORTWIDGET_H -+ -+#include -+ -+QT_BEGIN_NAMESPACE -+ -+#if 0 -+// pragma for syncqt, don't remove. -+#pragma qt_class(QDesignerExportWidget) -+#endif -+ -+#if defined(QDESIGNER_EXPORT_WIDGETS) -+# define QDESIGNER_WIDGET_EXPORT Q_DECL_EXPORT -+#else -+# define QDESIGNER_WIDGET_EXPORT Q_DECL_IMPORT -+#endif -+ -+QT_END_NAMESPACE -+ -+#endif //QDESIGNEREXPORTWIDGET_H -diff --git x/qttools/src/designer/src/uitools/CMakeLists.txt y/qttools/src/designer/src/uitools/CMakeLists.txt -new file mode 100644 -index 000000000..6040ac71d ---- /dev/null -+++ y/qttools/src/designer/src/uitools/CMakeLists.txt -@@ -0,0 +1,46 @@ -+# Generated from uitools.pro. -+ -+##################################################################### -+## UiTools Module: -+##################################################################### -+ -+qt_internal_add_module(UiTools -+ SOURCES -+ ../lib/uilib/abstractformbuilder.cpp ../lib/uilib/abstractformbuilder.h -+ ../lib/uilib/formbuilder.cpp ../lib/uilib/formbuilder.h -+ ../lib/uilib/formbuilderextra.cpp ../lib/uilib/formbuilderextra_p.h -+ ../lib/uilib/properties.cpp ../lib/uilib/properties_p.h -+ ../lib/uilib/resourcebuilder.cpp ../lib/uilib/resourcebuilder_p.h -+ ../lib/uilib/textbuilder.cpp ../lib/uilib/textbuilder_p.h -+ ../lib/uilib/ui4.cpp ../lib/uilib/ui4_p.h -+ quiloader.cpp quiloader.h -+ DEFINES -+ QFORMINTERNAL_NAMESPACE -+ QT_DESIGNER -+ QT_DESIGNER_STATIC -+ QT_USE_QSTRINGBUILDER -+ INCLUDE_DIRECTORIES -+ ../lib/uilib -+ LIBRARIES -+ Qt::UiPlugin -+ PUBLIC_LIBRARIES -+ Qt::Core -+ Qt::Gui -+ Qt::Widgets -+) -+ -+## Scopes: -+##################################################################### -+ -+qt_internal_extend_target(UiTools CONDITION TARGET Qt::OpenGLWidgets -+ PUBLIC_LIBRARIES -+ Qt::OpenGLWidgets -+) -+ -+qt_internal_extend_target(UiTools CONDITION QT_FEATURE_opengl -+ LIBRARIES -+ Qt::OpenGL -+) -+qt_internal_add_docs(UiTools -+ doc/qtuitools.qdocconf -+) -diff --git x/qttools/src/designer/src/uitools/qtuitoolsglobal.h y/qttools/src/designer/src/uitools/qtuitoolsglobal.h -new file mode 100644 -index 000000000..6874fb15b ---- /dev/null -+++ y/qttools/src/designer/src/uitools/qtuitoolsglobal.h -@@ -0,0 +1,23 @@ -+// Copyright (C) 2020 The Qt Company Ltd. -+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only -+ -+#ifndef QTUITOOLSGLOBAL_H -+#define QTUITOOLSGLOBAL_H -+ -+#include -+ -+QT_BEGIN_NAMESPACE -+ -+#ifndef QT_STATIC -+# if defined(QT_BUILD_UITOOLS_LIB) -+# define Q_UITOOLS_EXPORT Q_DECL_EXPORT -+# else -+# define Q_UITOOLS_EXPORT Q_DECL_IMPORT -+# endif -+#else -+# define Q_UITOOLS_EXPORT -+#endif -+ -+QT_END_NAMESPACE -+ -+#endif // QTUITOOLSGLOBAL_H -diff --git x/qttools/src/designer/src/uitools/quiloader.cpp y/qttools/src/designer/src/uitools/quiloader.cpp -new file mode 100644 -index 000000000..a06d4717b ---- /dev/null -+++ y/qttools/src/designer/src/uitools/quiloader.cpp -@@ -0,0 +1,914 @@ -+// Copyright (C) 2020 The Qt Company Ltd. -+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only -+ -+ -+#include "quiloader.h" -+#include "quiloader_p.h" -+ -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+QT_BEGIN_NAMESPACE -+ -+typedef QMap widget_map; -+Q_GLOBAL_STATIC(widget_map, g_widgets) -+ -+class QUiLoader; -+class QUiLoaderPrivate; -+ -+#ifndef QT_NO_DATASTREAM -+// QUiTranslatableStringValue must be streamable since they become part of the QVariant-based -+// mime data when dragging items in views with QAbstractItemView::InternalMove. -+QDataStream &operator<<(QDataStream &out, const QUiTranslatableStringValue &s) -+{ -+ out << s.qualifier() << s.value(); -+ return out; -+} -+ -+QDataStream &operator>>(QDataStream &in, QUiTranslatableStringValue &s) -+{ -+ QByteArray qualifier, value; -+ in >> qualifier >> value; -+ s.setQualifier(qualifier); -+ s.setValue(value); -+ return in; -+} -+#endif // QT_NO_DATASTREAM -+ -+QString QUiTranslatableStringValue::translate(const QByteArray &className, bool idBased) const -+{ -+ return idBased -+ ? qtTrId(m_qualifier.constData()) -+ : QCoreApplication::translate(className.constData(), m_value.constData(), m_qualifier.constData()); -+} -+ -+#ifdef QFORMINTERNAL_NAMESPACE -+namespace QFormInternal -+{ -+#endif -+ -+class TranslatingTextBuilder : public QTextBuilder -+{ -+public: -+ explicit TranslatingTextBuilder(bool idBased, bool trEnabled, const QByteArray &className) : -+ m_idBased(idBased), m_trEnabled(trEnabled), m_className(className) {} -+ -+ QVariant loadText(const DomProperty *icon) const override; -+ -+ QVariant toNativeValue(const QVariant &value) const override; -+ -+ bool idBased() const { return m_idBased; } -+ -+private: -+ bool m_idBased; -+ bool m_trEnabled; -+ QByteArray m_className; -+}; -+ -+QVariant TranslatingTextBuilder::loadText(const DomProperty *text) const -+{ -+ const DomString *str = text->elementString(); -+ if (!str) -+ return QVariant(); -+ if (str->hasAttributeNotr()) { -+ const QString notr = str->attributeNotr(); -+ if (notr == QStringLiteral("true") || notr == QStringLiteral("yes")) -+ return QVariant::fromValue(str->text()); -+ } -+ QUiTranslatableStringValue strVal; -+ strVal.setValue(str->text().toUtf8()); -+ if (m_idBased) -+ strVal.setQualifier(str->attributeId().toUtf8()); -+ else if (str->hasAttributeComment()) -+ strVal.setQualifier(str->attributeComment().toUtf8()); -+ return QVariant::fromValue(strVal); -+} -+ -+QVariant TranslatingTextBuilder::toNativeValue(const QVariant &value) const -+{ -+ if (value.canConvert()) { -+ QUiTranslatableStringValue tsv = qvariant_cast(value); -+ if (!m_trEnabled) -+ return QString::fromUtf8(tsv.value().constData()); -+ return QVariant::fromValue(tsv.translate(m_className, m_idBased)); -+ } -+ if (value.canConvert()) -+ return QVariant::fromValue(qvariant_cast(value)); -+ return value; -+} -+ -+// This is "exported" to linguist -+const QUiItemRolePair qUiItemRoles[] = { -+ { Qt::DisplayRole, Qt::DisplayPropertyRole }, -+#if QT_CONFIG(tooltip) -+ { Qt::ToolTipRole, Qt::ToolTipPropertyRole }, -+#endif -+#if QT_CONFIG(statustip) -+ { Qt::StatusTipRole, Qt::StatusTipPropertyRole }, -+#endif -+#if QT_CONFIG(whatsthis) -+ { Qt::WhatsThisRole, Qt::WhatsThisPropertyRole }, -+#endif -+ { -1 , -1 } -+}; -+ -+static void recursiveReTranslate(QTreeWidgetItem *item, const QByteArray &class_name, bool idBased) -+{ -+ const QUiItemRolePair *irs = qUiItemRoles; -+ -+ int cnt = item->columnCount(); -+ for (int i = 0; i < cnt; ++i) { -+ for (unsigned j = 0; irs[j].shadowRole >= 0; j++) { -+ QVariant v = item->data(i, irs[j].shadowRole); -+ if (v.isValid()) { -+ QUiTranslatableStringValue tsv = qvariant_cast(v); -+ item->setData(i, irs[j].realRole, tsv.translate(class_name, idBased)); -+ } -+ } -+ } -+ -+ cnt = item->childCount(); -+ for (int i = 0; i < cnt; ++i) -+ recursiveReTranslate(item->child(i), class_name, idBased); -+} -+ -+template -+static void reTranslateWidgetItem(T *item, const QByteArray &class_name, bool idBased) -+{ -+ const QUiItemRolePair *irs = qUiItemRoles; -+ -+ for (unsigned j = 0; irs[j].shadowRole >= 0; j++) { -+ QVariant v = item->data(irs[j].shadowRole); -+ if (v.isValid()) { -+ QUiTranslatableStringValue tsv = qvariant_cast(v); -+ item->setData(irs[j].realRole, tsv.translate(class_name, idBased)); -+ } -+ } -+} -+ -+static void reTranslateTableItem(QTableWidgetItem *item, const QByteArray &class_name, bool idBased) -+{ -+ if (item) -+ reTranslateWidgetItem(item, class_name, idBased); -+} -+ -+#define RETRANSLATE_SUBWIDGET_PROP(mainWidget, setter, propName) \ -+ do { \ -+ QVariant v = mainWidget->widget(i)->property(propName); \ -+ if (v.isValid()) { \ -+ QUiTranslatableStringValue tsv = qvariant_cast(v); \ -+ mainWidget->setter(i, tsv.translate(m_className, m_idBased)); \ -+ } \ -+ } while (0) -+ -+class TranslationWatcher: public QObject -+{ -+ Q_OBJECT -+ -+public: -+ explicit TranslationWatcher(QObject *parent, const QByteArray &className, bool idBased): -+ QObject(parent), -+ m_className(className), -+ m_idBased(idBased) -+ { -+ } -+ -+ bool eventFilter(QObject *o, QEvent *event) override -+ { -+ if (event->type() == QEvent::LanguageChange) { -+ const auto &dynamicPropertyNames = o->dynamicPropertyNames(); -+ for (const QByteArray &prop : dynamicPropertyNames) { -+ if (prop.startsWith(PROP_GENERIC_PREFIX)) { -+ const QByteArray propName = prop.mid(sizeof(PROP_GENERIC_PREFIX) - 1); -+ const QUiTranslatableStringValue tsv = -+ qvariant_cast(o->property(prop)); -+ o->setProperty(propName, tsv.translate(m_className, m_idBased)); -+ } -+ } -+ if (0) { -+#if QT_CONFIG(tabwidget) -+ } else if (QTabWidget *tabw = qobject_cast(o)) { -+ const int cnt = tabw->count(); -+ for (int i = 0; i < cnt; ++i) { -+ RETRANSLATE_SUBWIDGET_PROP(tabw, setTabText, PROP_TABPAGETEXT); -+#if QT_CONFIG(tooltip) -+ RETRANSLATE_SUBWIDGET_PROP(tabw, setTabToolTip, PROP_TABPAGETOOLTIP); -+# endif -+#if QT_CONFIG(whatsthis) -+ RETRANSLATE_SUBWIDGET_PROP(tabw, setTabWhatsThis, PROP_TABPAGEWHATSTHIS); -+# endif -+ } -+#endif -+#if QT_CONFIG(listwidget) -+ } else if (QListWidget *listw = qobject_cast(o)) { -+ const int cnt = listw->count(); -+ for (int i = 0; i < cnt; ++i) -+ reTranslateWidgetItem(listw->item(i), m_className, m_idBased); -+#endif -+#if QT_CONFIG(treewidget) -+ } else if (QTreeWidget *treew = qobject_cast(o)) { -+ if (QTreeWidgetItem *item = treew->headerItem()) -+ recursiveReTranslate(item, m_className, m_idBased); -+ const int cnt = treew->topLevelItemCount(); -+ for (int i = 0; i < cnt; ++i) { -+ QTreeWidgetItem *item = treew->topLevelItem(i); -+ recursiveReTranslate(item, m_className, m_idBased); -+ } -+#endif -+#if QT_CONFIG(tablewidget) -+ } else if (QTableWidget *tablew = qobject_cast(o)) { -+ const int row_cnt = tablew->rowCount(); -+ const int col_cnt = tablew->columnCount(); -+ for (int j = 0; j < col_cnt; ++j) -+ reTranslateTableItem(tablew->horizontalHeaderItem(j), m_className, m_idBased); -+ for (int i = 0; i < row_cnt; ++i) { -+ reTranslateTableItem(tablew->verticalHeaderItem(i), m_className, m_idBased); -+ for (int j = 0; j < col_cnt; ++j) -+ reTranslateTableItem(tablew->item(i, j), m_className, m_idBased); -+ } -+#endif -+#if QT_CONFIG(combobox) -+ } else if (QComboBox *combow = qobject_cast(o)) { -+ if (!qobject_cast(o)) { -+ const int cnt = combow->count(); -+ for (int i = 0; i < cnt; ++i) { -+ const QVariant v = combow->itemData(i, Qt::DisplayPropertyRole); -+ if (v.isValid()) { -+ QUiTranslatableStringValue tsv = qvariant_cast(v); -+ combow->setItemText(i, tsv.translate(m_className, m_idBased)); -+ } -+ } -+ } -+#endif -+#if QT_CONFIG(toolbox) -+ } else if (QToolBox *toolw = qobject_cast(o)) { -+ const int cnt = toolw->count(); -+ for (int i = 0; i < cnt; ++i) { -+ RETRANSLATE_SUBWIDGET_PROP(toolw, setItemText, PROP_TOOLITEMTEXT); -+#if QT_CONFIG(tooltip) -+ RETRANSLATE_SUBWIDGET_PROP(toolw, setItemToolTip, PROP_TOOLITEMTOOLTIP); -+# endif -+ } -+#endif -+ } -+ } -+ return false; -+ } -+ -+private: -+ QByteArray m_className; -+ bool m_idBased; -+}; -+ -+class FormBuilderPrivate: public QFormBuilder -+{ -+ friend class QT_PREPEND_NAMESPACE(QUiLoader); -+ friend class QT_PREPEND_NAMESPACE(QUiLoaderPrivate); -+ using ParentClass = QFormBuilder; -+ -+public: -+ QUiLoader *loader = nullptr; -+ -+ bool dynamicTr = false; -+ bool trEnabled = true; -+ -+ FormBuilderPrivate() = default; -+ -+ QWidget *defaultCreateWidget(const QString &className, QWidget *parent, const QString &name) -+ { -+ return ParentClass::createWidget(className, parent, name); -+ } -+ -+ QLayout *defaultCreateLayout(const QString &className, QObject *parent, const QString &name) -+ { -+ return ParentClass::createLayout(className, parent, name); -+ } -+ -+ QAction *defaultCreateAction(QObject *parent, const QString &name) -+ { -+ return ParentClass::createAction(parent, name); -+ } -+ -+ QActionGroup *defaultCreateActionGroup(QObject *parent, const QString &name) -+ { -+ return ParentClass::createActionGroup(parent, name); -+ } -+ -+ QWidget *createWidget(const QString &className, QWidget *parent, const QString &name) override -+ { -+ if (QWidget *widget = loader->createWidget(className, parent, name)) { -+ widget->setObjectName(name); -+ return widget; -+ } -+ -+ return nullptr; -+ } -+ -+ QLayout *createLayout(const QString &className, QObject *parent, const QString &name) override -+ { -+ if (QLayout *layout = loader->createLayout(className, parent, name)) { -+ layout->setObjectName(name); -+ return layout; -+ } -+ -+ return nullptr; -+ } -+ -+ QActionGroup *createActionGroup(QObject *parent, const QString &name) override -+ { -+ if (QActionGroup *actionGroup = loader->createActionGroup(parent, name)) { -+ actionGroup->setObjectName(name); -+ return actionGroup; -+ } -+ -+ return nullptr; -+ } -+ -+ QAction *createAction(QObject *parent, const QString &name) override -+ { -+ if (QAction *action = loader->createAction(parent, name)) { -+ action->setObjectName(name); -+ return action; -+ } -+ -+ return nullptr; -+ } -+ -+ void applyProperties(QObject *o, const QList &properties) override; -+ QWidget *create(DomUI *ui, QWidget *parentWidget) override; -+ QWidget *create(DomWidget *ui_widget, QWidget *parentWidget) override; -+ bool addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget) override; -+ -+private: -+ QByteArray m_class; -+ TranslationWatcher *m_trwatch = nullptr; -+ bool m_idBased = false; -+}; -+ -+static QString convertTranslatable(const DomProperty *p, const QByteArray &className, -+ bool idBased, QUiTranslatableStringValue *strVal) -+{ -+ if (p->kind() != DomProperty::String) -+ return QString(); -+ const DomString *dom_str = p->elementString(); -+ if (!dom_str) -+ return QString(); -+ if (dom_str->hasAttributeNotr()) { -+ const QString notr = dom_str->attributeNotr(); -+ if (notr == QStringLiteral("yes") || notr == QStringLiteral("true")) -+ return QString(); -+ } -+ strVal->setValue(dom_str->text().toUtf8()); -+ strVal->setQualifier(idBased ? dom_str->attributeId().toUtf8() : dom_str->attributeComment().toUtf8()); -+ if (strVal->value().isEmpty() && strVal->qualifier().isEmpty()) -+ return QString(); -+ return strVal->translate(className, idBased); -+} -+ -+void FormBuilderPrivate::applyProperties(QObject *o, const QList &properties) -+{ -+ QFormBuilder::applyProperties(o, properties); -+ -+ if (!m_trwatch) -+ m_trwatch = new TranslationWatcher(o, m_class, m_idBased); -+ -+ if (properties.isEmpty()) -+ return; -+ -+ // Unlike string item roles, string properties are not loaded via the textBuilder -+ // (as they are "shadowed" by the property sheets in designer). So do the initial -+ // translation here. -+ bool anyTrs = false; -+ for (const DomProperty *p : properties) { -+ QUiTranslatableStringValue strVal; -+ const QString text = convertTranslatable(p, m_class, m_idBased, &strVal); -+ if (text.isEmpty()) -+ continue; -+ const QByteArray name = p->attributeName().toUtf8(); -+ if (dynamicTr) { -+ const QByteArray dynname = QByteArray(PROP_GENERIC_PREFIX + name); -+ o->setProperty(dynname, QVariant::fromValue(strVal)); -+ anyTrs = trEnabled; -+ } -+ if (p->elementString()->text() != text) -+ o->setProperty(name, text); -+ } -+ if (anyTrs) -+ o->installEventFilter(m_trwatch); -+} -+ -+QWidget *FormBuilderPrivate::create(DomUI *ui, QWidget *parentWidget) -+{ -+ m_class = ui->elementClass().toUtf8(); -+ m_trwatch = nullptr; -+ m_idBased = ui->attributeIdbasedtr(); -+ setTextBuilder(new TranslatingTextBuilder(m_idBased, trEnabled, m_class)); -+ return QFormBuilder::create(ui, parentWidget); -+} -+ -+QWidget *FormBuilderPrivate::create(DomWidget *ui_widget, QWidget *parentWidget) -+{ -+ QWidget *w = QFormBuilder::create(ui_widget, parentWidget); -+ if (w == nullptr) -+ return nullptr; -+ -+ if (0) { -+#if QT_CONFIG(tabwidget) -+ } else if (qobject_cast(w)) { -+#endif -+#if QT_CONFIG(listwidget) -+ } else if (qobject_cast(w)) { -+#endif -+#if QT_CONFIG(treewidget) -+ } else if (qobject_cast(w)) { -+#endif -+#if QT_CONFIG(tablewidget) -+ } else if (qobject_cast(w)) { -+#endif -+#if QT_CONFIG(combobox) -+ } else if (qobject_cast(w)) { -+ if (qobject_cast(w)) -+ return w; -+#endif -+#if QT_CONFIG(toolbox) -+ } else if (qobject_cast(w)) { -+#endif -+ } else { -+ return w; -+ } -+ if (dynamicTr && trEnabled) -+ w->installEventFilter(m_trwatch); -+ return w; -+} -+ -+#define TRANSLATE_SUBWIDGET_PROP(mainWidget, attribute, setter, propName) \ -+ do { \ -+ if (const DomProperty *p##attribute = attributes.value(strings.attribute)) { \ -+ QUiTranslatableStringValue strVal; \ -+ const QString text = convertTranslatable(p##attribute, m_class, m_idBased, &strVal); \ -+ if (!text.isEmpty()) { \ -+ if (dynamicTr) \ -+ mainWidget->widget(i)->setProperty(propName, QVariant::fromValue(strVal)); \ -+ mainWidget->setter(i, text); \ -+ } \ -+ } \ -+ } while (0) -+ -+bool FormBuilderPrivate::addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget) -+{ -+ if (parentWidget == nullptr) -+ return true; -+ -+ if (!ParentClass::addItem(ui_widget, widget, parentWidget)) -+ return false; -+ -+ // Check special cases. First: Custom container -+ const QString className = QLatin1String(parentWidget->metaObject()->className()); -+ if (!d->customWidgetAddPageMethod(className).isEmpty()) -+ return true; -+ -+ const QFormBuilderStrings &strings = QFormBuilderStrings::instance(); -+ -+ if (0) { -+#if QT_CONFIG(tabwidget) -+ } else if (QTabWidget *tabWidget = qobject_cast(parentWidget)) { -+ const DomPropertyHash attributes = propertyMap(ui_widget->elementAttribute()); -+ const int i = tabWidget->count() - 1; -+ TRANSLATE_SUBWIDGET_PROP(tabWidget, titleAttribute, setTabText, PROP_TABPAGETEXT); -+#if QT_CONFIG(tooltip) -+ TRANSLATE_SUBWIDGET_PROP(tabWidget, toolTipAttribute, setTabToolTip, PROP_TABPAGETOOLTIP); -+# endif -+#if QT_CONFIG(whatsthis) -+ TRANSLATE_SUBWIDGET_PROP(tabWidget, whatsThisAttribute, setTabWhatsThis, PROP_TABPAGEWHATSTHIS); -+# endif -+#endif -+#if QT_CONFIG(toolbox) -+ } else if (QToolBox *toolBox = qobject_cast(parentWidget)) { -+ const DomPropertyHash attributes = propertyMap(ui_widget->elementAttribute()); -+ const int i = toolBox->count() - 1; -+ TRANSLATE_SUBWIDGET_PROP(toolBox, labelAttribute, setItemText, PROP_TOOLITEMTEXT); -+#if QT_CONFIG(tooltip) -+ TRANSLATE_SUBWIDGET_PROP(toolBox, toolTipAttribute, setItemToolTip, PROP_TOOLITEMTOOLTIP); -+# endif -+#endif -+ } -+ -+ return true; -+} -+ -+#ifdef QFORMINTERNAL_NAMESPACE -+} -+#endif -+ -+class QUiLoaderPrivate -+{ -+public: -+#ifdef QFORMINTERNAL_NAMESPACE -+ QFormInternal::FormBuilderPrivate builder; -+#else -+ FormBuilderPrivate builder; -+#endif -+ -+ void setupWidgetMap() const; -+}; -+ -+void QUiLoaderPrivate::setupWidgetMap() const -+{ -+ if (!g_widgets()->isEmpty()) -+ return; -+ -+#define DECLARE_WIDGET(a, b) g_widgets()->insert(QLatin1String(#a), true); -+#define DECLARE_LAYOUT(a, b) -+ -+#include "widgets.table" -+ -+#undef DECLARE_WIDGET -+#undef DECLARE_WIDGET_1 -+#undef DECLARE_LAYOUT -+} -+ -+/*! -+ \class QUiLoader -+ \inmodule QtUiTools -+ -+ \brief The QUiLoader class enables standalone applications to -+ dynamically create user interfaces at run-time using the -+ information stored in UI files or specified in plugin paths. -+ -+ In addition, you can customize or create your own user interface by -+ deriving your own loader class. -+ -+ If you have a custom component or an application that embeds \QD, you can -+ also use the QFormBuilder class provided by the QtDesigner module to create -+ user interfaces from UI files. -+ -+ The QUiLoader class provides a collection of functions allowing you to -+ create widgets based on the information stored in UI files (created -+ with \QD) or available in the specified plugin paths. The specified plugin -+ paths can be retrieved using the pluginPaths() function. Similarly, the -+ contents of a UI file can be retrieved using the load() function. For -+ example: -+ -+ \snippet quiloader/mywidget.cpp 0 -+ -+ \if !defined(qtforpython) -+ By including the user interface in the form's resources (\c myform.qrc), we -+ ensure that it will be present at run-time: -+ -+ \quotefile quiloader/mywidget.qrc -+ \endif -+ -+ The availableWidgets() function returns a QStringList with the class names -+ of the widgets available in the specified plugin paths. To create these -+ widgets, simply use the createWidget() function. For example: -+ -+ \snippet quiloader/main.cpp 0 -+ -+ To make a custom widget available to the loader, you can use the -+ addPluginPath() function; to remove all available widgets, you can call -+ the clearPluginPaths() function. -+ -+ The createAction(), createActionGroup(), createLayout(), and createWidget() -+ functions are used internally by the QUiLoader class whenever it has to -+ create an action, action group, layout, or widget respectively. For that -+ reason, you can subclass the QUiLoader class and reimplement these -+ functions to intervene the process of constructing a user interface. For -+ example, you might want to have a list of the actions created when loading -+ a form or creating a custom widget. -+ -+ For a complete example using the QUiLoader class, see the -+ \l{Calculator Builder Example}. -+ -+ \sa {Qt UI Tools}, QFormBuilder -+*/ -+ -+/*! -+ Creates a form loader with the given \a parent. -+*/ -+QUiLoader::QUiLoader(QObject *parent) -+ : QObject(parent), d_ptr(new QUiLoaderPrivate) -+{ -+ Q_D(QUiLoader); -+ -+#ifndef QT_NO_DATASTREAM -+ static int metaTypeId = 0; -+ if (!metaTypeId) { -+ metaTypeId = qRegisterMetaType("QUiTranslatableStringValue"); -+ } -+#endif // QT_NO_DATASTREAM -+ d->builder.loader = this; -+ -+#if QT_CONFIG(library) -+ QStringList paths; -+ const QStringList &libraryPaths = QApplication::libraryPaths(); -+ for (const QString &path : libraryPaths) { -+ QString libPath = path; -+ libPath += QDir::separator(); -+ libPath += QStringLiteral("designer"); -+ paths.append(libPath); -+ } -+ -+ d->builder.setPluginPath(paths); -+#endif // QT_CONFIG(library) -+} -+ -+/*! -+ Destroys the loader. -+*/ -+QUiLoader::~QUiLoader() = default; -+ -+/*! -+ Loads a form from the given \a device and creates a new widget with the -+ given \a parentWidget to hold its contents. -+ -+ \sa createWidget(), errorString() -+*/ -+QWidget *QUiLoader::load(QIODevice *device, QWidget *parentWidget) -+{ -+ Q_D(QUiLoader); -+ // QXmlStreamReader will report errors on open failure. -+ if (!device->isOpen()) -+ device->open(QIODevice::ReadOnly|QIODevice::Text); -+ return d->builder.load(device, parentWidget); -+} -+ -+/*! -+ Returns a list naming the paths in which the loader will search when -+ locating custom widget plugins. -+ -+ \sa addPluginPath(), clearPluginPaths() -+*/ -+QStringList QUiLoader::pluginPaths() const -+{ -+ Q_D(const QUiLoader); -+ return d->builder.pluginPaths(); -+} -+ -+/*! -+ Clears the list of paths in which the loader will search when locating -+ plugins. -+ -+ \sa addPluginPath(), pluginPaths() -+*/ -+void QUiLoader::clearPluginPaths() -+{ -+ Q_D(QUiLoader); -+ d->builder.clearPluginPaths(); -+} -+ -+/*! -+ Adds the given \a path to the list of paths in which the loader will search -+ when locating plugins. -+ -+ \sa pluginPaths(), clearPluginPaths() -+*/ -+void QUiLoader::addPluginPath(const QString &path) -+{ -+ Q_D(QUiLoader); -+ d->builder.addPluginPath(path); -+} -+ -+/*! -+ Creates a new widget with the given \a parent and \a name using the class -+ specified by \a className. You can use this function to create any of the -+ widgets returned by the availableWidgets() function. -+ -+ The function is also used internally by the QUiLoader class whenever it -+ creates a widget. Hence, you can subclass QUiLoader and reimplement this -+ function to intervene process of constructing a user interface or widget. -+ However, in your implementation, ensure that you call QUiLoader's version -+ first. -+ -+ \sa availableWidgets(), load() -+*/ -+QWidget *QUiLoader::createWidget(const QString &className, QWidget *parent, const QString &name) -+{ -+ Q_D(QUiLoader); -+ return d->builder.defaultCreateWidget(className, parent, name); -+} -+ -+/*! -+ Creates a new layout with the given \a parent and \a name using the class -+ specified by \a className. -+ -+ The function is also used internally by the QUiLoader class whenever it -+ creates a widget. Hence, you can subclass QUiLoader and reimplement this -+ function to intervene process of constructing a user interface or widget. -+ However, in your implementation, ensure that you call QUiLoader's version -+ first. -+ -+ \sa createWidget(), load() -+*/ -+QLayout *QUiLoader::createLayout(const QString &className, QObject *parent, const QString &name) -+{ -+ Q_D(QUiLoader); -+ return d->builder.defaultCreateLayout(className, parent, name); -+} -+ -+/*! -+ Creates a new action group with the given \a parent and \a name. -+ -+ The function is also used internally by the QUiLoader class whenever it -+ creates a widget. Hence, you can subclass QUiLoader and reimplement this -+ function to intervene process of constructing a user interface or widget. -+ However, in your implementation, ensure that you call QUiLoader's version -+ first. -+ -+ \sa createAction(), createWidget(), load() -+ */ -+QActionGroup *QUiLoader::createActionGroup(QObject *parent, const QString &name) -+{ -+ Q_D(QUiLoader); -+ return d->builder.defaultCreateActionGroup(parent, name); -+} -+ -+/*! -+ Creates a new action with the given \a parent and \a name. -+ -+ The function is also used internally by the QUiLoader class whenever it -+ creates a widget. Hence, you can subclass QUiLoader and reimplement this -+ function to intervene process of constructing a user interface or widget. -+ However, in your implementation, ensure that you call QUiLoader's version -+ first. -+ -+ \sa createActionGroup(), createWidget(), load() -+*/ -+QAction *QUiLoader::createAction(QObject *parent, const QString &name) -+{ -+ Q_D(QUiLoader); -+ return d->builder.defaultCreateAction(parent, name); -+} -+ -+/*! -+ Returns a list naming all available widgets that can be built using the -+ createWidget() function, i.e all the widgets specified within the given -+ plugin paths. -+ -+ \sa pluginPaths(), createWidget() -+ -+*/ -+QStringList QUiLoader::availableWidgets() const -+{ -+ Q_D(const QUiLoader); -+ -+ d->setupWidgetMap(); -+ widget_map available = *g_widgets(); -+ -+ const auto &customWidgets = d->builder.customWidgets(); -+ for (QDesignerCustomWidgetInterface *plugin : customWidgets) -+ available.insert(plugin->name(), true); -+ -+ return available.keys(); -+} -+ -+ -+/*! -+ \since 4.5 -+ Returns a list naming all available layouts that can be built using the -+ createLayout() function -+ -+ \sa createLayout() -+*/ -+ -+QStringList QUiLoader::availableLayouts() const -+{ -+ QStringList rc; -+#define DECLARE_WIDGET(a, b) -+#define DECLARE_LAYOUT(a, b) rc.push_back(QLatin1String(#a)); -+ -+#include "widgets.table" -+ -+#undef DECLARE_WIDGET -+#undef DECLARE_LAYOUT -+ return rc; -+} -+ -+/*! -+ Sets the working directory of the loader to \a dir. The loader will look -+ for other resources, such as icons and resource files, in paths relative to -+ this directory. -+ -+ \sa workingDirectory() -+*/ -+ -+void QUiLoader::setWorkingDirectory(const QDir &dir) -+{ -+ Q_D(QUiLoader); -+ d->builder.setWorkingDirectory(dir); -+} -+ -+/*! -+ Returns the working directory of the loader. -+ -+ \sa setWorkingDirectory() -+*/ -+ -+QDir QUiLoader::workingDirectory() const -+{ -+ Q_D(const QUiLoader); -+ return d->builder.workingDirectory(); -+} -+/*! -+ \since 4.5 -+ -+ If \a enabled is true, user interfaces loaded by this loader will -+ automatically retranslate themselves upon receiving a language change -+ event. Otherwise, the user interfaces will not be retranslated. -+ -+ \sa isLanguageChangeEnabled() -+*/ -+ -+void QUiLoader::setLanguageChangeEnabled(bool enabled) -+{ -+ Q_D(QUiLoader); -+ d->builder.dynamicTr = enabled; -+} -+ -+/*! -+ \since 4.5 -+ -+ Returns true if dynamic retranslation on language change is enabled; -+ returns false otherwise. -+ -+ \sa setLanguageChangeEnabled() -+*/ -+ -+bool QUiLoader::isLanguageChangeEnabled() const -+{ -+ Q_D(const QUiLoader); -+ return d->builder.dynamicTr; -+} -+ -+/*! -+ \internal -+ \since 4.5 -+ -+ If \a enabled is true, user interfaces loaded by this loader will be -+ translated. Otherwise, the user interfaces will not be translated. -+ -+ \note This is orthogonal to languageChangeEnabled. -+ -+ \sa isLanguageChangeEnabled(), setLanguageChangeEnabled() -+*/ -+ -+void QUiLoader::setTranslationEnabled(bool enabled) -+{ -+ Q_D(QUiLoader); -+ d->builder.trEnabled = enabled; -+} -+ -+/*! -+ \internal -+ \since 4.5 -+ -+ Returns true if translation is enabled; returns false otherwise. -+ -+ \sa setTranslationEnabled() -+*/ -+ -+bool QUiLoader::isTranslationEnabled() const -+{ -+ Q_D(const QUiLoader); -+ return d->builder.trEnabled; -+} -+ -+/*! -+ Returns a human-readable description of the last error occurred in load(). -+ -+ \since 5.0 -+ \sa load() -+*/ -+ -+QString QUiLoader::errorString() const -+{ -+ Q_D(const QUiLoader); -+ return d->builder.errorString(); -+} -+ -+QT_END_NAMESPACE -+ -+#include "quiloader.moc" -diff --git x/qttools/src/designer/src/uitools/quiloader.h y/qttools/src/designer/src/uitools/quiloader.h -new file mode 100644 -index 000000000..742b5606f ---- /dev/null -+++ y/qttools/src/designer/src/uitools/quiloader.h -@@ -0,0 +1,61 @@ -+// Copyright (C) 2020 The Qt Company Ltd. -+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only -+ -+#ifndef QUILOADER_H -+#define QUILOADER_H -+ -+#include -+#include -+#include -+ -+QT_BEGIN_NAMESPACE -+ -+class QWidget; -+class QLayout; -+class QAction; -+class QActionGroup; -+class QString; -+class QIODevice; -+class QDir; -+ -+class QUiLoaderPrivate; -+class Q_UITOOLS_EXPORT QUiLoader : public QObject -+{ -+ Q_OBJECT -+public: -+ explicit QUiLoader(QObject *parent = nullptr); -+ ~QUiLoader() override; -+ -+ QStringList pluginPaths() const; -+ void clearPluginPaths(); -+ void addPluginPath(const QString &path); -+ -+ QWidget *load(QIODevice *device, QWidget *parentWidget = nullptr); -+ QStringList availableWidgets() const; -+ QStringList availableLayouts() const; -+ -+ virtual QWidget *createWidget(const QString &className, QWidget *parent = nullptr, const QString &name = QString()); -+ virtual QLayout *createLayout(const QString &className, QObject *parent = nullptr, const QString &name = QString()); -+ virtual QActionGroup *createActionGroup(QObject *parent = nullptr, const QString &name = QString()); -+ virtual QAction *createAction(QObject *parent = nullptr, const QString &name = QString()); -+ -+ void setWorkingDirectory(const QDir &dir); -+ QDir workingDirectory() const; -+ -+ void setLanguageChangeEnabled(bool enabled); -+ bool isLanguageChangeEnabled() const; -+ -+ void setTranslationEnabled(bool enabled); -+ bool isTranslationEnabled() const; -+ -+ QString errorString() const; -+ -+private: -+ QScopedPointer d_ptr; -+ Q_DECLARE_PRIVATE(QUiLoader) -+ Q_DISABLE_COPY_MOVE(QUiLoader) -+}; -+ -+QT_END_NAMESPACE -+ -+#endif // QUILOADER_H -diff --git x/qttools/src/designer/src/uitools/quiloader_p.h y/qttools/src/designer/src/uitools/quiloader_p.h -new file mode 100644 -index 000000000..efd943217 ---- /dev/null -+++ y/qttools/src/designer/src/uitools/quiloader_p.h -@@ -0,0 +1,77 @@ -+// Copyright (C) 2020 The Qt Company Ltd. -+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only -+ -+#ifndef QUILOADER_P_H -+#define QUILOADER_P_H -+ -+// -+// W A R N I N G -+// ------------- -+// -+// This file is not part of the Qt API. It exists purely as an -+// implementation detail. This header file may change from version to -+// version without notice, or even be removed. -+// -+// We mean it. -+// -+ -+#include -+#include -+#include -+ -+QT_FORWARD_DECLARE_CLASS(QDataStream) -+ -+// This file is here for use by the form preview in Linguist. If you change anything -+// here or in the code which uses it, remember to adapt Linguist accordingly. -+ -+#define PROP_GENERIC_PREFIX "_q_notr_" -+#define PROP_TOOLITEMTEXT "_q_toolItemText_notr" -+#define PROP_TOOLITEMTOOLTIP "_q_toolItemToolTip_notr" -+#define PROP_TABPAGETEXT "_q_tabPageText_notr" -+#define PROP_TABPAGETOOLTIP "_q_tabPageToolTip_notr" -+#define PROP_TABPAGEWHATSTHIS "_q_tabPageWhatsThis_notr" -+ -+QT_BEGIN_NAMESPACE -+ -+class Q_UITOOLS_EXPORT QUiTranslatableStringValue -+{ -+public: -+ QByteArray value() const { return m_value; } -+ void setValue(const QByteArray &value) { m_value = value; } -+ QByteArray qualifier() const { return m_qualifier; } -+ void setQualifier(const QByteArray &qualifier) { m_qualifier = qualifier; } -+ -+ QString translate(const QByteArray &className, bool idBased) const; -+ -+private: -+ QByteArray m_value; -+ QByteArray m_qualifier; // Comment or ID for id-based tr(). -+}; -+ -+#ifndef QT_NO_DATASTREAM -+Q_UITOOLS_EXPORT QDataStream &operator<<(QDataStream &out, const QUiTranslatableStringValue &s); -+Q_UITOOLS_EXPORT QDataStream &operator>>(QDataStream &in, QUiTranslatableStringValue &s); -+#endif // QT_NO_DATASTREAM -+ -+struct QUiItemRolePair { -+ int realRole; -+ int shadowRole; -+}; -+ -+#ifdef QFORMINTERNAL_NAMESPACE -+namespace QFormInternal -+{ -+#endif -+ -+extern const Q_UITOOLS_EXPORT QUiItemRolePair qUiItemRoles[]; -+ -+#ifdef QFORMINTERNAL_NAMESPACE -+} -+#endif -+ -+QT_END_NAMESPACE -+ -+Q_DECLARE_METATYPE(QUiTranslatableStringValue) -+ -+ -+#endif // QUILOADER_P_H -diff --git x/qttools/src/uiplugin/CMakeLists.txt y/qttools/src/uiplugin/CMakeLists.txt -deleted file mode 100644 -index 4fedf8e33..000000000 ---- x/qttools/src/uiplugin/CMakeLists.txt -+++ /dev/null -@@ -1,27 +0,0 @@ --# Generated from uiplugin.pro. -- --##################################################################### --## UiPlugin Module: --##################################################################### -- --qt_internal_add_module(UiPlugin -- NO_PRIVATE_MODULE -- HEADER_MODULE -- QMAKE_MODULE_CONFIG designer_defines -- PUBLIC_LIBRARIES -- Qt::Core -- Qt::Gui -- Qt::Widgets --) -- --# special case begin --set(is_plugin "$") --target_compile_definitions( -- UiPlugin -- INTERFACE -- $<$:QDESIGNER_EXPORT_WIDGETS> --) --# special case end -- --#### Keys ignored in scope 1:.:.:uiplugin.pro:: --# MODULE_CONFIG = "designer_defines" -diff --git x/qttools/src/uiplugin/customwidget.h y/qttools/src/uiplugin/customwidget.h -deleted file mode 100644 -index 2a47a32f8..000000000 ---- x/qttools/src/uiplugin/customwidget.h -+++ /dev/null -@@ -1,62 +0,0 @@ --// Copyright (C) 2016 The Qt Company Ltd. --// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -- --#ifndef CUSTOMWIDGET_H --#define CUSTOMWIDGET_H -- --#include --#include --#include -- --QT_BEGIN_NAMESPACE -- --class QWidget; --class QDesignerFormEditorInterface; -- --class QDesignerCustomWidgetInterface --{ --public: -- virtual ~QDesignerCustomWidgetInterface() = default; // ### FIXME: weak vtable -- -- virtual QString name() const = 0; -- virtual QString group() const = 0; -- virtual QString toolTip() const = 0; -- virtual QString whatsThis() const = 0; -- virtual QString includeFile() const = 0; -- virtual QIcon icon() const = 0; -- -- virtual bool isContainer() const = 0; -- -- virtual QWidget *createWidget(QWidget *parent) = 0; -- -- virtual bool isInitialized() const { return false; } -- virtual void initialize(QDesignerFormEditorInterface *core) { Q_UNUSED(core); } -- -- virtual QString domXml() const -- { -- return QString::fromUtf8("") -- .arg(name()).arg(name().toLower()); -- } -- -- virtual QString codeTemplate() const { return QString(); } --}; -- --#define QDesignerCustomWidgetInterface_iid "org.qt-project.QDesignerCustomWidgetInterface" -- --Q_DECLARE_INTERFACE(QDesignerCustomWidgetInterface, QDesignerCustomWidgetInterface_iid) -- --class QDesignerCustomWidgetCollectionInterface --{ --public: -- virtual ~QDesignerCustomWidgetCollectionInterface() = default; // ### FIXME: weak vtable -- -- virtual QList customWidgets() const = 0; --}; -- --#define QDesignerCustomWidgetCollectionInterface_iid "org.qt-project.Qt.QDesignerCustomWidgetCollectionInterface" -- --Q_DECLARE_INTERFACE(QDesignerCustomWidgetCollectionInterface, QDesignerCustomWidgetCollectionInterface_iid) -- --QT_END_NAMESPACE -- --#endif // CUSTOMWIDGET_H -diff --git x/qttools/src/uiplugin/customwidget.qdoc y/qttools/src/uiplugin/customwidget.qdoc -deleted file mode 100644 -index 557e9a454..000000000 ---- x/qttools/src/uiplugin/customwidget.qdoc -+++ /dev/null -@@ -1,269 +0,0 @@ --// Copyright (C) 2016 The Qt Company Ltd. --// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only -- --/*! -- \class QDesignerCustomWidgetInterface -- -- \brief The QDesignerCustomWidgetInterface class enables Qt Designer -- to access and construct custom widgets. -- -- \inmodule QtDesigner -- -- QDesignerCustomWidgetInterface provides a custom widget with an -- interface. The class contains a set of functions that must be subclassed -- to return basic information about the widget, such as its class name and -- the name of its header file. Other functions must be implemented to -- initialize the plugin when it is loaded, and to construct instances of -- the custom widget for \QD to use. -- -- When implementing a custom widget you must subclass -- QDesignerCustomWidgetInterface to expose your widget to \QD. For -- example, this is the declaration for the plugin used in the -- \l{Custom Widget Plugin Example}{Custom Widget Plugin example} that -- enables an analog clock custom widget to be used by \QD: -- -- \snippet customwidgetplugin/customwidgetplugin.h 0 -- -- Note that the only part of the class definition that is specific -- to this particular custom widget is the class name. In addition, -- since we are implementing an interface, we must ensure that it's -- made known to the meta object system using the Q_INTERFACES() -- macro. This enables \QD to use the qobject_cast() function to -- query for supported interfaces using nothing but a QObject -- pointer. -- -- After \QD loads a custom widget plugin, it calls the interface's -- initialize() function to enable it to set up any resources that it -- may need. This function is called with a QDesignerFormEditorInterface -- parameter that provides the plugin with a gateway to all of \QD's API. -- -- \QD constructs instances of the custom widget by calling the plugin's -- createWidget() function with a suitable parent widget. Plugins must -- construct and return an instance of a custom widget with the specified -- parent widget. -- -- Exporting your custom widget plugin to \QD using the Q_PLUGIN_METADATA() -- macro. For example, if a library called \c libcustomwidgetplugin.so -- (on Unix) or \c libcustomwidget.dll (on Windows) contains a widget -- class called \c MyCustomWidget, we can export it by adding the -- following line to the file containing the plugin header: -- -- \snippet plugins/doc_src_qtdesigner.cpp 14 -- -- This macro ensures that \QD can access and construct the custom widget. -- Without this macro, there is no way for \QD to use it. -- -- When implementing a custom widget plugin, you build it as a -- separate library. If you want to include several custom widget -- plugins in the same library, you must in addition subclass -- QDesignerCustomWidgetCollectionInterface. -- -- \warning If your custom widget plugin contains QVariant -- properties, be aware that only the following \l -- {QVariant::Type}{types} are supported: -- -- \list -- \li QVariant::ByteArray -- \li QVariant::Bool -- \li QVariant::Color -- \li QVariant::Cursor -- \li QVariant::Date -- \li QVariant::DateTime -- \li QVariant::Double -- \li QVariant::Int -- \li QVariant::Point -- \li QVariant::Rect -- \li QVariant::Size -- \li QVariant::SizePolicy -- \li QVariant::String -- \li QVariant::Time -- \li QVariant::UInt -- \endlist -- -- For a complete example using the QDesignerCustomWidgetInterface -- class, see the \l {customwidgetplugin}{Custom Widget -- Example}. The example shows how to create a custom widget plugin -- for \QD. -- -- \sa QDesignerCustomWidgetCollectionInterface, {Creating Custom Widgets for Qt Designer} --*/ -- --/*! -- \fn QDesignerCustomWidgetInterface::~QDesignerCustomWidgetInterface() -- -- Destroys the custom widget interface. --*/ -- --/*! -- \fn QString QDesignerCustomWidgetInterface::name() const -- -- Returns the class name of the custom widget supplied by the interface. -- -- The name returned \e must be identical to the class name used for the -- custom widget. --*/ -- --/*! -- \fn QString QDesignerCustomWidgetInterface::group() const -- -- Returns the name of the group to which the custom widget belongs. --*/ -- --/*! -- \fn QString QDesignerCustomWidgetInterface::toolTip() const -- -- Returns a short description of the widget that can be used by \QD -- in a tool tip. --*/ -- --/*! -- \fn QString QDesignerCustomWidgetInterface::whatsThis() const -- -- Returns a description of the widget that can be used by \QD in -- "What's This?" help for the widget. --*/ -- --/*! -- \fn QString QDesignerCustomWidgetInterface::includeFile() const -- -- Returns the path to the include file that \l uic uses when -- creating code for the custom widget. --*/ -- --/*! -- \fn QIcon QDesignerCustomWidgetInterface::icon() const -- -- Returns the icon used to represent the custom widget in \QD's -- widget box. --*/ -- --/*! -- \fn bool QDesignerCustomWidgetInterface::isContainer() const -- -- Returns true if the custom widget is intended to be used as a -- container; otherwise returns false. -- -- Most custom widgets are not used to hold other widgets, so their -- implementations of this function will return false, but custom -- containers will return true to ensure that they behave correctly -- in \QD. --*/ -- --/*! -- \fn QWidget *QDesignerCustomWidgetInterface::createWidget(QWidget *parent) -- -- Returns a new instance of the custom widget, with the given \a -- parent. --*/ -- --/*! -- \fn bool QDesignerCustomWidgetInterface::isInitialized() const -- -- Returns true if the widget has been initialized; otherwise returns -- false. -- -- \sa initialize() --*/ -- --/*! -- \fn void QDesignerCustomWidgetInterface::initialize(QDesignerFormEditorInterface *formEditor) -- -- Initializes the widget for use with the specified \a formEditor -- interface. -- -- \sa isInitialized() --*/ -- --/*! -- \fn QString QDesignerCustomWidgetInterface::domXml() const -- -- Returns the XML that is used to describe the custom widget's -- properties to \QD. --*/ -- --/*! -- \fn QString QDesignerCustomWidgetInterface::codeTemplate() const -- -- This function is reserved for future use by \QD. -- -- \omit -- Returns the code template that \QD includes in forms that contain -- the custom widget when they are saved. -- \endomit --*/ -- --/*! -- \macro QDESIGNER_WIDGET_EXPORT -- \relates QDesignerCustomWidgetInterface -- \since 4.1 -- -- This macro is used when defining custom widgets to ensure that they are -- correctly exported from plugins for use with \QD. -- -- On some platforms, the symbols required by \QD to create new widgets -- are removed from plugins by the build system, making them unusable. -- Using this macro ensures that the symbols are retained on those platforms, -- and has no side effects on other platforms. -- -- For example, the \l{worldtimeclockplugin}{World Time Clock Plugin} -- example exports a custom widget class with the following declaration: -- -- \snippet worldtimeclockplugin/worldtimeclock.h 0 -- \dots -- \snippet worldtimeclockplugin/worldtimeclock.h 2 -- -- \sa {Creating Custom Widgets for Qt Designer} --*/ -- -- -- -- -- --/*! -- \class QDesignerCustomWidgetCollectionInterface -- -- \brief The QDesignerCustomWidgetCollectionInterface class allows -- you to include several custom widgets in one single library. -- -- \inmodule QtDesigner -- -- When implementing a custom widget plugin, you build it as a -- separate library. If you want to include several custom widget -- plugins in the same library, you must in addition subclass -- QDesignerCustomWidgetCollectionInterface. -- -- QDesignerCustomWidgetCollectionInterface contains one single -- function returning a list of the collection's -- QDesignerCustomWidgetInterface objects. For example, if you have -- several custom widgets \c CustomWidgetOne, \c CustomWidgetTwo and -- \c CustomWidgetThree, the class definition may look like this: -- -- \snippet plugins/doc_src_qtdesigner.cpp 12 -- -- In the class constructor you add the interfaces to your custom -- widgets to the list which you return in the customWidgets() -- function: -- -- \snippet plugins/doc_src_qtdesigner.cpp 13 -- -- Note that instead of exporting each custom widget plugin using the -- Q_PLUGIN_METADATA() macro, you export the entire collection. The -- Q_PLUGIN_METADATA() macro ensures that \QD can access and construct -- the custom widgets. Without this macro, there is no way for \QD to -- use them. -- -- \sa QDesignerCustomWidgetInterface, {Creating Custom Widgets for -- Qt Designer} --*/ -- --/*! -- \fn QDesignerCustomWidgetCollectionInterface::~QDesignerCustomWidgetCollectionInterface() { -- -- Destroys the custom widget collection interface. --*/ -- --/*! -- \fn QList QDesignerCustomWidgetCollectionInterface::customWidgets() const -- -- Returns a list of interfaces to the collection's custom widgets. --*/ -diff --git x/qttools/src/uiplugin/qdesignerexportwidget.h y/qttools/src/uiplugin/qdesignerexportwidget.h -deleted file mode 100644 -index d90e9b217..000000000 ---- x/qttools/src/uiplugin/qdesignerexportwidget.h -+++ /dev/null -@@ -1,24 +0,0 @@ --// Copyright (C) 2016 The Qt Company Ltd. --// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -- --#ifndef QDESIGNEREXPORTWIDGET_H --#define QDESIGNEREXPORTWIDGET_H -- --#include -- --QT_BEGIN_NAMESPACE -- --#if 0 --// pragma for syncqt, don't remove. --#pragma qt_class(QDesignerExportWidget) --#endif -- --#if defined(QDESIGNER_EXPORT_WIDGETS) --# define QDESIGNER_WIDGET_EXPORT Q_DECL_EXPORT --#else --# define QDESIGNER_WIDGET_EXPORT Q_DECL_IMPORT --#endif -- --QT_END_NAMESPACE -- --#endif //QDESIGNEREXPORTWIDGET_H -diff --git x/qttools/src/uitools/CMakeLists.txt y/qttools/src/uitools/CMakeLists.txt -deleted file mode 100644 -index 448bd1840..000000000 ---- x/qttools/src/uitools/CMakeLists.txt -+++ /dev/null -@@ -1,47 +0,0 @@ --# Generated from uitools.pro. -- --##################################################################### --## UiTools Module: --##################################################################### -- --qt_internal_add_module(UiTools -- SOURCES -- ../designer/src/lib/uilib/abstractformbuilder.cpp ../designer/src/lib/uilib/abstractformbuilder.h -- ../designer/src/lib/uilib/formbuilder.cpp ../designer/src/lib/uilib/formbuilder.h -- ../designer/src/lib/uilib/formbuilderextra.cpp ../designer/src/lib/uilib/formbuilderextra_p.h -- ../designer/src/lib/uilib/properties.cpp ../designer/src/lib/uilib/properties_p.h -- ../designer/src/lib/uilib/resourcebuilder.cpp ../designer/src/lib/uilib/resourcebuilder_p.h -- ../designer/src/lib/uilib/textbuilder.cpp ../designer/src/lib/uilib/textbuilder_p.h -- ../designer/src/lib/uilib/ui4.cpp ../designer/src/lib/uilib/ui4_p.h -- quiloader.cpp quiloader.h -- DEFINES -- QFORMINTERNAL_NAMESPACE -- QT_DESIGNER -- QT_DESIGNER_STATIC -- QT_USE_QSTRINGBUILDER -- INCLUDE_DIRECTORIES -- ../designer/src/lib/uilib -- LIBRARIES -- Qt::UiPlugin -- PUBLIC_LIBRARIES -- Qt::Core -- Qt::Gui -- Qt::Widgets --) -- --## Scopes: --##################################################################### -- --qt_internal_extend_target(UiTools CONDITION TARGET Qt::OpenGLWidgets -- PUBLIC_LIBRARIES -- Qt::OpenGLWidgets --) -- --qt_internal_extend_target(UiTools CONDITION TARGET Qt::OpenGL -- LIBRARIES -- Qt::OpenGL --) --qt_internal_add_docs(UiTools -- doc/qtuitools.qdocconf --) -- -diff --git x/qttools/src/uitools/qtuitoolsglobal.h y/qttools/src/uitools/qtuitoolsglobal.h -deleted file mode 100644 -index a2f967dee..000000000 ---- x/qttools/src/uitools/qtuitoolsglobal.h -+++ /dev/null -@@ -1,24 +0,0 @@ --// Copyright (C) 2020 The Qt Company Ltd. --// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only -- --#ifndef QTUITOOLSGLOBAL_H --#define QTUITOOLSGLOBAL_H -- --#include -- --QT_BEGIN_NAMESPACE -- --#ifndef QT_STATIC --# if defined(QT_BUILD_UITOOLS_LIB) --# define Q_UITOOLS_EXPORT Q_DECL_EXPORT --# else --# define Q_UITOOLS_EXPORT Q_DECL_IMPORT --# endif --#else --# define Q_UITOOLS_EXPORT --#endif -- --QT_END_NAMESPACE -- --#endif // QTUITOOLSGLOBAL_H -- -diff --git x/qttools/src/uitools/quiloader.cpp y/qttools/src/uitools/quiloader.cpp -deleted file mode 100644 -index a06d4717b..000000000 ---- x/qttools/src/uitools/quiloader.cpp -+++ /dev/null -@@ -1,914 +0,0 @@ --// Copyright (C) 2020 The Qt Company Ltd. --// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only -- -- --#include "quiloader.h" --#include "quiloader_p.h" -- --#include -- --#include --#include --#include --#include -- --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include -- --#include --#include -- --#include --#include --#include --#include --#include -- --QT_BEGIN_NAMESPACE -- --typedef QMap widget_map; --Q_GLOBAL_STATIC(widget_map, g_widgets) -- --class QUiLoader; --class QUiLoaderPrivate; -- --#ifndef QT_NO_DATASTREAM --// QUiTranslatableStringValue must be streamable since they become part of the QVariant-based --// mime data when dragging items in views with QAbstractItemView::InternalMove. --QDataStream &operator<<(QDataStream &out, const QUiTranslatableStringValue &s) --{ -- out << s.qualifier() << s.value(); -- return out; --} -- --QDataStream &operator>>(QDataStream &in, QUiTranslatableStringValue &s) --{ -- QByteArray qualifier, value; -- in >> qualifier >> value; -- s.setQualifier(qualifier); -- s.setValue(value); -- return in; --} --#endif // QT_NO_DATASTREAM -- --QString QUiTranslatableStringValue::translate(const QByteArray &className, bool idBased) const --{ -- return idBased -- ? qtTrId(m_qualifier.constData()) -- : QCoreApplication::translate(className.constData(), m_value.constData(), m_qualifier.constData()); --} -- --#ifdef QFORMINTERNAL_NAMESPACE --namespace QFormInternal --{ --#endif -- --class TranslatingTextBuilder : public QTextBuilder --{ --public: -- explicit TranslatingTextBuilder(bool idBased, bool trEnabled, const QByteArray &className) : -- m_idBased(idBased), m_trEnabled(trEnabled), m_className(className) {} -- -- QVariant loadText(const DomProperty *icon) const override; -- -- QVariant toNativeValue(const QVariant &value) const override; -- -- bool idBased() const { return m_idBased; } -- --private: -- bool m_idBased; -- bool m_trEnabled; -- QByteArray m_className; --}; -- --QVariant TranslatingTextBuilder::loadText(const DomProperty *text) const --{ -- const DomString *str = text->elementString(); -- if (!str) -- return QVariant(); -- if (str->hasAttributeNotr()) { -- const QString notr = str->attributeNotr(); -- if (notr == QStringLiteral("true") || notr == QStringLiteral("yes")) -- return QVariant::fromValue(str->text()); -- } -- QUiTranslatableStringValue strVal; -- strVal.setValue(str->text().toUtf8()); -- if (m_idBased) -- strVal.setQualifier(str->attributeId().toUtf8()); -- else if (str->hasAttributeComment()) -- strVal.setQualifier(str->attributeComment().toUtf8()); -- return QVariant::fromValue(strVal); --} -- --QVariant TranslatingTextBuilder::toNativeValue(const QVariant &value) const --{ -- if (value.canConvert()) { -- QUiTranslatableStringValue tsv = qvariant_cast(value); -- if (!m_trEnabled) -- return QString::fromUtf8(tsv.value().constData()); -- return QVariant::fromValue(tsv.translate(m_className, m_idBased)); -- } -- if (value.canConvert()) -- return QVariant::fromValue(qvariant_cast(value)); -- return value; --} -- --// This is "exported" to linguist --const QUiItemRolePair qUiItemRoles[] = { -- { Qt::DisplayRole, Qt::DisplayPropertyRole }, --#if QT_CONFIG(tooltip) -- { Qt::ToolTipRole, Qt::ToolTipPropertyRole }, --#endif --#if QT_CONFIG(statustip) -- { Qt::StatusTipRole, Qt::StatusTipPropertyRole }, --#endif --#if QT_CONFIG(whatsthis) -- { Qt::WhatsThisRole, Qt::WhatsThisPropertyRole }, --#endif -- { -1 , -1 } --}; -- --static void recursiveReTranslate(QTreeWidgetItem *item, const QByteArray &class_name, bool idBased) --{ -- const QUiItemRolePair *irs = qUiItemRoles; -- -- int cnt = item->columnCount(); -- for (int i = 0; i < cnt; ++i) { -- for (unsigned j = 0; irs[j].shadowRole >= 0; j++) { -- QVariant v = item->data(i, irs[j].shadowRole); -- if (v.isValid()) { -- QUiTranslatableStringValue tsv = qvariant_cast(v); -- item->setData(i, irs[j].realRole, tsv.translate(class_name, idBased)); -- } -- } -- } -- -- cnt = item->childCount(); -- for (int i = 0; i < cnt; ++i) -- recursiveReTranslate(item->child(i), class_name, idBased); --} -- --template --static void reTranslateWidgetItem(T *item, const QByteArray &class_name, bool idBased) --{ -- const QUiItemRolePair *irs = qUiItemRoles; -- -- for (unsigned j = 0; irs[j].shadowRole >= 0; j++) { -- QVariant v = item->data(irs[j].shadowRole); -- if (v.isValid()) { -- QUiTranslatableStringValue tsv = qvariant_cast(v); -- item->setData(irs[j].realRole, tsv.translate(class_name, idBased)); -- } -- } --} -- --static void reTranslateTableItem(QTableWidgetItem *item, const QByteArray &class_name, bool idBased) --{ -- if (item) -- reTranslateWidgetItem(item, class_name, idBased); --} -- --#define RETRANSLATE_SUBWIDGET_PROP(mainWidget, setter, propName) \ -- do { \ -- QVariant v = mainWidget->widget(i)->property(propName); \ -- if (v.isValid()) { \ -- QUiTranslatableStringValue tsv = qvariant_cast(v); \ -- mainWidget->setter(i, tsv.translate(m_className, m_idBased)); \ -- } \ -- } while (0) -- --class TranslationWatcher: public QObject --{ -- Q_OBJECT -- --public: -- explicit TranslationWatcher(QObject *parent, const QByteArray &className, bool idBased): -- QObject(parent), -- m_className(className), -- m_idBased(idBased) -- { -- } -- -- bool eventFilter(QObject *o, QEvent *event) override -- { -- if (event->type() == QEvent::LanguageChange) { -- const auto &dynamicPropertyNames = o->dynamicPropertyNames(); -- for (const QByteArray &prop : dynamicPropertyNames) { -- if (prop.startsWith(PROP_GENERIC_PREFIX)) { -- const QByteArray propName = prop.mid(sizeof(PROP_GENERIC_PREFIX) - 1); -- const QUiTranslatableStringValue tsv = -- qvariant_cast(o->property(prop)); -- o->setProperty(propName, tsv.translate(m_className, m_idBased)); -- } -- } -- if (0) { --#if QT_CONFIG(tabwidget) -- } else if (QTabWidget *tabw = qobject_cast(o)) { -- const int cnt = tabw->count(); -- for (int i = 0; i < cnt; ++i) { -- RETRANSLATE_SUBWIDGET_PROP(tabw, setTabText, PROP_TABPAGETEXT); --#if QT_CONFIG(tooltip) -- RETRANSLATE_SUBWIDGET_PROP(tabw, setTabToolTip, PROP_TABPAGETOOLTIP); --# endif --#if QT_CONFIG(whatsthis) -- RETRANSLATE_SUBWIDGET_PROP(tabw, setTabWhatsThis, PROP_TABPAGEWHATSTHIS); --# endif -- } --#endif --#if QT_CONFIG(listwidget) -- } else if (QListWidget *listw = qobject_cast(o)) { -- const int cnt = listw->count(); -- for (int i = 0; i < cnt; ++i) -- reTranslateWidgetItem(listw->item(i), m_className, m_idBased); --#endif --#if QT_CONFIG(treewidget) -- } else if (QTreeWidget *treew = qobject_cast(o)) { -- if (QTreeWidgetItem *item = treew->headerItem()) -- recursiveReTranslate(item, m_className, m_idBased); -- const int cnt = treew->topLevelItemCount(); -- for (int i = 0; i < cnt; ++i) { -- QTreeWidgetItem *item = treew->topLevelItem(i); -- recursiveReTranslate(item, m_className, m_idBased); -- } --#endif --#if QT_CONFIG(tablewidget) -- } else if (QTableWidget *tablew = qobject_cast(o)) { -- const int row_cnt = tablew->rowCount(); -- const int col_cnt = tablew->columnCount(); -- for (int j = 0; j < col_cnt; ++j) -- reTranslateTableItem(tablew->horizontalHeaderItem(j), m_className, m_idBased); -- for (int i = 0; i < row_cnt; ++i) { -- reTranslateTableItem(tablew->verticalHeaderItem(i), m_className, m_idBased); -- for (int j = 0; j < col_cnt; ++j) -- reTranslateTableItem(tablew->item(i, j), m_className, m_idBased); -- } --#endif --#if QT_CONFIG(combobox) -- } else if (QComboBox *combow = qobject_cast(o)) { -- if (!qobject_cast(o)) { -- const int cnt = combow->count(); -- for (int i = 0; i < cnt; ++i) { -- const QVariant v = combow->itemData(i, Qt::DisplayPropertyRole); -- if (v.isValid()) { -- QUiTranslatableStringValue tsv = qvariant_cast(v); -- combow->setItemText(i, tsv.translate(m_className, m_idBased)); -- } -- } -- } --#endif --#if QT_CONFIG(toolbox) -- } else if (QToolBox *toolw = qobject_cast(o)) { -- const int cnt = toolw->count(); -- for (int i = 0; i < cnt; ++i) { -- RETRANSLATE_SUBWIDGET_PROP(toolw, setItemText, PROP_TOOLITEMTEXT); --#if QT_CONFIG(tooltip) -- RETRANSLATE_SUBWIDGET_PROP(toolw, setItemToolTip, PROP_TOOLITEMTOOLTIP); --# endif -- } --#endif -- } -- } -- return false; -- } -- --private: -- QByteArray m_className; -- bool m_idBased; --}; -- --class FormBuilderPrivate: public QFormBuilder --{ -- friend class QT_PREPEND_NAMESPACE(QUiLoader); -- friend class QT_PREPEND_NAMESPACE(QUiLoaderPrivate); -- using ParentClass = QFormBuilder; -- --public: -- QUiLoader *loader = nullptr; -- -- bool dynamicTr = false; -- bool trEnabled = true; -- -- FormBuilderPrivate() = default; -- -- QWidget *defaultCreateWidget(const QString &className, QWidget *parent, const QString &name) -- { -- return ParentClass::createWidget(className, parent, name); -- } -- -- QLayout *defaultCreateLayout(const QString &className, QObject *parent, const QString &name) -- { -- return ParentClass::createLayout(className, parent, name); -- } -- -- QAction *defaultCreateAction(QObject *parent, const QString &name) -- { -- return ParentClass::createAction(parent, name); -- } -- -- QActionGroup *defaultCreateActionGroup(QObject *parent, const QString &name) -- { -- return ParentClass::createActionGroup(parent, name); -- } -- -- QWidget *createWidget(const QString &className, QWidget *parent, const QString &name) override -- { -- if (QWidget *widget = loader->createWidget(className, parent, name)) { -- widget->setObjectName(name); -- return widget; -- } -- -- return nullptr; -- } -- -- QLayout *createLayout(const QString &className, QObject *parent, const QString &name) override -- { -- if (QLayout *layout = loader->createLayout(className, parent, name)) { -- layout->setObjectName(name); -- return layout; -- } -- -- return nullptr; -- } -- -- QActionGroup *createActionGroup(QObject *parent, const QString &name) override -- { -- if (QActionGroup *actionGroup = loader->createActionGroup(parent, name)) { -- actionGroup->setObjectName(name); -- return actionGroup; -- } -- -- return nullptr; -- } -- -- QAction *createAction(QObject *parent, const QString &name) override -- { -- if (QAction *action = loader->createAction(parent, name)) { -- action->setObjectName(name); -- return action; -- } -- -- return nullptr; -- } -- -- void applyProperties(QObject *o, const QList &properties) override; -- QWidget *create(DomUI *ui, QWidget *parentWidget) override; -- QWidget *create(DomWidget *ui_widget, QWidget *parentWidget) override; -- bool addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget) override; -- --private: -- QByteArray m_class; -- TranslationWatcher *m_trwatch = nullptr; -- bool m_idBased = false; --}; -- --static QString convertTranslatable(const DomProperty *p, const QByteArray &className, -- bool idBased, QUiTranslatableStringValue *strVal) --{ -- if (p->kind() != DomProperty::String) -- return QString(); -- const DomString *dom_str = p->elementString(); -- if (!dom_str) -- return QString(); -- if (dom_str->hasAttributeNotr()) { -- const QString notr = dom_str->attributeNotr(); -- if (notr == QStringLiteral("yes") || notr == QStringLiteral("true")) -- return QString(); -- } -- strVal->setValue(dom_str->text().toUtf8()); -- strVal->setQualifier(idBased ? dom_str->attributeId().toUtf8() : dom_str->attributeComment().toUtf8()); -- if (strVal->value().isEmpty() && strVal->qualifier().isEmpty()) -- return QString(); -- return strVal->translate(className, idBased); --} -- --void FormBuilderPrivate::applyProperties(QObject *o, const QList &properties) --{ -- QFormBuilder::applyProperties(o, properties); -- -- if (!m_trwatch) -- m_trwatch = new TranslationWatcher(o, m_class, m_idBased); -- -- if (properties.isEmpty()) -- return; -- -- // Unlike string item roles, string properties are not loaded via the textBuilder -- // (as they are "shadowed" by the property sheets in designer). So do the initial -- // translation here. -- bool anyTrs = false; -- for (const DomProperty *p : properties) { -- QUiTranslatableStringValue strVal; -- const QString text = convertTranslatable(p, m_class, m_idBased, &strVal); -- if (text.isEmpty()) -- continue; -- const QByteArray name = p->attributeName().toUtf8(); -- if (dynamicTr) { -- const QByteArray dynname = QByteArray(PROP_GENERIC_PREFIX + name); -- o->setProperty(dynname, QVariant::fromValue(strVal)); -- anyTrs = trEnabled; -- } -- if (p->elementString()->text() != text) -- o->setProperty(name, text); -- } -- if (anyTrs) -- o->installEventFilter(m_trwatch); --} -- --QWidget *FormBuilderPrivate::create(DomUI *ui, QWidget *parentWidget) --{ -- m_class = ui->elementClass().toUtf8(); -- m_trwatch = nullptr; -- m_idBased = ui->attributeIdbasedtr(); -- setTextBuilder(new TranslatingTextBuilder(m_idBased, trEnabled, m_class)); -- return QFormBuilder::create(ui, parentWidget); --} -- --QWidget *FormBuilderPrivate::create(DomWidget *ui_widget, QWidget *parentWidget) --{ -- QWidget *w = QFormBuilder::create(ui_widget, parentWidget); -- if (w == nullptr) -- return nullptr; -- -- if (0) { --#if QT_CONFIG(tabwidget) -- } else if (qobject_cast(w)) { --#endif --#if QT_CONFIG(listwidget) -- } else if (qobject_cast(w)) { --#endif --#if QT_CONFIG(treewidget) -- } else if (qobject_cast(w)) { --#endif --#if QT_CONFIG(tablewidget) -- } else if (qobject_cast(w)) { --#endif --#if QT_CONFIG(combobox) -- } else if (qobject_cast(w)) { -- if (qobject_cast(w)) -- return w; --#endif --#if QT_CONFIG(toolbox) -- } else if (qobject_cast(w)) { --#endif -- } else { -- return w; -- } -- if (dynamicTr && trEnabled) -- w->installEventFilter(m_trwatch); -- return w; --} -- --#define TRANSLATE_SUBWIDGET_PROP(mainWidget, attribute, setter, propName) \ -- do { \ -- if (const DomProperty *p##attribute = attributes.value(strings.attribute)) { \ -- QUiTranslatableStringValue strVal; \ -- const QString text = convertTranslatable(p##attribute, m_class, m_idBased, &strVal); \ -- if (!text.isEmpty()) { \ -- if (dynamicTr) \ -- mainWidget->widget(i)->setProperty(propName, QVariant::fromValue(strVal)); \ -- mainWidget->setter(i, text); \ -- } \ -- } \ -- } while (0) -- --bool FormBuilderPrivate::addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget) --{ -- if (parentWidget == nullptr) -- return true; -- -- if (!ParentClass::addItem(ui_widget, widget, parentWidget)) -- return false; -- -- // Check special cases. First: Custom container -- const QString className = QLatin1String(parentWidget->metaObject()->className()); -- if (!d->customWidgetAddPageMethod(className).isEmpty()) -- return true; -- -- const QFormBuilderStrings &strings = QFormBuilderStrings::instance(); -- -- if (0) { --#if QT_CONFIG(tabwidget) -- } else if (QTabWidget *tabWidget = qobject_cast(parentWidget)) { -- const DomPropertyHash attributes = propertyMap(ui_widget->elementAttribute()); -- const int i = tabWidget->count() - 1; -- TRANSLATE_SUBWIDGET_PROP(tabWidget, titleAttribute, setTabText, PROP_TABPAGETEXT); --#if QT_CONFIG(tooltip) -- TRANSLATE_SUBWIDGET_PROP(tabWidget, toolTipAttribute, setTabToolTip, PROP_TABPAGETOOLTIP); --# endif --#if QT_CONFIG(whatsthis) -- TRANSLATE_SUBWIDGET_PROP(tabWidget, whatsThisAttribute, setTabWhatsThis, PROP_TABPAGEWHATSTHIS); --# endif --#endif --#if QT_CONFIG(toolbox) -- } else if (QToolBox *toolBox = qobject_cast(parentWidget)) { -- const DomPropertyHash attributes = propertyMap(ui_widget->elementAttribute()); -- const int i = toolBox->count() - 1; -- TRANSLATE_SUBWIDGET_PROP(toolBox, labelAttribute, setItemText, PROP_TOOLITEMTEXT); --#if QT_CONFIG(tooltip) -- TRANSLATE_SUBWIDGET_PROP(toolBox, toolTipAttribute, setItemToolTip, PROP_TOOLITEMTOOLTIP); --# endif --#endif -- } -- -- return true; --} -- --#ifdef QFORMINTERNAL_NAMESPACE --} --#endif -- --class QUiLoaderPrivate --{ --public: --#ifdef QFORMINTERNAL_NAMESPACE -- QFormInternal::FormBuilderPrivate builder; --#else -- FormBuilderPrivate builder; --#endif -- -- void setupWidgetMap() const; --}; -- --void QUiLoaderPrivate::setupWidgetMap() const --{ -- if (!g_widgets()->isEmpty()) -- return; -- --#define DECLARE_WIDGET(a, b) g_widgets()->insert(QLatin1String(#a), true); --#define DECLARE_LAYOUT(a, b) -- --#include "widgets.table" -- --#undef DECLARE_WIDGET --#undef DECLARE_WIDGET_1 --#undef DECLARE_LAYOUT --} -- --/*! -- \class QUiLoader -- \inmodule QtUiTools -- -- \brief The QUiLoader class enables standalone applications to -- dynamically create user interfaces at run-time using the -- information stored in UI files or specified in plugin paths. -- -- In addition, you can customize or create your own user interface by -- deriving your own loader class. -- -- If you have a custom component or an application that embeds \QD, you can -- also use the QFormBuilder class provided by the QtDesigner module to create -- user interfaces from UI files. -- -- The QUiLoader class provides a collection of functions allowing you to -- create widgets based on the information stored in UI files (created -- with \QD) or available in the specified plugin paths. The specified plugin -- paths can be retrieved using the pluginPaths() function. Similarly, the -- contents of a UI file can be retrieved using the load() function. For -- example: -- -- \snippet quiloader/mywidget.cpp 0 -- -- \if !defined(qtforpython) -- By including the user interface in the form's resources (\c myform.qrc), we -- ensure that it will be present at run-time: -- -- \quotefile quiloader/mywidget.qrc -- \endif -- -- The availableWidgets() function returns a QStringList with the class names -- of the widgets available in the specified plugin paths. To create these -- widgets, simply use the createWidget() function. For example: -- -- \snippet quiloader/main.cpp 0 -- -- To make a custom widget available to the loader, you can use the -- addPluginPath() function; to remove all available widgets, you can call -- the clearPluginPaths() function. -- -- The createAction(), createActionGroup(), createLayout(), and createWidget() -- functions are used internally by the QUiLoader class whenever it has to -- create an action, action group, layout, or widget respectively. For that -- reason, you can subclass the QUiLoader class and reimplement these -- functions to intervene the process of constructing a user interface. For -- example, you might want to have a list of the actions created when loading -- a form or creating a custom widget. -- -- For a complete example using the QUiLoader class, see the -- \l{Calculator Builder Example}. -- -- \sa {Qt UI Tools}, QFormBuilder --*/ -- --/*! -- Creates a form loader with the given \a parent. --*/ --QUiLoader::QUiLoader(QObject *parent) -- : QObject(parent), d_ptr(new QUiLoaderPrivate) --{ -- Q_D(QUiLoader); -- --#ifndef QT_NO_DATASTREAM -- static int metaTypeId = 0; -- if (!metaTypeId) { -- metaTypeId = qRegisterMetaType("QUiTranslatableStringValue"); -- } --#endif // QT_NO_DATASTREAM -- d->builder.loader = this; -- --#if QT_CONFIG(library) -- QStringList paths; -- const QStringList &libraryPaths = QApplication::libraryPaths(); -- for (const QString &path : libraryPaths) { -- QString libPath = path; -- libPath += QDir::separator(); -- libPath += QStringLiteral("designer"); -- paths.append(libPath); -- } -- -- d->builder.setPluginPath(paths); --#endif // QT_CONFIG(library) --} -- --/*! -- Destroys the loader. --*/ --QUiLoader::~QUiLoader() = default; -- --/*! -- Loads a form from the given \a device and creates a new widget with the -- given \a parentWidget to hold its contents. -- -- \sa createWidget(), errorString() --*/ --QWidget *QUiLoader::load(QIODevice *device, QWidget *parentWidget) --{ -- Q_D(QUiLoader); -- // QXmlStreamReader will report errors on open failure. -- if (!device->isOpen()) -- device->open(QIODevice::ReadOnly|QIODevice::Text); -- return d->builder.load(device, parentWidget); --} -- --/*! -- Returns a list naming the paths in which the loader will search when -- locating custom widget plugins. -- -- \sa addPluginPath(), clearPluginPaths() --*/ --QStringList QUiLoader::pluginPaths() const --{ -- Q_D(const QUiLoader); -- return d->builder.pluginPaths(); --} -- --/*! -- Clears the list of paths in which the loader will search when locating -- plugins. -- -- \sa addPluginPath(), pluginPaths() --*/ --void QUiLoader::clearPluginPaths() --{ -- Q_D(QUiLoader); -- d->builder.clearPluginPaths(); --} -- --/*! -- Adds the given \a path to the list of paths in which the loader will search -- when locating plugins. -- -- \sa pluginPaths(), clearPluginPaths() --*/ --void QUiLoader::addPluginPath(const QString &path) --{ -- Q_D(QUiLoader); -- d->builder.addPluginPath(path); --} -- --/*! -- Creates a new widget with the given \a parent and \a name using the class -- specified by \a className. You can use this function to create any of the -- widgets returned by the availableWidgets() function. -- -- The function is also used internally by the QUiLoader class whenever it -- creates a widget. Hence, you can subclass QUiLoader and reimplement this -- function to intervene process of constructing a user interface or widget. -- However, in your implementation, ensure that you call QUiLoader's version -- first. -- -- \sa availableWidgets(), load() --*/ --QWidget *QUiLoader::createWidget(const QString &className, QWidget *parent, const QString &name) --{ -- Q_D(QUiLoader); -- return d->builder.defaultCreateWidget(className, parent, name); --} -- --/*! -- Creates a new layout with the given \a parent and \a name using the class -- specified by \a className. -- -- The function is also used internally by the QUiLoader class whenever it -- creates a widget. Hence, you can subclass QUiLoader and reimplement this -- function to intervene process of constructing a user interface or widget. -- However, in your implementation, ensure that you call QUiLoader's version -- first. -- -- \sa createWidget(), load() --*/ --QLayout *QUiLoader::createLayout(const QString &className, QObject *parent, const QString &name) --{ -- Q_D(QUiLoader); -- return d->builder.defaultCreateLayout(className, parent, name); --} -- --/*! -- Creates a new action group with the given \a parent and \a name. -- -- The function is also used internally by the QUiLoader class whenever it -- creates a widget. Hence, you can subclass QUiLoader and reimplement this -- function to intervene process of constructing a user interface or widget. -- However, in your implementation, ensure that you call QUiLoader's version -- first. -- -- \sa createAction(), createWidget(), load() -- */ --QActionGroup *QUiLoader::createActionGroup(QObject *parent, const QString &name) --{ -- Q_D(QUiLoader); -- return d->builder.defaultCreateActionGroup(parent, name); --} -- --/*! -- Creates a new action with the given \a parent and \a name. -- -- The function is also used internally by the QUiLoader class whenever it -- creates a widget. Hence, you can subclass QUiLoader and reimplement this -- function to intervene process of constructing a user interface or widget. -- However, in your implementation, ensure that you call QUiLoader's version -- first. -- -- \sa createActionGroup(), createWidget(), load() --*/ --QAction *QUiLoader::createAction(QObject *parent, const QString &name) --{ -- Q_D(QUiLoader); -- return d->builder.defaultCreateAction(parent, name); --} -- --/*! -- Returns a list naming all available widgets that can be built using the -- createWidget() function, i.e all the widgets specified within the given -- plugin paths. -- -- \sa pluginPaths(), createWidget() -- --*/ --QStringList QUiLoader::availableWidgets() const --{ -- Q_D(const QUiLoader); -- -- d->setupWidgetMap(); -- widget_map available = *g_widgets(); -- -- const auto &customWidgets = d->builder.customWidgets(); -- for (QDesignerCustomWidgetInterface *plugin : customWidgets) -- available.insert(plugin->name(), true); -- -- return available.keys(); --} -- -- --/*! -- \since 4.5 -- Returns a list naming all available layouts that can be built using the -- createLayout() function -- -- \sa createLayout() --*/ -- --QStringList QUiLoader::availableLayouts() const --{ -- QStringList rc; --#define DECLARE_WIDGET(a, b) --#define DECLARE_LAYOUT(a, b) rc.push_back(QLatin1String(#a)); -- --#include "widgets.table" -- --#undef DECLARE_WIDGET --#undef DECLARE_LAYOUT -- return rc; --} -- --/*! -- Sets the working directory of the loader to \a dir. The loader will look -- for other resources, such as icons and resource files, in paths relative to -- this directory. -- -- \sa workingDirectory() --*/ -- --void QUiLoader::setWorkingDirectory(const QDir &dir) --{ -- Q_D(QUiLoader); -- d->builder.setWorkingDirectory(dir); --} -- --/*! -- Returns the working directory of the loader. -- -- \sa setWorkingDirectory() --*/ -- --QDir QUiLoader::workingDirectory() const --{ -- Q_D(const QUiLoader); -- return d->builder.workingDirectory(); --} --/*! -- \since 4.5 -- -- If \a enabled is true, user interfaces loaded by this loader will -- automatically retranslate themselves upon receiving a language change -- event. Otherwise, the user interfaces will not be retranslated. -- -- \sa isLanguageChangeEnabled() --*/ -- --void QUiLoader::setLanguageChangeEnabled(bool enabled) --{ -- Q_D(QUiLoader); -- d->builder.dynamicTr = enabled; --} -- --/*! -- \since 4.5 -- -- Returns true if dynamic retranslation on language change is enabled; -- returns false otherwise. -- -- \sa setLanguageChangeEnabled() --*/ -- --bool QUiLoader::isLanguageChangeEnabled() const --{ -- Q_D(const QUiLoader); -- return d->builder.dynamicTr; --} -- --/*! -- \internal -- \since 4.5 -- -- If \a enabled is true, user interfaces loaded by this loader will be -- translated. Otherwise, the user interfaces will not be translated. -- -- \note This is orthogonal to languageChangeEnabled. -- -- \sa isLanguageChangeEnabled(), setLanguageChangeEnabled() --*/ -- --void QUiLoader::setTranslationEnabled(bool enabled) --{ -- Q_D(QUiLoader); -- d->builder.trEnabled = enabled; --} -- --/*! -- \internal -- \since 4.5 -- -- Returns true if translation is enabled; returns false otherwise. -- -- \sa setTranslationEnabled() --*/ -- --bool QUiLoader::isTranslationEnabled() const --{ -- Q_D(const QUiLoader); -- return d->builder.trEnabled; --} -- --/*! -- Returns a human-readable description of the last error occurred in load(). -- -- \since 5.0 -- \sa load() --*/ -- --QString QUiLoader::errorString() const --{ -- Q_D(const QUiLoader); -- return d->builder.errorString(); --} -- --QT_END_NAMESPACE -- --#include "quiloader.moc" -diff --git x/qttools/src/uitools/quiloader.h y/qttools/src/uitools/quiloader.h -deleted file mode 100644 -index 742b5606f..000000000 ---- x/qttools/src/uitools/quiloader.h -+++ /dev/null -@@ -1,61 +0,0 @@ --// Copyright (C) 2020 The Qt Company Ltd. --// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only -- --#ifndef QUILOADER_H --#define QUILOADER_H -- --#include --#include --#include -- --QT_BEGIN_NAMESPACE -- --class QWidget; --class QLayout; --class QAction; --class QActionGroup; --class QString; --class QIODevice; --class QDir; -- --class QUiLoaderPrivate; --class Q_UITOOLS_EXPORT QUiLoader : public QObject --{ -- Q_OBJECT --public: -- explicit QUiLoader(QObject *parent = nullptr); -- ~QUiLoader() override; -- -- QStringList pluginPaths() const; -- void clearPluginPaths(); -- void addPluginPath(const QString &path); -- -- QWidget *load(QIODevice *device, QWidget *parentWidget = nullptr); -- QStringList availableWidgets() const; -- QStringList availableLayouts() const; -- -- virtual QWidget *createWidget(const QString &className, QWidget *parent = nullptr, const QString &name = QString()); -- virtual QLayout *createLayout(const QString &className, QObject *parent = nullptr, const QString &name = QString()); -- virtual QActionGroup *createActionGroup(QObject *parent = nullptr, const QString &name = QString()); -- virtual QAction *createAction(QObject *parent = nullptr, const QString &name = QString()); -- -- void setWorkingDirectory(const QDir &dir); -- QDir workingDirectory() const; -- -- void setLanguageChangeEnabled(bool enabled); -- bool isLanguageChangeEnabled() const; -- -- void setTranslationEnabled(bool enabled); -- bool isTranslationEnabled() const; -- -- QString errorString() const; -- --private: -- QScopedPointer d_ptr; -- Q_DECLARE_PRIVATE(QUiLoader) -- Q_DISABLE_COPY_MOVE(QUiLoader) --}; -- --QT_END_NAMESPACE -- --#endif // QUILOADER_H -diff --git x/qttools/src/uitools/quiloader_p.h y/qttools/src/uitools/quiloader_p.h -deleted file mode 100644 -index efd943217..000000000 ---- x/qttools/src/uitools/quiloader_p.h -+++ /dev/null -@@ -1,77 +0,0 @@ --// Copyright (C) 2020 The Qt Company Ltd. --// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only -- --#ifndef QUILOADER_P_H --#define QUILOADER_P_H -- --// --// W A R N I N G --// ------------- --// --// This file is not part of the Qt API. It exists purely as an --// implementation detail. This header file may change from version to --// version without notice, or even be removed. --// --// We mean it. --// -- --#include --#include --#include -- --QT_FORWARD_DECLARE_CLASS(QDataStream) -- --// This file is here for use by the form preview in Linguist. If you change anything --// here or in the code which uses it, remember to adapt Linguist accordingly. -- --#define PROP_GENERIC_PREFIX "_q_notr_" --#define PROP_TOOLITEMTEXT "_q_toolItemText_notr" --#define PROP_TOOLITEMTOOLTIP "_q_toolItemToolTip_notr" --#define PROP_TABPAGETEXT "_q_tabPageText_notr" --#define PROP_TABPAGETOOLTIP "_q_tabPageToolTip_notr" --#define PROP_TABPAGEWHATSTHIS "_q_tabPageWhatsThis_notr" -- --QT_BEGIN_NAMESPACE -- --class Q_UITOOLS_EXPORT QUiTranslatableStringValue --{ --public: -- QByteArray value() const { return m_value; } -- void setValue(const QByteArray &value) { m_value = value; } -- QByteArray qualifier() const { return m_qualifier; } -- void setQualifier(const QByteArray &qualifier) { m_qualifier = qualifier; } -- -- QString translate(const QByteArray &className, bool idBased) const; -- --private: -- QByteArray m_value; -- QByteArray m_qualifier; // Comment or ID for id-based tr(). --}; -- --#ifndef QT_NO_DATASTREAM --Q_UITOOLS_EXPORT QDataStream &operator<<(QDataStream &out, const QUiTranslatableStringValue &s); --Q_UITOOLS_EXPORT QDataStream &operator>>(QDataStream &in, QUiTranslatableStringValue &s); --#endif // QT_NO_DATASTREAM -- --struct QUiItemRolePair { -- int realRole; -- int shadowRole; --}; -- --#ifdef QFORMINTERNAL_NAMESPACE --namespace QFormInternal --{ --#endif -- --extern const Q_UITOOLS_EXPORT QUiItemRolePair qUiItemRoles[]; -- --#ifdef QFORMINTERNAL_NAMESPACE --} --#endif -- --QT_END_NAMESPACE -- --Q_DECLARE_METATYPE(QUiTranslatableStringValue) -- -- --#endif // QUILOADER_P_H -diff --git x/qttools/sync.profile y/qttools/sync.profile -index caa7ed5ad..de4261afc 100644 ---- x/qttools/sync.profile -+++ y/qttools/sync.profile -@@ -1,8 +1,8 @@ - %modules = ( # path to module name map - "QtTools" => "$basedir/src/global", - "QtHelp" => "$basedir/src/assistant/help", -- "QtUiTools" => "$basedir/src/uitools", -- "QtUiPlugin" => "$basedir/src/uiplugin", -+ "QtUiTools" => "$basedir/src/designer/src/uitools", -+ "QtUiPlugin" => "$basedir/src/designer/src/uiplugin", - "QtDesigner" => "$basedir/src/designer/src/lib", - "QtDesignerComponents" => "$basedir/src/designer/src/components/lib", - ); diff --git a/libs/patches/qtwebengine-0001-Fix-Linux-build-with-CMake-versions-3.25.patch b/libs/patches/qtwebengine-0001-Fix-Linux-build-with-CMake-versions-3.25.patch deleted file mode 100644 index 2aa80208d..000000000 --- a/libs/patches/qtwebengine-0001-Fix-Linux-build-with-CMake-versions-3.25.patch +++ /dev/null @@ -1,36 +0,0 @@ -From a120b53dcef4aebd5e7bea35bc6fc6c462e748f1 Mon Sep 17 00:00:00 2001 -From: Alexey Edelev -Date: Wed, 23 Nov 2022 12:40:45 +0100 -Subject: Fix Linux build with CMake versions >= 3.25 -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The 'LINUX' variable exists in CMake since the version 3.25. This -variable previously was undefined while preparsing the configure.cmake -files. Since the CMake script that defines the 'check_for_ulimit' -function is not included while evaluating configure.cmake first time -we need to add a stub. - -Change-Id: I25bdec4f4a1b6af23174507a8f0f9cbf01f0c398 -Reviewed-by: Jörg Bornemann -(cherry picked from commit 240e71877865ed07e4c8d5bd4553aa0772c2adf4) -Reviewed-by: Qt Cherry-pick Bot -(cherry picked from commit 517d0890f9e95c841bea3421f2455651ca0d8070) ---- - configure.cmake | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git x/qtwebengine/configure.cmake y/qtwebengine/configure.cmake -index f485c1b4b..fff76d54a 100644 ---- x/qtwebengine/configure.cmake -+++ y/qtwebengine/configure.cmake -@@ -3,6 +3,8 @@ if(QT_CONFIGURE_RUNNING) - endfunction() - function(add_check_for_support) - endfunction() -+ function(check_for_ulimit) -+ endfunction() - else() - find_package(Ninja 1.7.2) - find_package(Gn ${QT_REPO_MODULE_VERSION} EXACT) diff --git a/resources/CMakeLists.txt b/resources/CMakeLists.txt index eaa63d445..81f649c12 100644 --- a/resources/CMakeLists.txt +++ b/resources/CMakeLists.txt @@ -1,19 +1,53 @@ +function(GET_BASENAME _file _output) + string(REGEX REPLACE "_[\.|0-9]+" "." _file "${_file}") + set(${_output} ${_file} PARENT_SCOPE) +endfunction() + +function(FILTER_VERSIONED _files _output) + set(regex ".+_([\.|0-9]+)\.(qml|js)$") + + set(versioned_files "${_files}") + list(FILTER versioned_files INCLUDE REGEX ${regex}) + list(SORT versioned_files COMPARE NATURAL) + + list(FILTER _files EXCLUDE REGEX ${regex}) + + foreach(file ${versioned_files}) + string(REGEX MATCH ${regex} _unused "${file}") + if(CMAKE_MATCH_1 AND QT_VERSION VERSION_LESS CMAKE_MATCH_1) + GET_BASENAME("${file}" basefile) + list(FIND _files "${basefile}" index) + if(NOT index EQUAL -1) + list(REMOVE_ITEM _files "${basefile}") + list(APPEND _files "${file}") + endif() + endif() + endforeach() + + set(${_output} ${_files} PARENT_SCOPE) +endfunction() + function(WRITE_QRC _dest_file _dir _prefix _files) + FILTER_VERSIONED("${_files}" _files) file(WRITE "${_dest_file}" "\n") foreach(file ${_files}) string(REPLACE "${_dir}/" "" file_alias "${file}") + GET_BASENAME("${file_alias}" file_alias) file(APPEND "${_dest_file}" "${file}\n") endforeach() file(APPEND "${_dest_file}" "") endfunction() -function(WRITE_GLOB_QRC _dest_file _dir _prefix _wildcard) - file(GLOB_RECURSE files "${_dir}/${_wildcard}") +function(WRITE_GLOB_QRC _dest_file _dir _prefix) + foreach(arg ${ARGN}) + list(APPEND filter ${_dir}/${arg}) + endforeach() + file(GLOB_RECURSE files ${filter}) WRITE_QRC("${_dest_file}" "${_dir}" "${_prefix}" "${files}") endfunction() function(ADD_SHADERS_TO_TARGET _target) - if(TARGET ${Qt}::Qml AND QT6 AND NOT INTEGRATED_SDK) + if(TARGET ${Qt}::Qml AND NOT INTEGRATED_SDK) file(GLOB QT6_SHADERS "${RESOURCES_DIR}/shader/qt6/*.frag") message(STATUS "QT6_SHADERS " "${QT6_SHADERS}") foreach(shaderPath ${QT6_SHADERS}) @@ -54,12 +88,6 @@ if((IOS OR ANDROID) AND NOT INTEGRATED_SDK OR BUILD_TESTING) list(APPEND QRC_FILES "ausweisapp_mobile.qrc") endif() -if (IOS) - list(APPEND QRC_FILES "ausweisapp_ios.qrc") -elseif((ANDROID AND NOT INTEGRATED_SDK) OR BUILD_TESTING) - list(APPEND QRC_FILES "ausweisapp_android.qrc") -endif() - if((DESKTOP AND NOT INTEGRATED_SDK) OR BUILD_TESTING) list(APPEND QRC_FILES "ausweisapp_desktop.qrc") endif() @@ -74,7 +102,7 @@ if(TARGET ${Qt}::Qml) set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${QMLDIR_FILES}) set(ausweisapp_qml.qrc "${CMAKE_CURRENT_BINARY_DIR}/ausweisapp_qml.qrc") - WRITE_GLOB_QRC("${ausweisapp_qml.qrc}" "${CMAKE_CURRENT_SOURCE_DIR}/qml" "/qml" "*") + WRITE_GLOB_QRC("${ausweisapp_qml.qrc}" "${CMAKE_CURRENT_SOURCE_DIR}/qml" "/qml" "*.qml" "qmldir") list(APPEND QRC_FILES "${ausweisapp_qml.qrc}") set(ausweisapp_license.qrc "${CMAKE_CURRENT_BINARY_DIR}/ausweisapp_license.qrc") diff --git a/resources/asan_suppressions b/resources/asan_suppressions index b0dae86a0..724d2eff6 100644 --- a/resources/asan_suppressions +++ b/resources/asan_suppressions @@ -1,5 +1,5 @@ # Recommended usage: -# LSAN_OPTIONS=suppressions=/home/dev/AusweisApp2.src/resources/asan_suppressions ./AusweisApp2 +# LSAN_OPTIONS=suppressions=/home/dev/AusweisApp.src/resources/asan_suppressions ./AusweisApp leak:g_malloc* leak:libxcb* diff --git a/resources/ausweisapp.qrc b/resources/ausweisapp.qrc index 9890af022..e9af18b23 100644 --- a/resources/ausweisapp.qrc +++ b/resources/ausweisapp.qrc @@ -1,16 +1,18 @@ + fonts/Roboto-Medium.ttf + images/appearance_dark_mode.svg + images/appearance_light_mode.svg + images/appearance_system_mode.svg + images/eye_visibility_off.svg + images/eye_visibility_on.svg + images/faq_icon.svg + images/filter.svg + images/filter_off.svg images/mydata.svg - images/material_visibility.svg - images/material_visibility_off.svg - images/material_settings.svg - images/material_help.svg - images/material_lock.svg - images/material_delete.svg - images/material_filter.svg - images/material_filter_off.svg - images/material_open_in_new.svg - images/material_search.svg + images/material_arrow_back.svg + images/lock.svg + images/open_website.svg images/material_location.svg images/material_mail.svg images/material_phone.svg @@ -18,70 +20,111 @@ images/material_clear.svg images/material_check.svg images/material_refresh.svg - images/material_history.svg - images/material_alert.svg images/material_block.svg - images/material_live_help.svg images/material_person.svg + images/material_expand_less.svg + images/material_expand_more.svg + images/material_arrow_right.svg images/checkbox_indicator.svg images/npa.svg - images/id_card.png + images/can.svg images/signature.jp2 images/pin_letter_pinpuk.svg - images/pin_letter_pinpuk_red_bar.svg - images/pin_letter_pinpuk_red_bar_puk.svg + images/transportpin_lightmode.svg + images/transportpin_darkmode.svg + images/transportpin_highcontrast.svg images/pin_person.svg + images/pin_person.webp + images/pin_unknown.svg + images/can.webp images/logo_beta_background.svg images/logo_beta_testing.svg - images/status_error.svg - images/status_info.svg - images/status_ok.svg + images/status_error_darkmode.svg + images/status_error_highcontrast.svg + images/status_error_lightmode.svg + images/status_ok_darkmode.svg + images/status_ok_highcontrast.svg + images/status_ok_lightmode.svg + images/status_info_darkmode.svg + images/status_info_highcontrast.svg + images/status_info_lightmode.svg + images/status_warning.svg images/ausweis.svg images/ausweis_outline.svg - images/provider.svg images/identify.svg images/info.svg - images/provider/information.svg - images/provider/purpose.svg - images/provider/general.svg - images/provider/citizen.svg - images/provider/finance.svg - images/provider/insurance.svg - images/provider/other.svg - images/provider/default_bg.svg - images/provider/general_bg.svg - images/provider/general_button.svg - images/provider/citizen_bg.svg - images/provider/citizen_button.svg - images/provider/finance_bg.svg - images/provider/finance_button.svg - images/provider/insurance_bg.svg - images/provider/insurance_button.svg - images/provider/other_bg.svg - images/provider/other_button.svg + images/pairingCode.webp + images/puk_darkmode.webp + images/puk_highcontrast.webp + images/puk_lightmode.webp + images/puk_darkmode.svg + images/puk_highcontrast.svg + images/puk_lightmode.svg + images/transportpin_darkmode.webp + images/transportpin_highcontrast.webp + images/transportpin_lightmode.webp updatable-files/supported-providers.json images/icon_five_digit_pin.svg - images/icon_six_digit_pin_white.svg - images/icon_six_digit_pin_blue.svg - images/icon_ten_digit_puk.svg - images/icon_remote_inactive.svg - images/icon_remote_0.svg - images/icon_remote_25.svg - images/icon_remote_50.svg - images/icon_remote_75.svg - images/icon_remote_100.svg + images/icon_six_digit_pin.svg + images/icon_remote_inactive_darkmode.svg + images/icon_remote_inactive_highcontrast.svg + images/icon_remote_inactive_lightmode.svg + images/icon_remote_25_darkmode.svg + images/icon_remote_25_highcontrast.svg + images/icon_remote_25_lightmode.svg + images/icon_remote_50_darkmode.svg + images/icon_remote_50_highcontrast.svg + images/icon_remote_50_lightmode.svg + images/icon_remote_75_darkmode.svg + images/icon_remote_75_highcontrast.svg + images/icon_remote_75_lightmode.svg + images/icon_remote_100_darkmode.svg + images/icon_remote_100_highcontrast.svg + images/icon_remote_100_lightmode.svg images/phone_to_pc.svg images/location_flag_de.svg images/location_flag_en.svg images/location_flag_ru.svg images/location_flag_uk.svg - images/siteWithLogo.png + images/siteWithLogo_darkmode.svg + images/siteWithLogo_highcontrast.svg + images/siteWithLogo_lightmode.svg images/sandglass.svg - images/trash_icon_all.svg - images/triangle.svg + images/sandglass.webp + images/trash_icon.svg + images/trash_icon_old.svg + images/workflow_error_card_darkmode.svg + images/workflow_error_card_highcontrast.svg + images/workflow_error_card_lightmode.svg + images/workflow_error_network_darkmode.svg + images/workflow_error_network_highcontrast.svg + images/workflow_error_network_lightmode.svg + images/workflow_error_wrong_can_darkmode.svg + images/workflow_error_wrong_can_highcontrast.svg + images/workflow_error_wrong_can_lightmode.svg + images/workflow_error_wrong_pin_darkmode.svg + images/workflow_error_wrong_pin_highcontrast.svg + images/workflow_error_wrong_pin_lightmode.svg + images/workflow_error_wrong_puk_darkmode.svg + images/workflow_error_wrong_puk_highcontrast.svg + images/workflow_error_wrong_puk_lightmode.svg + images/workflow_error_wrong_transportpin_darkmode.svg + images/workflow_error_wrong_transportpin_highcontrast.svg + images/workflow_error_wrong_transportpin_lightmode.svg + images/workflow_error_no_sak_darkmode.svg + images/workflow_error_no_sak_highcontrast.svg + images/workflow_error_no_sak_lightmode.svg + images/workflow_error_puk_blocked_darkmode.svg + images/workflow_error_puk_blocked_highcontrast.svg + images/workflow_error_puk_blocked_lightmode.svg + images/workflow_success_changepin_darkmode.svg + images/workflow_success_changepin_highcontrast.svg + images/workflow_success_changepin_lightmode.svg + images/workflow_error_nfc_darkmode.svg + images/workflow_error_nfc_highcontrast.svg + images/workflow_error_nfc_lightmode.svg shader/ConicalGradientShader.frag shader/ColorOverlayShader.frag shader/DesaturateShader.frag - shader/OpacityMaskShader.frag diff --git a/resources/ausweisapp_android.qrc b/resources/ausweisapp_android.qrc deleted file mode 100644 index 47d5d95b7..000000000 --- a/resources/ausweisapp_android.qrc +++ /dev/null @@ -1,5 +0,0 @@ - - - images/android/material_share.svg - - diff --git a/resources/ausweisapp_desktop.qrc b/resources/ausweisapp_desktop.qrc index 90d7d0e66..7d3f1351a 100644 --- a/resources/ausweisapp_desktop.qrc +++ b/resources/ausweisapp_desktop.qrc @@ -1,25 +1,39 @@ images/macos/appIcon.svg + images/desktop/autostart.svg images/desktop/info_white.svg + images/desktop/help.svg + images/desktop/help_icon.svg + images/desktop/home.svg images/desktop/titlebar_arrow.svg images/desktop/material_assistant.svg - images/desktop/material_bug_report.svg images/desktop/material_new_releases.svg images/desktop/material_rate_review.svg - images/desktop/material_save.svg - images/desktop/material_view_list.svg - images/desktop/material_notifications.svg + images/desktop/notifications_on.svg + images/desktop/notifications_off.svg images/desktop/material_arrow_forward.svg images/desktop/material_question_answer.svg - images/desktop/material_highlight.svg - images/desktop/material_menu_book.svg - images/desktop/material_menu_book_white.svg images/desktop/material_settings_white.svg images/desktop/material_open_in_browser.svg - images/desktop/material_a11y.svg - images/desktop/material_privacy.svg - images/desktop/material_video.svg + images/desktop/a11y_icon.svg + images/desktop/list_icon.svg + images/desktop/save_icon.svg + images/desktop/settings.svg + images/desktop/status_ok_darkmode.svg + images/desktop/status_ok_highcontrast.svg + images/desktop/status_ok_lightmode.svg + images/desktop/privacy_icon.svg + images/desktop/trash_icon_white.svg + images/desktop/warning.svg + images/desktop/workflow_idcard_nfc.svg + images/desktop/workflow_idcard_usb.svg + images/desktop/workflow_waitfor_idcard_sak.webp + images/desktop/workflow_waitfor_idcard_usb.webp + images/desktop/workflow_waitfor_reader.webp + images/desktop/workflow_error_sak_connection_darkmode.svg + images/desktop/workflow_error_sak_connection_highcontrast.svg + images/desktop/workflow_error_sak_connection_lightmode.svg images/reader/default_more_reader.png images/reader/default_no_reader.png images/reader/default_reader.png diff --git a/resources/ausweisapp_ios.qrc b/resources/ausweisapp_ios.qrc deleted file mode 100644 index 401170d57..000000000 --- a/resources/ausweisapp_ios.qrc +++ /dev/null @@ -1,5 +0,0 @@ - - - images/ios/share.svg - - diff --git a/resources/ausweisapp_mobile.qrc b/resources/ausweisapp_mobile.qrc index f861f5da0..e690f309d 100644 --- a/resources/ausweisapp_mobile.qrc +++ b/resources/ausweisapp_mobile.qrc @@ -1,21 +1,23 @@ - images/android/stay_primary_landscape-24px.svg - images/android/stay_primary_portrait-24px.svg - images/ios/material_arrow_left.svg - images/ios/material_cancel.svg images/ios/material_more_horiz.svg images/material_add.svg + images/mobile/x.svg + images/mobile/questionmark.svg + images/mobile/card.svg images/mobile/device.svg + images/mobile/device_button.svg + images/mobile/mydata_button.svg images/mobile/generic_id_card.svg + images/mobile/help.svg + images/mobile/home.svg images/mobile/icon_nfc.svg images/mobile/icon_remote.svg images/mobile/icon_simulator.svg images/mobile/icon_smart.svg - images/mobile/material_arrow_back.svg - images/mobile/material_arrow_right.svg + images/mobile/share.svg + images/mobile/material_arrow_left.svg images/mobile/material_backspace.svg - images/mobile/material_home.svg images/mobile/material_view_headline.svg images/mobile/phone_card_reader.svg images/mobile/phone_nfc.svg @@ -23,198 +25,16 @@ images/mobile/phone_remote.svg images/mobile/phone_simulator.svg images/mobile/phone_smart.svg - images/provider/ios/citizen.svg - images/provider/citizen_bg.svg - images/provider/citizen_button.svg - images/provider/default_bg.svg - images/provider/ios/finance.svg - images/provider/finance_bg.svg - images/provider/finance_button.svg - images/provider/ios/general.svg - images/provider/general_bg.svg - images/provider/general_button.svg - images/provider/ios/insurance.svg - images/provider/insurance_bg.svg - images/provider/insurance_button.svg - images/provider/ios/other.svg - images/provider/other_bg.svg - images/provider/other_button.svg - images/tutorial/arrow_blue.svg - images/tutorial/arrows.svg - images/tutorial/background_icon_how.svg - images/tutorial/background_icon_important.svg - images/tutorial/background_icon_where.svg - images/tutorial/button_de.png - images/tutorial/button_en.png - images/tutorial/button_en.png - images/tutorial/button_en.png - images/tutorial/bva.svg - images/tutorial/check.svg - images/tutorial/circle-1.svg - images/tutorial/circle-2.svg - images/tutorial/circle-3.svg - images/tutorial/circle-4.svg - images/tutorial/circle-lock-2.svg - images/tutorial/circle-lock.svg - images/tutorial/click.svg - images/tutorial/cross.svg - images/tutorial/desktop.svg - images/tutorial/hand.svg - images/tutorial/hint.svg - images/tutorial/how_desktop.svg - images/tutorial/how_device_lineup.svg - images/tutorial/how_form_no_fun.svg - images/tutorial/how_method_nfc.svg - images/tutorial/how_method_sac_desktop.svg - images/tutorial/how_method_sac_mobile.svg - images/tutorial/how_questions_everywhere.svg - images/tutorial/icon_box.svg - images/tutorial/icon_circle.svg - images/tutorial/icon_diamond.svg - images/tutorial/icon_star.svg - images/tutorial/identify.svg - images/tutorial/important_lets_go.svg - images/tutorial/important_pin5.svg - images/tutorial/important_pin6.svg - images/tutorial/important_space_questionmark.svg - images/tutorial/laptop.svg - images/tutorial/letters.svg - images/tutorial/main_menu_how_caret.svg - images/tutorial/main_menu_important_caret.svg - images/tutorial/main_menu_what_caret.svg - images/tutorial/main_menu_where_caret.svg - images/tutorial/nfc.svg - images/tutorial/no-nfc.svg - images/tutorial/phone.svg - images/tutorial/phone_border.svg - images/tutorial/phone_list.svg - images/tutorial/phone_screen.svg - images/tutorial/phone_screen_de.png - images/tutorial/phone_screen_en.png - images/tutorial/phone_screen_en.png - images/tutorial/phone_screen_en.png - images/tutorial/pin-5@2x.png - images/tutorial/pin-6@2x.png - images/tutorial/play_movie.png - images/tutorial/provider_home.svg - images/tutorial/providericons.png - images/tutorial/questionmark.svg - images/tutorial/reader.svg - images/tutorial/reader_nfc_finished.svg - images/tutorial/reader_nfc_npa_on_smartphone.svg - images/tutorial/reader_nfc_pin6.svg - images/tutorial/reader_nfc_provider_on_smartphone.svg - images/tutorial/reader_nfc_smartphone_nfc_position.svg - images/tutorial/reader_nfc_userdata_example_de.svg - images/tutorial/reader_nfc_userdata_example_en.svg - images/tutorial/reader_nfc_userdata_example_en.svg - images/tutorial/reader_nfc_userdata_example_en.svg - images/tutorial/reader_sac_aa2_ok.svg - images/tutorial/reader_sac_menu_android_de.svg - images/tutorial/reader_sac_menu_android_en.svg - images/tutorial/reader_sac_menu_android_en.svg - images/tutorial/reader_sac_menu_android_en.svg - images/tutorial/reader_sac_menu_ios_de.svg - images/tutorial/reader_sac_menu_ios_en.svg - images/tutorial/reader_sac_menu_ios_en.svg - images/tutorial/reader_sac_menu_ios_en.svg - images/tutorial/reader_sac_no_nfc_devices.svg - images/tutorial/reader_sac_no_nfc_provider.svg - images/tutorial/reader_sac_npa_on_laptop.svg - images/tutorial/reader_sac_provider_on_laptop.svg - images/tutorial/rectangles.svg - images/tutorial/save.svg - images/tutorial/screenshot_cert_android_de.png - images/tutorial/screenshot_cert_android_en.png - images/tutorial/screenshot_cert_android_en.png - images/tutorial/screenshot_cert_android_en.png - images/tutorial/screenshot_cert_ios_de.png - images/tutorial/screenshot_cert_ios_en.png - images/tutorial/screenshot_cert_ios_en.png - images/tutorial/screenshot_cert_ios_en.png - images/tutorial/screenshot_check_id_card_android_de.png - images/tutorial/screenshot_check_id_card_android_en.png - images/tutorial/screenshot_check_id_card_android_en.png - images/tutorial/screenshot_check_id_card_android_en.png - images/tutorial/screenshot_check_id_card_ios_de.png - images/tutorial/screenshot_check_id_card_ios_en.png - images/tutorial/screenshot_check_id_card_ios_en.png - images/tutorial/screenshot_check_id_card_ios_en.png - images/tutorial/screenshot_choose_reader_android_de.png - images/tutorial/screenshot_choose_reader_android_en.png - images/tutorial/screenshot_choose_reader_android_en.png - images/tutorial/screenshot_choose_reader_android_en.png - images/tutorial/screenshot_choose_reader_ios_de.png - images/tutorial/screenshot_choose_reader_ios_en.png - images/tutorial/screenshot_choose_reader_ios_en.png - images/tutorial/screenshot_choose_reader_ios_en.png - images/tutorial/screenshot_pairing_de.png - images/tutorial/screenshot_pairing_en.png - images/tutorial/screenshot_pairing_en.png - images/tutorial/screenshot_pairing_en.png - images/tutorial/screenshot_pin_management_menu_android_de.png - images/tutorial/screenshot_pin_management_menu_android_en.png - images/tutorial/screenshot_pin_management_menu_android_en.png - images/tutorial/screenshot_pin_management_menu_android_en.png - images/tutorial/screenshot_pin_management_menu_ios_de.png - images/tutorial/screenshot_pin_management_menu_ios_en.png - images/tutorial/screenshot_pin_management_menu_ios_en.png - images/tutorial/screenshot_pin_management_menu_ios_en.png - images/tutorial/screenshot_providerlist_android_de.png - images/tutorial/screenshot_providerlist_android_en.png - images/tutorial/screenshot_providerlist_android_en.png - images/tutorial/screenshot_providerlist_android_en.png - images/tutorial/screenshot_providerlist_ios_de.png - images/tutorial/screenshot_providerlist_ios_en.png - images/tutorial/screenshot_providerlist_ios_en.png - images/tutorial/screenshot_providerlist_ios_en.png - images/tutorial/screenshot_remoteservice_android_de.png - images/tutorial/screenshot_remoteservice_android_en.png - images/tutorial/screenshot_remoteservice_android_en.png - images/tutorial/screenshot_remoteservice_android_en.png - images/tutorial/screenshot_remoteservice_ios_de.png - images/tutorial/screenshot_remoteservice_ios_en.png - images/tutorial/screenshot_remoteservice_ios_en.png - images/tutorial/screenshot_remoteservice_ios_en.png - images/tutorial/screenshot_selfauthentication_android_de.png - images/tutorial/screenshot_selfauthentication_android_en.png - images/tutorial/screenshot_selfauthentication_android_en.png - images/tutorial/screenshot_selfauthentication_android_en.png - images/tutorial/screenshot_selfauthentication_ios_de.png - images/tutorial/screenshot_selfauthentication_ios_en.png - images/tutorial/screenshot_selfauthentication_ios_en.png - images/tutorial/screenshot_selfauthentication_ios_en.png - images/tutorial/screenshot_start_android_de.png - images/tutorial/screenshot_start_android_en.png - images/tutorial/screenshot_start_android_en.png - images/tutorial/screenshot_start_android_en.png - images/tutorial/screenshot_start_ios_de.png - images/tutorial/screenshot_start_ios_en.png - images/tutorial/screenshot_start_ios_en.png - images/tutorial/screenshot_start_ios_en.png - images/tutorial/section_seperator_how.svg - images/tutorial/section_seperator_important.svg - images/tutorial/section_seperator_what.svg - images/tutorial/section_seperator_where.svg - images/tutorial/tablet-nfc.svg - images/tutorial/tablet-no-nfc.svg - images/tutorial/tablet.svg - images/tutorial/thumb_up.svg - images/tutorial/up_icon.svg - images/tutorial/usb.svg - images/tutorial/user-tine@3x.png - images/tutorial/where_identify_now_de.svg - images/tutorial/where_identify_now_en.svg - images/tutorial/where_identify_now_en.svg - images/tutorial/where_identify_now_en.svg - images/tutorial/where_lay_down_id.svg - images/tutorial/where_overview_question.svg - images/tutorial/where_pin6.svg - images/tutorial/where_userdata_example_de.svg - images/tutorial/where_userdata_example_en.svg - images/tutorial/where_userdata_example_en.svg - images/tutorial/where_userdata_example_en.svg - images/tutorial/wifi.svg + images/mobile/phone_nfc_info.svg + images/mobile/phone_remote_info.svg + images/mobile/settings.svg + images/mobile/smarteid.svg + images/mobile/no_internet_darkmode.svg + images/mobile/no_internet_highcontrast.svg + images/mobile/no_internet_lightmode.svg + images/mobile/workflow_success_nfc_darkmode.svg + images/mobile/workflow_success_nfc_highcontrast.svg + images/mobile/workflow_success_nfc_lightmode.svg qtquickcontrols2.conf diff --git a/resources/ausweisapp_webservice.qrc b/resources/ausweisapp_webservice.qrc index 40c075047..09d370f72 100644 --- a/resources/ausweisapp_webservice.qrc +++ b/resources/ausweisapp_webservice.qrc @@ -1,7 +1,7 @@ template.html - ../docs/sdk/Logo_AusweisApp2.png + ../docs/sdk/AusweisApp_Logo.svg images/html_templates/icon_attention.svg images/html_templates/html_message_section.jpg images/desktop/npa.ico diff --git a/resources/config.json.in b/resources/config.json.in index 3fa2a0c30..4e4f06176 100644 --- a/resources/config.json.in +++ b/resources/config.json.in @@ -21,6 +21,7 @@ "_comment_3": "array of Test-CVCs; hex encoded", "_comment_4": [ + "DETESTeID00007_DETESTeID00008", "DETESTeID00006_DETESTeID00007", "DETESTeID00005_DETESTeID00006", "DETESTeID00004_DETESTeID00005", @@ -34,6 +35,7 @@ "DECVCAeIDCT00001_DECVCAeIDCT00001" ], "cvRootCertificatesTest": [ + "7f218201b67f4e82016e5f290100420e44455445535465494430303030377f4982011d060a04007f000702020202038120a9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d1f6e537782207d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6ce94a4b44f330b5d9832026dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7e1ce6bccdc18ff8c07b68441048bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27e1e3bd23c23a4453bd9ace3262547ef835c3dac4fd97f8461a14611dc9c27745132ded8e545c1d54c72f0469978520a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a78641042cd9bc714f44bf697cb98f364050cf2ea34297a449fed086856cd0f633a6489c622da3ec5874ecdbf43700d7728aebaa0df77cbf1698bb20f4480ac1d3f60b5a8701015f200e44455445535465494430303030387f4c12060904007f0007030102025305fc4f13ffff5f25060203000800085f24060206000800075f37406e32790fe7bb8f07274edd0b6b5cc6a5e065be18aedfbc2078f882906eabb5fe9a23b748c7c1e2e2096f125745c32c401862c657933255e464686c1996af92d1", "7F218201B67F4E82016E5F290100420E44455445535465494430303030367F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A786410431D8F49A3095D324E52833E1354860FCD797F44730AA4B67486E10E6059A04B773E16F803A115788D307A7B99296D5AB5CBD658D3EA28D4771ED5A027DB5ADE28701015F200E44455445535465494430303030377F4C12060904007F0007030102025305FC0F13FFFF5F25060200010001035F24060203010001035F3740275BAD7EF24614F99ABE983C6643BE5385D2C2B1D146DD481AC422B1605CA5A64F87D4B2B9F56BEEE34B8E6B6AF6F3423A21F00AABF55F29C3771B06B22B3A0A", "7F218201B67F4E82016E5F290100420E44455445535465494430303030357F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A786410425AB80F9C7BCA0AB1759D8E469F911CC006D02131552AA5F248B2A38D7C72CFB3317EA6881FD24D8B31A2E75FBEDA87964B60787095F75C753CD8BC5264D3C9A8701015F200E44455445535465494430303030367F4C12060904007F0007030102025305FC0F13FFFF5F25060108000200055F24060201000200055F37402E55923ED687CB104D609DD183402E8292DB03C3EFFE5EF3FAC597D2A8DB27370269EAAD7341D72447C9184CD817AE0E2BD4DF6FCF89DC52F455D490F077E5E9", "7F218201B67F4E82016E5F290100420E44455445535465494430303030347F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A78641049BFEBA8DC7FAAB6E3BDEB3FF794DBB800848FE4F6940A4CC7EECB5159C87DA5395505892026D420A22596CD014ED1FD872DADA597DB0F8D64441041198F62D448701015F200E44455445535465494430303030357F4C12060904007F0007030102025305FC0F13FFFF5F25060105000500045F24060108000500045F37402D2468416D66BCBE259B9B907A73395BC1EF94ED75F9C17615210246E9EFB06E6753E9055CE76623B7699B9EFB1A7D3A9DD83F6E6E09E55A33EA0A5F62A1C719", @@ -219,7 +221,6 @@ "personalizationUrl": "@SMART_PERSONALIZATION_URL@", "personalizationTestUrl": "@SMART_PERSONALIZATION_URL_TEST@", "serviceId": "@SMART_SERVICEID@", - "versionTag": "@SMART_VERSIONTAG@", "ssdAid": "@SMART_SSDAID@" }, @@ -228,6 +229,7 @@ "minVersion": "1.100.0", "allowedCertificateHashes": [ "B02AC76B50A497AE810AEAC22598187B3D4290277D0851A7FA8E1AEA5A979870", + "F4A4D85A22103EBB5F4D35AEDE5117F40E591AB5DDF43DF39C953D08E3895138", "F96FD6BBA899845E06D3E6522F0843217681D473B6B09F1E313DEA1A21D6B8E7" ], "minPskSize": 256 diff --git a/resources/fonts/Roboto-Medium.ttf b/resources/fonts/Roboto-Medium.ttf new file mode 100644 index 000000000..ac0f908b9 Binary files /dev/null and b/resources/fonts/Roboto-Medium.ttf differ diff --git a/resources/images/android/hdpi/npa.png b/resources/images/android/hdpi/npa.png deleted file mode 100644 index 5eaa4b393..000000000 Binary files a/resources/images/android/hdpi/npa.png and /dev/null differ diff --git a/resources/images/android/hdpi/npa_beta.png b/resources/images/android/hdpi/npa_beta.png deleted file mode 100644 index 7a4405812..000000000 Binary files a/resources/images/android/hdpi/npa_beta.png and /dev/null differ diff --git a/resources/images/android/hdpi/npa_preview.png b/resources/images/android/hdpi/npa_preview.png deleted file mode 100644 index 0e67c649a..000000000 Binary files a/resources/images/android/hdpi/npa_preview.png and /dev/null differ diff --git a/resources/images/android/ldpi/npa.png b/resources/images/android/ldpi/npa.png deleted file mode 100644 index 68b8c2e79..000000000 Binary files a/resources/images/android/ldpi/npa.png and /dev/null differ diff --git a/resources/images/android/ldpi/npa_beta.png b/resources/images/android/ldpi/npa_beta.png deleted file mode 100644 index 4327828af..000000000 Binary files a/resources/images/android/ldpi/npa_beta.png and /dev/null differ diff --git a/resources/images/android/ldpi/npa_preview.png b/resources/images/android/ldpi/npa_preview.png deleted file mode 100644 index 93ec630b4..000000000 Binary files a/resources/images/android/ldpi/npa_preview.png and /dev/null differ diff --git a/resources/images/android/material_share.svg b/resources/images/android/material_share.svg deleted file mode 100644 index ed3e530b2..000000000 --- a/resources/images/android/material_share.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/resources/images/android/mdpi/npa.png b/resources/images/android/mdpi/npa.png deleted file mode 100644 index 60cd2fa55..000000000 Binary files a/resources/images/android/mdpi/npa.png and /dev/null differ diff --git a/resources/images/android/mdpi/npa_beta.png b/resources/images/android/mdpi/npa_beta.png deleted file mode 100644 index 7a63ec0b3..000000000 Binary files a/resources/images/android/mdpi/npa_beta.png and /dev/null differ diff --git a/resources/images/android/mdpi/npa_preview.png b/resources/images/android/mdpi/npa_preview.png deleted file mode 100644 index d9bca963d..000000000 Binary files a/resources/images/android/mdpi/npa_preview.png and /dev/null differ diff --git a/resources/images/android/stay_primary_landscape-24px.svg b/resources/images/android/stay_primary_landscape-24px.svg deleted file mode 100644 index 09f3a60db..000000000 --- a/resources/images/android/stay_primary_landscape-24px.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/resources/images/android/stay_primary_portrait-24px.svg b/resources/images/android/stay_primary_portrait-24px.svg deleted file mode 100644 index c41cad3f4..000000000 --- a/resources/images/android/stay_primary_portrait-24px.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/resources/images/android/xhdpi/npa.png b/resources/images/android/xhdpi/npa.png deleted file mode 100644 index bda882065..000000000 Binary files a/resources/images/android/xhdpi/npa.png and /dev/null differ diff --git a/resources/images/android/xhdpi/npa_beta.png b/resources/images/android/xhdpi/npa_beta.png deleted file mode 100644 index 00c7d9c90..000000000 Binary files a/resources/images/android/xhdpi/npa_beta.png and /dev/null differ diff --git a/resources/images/android/xhdpi/npa_preview.png b/resources/images/android/xhdpi/npa_preview.png deleted file mode 100644 index 3184273d8..000000000 Binary files a/resources/images/android/xhdpi/npa_preview.png and /dev/null differ diff --git a/resources/images/android/xxhdpi/npa.png b/resources/images/android/xxhdpi/npa.png deleted file mode 100644 index 05da4125e..000000000 Binary files a/resources/images/android/xxhdpi/npa.png and /dev/null differ diff --git a/resources/images/android/xxhdpi/npa_beta.png b/resources/images/android/xxhdpi/npa_beta.png deleted file mode 100644 index 942b14468..000000000 Binary files a/resources/images/android/xxhdpi/npa_beta.png and /dev/null differ diff --git a/resources/images/android/xxhdpi/npa_preview.png b/resources/images/android/xxhdpi/npa_preview.png deleted file mode 100644 index 746b91373..000000000 Binary files a/resources/images/android/xxhdpi/npa_preview.png and /dev/null differ diff --git a/resources/images/android/xxxhdpi/npa.png b/resources/images/android/xxxhdpi/npa.png deleted file mode 100644 index 6c335d231..000000000 Binary files a/resources/images/android/xxxhdpi/npa.png and /dev/null differ diff --git a/resources/images/android/xxxhdpi/npa_beta.png b/resources/images/android/xxxhdpi/npa_beta.png deleted file mode 100644 index f0aef9b18..000000000 Binary files a/resources/images/android/xxxhdpi/npa_beta.png and /dev/null differ diff --git a/resources/images/android/xxxhdpi/npa_preview.png b/resources/images/android/xxxhdpi/npa_preview.png deleted file mode 100644 index 52ddba23a..000000000 Binary files a/resources/images/android/xxxhdpi/npa_preview.png and /dev/null differ diff --git a/resources/images/appearance_dark_mode.svg b/resources/images/appearance_dark_mode.svg new file mode 100644 index 000000000..5ca5f479d --- /dev/null +++ b/resources/images/appearance_dark_mode.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + diff --git a/resources/images/appearance_light_mode.svg b/resources/images/appearance_light_mode.svg new file mode 100644 index 000000000..e45c2aeae --- /dev/null +++ b/resources/images/appearance_light_mode.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/appearance_system_mode.svg b/resources/images/appearance_system_mode.svg new file mode 100644 index 000000000..6d43aad83 --- /dev/null +++ b/resources/images/appearance_system_mode.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/can.svg b/resources/images/can.svg new file mode 100644 index 000000000..372a19b0f --- /dev/null +++ b/resources/images/can.svg @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/can.webp b/resources/images/can.webp new file mode 100644 index 000000000..f81086651 Binary files /dev/null and b/resources/images/can.webp differ diff --git a/resources/images/desktop/a11y_icon.svg b/resources/images/desktop/a11y_icon.svg new file mode 100644 index 000000000..ca85b07be --- /dev/null +++ b/resources/images/desktop/a11y_icon.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/desktop/autostart.svg b/resources/images/desktop/autostart.svg new file mode 100644 index 000000000..c8965babe --- /dev/null +++ b/resources/images/desktop/autostart.svg @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/desktop/help.svg b/resources/images/desktop/help.svg new file mode 100644 index 000000000..8c19f5c4b --- /dev/null +++ b/resources/images/desktop/help.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/images/desktop/help_icon.svg b/resources/images/desktop/help_icon.svg new file mode 100644 index 000000000..1a2f6d0c8 --- /dev/null +++ b/resources/images/desktop/help_icon.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + diff --git a/resources/images/desktop/home.svg b/resources/images/desktop/home.svg new file mode 100644 index 000000000..5260ef707 --- /dev/null +++ b/resources/images/desktop/home.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + diff --git a/resources/images/desktop/list_icon.svg b/resources/images/desktop/list_icon.svg new file mode 100644 index 000000000..80545797b --- /dev/null +++ b/resources/images/desktop/list_icon.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + diff --git a/resources/images/desktop/material_a11y.svg b/resources/images/desktop/material_a11y.svg deleted file mode 100644 index 3b02dc969..000000000 --- a/resources/images/desktop/material_a11y.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/resources/images/desktop/material_bug_report.svg b/resources/images/desktop/material_bug_report.svg deleted file mode 100644 index fb22e9dfe..000000000 --- a/resources/images/desktop/material_bug_report.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/resources/images/desktop/material_highlight.svg b/resources/images/desktop/material_highlight.svg deleted file mode 100644 index a9a7692dc..000000000 --- a/resources/images/desktop/material_highlight.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/resources/images/desktop/material_menu_book.svg b/resources/images/desktop/material_menu_book.svg deleted file mode 100644 index e2e3e95b2..000000000 --- a/resources/images/desktop/material_menu_book.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/resources/images/desktop/material_menu_book_white.svg b/resources/images/desktop/material_menu_book_white.svg deleted file mode 100644 index 0a9ef46da..000000000 --- a/resources/images/desktop/material_menu_book_white.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/resources/images/desktop/material_notifications.svg b/resources/images/desktop/material_notifications.svg deleted file mode 100644 index 1d539b3a3..000000000 --- a/resources/images/desktop/material_notifications.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/resources/images/desktop/material_privacy.svg b/resources/images/desktop/material_privacy.svg deleted file mode 100644 index 75866ac43..000000000 --- a/resources/images/desktop/material_privacy.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/resources/images/desktop/material_save.svg b/resources/images/desktop/material_save.svg deleted file mode 100644 index a9dba6978..000000000 --- a/resources/images/desktop/material_save.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/resources/images/desktop/material_video.svg b/resources/images/desktop/material_video.svg deleted file mode 100644 index a7530621f..000000000 --- a/resources/images/desktop/material_video.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/resources/images/desktop/material_view_list.svg b/resources/images/desktop/material_view_list.svg deleted file mode 100644 index d7af03ef2..000000000 --- a/resources/images/desktop/material_view_list.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/resources/images/desktop/notifications_off.svg b/resources/images/desktop/notifications_off.svg new file mode 100644 index 000000000..c8b0f1f40 --- /dev/null +++ b/resources/images/desktop/notifications_off.svg @@ -0,0 +1,10 @@ + + + + + diff --git a/resources/images/desktop/notifications_on.svg b/resources/images/desktop/notifications_on.svg new file mode 100644 index 000000000..f556f5187 --- /dev/null +++ b/resources/images/desktop/notifications_on.svg @@ -0,0 +1,16 @@ + + + + + + + + + diff --git a/resources/images/desktop/privacy_icon.svg b/resources/images/desktop/privacy_icon.svg new file mode 100644 index 000000000..c5e415862 --- /dev/null +++ b/resources/images/desktop/privacy_icon.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + diff --git a/resources/images/desktop/save_icon.svg b/resources/images/desktop/save_icon.svg new file mode 100644 index 000000000..40730f8b9 --- /dev/null +++ b/resources/images/desktop/save_icon.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + diff --git a/resources/images/desktop/settings.svg b/resources/images/desktop/settings.svg new file mode 100644 index 000000000..430f3c75f --- /dev/null +++ b/resources/images/desktop/settings.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/images/desktop/status_ok_darkmode.svg b/resources/images/desktop/status_ok_darkmode.svg new file mode 100644 index 000000000..db7cb67e6 --- /dev/null +++ b/resources/images/desktop/status_ok_darkmode.svg @@ -0,0 +1,9 @@ + + + + + + diff --git a/resources/images/desktop/status_ok_highcontrast.svg b/resources/images/desktop/status_ok_highcontrast.svg new file mode 100644 index 000000000..5dc19926f --- /dev/null +++ b/resources/images/desktop/status_ok_highcontrast.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + diff --git a/resources/images/desktop/status_ok_lightmode.svg b/resources/images/desktop/status_ok_lightmode.svg new file mode 100644 index 000000000..334955b00 --- /dev/null +++ b/resources/images/desktop/status_ok_lightmode.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + diff --git a/resources/images/desktop/trash_icon_white.svg b/resources/images/desktop/trash_icon_white.svg new file mode 100644 index 000000000..d7d2584b2 --- /dev/null +++ b/resources/images/desktop/trash_icon_white.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/resources/images/desktop/warning.svg b/resources/images/desktop/warning.svg new file mode 100644 index 000000000..23e6fc329 --- /dev/null +++ b/resources/images/desktop/warning.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + diff --git a/resources/images/desktop/workflow_error_sak_connection_darkmode.svg b/resources/images/desktop/workflow_error_sak_connection_darkmode.svg new file mode 100644 index 000000000..927546917 --- /dev/null +++ b/resources/images/desktop/workflow_error_sak_connection_darkmode.svg @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/desktop/workflow_error_sak_connection_highcontrast.svg b/resources/images/desktop/workflow_error_sak_connection_highcontrast.svg new file mode 100644 index 000000000..6bc1cc2c8 --- /dev/null +++ b/resources/images/desktop/workflow_error_sak_connection_highcontrast.svg @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/desktop/workflow_error_sak_connection_lightmode.svg b/resources/images/desktop/workflow_error_sak_connection_lightmode.svg new file mode 100644 index 000000000..b1cb4be4f --- /dev/null +++ b/resources/images/desktop/workflow_error_sak_connection_lightmode.svg @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/desktop/workflow_idcard_nfc.svg b/resources/images/desktop/workflow_idcard_nfc.svg new file mode 100644 index 000000000..746ecbd87 --- /dev/null +++ b/resources/images/desktop/workflow_idcard_nfc.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + diff --git a/resources/images/desktop/workflow_idcard_usb.svg b/resources/images/desktop/workflow_idcard_usb.svg new file mode 100644 index 000000000..3a6766f61 --- /dev/null +++ b/resources/images/desktop/workflow_idcard_usb.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + diff --git a/resources/images/desktop/workflow_waitfor_idcard_sak.webp b/resources/images/desktop/workflow_waitfor_idcard_sak.webp new file mode 100644 index 000000000..dd28124bc Binary files /dev/null and b/resources/images/desktop/workflow_waitfor_idcard_sak.webp differ diff --git a/resources/images/desktop/workflow_waitfor_idcard_usb.webp b/resources/images/desktop/workflow_waitfor_idcard_usb.webp new file mode 100644 index 000000000..70cccde15 Binary files /dev/null and b/resources/images/desktop/workflow_waitfor_idcard_usb.webp differ diff --git a/resources/images/desktop/workflow_waitfor_reader.webp b/resources/images/desktop/workflow_waitfor_reader.webp new file mode 100644 index 000000000..541aedcac Binary files /dev/null and b/resources/images/desktop/workflow_waitfor_reader.webp differ diff --git a/resources/images/eye_visibility_off.svg b/resources/images/eye_visibility_off.svg new file mode 100644 index 000000000..ec6d35c35 --- /dev/null +++ b/resources/images/eye_visibility_off.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + diff --git a/resources/images/eye_visibility_on.svg b/resources/images/eye_visibility_on.svg new file mode 100644 index 000000000..21e8cca2b --- /dev/null +++ b/resources/images/eye_visibility_on.svg @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/resources/images/faq_icon.svg b/resources/images/faq_icon.svg new file mode 100644 index 000000000..e29671753 --- /dev/null +++ b/resources/images/faq_icon.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + diff --git a/resources/images/filter.svg b/resources/images/filter.svg new file mode 100644 index 000000000..5afdbd3ec --- /dev/null +++ b/resources/images/filter.svg @@ -0,0 +1,12 @@ + + + + + + + diff --git a/resources/images/filter_off.svg b/resources/images/filter_off.svg new file mode 100644 index 000000000..bd9b1b3d0 --- /dev/null +++ b/resources/images/filter_off.svg @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/resources/images/icon_five_digit_pin.svg b/resources/images/icon_five_digit_pin.svg index a8a0d5274..30f47bad9 100644 --- a/resources/images/icon_five_digit_pin.svg +++ b/resources/images/icon_five_digit_pin.svg @@ -1,17 +1,18 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + +5 + diff --git a/resources/images/icon_remote_0.svg b/resources/images/icon_remote_0.svg deleted file mode 100755 index 2aba743bb..000000000 --- a/resources/images/icon_remote_0.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/resources/images/icon_remote_100.svg b/resources/images/icon_remote_100.svg deleted file mode 100755 index f6dc99ccb..000000000 --- a/resources/images/icon_remote_100.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/resources/images/icon_remote_100_darkmode.svg b/resources/images/icon_remote_100_darkmode.svg new file mode 100644 index 000000000..6b9ad9c85 --- /dev/null +++ b/resources/images/icon_remote_100_darkmode.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + diff --git a/resources/images/icon_remote_100_highcontrast.svg b/resources/images/icon_remote_100_highcontrast.svg new file mode 100644 index 000000000..b9375f526 --- /dev/null +++ b/resources/images/icon_remote_100_highcontrast.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + diff --git a/resources/images/icon_remote_100_lightmode.svg b/resources/images/icon_remote_100_lightmode.svg new file mode 100644 index 000000000..6e5e4adc6 --- /dev/null +++ b/resources/images/icon_remote_100_lightmode.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + diff --git a/resources/images/icon_remote_25.svg b/resources/images/icon_remote_25.svg deleted file mode 100755 index 687d6544b..000000000 --- a/resources/images/icon_remote_25.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/resources/images/icon_remote_25_darkmode.svg b/resources/images/icon_remote_25_darkmode.svg new file mode 100644 index 000000000..175ad08d5 --- /dev/null +++ b/resources/images/icon_remote_25_darkmode.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + diff --git a/resources/images/icon_remote_25_highcontrast.svg b/resources/images/icon_remote_25_highcontrast.svg new file mode 100644 index 000000000..8e875e18e --- /dev/null +++ b/resources/images/icon_remote_25_highcontrast.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + diff --git a/resources/images/icon_remote_25_lightmode.svg b/resources/images/icon_remote_25_lightmode.svg new file mode 100644 index 000000000..110898cfc --- /dev/null +++ b/resources/images/icon_remote_25_lightmode.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + diff --git a/resources/images/icon_remote_50.svg b/resources/images/icon_remote_50.svg deleted file mode 100755 index e5e81d38f..000000000 --- a/resources/images/icon_remote_50.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/resources/images/icon_remote_50_darkmode.svg b/resources/images/icon_remote_50_darkmode.svg new file mode 100644 index 000000000..e6665e4f5 --- /dev/null +++ b/resources/images/icon_remote_50_darkmode.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + diff --git a/resources/images/icon_remote_50_highcontrast.svg b/resources/images/icon_remote_50_highcontrast.svg new file mode 100644 index 000000000..8bb0c2783 --- /dev/null +++ b/resources/images/icon_remote_50_highcontrast.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + diff --git a/resources/images/icon_remote_50_lightmode.svg b/resources/images/icon_remote_50_lightmode.svg new file mode 100644 index 000000000..4db514231 --- /dev/null +++ b/resources/images/icon_remote_50_lightmode.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + diff --git a/resources/images/icon_remote_75.svg b/resources/images/icon_remote_75.svg deleted file mode 100755 index 8ce201307..000000000 --- a/resources/images/icon_remote_75.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/resources/images/icon_remote_75_darkmode.svg b/resources/images/icon_remote_75_darkmode.svg new file mode 100644 index 000000000..c7a058ef7 --- /dev/null +++ b/resources/images/icon_remote_75_darkmode.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + diff --git a/resources/images/icon_remote_75_highcontrast.svg b/resources/images/icon_remote_75_highcontrast.svg new file mode 100644 index 000000000..363b61c8b --- /dev/null +++ b/resources/images/icon_remote_75_highcontrast.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + diff --git a/resources/images/icon_remote_75_lightmode.svg b/resources/images/icon_remote_75_lightmode.svg new file mode 100644 index 000000000..37ba7c3ca --- /dev/null +++ b/resources/images/icon_remote_75_lightmode.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + diff --git a/resources/images/icon_remote_inactive.svg b/resources/images/icon_remote_inactive.svg deleted file mode 100755 index fc08bd4bb..000000000 --- a/resources/images/icon_remote_inactive.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/resources/images/icon_remote_inactive_darkmode.svg b/resources/images/icon_remote_inactive_darkmode.svg new file mode 100644 index 000000000..ce8ba7f0a --- /dev/null +++ b/resources/images/icon_remote_inactive_darkmode.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + diff --git a/resources/images/icon_remote_inactive_highcontrast.svg b/resources/images/icon_remote_inactive_highcontrast.svg new file mode 100644 index 000000000..de6dc5d96 --- /dev/null +++ b/resources/images/icon_remote_inactive_highcontrast.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + diff --git a/resources/images/icon_remote_inactive_lightmode.svg b/resources/images/icon_remote_inactive_lightmode.svg new file mode 100644 index 000000000..412dce562 --- /dev/null +++ b/resources/images/icon_remote_inactive_lightmode.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + diff --git a/resources/images/icon_six_digit_pin.svg b/resources/images/icon_six_digit_pin.svg new file mode 100644 index 000000000..f53cf5305 --- /dev/null +++ b/resources/images/icon_six_digit_pin.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + +6 + diff --git a/resources/images/icon_six_digit_pin_blue.svg b/resources/images/icon_six_digit_pin_blue.svg deleted file mode 100644 index 86e198d10..000000000 --- a/resources/images/icon_six_digit_pin_blue.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/resources/images/icon_six_digit_pin_white.svg b/resources/images/icon_six_digit_pin_white.svg deleted file mode 100644 index b667935f9..000000000 --- a/resources/images/icon_six_digit_pin_white.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/resources/images/id_card.png b/resources/images/id_card.png deleted file mode 100644 index 448ed85f5..000000000 Binary files a/resources/images/id_card.png and /dev/null differ diff --git a/resources/images/identify.svg b/resources/images/identify.svg index 71b841c25..5433a5514 100644 --- a/resources/images/identify.svg +++ b/resources/images/identify.svg @@ -1,9 +1,12 @@ - - - - - + + + + + + + + + + + diff --git a/resources/images/info.svg b/resources/images/info.svg index 81059acf2..e80332073 100644 --- a/resources/images/info.svg +++ b/resources/images/info.svg @@ -1,21 +1,12 @@ - - - + + + + + + + + + + + diff --git a/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/icon1024.png b/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/icon1024.png index cb9d185f1..2af8c4090 100644 Binary files a/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/icon1024.png and b/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/icon1024.png differ diff --git a/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/icon20.png b/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/icon20.png index 2a74570ab..6b05ac582 100644 Binary files a/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/icon20.png and b/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/icon20.png differ diff --git a/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/icon20@2x.png b/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/icon20@2x.png index 04196c069..d6cb9525f 100644 Binary files a/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/icon20@2x.png and b/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/icon20@2x.png differ diff --git a/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/icon20@3x.png b/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/icon20@3x.png index 7772ced64..d24995d07 100644 Binary files a/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/icon20@3x.png and b/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/icon20@3x.png differ diff --git a/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/icon60@2x.png b/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/icon60@2x.png index 754f904d0..9bd68fcf3 100644 Binary files a/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/icon60@2x.png and b/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/icon60@2x.png differ diff --git a/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/icon60@3x.png b/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/icon60@3x.png index a7f9b5a1e..fa2db5947 100644 Binary files a/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/icon60@3x.png and b/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/icon60@3x.png differ diff --git a/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/icon76.png b/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/icon76.png index 222251d21..bc2b21bad 100644 Binary files a/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/icon76.png and b/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/icon76.png differ diff --git a/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/icon76@2x.png b/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/icon76@2x.png index ab9f74c50..0f20fb63f 100644 Binary files a/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/icon76@2x.png and b/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/icon76@2x.png differ diff --git a/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/icon83.5@2x.png b/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/icon83.5@2x.png index 4733b28ec..a2319b17f 100644 Binary files a/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/icon83.5@2x.png and b/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/icon83.5@2x.png differ diff --git a/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/iconSmall.png b/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/iconSmall.png index 79627b9a4..951a8046c 100644 Binary files a/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/iconSmall.png and b/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/iconSmall.png differ diff --git a/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/iconSmall40.png b/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/iconSmall40.png index 04196c069..d6cb9525f 100644 Binary files a/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/iconSmall40.png and b/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/iconSmall40.png differ diff --git a/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/iconSmall40@2x.png b/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/iconSmall40@2x.png index 71732e778..0d7231cb4 100644 Binary files a/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/iconSmall40@2x.png and b/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/iconSmall40@2x.png differ diff --git a/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/iconSmall40@3x.png b/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/iconSmall40@3x.png index 754f904d0..9bd68fcf3 100644 Binary files a/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/iconSmall40@3x.png and b/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/iconSmall40@3x.png differ diff --git a/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/iconSmall@2x.png b/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/iconSmall@2x.png index 00bef7c46..e124420ae 100644 Binary files a/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/iconSmall@2x.png and b/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/iconSmall@2x.png differ diff --git a/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/iconSmall@3x.png b/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/iconSmall@3x.png index e08c5c805..0838ca390 100644 Binary files a/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/iconSmall@3x.png and b/resources/images/ios/appIcons/Images.xcassets/AppIcon.appiconset/iconSmall@3x.png differ diff --git a/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/icon1024.png b/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/icon1024.png index 7d09501f5..4d18391c7 100644 Binary files a/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/icon1024.png and b/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/icon1024.png differ diff --git a/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/icon20.png b/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/icon20.png index 3ddd1ab73..3d2538019 100644 Binary files a/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/icon20.png and b/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/icon20.png differ diff --git a/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/icon20@2x.png b/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/icon20@2x.png index 000dbf340..c4e7c9a93 100644 Binary files a/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/icon20@2x.png and b/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/icon20@2x.png differ diff --git a/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/icon20@3x.png b/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/icon20@3x.png index b705218c2..b27f8f2e8 100644 Binary files a/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/icon20@3x.png and b/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/icon20@3x.png differ diff --git a/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/icon60@2x.png b/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/icon60@2x.png index c6632d343..9fcc7ce8e 100644 Binary files a/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/icon60@2x.png and b/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/icon60@2x.png differ diff --git a/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/icon60@3x.png b/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/icon60@3x.png index 7aee17f3b..bd6f7f4f6 100644 Binary files a/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/icon60@3x.png and b/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/icon60@3x.png differ diff --git a/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/icon76.png b/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/icon76.png index 184cb52b9..11517d72d 100644 Binary files a/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/icon76.png and b/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/icon76.png differ diff --git a/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/icon76@2x.png b/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/icon76@2x.png index 9c66d5137..b441cadcb 100644 Binary files a/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/icon76@2x.png and b/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/icon76@2x.png differ diff --git a/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/icon83.5@2x.png b/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/icon83.5@2x.png index 997611603..73356e584 100644 Binary files a/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/icon83.5@2x.png and b/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/icon83.5@2x.png differ diff --git a/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/iconSmall.png b/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/iconSmall.png index 1d67b75d1..36f70e798 100644 Binary files a/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/iconSmall.png and b/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/iconSmall.png differ diff --git a/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/iconSmall40.png b/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/iconSmall40.png index 000dbf340..c4e7c9a93 100644 Binary files a/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/iconSmall40.png and b/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/iconSmall40.png differ diff --git a/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/iconSmall40@2x.png b/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/iconSmall40@2x.png index 060b5c1ed..608821f06 100644 Binary files a/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/iconSmall40@2x.png and b/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/iconSmall40@2x.png differ diff --git a/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/iconSmall40@3x.png b/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/iconSmall40@3x.png index c6632d343..9fcc7ce8e 100644 Binary files a/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/iconSmall40@3x.png and b/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/iconSmall40@3x.png differ diff --git a/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/iconSmall@2x.png b/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/iconSmall@2x.png index 0cec34233..d980b2aa7 100644 Binary files a/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/iconSmall@2x.png and b/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/iconSmall@2x.png differ diff --git a/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/iconSmall@3x.png b/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/iconSmall@3x.png index e58cd7bfd..4a8ebc5b3 100644 Binary files a/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/iconSmall@3x.png and b/resources/images/ios/appIcons/beta/Images.xcassets/AppIcon.appiconset/iconSmall@3x.png differ diff --git a/resources/images/ios/material_cancel.svg b/resources/images/ios/material_cancel.svg deleted file mode 100644 index 062783447..000000000 --- a/resources/images/ios/material_cancel.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/resources/images/ios/share.svg b/resources/images/ios/share.svg deleted file mode 100644 index 3e885b392..000000000 --- a/resources/images/ios/share.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - - diff --git a/resources/images/location_flag_de.svg b/resources/images/location_flag_de.svg index 96ce7cee2..534e01e44 100644 --- a/resources/images/location_flag_de.svg +++ b/resources/images/location_flag_de.svg @@ -1,7 +1,5 @@ - - - - - - + + + + diff --git a/resources/images/location_flag_en.svg b/resources/images/location_flag_en.svg index a1937bf12..6bb6eb873 100644 --- a/resources/images/location_flag_en.svg +++ b/resources/images/location_flag_en.svg @@ -1,18 +1,18 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + diff --git a/resources/images/location_flag_ru.svg b/resources/images/location_flag_ru.svg index ec7be12b3..2d6448c23 100644 --- a/resources/images/location_flag_ru.svg +++ b/resources/images/location_flag_ru.svg @@ -1,7 +1,5 @@ - - - - - - + + + + diff --git a/resources/images/location_flag_uk.svg b/resources/images/location_flag_uk.svg index ac05de181..819c6d4ea 100644 --- a/resources/images/location_flag_uk.svg +++ b/resources/images/location_flag_uk.svg @@ -1,6 +1,4 @@ - - - - - + + + diff --git a/resources/images/lock.svg b/resources/images/lock.svg new file mode 100644 index 000000000..2fed2f28e --- /dev/null +++ b/resources/images/lock.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/macos/AusweisApp2.icns b/resources/images/macos/AusweisApp.icns similarity index 100% rename from resources/images/macos/AusweisApp2.icns rename to resources/images/macos/AusweisApp.icns diff --git a/resources/images/macos/beta/AusweisApp2.icns b/resources/images/macos/beta/AusweisApp.icns similarity index 100% rename from resources/images/macos/beta/AusweisApp2.icns rename to resources/images/macos/beta/AusweisApp.icns diff --git a/resources/images/macos/dmg_background.png b/resources/images/macos/dmg_background.png index 708160b1c..09cfa43bf 100644 Binary files a/resources/images/macos/dmg_background.png and b/resources/images/macos/dmg_background.png differ diff --git a/resources/images/material_alert.svg b/resources/images/material_alert.svg deleted file mode 100644 index 23bd95733..000000000 --- a/resources/images/material_alert.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/resources/images/mobile/material_arrow_back.svg b/resources/images/material_arrow_back.svg similarity index 100% rename from resources/images/mobile/material_arrow_back.svg rename to resources/images/material_arrow_back.svg diff --git a/resources/images/mobile/material_arrow_right.svg b/resources/images/material_arrow_right.svg similarity index 100% rename from resources/images/mobile/material_arrow_right.svg rename to resources/images/material_arrow_right.svg diff --git a/resources/images/material_delete.svg b/resources/images/material_delete.svg deleted file mode 100644 index 80f0d1a1e..000000000 --- a/resources/images/material_delete.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/resources/images/material_expand_less.svg b/resources/images/material_expand_less.svg new file mode 100644 index 000000000..8032f4a6e --- /dev/null +++ b/resources/images/material_expand_less.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/images/material_expand_more.svg b/resources/images/material_expand_more.svg new file mode 100644 index 000000000..6d040715b --- /dev/null +++ b/resources/images/material_expand_more.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/images/material_filter.svg b/resources/images/material_filter.svg deleted file mode 100644 index 1a21c2b4e..000000000 --- a/resources/images/material_filter.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/resources/images/material_filter_off.svg b/resources/images/material_filter_off.svg deleted file mode 100644 index 804cd36e6..000000000 --- a/resources/images/material_filter_off.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/resources/images/material_help.svg b/resources/images/material_help.svg deleted file mode 100644 index 85fb2092a..000000000 --- a/resources/images/material_help.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/resources/images/material_history.svg b/resources/images/material_history.svg deleted file mode 100644 index 357da249c..000000000 --- a/resources/images/material_history.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/resources/images/material_live_help.svg b/resources/images/material_live_help.svg deleted file mode 100644 index 8f975fdda..000000000 --- a/resources/images/material_live_help.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/resources/images/material_lock.svg b/resources/images/material_lock.svg deleted file mode 100644 index 57dd76bc6..000000000 --- a/resources/images/material_lock.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/resources/images/material_open_in_new.svg b/resources/images/material_open_in_new.svg deleted file mode 100644 index dba1bc9fc..000000000 --- a/resources/images/material_open_in_new.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/resources/images/material_search.svg b/resources/images/material_search.svg deleted file mode 100644 index 883872d8e..000000000 --- a/resources/images/material_search.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/resources/images/material_settings.svg b/resources/images/material_settings.svg deleted file mode 100644 index 819864198..000000000 --- a/resources/images/material_settings.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/resources/images/material_visibility.svg b/resources/images/material_visibility.svg deleted file mode 100644 index 9999c128e..000000000 --- a/resources/images/material_visibility.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/resources/images/material_visibility_off.svg b/resources/images/material_visibility_off.svg deleted file mode 100644 index 90fac770f..000000000 --- a/resources/images/material_visibility_off.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/resources/images/mobile/card.svg b/resources/images/mobile/card.svg new file mode 100644 index 000000000..995f5a98e --- /dev/null +++ b/resources/images/mobile/card.svg @@ -0,0 +1,17 @@ + + + + + + + + + diff --git a/resources/images/mobile/device.svg b/resources/images/mobile/device.svg index bf4897510..8dc7a07c3 100644 --- a/resources/images/mobile/device.svg +++ b/resources/images/mobile/device.svg @@ -1,15 +1,41 @@ - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/mobile/device_button.svg b/resources/images/mobile/device_button.svg new file mode 100644 index 000000000..3c248ed14 --- /dev/null +++ b/resources/images/mobile/device_button.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/mobile/help.svg b/resources/images/mobile/help.svg new file mode 100644 index 000000000..01e00d835 --- /dev/null +++ b/resources/images/mobile/help.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + diff --git a/resources/images/mobile/home.svg b/resources/images/mobile/home.svg new file mode 100644 index 000000000..586b09f38 --- /dev/null +++ b/resources/images/mobile/home.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + diff --git a/resources/images/mobile/icon_nfc.svg b/resources/images/mobile/icon_nfc.svg index e37a9838e..d96729d7e 100644 --- a/resources/images/mobile/icon_nfc.svg +++ b/resources/images/mobile/icon_nfc.svg @@ -1,5 +1,9 @@ - - - - + + + + diff --git a/resources/images/mobile/icon_remote.svg b/resources/images/mobile/icon_remote.svg index ab167db1f..c77469f9b 100644 --- a/resources/images/mobile/icon_remote.svg +++ b/resources/images/mobile/icon_remote.svg @@ -1,11 +1,20 @@ - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/resources/images/mobile/icon_simulator.svg b/resources/images/mobile/icon_simulator.svg index e3a43d6d5..2c82f0ad8 100644 --- a/resources/images/mobile/icon_simulator.svg +++ b/resources/images/mobile/icon_simulator.svg @@ -2,7 +2,7 @@ - + + c 0,-5.5 4.8,-9 12.6,-9 9.5,0 14.8,4 15.3,11.4 z" fill="#0077B6" /> - + diff --git a/resources/images/mobile/icon_smart.svg b/resources/images/mobile/icon_smart.svg index 9f72756ed..885753163 100644 --- a/resources/images/mobile/icon_smart.svg +++ b/resources/images/mobile/icon_smart.svg @@ -1,10 +1,83 @@ - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/ios/material_arrow_left.svg b/resources/images/mobile/material_arrow_left.svg similarity index 100% rename from resources/images/ios/material_arrow_left.svg rename to resources/images/mobile/material_arrow_left.svg diff --git a/resources/images/mobile/material_home.svg b/resources/images/mobile/material_home.svg deleted file mode 100644 index 6bd84cfd4..000000000 --- a/resources/images/mobile/material_home.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/resources/images/mobile/mydata_button.svg b/resources/images/mobile/mydata_button.svg new file mode 100644 index 000000000..575783a49 --- /dev/null +++ b/resources/images/mobile/mydata_button.svg @@ -0,0 +1,17 @@ + + + + + + + + + diff --git a/resources/images/mobile/no_internet_darkmode.svg b/resources/images/mobile/no_internet_darkmode.svg new file mode 100644 index 000000000..ebc9275c2 --- /dev/null +++ b/resources/images/mobile/no_internet_darkmode.svg @@ -0,0 +1,36 @@ + + + + + + + + + diff --git a/resources/images/mobile/no_internet_highcontrast.svg b/resources/images/mobile/no_internet_highcontrast.svg new file mode 100644 index 000000000..a569d5a16 --- /dev/null +++ b/resources/images/mobile/no_internet_highcontrast.svg @@ -0,0 +1,36 @@ + + + + + + + + + diff --git a/resources/images/mobile/no_internet_lightmode.svg b/resources/images/mobile/no_internet_lightmode.svg new file mode 100644 index 000000000..890047995 --- /dev/null +++ b/resources/images/mobile/no_internet_lightmode.svg @@ -0,0 +1,36 @@ + + + + + + + + + diff --git a/resources/images/mobile/phone_card_reader.svg b/resources/images/mobile/phone_card_reader.svg index 81d3e8232..7b68f72b9 100644 --- a/resources/images/mobile/phone_card_reader.svg +++ b/resources/images/mobile/phone_card_reader.svg @@ -1,10 +1,31 @@ - - - - - - + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/mobile/phone_nfc.svg b/resources/images/mobile/phone_nfc.svg index 1f4376182..e0a51c28b 100644 --- a/resources/images/mobile/phone_nfc.svg +++ b/resources/images/mobile/phone_nfc.svg @@ -1,13 +1,20 @@ - - - - - - - - - - - - + + + + diff --git a/resources/images/mobile/phone_nfc_info.svg b/resources/images/mobile/phone_nfc_info.svg new file mode 100644 index 000000000..987400465 --- /dev/null +++ b/resources/images/mobile/phone_nfc_info.svg @@ -0,0 +1,25 @@ + + + + + + + diff --git a/resources/images/mobile/phone_remote_info.svg b/resources/images/mobile/phone_remote_info.svg new file mode 100644 index 000000000..4e93839a7 --- /dev/null +++ b/resources/images/mobile/phone_remote_info.svg @@ -0,0 +1,32 @@ + + + + + + + + diff --git a/resources/images/mobile/questionmark.svg b/resources/images/mobile/questionmark.svg new file mode 100644 index 000000000..dd585e37a --- /dev/null +++ b/resources/images/mobile/questionmark.svg @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/resources/images/mobile/settings.svg b/resources/images/mobile/settings.svg new file mode 100644 index 000000000..ba053f1e7 --- /dev/null +++ b/resources/images/mobile/settings.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + diff --git a/resources/images/mobile/share.svg b/resources/images/mobile/share.svg new file mode 100644 index 000000000..b342111a3 --- /dev/null +++ b/resources/images/mobile/share.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/mobile/smarteid.svg b/resources/images/mobile/smarteid.svg new file mode 100644 index 000000000..eb9dc8ed9 --- /dev/null +++ b/resources/images/mobile/smarteid.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/mobile/workflow_success_nfc_darkmode.svg b/resources/images/mobile/workflow_success_nfc_darkmode.svg new file mode 100644 index 000000000..66a7144ea --- /dev/null +++ b/resources/images/mobile/workflow_success_nfc_darkmode.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + diff --git a/resources/images/mobile/workflow_success_nfc_highcontrast.svg b/resources/images/mobile/workflow_success_nfc_highcontrast.svg new file mode 100644 index 000000000..26c6ac17e --- /dev/null +++ b/resources/images/mobile/workflow_success_nfc_highcontrast.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + diff --git a/resources/images/mobile/workflow_success_nfc_lightmode.svg b/resources/images/mobile/workflow_success_nfc_lightmode.svg new file mode 100644 index 000000000..2a9700f64 --- /dev/null +++ b/resources/images/mobile/workflow_success_nfc_lightmode.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + diff --git a/resources/images/mobile/x.svg b/resources/images/mobile/x.svg new file mode 100644 index 000000000..6445d732d --- /dev/null +++ b/resources/images/mobile/x.svg @@ -0,0 +1,11 @@ + + + + + + + diff --git a/resources/images/mydata.svg b/resources/images/mydata.svg index 8d1a386d1..784b6ba17 100644 --- a/resources/images/mydata.svg +++ b/resources/images/mydata.svg @@ -1,11 +1,39 @@ - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/open_website.svg b/resources/images/open_website.svg new file mode 100644 index 000000000..dc33ca403 --- /dev/null +++ b/resources/images/open_website.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + diff --git a/resources/images/pairingCode.webp b/resources/images/pairingCode.webp new file mode 100644 index 000000000..56ed05ec0 Binary files /dev/null and b/resources/images/pairingCode.webp differ diff --git a/resources/images/phone_to_pc.svg b/resources/images/phone_to_pc.svg index b18e30f05..f69215979 100644 --- a/resources/images/phone_to_pc.svg +++ b/resources/images/phone_to_pc.svg @@ -1,29 +1,65 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + diff --git a/resources/images/icon_ten_digit_puk.svg b/resources/images/pin_letter_five_digit_pin.svg similarity index 56% rename from resources/images/icon_ten_digit_puk.svg rename to resources/images/pin_letter_five_digit_pin.svg index 0035185dc..a8a0d5274 100644 --- a/resources/images/icon_ten_digit_puk.svg +++ b/resources/images/pin_letter_five_digit_pin.svg @@ -1,22 +1,17 @@ - + - + - - - - + + + - - - - - + \ No newline at end of file diff --git a/resources/images/pin_letter_pinpuk_red_bar.svg b/resources/images/pin_letter_pinpuk_red_bar.svg deleted file mode 100644 index d5911235a..000000000 --- a/resources/images/pin_letter_pinpuk_red_bar.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/resources/images/pin_letter_pinpuk_red_bar_puk.svg b/resources/images/pin_letter_pinpuk_red_bar_puk.svg deleted file mode 100644 index b25eeaf2e..000000000 --- a/resources/images/pin_letter_pinpuk_red_bar_puk.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/resources/images/pin_person.svg b/resources/images/pin_person.svg index 182b09fd5..6917c97af 100644 --- a/resources/images/pin_person.svg +++ b/resources/images/pin_person.svg @@ -1,5 +1,83 @@ - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/pin_person.webp b/resources/images/pin_person.webp new file mode 100644 index 000000000..152767886 Binary files /dev/null and b/resources/images/pin_person.webp differ diff --git a/resources/images/pin_unknown.svg b/resources/images/pin_unknown.svg new file mode 100644 index 000000000..7a9d342c2 --- /dev/null +++ b/resources/images/pin_unknown.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + diff --git a/resources/images/provider.svg b/resources/images/provider.svg deleted file mode 100644 index cc58a7752..000000000 --- a/resources/images/provider.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - diff --git a/resources/images/provider/citizen.svg b/resources/images/provider/citizen.svg deleted file mode 100644 index b1343abb9..000000000 --- a/resources/images/provider/citizen.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/resources/images/provider/citizen_bg.svg b/resources/images/provider/citizen_bg.svg deleted file mode 100644 index 9c3f28ae5..000000000 --- a/resources/images/provider/citizen_bg.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/images/provider/citizen_button.svg b/resources/images/provider/citizen_button.svg deleted file mode 100644 index 0798e5c5d..000000000 --- a/resources/images/provider/citizen_button.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/resources/images/provider/default_bg.svg b/resources/images/provider/default_bg.svg deleted file mode 100644 index 5c5b7aff8..000000000 --- a/resources/images/provider/default_bg.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/resources/images/provider/finance.svg b/resources/images/provider/finance.svg deleted file mode 100644 index 873a09c50..000000000 --- a/resources/images/provider/finance.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/resources/images/provider/finance_bg.svg b/resources/images/provider/finance_bg.svg deleted file mode 100644 index b98f4718d..000000000 --- a/resources/images/provider/finance_bg.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/resources/images/provider/finance_button.svg b/resources/images/provider/finance_button.svg deleted file mode 100644 index 9515bed7e..000000000 --- a/resources/images/provider/finance_button.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/resources/images/provider/general.svg b/resources/images/provider/general.svg deleted file mode 100644 index d87ba87a4..000000000 --- a/resources/images/provider/general.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - diff --git a/resources/images/provider/general_bg.svg b/resources/images/provider/general_bg.svg deleted file mode 100644 index 4810c936a..000000000 --- a/resources/images/provider/general_bg.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - diff --git a/resources/images/provider/general_button.svg b/resources/images/provider/general_button.svg deleted file mode 100644 index f584db190..000000000 --- a/resources/images/provider/general_button.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - diff --git a/resources/images/provider/information.svg b/resources/images/provider/information.svg deleted file mode 100644 index 83f04f3b1..000000000 --- a/resources/images/provider/information.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/resources/images/provider/insurance.svg b/resources/images/provider/insurance.svg deleted file mode 100644 index fef881f2b..000000000 --- a/resources/images/provider/insurance.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/resources/images/provider/insurance_bg.svg b/resources/images/provider/insurance_bg.svg deleted file mode 100644 index e2e567c4e..000000000 --- a/resources/images/provider/insurance_bg.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/resources/images/provider/insurance_button.svg b/resources/images/provider/insurance_button.svg deleted file mode 100644 index cc23024af..000000000 --- a/resources/images/provider/insurance_button.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/resources/images/provider/ios/citizen.svg b/resources/images/provider/ios/citizen.svg deleted file mode 100644 index 65ed268b2..000000000 --- a/resources/images/provider/ios/citizen.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/images/provider/ios/finance.svg b/resources/images/provider/ios/finance.svg deleted file mode 100644 index 0801ab800..000000000 --- a/resources/images/provider/ios/finance.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/resources/images/provider/ios/general.svg b/resources/images/provider/ios/general.svg deleted file mode 100644 index f9a4cfe27..000000000 --- a/resources/images/provider/ios/general.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - diff --git a/resources/images/provider/ios/insurance.svg b/resources/images/provider/ios/insurance.svg deleted file mode 100644 index cbbf93499..000000000 --- a/resources/images/provider/ios/insurance.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/resources/images/provider/ios/other.svg b/resources/images/provider/ios/other.svg deleted file mode 100644 index eb8d69d05..000000000 --- a/resources/images/provider/ios/other.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/resources/images/provider/other.svg b/resources/images/provider/other.svg deleted file mode 100644 index dd1d518bf..000000000 --- a/resources/images/provider/other.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/resources/images/provider/other_bg.svg b/resources/images/provider/other_bg.svg deleted file mode 100644 index cbbcdad24..000000000 --- a/resources/images/provider/other_bg.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/resources/images/provider/other_button.svg b/resources/images/provider/other_button.svg deleted file mode 100644 index a6afc7b69..000000000 --- a/resources/images/provider/other_button.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/resources/images/provider/purpose.svg b/resources/images/provider/purpose.svg deleted file mode 100644 index aca310a8f..000000000 --- a/resources/images/provider/purpose.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/resources/images/puk_darkmode.svg b/resources/images/puk_darkmode.svg new file mode 100644 index 000000000..5d26d99ef --- /dev/null +++ b/resources/images/puk_darkmode.svg @@ -0,0 +1,371 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/puk_darkmode.webp b/resources/images/puk_darkmode.webp new file mode 100644 index 000000000..fbf41df5c Binary files /dev/null and b/resources/images/puk_darkmode.webp differ diff --git a/resources/images/puk_highcontrast.svg b/resources/images/puk_highcontrast.svg new file mode 100644 index 000000000..69fc9bf0c --- /dev/null +++ b/resources/images/puk_highcontrast.svg @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/puk_highcontrast.webp b/resources/images/puk_highcontrast.webp new file mode 100644 index 000000000..56bc28d1a Binary files /dev/null and b/resources/images/puk_highcontrast.webp differ diff --git a/resources/images/puk_lightmode.svg b/resources/images/puk_lightmode.svg new file mode 100644 index 000000000..3f4ad1917 --- /dev/null +++ b/resources/images/puk_lightmode.svg @@ -0,0 +1,371 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/puk_lightmode.webp b/resources/images/puk_lightmode.webp new file mode 100644 index 000000000..2483d20e8 Binary files /dev/null and b/resources/images/puk_lightmode.webp differ diff --git a/resources/images/sandglass.svg b/resources/images/sandglass.svg old mode 100755 new mode 100644 index 118606d3e..515b55774 --- a/resources/images/sandglass.svg +++ b/resources/images/sandglass.svg @@ -1,17 +1,24 @@ - - - - - - - - - - - - - - - - + + + + + + diff --git a/resources/images/sandglass.webp b/resources/images/sandglass.webp new file mode 100644 index 000000000..525d0b738 Binary files /dev/null and b/resources/images/sandglass.webp differ diff --git a/resources/images/siteWithLogo.png b/resources/images/siteWithLogo.png deleted file mode 100644 index cee4fd42b..000000000 Binary files a/resources/images/siteWithLogo.png and /dev/null differ diff --git a/resources/images/siteWithLogo_darkmode.svg b/resources/images/siteWithLogo_darkmode.svg new file mode 100644 index 000000000..8ab41d291 --- /dev/null +++ b/resources/images/siteWithLogo_darkmode.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/siteWithLogo_highcontrast.svg b/resources/images/siteWithLogo_highcontrast.svg new file mode 100644 index 000000000..f640fa8f2 --- /dev/null +++ b/resources/images/siteWithLogo_highcontrast.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/siteWithLogo_lightmode.svg b/resources/images/siteWithLogo_lightmode.svg new file mode 100644 index 000000000..4ab8657c9 --- /dev/null +++ b/resources/images/siteWithLogo_lightmode.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/src/wix_dialog.svg b/resources/images/src/wix_dialog.svg new file mode 100644 index 000000000..7f2f91352 --- /dev/null +++ b/resources/images/src/wix_dialog.svg @@ -0,0 +1,11 @@ + + + + + + + + + + AusweisApp + diff --git a/resources/images/status_error.svg b/resources/images/status_error.svg deleted file mode 100644 index ce3d085f5..000000000 --- a/resources/images/status_error.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/resources/images/status_error_darkmode.svg b/resources/images/status_error_darkmode.svg new file mode 100644 index 000000000..311e20863 --- /dev/null +++ b/resources/images/status_error_darkmode.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/resources/images/status_error_highcontrast.svg b/resources/images/status_error_highcontrast.svg new file mode 100644 index 000000000..8c5dbd623 --- /dev/null +++ b/resources/images/status_error_highcontrast.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/resources/images/status_error_lightmode.svg b/resources/images/status_error_lightmode.svg new file mode 100644 index 000000000..311e20863 --- /dev/null +++ b/resources/images/status_error_lightmode.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/resources/images/status_info.svg b/resources/images/status_info.svg deleted file mode 100644 index f92bbd1b1..000000000 --- a/resources/images/status_info.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/resources/images/status_info_darkmode.svg b/resources/images/status_info_darkmode.svg new file mode 100644 index 000000000..d34f3041c --- /dev/null +++ b/resources/images/status_info_darkmode.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/resources/images/status_info_highcontrast.svg b/resources/images/status_info_highcontrast.svg new file mode 100644 index 000000000..7e7f565bb --- /dev/null +++ b/resources/images/status_info_highcontrast.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/resources/images/status_info_lightmode.svg b/resources/images/status_info_lightmode.svg new file mode 100644 index 000000000..e80332073 --- /dev/null +++ b/resources/images/status_info_lightmode.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/resources/images/status_ok.svg b/resources/images/status_ok.svg deleted file mode 100755 index 1d83b6aa5..000000000 --- a/resources/images/status_ok.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/resources/images/status_ok_darkmode.svg b/resources/images/status_ok_darkmode.svg new file mode 100644 index 000000000..ea1c47e74 --- /dev/null +++ b/resources/images/status_ok_darkmode.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + diff --git a/resources/images/status_ok_highcontrast.svg b/resources/images/status_ok_highcontrast.svg new file mode 100644 index 000000000..730cfae5c --- /dev/null +++ b/resources/images/status_ok_highcontrast.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + diff --git a/resources/images/status_ok_lightmode.svg b/resources/images/status_ok_lightmode.svg new file mode 100644 index 000000000..0a46e431e --- /dev/null +++ b/resources/images/status_ok_lightmode.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + diff --git a/resources/images/status_warning.svg b/resources/images/status_warning.svg new file mode 100644 index 000000000..b9105f577 --- /dev/null +++ b/resources/images/status_warning.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/resources/images/transportpin_darkmode.svg b/resources/images/transportpin_darkmode.svg new file mode 100644 index 000000000..1a3f853f4 --- /dev/null +++ b/resources/images/transportpin_darkmode.svg @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/transportpin_darkmode.webp b/resources/images/transportpin_darkmode.webp new file mode 100644 index 000000000..ffc9b8998 Binary files /dev/null and b/resources/images/transportpin_darkmode.webp differ diff --git a/resources/images/transportpin_highcontrast.svg b/resources/images/transportpin_highcontrast.svg new file mode 100644 index 000000000..fbf8c9a8f --- /dev/null +++ b/resources/images/transportpin_highcontrast.svg @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/transportpin_highcontrast.webp b/resources/images/transportpin_highcontrast.webp new file mode 100644 index 000000000..8fe58fb0e Binary files /dev/null and b/resources/images/transportpin_highcontrast.webp differ diff --git a/resources/images/transportpin_lightmode.svg b/resources/images/transportpin_lightmode.svg new file mode 100644 index 000000000..adb47e7f8 --- /dev/null +++ b/resources/images/transportpin_lightmode.svg @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/transportpin_lightmode.webp b/resources/images/transportpin_lightmode.webp new file mode 100644 index 000000000..642754d28 Binary files /dev/null and b/resources/images/transportpin_lightmode.webp differ diff --git a/resources/images/trash_icon.svg b/resources/images/trash_icon.svg new file mode 100644 index 000000000..bf9011acb --- /dev/null +++ b/resources/images/trash_icon.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/trash_icon_all.svg b/resources/images/trash_icon_all.svg deleted file mode 100644 index 9371891ec..000000000 --- a/resources/images/trash_icon_all.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/resources/images/trash_icon_old.svg b/resources/images/trash_icon_old.svg new file mode 100644 index 000000000..7f286a457 --- /dev/null +++ b/resources/images/trash_icon_old.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/triangle.svg b/resources/images/triangle.svg deleted file mode 100644 index 93d81f553..000000000 --- a/resources/images/triangle.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/resources/images/tutorial/arrow_blue.svg b/resources/images/tutorial/arrow_blue.svg deleted file mode 100644 index 835b6fcfc..000000000 --- a/resources/images/tutorial/arrow_blue.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/resources/images/tutorial/arrows.svg b/resources/images/tutorial/arrows.svg deleted file mode 100644 index cb955c08e..000000000 --- a/resources/images/tutorial/arrows.svg +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/images/tutorial/background_icon_how.svg b/resources/images/tutorial/background_icon_how.svg deleted file mode 100644 index bdc623a14..000000000 --- a/resources/images/tutorial/background_icon_how.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/resources/images/tutorial/background_icon_important.svg b/resources/images/tutorial/background_icon_important.svg deleted file mode 100644 index 81d668524..000000000 --- a/resources/images/tutorial/background_icon_important.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/resources/images/tutorial/background_icon_where.svg b/resources/images/tutorial/background_icon_where.svg deleted file mode 100644 index 6d168cd89..000000000 --- a/resources/images/tutorial/background_icon_where.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/resources/images/tutorial/button_de.png b/resources/images/tutorial/button_de.png deleted file mode 100644 index 818254c17..000000000 Binary files a/resources/images/tutorial/button_de.png and /dev/null differ diff --git a/resources/images/tutorial/button_en.png b/resources/images/tutorial/button_en.png deleted file mode 100644 index 362954217..000000000 Binary files a/resources/images/tutorial/button_en.png and /dev/null differ diff --git a/resources/images/tutorial/bva.svg b/resources/images/tutorial/bva.svg deleted file mode 100644 index 11f3c24c9..000000000 --- a/resources/images/tutorial/bva.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/resources/images/tutorial/check.svg b/resources/images/tutorial/check.svg deleted file mode 100644 index df7b14f1d..000000000 --- a/resources/images/tutorial/check.svg +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/images/tutorial/circle-1.svg b/resources/images/tutorial/circle-1.svg deleted file mode 100644 index 6e764fffd..000000000 --- a/resources/images/tutorial/circle-1.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/resources/images/tutorial/circle-2.svg b/resources/images/tutorial/circle-2.svg deleted file mode 100644 index f2dac7236..000000000 --- a/resources/images/tutorial/circle-2.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/resources/images/tutorial/circle-3.svg b/resources/images/tutorial/circle-3.svg deleted file mode 100644 index 798844e99..000000000 --- a/resources/images/tutorial/circle-3.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/resources/images/tutorial/circle-4.svg b/resources/images/tutorial/circle-4.svg deleted file mode 100644 index 61edd8094..000000000 --- a/resources/images/tutorial/circle-4.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/resources/images/tutorial/circle-lock-2.svg b/resources/images/tutorial/circle-lock-2.svg deleted file mode 100644 index f917a700b..000000000 --- a/resources/images/tutorial/circle-lock-2.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/resources/images/tutorial/circle-lock.svg b/resources/images/tutorial/circle-lock.svg deleted file mode 100644 index 0c1b37c27..000000000 --- a/resources/images/tutorial/circle-lock.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/resources/images/tutorial/click.svg b/resources/images/tutorial/click.svg deleted file mode 100644 index f67b5abc4..000000000 --- a/resources/images/tutorial/click.svg +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/images/tutorial/cross.svg b/resources/images/tutorial/cross.svg deleted file mode 100644 index 2645c4804..000000000 --- a/resources/images/tutorial/cross.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/resources/images/tutorial/desktop.svg b/resources/images/tutorial/desktop.svg deleted file mode 100644 index af7c501d0..000000000 --- a/resources/images/tutorial/desktop.svg +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/images/tutorial/hand.svg b/resources/images/tutorial/hand.svg deleted file mode 100644 index 87eb6bbde..000000000 --- a/resources/images/tutorial/hand.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/resources/images/tutorial/hint.svg b/resources/images/tutorial/hint.svg deleted file mode 100644 index 3a46e88a2..000000000 --- a/resources/images/tutorial/hint.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/resources/images/tutorial/how_desktop.svg b/resources/images/tutorial/how_desktop.svg deleted file mode 100644 index 5d0044dd4..000000000 --- a/resources/images/tutorial/how_desktop.svg +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/images/tutorial/how_device_lineup.svg b/resources/images/tutorial/how_device_lineup.svg deleted file mode 100644 index 03b4c547e..000000000 --- a/resources/images/tutorial/how_device_lineup.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/resources/images/tutorial/how_form_no_fun.svg b/resources/images/tutorial/how_form_no_fun.svg deleted file mode 100644 index 3e8061c8b..000000000 --- a/resources/images/tutorial/how_form_no_fun.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/resources/images/tutorial/how_idcard_cycle.svg b/resources/images/tutorial/how_idcard_cycle.svg deleted file mode 100644 index db9bd817a..000000000 --- a/resources/images/tutorial/how_idcard_cycle.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/resources/images/tutorial/how_method_nfc.svg b/resources/images/tutorial/how_method_nfc.svg deleted file mode 100644 index dd4a50bdc..000000000 --- a/resources/images/tutorial/how_method_nfc.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/resources/images/tutorial/how_method_sac_desktop.svg b/resources/images/tutorial/how_method_sac_desktop.svg deleted file mode 100644 index b6d91ee65..000000000 --- a/resources/images/tutorial/how_method_sac_desktop.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/resources/images/tutorial/how_method_sac_mobile.svg b/resources/images/tutorial/how_method_sac_mobile.svg deleted file mode 100644 index 15316e407..000000000 --- a/resources/images/tutorial/how_method_sac_mobile.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/resources/images/tutorial/how_questions_everywhere.svg b/resources/images/tutorial/how_questions_everywhere.svg deleted file mode 100644 index 31af16a20..000000000 --- a/resources/images/tutorial/how_questions_everywhere.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/resources/images/tutorial/icon_box.svg b/resources/images/tutorial/icon_box.svg deleted file mode 100644 index df5e08865..000000000 --- a/resources/images/tutorial/icon_box.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/resources/images/tutorial/icon_circle.svg b/resources/images/tutorial/icon_circle.svg deleted file mode 100644 index 3aa6a1679..000000000 --- a/resources/images/tutorial/icon_circle.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/resources/images/tutorial/icon_diamond.svg b/resources/images/tutorial/icon_diamond.svg deleted file mode 100644 index f31b1194c..000000000 --- a/resources/images/tutorial/icon_diamond.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/resources/images/tutorial/icon_star.svg b/resources/images/tutorial/icon_star.svg deleted file mode 100644 index ed3464a6a..000000000 --- a/resources/images/tutorial/icon_star.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/resources/images/tutorial/identify.svg b/resources/images/tutorial/identify.svg deleted file mode 100644 index b391d9f79..000000000 --- a/resources/images/tutorial/identify.svg +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/images/tutorial/important_lets_go.svg b/resources/images/tutorial/important_lets_go.svg deleted file mode 100644 index 85699f3f4..000000000 --- a/resources/images/tutorial/important_lets_go.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/resources/images/tutorial/important_pin5.svg b/resources/images/tutorial/important_pin5.svg deleted file mode 100644 index a1d6fe58c..000000000 --- a/resources/images/tutorial/important_pin5.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/resources/images/tutorial/important_pin6.svg b/resources/images/tutorial/important_pin6.svg deleted file mode 100644 index 609fa8a9b..000000000 --- a/resources/images/tutorial/important_pin6.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/resources/images/tutorial/important_space_questionmark.svg b/resources/images/tutorial/important_space_questionmark.svg deleted file mode 100644 index 8f2afc583..000000000 --- a/resources/images/tutorial/important_space_questionmark.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/resources/images/tutorial/laptop.svg b/resources/images/tutorial/laptop.svg deleted file mode 100644 index abb0e0ad4..000000000 --- a/resources/images/tutorial/laptop.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/resources/images/tutorial/letters.svg b/resources/images/tutorial/letters.svg deleted file mode 100644 index d92c692c9..000000000 --- a/resources/images/tutorial/letters.svg +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/images/tutorial/main_menu_how_caret.svg b/resources/images/tutorial/main_menu_how_caret.svg deleted file mode 100644 index a8104cb64..000000000 --- a/resources/images/tutorial/main_menu_how_caret.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/resources/images/tutorial/main_menu_important_caret.svg b/resources/images/tutorial/main_menu_important_caret.svg deleted file mode 100644 index 8ccd62d03..000000000 --- a/resources/images/tutorial/main_menu_important_caret.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/resources/images/tutorial/main_menu_what_caret.svg b/resources/images/tutorial/main_menu_what_caret.svg deleted file mode 100644 index faf15ce1e..000000000 --- a/resources/images/tutorial/main_menu_what_caret.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/resources/images/tutorial/main_menu_where_caret.svg b/resources/images/tutorial/main_menu_where_caret.svg deleted file mode 100644 index 5f1eabeb7..000000000 --- a/resources/images/tutorial/main_menu_where_caret.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/resources/images/tutorial/nfc.svg b/resources/images/tutorial/nfc.svg deleted file mode 100644 index 468e0705c..000000000 --- a/resources/images/tutorial/nfc.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/resources/images/tutorial/no-nfc.svg b/resources/images/tutorial/no-nfc.svg deleted file mode 100644 index 86ced3a54..000000000 --- a/resources/images/tutorial/no-nfc.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/resources/images/tutorial/phone.svg b/resources/images/tutorial/phone.svg deleted file mode 100644 index 32ff6bdb8..000000000 --- a/resources/images/tutorial/phone.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/resources/images/tutorial/phone_border.svg b/resources/images/tutorial/phone_border.svg deleted file mode 100644 index fa50dbdd1..000000000 --- a/resources/images/tutorial/phone_border.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/resources/images/tutorial/phone_list.svg b/resources/images/tutorial/phone_list.svg deleted file mode 100755 index 09dbba65a..000000000 --- a/resources/images/tutorial/phone_list.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/resources/images/tutorial/phone_screen.svg b/resources/images/tutorial/phone_screen.svg deleted file mode 100644 index 809190ac5..000000000 --- a/resources/images/tutorial/phone_screen.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/resources/images/tutorial/phone_screen_de.png b/resources/images/tutorial/phone_screen_de.png deleted file mode 100644 index 0756f319d..000000000 Binary files a/resources/images/tutorial/phone_screen_de.png and /dev/null differ diff --git a/resources/images/tutorial/phone_screen_en.png b/resources/images/tutorial/phone_screen_en.png deleted file mode 100644 index d5f6ba249..000000000 Binary files a/resources/images/tutorial/phone_screen_en.png and /dev/null differ diff --git a/resources/images/tutorial/pin-5@2x.png b/resources/images/tutorial/pin-5@2x.png deleted file mode 100644 index 06b5ba3bb..000000000 Binary files a/resources/images/tutorial/pin-5@2x.png and /dev/null differ diff --git a/resources/images/tutorial/pin-6@2x.png b/resources/images/tutorial/pin-6@2x.png deleted file mode 100644 index 9c5c09bcc..000000000 Binary files a/resources/images/tutorial/pin-6@2x.png and /dev/null differ diff --git a/resources/images/tutorial/play_movie.png b/resources/images/tutorial/play_movie.png deleted file mode 100644 index af0e3bfaf..000000000 Binary files a/resources/images/tutorial/play_movie.png and /dev/null differ diff --git a/resources/images/tutorial/provider_home.svg b/resources/images/tutorial/provider_home.svg deleted file mode 100644 index 05c02740d..000000000 --- a/resources/images/tutorial/provider_home.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - diff --git a/resources/images/tutorial/providericons.png b/resources/images/tutorial/providericons.png deleted file mode 100644 index 2ec75f20b..000000000 Binary files a/resources/images/tutorial/providericons.png and /dev/null differ diff --git a/resources/images/tutorial/questionmark.svg b/resources/images/tutorial/questionmark.svg deleted file mode 100644 index 66abe3d1e..000000000 --- a/resources/images/tutorial/questionmark.svg +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/images/tutorial/reader.svg b/resources/images/tutorial/reader.svg deleted file mode 100644 index afd797564..000000000 --- a/resources/images/tutorial/reader.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/resources/images/tutorial/reader_nfc_finished.svg b/resources/images/tutorial/reader_nfc_finished.svg deleted file mode 100644 index c4ce3569d..000000000 --- a/resources/images/tutorial/reader_nfc_finished.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/resources/images/tutorial/reader_nfc_npa_on_smartphone.svg b/resources/images/tutorial/reader_nfc_npa_on_smartphone.svg deleted file mode 100644 index d698dcb4f..000000000 --- a/resources/images/tutorial/reader_nfc_npa_on_smartphone.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/resources/images/tutorial/reader_nfc_pin6.svg b/resources/images/tutorial/reader_nfc_pin6.svg deleted file mode 100644 index 3c0857dcd..000000000 --- a/resources/images/tutorial/reader_nfc_pin6.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/resources/images/tutorial/reader_nfc_provider_on_smartphone.svg b/resources/images/tutorial/reader_nfc_provider_on_smartphone.svg deleted file mode 100644 index bccb43118..000000000 --- a/resources/images/tutorial/reader_nfc_provider_on_smartphone.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/resources/images/tutorial/reader_nfc_smartphone_nfc_position.svg b/resources/images/tutorial/reader_nfc_smartphone_nfc_position.svg deleted file mode 100644 index 4c262414d..000000000 --- a/resources/images/tutorial/reader_nfc_smartphone_nfc_position.svg +++ /dev/null @@ -1,24 +0,0 @@ - - - - - NFC? - NFC? - NFC? - NFC? - diff --git a/resources/images/tutorial/reader_nfc_userdata_example_de.svg b/resources/images/tutorial/reader_nfc_userdata_example_de.svg deleted file mode 100644 index a03859618..000000000 --- a/resources/images/tutorial/reader_nfc_userdata_example_de.svg +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - Zum Beispiel - Name? - Vorname? - Geburtsdatum? - Adresse? - diff --git a/resources/images/tutorial/reader_nfc_userdata_example_en.svg b/resources/images/tutorial/reader_nfc_userdata_example_en.svg deleted file mode 100644 index ef302ad00..000000000 --- a/resources/images/tutorial/reader_nfc_userdata_example_en.svg +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - For Example - Surname? - Given Name? - Date of Birth? - Address? - diff --git a/resources/images/tutorial/reader_sac_aa2_ok.svg b/resources/images/tutorial/reader_sac_aa2_ok.svg deleted file mode 100644 index dc561ea92..000000000 --- a/resources/images/tutorial/reader_sac_aa2_ok.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/resources/images/tutorial/reader_sac_menu_android_de.svg b/resources/images/tutorial/reader_sac_menu_android_de.svg deleted file mode 100644 index 5c853c44f..000000000 --- a/resources/images/tutorial/reader_sac_menu_android_de.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/resources/images/tutorial/reader_sac_menu_android_en.svg b/resources/images/tutorial/reader_sac_menu_android_en.svg deleted file mode 100644 index df71aca8a..000000000 --- a/resources/images/tutorial/reader_sac_menu_android_en.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/resources/images/tutorial/reader_sac_menu_ios_de.svg b/resources/images/tutorial/reader_sac_menu_ios_de.svg deleted file mode 100644 index 0650ae297..000000000 --- a/resources/images/tutorial/reader_sac_menu_ios_de.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/resources/images/tutorial/reader_sac_menu_ios_en.svg b/resources/images/tutorial/reader_sac_menu_ios_en.svg deleted file mode 100644 index d941a6834..000000000 --- a/resources/images/tutorial/reader_sac_menu_ios_en.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/resources/images/tutorial/reader_sac_no_nfc_devices.svg b/resources/images/tutorial/reader_sac_no_nfc_devices.svg deleted file mode 100644 index d8afccde9..000000000 --- a/resources/images/tutorial/reader_sac_no_nfc_devices.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/resources/images/tutorial/reader_sac_no_nfc_provider.svg b/resources/images/tutorial/reader_sac_no_nfc_provider.svg deleted file mode 100644 index 6b0edcecc..000000000 --- a/resources/images/tutorial/reader_sac_no_nfc_provider.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/resources/images/tutorial/reader_sac_npa_on_laptop.svg b/resources/images/tutorial/reader_sac_npa_on_laptop.svg deleted file mode 100644 index 33b5c6d62..000000000 --- a/resources/images/tutorial/reader_sac_npa_on_laptop.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/resources/images/tutorial/reader_sac_provider_on_laptop.svg b/resources/images/tutorial/reader_sac_provider_on_laptop.svg deleted file mode 100644 index cc63a9916..000000000 --- a/resources/images/tutorial/reader_sac_provider_on_laptop.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/resources/images/tutorial/rectangles.svg b/resources/images/tutorial/rectangles.svg deleted file mode 100644 index 51132d2bd..000000000 --- a/resources/images/tutorial/rectangles.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/resources/images/tutorial/save.svg b/resources/images/tutorial/save.svg deleted file mode 100644 index 81e1e2704..000000000 --- a/resources/images/tutorial/save.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/resources/images/tutorial/screenshot_cert_android_de.png b/resources/images/tutorial/screenshot_cert_android_de.png deleted file mode 100644 index 05a5fbe8a..000000000 Binary files a/resources/images/tutorial/screenshot_cert_android_de.png and /dev/null differ diff --git a/resources/images/tutorial/screenshot_cert_android_en.png b/resources/images/tutorial/screenshot_cert_android_en.png deleted file mode 100644 index 3d0276b77..000000000 Binary files a/resources/images/tutorial/screenshot_cert_android_en.png and /dev/null differ diff --git a/resources/images/tutorial/screenshot_cert_ios_de.png b/resources/images/tutorial/screenshot_cert_ios_de.png deleted file mode 100644 index f3a355c86..000000000 Binary files a/resources/images/tutorial/screenshot_cert_ios_de.png and /dev/null differ diff --git a/resources/images/tutorial/screenshot_cert_ios_en.png b/resources/images/tutorial/screenshot_cert_ios_en.png deleted file mode 100644 index 6b21543db..000000000 Binary files a/resources/images/tutorial/screenshot_cert_ios_en.png and /dev/null differ diff --git a/resources/images/tutorial/screenshot_check_id_card_android_de.png b/resources/images/tutorial/screenshot_check_id_card_android_de.png deleted file mode 100644 index 06efc92f0..000000000 Binary files a/resources/images/tutorial/screenshot_check_id_card_android_de.png and /dev/null differ diff --git a/resources/images/tutorial/screenshot_check_id_card_android_en.png b/resources/images/tutorial/screenshot_check_id_card_android_en.png deleted file mode 100644 index 7ff2f9c1a..000000000 Binary files a/resources/images/tutorial/screenshot_check_id_card_android_en.png and /dev/null differ diff --git a/resources/images/tutorial/screenshot_check_id_card_ios_de.png b/resources/images/tutorial/screenshot_check_id_card_ios_de.png deleted file mode 100644 index 6afd05efd..000000000 Binary files a/resources/images/tutorial/screenshot_check_id_card_ios_de.png and /dev/null differ diff --git a/resources/images/tutorial/screenshot_check_id_card_ios_en.png b/resources/images/tutorial/screenshot_check_id_card_ios_en.png deleted file mode 100644 index 547edc377..000000000 Binary files a/resources/images/tutorial/screenshot_check_id_card_ios_en.png and /dev/null differ diff --git a/resources/images/tutorial/screenshot_choose_reader_android_de.png b/resources/images/tutorial/screenshot_choose_reader_android_de.png deleted file mode 100644 index 7c3c9fc9e..000000000 Binary files a/resources/images/tutorial/screenshot_choose_reader_android_de.png and /dev/null differ diff --git a/resources/images/tutorial/screenshot_choose_reader_android_en.png b/resources/images/tutorial/screenshot_choose_reader_android_en.png deleted file mode 100644 index e97784757..000000000 Binary files a/resources/images/tutorial/screenshot_choose_reader_android_en.png and /dev/null differ diff --git a/resources/images/tutorial/screenshot_choose_reader_ios_de.png b/resources/images/tutorial/screenshot_choose_reader_ios_de.png deleted file mode 100644 index 4186f85bb..000000000 Binary files a/resources/images/tutorial/screenshot_choose_reader_ios_de.png and /dev/null differ diff --git a/resources/images/tutorial/screenshot_choose_reader_ios_en.png b/resources/images/tutorial/screenshot_choose_reader_ios_en.png deleted file mode 100644 index 3ad8e752f..000000000 Binary files a/resources/images/tutorial/screenshot_choose_reader_ios_en.png and /dev/null differ diff --git a/resources/images/tutorial/screenshot_pairing_de.png b/resources/images/tutorial/screenshot_pairing_de.png deleted file mode 100644 index c028d5cd9..000000000 Binary files a/resources/images/tutorial/screenshot_pairing_de.png and /dev/null differ diff --git a/resources/images/tutorial/screenshot_pairing_en.png b/resources/images/tutorial/screenshot_pairing_en.png deleted file mode 100644 index e27d77615..000000000 Binary files a/resources/images/tutorial/screenshot_pairing_en.png and /dev/null differ diff --git a/resources/images/tutorial/screenshot_pin_management_menu_android_de.png b/resources/images/tutorial/screenshot_pin_management_menu_android_de.png deleted file mode 100644 index 7d05f5d10..000000000 Binary files a/resources/images/tutorial/screenshot_pin_management_menu_android_de.png and /dev/null differ diff --git a/resources/images/tutorial/screenshot_pin_management_menu_android_en.png b/resources/images/tutorial/screenshot_pin_management_menu_android_en.png deleted file mode 100644 index dedbf5087..000000000 Binary files a/resources/images/tutorial/screenshot_pin_management_menu_android_en.png and /dev/null differ diff --git a/resources/images/tutorial/screenshot_pin_management_menu_ios_de.png b/resources/images/tutorial/screenshot_pin_management_menu_ios_de.png deleted file mode 100644 index d5bdf8de5..000000000 Binary files a/resources/images/tutorial/screenshot_pin_management_menu_ios_de.png and /dev/null differ diff --git a/resources/images/tutorial/screenshot_pin_management_menu_ios_en.png b/resources/images/tutorial/screenshot_pin_management_menu_ios_en.png deleted file mode 100644 index d40e8ba6f..000000000 Binary files a/resources/images/tutorial/screenshot_pin_management_menu_ios_en.png and /dev/null differ diff --git a/resources/images/tutorial/screenshot_providerlist_android_de.png b/resources/images/tutorial/screenshot_providerlist_android_de.png deleted file mode 100644 index 96d6f4d64..000000000 Binary files a/resources/images/tutorial/screenshot_providerlist_android_de.png and /dev/null differ diff --git a/resources/images/tutorial/screenshot_providerlist_android_en.png b/resources/images/tutorial/screenshot_providerlist_android_en.png deleted file mode 100644 index 47a1600ac..000000000 Binary files a/resources/images/tutorial/screenshot_providerlist_android_en.png and /dev/null differ diff --git a/resources/images/tutorial/screenshot_providerlist_ios_de.png b/resources/images/tutorial/screenshot_providerlist_ios_de.png deleted file mode 100644 index 4094e2853..000000000 Binary files a/resources/images/tutorial/screenshot_providerlist_ios_de.png and /dev/null differ diff --git a/resources/images/tutorial/screenshot_providerlist_ios_en.png b/resources/images/tutorial/screenshot_providerlist_ios_en.png deleted file mode 100644 index 59a677fd7..000000000 Binary files a/resources/images/tutorial/screenshot_providerlist_ios_en.png and /dev/null differ diff --git a/resources/images/tutorial/screenshot_remoteservice_android_de.png b/resources/images/tutorial/screenshot_remoteservice_android_de.png deleted file mode 100644 index 0070adebd..000000000 Binary files a/resources/images/tutorial/screenshot_remoteservice_android_de.png and /dev/null differ diff --git a/resources/images/tutorial/screenshot_remoteservice_android_en.png b/resources/images/tutorial/screenshot_remoteservice_android_en.png deleted file mode 100644 index 21b7beb51..000000000 Binary files a/resources/images/tutorial/screenshot_remoteservice_android_en.png and /dev/null differ diff --git a/resources/images/tutorial/screenshot_remoteservice_ios_de.png b/resources/images/tutorial/screenshot_remoteservice_ios_de.png deleted file mode 100644 index 709310fd5..000000000 Binary files a/resources/images/tutorial/screenshot_remoteservice_ios_de.png and /dev/null differ diff --git a/resources/images/tutorial/screenshot_remoteservice_ios_en.png b/resources/images/tutorial/screenshot_remoteservice_ios_en.png deleted file mode 100644 index 744340ce6..000000000 Binary files a/resources/images/tutorial/screenshot_remoteservice_ios_en.png and /dev/null differ diff --git a/resources/images/tutorial/screenshot_selfauthentication_android_de.png b/resources/images/tutorial/screenshot_selfauthentication_android_de.png deleted file mode 100644 index 9e961d5aa..000000000 Binary files a/resources/images/tutorial/screenshot_selfauthentication_android_de.png and /dev/null differ diff --git a/resources/images/tutorial/screenshot_selfauthentication_android_en.png b/resources/images/tutorial/screenshot_selfauthentication_android_en.png deleted file mode 100644 index bd53a88bd..000000000 Binary files a/resources/images/tutorial/screenshot_selfauthentication_android_en.png and /dev/null differ diff --git a/resources/images/tutorial/screenshot_selfauthentication_ios_de.png b/resources/images/tutorial/screenshot_selfauthentication_ios_de.png deleted file mode 100644 index 9415d6db3..000000000 Binary files a/resources/images/tutorial/screenshot_selfauthentication_ios_de.png and /dev/null differ diff --git a/resources/images/tutorial/screenshot_selfauthentication_ios_en.png b/resources/images/tutorial/screenshot_selfauthentication_ios_en.png deleted file mode 100644 index 13d7709cf..000000000 Binary files a/resources/images/tutorial/screenshot_selfauthentication_ios_en.png and /dev/null differ diff --git a/resources/images/tutorial/screenshot_start_android_de.png b/resources/images/tutorial/screenshot_start_android_de.png deleted file mode 100644 index f0a0d6066..000000000 Binary files a/resources/images/tutorial/screenshot_start_android_de.png and /dev/null differ diff --git a/resources/images/tutorial/screenshot_start_android_en.png b/resources/images/tutorial/screenshot_start_android_en.png deleted file mode 100644 index 09e2e3d1a..000000000 Binary files a/resources/images/tutorial/screenshot_start_android_en.png and /dev/null differ diff --git a/resources/images/tutorial/screenshot_start_ios_de.png b/resources/images/tutorial/screenshot_start_ios_de.png deleted file mode 100644 index 330c654c4..000000000 Binary files a/resources/images/tutorial/screenshot_start_ios_de.png and /dev/null differ diff --git a/resources/images/tutorial/screenshot_start_ios_en.png b/resources/images/tutorial/screenshot_start_ios_en.png deleted file mode 100644 index e2b1d5fbf..000000000 Binary files a/resources/images/tutorial/screenshot_start_ios_en.png and /dev/null differ diff --git a/resources/images/tutorial/section_seperator_how.svg b/resources/images/tutorial/section_seperator_how.svg deleted file mode 100644 index c1f25da84..000000000 --- a/resources/images/tutorial/section_seperator_how.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/resources/images/tutorial/section_seperator_important.svg b/resources/images/tutorial/section_seperator_important.svg deleted file mode 100644 index 797550675..000000000 --- a/resources/images/tutorial/section_seperator_important.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/resources/images/tutorial/section_seperator_what.svg b/resources/images/tutorial/section_seperator_what.svg deleted file mode 100644 index d4a02a36c..000000000 --- a/resources/images/tutorial/section_seperator_what.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/resources/images/tutorial/section_seperator_where.svg b/resources/images/tutorial/section_seperator_where.svg deleted file mode 100644 index 690ce66d7..000000000 --- a/resources/images/tutorial/section_seperator_where.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/resources/images/tutorial/src/phone_screen_de.svg b/resources/images/tutorial/src/phone_screen_de.svg deleted file mode 100644 index 9f2020185..000000000 --- a/resources/images/tutorial/src/phone_screen_de.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/resources/images/tutorial/src/phone_screen_en.svg b/resources/images/tutorial/src/phone_screen_en.svg deleted file mode 100644 index a950f6fb0..000000000 --- a/resources/images/tutorial/src/phone_screen_en.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/resources/images/tutorial/tablet-nfc.svg b/resources/images/tutorial/tablet-nfc.svg deleted file mode 100644 index b32fb82f0..000000000 --- a/resources/images/tutorial/tablet-nfc.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/resources/images/tutorial/tablet-no-nfc.svg b/resources/images/tutorial/tablet-no-nfc.svg deleted file mode 100644 index 480a4072d..000000000 --- a/resources/images/tutorial/tablet-no-nfc.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/resources/images/tutorial/tablet.svg b/resources/images/tutorial/tablet.svg deleted file mode 100644 index c207d5d6e..000000000 --- a/resources/images/tutorial/tablet.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/resources/images/tutorial/thumb_up.svg b/resources/images/tutorial/thumb_up.svg deleted file mode 100644 index 311fcb52f..000000000 --- a/resources/images/tutorial/thumb_up.svg +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/images/tutorial/up_icon.svg b/resources/images/tutorial/up_icon.svg deleted file mode 100644 index d5c0888c2..000000000 --- a/resources/images/tutorial/up_icon.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/resources/images/tutorial/usb.svg b/resources/images/tutorial/usb.svg deleted file mode 100644 index 7dddd2ec2..000000000 --- a/resources/images/tutorial/usb.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/resources/images/tutorial/user-tine@3x.png b/resources/images/tutorial/user-tine@3x.png deleted file mode 100644 index 3047f77c3..000000000 Binary files a/resources/images/tutorial/user-tine@3x.png and /dev/null differ diff --git a/resources/images/tutorial/where_identify_now_de.svg b/resources/images/tutorial/where_identify_now_de.svg deleted file mode 100644 index 2d8dd9bfa..000000000 --- a/resources/images/tutorial/where_identify_now_de.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/resources/images/tutorial/where_identify_now_en.svg b/resources/images/tutorial/where_identify_now_en.svg deleted file mode 100644 index d2dd6ad9a..000000000 --- a/resources/images/tutorial/where_identify_now_en.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/resources/images/tutorial/where_lay_down_id.svg b/resources/images/tutorial/where_lay_down_id.svg deleted file mode 100644 index 1f698fd31..000000000 --- a/resources/images/tutorial/where_lay_down_id.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/resources/images/tutorial/where_overview_question.svg b/resources/images/tutorial/where_overview_question.svg deleted file mode 100644 index 414b7b830..000000000 --- a/resources/images/tutorial/where_overview_question.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/resources/images/tutorial/where_pin6.svg b/resources/images/tutorial/where_pin6.svg deleted file mode 100644 index 2e4e4c2f0..000000000 --- a/resources/images/tutorial/where_pin6.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/resources/images/tutorial/where_userdata_example_de.svg b/resources/images/tutorial/where_userdata_example_de.svg deleted file mode 100644 index 27c0d66cc..000000000 --- a/resources/images/tutorial/where_userdata_example_de.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - Zum Beispiel - Name? - Vorname? - Geburtsdatum? - Adresse? - diff --git a/resources/images/tutorial/where_userdata_example_en.svg b/resources/images/tutorial/where_userdata_example_en.svg deleted file mode 100644 index 3b36f9700..000000000 --- a/resources/images/tutorial/where_userdata_example_en.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - For Example - Surname? - Given Name? - Date of Birth? - Address? - diff --git a/resources/images/tutorial/wifi.svg b/resources/images/tutorial/wifi.svg deleted file mode 100644 index 3297568de..000000000 --- a/resources/images/tutorial/wifi.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/resources/images/wix_dialog.jpg b/resources/images/wix_dialog.jpg index 550357334..9034a8b36 100644 Binary files a/resources/images/wix_dialog.jpg and b/resources/images/wix_dialog.jpg differ diff --git a/resources/images/workflow_error_card_darkmode.svg b/resources/images/workflow_error_card_darkmode.svg new file mode 100644 index 000000000..4840548a9 --- /dev/null +++ b/resources/images/workflow_error_card_darkmode.svg @@ -0,0 +1,24 @@ + + + + + + + + + diff --git a/resources/images/workflow_error_card_highcontrast.svg b/resources/images/workflow_error_card_highcontrast.svg new file mode 100644 index 000000000..138d21efd --- /dev/null +++ b/resources/images/workflow_error_card_highcontrast.svg @@ -0,0 +1,24 @@ + + + + + + + + + diff --git a/resources/images/workflow_error_card_lightmode.svg b/resources/images/workflow_error_card_lightmode.svg new file mode 100644 index 000000000..3ec6e7b07 --- /dev/null +++ b/resources/images/workflow_error_card_lightmode.svg @@ -0,0 +1,24 @@ + + + + + + + + + diff --git a/resources/images/workflow_error_network_darkmode.svg b/resources/images/workflow_error_network_darkmode.svg new file mode 100644 index 000000000..33fe4100b --- /dev/null +++ b/resources/images/workflow_error_network_darkmode.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + diff --git a/resources/images/workflow_error_network_highcontrast.svg b/resources/images/workflow_error_network_highcontrast.svg new file mode 100644 index 000000000..bd7799f10 --- /dev/null +++ b/resources/images/workflow_error_network_highcontrast.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + diff --git a/resources/images/workflow_error_network_lightmode.svg b/resources/images/workflow_error_network_lightmode.svg new file mode 100644 index 000000000..8d028dd2d --- /dev/null +++ b/resources/images/workflow_error_network_lightmode.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + diff --git a/resources/images/workflow_error_nfc_darkmode.svg b/resources/images/workflow_error_nfc_darkmode.svg new file mode 100644 index 000000000..b89fb715d --- /dev/null +++ b/resources/images/workflow_error_nfc_darkmode.svg @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/resources/images/workflow_error_nfc_highcontrast.svg b/resources/images/workflow_error_nfc_highcontrast.svg new file mode 100644 index 000000000..f6a3da163 --- /dev/null +++ b/resources/images/workflow_error_nfc_highcontrast.svg @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/resources/images/workflow_error_nfc_lightmode.svg b/resources/images/workflow_error_nfc_lightmode.svg new file mode 100644 index 000000000..e11bfbc21 --- /dev/null +++ b/resources/images/workflow_error_nfc_lightmode.svg @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/resources/images/workflow_error_no_sak_darkmode.svg b/resources/images/workflow_error_no_sak_darkmode.svg new file mode 100644 index 000000000..16775573b --- /dev/null +++ b/resources/images/workflow_error_no_sak_darkmode.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/resources/images/workflow_error_no_sak_highcontrast.svg b/resources/images/workflow_error_no_sak_highcontrast.svg new file mode 100644 index 000000000..320e6d371 --- /dev/null +++ b/resources/images/workflow_error_no_sak_highcontrast.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/resources/images/workflow_error_no_sak_lightmode.svg b/resources/images/workflow_error_no_sak_lightmode.svg new file mode 100644 index 000000000..7bd1fb1fb --- /dev/null +++ b/resources/images/workflow_error_no_sak_lightmode.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/resources/images/workflow_error_puk_blocked_darkmode.svg b/resources/images/workflow_error_puk_blocked_darkmode.svg new file mode 100644 index 000000000..f74f0c033 --- /dev/null +++ b/resources/images/workflow_error_puk_blocked_darkmode.svg @@ -0,0 +1,197 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/workflow_error_puk_blocked_highcontrast.svg b/resources/images/workflow_error_puk_blocked_highcontrast.svg new file mode 100644 index 000000000..42c6619a1 --- /dev/null +++ b/resources/images/workflow_error_puk_blocked_highcontrast.svg @@ -0,0 +1,198 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/workflow_error_puk_blocked_lightmode.svg b/resources/images/workflow_error_puk_blocked_lightmode.svg new file mode 100644 index 000000000..c77d5397a --- /dev/null +++ b/resources/images/workflow_error_puk_blocked_lightmode.svg @@ -0,0 +1,197 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/workflow_error_wrong_can_darkmode.svg b/resources/images/workflow_error_wrong_can_darkmode.svg new file mode 100644 index 000000000..d11c74eff --- /dev/null +++ b/resources/images/workflow_error_wrong_can_darkmode.svg @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/workflow_error_wrong_can_highcontrast.svg b/resources/images/workflow_error_wrong_can_highcontrast.svg new file mode 100644 index 000000000..6ea66db85 --- /dev/null +++ b/resources/images/workflow_error_wrong_can_highcontrast.svg @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/workflow_error_wrong_can_lightmode.svg b/resources/images/workflow_error_wrong_can_lightmode.svg new file mode 100644 index 000000000..9faf4979f --- /dev/null +++ b/resources/images/workflow_error_wrong_can_lightmode.svg @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/workflow_error_wrong_pin_darkmode.svg b/resources/images/workflow_error_wrong_pin_darkmode.svg new file mode 100644 index 000000000..b0fe9995d --- /dev/null +++ b/resources/images/workflow_error_wrong_pin_darkmode.svg @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/workflow_error_wrong_pin_highcontrast.svg b/resources/images/workflow_error_wrong_pin_highcontrast.svg new file mode 100644 index 000000000..f1b2cc5e6 --- /dev/null +++ b/resources/images/workflow_error_wrong_pin_highcontrast.svg @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/workflow_error_wrong_pin_lightmode.svg b/resources/images/workflow_error_wrong_pin_lightmode.svg new file mode 100644 index 000000000..9bab77144 --- /dev/null +++ b/resources/images/workflow_error_wrong_pin_lightmode.svg @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/workflow_error_wrong_puk_darkmode.svg b/resources/images/workflow_error_wrong_puk_darkmode.svg new file mode 100644 index 000000000..946dad818 --- /dev/null +++ b/resources/images/workflow_error_wrong_puk_darkmode.svg @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/workflow_error_wrong_puk_highcontrast.svg b/resources/images/workflow_error_wrong_puk_highcontrast.svg new file mode 100644 index 000000000..274979c84 --- /dev/null +++ b/resources/images/workflow_error_wrong_puk_highcontrast.svg @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/workflow_error_wrong_puk_lightmode.svg b/resources/images/workflow_error_wrong_puk_lightmode.svg new file mode 100644 index 000000000..867ca4132 --- /dev/null +++ b/resources/images/workflow_error_wrong_puk_lightmode.svg @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/workflow_error_wrong_transportpin_darkmode.svg b/resources/images/workflow_error_wrong_transportpin_darkmode.svg new file mode 100644 index 000000000..9ff752f23 --- /dev/null +++ b/resources/images/workflow_error_wrong_transportpin_darkmode.svg @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/workflow_error_wrong_transportpin_highcontrast.svg b/resources/images/workflow_error_wrong_transportpin_highcontrast.svg new file mode 100644 index 000000000..1d2eb2511 --- /dev/null +++ b/resources/images/workflow_error_wrong_transportpin_highcontrast.svg @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/workflow_error_wrong_transportpin_lightmode.svg b/resources/images/workflow_error_wrong_transportpin_lightmode.svg new file mode 100644 index 000000000..ad3080494 --- /dev/null +++ b/resources/images/workflow_error_wrong_transportpin_lightmode.svg @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/workflow_success_changepin_darkmode.svg b/resources/images/workflow_success_changepin_darkmode.svg new file mode 100644 index 000000000..91dc90c7b --- /dev/null +++ b/resources/images/workflow_success_changepin_darkmode.svg @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/workflow_success_changepin_highcontrast.svg b/resources/images/workflow_success_changepin_highcontrast.svg new file mode 100644 index 000000000..6e3e2baec --- /dev/null +++ b/resources/images/workflow_success_changepin_highcontrast.svg @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/workflow_success_changepin_lightmode.svg b/resources/images/workflow_success_changepin_lightmode.svg new file mode 100644 index 000000000..40da24c65 --- /dev/null +++ b/resources/images/workflow_success_changepin_lightmode.svg @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/jenkins/docker/Dockerfile b/resources/jenkins/docker/Dockerfile index 98ea74873..d27bf31eb 100644 --- a/resources/jenkins/docker/Dockerfile +++ b/resources/jenkins/docker/Dockerfile @@ -1,17 +1,18 @@ -ARG ALPINE_VERSION=3.16 +ARG ALPINE_VERSION=3.17 FROM alpine:$ALPINE_VERSION as builder # Install development stuff RUN apk --no-cache upgrade -a && \ apk --no-cache add patch cmake ccache make ninja g++ pkgconf pcsc-lite-dev binutils-gold eudev-libs \ - http-parser-dev openssl-dev qt6-qtbase-dev qt6-qtsvg-dev qt6-qtwebsockets-dev qt6-qttools-dev qt6-qtdeclarative-dev qt6-qtscxml-dev qt6-qtconnectivity-dev + http-parser-dev openssl-dev \ + qt6-qtbase-dev qt6-qtsvg-dev qt6-qtwebsockets-dev qt6-qttools-dev qt6-qtdeclarative-dev qt6-qtscxml-dev qt6-qtconnectivity-dev qt6-qtimageformats-dev qt6-qtimageformats # Use optional remote ccache -# redis://YOUR_SERVER:6379|share-hits=false +# redis://YOUR_SERVER:6379 ARG CCACHE_REMOTE_STORAGE="" -ENV CCACHE_SECONDARY_STORAGE=$CCACHE_REMOTE_STORAGE CCACHE_RESHARE=true CCACHE_DIR=/build/ccache XDG_RUNTIME_DIR=/root +ENV CCACHE_REMOTE_STORAGE=$CCACHE_REMOTE_STORAGE CCACHE_REMOTE_ONLY=true CCACHE_RESHARE=true CCACHE_DIR=/build/ccache XDG_RUNTIME_DIR=/root -# Build AusweisApp2 +# Build AusweisApp COPY README.rst /src/ausweisapp/ COPY LICENSE.txt/ /src/ausweisapp/ COPY LICENSE.officially.txt/ /src/ausweisapp/ @@ -34,7 +35,7 @@ RUN cmake /src/ausweisapp -B /build/app \ RUN find /usr/local/ -type d -empty -delete && \ find /usr/local/lib/ -type f -not -name "*.so*" -delete && \ find /usr/local/lib/ -type f -name "*.so*" -exec strip {} + && \ - strip /usr/local/bin/AusweisApp2 + strip /usr/local/bin/AusweisApp @@ -43,11 +44,11 @@ ENV XDG_RUNTIME_DIR=/home/ausweisapp QT_QPA_PLATFORM=vnc COPY --from=builder /usr/local/lib /usr/local/lib COPY --from=builder /usr/local/share /usr/local/share -COPY --from=builder /usr/local/bin/AusweisApp2 /usr/local/bin/AusweisApp2 +COPY --from=builder /usr/local/bin/AusweisApp /usr/local/bin/AusweisApp RUN apk --no-cache upgrade -a && \ apk --no-cache add tini pcsc-lite-libs eudev-libs doas ttf-freefont \ - http-parser qt6-qtbase qt6-qtsvg qt6-qtwebsockets qt6-qtdeclarative qt6-qtscxml qt6-qtconnectivity && \ + http-parser qt6-qtbase qt6-qtsvg qt6-qtwebsockets qt6-qtdeclarative qt6-qtscxml qt6-qtconnectivity qt6-qtimageformats && \ echo 'permit nopass :wheel' > /etc/doas.d/wheel.conf && \ adduser ausweisapp -G wheel -s /bin/sh -D && \ chmod 0700 /home/ausweisapp && mkdir -p /home/ausweisapp/.config && chown ausweisapp: /home/ausweisapp/.config @@ -56,4 +57,4 @@ USER ausweisapp VOLUME ["/home/ausweisapp/.config"] ENTRYPOINT ["/sbin/tini", "--"] EXPOSE 5900/tcp 24727/tcp 24727/udp -CMD ["AusweisApp2", "--address", "0.0.0.0"] +CMD ["AusweisApp", "--address", "0.0.0.0"] diff --git a/resources/jenkins/docker/alpine-swarm/Dockerfile b/resources/jenkins/docker/alpine-swarm/Dockerfile index 527175dac..5c75ef601 100644 --- a/resources/jenkins/docker/alpine-swarm/Dockerfile +++ b/resources/jenkins/docker/alpine-swarm/Dockerfile @@ -1,7 +1,7 @@ -FROM alpine:3.17 +FROM alpine:3.18 MAINTAINER Governikus KG -ARG JENKINS_SWARM_VERSION=3.39 +ARG JENKINS_SWARM_VERSION=3.40 ENV EXECUTOR=3 LABELS= NAME= PASSWORD= RUN adduser governikus -s /bin/sh -D diff --git a/resources/jenkins/docker/ubuntu-android/Dockerfile b/resources/jenkins/docker/ubuntu-android/Dockerfile index dec559324..921bb14eb 100644 --- a/resources/jenkins/docker/ubuntu-android/Dockerfile +++ b/resources/jenkins/docker/ubuntu-android/Dockerfile @@ -1,25 +1,24 @@ FROM dev-docker.governikus.de/ausweisapp2/ubuntu:swarm MAINTAINER Governikus KG -ARG ANDROID_CMDLINE_TOOLS=9477386 -ARG ANDROID_NDK_VERSION=25.2.9519653 -ARG CMAKE=3.26.3 +ARG ANDROID_CMDLINE_TOOLS=10406996 +ARG ANDROID_NDK_VERSION=26.1.10909125 +ARG CMAKE=3.27.7 ENV NAME=Android LABELS="Android" PACKAGES_DIR=/home/governikus/packages ENV ANDROID_SDK_ROOT /opt/android-sdk ENV ANDROID_NDK_ROOT $ANDROID_SDK_ROOT/ndk/$ANDROID_NDK_VERSION RUN apt-get update && \ - apt-get -y install g++ make ccache ninja-build perl unzip gradle maven patch openjdk-11-jdk-headless && \ + apt-get -y install g++ make ccache ninja-build perl unzip gradle maven patch openjdk-17-jdk-headless && \ rm -rf /var/lib/apt/lists/* -# CMake 3.16 is required for NDK r19+ RUN wget https://github.com/Kitware/CMake/releases/download/v$CMAKE/cmake-$CMAKE-Linux-x86_64.sh -O /tmp/cmake.sh && \ sh /tmp/cmake.sh --prefix=/usr --skip-license --exclude-subdir && rm /tmp/cmake.sh RUN mkdir -p /tmp/dl && cd /tmp/dl && wget -O sdk.zip https://dl.google.com/android/repository/commandlinetools-linux-${ANDROID_CMDLINE_TOOLS}_latest.zip && \ unzip sdk.zip && \ - yes | /tmp/dl/cmdline-tools/bin/sdkmanager --sdk_root=$ANDROID_SDK_ROOT "cmdline-tools;9.0" "build-tools;33.0.2" "platforms;android-33" "ndk;${ANDROID_NDK_VERSION}" && \ + yes | /tmp/dl/cmdline-tools/bin/sdkmanager --sdk_root=$ANDROID_SDK_ROOT "cmdline-tools;11.0" "build-tools;34.0.0" "platforms;android-33" "platforms;android-34" "ndk;${ANDROID_NDK_VERSION}" && \ rm -rf /tmp/dl USER governikus diff --git a/resources/jenkins/docker/ubuntu-swarm/Dockerfile b/resources/jenkins/docker/ubuntu-swarm/Dockerfile index caaab8a96..ae4298168 100644 --- a/resources/jenkins/docker/ubuntu-swarm/Dockerfile +++ b/resources/jenkins/docker/ubuntu-swarm/Dockerfile @@ -1,13 +1,18 @@ -FROM ubuntu:22.04 +FROM ubuntu:23.04 MAINTAINER Governikus KG -ARG JENKINS_SWARM_VERSION=3.39 +ARG JENKINS_SWARM_VERSION=3.40 ENV EXECUTOR=3 LABELS= NAME= PASSWORD= ENV DEBIAN_FRONTEND noninteractive +ENV PIP_BREAK_SYSTEM_PACKAGES=1 -RUN useradd -m governikus +# Use optional remote ccache +# redis://YOUR_SERVER:6379 +ENV CCACHE_REMOTE_STORAGE= CCACHE_RESHARE=true CCACHE_REMOTE_ONLY= + +RUN useradd -m governikus -g users -u 1111 RUN apt-get update && \ - apt-get -y install openjdk-11-jre-headless tini python3-pip wget && \ + apt-get -y install openjdk-17-jre-headless tini python3-pip wget && \ pip3 install rbtools mercurial python-hglib && \ rm -rf /var/lib/apt/lists/* RUN wget -O /swarm-client.jar https://repo.jenkins-ci.org/releases/org/jenkins-ci/plugins/swarm-client/$JENKINS_SWARM_VERSION/swarm-client-$JENKINS_SWARM_VERSION.jar diff --git a/resources/jenkins/docker/ubuntu-vanilla/Dockerfile b/resources/jenkins/docker/ubuntu-vanilla/Dockerfile index b6f0a6d03..1822ac91e 100644 --- a/resources/jenkins/docker/ubuntu-vanilla/Dockerfile +++ b/resources/jenkins/docker/ubuntu-vanilla/Dockerfile @@ -6,10 +6,34 @@ ENV NAME=Vanilla LABELS="Vanilla" PACKAGES_DIR=/home/governikus/packages RUN apt-get update && \ apt-get -y install cmake make g++ clazy clang clang-tidy ccache gcovr cloc pkg-config ninja-build binutils-gold lld \ valgrind tree libpcsclite-dev libhttp-parser-dev libssl-dev libudev-dev \ + \ qml-module-qt-labs-platform qml-module-qtquick-controls2 qml-module-qtquick-controls2 qml-module-qttest \ qml-module-qtquick-layouts qml-module-qtqml-models2 \ qtdeclarative5-dev qtquickcontrols2-5-dev qttools5-dev libqt5svg5-dev \ - libqt5websockets5-dev qtconnectivity5-dev && \ + libqt5websockets5-dev qtconnectivity5-dev \ + \ + libqt6opengl6-dev \ + libqt6shadertools6-dev \ + libqt6svg6-dev \ + libqt6websockets6-dev \ + qt6-base-dev \ + qt6-base-private-dev \ + qt6-connectivity-dev \ + qt6-declarative-dev \ + qt6-scxml-dev \ + qt6-tools-dev \ + qt6-tools-dev-tools \ + qt6-l10n-tools \ + qml6-module-qt-labs-platform \ + qml6-module-qtqml \ + qml6-module-qtqml-models \ + qml6-module-qtqml-statemachine \ + qml6-module-qtqml-workerscript \ + qml6-module-qtquick-controls \ + qml6-module-qtquick-layouts \ + qml6-module-qtquick-templates \ + qml6-module-qtquick-window \ + && \ rm -rf /var/lib/apt/lists/* USER governikus diff --git a/resources/jenkins/dsl/Builds/Build_Android.groovy b/resources/jenkins/dsl/Builds/Build_Android.groovy index 55f805ef9..c3a794cbb 100644 --- a/resources/jenkins/dsl/Builds/Build_Android.groovy +++ b/resources/jenkins/dsl/Builds/Build_Android.groovy @@ -10,7 +10,7 @@ def j = new Build name: 'Android_APK_' + ARCH, libraries: ['Android_' + ARCH], label: 'Android', - artifacts: 'build/dist/**/AusweisApp2-*.apk*,build/debug.symbols/*' + artifacts: 'build/dist/**/AusweisApp-*.apk*,build/debug.symbols/*' ).generate(this) diff --git a/resources/jenkins/dsl/Builds/Build_Container.groovy b/resources/jenkins/dsl/Builds/Build_Container.groovy index 4b4c90010..8980d2781 100644 --- a/resources/jenkins/dsl/Builds/Build_Container.groovy +++ b/resources/jenkins/dsl/Builds/Build_Container.groovy @@ -5,7 +5,7 @@ def j = new Build ( name: 'Container', label: 'Docker', - artifacts: 'build/AusweisApp2*.tar' + artifacts: 'build/AusweisApp*.tar' ).generate(this) @@ -25,13 +25,13 @@ j.with shell(strip('''\ docker build --pull - -t dev-docker.govkg.de/ausweisapp2/sdk:${TAG//-default/""} - --build-arg CCACHE_REMOTE_STORAGE="redis://${CCACHE_REMOTE_STORAGE_HOST}|share-hits=false" + -t dev-docker.govkg.de/ausweisapp/sdk:${TAG//-default/""} + --build-arg CCACHE_REMOTE_STORAGE="redis://${CCACHE_REMOTE_STORAGE_HOST}" source ''')) - shell('docker save -o build/AusweisApp2-${MERCURIAL_REVISION_SHORT}.tar dev-docker.govkg.de/ausweisapp2/sdk:${TAG//-default/""}') - shell('docker push dev-docker.govkg.de/ausweisapp2/sdk:${TAG//-default/""}') + shell('docker save -o build/AusweisApp-${MERCURIAL_REVISION_SHORT}.tar dev-docker.govkg.de/ausweisapp/sdk:${TAG//-default/""}') + shell('docker push dev-docker.govkg.de/ausweisapp/sdk:${TAG//-default/""}') shell('''\ IMAGES=`docker images --filter "dangling=true" -q | tail -n +50` diff --git a/resources/jenkins/dsl/Builds/Build_Docker_VNC.groovy b/resources/jenkins/dsl/Builds/Build_Docker_VNC.groovy index 70fc48d9f..5287eefd0 100644 --- a/resources/jenkins/dsl/Builds/Build_Docker_VNC.groovy +++ b/resources/jenkins/dsl/Builds/Build_Docker_VNC.groovy @@ -5,7 +5,7 @@ def j = new Build ( name: 'Docker_VNC', label: 'Docker', - artifacts: 'build/AusweisApp2*.tar' + artifacts: 'build/AusweisApp*.tar' ).generate(this) @@ -23,15 +23,15 @@ j.with { shell(strip('''\ docker build --pull - -t dev-docker.govkg.de/ausweisapp2/vnc:${TAG//-default/""} - --build-arg CCACHE_REMOTE_STORAGE="redis://${CCACHE_REMOTE_STORAGE_HOST}|share-hits=false" + -t dev-docker.govkg.de/ausweisapp/vnc:${TAG//-default/""} + --build-arg CCACHE_REMOTE_STORAGE="redis://${CCACHE_REMOTE_STORAGE_HOST}" -f source/resources/jenkins/docker/Dockerfile source ''')) - shell('docker run --rm dev-docker.govkg.de/ausweisapp2/vnc:${TAG//-default/""} AusweisApp2 --help') - shell('docker save -o build/AusweisApp2-VNC-${MERCURIAL_REVISION_SHORT}.tar dev-docker.govkg.de/ausweisapp2/vnc:${TAG//-default/""}') - shell('docker push dev-docker.govkg.de/ausweisapp2/vnc:${TAG//-default/""}') + shell('docker run --rm dev-docker.govkg.de/ausweisapp/vnc:${TAG//-default/""} AusweisApp --help') + shell('docker save -o build/AusweisApp-VNC-${MERCURIAL_REVISION_SHORT}.tar dev-docker.govkg.de/ausweisapp/vnc:${TAG//-default/""}') + shell('docker push dev-docker.govkg.de/ausweisapp/vnc:${TAG//-default/""}') shell('''\ IMAGES=`docker images --filter "dangling=true" -q | tail -n +50` diff --git a/resources/jenkins/dsl/Builds/Build_Docs.groovy b/resources/jenkins/dsl/Builds/Build_Docs.groovy index f848bef04..19dac6f00 100644 --- a/resources/jenkins/dsl/Builds/Build_Docs.groovy +++ b/resources/jenkins/dsl/Builds/Build_Docs.groovy @@ -16,18 +16,16 @@ j.with shell('cmake --build build --target notes') shell('cmake --build build --target notes.latex.pdf') - shell('cd build/docs/notes; cmake -E tar cfJ ../AusweisApp2_ReleaseNotes.tar.xz .') + shell('cd build/docs/notes; cmake -E tar cfJ ../AusweisApp_ReleaseNotes.tar.xz .') shell('cmake --build build --target sdk') shell('cmake --build build --target sdk.latex.pdf') - shell('cd build/docs/sdk/html; cmake -E tar cfJ ../../AusweisApp2_SDK.tar.xz .') + shell('cd build/docs/sdk/html; cmake -E tar cfJ ../../AusweisApp_SDK.tar.xz .') shell('cmake --build build --target failurecodes') shell('cmake --build build --target failurecodes.latex.pdf') - shell('cmake --build build --target inst.latex.pdf') - - shell('cmake --build build --target inte.latex.pdf') + shell('cmake --build build --target installation_integration.latex.pdf') shell('cmake --build build --target license') diff --git a/resources/jenkins/dsl/Builds/Build_SonarQube.groovy b/resources/jenkins/dsl/Builds/Build_SonarQube.groovy index 0e426d816..2452099ed 100644 --- a/resources/jenkins/dsl/Builds/Build_SonarQube.groovy +++ b/resources/jenkins/dsl/Builds/Build_SonarQube.groovy @@ -37,7 +37,7 @@ j.with shell('$WORKSPACE/sonarqubetools/sonar-build-wrapper/build-wrapper-linux-x86-64 --out-dir build cmake --build build') - shell('ctest -LE qml -E Test_ui_qml_UIPlugInQml --test-dir build --output-on-failure') + shell('ctest -LE qml -E Test_ui_qml_Qml --test-dir build --output-on-failure') shell('cmake --build build --target gcovr.sonar') diff --git a/resources/jenkins/dsl/Builds/Build_Win64_GNU_MSI_dev.groovy b/resources/jenkins/dsl/Builds/Build_Win64_GNU_MSI_dev.groovy deleted file mode 100644 index 0f7a9e116..000000000 --- a/resources/jenkins/dsl/Builds/Build_Win64_GNU_MSI_dev.groovy +++ /dev/null @@ -1,25 +0,0 @@ -import common.Build - -def j = new Build - ( - name: 'Win64_GNU_MSI_dev', - libraries: ['Win64_GNU_dev'], - label: 'Windows', - artifacts: 'build/*.msi', - weight: 2 - ).generate(this) - - -j.with -{ - steps - { - batchFile('cd source & cmake --preset ci-win-debug') - - batchFile('cmake --build build --target package') - - batchFile('cmake --build build --target package.sign') - - batchFile('cmake -DCMD=CHECK_WIX_WARNING -DFILE=build/_CPack_Packages/win64/WIX/wix.log -P source/cmake/cmd.cmake') - } -} diff --git a/resources/jenkins/dsl/Builds/Build_iOS_IPA.groovy b/resources/jenkins/dsl/Builds/Build_iOS_IPA.groovy index 42faaed94..9a914966d 100644 --- a/resources/jenkins/dsl/Builds/Build_iOS_IPA.groovy +++ b/resources/jenkins/dsl/Builds/Build_iOS_IPA.groovy @@ -17,8 +17,8 @@ j.with shell('cd source; cmake --preset ci-ios') - shell('cd build; xcodebuild -configuration MinSizeRel -archivePath AusweisApp2.xcarchive -scheme AusweisApp archive') - shell('cd build; xcodebuild -configuration MinSizeRel -archivePath AusweisApp2.xcarchive -exportArchive -exportOptionsPlist exportOptions.plist -exportPath .') + shell('cd build; xcodebuild -configuration MinSizeRel -archivePath AusweisApp.xcarchive -scheme AusweisAppBinary archive') + shell('cd build; xcodebuild -configuration MinSizeRel -archivePath AusweisApp.xcarchive -exportArchive -exportOptionsPlist exportOptions.plist -exportPath .') shell('cd build; xcodebuild -configuration MinSizeRel -target ipa') } } diff --git a/resources/jenkins/dsl/Libraries/Libs_Win64_GNU.groovy b/resources/jenkins/dsl/Libraries/Libs_Win64_GNU.groovy index 9d49d9d4d..98679a079 100644 --- a/resources/jenkins/dsl/Libraries/Libs_Win64_GNU.groovy +++ b/resources/jenkins/dsl/Libraries/Libs_Win64_GNU.groovy @@ -17,6 +17,7 @@ j.with environmentVariables { env('MSYS2_PATH_TYPE', 'inherit') + env('PATH', '$WORKSPACE/build/dist/bin;$PATH') } } diff --git a/resources/jenkins/dsl/Libraries/Libs_Win64_GNU_dev.groovy b/resources/jenkins/dsl/Libraries/Libs_Win64_GNU_dev.groovy deleted file mode 100644 index 91bc7d4d9..000000000 --- a/resources/jenkins/dsl/Libraries/Libs_Win64_GNU_dev.groovy +++ /dev/null @@ -1,35 +0,0 @@ -import common.Library - -def j = new Library - ( - name: 'Win64_GNU_dev', - label: 'Windows', - weight: 3 - ).generate(this) - - -j.with -{ - customWorkspace('workspace/' + MERCURIAL_REVISION_BRANCH + '_LW64GD') - - wrappers - { - environmentVariables - { - env('MSYS2_PATH_TYPE', 'inherit') - } - } - - steps - { - batchFile('cd source/libs & cmake --preset ci-gnu-debug') - - shell('''\ - #!c:\\msys64\\usr\\bin\\bash --login - cd /jenkins/${MERCURIAL_REVISION_BRANCH}_LW64GD/ - cmake --build build --target openssl - '''.stripIndent().trim()) - - batchFile('cmake --build build --target compress') - } -} diff --git a/resources/jenkins/dsl/Libraries/Libs_Win64_MSVC.groovy b/resources/jenkins/dsl/Libraries/Libs_Win64_MSVC.groovy index 9290c0f40..cec8fecbc 100644 --- a/resources/jenkins/dsl/Libraries/Libs_Win64_MSVC.groovy +++ b/resources/jenkins/dsl/Libraries/Libs_Win64_MSVC.groovy @@ -11,6 +11,14 @@ j.with { customWorkspace('workspace/' + MERCURIAL_REVISION_BRANCH + '_LW64M') + wrappers + { + environmentVariables + { + env('PATH', '$WORKSPACE/build/dist/bin;$PATH') + } + } + steps { batchFile('''\ diff --git a/resources/jenkins/dsl/Libraries/Libs_Win64_MSVC_dev.groovy b/resources/jenkins/dsl/Libraries/Libs_Win64_MSVC_dev.groovy index 0321d6dff..2cb222993 100644 --- a/resources/jenkins/dsl/Libraries/Libs_Win64_MSVC_dev.groovy +++ b/resources/jenkins/dsl/Libraries/Libs_Win64_MSVC_dev.groovy @@ -11,6 +11,14 @@ j.with { customWorkspace('workspace/' + MERCURIAL_REVISION_BRANCH + '_LW64MD') + wrappers + { + environmentVariables + { + env('PATH', '$WORKSPACE/build/dist/bin;$PATH') + } + } + steps { batchFile('''\ diff --git a/resources/jenkins/dsl/Releases/Release_Android.groovy b/resources/jenkins/dsl/Releases/Release_Android.groovy index 9777c1da3..ccc21ef07 100644 --- a/resources/jenkins/dsl/Releases/Release_Android.groovy +++ b/resources/jenkins/dsl/Releases/Release_Android.groovy @@ -12,7 +12,7 @@ def j = new Release name: 'Android_APK_' + ARCH, libraries: ['Android_' + ARCH], label: 'Android', - artifacts: 'libs/build/Toolchain_*,build/dist/**/AusweisApp2-*.apk*,build/debug.symbols/*' + artifacts: 'libs/build/Toolchain_*,build/dist/**/AusweisApp-*.apk*,build/debug.symbols/*' ).generate(this) diff --git a/resources/jenkins/dsl/Releases/Release_Container.groovy b/resources/jenkins/dsl/Releases/Release_Container.groovy index 3a895b341..dbdf112f9 100644 --- a/resources/jenkins/dsl/Releases/Release_Container.groovy +++ b/resources/jenkins/dsl/Releases/Release_Container.groovy @@ -5,7 +5,7 @@ def j = new Release ( name: 'Container', label: 'Docker', - artifacts: 'build/AusweisApp2*.tar' + artifacts: 'build/AusweisApp*.tar' ).generate(this) @@ -20,13 +20,13 @@ j.with { shell(strip('''\ docker build --pull - -t dev-docker.govkg.de/ausweisapp2/sdk:${changeset} - --build-arg CCACHE_REMOTE_STORAGE="redis://${CCACHE_REMOTE_STORAGE_HOST}|share-hits=false" + -t dev-docker.govkg.de/ausweisapp/sdk:${changeset} + --build-arg CCACHE_REMOTE_STORAGE="redis://${CCACHE_REMOTE_STORAGE_HOST}" source ''')) - shell('docker save -o build/AusweisApp2-${changeset}.tar dev-docker.govkg.de/ausweisapp2/sdk:${changeset}') - shell('docker push dev-docker.govkg.de/ausweisapp2/sdk:${changeset}') + shell('docker save -o build/AusweisApp-${changeset}.tar dev-docker.govkg.de/ausweisapp/sdk:${changeset}') + shell('docker push dev-docker.govkg.de/ausweisapp/sdk:${changeset}') conditionalSteps { @@ -37,8 +37,8 @@ j.with steps { - shell('docker tag dev-docker.govkg.de/ausweisapp2/sdk:${changeset} dev-docker.govkg.de/ausweisapp2/sdk:latest') - shell('docker push dev-docker.govkg.de/ausweisapp2/sdk:latest') + shell('docker tag dev-docker.govkg.de/ausweisapp/sdk:${changeset} dev-docker.govkg.de/ausweisapp/sdk:latest') + shell('docker push dev-docker.govkg.de/ausweisapp/sdk:latest') } } } diff --git a/resources/jenkins/dsl/Releases/Release_Docs.groovy b/resources/jenkins/dsl/Releases/Release_Docs.groovy index 69e02f937..f7c7d7b22 100644 --- a/resources/jenkins/dsl/Releases/Release_Docs.groovy +++ b/resources/jenkins/dsl/Releases/Release_Docs.groovy @@ -21,18 +21,16 @@ j.with shell('cmake --build build --target notes') shell('cmake --build build --target notes.latex.pdf') - shell('cd build/docs/notes; cmake -E tar cfJ ../AusweisApp2_ReleaseNotes.tar.xz .') + shell('cd build/docs/notes; cmake -E tar cfJ ../AusweisApp_ReleaseNotes.tar.xz .') shell('cmake --build build --target sdk') shell('cmake --build build --target sdk.latex.pdf') - shell('cd build/docs/sdk/html; cmake -E tar cfJ ../../AusweisApp2_SDK.tar.xz .') + shell('cd build/docs/sdk/html; cmake -E tar cfJ ../../AusweisApp_SDK.tar.xz .') shell('cmake --build build --target failurecodes') shell('cmake --build build --target failurecodes.latex.pdf') - shell('cmake --build build --target inst.latex.pdf') - - shell('cmake --build build --target inte.latex.pdf') + shell('cmake --build build --target installation_integration.latex.pdf') shell('cmake --build build --target license') } diff --git a/resources/jenkins/dsl/Releases/Release_MacOS.groovy b/resources/jenkins/dsl/Releases/Release_MacOS.groovy index 58672731b..7a491ff87 100644 --- a/resources/jenkins/dsl/Releases/Release_MacOS.groovy +++ b/resources/jenkins/dsl/Releases/Release_MacOS.groovy @@ -13,7 +13,7 @@ j.with { parameters { - booleanParam("UPLOAD", true, "Upload AusweisApp2 to the AppStore") + booleanParam("UPLOAD", true, "Upload AusweisApp to the AppStore") } steps @@ -28,7 +28,7 @@ j.with cmake --build build --target package --config MinSizeRel '''.stripIndent().trim()) - shell('cd build/src/MinSizeRel/; cmake -E tar cf ../../AusweisApp2.app.dSYM.zip --format=zip AusweisApp2.app.dSYM') + shell('cd build/src/MinSizeRel/; cmake -E tar cf ../../AusweisApp.app.dSYM.zip --format=zip AusweisApp.app.dSYM') shell('cd build/_CPack_Packages/Darwin/; codesign -vvvv **/**/*.app') shell('cd build/_CPack_Packages/Darwin/DragNDrop; spctl -a -vv **/*.app') diff --git a/resources/jenkins/dsl/Releases/Release_iOS.groovy b/resources/jenkins/dsl/Releases/Release_iOS.groovy index 6d90598d3..717edb9d3 100644 --- a/resources/jenkins/dsl/Releases/Release_iOS.groovy +++ b/resources/jenkins/dsl/Releases/Release_iOS.groovy @@ -13,7 +13,7 @@ j.with { parameters { - booleanParam("USE_DISTRIBUTION_PROFILE", true, "Use the provisioning profile necessary to upload AusweisApp2 to the AppStore") + booleanParam("USE_DISTRIBUTION_PROFILE", true, "Use the provisioning profile necessary to upload AusweisApp to the AppStore") } steps @@ -24,9 +24,9 @@ j.with shell('cd source; cmake --preset ci-ios -DUSE_DISTRIBUTION_PROFILE=${USE_DISTRIBUTION_PROFILE}') - shell('cd build; xcodebuild -configuration MinSizeRel -archivePath AusweisApp2.xcarchive -scheme AusweisApp archive') - shell('cd build; xcodebuild -configuration MinSizeRel -archivePath AusweisApp2.xcarchive -exportArchive -exportOptionsPlist exportOptions.plist -exportPath .') - shell('cmake -E tar cf AusweisApp2_BuildDir.tar.zstd --zstd build') + shell('cd build; xcodebuild -configuration MinSizeRel -archivePath AusweisApp.xcarchive -scheme AusweisAppBinary archive') + shell('cd build; xcodebuild -configuration MinSizeRel -archivePath AusweisApp.xcarchive -exportArchive -exportOptionsPlist exportOptions.plist -exportPath .') + shell('cmake -E tar cf AusweisApp_BuildDir.tar.zstd --zstd build') shell('cd build; xcodebuild -configuration MinSizeRel -target ipa') conditionalSteps diff --git a/resources/jenkins/dsl/Releases/Release_iOS_Framework.groovy b/resources/jenkins/dsl/Releases/Release_iOS_Framework.groovy index 57c4c04fc..11873d865 100644 --- a/resources/jenkins/dsl/Releases/Release_iOS_Framework.groovy +++ b/resources/jenkins/dsl/Releases/Release_iOS_Framework.groovy @@ -18,7 +18,7 @@ j.with shell('cd source; cmake --preset ci-ios-framework') shell('cd build; xcodebuild -configuration MinSizeRel') - shell('cmake -E tar cf AusweisApp2_BuildDir.tar.zstd --zstd build') + shell('cmake -E tar cf AusweisApp_BuildDir.tar.zstd --zstd build') shell('cd build; xcodebuild -configuration MinSizeRel -target zip') } } diff --git a/resources/jenkins/dsl/Releases/Release_iOS_Simulator_Framework.groovy b/resources/jenkins/dsl/Releases/Release_iOS_Simulator_Framework.groovy index 9dd019a1e..e2d005452 100644 --- a/resources/jenkins/dsl/Releases/Release_iOS_Simulator_Framework.groovy +++ b/resources/jenkins/dsl/Releases/Release_iOS_Simulator_Framework.groovy @@ -18,7 +18,7 @@ j.with shell('cd source; cmake --preset ci-ios-framework-simulator') shell('cd build; xcodebuild -configuration MinSizeRel') - shell('cmake -E tar cf AusweisApp2_BuildDir.tar.zstd --zstd build') + shell('cmake -E tar cf AusweisApp_BuildDir.tar.zstd --zstd build') shell('cd build; xcodebuild -configuration MinSizeRel -target zip') } } diff --git a/resources/jenkins/dsl/Releases/Release_iOS_Simulator_arm64_Framework.groovy b/resources/jenkins/dsl/Releases/Release_iOS_Simulator_arm64_Framework.groovy index 9046da2e6..bbcac9e30 100644 --- a/resources/jenkins/dsl/Releases/Release_iOS_Simulator_arm64_Framework.groovy +++ b/resources/jenkins/dsl/Releases/Release_iOS_Simulator_arm64_Framework.groovy @@ -18,7 +18,7 @@ j.with shell('cd source; cmake --preset ci-ios-framework-simulator-arm64') shell('cd build; xcodebuild -configuration MinSizeRel') - shell('cmake -E tar cf AusweisApp2_BuildDir.tar.zstd --zstd build') + shell('cmake -E tar cf AusweisApp_BuildDir.tar.zstd --zstd build') shell('cd build; xcodebuild -configuration MinSizeRel -target zip') } } diff --git a/resources/jenkins/dsl/Reviews/Review_Android.groovy b/resources/jenkins/dsl/Reviews/Review_Android.groovy index 5cc05c336..ca6443e13 100644 --- a/resources/jenkins/dsl/Reviews/Review_Android.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Android.groovy @@ -10,7 +10,7 @@ def j = new Review name: 'Android_APK_' + ARCH, libraries: ['Android_' + ARCH], label: 'Android', - artifacts: 'build/dist/**/AusweisApp2-*.apk*,build/debug.symbols/*' + artifacts: 'build/dist/**/AusweisApp-*.apk*,build/debug.symbols/*' ).generate(this) diff --git a/resources/jenkins/dsl/Reviews/Review_Container.groovy b/resources/jenkins/dsl/Reviews/Review_Container.groovy index 90a213f17..85319b982 100644 --- a/resources/jenkins/dsl/Reviews/Review_Container.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Container.groovy @@ -5,7 +5,7 @@ def j = new Review ( name: 'Container', label: 'Docker', - artifacts: 'build/AusweisApp2*.tar' + artifacts: 'build/AusweisApp*.tar' ).generate(this) @@ -17,13 +17,13 @@ j.with shell(strip('''\ docker build - -t dev-docker.govkg.de/ausweisapp2/sdk:${BUILD_TAG} - --build-arg CCACHE_REMOTE_STORAGE="redis://${CCACHE_REMOTE_STORAGE_HOST}|share-hits=false" + -t dev-docker.govkg.de/ausweisapp/sdk:${BUILD_TAG} + --build-arg CCACHE_REMOTE_STORAGE="redis://${CCACHE_REMOTE_STORAGE_HOST}" source ''')) - shell('docker save -o build/AusweisApp2-${BUILD_TAG}.tar dev-docker.govkg.de/ausweisapp2/sdk:${BUILD_TAG}') + shell('docker save -o build/AusweisApp-${BUILD_TAG}.tar dev-docker.govkg.de/ausweisapp/sdk:${BUILD_TAG}') - shell('docker rmi -f dev-docker.govkg.de/ausweisapp2/sdk:${BUILD_TAG}') + shell('docker rmi -f dev-docker.govkg.de/ausweisapp/sdk:${BUILD_TAG}') } } diff --git a/resources/jenkins/dsl/Reviews/Review_Docker_VNC.groovy b/resources/jenkins/dsl/Reviews/Review_Docker_VNC.groovy index 7946227e5..abfdb2f54 100644 --- a/resources/jenkins/dsl/Reviews/Review_Docker_VNC.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Docker_VNC.groovy @@ -5,7 +5,7 @@ def j = new Review ( name: 'Docker_VNC', label: 'Docker', - artifacts: 'build/AusweisApp2*.tar' + artifacts: 'build/AusweisApp*.tar' ).generate(this) @@ -17,15 +17,15 @@ j.with shell(strip('''\ docker build - -t dev-docker.govkg.de/ausweisapp2/vnc:${BUILD_TAG} - --build-arg CCACHE_REMOTE_STORAGE="redis://${CCACHE_REMOTE_STORAGE_HOST}|share-hits=false" + -t dev-docker.govkg.de/ausweisapp/vnc:${BUILD_TAG} + --build-arg CCACHE_REMOTE_STORAGE="redis://${CCACHE_REMOTE_STORAGE_HOST}" -f source/resources/jenkins/docker/Dockerfile source ''')) - shell('docker run --rm dev-docker.govkg.de/ausweisapp2/vnc:${BUILD_TAG} AusweisApp2 --help') - shell('docker save -o build/AusweisApp2-VNC-${BUILD_TAG}.tar dev-docker.govkg.de/ausweisapp2/vnc:${BUILD_TAG}') + shell('docker run --rm dev-docker.govkg.de/ausweisapp/vnc:${BUILD_TAG} AusweisApp --help') + shell('docker save -o build/AusweisApp-VNC-${BUILD_TAG}.tar dev-docker.govkg.de/ausweisapp/vnc:${BUILD_TAG}') - shell('docker rmi -f dev-docker.govkg.de/ausweisapp2/vnc:${BUILD_TAG}') + shell('docker rmi -f dev-docker.govkg.de/ausweisapp/vnc:${BUILD_TAG}') } } diff --git a/resources/jenkins/dsl/Reviews/Review_Docs.groovy b/resources/jenkins/dsl/Reviews/Review_Docs.groovy index 5c2af0fb1..37667a586 100644 --- a/resources/jenkins/dsl/Reviews/Review_Docs.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Docs.groovy @@ -20,18 +20,16 @@ j.with shell('cmake --build build --target notes') shell('cmake --build build --target notes.latex.pdf') - shell('cd build/docs/notes; cmake -E tar cfJ ../AusweisApp2_ReleaseNotes.tar.xz .') + shell('cd build/docs/notes; cmake -E tar cfJ ../AusweisApp_ReleaseNotes.tar.xz .') shell('cmake --build build --target sdk') shell('cmake --build build --target sdk.latex.pdf') - shell('cd build/docs/sdk/html; cmake -E tar cfJ ../../AusweisApp2_SDK.tar.xz .') + shell('cd build/docs/sdk/html; cmake -E tar cfJ ../../AusweisApp_SDK.tar.xz .') shell('cmake --build build --target failurecodes') shell('cmake --build build --target failurecodes.latex.pdf') - shell('cmake --build build --target inst.latex.pdf') - - shell('cmake --build build --target inte.latex.pdf') + shell('cmake --build build --target installation_integration.latex.pdf') shell('cmake --build build --target license') diff --git a/resources/jenkins/dsl/Reviews/Review_Formatting.groovy b/resources/jenkins/dsl/Reviews/Review_Formatting.groovy index 54bd2604e..58f03ebde 100644 --- a/resources/jenkins/dsl/Reviews/Review_Formatting.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Formatting.groovy @@ -35,7 +35,7 @@ j.with hg commit -m "fix formatting" -s fi - (hg --config phases.new-commit=secret import -m 'jenkins patch formatting' -d 'today' -u 'jenkins' ../patch.diff) + (hg --config patch.eol=auto --config phases.new-commit=secret import -m 'jenkins patch formatting' -d 'today' -u 'jenkins' ../patch.diff) if [ "$?" != "0" ]; then echo 'FORMATTING FAILED: Patch cannot be applied' exit 0 diff --git a/resources/jenkins/dsl/Reviews/Review_Libs_Win64_GNU.groovy b/resources/jenkins/dsl/Reviews/Review_Libs_Win64_GNU.groovy index b4ae43dbf..06c61ed12 100644 --- a/resources/jenkins/dsl/Reviews/Review_Libs_Win64_GNU.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Libs_Win64_GNU.groovy @@ -17,6 +17,7 @@ j.with environmentVariables { env('MSYS2_PATH_TYPE', 'inherit') + env('PATH', '$WORKSPACE/build/dist/bin;$PATH') } } diff --git a/resources/jenkins/dsl/Reviews/Review_Libs_Win64_MSVC.groovy b/resources/jenkins/dsl/Reviews/Review_Libs_Win64_MSVC.groovy index 6fd8e548c..636078c66 100644 --- a/resources/jenkins/dsl/Reviews/Review_Libs_Win64_MSVC.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Libs_Win64_MSVC.groovy @@ -11,6 +11,14 @@ j.with { customWorkspace('workspace/' + MERCURIAL_REVISION_BRANCH + '_RLW64M') + wrappers + { + environmentVariables + { + env('PATH', '$WORKSPACE/build/dist/bin;$PATH') + } + } + steps { batchFile('cd source & cmake -DCMD=IMPORT_PATCH -P cmake/cmd.cmake') diff --git a/resources/jenkins/dsl/Reviews/Review_Libs_Win64_MSVC_dev.groovy b/resources/jenkins/dsl/Reviews/Review_Libs_Win64_MSVC_dev.groovy index dda99fd6a..649b7185b 100644 --- a/resources/jenkins/dsl/Reviews/Review_Libs_Win64_MSVC_dev.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Libs_Win64_MSVC_dev.groovy @@ -11,6 +11,14 @@ j.with { customWorkspace('workspace/' + MERCURIAL_REVISION_BRANCH + '_RLW64MD') + wrappers + { + environmentVariables + { + env('PATH', '$WORKSPACE/build/dist/bin;$PATH') + } + } + steps { batchFile('cd source & cmake -DCMD=IMPORT_PATCH -P cmake/cmd.cmake') diff --git a/resources/jenkins/dsl/Reviews/Review_SonarQube.groovy b/resources/jenkins/dsl/Reviews/Review_SonarQube.groovy index de8179cf2..ed8175190 100644 --- a/resources/jenkins/dsl/Reviews/Review_SonarQube.groovy +++ b/resources/jenkins/dsl/Reviews/Review_SonarQube.groovy @@ -41,7 +41,7 @@ j.with shell('$WORKSPACE/sonarqubetools/sonar-build-wrapper/build-wrapper-linux-x86-64 --out-dir build cmake --build build') - shell('ctest -LE qml -E Test_ui_qml_UIPlugInQml --test-dir build --output-on-failure') + shell('ctest -LE qml -E Test_ui_qml_Qml --test-dir build --output-on-failure') shell('cmake --build build --target gcovr.sonar') diff --git a/resources/jenkins/dsl/Reviews/Review_Trigger.groovy b/resources/jenkins/dsl/Reviews/Review_Trigger.groovy index f556aaedb..66b3ad3d3 100644 --- a/resources/jenkins/dsl/Reviews/Review_Trigger.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Trigger.groovy @@ -56,7 +56,7 @@ j.with { shell('cd source; resources/jenkins/notify_rb.sh') - shell('cd source; hg import --no-commit ../patch.diff') + shell('cd source; hg --config patch.eol=auto import --no-commit ../patch.diff') phase('General', 'UNSTABLE') { diff --git a/resources/jenkins/dsl/Reviews/Review_Trigger_Configuration.groovy b/resources/jenkins/dsl/Reviews/Review_Trigger_Configuration.groovy index e25460b34..6ae107268 100644 --- a/resources/jenkins/dsl/Reviews/Review_Trigger_Configuration.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Trigger_Configuration.groovy @@ -32,7 +32,7 @@ j.with { shell('cd source; resources/jenkins/notify_rb.sh') - shell('cd source; hg import --no-commit ../patch.diff') + shell('cd source; hg --config patch.eol=auto import --no-commit ../patch.diff') phase('General', 'UNSTABLE') { diff --git a/resources/jenkins/dsl/Reviews/Review_Trigger_Libs.groovy b/resources/jenkins/dsl/Reviews/Review_Trigger_Libs.groovy index dcf33bcc6..abb305572 100644 --- a/resources/jenkins/dsl/Reviews/Review_Trigger_Libs.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Trigger_Libs.groovy @@ -44,7 +44,7 @@ j.with { shell('cd source; resources/jenkins/notify_rb.sh') - shell('cd source; hg import --no-commit ../patch.diff') + shell('cd source; hg --config patch.eol=auto import --no-commit ../patch.diff') phase('Libraries') { diff --git a/resources/jenkins/dsl/common/RootTrigger.groovy b/resources/jenkins/dsl/common/RootTrigger.groovy index a89c8e957..b8ea16937 100644 --- a/resources/jenkins/dsl/common/RootTrigger.groovy +++ b/resources/jenkins/dsl/common/RootTrigger.groovy @@ -32,6 +32,8 @@ class RootTrigger { buildDescription('', '${REVIEWBOARD_REVIEW_ID} / ${REVIEWBOARD_DIFF_REVISION}') + shell('rbt status-update set --url ${BUILD_URL} --url-text "See trigger" -r ${REVIEWBOARD_REVIEW_ID} -s ${REVIEWBOARD_STATUS_UPDATE_ID} --server ${REVIEWBOARD_SERVER} --username ${REVIEWBOARD_USER} --api-token ${REVIEWBOARD_TOKEN}') + shell('rbt patch --write patch.diff --server ${REVIEWBOARD_SERVER} --diff-revision ${REVIEWBOARD_DIFF_REVISION} ${REVIEWBOARD_REVIEW_ID}') downstreamParameterized diff --git a/resources/jenkins/dsl/config.xml b/resources/jenkins/dsl/config.xml index f36074a98..396a5692c 100644 --- a/resources/jenkins/dsl/config.xml +++ b/resources/jenkins/dsl/config.xml @@ -4,7 +4,7 @@ false - https://hg.govkg.de/AusweisApp/AusweisApp2 + https://hg.governikus.de/AusweisApp/AusweisApp2 resources/jenkins/dsl/ TAG default diff --git a/resources/jenkins/import.py b/resources/jenkins/import.py index 193ec3ed6..21c491d10 100755 --- a/resources/jenkins/import.py +++ b/resources/jenkins/import.py @@ -92,6 +92,7 @@ def main(): cfg = ['extensions.hgext.purge=', 'extensions.hgext.strip=', + 'patch.eol=auto', 'phases.new-commit=draft'] client = hglib.open(configs=cfg) diff --git a/resources/packaging/android/AndroidManifest.xml.apk.in b/resources/packaging/android/AndroidManifest.xml.apk.in index 2ecd59075..bd1585372 100644 --- a/resources/packaging/android/AndroidManifest.xml.apk.in +++ b/resources/packaging/android/AndroidManifest.xml.apk.in @@ -6,7 +6,7 @@ android:versionCode="@ANDROID_VERSION_CODE@" android:versionName="@ANDROID_VERSION_NAME@"> - + @@ -73,7 +73,9 @@ android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density" android:exported="true" android:launchMode="singleTask" - android:resizeableActivity="false"> + android:resizeableActivity="true" + android:screenOrientation="user" + android:supportsPictureInPicture="true"> @@ -84,16 +86,11 @@ - - + + + + + diff --git a/resources/packaging/android/build.gradle.append b/resources/packaging/android/build.gradle.append index babc9a356..51147ca6e 100644 --- a/resources/packaging/android/build.gradle.append +++ b/resources/packaging/android/build.gradle.append @@ -5,8 +5,7 @@ task sourcesJar(type: Jar) { } dependencies { - implementation "androidx.appcompat:appcompat:1.4.0" - implementation "androidx.core:core:1.4.0" + implementation "androidx.core:core:1.12.0" } allprojects { @@ -44,7 +43,6 @@ android { exclude '**/libplugins_imageformats_qico_*.so' exclude '**/libplugins_imageformats_qtga_*.so' exclude '**/libplugins_imageformats_qtiff_*.so' - exclude '**/libplugins_imageformats_qwebp_*.so' exclude '**/libplugins_imageformats_qwbmp_*.so' jniLibs { diff --git a/resources/packaging/android/build.gradle.append.aar b/resources/packaging/android/build.gradle.append.aar index a83b56381..6557c1109 100644 --- a/resources/packaging/android/build.gradle.append.aar +++ b/resources/packaging/android/build.gradle.append.aar @@ -1,5 +1,7 @@ android { packagingOptions { exclude '**/libplugins_imageformats_*.so' + exclude '**/libplugins_iconengines_*.so' + exclude '**/libQt6Svg_*.so' } } diff --git a/resources/packaging/android/build.gradle.append.smarteid b/resources/packaging/android/build.gradle.append.smarteid index 4dd59ae0c..d445cb3be 100644 --- a/resources/packaging/android/build.gradle.append.smarteid +++ b/resources/packaging/android/build.gradle.append.smarteid @@ -1,4 +1,3 @@ dependencies { - implementation "de.bdr.android.eid-applet-service-lib:eid-applet-service-lib:0.11.0-182" - implementation "com.tsystems.optimos.tsms:tsm-api-sdk:0.9.5" + runtimeOnly "de.bundesdruckerei.android.eid-applet-service-lib:eid-applet-service-lib:1.1.0" } diff --git a/resources/packaging/android/libAusweisApp2.so-deployment-settings.json.in b/resources/packaging/android/libAusweisApp.so-deployment-settings.json.in similarity index 68% rename from resources/packaging/android/libAusweisApp2.so-deployment-settings.json.in rename to resources/packaging/android/libAusweisApp.so-deployment-settings.json.in index 724108c52..0ccf6281b 100644 --- a/resources/packaging/android/libAusweisApp2.so-deployment-settings.json.in +++ b/resources/packaging/android/libAusweisApp.so-deployment-settings.json.in @@ -5,7 +5,24 @@ "android-version-name": "@ANDROID_VERSION_NAME@", "android-version-code": "@ANDROID_VERSION_CODE@", "android-package-source-directory": "@ANDROID_PACKAGE_SRC_DIR@", - "qt": "@QT_INSTALL_ARCHDATA@", + "qt": { + "@CMAKE_ANDROID_ARCH_ABI@": "@QT_INSTALL_ARCHDATA@" + }, + "qtDataDirectory": { + "@CMAKE_ANDROID_ARCH_ABI@": "." + }, + "qtLibExecsDirectory": { + "@CMAKE_ANDROID_ARCH_ABI@": "libexec" + }, + "qtLibsDirectory": { + "@CMAKE_ANDROID_ARCH_ABI@": "lib" + }, + "qtPluginsDirectory": { + "@CMAKE_ANDROID_ARCH_ABI@": "plugins" + }, + "qtQmlDirectory": { + "@CMAKE_ANDROID_ARCH_ABI@": "qml" + }, "sdk": "@ANDROID_SDK@", "sdkBuildToolsRevision": "@ANDROID_BUILD_TOOLS_REVISION@", "ndk": "@CMAKE_ANDROID_NDK@", @@ -14,7 +31,7 @@ "ndk-host": "@CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG@", "architectures": {"@CMAKE_ANDROID_ARCH_ABI@":"@CMAKE_CXX_ANDROID_TOOLCHAIN_MACHINE@"}, "stdcpp-path": "@CMAKE_ANDROID_NDK@/toolchains/llvm/prebuilt/@CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG@/sysroot/usr/lib/", - "application-binary": "AusweisApp2", + "application-binary": "AusweisApp", "qml-importscanner-binary": "@QT_HOST_PATH@/libexec/qmlimportscanner", "rcc-binary": "@QT_HOST_PATH@/libexec/rcc", "qml-root-path": @QML_ROOT_PATH@ diff --git a/resources/packaging/android/lint.aar.xml b/resources/packaging/android/lint.aar.xml index 3ce203f94..a2ccff2f4 100644 --- a/resources/packaging/android/lint.aar.xml +++ b/resources/packaging/android/lint.aar.xml @@ -1,16 +1,5 @@ - - - - - - - - - - - - + - + @@ -68,4 +49,18 @@ + + + + + diff --git a/resources/packaging/android/pom.xml.in b/resources/packaging/android/pom.xml.in index 40d26d307..72171ee4c 100644 --- a/resources/packaging/android/pom.xml.in +++ b/resources/packaging/android/pom.xml.in @@ -5,8 +5,8 @@ ausweisapp @PROJECT_VERSION@@POM_SNAPSHOT@ aar - Governikus AusweisApp2 - The AusweisApp2 is a software, that you can use to identify yourself online with your electronic residence permit or your eID card. + AusweisApp + The AusweisApp is a software, that you can use to identify yourself online with your electronic residence permit or your eID card. https://github.com/Governikus/AusweisApp2/ diff --git a/resources/packaging/android/res/mipmap-anydpi-v26/npa.xml b/resources/packaging/android/res/mipmap-anydpi/npa.xml similarity index 100% rename from resources/packaging/android/res/mipmap-anydpi-v26/npa.xml rename to resources/packaging/android/res/mipmap-anydpi/npa.xml diff --git a/resources/packaging/android/res/values/strings.xml b/resources/packaging/android/res/values/strings.xml index 6eacd9914..ee1b102aa 100644 --- a/resources/packaging/android/res/values/strings.xml +++ b/resources/packaging/android/res/values/strings.xml @@ -1,4 +1,4 @@ - AusweisApp2 + AusweisApp diff --git a/resources/packaging/android/res/values/style.xml b/resources/packaging/android/res/values/style.xml index a3600a55e..2948c29fa 100644 --- a/resources/packaging/android/res/values/style.xml +++ b/resources/packaging/android/res/values/style.xml @@ -1,5 +1,5 @@ - #dcebf6 + #ffffff

The AusweisApp2 is a software, that you can install on your Computer/Smartphone/Tablet, to identify yourself online with your ID card or your electronic residence permit. +

The AusweisApp is a software, that you can install on your Computer/Smartphone/Tablet, to identify yourself online with your ID card or your electronic residence permit. The App is available for the most used operating systems and works in all common browsers.

-

The AusweisApp2 offers you an intigrated self-assessment where you are able to view your data that is stored on the online ID.

+

The AusweisApp offers you an intigrated self-assessment where you are able to view your data that is stored on the online ID.

In the app you will also find an overview with the available services, a running overview and you can manage your PIN there.

This app is on behalf of the Federal Office for Information Security.

@@ -19,6 +19,6 @@ https://www.ausweisapp.bund.de/en com.governikus.ausweisapp2.desktop - AusweisApp2 + AusweisApp diff --git a/resources/packaging/macos/AusweisApp2.entitlements b/resources/packaging/macos/AusweisApp.entitlements similarity index 100% rename from resources/packaging/macos/AusweisApp2.entitlements rename to resources/packaging/macos/AusweisApp.entitlements diff --git a/resources/packaging/macos/DS_Store b/resources/packaging/macos/DS_Store deleted file mode 100644 index c46320ce4..000000000 Binary files a/resources/packaging/macos/DS_Store and /dev/null differ diff --git a/resources/packaging/win/WIX.Texts.de-DE.wxl b/resources/packaging/win/WIX.Texts.de-DE.wxl index 48c4dce7b..07267b2b9 100644 --- a/resources/packaging/win/WIX.Texts.de-DE.wxl +++ b/resources/packaging/win/WIX.Texts.de-DE.wxl @@ -36,22 +36,22 @@ 1031 Ausweis, Authentisierung - Installationspaket für die AusweisApp2 + Installationspaket für die AusweisApp Offizieller eID-Client des Bundes https://www.ausweisapp.bund.de/de/aa2/support https://www.ausweisapp.bund.de https://www.ausweisapp.bund.de/de/aa2/download Eine aktuellere Version der [ProductName] ist bereits installiert. Die Installation wird nun beendet. - Ihr Betriebssystem erfüllt leider nicht die Mindestvoraussetzungen für die AusweisApp2. Sie benötigen mindestens eine 64-Bit-Version von Windows 10 oder Windows Server 2016. - Ihr Betriebssystem erfüllt leider nicht die Mindestvoraussetzungen für die AusweisApp2. Sie benötigen mindestens eine 64-Bit-Version von Windows 10 Version 1809. - Ihr Betriebssystem erfüllt leider nicht die Mindestvoraussetzungen für die AusweisApp2. Sie benötigen mindestens eine 64-Bit-Version von Windows Server 2016 Version 1607. - AusweisApp2, der eID-Client der Governikus KG - Ermöglicht den parallelen Betrieb mehrere Instanzen der AusweisApp2 auf einem System im Anwendungsservermodus. + Ihr Betriebssystem erfüllt leider nicht die Mindestvoraussetzungen für die AusweisApp. Sie benötigen mindestens eine 64-Bit-Version von Windows 10 oder Windows Server 2016. + Ihr Betriebssystem erfüllt leider nicht die Mindestvoraussetzungen für die AusweisApp. Sie benötigen mindestens eine 64-Bit-Version von Windows 10 Version 1809. + Ihr Betriebssystem erfüllt leider nicht die Mindestvoraussetzungen für die AusweisApp. Sie benötigen mindestens eine 64-Bit-Version von Windows Server 2016 Version 1607. + AusweisApp, der eID-Client der Governikus KG + Ermöglicht den parallelen Betrieb mehrere Instanzen der AusweisApp auf einem System im Anwendungsservermodus. Installationsoptionen Verknüpfung auf dem Desktop anlegen Proxy-Dienst installieren Notwendige Regeln zur Windows-Firewall hinzufügen Firewallregeln sind u.A. für die Funktion Smartphone als Kartenleser notwendig. - Starten der AusweisApp2 + Starten der AusweisApp diff --git a/resources/packaging/win/WIX.Texts.en-US.wxl b/resources/packaging/win/WIX.Texts.en-US.wxl index 90110296c..a962543ea 100644 --- a/resources/packaging/win/WIX.Texts.en-US.wxl +++ b/resources/packaging/win/WIX.Texts.en-US.wxl @@ -2,15 +2,15 @@ 1033 A later version of [ProductName] is already installed. Setup will now exit. - Your operating system does not meet the minimum requirements for AusweisApp2. You need at least a 64-bit version of Windows 10 or Windows Server 2016. - Your operating system does not meet the minimum requirements for AusweisApp2. You need at least a 64-bit version of Windows 10 version 1809. - Your operating system does not meet the minimum requirements for AusweisApp2. You need at least a 64-bit version of Windows Server 2016 version 1607. - AusweisApp2, the eID-Client of Governikus KG + Your operating system does not meet the minimum requirements for AusweisApp. You need at least a 64-bit version of Windows 10 or Windows Server 2016. + Your operating system does not meet the minimum requirements for AusweisApp. You need at least a 64-bit version of Windows 10 version 1809. + Your operating system does not meet the minimum requirements for AusweisApp. You need at least a 64-bit version of Windows Server 2016 version 1607. + AusweisApp, the eID-Client of Governikus KG Installation options Create link on desktop The installation takes place on a Windows Terminal Server. Please take note of the information in the documentation on installations in company networks. Add required rules to Windows Firewall Firewall rules are required, among others, by the function smartphone as card reader. - Start AusweisApp2 + Start AusweisApp diff --git a/resources/packaging/win/WIX.template.in b/resources/packaging/win/WIX.template.in index cb99abade..7c84505cc 100644 --- a/resources/packaging/win/WIX.template.in +++ b/resources/packaging/win/WIX.template.in @@ -62,7 +62,7 @@ - + ProductIcon.ico diff --git a/resources/packaging/win/executable.wxs b/resources/packaging/win/executable.wxs index 70c67dc94..b92d0a1b4 100644 --- a/resources/packaging/win/executable.wxs +++ b/resources/packaging/win/executable.wxs @@ -6,11 +6,14 @@ - + + + + (NOT PROXYSERVICE) AND ( - ((WIX_UPGRADE_DETECTED OR REINSTALL) AND PROXYSERVICE_FOUND) + ((WIX_UPGRADE_DETECTED OR REINSTALL) AND (PROXYSERVICE_FOUND OR PROXYSERVICE_OLD_FOUND)) OR (NOT (WIX_UPGRADE_DETECTED OR REINSTALL) AND (WIX_SUITE_TERMINAL="1") AND NOT (WIX_SUITE_SINGLEUSERTS)) ) @@ -30,15 +33,15 @@ NOT (PROXYSERVICE = "true") - + PROXYSERVICE = "true" - - + - - + + + + (NOT SYSTEMSETTINGS) AND ( - ((WIX_UPGRADE_DETECTED OR REINSTALL) AND SYSTEMSETTINGS_FOUND) + ((WIX_UPGRADE_DETECTED OR REINSTALL) AND (SYSTEMSETTINGS_FOUND OR SYSTEMSETTINGS_OLD_FOUND)) OR (NOT (WIX_UPGRADE_DETECTED OR REINSTALL)) ) @@ -91,7 +94,7 @@ - + @@ -101,7 +104,7 @@ Protocol="udp" Profile="all" Scope="localSubnet" - Name="AusweisApp2-SaC" + Name="AusweisApp-SaC" Description="Allow inbound udp connections for Smartphone as card reader." /> diff --git a/resources/packaging/win/runtime_settings.wxs b/resources/packaging/win/runtime_settings.wxs index 94d602f96..ffb54d2f5 100644 --- a/resources/packaging/win/runtime_settings.wxs +++ b/resources/packaging/win/runtime_settings.wxs @@ -10,13 +10,21 @@ - + + + + (NOT AUTOSTART) AND ( (WIX_UPGRADE_DETECTED OR REINSTALL) AND AUTOSTART_FOUND ) + + (NOT AUTOSTART) AND ( + (WIX_UPGRADE_DETECTED OR REINSTALL) AND AUTOSTART_OLD_FOUND + ) + @@ -148,15 +156,6 @@ ) - - - - - - (NOT HISTORY) AND ( - (WIX_UPGRADE_DETECTED OR REINSTALL) AND HISTORY_FOUND - ) - @@ -175,7 +174,6 @@ - @@ -184,7 +182,7 @@ AUTOSTART = "true" - + @@ -278,13 +276,6 @@ - - - HISTORY - - - - diff --git a/resources/qml/+desktop/main.qml b/resources/qml/+desktop/main.qml index c5980ac5e..9b1fceec0 100644 --- a/resources/qml/+desktop/main.qml +++ b/resources/qml/+desktop/main.qml @@ -1,38 +1,52 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import Governikus.Global 1.0 -import Governikus.TitleBar 1.0 -import Governikus.FeedbackView 1.0 -import Governikus.MainView 1.0 -import Governikus.HistoryView 1.0 -import Governikus.SelfAuthenticationView 1.0 -import Governikus.AuthView 1.0 -import Governikus.ChangePinView 1.0 -import Governikus.ProgressView 1.0 -import Governikus.ProviderView 1.0 -import Governikus.MoreView 1.0 -import Governikus.SettingsView 1.0 -import Governikus.TutorialView 1.0 -import Governikus.UpdateView 1.0 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.AuthModel 1.0 -import Governikus.Type.UiModule 1.0 -import Governikus.Type.SettingsModel 1.0 -import Governikus.Type.SelfAuthModel 1.0 -import Governikus.Type.ChangePinModel 1.0 -import Governikus.Style 1.0 -import QtQml 2.15 -import QtQml.Models 2.15 -import QtQuick 2.15 -import QtQuick.Controls 2.15 +import Governikus.Global +import Governikus.TitleBar +import Governikus.FeedbackView +import Governikus.MainView +import Governikus.SelfAuthenticationView +import Governikus.AuthView +import Governikus.ChangePinView +import Governikus.ProgressView +import Governikus.MoreView +import Governikus.SettingsView +import Governikus.SetupAssistantView +import Governikus.UpdateView +import Governikus.View +import Governikus.Type.ApplicationModel +import Governikus.Type.AuthModel +import Governikus.Type.UiModule +import Governikus.Type.SettingsModel +import Governikus.Type.SelfAuthModel +import Governikus.Type.ChangePinModel +import Governikus.Style +import QtQml +import QtQml.Models +import QtQuick +import QtQuick.Controls ApplicationWindow { id: appWindow + + property var dominationPopup: null + + function closingPopup() { + if (SettingsModel.showTrayIcon) { + return closeWarning; + } + return quitWarning; + } + function handleClosing() { + if (SettingsModel.showTrayIcon) { + d.hideUiAndTaskbarEntry(); + return; + } + plugin.fireQuitApplicationRequest(); + } function showDetachedLogView() { if (d.detachedLogView === null) { - d.detachedLogView = detachedLogViewWindow.createObject(appWindow); + d.detachedLogView = detachedLogViewWindow.createObject(); } else { d.detachedLogView.raise(); } @@ -41,7 +55,7 @@ ApplicationWindow { color: Style.color.background minimumHeight: 360 minimumWidth: 480 - title: menuBar.rightMostAction.text + title: menuBar.title visible: false menuBar: TitleBar { @@ -57,15 +71,16 @@ ApplicationWindow { close.accepted = false; return; } - if (d.isMacOsAndAutoStartDisabled) { - close.accepted = true; + if (d.detachedLogView !== null) { + visibility = ApplicationWindow.Minimized; + close.accepted = false; return; } if (SettingsModel.remindUserToClose && !d.suppressAbortWarning) { - closeWarning.open(); + closingPopup().open(); close.accepted = false; } else { - d.hideUiAndTaskbarEntry(); + handleClosing(); } } onHeightChanged: d.setScaleFactor() @@ -75,6 +90,11 @@ ApplicationWindow { } onWidthChanged: d.setScaleFactor() + Item { + Component.onCompleted: { + Style.software_renderer = GraphicsInfo.api === GraphicsInfo.Software; + } + } QtObject { id: d @@ -89,7 +109,6 @@ ApplicationWindow { //: INFO DESKTOP Content of the popup that is shown when the AA2 is closed and the close/minimize info was not disabled. return qsTr("The program remains available via the icon in the system tray. Click on the %1 icon to reopen the user interface.").arg(Qt.application.name); } - readonly property bool isMacOsAndAutoStartDisabled: Qt.platform.os === "osx" && !SettingsModel.autoStartApp property int lastVisibility: ApplicationWindow.Windowed property bool suppressAbortWarning: false @@ -112,7 +131,7 @@ ApplicationWindow { } function setScaleFactor() { let initialSize = plugin.initialWindowSize; - ApplicationModel.scaleFactor = Math.min(width / initialSize.width, height / initialSize.height); + plugin.scaleFactor = Math.min(width / initialSize.width, height / initialSize.height); } function showDetachedLogViewIfPresent() { if (d.detachedLogView !== null) { @@ -124,7 +143,7 @@ ApplicationWindow { if (active) { return; } - var currentFlags = flags; + let currentFlags = flags; // Force the window to the foreground if it was minimized or is behind other windows (not closed to tray) if (Qt.platform.os === "windows") { flags = currentFlags | Qt.WindowStaysOnTopHint | Qt.WindowTitleHint; @@ -139,30 +158,51 @@ ApplicationWindow { requestActivate(); } } - ConfirmationPopup { + Component { id: domination - closePolicy: Popup.NoAutoClose - style: ConfirmationPopup.PopupStyle.NoButtons - text: plugin.dominator - //: INFO DESKTOP The AA2 is currently remote controlled via the SDK interface, concurrent usage of the AA2 is not possible. - title: qsTr("Another application uses %1").arg(Qt.application.name) - visible: plugin.dominated + + ConfirmationPopup { + closePolicy: Popup.NoAutoClose + style: ConfirmationPopup.PopupStyle.NoButtons + //: INFO DESKTOP The AA2 is currently remote controlled via the SDK interface, concurrent usage of the AA2 is not possible. + title: qsTr("Another application uses %1").arg(Qt.application.name) + } } ConfirmationPopup { id: closeWarning + closePolicy: Popup.NoAutoClose style: ConfirmationPopup.PopupStyle.OkButton text: d.hideToTrayText //: INFO DESKTOP Header of the popup that is shown when the AA2 is closed for the first time. title: qsTr("The user interface of the %1 is closed.").arg(Qt.application.name) - onConfirmed: d.hideUiAndTaskbarEntry() + onConfirmed: handleClosing() + + GCheckBox { + checked: !SettingsModel.remindUserToClose + //: LABEL DESKTOP + text: qsTr("Do not show this dialog again.") + + onCheckedChanged: SettingsModel.remindUserToClose = !checked + } + } + ConfirmationPopup { + id: quitWarning + + closePolicy: Popup.NoAutoClose + style: ConfirmationPopup.PopupStyle.OkButton + //: INFO DESKTOP Text of the popup that is shown when the AA2 is quit for the first time. + text: qsTr("The %1 will be shut down and an authentication will no longer be possible. You will have to restart the %1 to identify yourself towards providers.").arg(Qt.application.name) + //: INFO DESKTOP Header of the popup that is shown when the AA2 is quit for the first time. + title: qsTr("The %1 is closed.").arg(Qt.application.name) + + onConfirmed: handleClosing() GCheckBox { checked: !SettingsModel.remindUserToClose //: LABEL DESKTOP text: qsTr("Do not show this dialog again.") - textStyle: Style.text.normal onCheckedChanged: SettingsModel.remindUserToClose = !checked } @@ -170,11 +210,17 @@ ApplicationWindow { ConfirmationPopup { id: abortWorkflowWarning - //: INFO DESKTOP Content of the popup that is shown when the AA2 is closed and a workflow is still active. - readonly property string abortText: qsTr("This will cancel the current operation and hide the UI of %1. You can restart the operation at any time.").arg(Qt.application.name) + readonly property string abortText: { + if (SettingsModel.showTrayIcon) { + //: INFO DESKTOP Content of the popup that is shown when the AA2 is closed and a workflow is still active. + return qsTr("This will cancel the current operation and hide the UI of %1. You can restart the operation at any time.").arg(Qt.application.name); + } + //: INFO DESKTOP Content of the popup that is shown when the AA2 is shut down and a workflow is still active. + return qsTr("This will cancel the current operation and shut the %1 down. You will have to restart the %1 to restart the operation.").arg(Qt.application.name); + } closePolicy: Popup.NoAutoClose - text: "%1%2".arg(abortText).arg(SettingsModel.remindUserToClose && !d.isMacOsAndAutoStartDisabled ? "

%1".arg(d.hideToTrayText) : "") + text: "%1%2".arg(abortText).arg(SettingsModel.remindUserToClose && SettingsModel.showTrayIcon ? "

%1".arg(d.hideToTrayText) : "") //: INFO DESKTOP Header of the popup that is shown when the AA2 is closed and a workflow is still active title: qsTr("Abort operation") @@ -186,6 +232,19 @@ ApplicationWindow { } } Connections { + function onFireDominatorChanged() { + if (dominationPopup) { + dominationPopup.close(); + dominationPopup.destroy(); + dominationPopup = null; + } + if (plugin.dominated) { + dominationPopup = domination.createObject(appWindow, { + "text": plugin.dominator + }); + dominationPopup.open(); + } + } function onFireHideRequest() { hide(); } @@ -237,11 +296,6 @@ ApplicationWindow { target: SettingsModel } - Shortcut { - sequence: StandardKey.HelpContents - - onActivated: ApplicationModel.openOnlineHelp(menuBar.rightMostAction.helpTopic) - } Shortcut { enabled: Qt.platform.os === "osx" sequence: "Ctrl+W" @@ -259,6 +313,7 @@ ApplicationWindow { } Loader { id: contentLoader + anchors.fill: parent sourceComponent: switch (d.activeView) { case UiModule.SELF_AUTHENTICATION: @@ -267,16 +322,15 @@ ApplicationWindow { return auth; case UiModule.PINMANAGEMENT: return pinmanagement; - case UiModule.PROVIDER: - return provider; case UiModule.HELP: return help; case UiModule.SETTINGS: return settings; - case UiModule.HISTORY: - return history; case UiModule.TUTORIAL: - return tutorial; + if (SettingsModel.autoStartAvailable && !SettingsModel.autoStartSetByAdmin) { + return tutorial; + } + return main; case UiModule.UPDATEINFORMATION: return updateinformation; default: @@ -295,51 +349,49 @@ ApplicationWindow { Component { id: main + MainView { } } Component { id: selfauthentication + SelfAuthenticationView { } } Component { id: auth + AuthView { } } Component { id: pinmanagement + ChangePinView { } } - Component { - id: provider - ProviderView { - } - } Component { id: help + MoreView { } } Component { id: settings + SettingsView { } } - Component { - id: history - HistoryView { - } - } Component { id: tutorial - SetupAssistantView { + + SetupAutostartView { } } Component { id: updateinformation + UpdateView { onLeaveView: d.activeView = UiModule.DEFAULT } @@ -356,18 +408,17 @@ ApplicationWindow { } } Rectangle { - color: Constants.white + color: Style.color.pane_sublevel height: childrenRect.height opacity: 0.7 - radius: ApplicationModel.scaleFactor * 4 + radius: Style.dimens.pane_radius visible: SettingsModel.developerMode && d.activeView !== UiModule.SETTINGS width: childrenRect.width anchors { bottom: parent.bottom bottomMargin: 4 - right: parent.right - rightMargin: 4 + horizontalCenter: parent.horizontalCenter } Row { padding: Constants.pane_padding / 2 @@ -388,17 +439,10 @@ ApplicationWindow { } } } - Rectangle { - id: developerWarning - anchors.verticalCenter: parent.bottom - antialiasing: true - color: Constants.red - height: ApplicationModel.scaleFactor * 50 - opacity: 0.5 - rotation: -Math.atan(contentLoader.height / contentLoader.width) * 180 / Math.PI - transformOrigin: Item.Left + Crossed { + height: contentLoader.height visible: SettingsModel.developerMode && d.activeView !== UiModule.SETTINGS - width: Math.sqrt(contentLoader.width * contentLoader.width + contentLoader.height * contentLoader.height) + width: contentLoader.width } Connections { function onFireProxyAuthenticationRequired(pProxyCredentials) { @@ -410,9 +454,11 @@ ApplicationWindow { } ProxyCredentialsPopup { id: proxyCredentials + } Component { id: detachedLogViewWindow + ApplicationWindow { height: plugin.initialWindowSize.height minimumHeight: appWindow.minimumHeight diff --git a/resources/qml/+mobile/main.qml b/resources/qml/+mobile/main.qml index f06d3e076..5eed94ccf 100644 --- a/resources/qml/+mobile/main.qml +++ b/resources/qml/+mobile/main.qml @@ -1,27 +1,29 @@ /** * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.TitleBar 1.0 -import Governikus.Navigation 1.0 -import Governikus.View 1.0 -import Governikus.FeedbackView 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.RemoteServiceModel 1.0 -import Governikus.Type.SettingsModel 1.0 -import Governikus.Type.UiModule 1.0 -import Governikus.Style 1.0 +import QtQuick +import QtQuick.Controls +import Governikus.Global +import Governikus.TitleBar +import Governikus.Navigation +import Governikus.View +import Governikus.FeedbackView +import Governikus.Type.ApplicationModel +import Governikus.Type.RemoteServiceModel +import Governikus.Type.SettingsModel +import Governikus.Type.UiModule +import Governikus.Style ApplicationWindow { id: appWindow + property var feedbackPopup: null + // Workaround for qt 5.12 not calculating the highdpi scaling factor correctly. On some devices (like the pixel 3) // this leads to a small light stripe above the dark statusbar. By setting the background to black and filling the // rest of the window with the background color, it's still there but not noticeable. color: "#000000" - flags: Qt.Window | Qt.MaximizeUsingFullscreenGeometryHint + flags: Qt.platform.os === "ios" ? Qt.Window | Qt.MaximizeUsingFullscreenGeometryHint : Qt.Window visible: true background: Rectangle { @@ -31,15 +33,19 @@ ApplicationWindow { readonly property var currentSectionPage: contentArea.currentSectionPage readonly property bool isBackAction: navigationAction && navigationAction.action === NavigationAction.Action.Back - color: currentSectionPage ? currentSectionPage.titleBarColor : null navigationAction: currentSectionPage ? currentSectionPage.navigationAction : null rightAction: currentSectionPage ? currentSectionPage.rightTitleBarAction : null + showSeparator: currentSectionPage ? currentSectionPage.contentIsScrolled : false + smartEidUsed: currentSectionPage ? currentSectionPage.smartEidUsed : false title: currentSectionPage ? currentSectionPage.title : "" titleBarOpacity: currentSectionPage ? currentSectionPage.titleBarOpacity : 1 visible: !currentSectionPage || currentSectionPage.titleBarVisible } Component.onCompleted: { + Style.dimens.screenHeight = Qt.binding(function () { + return appWindow.height; + }); feedback.showIfNecessary(); } onClosing: pClose => { @@ -47,7 +53,7 @@ ApplicationWindow { pClose.accepted = false; if (contentArea.visibleItem) { if (contentArea.activeModule === UiModule.DEFAULT) { - var currentTime = new Date().getTime(); + let currentTime = new Date().getTime(); if (currentTime - d.lastCloseInvocation < 1000) { plugin.fireQuitApplicationRequest(); pClose.accepted = true; @@ -58,9 +64,9 @@ ApplicationWindow { ApplicationModel.showFeedback(qsTr("To close the app, quickly press the back button twice.")); return; } - var activeStackView = contentArea.visibleItem; - var navigationAction = contentArea.currentSectionPage.navigationAction; - if (activeStackView.depth <= 1 && (!navigationAction || navigationAction.action !== NavigationAction.Action.Cancel) && contentArea.activeModule !== UiModule.PROVIDER) { + let activeStackView = contentArea.visibleItem; + let navigationAction = contentArea.currentSectionPage.navigationAction; + if (activeStackView.depth <= 1 && (!navigationAction || navigationAction.action !== NavigationAction.Action.Cancel)) { navigation.show(UiModule.DEFAULT); } else if (navigationAction) { navigationAction.clicked(undefined); @@ -116,6 +122,7 @@ ApplicationWindow { } ContentArea { id: contentArea + function reset() { currentSectionPage.popAll(); currentSectionPage.reset(); @@ -125,14 +132,14 @@ ApplicationWindow { anchors { bottom: navigation.top - bottomMargin: !navigation.lockedAndHidden || !currentSectionPage ? 0 : (currentSectionPage.automaticSafeAreaMarginHandling ? plugin.safeAreaMargins.bottom : 0) + (currentSectionPage.hiddenNavbarPadding ? Style.dimens.navigation_bar_height : 0) + bottomMargin: !navigation.lockedAndHidden || !currentSectionPage ? 0 : plugin.safeAreaMargins.bottom + (currentSectionPage.hiddenNavbarPadding ? navigation.height : 0) left: parent.left leftMargin: plugin.safeAreaMargins.left right: parent.right rightMargin: plugin.safeAreaMargins.right top: parent.top - Behavior on bottomMargin { + Behavior on bottomMargin { enabled: !ApplicationModel.isScreenReaderRunning() NumberAnimation { @@ -143,12 +150,15 @@ ApplicationWindow { } Navigation { id: navigation + onResetContentArea: contentArea.reset() anchors { bottom: parent.bottom left: parent.left + leftMargin: plugin.safeAreaMargins.left right: parent.right + rightMargin: plugin.safeAreaMargins.right } } IosBackGestureMouseArea { @@ -157,19 +167,38 @@ ApplicationWindow { onBackGestureTriggered: menuBar.navigationAction.clicked() } - ConfirmationPopup { + Connections { + function onFireFeedbackChanged() { + if (feedbackPopup) { + feedbackPopup.close(); + feedbackPopup.destroy(); + feedbackPopup = null; + } + if (ApplicationModel.feedback !== "") { + feedbackPopup = toast.createObject(appWindow, { + "text": ApplicationModel.feedback + }); + feedbackPopup.open(); + } + } + + target: ApplicationModel + } + Component { id: toast - closePolicy: Popup.NoAutoClose - dim: true - modal: ApplicationModel.isScreenReaderRunning() - style: ApplicationModel.isScreenReaderRunning() ? ConfirmationPopup.PopupStyle.OkButton : ConfirmationPopup.PopupStyle.NoButtons - text: ApplicationModel.feedback - visible: ApplicationModel.feedback !== "" - - onConfirmed: ApplicationModel.onShowNextFeedback() + + ConfirmationPopup { + closePolicy: Popup.NoAutoClose + dim: true + modal: ApplicationModel.isScreenReaderRunning() + style: ApplicationModel.isScreenReaderRunning() ? ConfirmationPopup.PopupStyle.OkButton : ConfirmationPopup.PopupStyle.NoButtons + + onConfirmed: ApplicationModel.onShowNextFeedback() + } } StoreFeedbackPopup { id: feedback + function showIfNecessary() { if (ApplicationModel.currentWorkflow === ApplicationModel.WORKFLOW_NONE && !RemoteServiceModel.running && SettingsModel.requestStoreFeedback()) { SettingsModel.hideFutureStoreFeedbackDialogs(); diff --git a/resources/qml/Governikus/AuthView/+desktop/AuthController.qml b/resources/qml/Governikus/AuthView/+desktop/AuthController.qml index 40533ee0c..291f2e60b 100644 --- a/resources/qml/Governikus/AuthView/+desktop/AuthController.qml +++ b/resources/qml/Governikus/AuthView/+desktop/AuthController.qml @@ -1,17 +1,18 @@ /** * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.AuthModel 1.0 -import Governikus.Type.NumberModel 1.0 -import Governikus.Type.SettingsModel 1.0 -import Governikus.Type.ChatModel 1.0 -import Governikus.Type.ConnectivityManager 1.0 +import QtQuick +import Governikus.View +import Governikus.Type.ApplicationModel +import Governikus.Type.AuthModel +import Governikus.Type.NumberModel +import Governikus.Type.SettingsModel +import Governikus.Type.ChatModel +import Governikus.Type.ConnectivityManager Controller { id: controller + enum WorkflowStates { Initial, Reader, @@ -20,16 +21,15 @@ Controller { Processing } + readonly property alias networkInterfaceActive: connectivityManager.networkInterfaceActive property bool workflowProgressVisible: false property int workflowState: 0 - function processStateChange() { - switch (AuthModel.currentState) { - case "Initial": - break; + function processStateChange(pState) { + switch (pState) { case "StateGetTcToken": controller.workflowState = AuthController.WorkflowStates.Initial; - if (!ConnectivityManager.networkInterfaceActive) { + if (!networkInterfaceActive) { controller.nextView(AuthView.SubViews.Connectivity); } else { controller.nextView(AuthView.SubViews.Progress); @@ -80,7 +80,7 @@ Controller { } setAuthWorkflowStateAndContinue(AuthController.WorkflowStates.Processing); break; - case "StateWriteHistory": + case "StateActivateStoreFeedbackDialog": showRemoveCardFeedback(AuthModel, true); AuthModel.continueWorkflow(); break; @@ -110,24 +110,28 @@ Controller { AuthModel.continueWorkflow(); } - Component.onCompleted: if (AuthModel.currentState === "StateProcessing") - processStateChange() + Component.onCompleted: if (AuthModel.currentState === "StateParseTcTokenUrl") + processStateChange(AuthModel.currentState) Connections { - // This is necessary because onCurrentStateChanged is not - // working, when we need to process a state a second time. - function onFireCurrentStateChanged(pState) { - processStateChange(); + function onFireStateEntered(pState) { + processStateChange(pState); + } + function onFireWorkflowFinished() { + connectivityManager.watching = false; + } + function onFireWorkflowStarted() { + connectivityManager.watching = true; } target: AuthModel } - Connections { - function onFireNetworkInterfaceActiveChanged(pActive) { - processStateChange(); - } + ConnectivityManager { + id: connectivityManager - enabled: AuthModel.currentState === "StateGetTcToken" - target: ConnectivityManager + onNetworkInterfaceActiveChanged: { + if (AuthModel.currentState === "StateGetTcToken") + processStateChange(AuthModel.currentState); + } } } diff --git a/resources/qml/Governikus/AuthView/+desktop/AuthView.qml b/resources/qml/Governikus/AuthView/+desktop/AuthView.qml index 390ef5722..05a36fc58 100644 --- a/resources/qml/Governikus/AuthView/+desktop/AuthView.qml +++ b/resources/qml/Governikus/AuthView/+desktop/AuthView.qml @@ -1,28 +1,28 @@ /** * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.EnterPasswordView 1.0 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.PasswordInfoView 1.0 -import Governikus.ProgressView 1.0 -import Governikus.ResultView 1.0 -import Governikus.SettingsView 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 -import Governikus.Workflow 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.SettingsModel 1.0 -import Governikus.Type.AuthModel 1.0 -import Governikus.Type.NumberModel 1.0 -import Governikus.Type.PasswordType 1.0 -import Governikus.Type.ConnectivityManager 1.0 -import Governikus.Type.UiModule 1.0 +import QtQuick +import QtQuick.Controls +import Governikus.EnterPasswordView +import Governikus.Global +import Governikus.Style +import Governikus.PasswordInfoView +import Governikus.ProgressView +import Governikus.ResultView +import Governikus.SettingsView +import Governikus.TitleBar +import Governikus.View +import Governikus.Workflow +import Governikus.Type.ApplicationModel +import Governikus.Type.SettingsModel +import Governikus.Type.AuthModel +import Governikus.Type.NumberModel +import Governikus.Type.PasswordType +import Governikus.Type.UiModule SectionPage { id: authView + enum SubViews { Undefined, TransportPinReminder, @@ -57,14 +57,13 @@ SectionPage { titleBarAction: TitleBarAction { customSettingsHandler: authView.showSettings - helpTopic: "authentication" rootEnabled: false showSettings: authController.workflowState === AuthController.WorkflowStates.Reader //: LABEL DESKTOP text: qsTr("Identify") - customSubAction: CancelAction { - visible: d.cancelAllowed + customSubAction: NavigationAction { + enabled: d.cancelAllowed onClicked: { if (authResult.visible) { @@ -78,9 +77,17 @@ SectionPage { onClicked: { editRights.showProviderInformation(false); - if (d.activeView === AuthView.SubViews.TransportPinReminderInfo || d.activeView === AuthView.SubViews.PasswordInfo || d.activeView === AuthView.SubViews.ReaderSettings) { + switch (d.activeView) { + case AuthView.SubViews.TransportPinReminderInfo: + case AuthView.SubViews.PasswordInfo: + case AuthView.SubViews.ReaderSettings: d.view = d.precedingView; updateTitleBarActions(); + break; + case AuthView.SubViews.Data: + authView.nextView(UiModule.SELF_AUTHENTICATION); + AuthModel.continueWorkflow(); + break; } } } @@ -93,6 +100,7 @@ SectionPage { readonly property int activeView: inputError.visible ? AuthView.SubViews.InputError : view readonly property bool cancelAllowed: AuthModel.isBasicReader || generalWorkflow.waitingFor !== Workflow.WaitingFor.Password + property int enteredPasswordType: PasswordType.PIN readonly property int passwordType: NumberModel.passwordType property int precedingView: AuthView.SubViews.Undefined property int view: AuthView.SubViews.Undefined @@ -107,6 +115,7 @@ SectionPage { } AuthController { id: authController + onNextView: pName => { if (pName === AuthView.SubViews.ReturnToMain) { if (AuthModel.showChangePinView) { @@ -135,6 +144,7 @@ SectionPage { } ProgressView { id: checkConnectivityView + //: INFO DESKTOP Content of the message that no network connection is present during the authentication procedure. subText: qsTr("Please establish an internet connection.") subTextColor: Constants.red @@ -145,10 +155,12 @@ SectionPage { } EditRights { id: editRights + visible: d.activeView === AuthView.SubViews.AccessRights } GeneralWorkflow { id: generalWorkflow + isPinChange: false visible: d.activeView === AuthView.SubViews.Workflow waitingFor: switch (authController.workflowState) { @@ -171,7 +183,7 @@ SectionPage { property string deviceName - resultType: ResultView.Type.IsError + icon: "qrc:///images/workflow_error_no_sak_%1.svg".arg(Style.currentTheme.name) //: INFO DESKTOP The paired devices was removed since it did not respond to connection attempts. It needs to be paired again if it should be used as card reader. text: qsTr("The device \"%1\" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader.").arg(deviceName) visible: d.activeView === AuthView.SubViews.WorkflowError @@ -180,12 +192,14 @@ SectionPage { } EnterPasswordView { id: enterPasswordView + //: LABEL DESKTOP A11y button to confirm the PIN and start the provider authentication accessibleContinueText: passwordType === PasswordType.PIN || passwordType === PasswordType.SMART_PIN || (passwordType === PasswordType.CAN && NumberModel.isCanAllowedMode) ? qsTr("Authenticate with provider") : "" moreInformationText: infoData.linkText visible: d.activeView === AuthView.SubViews.Password - onPasswordEntered: { + onPasswordEntered: pPasswordType => { + d.enteredPasswordType = pPasswordType; d.view = AuthView.SubViews.Progress; AuthModel.continueWorkflow(); } @@ -193,14 +207,16 @@ SectionPage { } PasswordInfoData { id: infoData + contentType: d.activeView === AuthView.SubViews.TransportPinReminder || d.activeView === AuthView.SubViews.TransportPinReminderInfo ? PasswordInfoContent.Type.CHANGE_PIN : fromPasswordType(d.passwordType, NumberModel.isCanAllowedMode) } PasswordInfoView { id: passwordInfoView + infoContent: infoData visible: d.activeView === AuthView.SubViews.PasswordInfo || d.activeView === AuthView.SubViews.TransportPinReminderInfo - titleBarAction.customSubAction: CancelAction { + titleBarAction.customSubAction: NavigationAction { onClicked: passwordInfoView.close() } @@ -215,7 +231,17 @@ SectionPage { property bool errorConfirmed: false - resultType: ResultView.Type.IsError + icon: switch (d.enteredPasswordType) { + case PasswordType.SMART_PIN: + case PasswordType.PIN: + return "qrc:///images/workflow_error_wrong_pin_%1.svg".arg(Style.currentTheme.name); + case PasswordType.CAN: + return "qrc:///images/workflow_error_wrong_can_%1.svg".arg(Style.currentTheme.name); + case PasswordType.PUK: + return "qrc:///images/workflow_error_wrong_puk_%1.svg".arg(Style.currentTheme.name); + default: + return ""; + } text: NumberModel.inputError visible: !errorConfirmed && NumberModel.hasPasswordError && d.view !== AuthView.SubViews.Result @@ -231,7 +257,8 @@ SectionPage { } ResultView { id: cardPositionView - resultType: ResultView.Type.IsInfo + + icon: "qrc:///images/workflow_error_nfc_%1.svg".arg(Style.currentTheme.name) text: AuthModel.isRemoteReader ? //: INFO DESKTOP A weak NFC signal was detected since the card communication was aborted. The card's position needs to be adjusted to hopefully achieve better signal strength. qsTr("Weak NFC signal. Please\n- change the card position\n- remove the mobile phone case (if present)\n- connect the smartphone with a charging cable") : @@ -244,14 +271,14 @@ SectionPage { ProgressView { progressBarVisible: false subText: { - if (ConnectivityManager.networkInterfaceActive) { + if (authController.networkInterfaceActive) { //: INFO DESKTOP Information message about cancellation process with present network connectivity return qsTr("Please wait a moment."); } //: INFO DESKTOP Information message about cancellation process without working network connectivity return qsTr("Network problems detected, trying to reach server within 30 seconds."); } - subTextColor: !ConnectivityManager.networkInterfaceActive ? Style.color.warning_text : Style.color.secondary_text + subTextColor: !authController.networkInterfaceActive ? Style.color.text_warning : Style.color.text //: INFO DESKTOP The user aborted the authentication process, according to TR we need to inform the service provider text: qsTr("Aborting process and informing the service provider") @@ -281,7 +308,7 @@ SectionPage { //: INFO DESKTOP Generic progress status message during authentication. return qsTr("Please wait a moment."); } - subTextColor: !AuthModel.isBasicReader && NumberModel.inputError ? Style.color.warning_text : Style.color.secondary_text + subTextColor: !AuthModel.isBasicReader && NumberModel.inputError ? Style.color.text_warning : Style.color.text text: (isInitialState ? //: INFO DESKTOP Header of the progress information during the authentication process. qsTr("Acquiring provider certificate") : @@ -292,22 +319,23 @@ SectionPage { SelfAuthenticationData { visible: d.activeView === AuthView.SubViews.Data - onNextView: pName => { - authView.nextView(pName); + onAccept: { + authView.nextView(UiModule.DEFAULT); AuthModel.continueWorkflow(); } onVisibleChanged: updateTitleBarActions() } ResultView { id: authResult + header: AuthModel.errorHeader hintButtonText: AuthModel.statusHintActionText hintText: AuthModel.statusHintText + icon: AuthModel.statusCodeImage !== "" ? AuthModel.statusCodeImage.arg(Style.currentTheme.name) : "" mailButtonVisible: AuthModel.errorIsMasked popupText: AuthModel.errorText //: INFO DESKTOP Error code (string) of current GlobalStatus code, shown as header of popup. popupTitle: qsTr("Error code: %1").arg(AuthModel.statusCodeString) - resultType: AuthModel.resultString ? ResultView.Type.IsError : ResultView.Type.IsSuccess text: AuthModel.resultString visible: d.activeView === AuthView.SubViews.Result diff --git a/resources/qml/Governikus/AuthView/+desktop/CertificateDescriptionPage.qml b/resources/qml/Governikus/AuthView/+desktop/CertificateDescriptionPage.qml index 12acd67d3..47d8fa569 100644 --- a/resources/qml/Governikus/AuthView/+desktop/CertificateDescriptionPage.qml +++ b/resources/qml/Governikus/AuthView/+desktop/CertificateDescriptionPage.qml @@ -1,16 +1,15 @@ /** * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 -import Governikus.Type.CertificateDescriptionModel 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.TitleBar +import Governikus.View +import Governikus.Type.CertificateDescriptionModel SectionPage { - signal exit - titleBarAction: TitleBarAction { rootEnabled: false showHelp: false @@ -20,34 +19,23 @@ SectionPage { ScrollablePane { id: pane + activeFocusOnTab: true anchors.fill: parent anchors.margins: Constants.pane_padding - //: LABEL DESKTOP - title: qsTr("Provider Information") - Repeater { id: listView + model: CertificateDescriptionModel LabeledText { + Layout.fillWidth: true + alignment: Text.AlignHCenter label: model.label text: model.text textFormat: Text.PlainText - width: parent.width } } } - GButton { - id: button - anchors.bottom: pane.bottom - anchors.margins: Constants.pane_padding - anchors.right: pane.right - - //: LABEL DESKTOP - text: qsTr("Close") - - onClicked: parent.exit() - } } diff --git a/resources/qml/Governikus/AuthView/+desktop/DataGroup.qml b/resources/qml/Governikus/AuthView/+desktop/DataGroup.qml index e07424381..8ca094ffc 100644 --- a/resources/qml/Governikus/AuthView/+desktop/DataGroup.qml +++ b/resources/qml/Governikus/AuthView/+desktop/DataGroup.qml @@ -1,14 +1,15 @@ /** * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 - -Column { +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.View +import Governikus.Type.ApplicationModel + +ColumnLayout { id: root property alias chat: repeater.model @@ -16,28 +17,34 @@ Column { readonly property alias count: repeater.count property alias title: dataTitle.text property alias titleStyle: dataTitle.textStyle + property bool writeAccess: false spacing: Constants.pane_spacing visible: count > 0 GText { id: dataTitle + Accessible.name: dataTitle.text activeFocusOnTab: true - textStyle: Style.text.header_accent + color: writeAccess ? Style.color.text_warning : titleStyle.textColor + textStyle: Style.text.headline FocusFrame { } } Grid { id: grid + + Layout.fillWidth: true + Layout.preferredWidth: repeater.maxItemWidth * columns + grid.columnSpacing * (columns - 1) columnSpacing: Constants.pane_spacing flow: Grid.TopToBottom verticalItemAlignment: Grid.AlignBottom - width: parent.width - Repeater { + GRepeater { id: repeater + visible: count > 0 Item { @@ -48,14 +55,16 @@ Column { Accessible.name: dataText.text + (optional ? ": " + (selected ? qsTr("selected") : qsTr("not selected")) : "") Accessible.role: optional ? Accessible.CheckBox : Accessible.StaticText activeFocusOnTab: true - height: dataText.height * 1.5 - width: (grid.width - ((grid.columns - 1) * grid.columnSpacing)) / grid.columns + implicitHeight: dataText.height * 1.5 + implicitWidth: dataText.implicitWidth + (checkBox.visible ? checkBox.implicitWidth : 0) + width: (grid.width - (grid.columnSpacing * (grid.columns - 1))) / grid.columns Keys.onSpacePressed: if (optional) selected = !selected GText { id: dataText + anchors.left: parent.left anchors.right: parent.right anchors.rightMargin: checkBox.visible ? checkBox.width + Constants.pane_spacing : 0 @@ -75,6 +84,7 @@ Column { } GCheckBox { id: checkBox + activeFocusOnTab: false anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter @@ -89,10 +99,10 @@ Column { Rectangle { anchors.fill: parent - color: Style.color.accent + color: Style.color.control opacity: parent.pressed ? 0.5 : 0 - Behavior on opacity { + Behavior on opacity { NumberAnimation { duration: 100 } diff --git a/resources/qml/Governikus/AuthView/+desktop/EditRights.qml b/resources/qml/Governikus/AuthView/+desktop/EditRights.qml index 65d8fc50e..5753892e3 100644 --- a/resources/qml/Governikus/AuthView/+desktop/EditRights.qml +++ b/resources/qml/Governikus/AuthView/+desktop/EditRights.qml @@ -1,19 +1,18 @@ /** * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Provider 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.AuthModel 1.0 -import Governikus.Type.NumberModel 1.0 -import Governikus.Type.CertificateDescriptionModel 1.0 -import Governikus.Type.ChatModel 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.TitleBar +import Governikus.View +import Governikus.Type.ApplicationModel +import Governikus.Type.AuthModel +import Governikus.Type.NumberModel +import Governikus.Type.CertificateDescriptionModel +import Governikus.Type.ChatModel SectionPage { id: root @@ -39,6 +38,7 @@ SectionPage { QtObject { id: d + function onKeyboardConfirmPressed(event) { if (detailView) { showProviderInformation(false); @@ -49,104 +49,62 @@ SectionPage { } ColumnLayout { anchors.fill: parent - anchors.topMargin: (providerImage.height / 2) + (Constants.pane_padding * 2) + anchors.topMargin: Constants.pane_padding * 2 spacing: Constants.pane_spacing visible: !root.detailView - Rectangle { - id: providerRect - Layout.fillWidth: true - Layout.preferredHeight: providerColumn.height - border.color: Style.color.high_contrast_item_border - border.width: Style.dimens.high_contrast_item_border - color: Style.color.background_pane + RowLayout { + Layout.alignment: Qt.AlignHCenter + Layout.maximumWidth: parent.width * 0.65 + spacing: Constants.pane_spacing Image { - id: providerImage - anchors.left: parent.left - anchors.leftMargin: Constants.pane_padding - anchors.verticalCenter: parent.top + id: npaIcon + source: "qrc:///images/npa.svg" - sourceSize.height: providerColumn.height + sourceSize.height: Style.dimens.huge_icon_size } - Column { - id: providerColumn - bottomPadding: Constants.pane_padding - spacing: Constants.pane_spacing - topPadding: Constants.pane_padding - - anchors { - left: providerImage.right - margins: Constants.pane_padding - right: parent.right - } + GPane { + id: providerInfoSectionPane + + Layout.fillWidth: true + ProviderInfoSection { - id: providerInfo + Layout.fillWidth: true activeFocusOnTab: true - image: "qrc:///images/provider/information.svg" + image: "qrc:///images/info.svg" name: CertificateDescriptionModel.subjectName //: LABEL DESKTOP - title: qsTr("You are about to identify yourself towards the following provider") + title: qsTr("You are about to identify yourself towards the following provider:") - anchors { - left: parent.left - right: parent.right - rightMargin: Constants.component_spacing - } + onClicked: showProviderInformation(true) } - Item { - height: Math.max(detailsButton.height, confirmButton.height) - - anchors { - left: parent.left - right: parent.right - } - GButton { - id: detailsButton - Accessible.description: qsTr("Show more information about the service provider") - activeFocusOnTab: true - icon.source: "qrc:///images/desktop/info_white.svg" - - //: LABEL DESKTOP - text: qsTr("Details about the provider") - - onClicked: showProviderInformation(true) + } + } + GButton { + id: confirmButton - anchors { - left: parent.left - top: parent.top - } - } - GButton { - id: confirmButton - Accessible.name: confirmButton.text - activeFocusOnTab: true - icon.source: "qrc:///images/identify.svg" - //: LABEL DESKTOP %1 can be "CAN" or "PIN" - text: qsTr("Proceed to %1 entry").arg(NumberModel.isCanAllowedMode ? - //: LABEL DESKTOP Inserted into "Proceed to %1 entry" - qsTr("CAN") : - //: LABEL DESKTOP Inserted into "Proceed to %1 entry" - qsTr("PIN")) - tintIcon: true - - onClicked: { - ChatModel.transferAccessRights(); - AuthModel.continueWorkflow(); - } - - anchors { - bottom: parent.bottom - right: parent.right - } - } - } + Accessible.name: confirmButton.text + Layout.alignment: Qt.AlignHCenter + activeFocusOnTab: true + icon.source: "qrc:/images/identify.svg" + //: LABEL DESKTOP %1 can be "CAN" or "PIN" + text: qsTr("Proceed to %1 entry").arg(NumberModel.isCanAllowedMode ? + //: LABEL DESKTOP Inserted into "Proceed to %1 entry" + qsTr("CAN") : + //: LABEL DESKTOP Inserted into "Proceed to %1 entry" + qsTr("PIN")) + tintIcon: true + + onClicked: { + ChatModel.transferAccessRights(); + AuthModel.continueWorkflow(); } } GText { id: dataIntroduction + Accessible.name: dataIntroduction.text - Layout.fillWidth: true Layout.leftMargin: Constants.pane_padding Layout.rightMargin: Constants.pane_padding activeFocusOnTab: true @@ -155,18 +113,18 @@ SectionPage { qsTr("By entering the CAN, access to the following data of the ID card will be allowed to the mentioned provider:") : //: LABEL DESKTOP qsTr("By entering your PIN, access to the following data of your ID card will be allowed to the mentioned provider:") - textStyle: Style.text.normal FocusFrame { } } ScrollablePane { - Layout.fillHeight: true Layout.fillWidth: true Layout.leftMargin: Constants.pane_padding - Layout.maximumHeight: implicitHeight + Layout.maximumHeight: parent.height / parent.children.length Layout.rightMargin: Constants.pane_padding activeFocusOnTab: true + backgroundColor: Style.color.pane_sublevel + minimumVisibleContentHeight: transactionText.effectiveFirstLineHeight //: LABEL DESKTOP title: qsTr("Transactional information") @@ -174,88 +132,102 @@ SectionPage { GText { id: transactionText + Accessible.name: transactionText.text activeFocusOnTab: true text: AuthModel.transactionInfo - textStyle: Style.text.normal visible: !!text - width: parent.width FocusFrame { } } GText { id: noAccessRightsText + Accessible.name: noAccessRightsText.text activeFocusOnTab: true //: LABEL DESKTOP text: qsTr("The provider mentioned above does not require any data stored on your ID card, only confirmation of you possessing a valid ID card.") - textStyle: Style.text.normal visible: !writeDataPane.visible && !readDataPane.visible - width: parent.width FocusFrame { } } } - Row { + RowLayout { id: requestedDataRow - readonly property int columnWidth: (width - spacing) / maxColumns readonly property int maxColumns: 3 Layout.fillWidth: true Layout.leftMargin: Constants.pane_padding - Layout.preferredHeight: Math.max(writeDataPane.implicitHeight, readDataPane.implicitHeight) + Layout.maximumHeight: implicitHeight Layout.rightMargin: Constants.pane_padding spacing: Constants.pane_spacing visible: writeData.count > 0 || requiredData.count > 0 || optionalData.count > 0 - GPane { + ScrollablePane { id: writeDataPane - height: parent.height + + Layout.alignment: Qt.AlignTop + Layout.fillHeight: true + Layout.fillWidth: true + backgroundColor: Style.color.pane_sublevel visible: writeData.count > 0 - width: readDataPane.visible ? requestedDataRow.columnWidth : parent.width DataGroup { id: writeData + + Layout.fillWidth: true chat: ChatModel.write columns: readDataPane.visible ? 1 : requestedDataRow.maxColumns //: LABEL DESKTOP title: qsTr("Write access (update)") - titleStyle: Style.text.header_warning - width: parent.width + titleStyle: Style.text.headline + writeAccess: true } } - GPane { + ScrollablePane { id: readDataPane - height: parent.height + + Layout.alignment: Qt.AlignTop + Layout.fillHeight: true + Layout.fillWidth: true + backgroundColor: Style.color.pane_sublevel visible: requiredData.count > 0 || optionalData.count > 0 - width: writeDataPane.visible ? requestedDataRow.columnWidth * 2 : parent.width - Row { + RowLayout { + id: readRow + + readonly property real columnWidth: Math.max(requiredData.implicitWidth / requiredData.columns, optionalData.implicitWidth / optionalData.columns) + spacing: Constants.pane_spacing - width: parent.width DataGroup { id: requiredData + + Layout.alignment: Qt.AlignTop | Qt.AlignRight + Layout.fillWidth: true + Layout.preferredWidth: readRow.columnWidth * columns chat: ChatModel.required columns: Math.max(1, requestedDataRow.maxColumns - (writeData.visible ? writeData.columns : 0) - (optionalData.visible ? 1 : 0) - (count > optionalData.count ? 0 : 1)) //: LABEL DESKTOP title: qsTr("Read access") - width: optionalData.visible ? parent.width / 2 : parent.width } DataGroup { id: optionalData + + Layout.alignment: Qt.AlignTop | Qt.AlignLeft + Layout.fillWidth: true + Layout.preferredWidth: readRow.columnWidth * columns chat: ChatModel.optional columns: Math.max(1, requestedDataRow.maxColumns - (writeData.visible ? writeData.columns : 0) - (requiredData.visible ? requiredData.columns : 0)) //: LABEL DESKTOP title: qsTr("Read access (optional)") - width: requiredData.visible ? parent.width / 2 : parent.width } } } @@ -267,8 +239,7 @@ SectionPage { } CertificateDescriptionPage { id: certificateDescriptionPage - visible: root.detailView - onExit: showProviderInformation(false) + visible: root.detailView } } diff --git a/resources/qml/Governikus/AuthView/+desktop/ProviderInfoSection.qml b/resources/qml/Governikus/AuthView/+desktop/ProviderInfoSection.qml new file mode 100644 index 000000000..0d9456208 --- /dev/null +++ b/resources/qml/Governikus/AuthView/+desktop/ProviderInfoSection.qml @@ -0,0 +1,75 @@ +/** + * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.View +import Governikus.Type.ApplicationModel + +MouseArea { + id: baseItem + + property alias image: icon.source + property string name: "" + property alias title: text.label + + Accessible.name: text.Accessible.name + Accessible.role: Accessible.StaticText + cursorShape: Qt.PointingHandCursor + implicitHeight: contentRow.height + + GridLayout { + id: contentRow + + anchors.verticalCenter: parent.verticalCenter + columnSpacing: Constants.text_spacing + columns: 3 + rowSpacing: columnSpacing + rows: 2 + width: parent.width + + TintableIcon { + id: icon + + Layout.alignment: Qt.AlignVCenter + Layout.rightMargin: Constants.groupbox_spacing + sourceSize.height: Style.dimens.icon_size + tintColor: Style.text.subline.textColor + tintEnabled: true + } + LabeledText { + id: text + + Layout.fillWidth: true + activeFocusOnTab: false + bodyElide: Text.ElideRight + maximumBodyLineCount: 1 + + //: LABEL DESKTOP + text: name.length > 0 ? name : qsTr("See details under \"more...\"") + } + TintableIcon { + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + Layout.rowSpan: 2 + source: "qrc:///images/material_arrow_right.svg" + sourceSize.height: Style.dimens.icon_size + tintColor: Style.color.text + } + GText { + //: LABEL DESKTOP + Accessible.description: qsTr("Show more information about the service provider") + Layout.column: 1 + Layout.row: 1 + Layout.topMargin: Constants.component_spacing + activeFocusOnTab: true + font.pixelSize: plugin.scaleFactor * 24 + //: LABEL DESKTOP + text: qsTr("Details about the provider") + textStyle: Style.text.subline + } + } + FocusFrame { + } +} diff --git a/resources/qml/Governikus/AuthView/+desktop/SelfAuthenticationData.qml b/resources/qml/Governikus/AuthView/+desktop/SelfAuthenticationData.qml index fef51023f..67b81598d 100644 --- a/resources/qml/Governikus/AuthView/+desktop/SelfAuthenticationData.qml +++ b/resources/qml/Governikus/AuthView/+desktop/SelfAuthenticationData.qml @@ -1,20 +1,23 @@ /** * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.AuthModel 1.0 -import Governikus.Type.SelfAuthModel 1.0 -import Governikus.Type.UiModule 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.TitleBar +import Governikus.View +import Governikus.Type.ApplicationModel +import Governikus.Type.AuthModel +import Governikus.Type.SelfAuthModel +import Governikus.Type.UiModule SectionPage { id: baseItem + + signal accept + titleBarAction: TitleBarAction { rootEnabled: false showHelp: false @@ -26,105 +29,92 @@ SectionPage { Keys.onEscapePressed: okButton.onClicked() Keys.onReturnPressed: okButton.onClicked() + Connections { + function onFireCancelWorkflow() { + if (SelfAuthModel.workflowCancelled) { + accept(); + } + } + + enabled: visible + target: SelfAuthModel + } ColumnLayout { anchors.fill: parent - anchors.margins: Constants.pane_padding + anchors.margins: Constants.pane_padding * 2 + spacing: Constants.component_spacing Row { id: statusRow - Layout.alignment: Qt.AlignHCenter + Layout.preferredHeight: baseItem.height / 4 spacing: Constants.component_spacing - StatusIcon { + TintableIcon { anchors.verticalCenter: parent.verticalCenter height: Style.dimens.status_icon_medium - source: "qrc:///images/status_ok.svg" + source: "qrc:///images/desktop/status_ok_%1.svg".arg(Style.currentTheme.name) + tintEnabled: false } GText { id: successText + Accessible.name: successText.text activeFocusOnTab: true anchors.verticalCenter: parent.verticalCenter //: INFO DESKTOP Status message that the self authentication successfully completed. text: qsTr("Successfully read data") - textStyle: Style.text.header + textStyle: Style.text.headline FocusFrame { } } } - Item { + ScrollablePane { + id: pane + Layout.fillHeight: true Layout.fillWidth: true + Layout.maximumHeight: implicitHeight + activeFocusOnTab: true + enableDropShadow: true - ScrollablePane { - id: pane - activeFocusOnTab: true - height: Math.min(parent.height, implicitHeight) - - //: LABEL DESKTOP Title of the self authentication result data view - title: qsTr("Read data") - width: parent.width - - Grid { - id: grid - columns: 3 - spacing: Constants.groupbox_spacing - verticalItemAlignment: Grid.AlignTop - width: parent.width - - Repeater { - id: dataRepeater - model: SelfAuthModel - - LabeledText { - label: name - text: value === "" ? "---" : value - width: (pane.width - 2 * Constants.pane_padding - (grid.columns - 1) * grid.spacing) / grid.columns - } - } - } - RowLayout { - anchors.right: parent.right - spacing: Constants.component_spacing - - GButton { - id: saveDataToPdfButton - icon.source: "qrc:///images/desktop/material_save.svg" - //: LABEL DESKTOP - text: qsTr("Save as PDF...") - tintIcon: true - - onClicked: { - let now = new Date().toLocaleDateString(Qt.locale(), "yyyy-MM-dd"); - let filenameSuggestion = "%1.%2.%3.pdf".arg(Qt.application.name).arg(qsTr("Information")).arg(now); - fileDialog.selectFile(filenameSuggestion); - } - - GFileDialog { - id: fileDialog - defaultSuffix: "pdf" - //: LABEL DESKTOP - nameFilters: qsTr("Portable Document Format (*.pdf)") - - //: LABEL DESKTOP - title: qsTr("Save read self-authentication data") - - onAccepted: SelfAuthModel.exportData(file) - } - } - GButton { - id: okButton + //: LABEL DESKTOP Title of the self authentication result data view + title: qsTr("Read data") + + Grid { + id: grid - //: LABEL DESKTOP - text: qsTr("OK") + columns: 3 + spacing: Constants.groupbox_spacing + verticalItemAlignment: Grid.AlignTop - onClicked: baseItem.nextView(UiModule.DEFAULT) + Repeater { + id: dataRepeater + + model: SelfAuthModel + + LabeledText { + label: name + text: value === "" ? "---" : value + width: (pane.width - 2 * Constants.pane_padding - (grid.columns - 1) * grid.spacing) / grid.columns } } } } + GButton { + id: okButton + + Layout.alignment: Qt.AlignHCenter + + //: LABEL DESKTOP + text: qsTr("OK") + + onClicked: baseItem.accept() + } + GSpacer { + Layout.fillHeight: true + } } } diff --git a/resources/qml/Governikus/AuthView/+mobile/+phone/DataGroup.qml b/resources/qml/Governikus/AuthView/+mobile/+phone/DataGroup.qml deleted file mode 100644 index 80e09e3f8..000000000 --- a/resources/qml/Governikus/AuthView/+mobile/+phone/DataGroup.qml +++ /dev/null @@ -1,89 +0,0 @@ -/** - * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 - -Column { - id: root - - property alias chat: repeater.model - readonly property alias count: repeater.count - property alias title: dataTitle.text - property alias titleStyle: dataTitle.textStyle - - signal scrollPageDown - signal scrollPageUp - - spacing: 0 - visible: count > 0 - - PaneTitle { - id: dataTitle - height: implicitHeight * 1.5 - verticalAlignment: Text.AlignTop - width: parent.width - } - Repeater { - id: repeater - Item { - Accessible.checkable: optional - Accessible.checked: checkBox.checked - Accessible.name: name - Accessible.role: Accessible.ListItem - height: 40 - width: parent.width - - Accessible.onPressAction: if (optional) - selected = !selected - Accessible.onScrollDownAction: baseItem.scrollPageDown() - Accessible.onScrollUpAction: baseItem.scrollPageUp() - - GText { - id: dataGroup - Accessible.ignored: true - anchors.left: parent.left - anchors.right: checkBox.left - anchors.verticalCenter: parent.verticalCenter - text: name - textStyle: writeRight ? Style.text.normal_warning : Style.text.normal_secondary - width: parent.width - } - GSeparator { - anchors.left: dataGroup.left - anchors.right: dataGroup.right - anchors.top: parent.bottom - anchors.topMargin: -height - visible: index < repeater.count - 1 - } - GCheckBox { - id: checkBox - Accessible.ignored: true - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - checked: selected - visible: optional - } - MouseArea { - anchors.fill: parent - enabled: optional - - onClicked: selected = !selected - - Rectangle { - anchors.fill: parent - color: Constants.grey - opacity: parent.pressed ? 0.5 : 0 - - Behavior on opacity { - NumberAnimation { - duration: 100 - } - } - } - } - } - } -} diff --git a/resources/qml/Governikus/AuthView/+mobile/+phone/EditRights.qml b/resources/qml/Governikus/AuthView/+mobile/+phone/EditRights.qml deleted file mode 100644 index 40cbf7922..000000000 --- a/resources/qml/Governikus/AuthView/+mobile/+phone/EditRights.qml +++ /dev/null @@ -1,221 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Provider 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 -import Governikus.Type.AuthModel 1.0 -import Governikus.Type.NumberModel 1.0 -import Governikus.Type.CertificateDescriptionModel 1.0 -import Governikus.Type.ChatModel 1.0 - -SectionPage { - id: baseItem - - property alias actionText: actionText.text - property alias dataText: dataPasswordText.text - property var workflowModel: AuthModel - - signal rightsAccepted - - //: LABEL IOS_PHONE ANDROID_PHONE - title: qsTr("Identify") - - content: Column { - padding: Constants.pane_padding - width: baseItem.width - - Column { - spacing: Constants.component_spacing - width: parent.width - 2 * Constants.pane_padding - - GText { - id: actionText - - //: LABEL IOS_PHONE ANDROID_PHONE - text: qsTr("You are about to identify yourself towards the following provider:") - textStyle: Style.text.normal_secondary - width: parent.width - } - GPane { - color: mouseArea.pressed ? Style.color.background_pane_active : Style.color.background_pane - - anchors { - left: parent.left - right: parent.right - } - Item { - Accessible.description: providerInfoSection.title + ". " + providerInfoSection.name + ". " + providerInfoAction.text - Accessible.role: Accessible.Button - height: providerEntries.height - width: parent.width - - Accessible.onPressAction: mouseArea.clicked(null) - - Column { - id: providerEntries - spacing: Constants.groupbox_spacing - - anchors { - left: parent.left - right: forwardAction.left - rightMargin: Constants.text_spacing - top: parent.top - } - ProviderInfoSection { - id: providerInfoSection - imageSource: "qrc:///images/provider/information.svg" - name: CertificateDescriptionModel.subjectName - //: LABEL IOS_PHONE ANDROID_PHONE - title: qsTr("Provider") - } - GText { - id: providerInfoAction - Accessible.ignored: true - - //: LABEL IOS_PHONE ANDROID_PHONE - text: qsTr("Touch for more details") - textStyle: Style.text.normal_accent - wrapMode: Text.WordWrap - - anchors { - left: parent.left - leftMargin: Style.dimens.icon_size + Constants.groupbox_spacing - right: parent.right - } - } - } - TintableIcon { - id: forwardAction - anchors.right: parent.right - anchors.verticalCenter: providerEntries.verticalCenter - source: "qrc:///images/mobile/material_arrow_right.svg" - sourceSize.height: Style.dimens.small_icon_size - tintColor: Style.color.secondary_text - } - MouseArea { - id: mouseArea - anchors.fill: parent - - onClicked: push(certificateDescriptionPage) - } - Component { - id: certificateDescriptionPage - CertificateDescriptionPage { - name: CertificateDescriptionModel.subjectName - } - } - } - } - GButton { - anchors.horizontalCenter: parent.horizontalCenter - icon.source: "qrc:///images/identify.svg" - //: LABEL IOS_PHONE ANDROID_PHONE %1 can be "CAN" or "PIN" - text: qsTr("Proceed to %1 entry").arg(NumberModel.isCanAllowedMode ? - //: LABEL IOS_PHONE Inserted into "Proceed to %1 entry" - qsTr("CAN") : - //: LABEL IOS_PHONE Inserted into "Proceed to %1 entry" - qsTr("PIN")) - tintIcon: true - - onClicked: rightsAccepted() - } - GText { - id: dataPasswordText - text: NumberModel.isCanAllowedMode ? - //: LABEL IOS_PHONE ANDROID_PHONE - qsTr("By entering the CAN, access to the following data of the ID card will be allowed to the mentioned provider:") : - //: LABEL IOS_PHONE ANDROID_PHONE - qsTr("By entering your PIN, access to the following data of your ID card will be allowed to the mentioned provider:") - textStyle: Style.text.normal_secondary - width: parent.width - } - GPane { - - //: LABEL IOS_PHONE ANDROID_PHONE - title: qsTr("Transactional information") - visible: !!workflowModel.transactionInfo || (!writeData.visible && !readData.visible) - - anchors { - left: parent.left - right: parent.right - } - GText { - activeFocusOnTab: true - text: workflowModel.transactionInfo - textStyle: Style.text.normal_secondary - visible: !!text - width: parent.width - } - GText { - activeFocusOnTab: true - - //: LABEL IOS_PHONE ANDROID_PHONE - text: qsTr("The provider mentioned above does not require any data stored on your ID card, only confirmation of you possessing a valid ID card.") - textStyle: Style.text.normal - visible: !writeData.visible && !readData.visible - width: parent.width - } - } - GPane { - visible: writeData.count > 0 - - anchors { - left: parent.left - right: parent.right - } - DataGroup { - id: writeData - chat: ChatModel.write - - //: LABEL IOS_PHONE ANDROID_PHONE - title: qsTr("Write access (update)") - titleStyle: Style.text.header_warning - width: parent.width - - onScrollPageDown: baseItem.scrollPageDown() - onScrollPageUp: baseItem.scrollPageUp() - } - } - GPane { - id: readData - visible: requiredData.count > 0 || optionalData.count > 0 - - anchors { - left: parent.left - right: parent.right - } - DataGroup { - id: requiredData - chat: ChatModel.required - - //: LABEL IOS_PHONE ANDROID_PHONE - title: qsTr("Read access") - width: parent.width - - onScrollPageDown: baseItem.scrollPageDown() - onScrollPageUp: baseItem.scrollPageUp() - } - DataGroup { - id: optionalData - chat: ChatModel.optional - - //: LABEL IOS_PHONE ANDROID_PHONE - title: qsTr("Read access (optional)") - width: parent.width - - onScrollPageDown: baseItem.scrollPageDown() - onScrollPageUp: baseItem.scrollPageUp() - } - } - } - } - navigationAction: NavigationAction { - action: NavigationAction.Action.Cancel - - onClicked: workflowModel.cancelWorkflow() - } -} diff --git a/resources/qml/Governikus/AuthView/+mobile/+tablet/EditRights.qml b/resources/qml/Governikus/AuthView/+mobile/+tablet/EditRights.qml deleted file mode 100644 index bbffaadbb..000000000 --- a/resources/qml/Governikus/AuthView/+mobile/+tablet/EditRights.qml +++ /dev/null @@ -1,213 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Provider 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 -import Governikus.Type.AuthModel 1.0 -import Governikus.Type.NumberModel 1.0 -import Governikus.Type.CertificateDescriptionModel 1.0 -import Governikus.Type.ChatModel 1.0 - -SectionPage { - id: baseItem - - property alias actionText: actionText.text - property alias dataText: dataPasswordText.text - property var workflowModel: AuthModel - - signal rightsAccepted - - //: LABEL ANDROID_TABLET IOS_TABLET - title: qsTr("Identify") - - content: Column { - padding: Constants.pane_padding - width: baseItem.width - - Column { - spacing: Constants.pane_spacing - width: parent.width - 2 * Constants.pane_padding - - GText { - id: actionText - - //: LABEL ANDROID_TABLET IOS_TABLET - text: qsTr("You are about to identify yourself towards the following provider:") - width: parent.width - } - GPane { - anchors { - left: parent.left - right: parent.right - } - ProviderInfoSection { - imageSource: "qrc:///images/provider/information.svg" - name: CertificateDescriptionModel.subjectName - //: LABEL ANDROID_TABLET IOS_TABLET - title: qsTr("Provider") - } - Item { - height: Math.max(detailsButton.height, confirmButton.height) - width: parent.width - - GButton { - id: detailsButton - Accessible.description: qsTr("Show more information about the service provider") - activeFocusOnTab: true - icon.source: "qrc:///images/info.svg" - - //: LABEL ANDROID_TABLET IOS_TABLET - text: qsTr("Details about the provider") - - onClicked: push(certificateDescriptionPage) - - anchors { - left: parent.left - verticalCenter: parent.verticalCenter - } - } - GButton { - id: confirmButton - icon.source: "qrc:///images/identify.svg" - - //: LABEL ANDROID_TABLET IOS_TABLET %1 can be "CAN" or "PIN" - text: qsTr("Proceed to %1 entry").arg(NumberModel.isCanAllowedMode ? - //: LABEL ANDROID_TABLET IOS_TABLET Inserted into "Proceed to %1 entry" - qsTr("CAN") : - //: LABEL ANDROID_TABLET IOS_TABLET Inserted into "Proceed to %1 entry" - qsTr("PIN")) - tintIcon: true - - onClicked: rightsAccepted() - - anchors { - right: parent.right - verticalCenter: parent.verticalCenter - } - } - Component { - id: certificateDescriptionPage - CertificateDescriptionPage { - name: CertificateDescriptionModel.subjectName - } - } - } - } - GText { - id: dataPasswordText - text: NumberModel.isCanAllowedMode ? - //: LABEL ANDROID_TABLET IOS_TABLET - qsTr("By entering the CAN, access to the following data of the ID card will be allowed to the mentioned provider:") : - //: LABEL ANDROID_TABLET IOS_TABLET - qsTr("By entering your PIN, access to the following data of your ID card will be allowed to the mentioned provider:") - width: parent.width - } - GPane { - - //: LABEL ANDROID_TABLET IOS_TABLET - title: qsTr("Transactional information") - visible: !!workflowModel.transactionInfo || (!writeDataPane.visible && !readDataPane.visible) - - anchors { - left: parent.left - right: parent.right - } - GText { - activeFocusOnTab: true - text: workflowModel.transactionInfo - textStyle: Style.text.normal_secondary - visible: !!text - width: parent.width - } - GText { - activeFocusOnTab: true - - //: LABEL ANDROID_TABLET IOS_TABLET - text: qsTr("The provider mentioned above does not require any data stored on your ID card, only confirmation of you possessing a valid ID card.") - textStyle: Style.text.normal - visible: !writeDataPane.visible && !readDataPane.visible - width: parent.width - } - } - Row { - id: requestedDataRow - - readonly property int columnWidth: (width - spacing) / maxColumns - readonly property int maxColumns: 3 - - height: Math.max(writeDataPane.implicitHeight, readDataPane.implicitHeight) - spacing: Constants.pane_spacing - - anchors { - left: parent.left - right: parent.right - } - GPane { - id: writeDataPane - height: parent.height - visible: writeData.count > 0 - width: readDataPane.visible ? requestedDataRow.columnWidth : parent.width - - DataGroup { - id: writeData - chat: ChatModel.write - columns: readDataPane.visible ? 1 : requestedDataRow.maxColumns - - //: LABEL ANDROID_TABLET IOS_TABLET - title: qsTr("Write access (update)") - titleStyle: Style.text.header_warning - width: parent.width - - onScrollPageDown: baseItem.scrollPageDown() - onScrollPageUp: baseItem.scrollPageUp() - } - } - GPane { - id: readDataPane - height: parent.height - visible: requiredData.count > 0 || optionalData.count > 0 - width: writeDataPane.visible ? requestedDataRow.columnWidth * 2 : parent.width - - Row { - spacing: Constants.pane_spacing - width: parent.width - - DataGroup { - id: requiredData - chat: ChatModel.required - columns: Math.max(1, requestedDataRow.maxColumns - (writeData.visible ? writeData.columns : 0) - (optionalData.visible ? 1 : 0) - (count > optionalData.count ? 0 : 1)) - - //: LABEL ANDROID_TABLET IOS_TABLET - title: qsTr("Read access") - width: optionalData.visible ? parent.width / 2 : parent.width - - onScrollPageDown: baseItem.scrollPageDown() - onScrollPageUp: baseItem.scrollPageUp() - } - DataGroup { - id: optionalData - chat: ChatModel.optional - columns: Math.max(1, requestedDataRow.maxColumns - (writeData.visible ? writeData.columns : 0) - (requiredData.visible ? requiredData.columns : 0)) - - //: LABEL ANDROID_TABLET IOS_TABLET - title: qsTr("Read access (optional)") - width: requiredData.visible ? parent.width / 2 : parent.width - - onScrollPageDown: baseItem.scrollPageDown() - onScrollPageUp: baseItem.scrollPageUp() - } - } - } - } - } - } - navigationAction: NavigationAction { - action: NavigationAction.Action.Cancel - - onClicked: workflowModel.cancelWorkflow() - } -} diff --git a/resources/qml/Governikus/AuthView/+mobile/AbortedProgressView.qml b/resources/qml/Governikus/AuthView/+mobile/AbortedProgressView.qml index 483e44da8..957ab9a59 100644 --- a/resources/qml/Governikus/AuthView/+mobile/AbortedProgressView.qml +++ b/resources/qml/Governikus/AuthView/+mobile/AbortedProgressView.qml @@ -1,26 +1,28 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.ProgressView 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.Type.ConnectivityManager 1.0 +import QtQuick +import Governikus.ProgressView +import Governikus.Style +import Governikus.TitleBar ProgressView { id: root + + required property bool networkInterfaceActive + signal cancel progressBarVisible: false subText: { - if (ConnectivityManager.networkInterfaceActive) { + if (networkInterfaceActive) { //: INFO DESKTOP Information message about cancellation process with present network connectivity return qsTr("Please wait a moment."); } //: INFO DESKTOP Information message about cancellation process without working network connectivity return qsTr("Network problems detected, trying to reach server within 30 seconds."); } - subTextColor: !ConnectivityManager.networkInterfaceActive ? Style.color.warning_text : Style.color.secondary_text + subTextColor: networkInterfaceActive ? Style.color.text : Style.color.text_warning //: INFO DESKTOP The user aborted the authentication process, according to TR we need to inform the service provider text: qsTr("Aborting process and informing the service provider") diff --git a/resources/qml/Governikus/AuthView/+mobile/AuthController.qml b/resources/qml/Governikus/AuthView/+mobile/AuthController.qml index dfde7af2c..3f1941952 100644 --- a/resources/qml/Governikus/AuthView/+mobile/AuthController.qml +++ b/resources/qml/Governikus/AuthView/+mobile/AuthController.qml @@ -1,21 +1,30 @@ /** * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.AuthModel 1.0 -import Governikus.Type.ChatModel 1.0 -import Governikus.Type.ConnectivityManager 1.0 -import Governikus.Type.NumberModel 1.0 -import Governikus.Type.PasswordType 1.0 -import Governikus.Type.ReaderPlugIn 1.0 -import Governikus.Type.SettingsModel 1.0 -import Governikus.Type.SurveyModel 1.0 -import Governikus.Type.UiModule 1.0 -import Governikus.View 1.0 +import QtQuick +import Governikus.EnterPasswordView +import Governikus.Global +import Governikus.Style +import Governikus.TitleBar +import Governikus.PasswordInfoView +import Governikus.ProgressView +import Governikus.ResultView +import Governikus.WhiteListClient +import Governikus.View +import Governikus.Workflow +import Governikus.Type.AuthModel +import Governikus.Type.ChatModel +import Governikus.Type.ConnectivityManager +import Governikus.Type.LogModel +import Governikus.Type.NumberModel +import Governikus.Type.PasswordType +import Governikus.Type.ReaderPlugIn +import Governikus.Type.SettingsModel +import Governikus.Type.SurveyModel Controller { - id: controller + id: rootController + enum WorkflowStates { Initial, Reader, @@ -26,22 +35,28 @@ Controller { Processing } + property bool autoInsertCard: false + property bool hideTechnologySwitch: false + property var initialPlugIn: null + readonly property bool isInitialState: workflowState === AuthController.WorkflowStates.Initial + readonly property bool isSmartWorkflow: AuthModel.readerPlugInType === ReaderPlugIn.SMART readonly property int passwordType: NumberModel.passwordType + readonly property bool smartEidUsed: isSmartWorkflow && !isInitialState + property string title property bool workflowProgressVisible: false property int workflowState: 0 - function processStateChange() { - switch (AuthModel.currentState) { - case "Initial": - popAll(); - break; + signal showChangePinView + signal workflowFinished + + function processStateChange(pState) { + switch (pState) { case "StateGetTcToken": - show(UiModule.IDENTIFY, true); - popAll(); - if (!ConnectivityManager.networkInterfaceActive) { - push(checkConnectivityView); - } else { + if (connectivityManager.networkInterfaceActive) { + push(progressView); setAuthWorkflowStateAndContinue(AuthController.WorkflowStates.Initial); + } else { + push(checkConnectivityView); } break; case "StatePreVerification": @@ -67,10 +82,6 @@ Controller { } setAuthWorkflowStateAndContinue(AuthController.WorkflowStates.Reader); break; - case "StatePreparePace": - popAll(); - setAuthWorkflowStateAndContinue(AuthController.WorkflowStates.Update); - break; case "StateEnterPacePassword": if (NumberModel.passwordType === PasswordType.PIN) { setAuthWorkflowStateAndRequestInput(AuthController.WorkflowStates.Pin); @@ -85,28 +96,30 @@ Controller { case "StateUnfortunateCardPosition": push(cardPositionView); break; + case "StateEstablishPaceChannel": + replace(progressView); + setAuthWorkflowStateAndContinue(AuthController.WorkflowStates.Update); + break; case "StateDidAuthenticateEac1": - controller.workflowProgressVisible = true; + rootController.workflowProgressVisible = true; setAuthWorkflowStateAndContinue(AuthController.WorkflowStates.Processing); break; case "StateSendDIDAuthenticateResponseEAC1": if (AuthModel.isCancellationByUser()) { replace(authAbortedProgressView); - } else { - popAll(); } AuthModel.continueWorkflow(); break; - case "StateWriteHistory": + case "StateActivateStoreFeedbackDialog": showRemoveCardFeedback(AuthModel, true); AuthModel.continueWorkflow(); break; case "StateShowResult": - push(selfAuthenticationData); + replace(selfAuthenticationData); break; case "StateSendWhitelistSurvey": if (SurveyModel.askForDeviceSurvey()) { - push(whiteListSurveyView); + replace(whiteListSurveyView); } else { AuthModel.continueWorkflow(); } @@ -114,57 +127,281 @@ Controller { case "FinalState": if (AuthModel.showChangePinView) { AuthModel.continueWorkflow(); - popAll(); - navBar.show(UiModule.PINMANAGEMENT); + showChangePinView(); } else if (AuthModel.error && !AuthModel.hasNextWorkflowPending && !AuthModel.shouldSkipResultView()) { showRemoveCardFeedback(AuthModel, false); - push(authResult); + replace(authResult); } else { AuthModel.continueWorkflow(); - popAll(); - if (ApplicationModel.currentWorkflow === ApplicationModel.WORKFLOW_AUTHENTICATION) { - show(UiModule.DEFAULT); - } else { - show(UiModule.SELF_AUTHENTICATION); - } } - controller.workflowProgressVisible = false; + rootController.workflowProgressVisible = false; break; default: AuthModel.continueWorkflow(); } } function setAuthWorkflowStateAndContinue(pState) { - controller.workflowState = pState; + rootController.workflowState = pState; AuthModel.continueWorkflow(); } function setAuthWorkflowStateAndRequestInput(pState) { - controller.workflowState = pState; + rootController.workflowState = pState; if (AuthModel.isBasicReader) { - push(enterPinView); + replace(enterPinView, { + "passwordType": NumberModel.passwordType, + "inputError": NumberModel.inputError + }); } else { AuthModel.continueWorkflow(); } } - Component.onCompleted: if (AuthModel.currentState === "StateProcessing") - processStateChange() - Connections { - // This is necessary because onCurrentStateChanged is not - // working, when we need to process a state a second time - function onFireCurrentStateChanged() { - processStateChange(); + function onFireStateEntered(pState) { + processStateChange(pState); + } + function onFireWorkflowFinished() { + rootController.workflowFinished(); } target: AuthModel } - Connections { - function onFireNetworkInterfaceActiveChanged() { - processStateChange(); + ConnectivityManager { + id: connectivityManager + + watching: true + + onNetworkInterfaceActiveChanged: { + if (AuthModel.currentState === "StateGetTcToken") + processStateChange(AuthModel.currentState); + } + } + Component { + id: progressView + + ProgressView { + progressBarVisible: workflowProgressVisible + progressText: AuthModel.progressMessage + progressValue: AuthModel.progressValue + smartEidUsed: rootController.smartEidUsed + subText: { + //: INFO ANDROID IOS Generic status message during the authentication process. + if (isInitialState || AuthModel.error || isSmartWorkflow) { + return qsTr("Please wait a moment."); + } + if (AuthModel.isBasicReader) { + //: INFO ANDROID IOS Second line text if a basic card reader is used and background communication with the card/server is running. Is not actually visible since the basic reader password handling is done by EnterPasswordView. + return qsTr("Please do not move the ID card."); + } + if (!!NumberModel.inputError) { + return NumberModel.inputError; + } + if (rootController.workflowState === AuthController.WorkflowStates.Update || rootController.workflowState === AuthController.WorkflowStates.Pin) { + //: INFO ANDROID IOS The card reader requests the user's attention. + return qsTr("Please observe the display of your card reader."); + } + if (rootController.workflowState === AuthController.WorkflowStates.Can) { + //: INFO ANDROID IOS The PIN was entered wrongfully two times, the third attempts requires additional CAN verification, hint where the CAN is found. + return qsTr("A wrong PIN has been entered twice on your ID card. For a third attempt, please first enter the six-digit Card Access Number (CAN). You can find your CAN in the bottom right on the front of your ID card."); + } + + //: INFO ANDROID IOS Generic status message during the authentication process. + return qsTr("Please wait a moment."); + } + subTextColor: !AuthModel.isBasicReader && (NumberModel.inputError || workflowState === AuthController.WorkflowStates.Can) ? Style.color.text_warning : Style.color.text + //: LABEL ANDROID IOS + text: (AuthModel.error ? qsTr("Cancel authentication process") : + //: INFO ANDROID IOS Header of the progress status message during the authentication process. + isInitialState ? qsTr("Acquiring provider certificate") : + //: INFO ANDROID IOS Header of the progress status message during the authentication process. + qsTr("Authentication in progress")) + //: LABEL ANDROID IOS + title: qsTr("Identify") + + navigationAction: NavigationAction { + action: AuthModel.isBasicReader || workflowProgressVisible ? NavigationAction.Action.Cancel : NavigationAction.Action.None + + onClicked: AuthModel.cancelWorkflow() + } + } + } + Component { + id: editRights + + EditRights { + title: rootController.title + + onRightsAccepted: { + ChatModel.transferAccessRights(); + AuthModel.continueWorkflow(); + } + } + } + Component { + id: selfAuthenticationData + + SelfAuthenticationData { + smartEidUsed: rootController.smartEidUsed + + onDone: { + AuthModel.continueWorkflow(); + } + } + } + Component { + id: whiteListSurveyView + + WhiteListSurveyView { + smartEidUsed: rootController.smartEidUsed + + onDone: pUserAccepted => { + SurveyModel.setDeviceSurveyPending(pUserAccepted); + AuthModel.continueWorkflow(); + } + } + } + Component { + id: authWorkflow + + GeneralWorkflow { + autoInsertCard: rootController.autoInsertCard + hideSwitch: rootController.hideTechnologySwitch + initialPlugIn: rootController.initialPlugIn + smartEidUsed: rootController.smartEidUsed + workflowModel: AuthModel + workflowTitle: rootController.title + } + } + Component { + id: transportPinReminder + + TransportPinReminderView { + moreInformationText: transportPinReminderInfoData.linkText + title: rootController.title + + onCancel: AuthModel.cancelWorkflow() + onPinKnown: { + pop(); + AuthModel.continueWorkflow(); + } + onPinUnknown: { + pop(); + AuthModel.cancelWorkflowToChangePin(); + } + onShowInfoView: { + push(transportPinReminderInfoView); + } + } + } + PasswordInfoData { + id: transportPinReminderInfoData + + contentType: PasswordInfoContent.Type.CHANGE_PIN + } + Component { + id: transportPinReminderInfoView + + PasswordInfoView { + infoContent: transportPinReminderInfoData + + onClose: pop() } + } + PasswordInfoData { + id: infoData + + contentType: fromPasswordType(NumberModel.passwordType, NumberModel.isCanAllowedMode) + } + Component { + id: passwordInfoView + + PasswordInfoView { + infoContent: infoData + smartEidUsed: rootController.smartEidUsed - enabled: AuthModel.currentState === "StateGetTcToken" - target: ConnectivityManager + onAbortCurrentWorkflow: AuthModel.cancelWorkflow() + onClose: pop() + } + } + Component { + id: enterPinView + + EnterPasswordView { + //: LABEL ANDROID IOS A11y button to confirm the PIN and start the provider authentication + accessibleContinueText: passwordType === PasswordType.PIN || passwordType === PasswordType.SMART_PIN || (passwordType === PasswordType.CAN && NumberModel.isCanAllowedMode) ? qsTr("Authenticate with provider") : undefined + moreInformationText: infoData.linkText + smartEidUsed: rootController.smartEidUsed + title: rootController.title + + navigationAction: NavigationAction { + action: NavigationAction.Action.Cancel + + onClicked: { + AuthModel.cancelWorkflow(); + } + } + + onPasswordEntered: { + AuthModel.continueWorkflow(); + } + onRequestPasswordInfo: push(passwordInfoView) + } + } + Component { + id: authAbortedProgressView + + AbortedProgressView { + networkInterfaceActive: connectivityManager.networkInterfaceActive + smartEidUsed: rootController.smartEidUsed + title: rootController.title + + onCancel: AuthModel.cancelWorkflow() + } + } + Component { + id: checkConnectivityView + + CheckConnectivityView { + title: rootController.title + + onCancel: AuthModel.cancelWorkflow() + } + } + Component { + id: cardPositionView + + CardPositionView { + title: rootController.title + + onCancelClicked: AuthModel.cancelWorkflow() + onContinueClicked: { + pop(); + AuthModel.continueWorkflow(); + } + } + } + Component { + id: authResult + + ResultErrorView { + errorCode: AuthModel.statusCodeString + errorDescription: AuthModel.errorText + header: AuthModel.errorHeader + hintButtonText: AuthModel.statusHintActionText + hintText: AuthModel.statusHintText + icon: AuthModel.statusCodeImage.arg(Style.currentTheme.name) + //: LABEL ANDROID IOS + mailButtonText: AuthModel.errorIsMasked ? qsTr("Send log") : "" + smartEidUsed: rootController.smartEidUsed + text: AuthModel.resultString + title: rootController.title + + onContinueClicked: AuthModel.continueWorkflow() + onHintClicked: { + AuthModel.continueWorkflow(); + AuthModel.invokeStatusHintAction(); + } + onMailClicked: LogModel.mailLog("support@ausweisapp.de", AuthModel.getEmailHeader(), AuthModel.getEmailBody()) + } } } diff --git a/resources/qml/Governikus/AuthView/+mobile/AuthView.qml b/resources/qml/Governikus/AuthView/+mobile/AuthView.qml index 89346e3d6..889292aa6 100644 --- a/resources/qml/Governikus/AuthView/+mobile/AuthView.qml +++ b/resources/qml/Governikus/AuthView/+mobile/AuthView.qml @@ -1,255 +1,52 @@ /** * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.EnterPasswordView 1.0 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.PasswordInfoView 1.0 -import Governikus.ProgressView 1.0 -import Governikus.ResultView 1.0 -import Governikus.WhiteListClient 1.0 -import Governikus.View 1.0 -import Governikus.Workflow 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.AuthModel 1.0 -import Governikus.Type.ChatModel 1.0 -import Governikus.Type.LogModel 1.0 -import Governikus.Type.NumberModel 1.0 -import Governikus.Type.PasswordType 1.0 -import Governikus.Type.ReaderPlugIn 1.0 -import Governikus.Type.SurveyModel 1.0 -import Governikus.Type.UiModule 1.0 +import QtQuick +import Governikus.View +import Governikus.Type.AuthModel -ProgressView { +SectionPage { id: root - readonly property bool isInitialState: authController.workflowState === AuthController.WorkflowStates.Initial - readonly property bool isSmartWorkflow: AuthModel.readerPlugInType === ReaderPlugIn.SMART + property bool autoInsertCard: false + property bool hideTechnologySwitch: false + property var initialPlugIn: null - progressBarVisible: authController.workflowProgressVisible - progressText: AuthModel.progressMessage - progressValue: AuthModel.progressValue - subText: { - if (!visible) { - return ""; - } - //: INFO ANDROID IOS Generic status message during the authentication process. - if (isInitialState || AuthModel.error || isSmartWorkflow) { - return qsTr("Please wait a moment."); - } - if (AuthModel.isBasicReader) { - //: INFO ANDROID IOS Second line text if a basic card reader is used and background communication with the card/server is running. Is not actually visible since the basic reader password handling is done by EnterPasswordView. - return qsTr("Please do not move the ID card."); - } - if (!!NumberModel.inputError) { - return NumberModel.inputError; - } - if (authController.workflowState === AuthController.WorkflowStates.Update || authController.workflowState === AuthController.WorkflowStates.Pin) { - //: INFO ANDROID IOS The card reader requests the user's attention. - return qsTr("Please observe the display of your card reader."); - } - if (authController.workflowState === AuthController.WorkflowStates.Can) { - //: INFO ANDROID IOS The PIN was entered wrongfully two times, the third attempts requires additional CAN verification, hint where the CAN is found. - return qsTr("A wrong PIN has been entered twice on your ID card. For a third attempt, please first enter the six-digit Card Access Number (CAN). You can find your CAN in the bottom right on the front of your ID card."); - } - - //: INFO ANDROID IOS Generic status message during the authentication process. - return qsTr("Please wait a moment."); - } - subTextColor: !AuthModel.isBasicReader && (NumberModel.inputError || authController.workflowState === AuthController.WorkflowStates.Can) ? Style.color.warning_text : Style.color.secondary_text + signal showChangePinView + signal workflowFinished - //: LABEL ANDROID IOS - text: (AuthModel.error ? qsTr("Cancel authentication process") : - //: INFO ANDROID IOS Header of the progress status message during the authentication process. - isInitialState ? qsTr("Acquiring provider certificate") : - //: INFO ANDROID IOS Header of the progress status message during the authentication process. - qsTr("Authentication in progress")) //: LABEL ANDROID IOS title: qsTr("Identify") - titleBarColor: isSmartWorkflow && !isInitialState ? Style.color.accent_smart : Style.color.accent - - navigationAction: NavigationAction { - action: AuthModel.isBasicReader || authController.workflowProgressVisible ? NavigationAction.Action.Cancel : NavigationAction.Action.None - - onClicked: AuthModel.cancelWorkflow() - } - - AuthController { - id: authController - } - Component { - id: editRights - EditRights { - onRightsAccepted: { - ChatModel.transferAccessRights(); - AuthModel.continueWorkflow(); - } - } - } - Component { - id: selfAuthenticationData - SelfAuthenticationData { - titleBarColor: root.titleBarColor - onDone: { - pop(); - AuthModel.continueWorkflow(); - } + Connections { + function onFireWorkflowStarted() { + authController.createObject(root); + setLockedAndHidden(true); } - } - Component { - id: whiteListSurveyView - WhiteListSurveyView { - titleBarColor: root.titleBarColor - onDone: pUserAccepted => { - SurveyModel.setDeviceSurveyPending(pUserAccepted); - pop(); - AuthModel.continueWorkflow(); - } - } - } - Component { - id: authWorkflow - GeneralWorkflow { - titleBarColor: root.titleBarColor - workflowModel: AuthModel - workflowTitle: root.title - } + enabled: visible + target: AuthModel } Component { - id: transportPinReminder - TransportPinReminderView { - moreInformationText: transportPinReminderInfoData.linkText - title: root.title - - onCancel: AuthModel.cancelWorkflow() - onPinKnown: { - pop(); - AuthModel.continueWorkflow(); - } - onPinUnknown: { - pop(); - AuthModel.cancelWorkflowToChangePin(); - } - onShowInfoView: { - push(transportPinReminderInfoView); - } - } - } - PasswordInfoData { - id: transportPinReminderInfoData - contentType: PasswordInfoContent.Type.CHANGE_PIN - } - Component { - id: transportPinReminderInfoView - PasswordInfoView { - infoContent: transportPinReminderInfoData - - onClose: pop() - } - } - PasswordInfoData { - id: infoData - contentType: fromPasswordType(NumberModel.passwordType, NumberModel.isCanAllowedMode) - } - Component { - id: passwordInfoView - PasswordInfoView { - infoContent: infoData - - onAbortCurrentWorkflow: AuthModel.cancelWorkflow() - onClose: pop() - } - } - Component { - id: enterPinView - EnterPasswordView { - //: LABEL ANDROID IOS A11y button to confirm the PIN and start the provider authentication - accessibleContinueText: passwordType === PasswordType.PIN || passwordType === PasswordType.SMART_PIN || (passwordType === PasswordType.CAN && NumberModel.isCanAllowedMode) ? qsTr("Authenticate with provider") : "" - moreInformationText: infoData.linkText - title: root.title - titleBarColor: root.titleBarColor - - navigationAction: NavigationAction { - action: NavigationAction.Action.Cancel - - onClicked: { - pop(); - AuthModel.cancelWorkflow(); - } - } - - onPasswordEntered: { - pop(); - AuthModel.continueWorkflow(); - } - onRequestPasswordInfo: push(passwordInfoView) - } - } - Component { - id: authAbortedProgressView - AbortedProgressView { - titleBarColor: root.titleBarColor - - onCancel: AuthModel.cancelWorkflow() - } - } - Component { - id: checkConnectivityView - CheckConnectivityView { - title: root.title - - onCancel: AuthModel.cancelWorkflow() - } - } - Component { - id: cardPositionView - CardPositionView { - title: root.title - - onCancelClicked: AuthModel.cancelWorkflow() - onContinueClicked: { - pop(); - AuthModel.continueWorkflow(); - } - } - } - Component { - id: authResult - ResultErrorView { - property bool skipShowAfterContinue: true + id: authController - errorCode: AuthModel.statusCodeString - errorDescription: AuthModel.errorText - header: AuthModel.errorHeader - hintButtonText: AuthModel.statusHintActionText - hintText: AuthModel.statusHintText - //: LABEL ANDROID IOS - mailButtonText: AuthModel.errorIsMasked ? qsTr("Send log") : "" - resultType: AuthModel.resultString ? ResultView.Type.IsError : ResultView.Type.IsSuccess - text: AuthModel.resultString + AuthController { + autoInsertCard: root.autoInsertCard + hideTechnologySwitch: root.hideTechnologySwitch + initialPlugIn: root.initialPlugIn + stackView: root.stackView title: root.title - titleBarColor: root.titleBarColor - Component.onDestruction: { - if (skipShowAfterContinue) - return; - if (ApplicationModel.currentWorkflow === ApplicationModel.WORKFLOW_AUTHENTICATION) { - show(UiModule.DEFAULT); - } else { - show(UiModule.SELF_AUTHENTICATION); - } + onShowChangePinView: { + setLockedAndHidden(false); + root.showChangePinView(); + this.destroy(); } - onContinueClicked: { - AuthModel.continueWorkflow(); - popAll(); - skipShowAfterContinue = false; + onWorkflowFinished: { + setLockedAndHidden(false); + root.workflowFinished(); + this.destroy(); } - onHintClicked: AuthModel.invokeStatusHintAction() - onMailClicked: LogModel.mailLog("support@ausweisapp.de", AuthModel.getEmailHeader(), AuthModel.getEmailBody()) } } } diff --git a/resources/qml/Governikus/AuthView/+mobile/CardPositionView.qml b/resources/qml/Governikus/AuthView/+mobile/CardPositionView.qml index 80dfbd517..9a27ce3fa 100644 --- a/resources/qml/Governikus/AuthView/+mobile/CardPositionView.qml +++ b/resources/qml/Governikus/AuthView/+mobile/CardPositionView.qml @@ -1,14 +1,16 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.ResultView 1.0 +import QtQuick +import Governikus.ResultView +import Governikus.Style ResultView { id: root + //: LABEL ANDROID IOS buttonText: qsTr("Retry") - resultType: ResultView.Type.IsInfo + icon: "qrc:///images/workflow_error_nfc_%1.svg".arg(Style.currentTheme.name) //: INFO ANDROID IOS The NFC signal is weak, by repositioning the card the signal might improve. text: qsTr("Weak NFC signal. Please\n- change the card position\n- remove the mobile phone case (if present)\n- connect the smartphone with a charging cable") } diff --git a/resources/qml/Governikus/AuthView/+mobile/CertificateDescriptionPage.qml b/resources/qml/Governikus/AuthView/+mobile/CertificateDescriptionPage.qml index 72473ceaf..53cea1de1 100644 --- a/resources/qml/Governikus/AuthView/+mobile/CertificateDescriptionPage.qml +++ b/resources/qml/Governikus/AuthView/+mobile/CertificateDescriptionPage.qml @@ -1,54 +1,41 @@ /** * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 -import Governikus.Type.CertificateDescriptionModel 1.0 - -SectionPage { +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.TitleBar +import Governikus.View +import Governikus.Type.CertificateDescriptionModel + +FlickableSectionPage { id: root - property string name - - title: name - - content: Item { - height: pane.height + 2 * Constants.component_spacing - width: root.width - - Column { - anchors.fill: parent - anchors.margins: Constants.component_spacing - - GPane { - id: pane - //: LABEL ANDROID IOS - title: qsTr("Provider Information") - - anchors { - left: parent.left - right: parent.right - } - Repeater { - id: listView - model: CertificateDescriptionModel + spacing: Constants.pane_padding - LabeledText { - id: delegate - label: model.label - text: model.text - textFormat: Text.PlainText - width: parent.width - } - } - } - } - } navigationAction: NavigationAction { action: NavigationAction.Action.Back onClicked: pop() } + + PaneTitle { + Layout.alignment: Qt.AlignHCenter + Layout.leftMargin: Constants.pane_padding + Layout.rightMargin: Constants.pane_padding + //: LABEL ANDROID IOS + text: qsTr("Provider Information") + } + Repeater { + model: CertificateDescriptionModel + + LabeledText { + Layout.fillWidth: true + Layout.leftMargin: Constants.pane_padding + Layout.rightMargin: Constants.pane_padding + label: model.label + text: model.text + textFormat: Text.PlainText + } + } } diff --git a/resources/qml/Governikus/AuthView/+mobile/CheckConnectivityView.qml b/resources/qml/Governikus/AuthView/+mobile/CheckConnectivityView.qml index eda1044d8..12884d2de 100644 --- a/resources/qml/Governikus/AuthView/+mobile/CheckConnectivityView.qml +++ b/resources/qml/Governikus/AuthView/+mobile/CheckConnectivityView.qml @@ -1,18 +1,20 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.ProgressView 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 +import QtQuick +import Governikus.ProgressView +import Governikus.Style +import Governikus.TitleBar ProgressView { id: root + signal cancel + icon: "qrc:///images/mobile/no_internet_%1.svg".arg(Style.currentTheme.name) //: INFO ANDROID IOS No network connection, the user needs to active the network interface or abort the procedure. subText: qsTr("Please establish an internet connection.") - subTextColor: Style.color.warning_text + subTextColor: Style.color.text_warning //: LABEL ANDROID IOS text: qsTr("No network connectivity") diff --git a/resources/qml/Governikus/AuthView/+mobile/+tablet/DataGroup.qml b/resources/qml/Governikus/AuthView/+mobile/DataGroup.qml similarity index 87% rename from resources/qml/Governikus/AuthView/+mobile/+tablet/DataGroup.qml rename to resources/qml/Governikus/AuthView/+mobile/DataGroup.qml index f3a70d5d3..24d724dc8 100644 --- a/resources/qml/Governikus/AuthView/+mobile/+tablet/DataGroup.qml +++ b/resources/qml/Governikus/AuthView/+mobile/DataGroup.qml @@ -1,10 +1,10 @@ /** * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import QtQuick.Controls +import Governikus.Global +import Governikus.Style Item { id: root @@ -14,6 +14,7 @@ Item { readonly property alias count: repeater.count property alias title: dataTitle.text property alias titleStyle: dataTitle.textStyle + property bool writeAccess: false signal scrollPageDown signal scrollPageUp @@ -24,18 +25,22 @@ Item { Column { id: column + anchors.left: parent.left anchors.right: parent.right anchors.top: parent.top PaneTitle { id: dataTitle + + color: writeAccess ? Style.color.text_warning : titleStyle.textColor height: implicitHeight * 1.5 verticalAlignment: Text.AlignTop width: parent.width } Grid { id: grid + columnSpacing: Constants.pane_spacing columns: root.columns flow: Grid.TopToBottom @@ -44,6 +49,7 @@ Item { Repeater { id: repeater + model: chat visible: repeater.count > 0 @@ -52,7 +58,7 @@ Item { Accessible.checked: checkBox.checked Accessible.name: name Accessible.role: Accessible.ListItem - height: 40 + height: text.implicitHeight + 2 * Constants.text_spacing width: (grid.width - ((grid.columns - 1) * grid.columnSpacing)) / grid.columns Accessible.onPressAction: if (optional) @@ -62,12 +68,13 @@ Item { GText { id: text + Accessible.ignored: true anchors.left: parent.left anchors.right: checkBox.left anchors.verticalCenter: parent.verticalCenter text: name - textStyle: writeRight ? Style.text.normal_warning : Style.text.normal_secondary + textStyle: writeRight ? Style.text.normal_warning : Style.text.normal } GSeparator { anchors.top: parent.bottom @@ -77,6 +84,7 @@ Item { } GCheckBox { id: checkBox + Accessible.ignored: true anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter @@ -91,12 +99,12 @@ Item { Rectangle { anchors.centerIn: parent - color: Style.color.accent + color: Style.color.control height: parent.height opacity: parent.pressed ? 0.5 : 0 width: root.width - Behavior on opacity { + Behavior on opacity { NumberAnimation { duration: 100 } diff --git a/resources/qml/Governikus/AuthView/+mobile/EditRights.qml b/resources/qml/Governikus/AuthView/+mobile/EditRights.qml new file mode 100644 index 000000000..c8e05f8d3 --- /dev/null +++ b/resources/qml/Governikus/AuthView/+mobile/EditRights.qml @@ -0,0 +1,213 @@ +/** + * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.TitleBar +import Governikus.View +import Governikus.Type.AuthModel +import Governikus.Type.NumberModel +import Governikus.Type.CertificateDescriptionModel +import Governikus.Type.ChatModel + +FlickableSectionPage { + id: baseItem + + property alias actionText: actionText.text + property alias dataText: dataPasswordText.text + property var workflowModel: AuthModel + + signal rightsAccepted + + spacing: Constants.component_spacing + + //: LABEL IOS_PHONE ANDROID_PHONE + title: qsTr("Identify") + + navigationAction: NavigationAction { + action: NavigationAction.Action.Cancel + + onClicked: workflowModel.cancelWorkflow() + } + + GText { + id: actionText + + //: LABEL IOS_PHONE ANDROID_PHONE + text: qsTr("You are about to identify yourself towards the following provider:") + } + GPane { + Layout.fillWidth: true + color: mouseArea.pressed ? Style.color.pane_active : Style.color.pane + + Item { + Accessible.description: providerInfoSection.title + ". " + providerInfoSection.name + ". " + providerInfoAction.text + Accessible.role: Accessible.Button + height: providerEntries.height + width: parent.width + + Accessible.onPressAction: mouseArea.clicked(null) + + Column { + id: providerEntries + + spacing: Constants.groupbox_spacing + + anchors { + left: parent.left + right: forwardAction.left + rightMargin: Constants.text_spacing + top: parent.top + } + ProviderInfoSection { + id: providerInfoSection + + imageSource: "qrc:///images/info.svg" + name: CertificateDescriptionModel.subjectName + //: LABEL IOS_PHONE ANDROID_PHONE + title: qsTr("Provider") + } + GText { + id: providerInfoAction + + Accessible.ignored: true + + //: LABEL IOS_PHONE ANDROID_PHONE + text: qsTr("Touch for more details") + wrapMode: Text.WordWrap + + anchors { + left: parent.left + leftMargin: Style.dimens.small_icon_size + Constants.groupbox_spacing + right: parent.right + } + } + } + TintableIcon { + id: forwardAction + + anchors.right: parent.right + anchors.verticalCenter: providerEntries.verticalCenter + source: "qrc:///images/material_arrow_right.svg" + sourceSize.height: Style.dimens.small_icon_size + tintColor: Style.color.text + } + MouseArea { + id: mouseArea + + anchors.fill: parent + + onClicked: push(certificateDescriptionPage) + } + Component { + id: certificateDescriptionPage + + CertificateDescriptionPage { + title: baseItem.title + } + } + } + } + GButton { + Layout.alignment: Qt.AlignHCenter + icon.source: "qrc:///images/identify.svg" + //: LABEL IOS_PHONE ANDROID_PHONE %1 can be "CAN" or "PIN" + text: qsTr("Proceed to %1 entry").arg(NumberModel.isCanAllowedMode ? + //: LABEL IOS_PHONE Inserted into "Proceed to %1 entry" + qsTr("CAN") : + //: LABEL IOS_PHONE Inserted into "Proceed to %1 entry" + qsTr("PIN")) + tintIcon: true + + onClicked: rightsAccepted() + } + GText { + id: dataPasswordText + + horizontalAlignment: Text.AlignHCenter + text: NumberModel.isCanAllowedMode ? + //: LABEL IOS_PHONE ANDROID_PHONE + qsTr("By entering the CAN, access to the following data of the ID card will be allowed to the mentioned provider:") : + //: LABEL IOS_PHONE ANDROID_PHONE + qsTr("By entering your PIN, access to the following data of your ID card will be allowed to the mentioned provider:") + } + GPane { + Layout.fillWidth: true + color: Style.color.pane_sublevel + drawShadow: false + //: LABEL IOS_PHONE ANDROID_PHONE + title: qsTr("Transactional information") + visible: !!workflowModel.transactionInfo || (!writeData.visible && !readData.visible) + + GText { + activeFocusOnTab: true + text: workflowModel.transactionInfo + visible: !!text + width: parent.width + } + GText { + activeFocusOnTab: true + + //: LABEL IOS_PHONE ANDROID_PHONE + text: qsTr("The provider mentioned above does not require any data stored on your ID card, only confirmation of you possessing a valid ID card.") + visible: !writeData.visible && !readData.visible + width: parent.width + } + } + GPane { + Layout.fillWidth: true + color: Style.color.pane_sublevel + drawShadow: false + visible: writeData.count > 0 + + DataGroup { + id: writeData + + chat: ChatModel.write + + //: LABEL IOS_PHONE ANDROID_PHONE + title: qsTr("Write access (update)") + titleStyle: Style.text.headline + width: parent.width + writeAccess: true + + onScrollPageDown: baseItem.scrollPageDown() + onScrollPageUp: baseItem.scrollPageUp() + } + } + GPane { + id: readData + + Layout.fillWidth: true + color: Style.color.pane_sublevel + drawShadow: false + visible: requiredData.count > 0 || optionalData.count > 0 + + DataGroup { + id: requiredData + + chat: ChatModel.required + + //: LABEL IOS_PHONE ANDROID_PHONE + title: qsTr("Read access") + width: parent.width + + onScrollPageDown: baseItem.scrollPageDown() + onScrollPageUp: baseItem.scrollPageUp() + } + DataGroup { + id: optionalData + + chat: ChatModel.optional + + //: LABEL IOS_PHONE ANDROID_PHONE + title: qsTr("Read access (optional)") + width: parent.width + + onScrollPageDown: baseItem.scrollPageDown() + onScrollPageUp: baseItem.scrollPageUp() + } + } +} diff --git a/resources/qml/Governikus/Provider/+mobile/ProviderInfoSection.qml b/resources/qml/Governikus/AuthView/+mobile/ProviderInfoSection.qml similarity index 76% rename from resources/qml/Governikus/Provider/+mobile/ProviderInfoSection.qml rename to resources/qml/Governikus/AuthView/+mobile/ProviderInfoSection.qml index 752b7b58e..c000e56ba 100644 --- a/resources/qml/Governikus/Provider/+mobile/ProviderInfoSection.qml +++ b/resources/qml/Governikus/AuthView/+mobile/ProviderInfoSection.qml @@ -1,9 +1,9 @@ /** * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import Governikus.Global +import Governikus.Style Item { property string imageSource @@ -14,17 +14,20 @@ Item { height: Math.max(image.height, providerTitle.height) width: parent.width - Image { + TintableIcon { id: image + anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter fillMode: Image.PreserveAspectFit - height: Style.dimens.icon_size + height: Style.dimens.small_icon_size source: imageSource - width: Style.dimens.icon_size + tintColor: Style.color.text_subline + width: Style.dimens.small_icon_size } LabeledText { id: providerTitle + Accessible.ignored: true anchors.left: image.right anchors.leftMargin: Constants.groupbox_spacing diff --git a/resources/qml/Governikus/AuthView/+mobile/SelfAuthenticationData.qml b/resources/qml/Governikus/AuthView/+mobile/SelfAuthenticationData.qml index 8b794e1db..bfac198b8 100644 --- a/resources/qml/Governikus/AuthView/+mobile/SelfAuthenticationData.qml +++ b/resources/qml/Governikus/AuthView/+mobile/SelfAuthenticationData.qml @@ -1,34 +1,40 @@ /** * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.ResultView 1.0 -import Governikus.Style 1.0 -import Governikus.View 1.0 -import Governikus.Type.SelfAuthModel 1.0 - -ResultView { +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.ResultView +import Governikus.Style +import Governikus.TitleBar +import Governikus.View +import Governikus.Type.SelfAuthModel + +FlickableSectionPage { id: root - signal done - header: qsTr("Read data") + signal done //: LABEL ANDROID IOS title: qsTr("Identify") - onCancelClicked: done() - onContinueClicked: done() + navigationAction: NavigationAction { + action: NavigationAction.Action.Cancel + + onClicked: done() + } GridLayout { id: grid + columnSpacing: Constants.text_spacing - columns: Constants.is_tablet ? 3 : 1 + columns: Math.max(1, (width + columnSpacing) / (repeater.maxItemWidth + columnSpacing)) rowSpacing: Constants.text_spacing width: parent.width - Repeater { + GRepeater { + id: repeater + model: SelfAuthModel LabeledText { @@ -41,4 +47,11 @@ ResultView { } } } + GButton { + Layout.alignment: Qt.AlignHCenter + //: LABEL ANDROID IOS + text: qsTr("OK") + + onClicked: done() + } } diff --git a/resources/qml/Governikus/AuthView/+mobile/TransportPinReminderView.qml b/resources/qml/Governikus/AuthView/+mobile/TransportPinReminderView.qml index 88badfe5b..3a477138f 100644 --- a/resources/qml/Governikus/AuthView/+mobile/TransportPinReminderView.qml +++ b/resources/qml/Governikus/AuthView/+mobile/TransportPinReminderView.qml @@ -1,14 +1,15 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 - -SectionPage { +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.TitleBar +import Governikus.View +import Governikus.Type.WorkflowModel + +FlickableSectionPage { id: root property alias moreInformationText: moreInformationLink.text @@ -18,74 +19,76 @@ SectionPage { signal pinUnknown signal showInfoView + margins: Constants.pane_padding * 2 + spacing: Constants.component_spacing + navigationAction: NavigationAction { action: NavigationAction.Action.Cancel onClicked: cancel() } - GFlickableColumnLayout { - id: layout - anchors.fill: parent + TintableIcon { + Layout.alignment: Qt.AlignHCenter + source: "qrc:///images/info.svg" + sourceSize.height: Style.dimens.header_icon_size + tintColor: Style.color.control + } + PaneTitle { + Layout.alignment: Qt.AlignHCenter + //: LABEL ANDROID IOS + text: qsTr("Do you know your six-digit ID card PIN?") + } + GText { + Layout.alignment: Qt.AlignHCenter + horizontalAlignment: Text.AlignHCenter + //: LABEL ANDROID IOS + text: qsTr("Online identification with Transport PIN is not possible. The self-selected, six-digit ID card PIN is mandatory to use the eID function.") + } + GText { + Layout.alignment: Qt.AlignHCenter + horizontalAlignment: Text.AlignHCenter + //: LABEL ANDROID IOS + text: qsTr("To set up a Smart-eID you also need to have assigned a six-digit PIN beforehand.") + visible: WorkflowModel.isSmartSupported + } + MoreInformationLink { + id: moreInformationLink + + Layout.alignment: Qt.AlignCenter + Layout.topMargin: Constants.component_spacing + + onClicked: root.showInfoView() + } + GSpacer { + Layout.fillHeight: true + } + RowLayout { + Layout.alignment: Qt.AlignHCenter + Layout.fillWidth: true spacing: Constants.component_spacing - StatusIcon { - Layout.alignment: Qt.AlignHCenter - Layout.preferredHeight: Style.dimens.header_icon_size - Layout.preferredWidth: Style.dimens.header_icon_size - source: "qrc:///images/status_info.svg" - } - GPane { - Layout.alignment: Qt.AlignHCenter + GButton { + Layout.alignment: Qt.AlignVCenter Layout.fillWidth: true - Layout.maximumWidth: Style.dimens.max_text_width + Layout.maximumWidth: Style.dimens.max_text_width / 2 + Layout.preferredWidth: Style.dimens.max_text_width / 2 //: LABEL ANDROID IOS - title: qsTr("Do you know your six-digit ID card PIN?") - - GText { + text: qsTr("No") - //: LABEL ANDROID IOS - text: qsTr("Online identification with Transport PIN is not possible. The self-selected, six-digit ID card PIN is mandatory to use the eID function.") - width: parent.width - } - } - MoreInformationLink { - id: moreInformationLink - Layout.alignment: Qt.AlignCenter - Layout.maximumWidth: layout.effectiveContentWidth - Layout.topMargin: Constants.component_spacing - - onClicked: root.showInfoView() - } - GSpacer { - Layout.fillHeight: true + onClicked: pinUnknown() } - RowLayout { - Layout.alignment: Qt.AlignHCenter + GButton { + Layout.alignment: Qt.AlignVCenter Layout.fillWidth: true - spacing: Constants.component_spacing + Layout.maximumWidth: Style.dimens.max_text_width / 2 + Layout.preferredWidth: Style.dimens.max_text_width / 2 - GButton { - Layout.alignment: Qt.AlignVCenter - Layout.fillWidth: true - Layout.maximumWidth: Style.dimens.max_text_width / 2 - - //: LABEL ANDROID IOS - text: qsTr("No") - - onClicked: pinUnknown() - } - GButton { - Layout.alignment: Qt.AlignVCenter - Layout.fillWidth: true - Layout.maximumWidth: Style.dimens.max_text_width / 2 - - //: LABEL ANDROID IOS - text: qsTr("Yes") + //: LABEL ANDROID IOS + text: qsTr("Yes") - onClicked: pinKnown() - } + onClicked: pinKnown() } } } diff --git a/resources/qml/Governikus/AuthView/qmldir b/resources/qml/Governikus/AuthView/qmldir index e34f5377e..73cf4f9dd 100644 --- a/resources/qml/Governikus/AuthView/qmldir +++ b/resources/qml/Governikus/AuthView/qmldir @@ -3,6 +3,7 @@ module AuthView internal AuthController AuthController.qml internal CertificateDescriptionPage CertificateDescriptionPage.qml internal DataGroup DataGroup.qml +internal ProviderInfoSection ProviderInfoSection.qml internal SelfAuthenticationData SelfAuthenticationData.qml AbortedProgressView 1.0 AbortedProgressView.qml diff --git a/resources/qml/Governikus/ChangePinView/+desktop/ChangePinController.qml b/resources/qml/Governikus/ChangePinView/+desktop/ChangePinController.qml index b06842c77..296bd0989 100644 --- a/resources/qml/Governikus/ChangePinView/+desktop/ChangePinController.qml +++ b/resources/qml/Governikus/ChangePinView/+desktop/ChangePinController.qml @@ -1,13 +1,14 @@ /** * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.View 1.0 -import Governikus.Type.ChangePinModel 1.0 -import Governikus.Type.NumberModel 1.0 +import QtQuick +import Governikus.View +import Governikus.Type.ChangePinModel +import Governikus.Type.NumberModel Controller { id: controller + enum WorkflowStates { Initial, Reader, @@ -18,11 +19,8 @@ Controller { property int workflowState: ChangePinController.WorkflowStates.Initial - function processStateChange() { - switch (ChangePinModel.currentState) { - case "Initial": - ChangePinModel.setInitialPluginType(); - break; + function processStateChange(pState) { + switch (pState) { case "StateSelectReader": controller.nextView(ChangePinView.SubViews.Workflow); setPinWorkflowStateAndContinue(ChangePinController.WorkflowStates.Reader); @@ -66,10 +64,11 @@ Controller { } Connections { - // This is necessary because onCurrentStateChanged is not - // working, when we need to process a state a second time. - function onFireCurrentStateChanged() { - processStateChange(); + function onFireStateEntered(pState) { + processStateChange(pState); + } + function onFireWorkflowStarted() { + ChangePinModel.setInitialPluginType(); } target: ChangePinModel diff --git a/resources/qml/Governikus/ChangePinView/+desktop/ChangePinView.qml b/resources/qml/Governikus/ChangePinView/+desktop/ChangePinView.qml index 82e33d540..3f8a35e1f 100644 --- a/resources/qml/Governikus/ChangePinView/+desktop/ChangePinView.qml +++ b/resources/qml/Governikus/ChangePinView/+desktop/ChangePinView.qml @@ -1,24 +1,26 @@ /** * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.EnterPasswordView 1.0 -import Governikus.Global 1.0 -import Governikus.TitleBar 1.0 -import Governikus.PasswordInfoView 1.0 -import Governikus.ProgressView 1.0 -import Governikus.ResultView 1.0 -import Governikus.SettingsView 1.0 -import Governikus.View 1.0 -import Governikus.Workflow 1.0 -import Governikus.Type.ChangePinModel 1.0 -import Governikus.Type.NumberModel 1.0 -import Governikus.Type.PasswordType 1.0 -import Governikus.Type.UiModule 1.0 +import QtQuick +import QtQuick.Controls +import Governikus.EnterPasswordView +import Governikus.Global +import Governikus.TitleBar +import Governikus.PasswordInfoView +import Governikus.ProgressView +import Governikus.ResultView +import Governikus.SettingsView +import Governikus.Style +import Governikus.View +import Governikus.Workflow +import Governikus.Type.ChangePinModel +import Governikus.Type.NumberModel +import Governikus.Type.PasswordType +import Governikus.Type.UiModule SectionPage { id: baseItem + enum SubViews { Start, Workflow, @@ -54,14 +56,13 @@ SectionPage { titleBarAction: TitleBarAction { customSettingsHandler: baseItem.showSettings - helpTopic: "pinManagement" rootEnabled: d.activeView === ChangePinView.SubViews.Start || d.activeView === ChangePinView.SubViews.NoPassword showSettings: changePinController.workflowState === ChangePinController.WorkflowStates.Reader //: LABEL DESKTOP text: qsTr("Change PIN") - customSubAction: CancelAction { - visible: d.cancelAllowed + customSubAction: NavigationAction { + enabled: d.cancelAllowed onClicked: { if (pinResult.visible) { @@ -89,6 +90,7 @@ SectionPage { readonly property int activeView: inputError.visible ? ChangePinView.SubViews.InputError : pinUnlocked.visible ? ChangePinView.SubViews.PinUnlocked : view readonly property bool cancelAllowed: view !== ChangePinView.SubViews.NoPassword && view !== ChangePinView.SubViews.Start && (ChangePinModel.isBasicReader || generalWorkflow.waitingFor !== Workflow.WaitingFor.Password) + property int enteredPasswordType: PasswordType.PIN readonly property int passwordType: NumberModel.passwordType property int precedingView: ChangePinView.SubViews.Start property var view: ChangePinView.SubViews.Start @@ -103,6 +105,7 @@ SectionPage { } ChangePinController { id: changePinController + onNextView: pName => { if (pName === ChangePinView.SubViews.ReturnToMain) { baseItem.nextView(UiModule.DEFAULT); @@ -118,12 +121,15 @@ SectionPage { anchors.fill: parent moreInformationText: infoData.linkText + onChangePin: ChangePinModel.startWorkflow(false) + onChangeTransportPin: ChangePinModel.startWorkflow(true) onMoreInformationRequested: baseItem.showPasswordInfo() onNoPinAvailable: d.view = ChangePinView.SubViews.NoPassword } } PasswordInfoView { id: noPasswordView + visible: d.activeView === ChangePinView.SubViews.NoPassword infoContent: PasswordInfoData { @@ -134,6 +140,7 @@ SectionPage { } GeneralWorkflow { id: generalWorkflow + isPinChange: true visible: d.activeView === ChangePinView.SubViews.Workflow waitingFor: switch (changePinController.workflowState) { @@ -156,7 +163,7 @@ SectionPage { property string deviceName - resultType: ResultView.Type.IsError + icon: "qrc:///images/workflow_error_no_sak_%1.svg".arg(Style.currentTheme.name) //: INFO DESKTOP The paired devices was removed since it did not respond to connection attempts. It needs to be paired again if it should be used as card reader. text: qsTr("The device \"%1\" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader.").arg(deviceName) visible: d.activeView === ChangePinView.SubViews.WorkflowError @@ -165,21 +172,38 @@ SectionPage { } EnterPasswordView { id: enterPasswordView + moreInformationText: infoData.linkText visible: d.activeView === ChangePinView.SubViews.Password - onPasswordEntered: pWasNewPin => { - d.view = pWasNewPin ? ChangePinView.SubViews.ProgressNewPin : ChangePinView.SubViews.Progress; - ChangePinModel.continueWorkflow(); + onPasswordEntered: pPasswordType => { + d.enteredPasswordType = pPasswordType; + switch (pPasswordType) { + case PasswordType.NEW_PIN: + case PasswordType.NEW_SMART_PIN: + break; + case PasswordType.NEW_PIN_CONFIRMATION: + case PasswordType.NEW_SMART_PIN_CONFIRMATION: + if (NumberModel.commitNewPin()) { + d.view = ChangePinView.SubViews.ProgressNewPin; + ChangePinModel.continueWorkflow(); + } + break; + default: + ChangePinModel.continueWorkflow(); + d.view = ChangePinView.SubViews.Progress; + } } onRequestPasswordInfo: baseItem.showPasswordInfo() } PasswordInfoData { id: infoData + contentType: changePinController.workflowState === ChangePinController.WorkflowStates.Initial ? PasswordInfoContent.Type.CHANGE_PIN : fromPasswordType(d.passwordType) } PasswordInfoView { id: passwordInfoView + infoContent: infoData visible: d.activeView === ChangePinView.SubViews.PasswordInfo @@ -191,6 +215,7 @@ SectionPage { } ProgressView { id: pinProgressView + //: INFO DESKTOP Processing screen text while the card communication is running after the PIN has been entered during PIN change process. subText: qsTr("Please do not move the ID card.") text: d.activeView === ChangePinView.SubViews.ProgressNewPin ? @@ -204,9 +229,23 @@ SectionPage { id: inputError property bool errorConfirmed: false - - resultType: ResultView.Type.IsError - text: NumberModel.inputError + //: INFO DESKTOP + readonly property string transportPinHint: qsTr("Please note that you may use the five-digit Transport PIN only once to change to a six-digit ID card PIN. If you already set a six-digit ID card PIN, the five-digit Transport PIN is no longer valid.") + + icon: switch (d.enteredPasswordType) { + case PasswordType.TRANSPORT_PIN: + return "qrc:///images/workflow_error_wrong_transportpin_%1.svg".arg(Style.currentTheme.name); + case PasswordType.SMART_PIN: + case PasswordType.PIN: + return "qrc:///images/workflow_error_wrong_pin_%1.svg".arg(Style.currentTheme.name); + case PasswordType.CAN: + return "qrc:///images/workflow_error_wrong_can_%1.svg".arg(Style.currentTheme.name); + case PasswordType.PUK: + return "qrc:///images/workflow_error_wrong_puk_%1.svg".arg(Style.currentTheme.name); + default: + return "qrc:///images/status_error_%1.svg".arg(Style.currentTheme.name); + } + text: NumberModel.inputError + (NumberModel.inputError !== "" && ChangePinModel.requestTransportPin ? "

%1".arg(transportPinHint) : "") visible: !errorConfirmed && NumberModel.hasPasswordError && d.view !== ChangePinView.SubViews.Result onNextView: errorConfirmed = true @@ -224,7 +263,7 @@ SectionPage { property bool confirmed: true - resultType: ResultView.Type.IsSuccess + animatedIcon: "qrc:///images/puk_%1.webp".arg(Style.currentTheme.name) //: INFO DESKTOP The ID card has just been unblocked and the user can now continue with their ID card PIN change. text: qsTr("Your ID card PIN is unblocked. You now have three more attempts to change your PIN.") visible: !confirmed && (d.view === ChangePinView.SubViews.Password || generalWorkflow.waitingFor === Workflow.WaitingFor.Password) @@ -241,7 +280,8 @@ SectionPage { } ResultView { id: cardPositionView - resultType: ResultView.Type.IsInfo + + icon: "qrc:///images/workflow_error_nfc_%1.svg".arg(Style.currentTheme.name) text: ChangePinModel.isRemoteReader ? //: INFO DESKTOP The NFC signal is weak or unstable, the user is asked to change the card's position to (hopefully) reduce the distance to the NFC chip. qsTr("Weak NFC signal. Please\n- change the card position\n- remove the mobile phone case (if present)\n- connect the smartphone with a charging cable") : @@ -253,10 +293,11 @@ SectionPage { } ResultView { id: pinResult + hintButtonText: ChangePinModel.statusHintActionText hintText: ChangePinModel.statusHintText + icon: ChangePinModel.error ? ChangePinModel.statusCodeImage.arg(Style.currentTheme.name) : "qrc:///images/workflow_success_changepin_%1.svg".arg(Style.currentTheme.name) mailButtonVisible: ChangePinModel.errorIsMasked - resultType: ChangePinModel.error ? ResultView.Type.IsError : ResultView.Type.IsSuccess text: ChangePinModel.resultString visible: d.activeView === ChangePinView.SubViews.Result diff --git a/resources/qml/Governikus/ChangePinView/+mobile/ChangePinController.qml b/resources/qml/Governikus/ChangePinView/+mobile/ChangePinController.qml index 28cb8697e..1376daea8 100644 --- a/resources/qml/Governikus/ChangePinView/+mobile/ChangePinController.qml +++ b/resources/qml/Governikus/ChangePinView/+mobile/ChangePinController.qml @@ -1,15 +1,26 @@ /** * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.View 1.0 -import Governikus.Type.ChangePinModel 1.0 -import Governikus.Type.NumberModel 1.0 -import Governikus.Type.PasswordType 1.0 -import Governikus.Type.UiModule 1.0 +import QtQuick +import Governikus.AuthView +import Governikus.EnterPasswordView +import Governikus.Global +import Governikus.ProgressView +import Governikus.ResultView +import Governikus.Style +import Governikus.TitleBar +import Governikus.PasswordInfoView +import Governikus.View +import Governikus.Workflow +import Governikus.Type.ApplicationModel +import Governikus.Type.ChangePinModel +import Governikus.Type.NumberModel +import Governikus.Type.PasswordType +import Governikus.Type.UiModule Controller { - id: controller + id: rootController + enum WorkflowStates { Initial, Reader, @@ -22,17 +33,23 @@ Controller { Processing } - readonly property string currentState: ChangePinModel.currentState - property bool wasNewPin: false + property bool autoInsertCard: false + property bool hideTechnologySwitch: false + property var initialPlugIn: null + property bool isNewPin: false + property bool smartEidUsed: false + property string title + //: INFO ANDROID IOS + readonly property string transportPinHint: qsTr("Please note that you may use the five-digit Transport PIN only once to change to a six-digit ID card PIN. If you already set a six-digit ID card PIN, the five-digit Transport PIN is no longer valid.") property int workflowState: 0 - function processStateChange() { - switch (currentState) { - case "Initial": - break; + signal workflowFinished + + function processStateChange(pState) { + switch (pState) { case "StateSelectReader": if (!workflowActive) { - replace(pinWorkflow); + push(pinWorkflow); } setPinWorkflowStateAndContinue(ChangePinController.WorkflowStates.Reader); break; @@ -67,7 +84,6 @@ Controller { showRemoveCardFeedback(ChangePinModel, false); if (ChangePinModel.shouldSkipResultView()) { ChangePinModel.continueWorkflow(); - popAll(); setLockedAndHidden(false); break; } @@ -78,31 +94,203 @@ Controller { } } function setPinWorkflowStateAndContinue(pState) { - controller.workflowState = pState; + rootController.workflowState = pState; ChangePinModel.continueWorkflow(); } function setPinWorkflowStateAndRequestInput(pState) { - controller.workflowState = pState; + rootController.workflowState = pState; if (ChangePinModel.isBasicReader) { - push(enterPinView); + push(enterPinView, { + "passwordType": NumberModel.passwordType, + "inputError": NumberModel.inputError + (NumberModel.inputError !== "" && ChangePinModel.requestTransportPin ? "

%1".arg(transportPinHint) : "") + }); } else { ChangePinModel.continueWorkflow(); } } + Component.onCompleted: if (ChangePinModel.currentState === "StateMaintainCardConnection") + processStateChange(ChangePinModel.currentState) + Connections { - // This is necessary because onCurrentStateChanged is not - // working, when we need to process a state a second time - function onFireCurrentStateChanged() { - processStateChange(); + //: INFO ANDROID IOS The ID card has just been unblocked and the user can now continue with their PIN change. + function onFireOnPinUnlocked() { + ApplicationModel.showFeedback(qsTr("Your ID card PIN is unblocked. You now have three more attempts to change your PIN.")); + } + function onFireStateEntered(pState) { + processStateChange(pState); } - function onFireNewContextSet() { - controller.wasNewPin = false; - show(UiModule.PINMANAGEMENT, true); - controller.workflowState = ChangePinController.WorkflowStates.Initial; - ChangePinModel.setInitialPluginType(); + function onFireWorkflowFinished() { + rootController.workflowFinished(); + popAll(); } target: ChangePinModel } + Component { + id: pinWorkflow + + GeneralWorkflow { + autoInsertCard: rootController.autoInsertCard + hideSwitch: rootController.hideTechnologySwitch + initialPlugIn: rootController.initialPlugIn + smartEidUsed: rootController.smartEidUsed + workflowModel: ChangePinModel + workflowTitle: rootController.title + } + } + Component { + id: cardPositionView + + CardPositionView { + title: rootController.title + + onCancelClicked: ChangePinModel.cancelWorkflow() + onContinueClicked: { + pop(); + ChangePinModel.continueWorkflow(); + } + } + } + Component { + id: pinResult + + ResultView { + function endWorkflow() { + ChangePinModel.continueWorkflow(); + setLockedAndHidden(false); + } + + hintButtonText: ChangePinModel.statusHintActionText + hintText: ChangePinModel.statusHintText + icon: ChangePinModel.error ? ChangePinModel.statusCodeImage.arg(Style.currentTheme.name) : "qrc:///images/workflow_success_changepin_%1.svg".arg(Style.currentTheme.name) + smartEidUsed: rootController.smartEidUsed + text: ChangePinModel.resultString + title: rootController.title + + onCancelClicked: continueClicked() + onContinueClicked: endWorkflow() + onHintClicked: { + endWorkflow(); + ChangePinModel.invokeStatusHintAction(); + } + } + } + PasswordInfoData { + id: infoData + + contentType: fromPasswordType(NumberModel.passwordType) + } + Component { + id: passwordInfoView + + PasswordInfoView { + infoContent: infoData + smartEidUsed: rootController.smartEidUsed + + navigationAction: NavigationAction { + action: NavigationAction.Action.Back + + onClicked: pop() + } + } + } + Component { + id: enterPinView + + EnterPasswordView { + moreInformationText: infoData.linkText + smartEidUsed: rootController.smartEidUsed + title: rootController.title + + navigationAction: NavigationAction { + action: NavigationAction.Action.Cancel + + onClicked: ChangePinModel.cancelWorkflow() + } + + onPasswordEntered: pPasswordType => { + switch (pPasswordType) { + case PasswordType.NEW_PIN: + case PasswordType.NEW_SMART_PIN: + rootController.processStateChange(ChangePinModel.currentState); + break; + case PasswordType.NEW_PIN_CONFIRMATION: + case PasswordType.NEW_SMART_PIN_CONFIRMATION: + if (NumberModel.commitNewPin()) { + pop(); + rootController.isNewPin = true; + ChangePinModel.continueWorkflow(); + } else { + rootController.processStateChange(ChangePinModel.currentState); + } + break; + default: + pop(); + ChangePinModel.continueWorkflow(); + } + } + onRequestPasswordInfo: push(passwordInfoView) + } + } + Component { + id: pinProgressView + + ProgressView { + smartEidUsed: rootController.smartEidUsed + subText: { + if (!visible) { + return ""; + } + if (isSmartWorkflow) { + //: INFO ANDROID IOS Generic progress message during PIN change process. + return qsTr("Please wait a moment."); + } + if (ChangePinModel.isBasicReader) { + //: INFO ANDROID IOS Loading screen during PIN change process, data communication is currently ongoing. Message is usually not visible since the password handling with basic reader is handled by EnterPasswordView. + return qsTr("Please do not move the ID card."); + } + if (NumberModel.inputError !== "") { + return NumberModel.inputError; + } + if (rootController.workflowState === ChangePinController.WorkflowStates.Update || rootController.workflowState === ChangePinController.WorkflowStates.Pin || rootController.workflowState === ChangePinController.WorkflowStates.NewPin) { + //: INFO ANDROID IOS Either an comfort card reader or smartphone-as-card-reader is used, the user needs to react to request on that device. + return qsTr("Please observe the display of your card reader."); + } + if (rootController.workflowState === ChangePinController.WorkflowStates.Can) { + //: INFO ANDROID IOS The wrong ID card PIN was entered twice, the next attempt requires additional verifcation via CAN. + return qsTr("A wrong ID card PIN has been entered twice on your ID card. For a third attempt, please first enter the six-digit Card Access Number (CAN). You can find your CAN in the bottom right on the front of your ID card."); + } + if (rootController.workflowState === ChangePinController.WorkflowStates.Puk) { + //: INFO ANDROID IOS The ID card PIN (including the CAN) was entered wrongfully three times, the PUK is required to unlock the ID card. + return qsTr("You have entered an incorrect, six-digit ID card PIN thrice, your ID card PIN is now blocked. To remove the block, the ten-digit PUK must be entered first."); + } + + //: INFO ANDROID IOS Generic progress message during PIN change process. + return qsTr("Please wait a moment."); + } + subTextColor: !ChangePinModel.isBasicReader && (NumberModel.inputError || rootController.workflowState === ChangePinController.WorkflowStates.Can || rootController.workflowState === ChangePinController.WorkflowStates.Puk) ? Constants.red : Style.color.text + text: { + if (isSmartWorkflow) { + return rootController.isNewPin ? + //: LABEL ANDROID IOS Processing screen label while the card communication is running after the new Smart-eID PIN has been entered during PIN change process. + qsTr("Setting new Smart-eID PIN") : + //: LABEL ANDROID IOS Processing screen label while the card communication is running before the new ID card PIN has been entered during PIN change process. + qsTr("Change Smart-eID PIN"); + } + return rootController.isNewPin ? + //: LABEL ANDROID IOS Processing screen label while the card communication is running after the new ID card PIN has been entered during PIN change process. + qsTr("Setting new ID card PIN") : + //: LABEL ANDROID IOS Processing screen label while the card communication is running before the new ID card PIN has been entered during PIN change process. + qsTr("Change ID card PIN"); + } + title: rootController.title + + navigationAction: NavigationAction { + action: ChangePinModel.isBasicReader ? NavigationAction.Action.Cancel : NavigationAction.Action.None + + onClicked: ChangePinModel.cancelWorkflow() + } + } + } } diff --git a/resources/qml/Governikus/ChangePinView/+mobile/ChangePinView.qml b/resources/qml/Governikus/ChangePinView/+mobile/ChangePinView.qml index 42116e3eb..0b9803017 100644 --- a/resources/qml/Governikus/ChangePinView/+mobile/ChangePinView.qml +++ b/resources/qml/Governikus/ChangePinView/+mobile/ChangePinView.qml @@ -1,62 +1,92 @@ /** * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.EnterPasswordView 1.0 -import Governikus.Global 1.0 -import Governikus.AuthView 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.PasswordInfoView 1.0 -import Governikus.ProgressView 1.0 -import Governikus.ResultView 1.0 -import Governikus.View 1.0 -import Governikus.Workflow 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.ChangePinModel 1.0 -import Governikus.Type.NumberModel 1.0 -import Governikus.Type.PasswordType 1.0 -import Governikus.Type.UiModule 1.0 -import Governikus.Type.ReaderPlugIn 1.0 +import QtQuick +import Governikus.EnterPasswordView +import Governikus.Global +import Governikus.AuthView +import Governikus.Style +import Governikus.TitleBar +import Governikus.PasswordInfoView +import Governikus.ProgressView +import Governikus.ResultView +import Governikus.View +import Governikus.Workflow +import Governikus.Type.ApplicationModel +import Governikus.Type.ChangePinModel +import Governikus.Type.NumberModel +import Governikus.Type.PasswordType +import Governikus.Type.UiModule +import Governikus.Type.ReaderPlugIn SectionPage { id: baseItem + property bool autoInsertCard: false + property bool hidePinTypeSelection: false + property bool hideTechnologySwitch: false + property var initialPlugIn: null readonly property bool isSmartWorkflow: ChangePinModel.readerPlugInType === ReaderPlugIn.SMART - sectionPageFlickable: changePinViewContent - title: changePinController.currentState === "" ? - //: LABEL ANDROID IOS - qsTr("Change my (Transport) PIN") : NumberModel.passwordType === PasswordType.TRANSPORT_PIN ? + signal close + signal workflowFinished + + contentIsScrolled: !changePinViewContent.atYBeginning + smartEidUsed: isSmartWorkflow + title: NumberModel.passwordType === PasswordType.TRANSPORT_PIN ? //: LABEL ANDROID IOS qsTr("Change Transport PIN") : //: LABEL ANDROID IOS qsTr("Change PIN") - titleBarColor: isSmartWorkflow ? Style.color.accent_smart : Style.color.accent navigationAction: NavigationAction { action: NavigationAction.Action.Back - onClicked: show(UiModule.DEFAULT) + onClicked: baseItem.close() } - ChangePinController { - id: changePinController + Connections { + function onActivate() { + changePinViewContent.highlightScrollbar(); + } } Connections { - //: INFO ANDROID IOS The ID card has just been unblocked and the user can now continue with their PIN change. - function onFireOnPinUnlocked() { - ApplicationModel.showFeedback(qsTr("Your ID card PIN is unblocked. You now have three more attempts to change your PIN.")); + function onFireWorkflowStarted() { + changePinController.createObject(baseItem); + setLockedAndHidden(true); + ChangePinModel.setInitialPluginType(); } + enabled: visible target: ChangePinModel } + Component { + id: changePinController + + ChangePinController { + autoInsertCard: baseItem.autoInsertCard + hideTechnologySwitch: baseItem.hideTechnologySwitch + initialPlugIn: baseItem.initialPlugIn + smartEidUsed: baseItem.smartEidUsed + stackView: baseItem.stackView + title: baseItem.title + + onWorkflowFinished: { + baseItem.workflowFinished(); + this.destroy(); + } + } + } ChangePinViewContent { id: changePinViewContent + anchors.fill: parent moreInformationText: changePinInfo.linkText + visible: !baseItem.hidePinTypeSelection - onMoreInformationRequested: push(passwordInfoView) + onChangePin: ChangePinModel.startWorkflow(false) + onChangeTransportPin: ChangePinModel.startWorkflow(true) + onMoreInformationRequested: push(changePinInfoView) onNoPinAvailable: { setLockedAndHidden(); push(pinUnknownView); @@ -64,17 +94,15 @@ SectionPage { PasswordInfoData { id: changePinInfo + contentType: PasswordInfoContent.Type.CHANGE_PIN } - PasswordInfoData { - id: infoData - contentType: ApplicationModel.currentWorkflow === ApplicationModel.WORKFLOW_NONE ? PasswordInfoContent.Type.CHANGE_PIN : fromPasswordType(NumberModel.passwordType) - } } Component { - id: passwordInfoView + id: changePinInfoView + PasswordInfoView { - infoContent: infoData + infoContent: changePinInfo navigationAction: NavigationAction { action: NavigationAction.Action.Back @@ -87,6 +115,7 @@ SectionPage { } Component { id: pinUnknownView + PasswordInfoView { infoContent: PasswordInfoData { contentType: PasswordInfoContent.Type.NO_PIN @@ -101,123 +130,4 @@ SectionPage { } } } - Component { - id: pinWorkflow - GeneralWorkflow { - titleBarColor: baseItem.titleBarColor - workflowModel: ChangePinModel - workflowTitle: baseItem.title - } - } - Component { - id: cardPositionView - CardPositionView { - title: baseItem.title - - onCancelClicked: ChangePinModel.cancelWorkflow() - onContinueClicked: { - pop(); - ChangePinModel.continueWorkflow(); - } - } - } - Component { - id: pinResult - ResultView { - hintButtonText: ChangePinModel.statusHintActionText - hintText: ChangePinModel.statusHintText - resultType: ChangePinModel.error ? ResultView.Type.IsError : ResultView.Type.IsSuccess - text: ChangePinModel.resultString - title: baseItem.title - titleBarColor: baseItem.titleBarColor - - onCancelClicked: continueClicked() - onContinueClicked: { - ChangePinModel.continueWorkflow(); - setLockedAndHidden(false); - popAll(); - } - onHintClicked: ChangePinModel.invokeStatusHintAction() - } - } - Component { - id: enterPinView - EnterPasswordView { - moreInformationText: infoData.linkText - title: baseItem.title - titleBarColor: baseItem.titleBarColor - - navigationAction: NavigationAction { - action: NavigationAction.Action.Cancel - - onClicked: ChangePinModel.cancelWorkflow() - } - - onPasswordEntered: pWasNewPin => { - changePinController.wasNewPin = pWasNewPin; - pop(); - ChangePinModel.continueWorkflow(); - } - onRequestPasswordInfo: push(passwordInfoView) - } - } - Component { - id: pinProgressView - ProgressView { - subText: { - if (!visible) { - return ""; - } - if (isSmartWorkflow) { - //: INFO ANDROID IOS Generic progress message during PIN change process. - return qsTr("Please wait a moment."); - } - if (ChangePinModel.isBasicReader) { - //: INFO ANDROID IOS Loading screen during PIN change process, data communication is currently ongoing. Message is usually not visible since the password handling with basic reader is handled by EnterPasswordView. - return qsTr("Please do not move the ID card."); - } - if (NumberModel.inputError !== "") { - return NumberModel.inputError; - } - if (changePinController.workflowState === ChangePinController.WorkflowStates.Update || changePinController.workflowState === ChangePinController.WorkflowStates.Pin || changePinController.workflowState === ChangePinController.WorkflowStates.NewPin) { - //: INFO ANDROID IOS Either an comfort card reader or smartphone-as-card-reader is used, the user needs to react to request on that device. - return qsTr("Please observe the display of your card reader."); - } - if (changePinController.workflowState === ChangePinController.WorkflowStates.Can) { - //: INFO ANDROID IOS The wrong ID card PIN was entered twice, the next attempt requires additional verification via CAN. - return qsTr("A wrong ID card PIN has been entered twice on your ID card. For a third attempt, please first enter the six-digit Card Access Number (CAN). You can find your CAN in the bottom right on the front of your ID card."); - } - if (changePinController.workflowState === ChangePinController.WorkflowStates.Puk) { - //: INFO ANDROID IOS The ID card PIN (including the CAN) was entered wrongfully three times, the PUK is required to unlock the ID card. - return qsTr("You have entered an incorrect, six-digit ID card PIN thrice, your ID card PIN is now blocked. To remove the block, the ten-digit PUK must be entered first."); - } - - //: INFO ANDROID IOS Generic progress message during PIN change process. - return qsTr("Please wait a moment."); - } - subTextColor: !ChangePinModel.isBasicReader && (NumberModel.inputError || changePinController.workflowState === ChangePinController.WorkflowStates.Can || changePinController.workflowState === ChangePinController.WorkflowStates.Puk) ? Constants.red : Style.color.secondary_text - text: { - if (isSmartWorkflow) { - return changePinController.wasNewPin ? - //: LABEL ANDROID IOS Processing screen label while the card communication is running after the new Smart-eID PIN has been entered during PIN change process. - qsTr("Setting new Smart-eID PIN") : - //: LABEL ANDROID IOS Processing screen label while the card communication is running before the new ID card PIN has been entered during PIN change process. - qsTr("Change Smart-eID PIN"); - } - return changePinController.wasNewPin ? - //: LABEL ANDROID IOS Processing screen label while the card communication is running after the new ID card PIN has been entered during PIN change process. - qsTr("Setting new ID card PIN") : - //: LABEL ANDROID IOS Processing screen label while the card communication is running before the new ID card PIN has been entered during PIN change process. - qsTr("Change ID card PIN"); - } - title: baseItem.title - titleBarColor: baseItem.titleBarColor - - navigationAction: NavigationAction { - action: ChangePinModel.isBasicReader ? NavigationAction.Action.Cancel : NavigationAction.Action.None - - onClicked: ChangePinModel.cancelWorkflow() - } - } - } } diff --git a/resources/qml/Governikus/ChangePinView/ChangePinViewContent.qml b/resources/qml/Governikus/ChangePinView/ChangePinViewContent.qml index 9b73d8b84..a2c46fbd7 100644 --- a/resources/qml/Governikus/ChangePinView/ChangePinViewContent.qml +++ b/resources/qml/Governikus/ChangePinView/ChangePinViewContent.qml @@ -1,99 +1,95 @@ /** * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.ChangePinModel 1.0 -import Governikus.Type.NumberModel 1.0 -import Governikus.Type.ApplicationModel 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.Type.NumberModel +import Governikus.Type.ApplicationModel GFlickableColumnLayout { id: root + readonly property double buttonHeight: Math.max(sixDigitButton.implicitHeight, fiveDigitButton.implicitHeight, dontKnowButton.implicitHeight) + readonly property double buttonWidth: Math.max(sixDigitButton.implicitWidth, fiveDigitButton.implicitWidth, dontKnowButton.implicitWidth) property alias moreInformationText: moreInformationLink.text + signal changePin + signal changeTransportPin signal moreInformationRequested signal noPinAvailable maximumContentWidth: Style.dimens.max_text_width - spacing: 0 + spacing: Constants.component_spacing GText { id: pinDescWhatType - Layout.alignment: Qt.AlignCenter - Layout.maximumWidth: root.effectiveContentWidth + + Layout.alignment: Qt.AlignHCenter Layout.topMargin: Constants.component_spacing - horizontalAlignment: Text.AlignLeft //: LABEL ALL_PLATFORMS text: qsTr("What kind of PIN do you have?") - textStyle: Style.text.title_highlight + textStyle: Style.text.headline wrapMode: Text.WordWrap } MoreInformationLink { id: moreInformationLink - Layout.alignment: Qt.AlignCenter - Layout.maximumWidth: root.effectiveContentWidth - Layout.topMargin: Constants.component_spacing + + Layout.alignment: Qt.AlignHCenter onClicked: root.moreInformationRequested() } - ColumnLayout { - id: buttonLayout + GInformativeButton { + id: sixDigitButton - readonly property double buttonHeight: Math.max(sixDigitButton.implicitHeight, fiveDigitButton.implicitHeight, dontKnowButton.implicitHeight) + Layout.alignment: Qt.AlignHCenter + Layout.fillWidth: true + Layout.maximumWidth: root.buttonWidth + Layout.preferredHeight: root.buttonHeight + //: LABEL ALL_PLATFORMS + description: qsTr("Set by yourself") + icon.source: "qrc:///images/icon_six_digit_pin.svg" - Layout.alignment: Qt.AlignCenter - Layout.fillWidth: false - Layout.maximumWidth: root.effectiveContentWidth - Layout.topMargin: Constants.component_spacing - spacing: Constants.component_spacing - - GInformativeButton { - id: sixDigitButton - Layout.fillWidth: true - Layout.preferredHeight: buttonLayout.buttonHeight - //: LABEL ALL_PLATFORMS - description: qsTr("Set by yourself") - icon.source: "qrc:///images/icon_six_digit_pin_white.svg" - - //: LABEL ALL_PLATFORMS - text: qsTr("Six-digit PIN") - - onClicked: ChangePinModel.startWorkflow(false) - } - GInformativeButton { - id: fiveDigitButton - Layout.fillWidth: true - Layout.preferredHeight: buttonLayout.buttonHeight - //: LABEL ALL_PLATFORMS - description: qsTr("Received by mail in PIN letter") - icon.source: "qrc:///images/icon_five_digit_pin.svg" - - //: LABEL ALL_PLATFORMS - text: qsTr("Five-digit Transport PIN") - - onClicked: ChangePinModel.startWorkflow(true) - } - GInformativeButton { - id: dontKnowButton - Layout.fillWidth: true - Layout.preferredHeight: buttonLayout.buttonHeight - //: LABEL ALL_PLATFORMS - description: qsTr("Lost, forgotten, or never received it") - icon.source: "qrc:///images/material_block.svg" - scaleIcon: 0.5 - - //: LABEL ALL_PLATFORMS - text: qsTr("No PIN") - tintIcon: true - - onClicked: root.noPinAvailable() - } + //: LABEL ALL_PLATFORMS + text: qsTr("Six-digit PIN") + tintIcon: true + + onClicked: root.changePin() + } + GInformativeButton { + id: fiveDigitButton + + Layout.alignment: Qt.AlignHCenter + Layout.fillWidth: true + Layout.maximumWidth: root.buttonWidth + Layout.preferredHeight: root.buttonHeight + //: LABEL ALL_PLATFORMS + description: qsTr("Received by mail in PIN letter") + icon.source: "qrc:///images/icon_five_digit_pin.svg" + + //: LABEL ALL_PLATFORMS + text: qsTr("Five-digit Transport PIN") + tintIcon: true + + onClicked: root.changeTransportPin() } - GSpacer { - Layout.fillHeight: true + GInformativeButton { + id: dontKnowButton + + Layout.alignment: Qt.AlignHCenter + Layout.fillWidth: true + Layout.maximumWidth: root.buttonWidth + Layout.preferredHeight: root.buttonHeight + //: LABEL ALL_PLATFORMS + description: qsTr("Lost, forgotten, or never received it") + icon.source: "qrc:///images/material_block.svg" + + //: LABEL ALL_PLATFORMS + text: qsTr("No PIN") + tintIcon: true + + onClicked: root.noPinAvailable() } } diff --git a/resources/qml/Governikus/CheckIDCardView/+mobile/CheckIDCardResultView.qml b/resources/qml/Governikus/CheckIDCardView/+mobile/CheckIDCardResultView.qml index 69e1ff15d..b87ff7041 100644 --- a/resources/qml/Governikus/CheckIDCardView/+mobile/CheckIDCardResultView.qml +++ b/resources/qml/Governikus/CheckIDCardView/+mobile/CheckIDCardResultView.qml @@ -1,20 +1,21 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQml.Models 2.15 -import Governikus.CheckResultView 1.0 -import Governikus.Global 1.0 -import Governikus.ResultView 1.0 -import Governikus.Style 1.0 -import Governikus.Type.CheckIDCardModel 1.0 +import QtQuick +import QtQml.Models +import Governikus.CheckResultView +import Governikus.Global +import Governikus.ResultView +import Governikus.Style +import Governikus.Type.CheckIDCardModel CheckResultView { id: root + signal restartCheck signal startAuth - buttonIcon: result === CheckIDCardModel.SUCCESS ? "qrc:///images/identify.svg" : "qrc:///images/material_help.svg" + buttonIcon: result === CheckIDCardModel.SUCCESS ? "qrc:///images/mydata.svg" : "qrc:///images/mobile/help.svg" //: LABEL ANDROID IOS buttonText: { switch (result) { @@ -33,8 +34,8 @@ CheckResultView { } //: LABEL ANDROID IOS header: qsTr("Test Result") + icon: result === CheckIDCardModel.SUCCESS ? "qrc:///images/mobile/workflow_success_nfc_%1.svg".arg(Style.currentTheme.name) : "qrc:///images/workflow_error_nfc_%1.svg".arg(Style.currentTheme.name) model: resultModel - resultType: result === CheckIDCardModel.SUCCESS ? ResultView.Type.IsSuccess : ResultView.Type.IsError //: LABEL ANDROID IOS title: qsTr("Check device and ID card") @@ -49,14 +50,18 @@ CheckResultView { } GText { + font.bold: true + horizontalAlignment: Text.AlignHCenter text: result === CheckIDCardModel.SUCCESS ? qsTr("You may now try the function: \"See my personal data\". Press the Continue button to do so now.") : "" - textStyle: Style.text.normal_highlight visible: text !== "" width: parent.width } Component { id: checkIDCardSuggestionView + CheckIDCardSuggestionView { + title: root.title + onCancelClicked: root.cancelClicked() onRestartCheck: root.restartCheck() onStartAuth: root.startAuth() @@ -64,10 +69,11 @@ CheckResultView { } ObjectModel { id: resultModel + ResultEntry { readonly property bool nfcSupported: result !== CheckIDCardModel.NO_NFC - resultType: nfcSupported ? ResultView.Type.IsSuccess : ResultView.Type.IsError + resultType: nfcSupported ? ResultEntry.Type.IsSuccess : ResultEntry.Type.IsError //: LABEL ANDROID IOS text: nfcSupported ? @@ -83,7 +89,7 @@ CheckResultView { visible: result > CheckIDCardModel.NO_NFC } ResultEntry { - resultType: ResultView.Type.IsInfo + resultType: ResultEntry.Type.IsInfo //: LABEL ANDROID IOS text: qsTr("No supported card detected") @@ -98,7 +104,7 @@ CheckResultView { ResultEntry { readonly property bool insufficientApduLength: result === CheckIDCardModel.INSUFFICIENT_APDU_LENGTH - resultType: insufficientApduLength ? ResultView.Type.IsError : ResultView.Type.IsSuccess + resultType: insufficientApduLength ? ResultEntry.Type.IsError : ResultEntry.Type.IsSuccess //: LABEL ANDROID IOS text: insufficientApduLength ? @@ -111,7 +117,7 @@ CheckResultView { ResultEntry { readonly property bool cardAccessFailed: result === CheckIDCardModel.CARD_ACCESS_FAILED - resultType: cardAccessFailed ? ResultView.Type.IsError : ResultView.Type.IsSuccess + resultType: cardAccessFailed ? ResultEntry.Type.IsError : ResultEntry.Type.IsSuccess text: cardAccessFailed ? //: LABEL ANDROID IOS qsTr("ID card access failed") : @@ -122,7 +128,7 @@ CheckResultView { ResultEntry { readonly property bool pinDeactivated: result === CheckIDCardModel.PIN_DEACTIVATED - resultType: pinDeactivated ? ResultView.Type.IsError : ResultView.Type.IsSuccess + resultType: pinDeactivated ? ResultEntry.Type.IsError : ResultEntry.Type.IsSuccess text: pinDeactivated ? //: LABEL ANDROID IOS qsTr("Online identification feature disabled") : @@ -131,14 +137,14 @@ CheckResultView { visible: result >= CheckIDCardModel.PIN_DEACTIVATED } ResultEntry { - resultType: ResultView.Type.IsInfo + resultType: ResultEntry.Type.IsInfo //: LABEL ANDROID IOS text: qsTr("ID card PIN suspended") visible: result === CheckIDCardModel.PIN_SUSPENDED } ResultEntry { - resultType: ResultView.Type.IsInfo + resultType: ResultEntry.Type.IsInfo //: LABEL ANDROID IOS text: qsTr("ID card PIN blocked") diff --git a/resources/qml/Governikus/CheckIDCardView/+mobile/CheckIDCardSuggestionView.qml b/resources/qml/Governikus/CheckIDCardView/+mobile/CheckIDCardSuggestionView.qml index efa3ba040..b68d616ba 100644 --- a/resources/qml/Governikus/CheckIDCardView/+mobile/CheckIDCardSuggestionView.qml +++ b/resources/qml/Governikus/CheckIDCardView/+mobile/CheckIDCardSuggestionView.qml @@ -1,16 +1,16 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.CheckResultView 1.0 -import Governikus.Type.CheckIDCardModel 1.0 -import Governikus.Type.PinResetInformationModel 1.0 -import Governikus.Type.SettingsModel 1.0 +import QtQuick +import Governikus.CheckResultView +import Governikus.Type.CheckIDCardModel +import Governikus.Type.PinResetInformationModel +import Governikus.Type.SettingsModel CheckResultSuggestionView { id: root - property int result + required property int result signal restartCheck signal startAuth @@ -45,7 +45,8 @@ CheckResultSuggestionView { } SuggestionData { id: noNfcSuggestionData - continueButtonIcon: "qrc:///images/material_open_in_new.svg" + + continueButtonIcon: "qrc:///images/open_website.svg" //: LABEL ANDROID IOS continueButtonText: qsTr("Open website") //: LABEL ANDROID IOS @@ -58,7 +59,8 @@ CheckResultSuggestionView { } SuggestionData { id: unknownCardSuggestionData - continueButtonIcon: "qrc:///images/mobile/device.svg" + + continueButtonIcon: "qrc:///images/mobile/device_button.svg" //: LABEL ANDROID IOS continueButtonText: qsTr("Retry") //: LABEL ANDROID IOS @@ -71,7 +73,8 @@ CheckResultSuggestionView { } SuggestionData { id: insufficientApduLengthSuggestionData - continueButtonIcon: "qrc:///images/material_open_in_new.svg" + + continueButtonIcon: "qrc:///images/open_website.svg" //: LABEL ANDROID IOS continueButtonText: qsTr("Open website") //: LABEL ANDROID IOS @@ -87,7 +90,7 @@ CheckResultSuggestionView { readonly property string deviceUrl: "https://www.ausweisapp.bund.de/%1/aa2/mobile-devices".arg(SettingsModel.language) - continueButtonIcon: "qrc:///images/mobile/device.svg" + continueButtonIcon: "qrc:///images/mobile/device_button.svg" //: LABEL ANDROID IOS continueButtonText: qsTr("Retry") @@ -100,6 +103,7 @@ CheckResultSuggestionView { } SuggestionData { id: pinDeactivatedSuggestionData + //: LABEL ANDROID IOS continueButtonText: qsTr("OK") hintButtonText: PinResetInformationModel.pinResetActionText @@ -114,6 +118,7 @@ CheckResultSuggestionView { } SuggestionData { id: pinSuspendedSuggestionData + continueButtonIcon: "qrc:///images/identify.svg" //: LABEL ANDROID IOS continueButtonText: qsTr("Continue") @@ -127,6 +132,7 @@ CheckResultSuggestionView { } SuggestionData { id: pinBlockedSuggestionData + continueButtonIcon: "qrc:///images/identify.svg" //: LABEL ANDROID IOS continueButtonText: qsTr("Continue") diff --git a/resources/qml/Governikus/CheckIDCardView/+mobile/CheckIDCardView.qml b/resources/qml/Governikus/CheckIDCardView/+mobile/CheckIDCardView.qml index aee129c52..4678a4b5e 100644 --- a/resources/qml/Governikus/CheckIDCardView/+mobile/CheckIDCardView.qml +++ b/resources/qml/Governikus/CheckIDCardView/+mobile/CheckIDCardView.qml @@ -1,22 +1,25 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.CheckIDCardModel 1.0 -import Governikus.Type.UiModule 1.0 - -SectionPage { +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.SelfAuthenticationView +import Governikus.Style +import Governikus.TitleBar +import Governikus.View +import Governikus.Type.ApplicationModel +import Governikus.Type.CheckIDCardModel +import Governikus.Type.ReaderPlugIn +import Governikus.Type.UiModule + +FlickableSectionPage { id: root + signal startAuth - sectionPageFlickable: contentItem + spacing: Constants.component_spacing //: LABEL ANDROID IOS title: qsTr("Check device and ID card") @@ -29,11 +32,26 @@ SectionPage { onStartAuth: { popAll(); - show(UiModule.SELF_AUTHENTICATION); + push(selfAuthView); } + Component { + id: selfAuthView + + SelfAuthenticationView { + hideTechnologySwitch: true + initialPlugIn: ReaderPlugIn.NFC + + onBack: { + setLockedAndHidden(false); + pop(); + show(UiModule.DEFAULT); + } + } + } QtObject { id: d + function cancel() { setLockedAndHidden(false); popAll(); @@ -49,7 +67,10 @@ SectionPage { } Component { id: checkIDCardResultView + CheckIDCardResultView { + title: root.title + onCancelClicked: d.cancel() onRestartCheck: d.restartCheck() onStartAuth: root.startAuth() @@ -57,69 +78,52 @@ SectionPage { } Component { id: checkIDCardWorkflow + CheckIDCardWorkflow { onCancel: d.cancel() onRestartCheck: d.restartCheck() onStartAuth: root.startAuth() } } - GFlickableColumnLayout { - id: contentItem - - readonly property var maxIconHeight: Style.dimens.header_icon_size - readonly property var minIconHeight: Style.dimens.medium_icon_size - - anchors.fill: parent - maximumContentWidth: Style.dimens.max_text_width - minimumContentHeight: implicitContentHeight - (maxIconHeight - minIconHeight) - spacing: Constants.component_spacing - - TintableIcon { - Layout.alignment: Qt.AlignHCenter - Layout.fillHeight: true - Layout.maximumHeight: contentItem.maxIconHeight - Layout.minimumHeight: contentItem.minIconHeight - Layout.preferredHeight: contentItem.maxIconHeight - source: "qrc:///images/mobile/device.svg" - sourceSize.height: contentItem.maxIconHeight - tintColor: Style.color.accent - } - GPane { - Layout.alignment: Qt.AlignHCenter - Layout.fillWidth: true - - GText { + TintableIcon { + Layout.alignment: Qt.AlignHCenter + source: "qrc:///images/mobile/device.svg" + sourceSize.height: Style.dimens.header_icon_size + tintColor: Style.color.control + } + GText { + Layout.alignment: Qt.AlignHCenter + Layout.margins: Constants.pane_padding + horizontalAlignment: Text.AlignHCenter + //: LABEL ANDROID IOS + text: qsTr("To use the eID function, your device must meet certain technical requirements. Furthermore, the eID function must be activated.") + } + GText { + Layout.alignment: Qt.AlignHCenter + Layout.margins: Constants.pane_padding + horizontalAlignment: Text.AlignHCenter + //: LABEL ANDROID IOS + text: qsTr("Check if your smartphone and ID card are ready for use.") + } + GSpacer { + Layout.fillHeight: true + } + GButton { + Layout.alignment: Qt.AlignHCenter + icon.source: "qrc:///images/mobile/device_button.svg" - //: LABEL ANDROID IOS - text: qsTr("To use the eID function, your device must meet certain technical requirements. Furthermore, the eID function must be activated.") - width: parent.width - } - GText { + //: LABEL ANDROID IOS + text: qsTr("Start check") + tintIcon: true - //: LABEL ANDROID IOS - text: qsTr("Check if your smartphone and ID card are ready for use.") - width: parent.width - } - } - GSpacer { - Layout.fillHeight: true - } - GButton { - Layout.alignment: Qt.AlignHCenter - icon.source: "qrc:///images/mobile/device.svg" - - //: LABEL ANDROID IOS - text: qsTr("Start check") - - onClicked: { - if (ApplicationModel.nfcState === ApplicationModel.NFC_UNAVAILABLE) { - setLockedAndHidden(); - push(checkIDCardResultView, { - "result": CheckIDCardModel.NO_NFC - }); - } else { - d.startCheck(); - } + onClicked: { + if (ApplicationModel.nfcState === ApplicationModel.NFC_UNAVAILABLE) { + setLockedAndHidden(); + push(checkIDCardResultView, { + "result": CheckIDCardModel.NO_NFC + }); + } else { + d.startCheck(); } } } diff --git a/resources/qml/Governikus/CheckIDCardView/+mobile/CheckIDCardWorkflow.qml b/resources/qml/Governikus/CheckIDCardView/+mobile/CheckIDCardWorkflow.qml index a0511b6e4..d5cb42514 100644 --- a/resources/qml/Governikus/CheckIDCardView/+mobile/CheckIDCardWorkflow.qml +++ b/resources/qml/Governikus/CheckIDCardView/+mobile/CheckIDCardWorkflow.qml @@ -1,20 +1,23 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.ProgressView 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 -import Governikus.Workflow 1.0 -import Governikus.Type.CheckIDCardModel 1.0 -import Governikus.Type.ApplicationModel 1.0 +import QtQuick +import Governikus.ProgressView +import Governikus.TitleBar +import Governikus.View +import Governikus.Workflow +import Governikus.Type.CheckIDCardModel +import Governikus.Type.ApplicationModel SectionPage { id: root + signal cancel signal restartCheck signal startAuth + contentIsScrolled: nfcWorkflow.visible && !nfcWorkflow.atYBeginning || progressView.visible && progressView.contentIsScrolled + //: LABEL ANDROID IOS title: qsTr("Check device and ID card") @@ -30,10 +33,12 @@ SectionPage { CheckIDCardModel { id: checkIDCardModel + onFireScanCompleted: timerHelper.start() } Timer { id: timerHelper + interval: 1 onTriggered: push(checkIDCardResultView, { @@ -42,25 +47,33 @@ SectionPage { } Component { id: checkIDCardResultView + CheckIDCardResultView { + title: root.title + onCancelClicked: root.cancel() onRestartCheck: root.restartCheck() onStartAuth: root.startAuth() } } NfcWorkflow { + id: nfcWorkflow + anchors.fill: parent visible: checkIDCardModel.result < CheckIDCardModel.ID_CARD_DETECTED onStartScanIfNecessary: checkIDCardModel.startScanIfNecessary() } ProgressView { + id: progressView + anchors.fill: parent //: LABEL ANDROID IOS subText: qsTr("Please do not move the ID card.") //: LABEL ANDROID IOS text: qsTr("Checking ID card") + title: root.title visible: checkIDCardModel.result >= CheckIDCardModel.ID_CARD_DETECTED } } diff --git a/resources/qml/Governikus/CheckResultView/+mobile/CheckResultSuggestionView.qml b/resources/qml/Governikus/CheckResultView/+mobile/CheckResultSuggestionView.qml index a195d8c20..8f4f1ab25 100644 --- a/resources/qml/Governikus/CheckResultView/+mobile/CheckResultSuggestionView.qml +++ b/resources/qml/Governikus/CheckResultView/+mobile/CheckResultSuggestionView.qml @@ -1,22 +1,22 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.ResultView 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.ResultView ResultView { id: root - property var suggestionData: SuggestionData { - } + required property SuggestionData suggestionData buttonIcon: suggestionData.continueButtonIcon buttonText: suggestionData.continueButtonText header: suggestionData.header hintButtonText: suggestionData.hintButtonText hintText: suggestionData.hintText - resultType: ResultView.Type.IsInfo + icon: suggestionData.icon text: suggestionData.text textFormat: suggestionData.textFormat title: suggestionData.title @@ -25,7 +25,7 @@ ResultView { onHintClicked: suggestionData.hintClicked() GButton { - anchors.horizontalCenter: parent.horizontalCenter + Layout.alignment: Qt.AlignHCenter icon.source: suggestionData.actionButtonIcon text: suggestionData.actionButtonText tintIcon: true diff --git a/resources/qml/Governikus/CheckResultView/+mobile/CheckResultView.qml b/resources/qml/Governikus/CheckResultView/+mobile/CheckResultView.qml index 708b31eec..2d8545f10 100644 --- a/resources/qml/Governikus/CheckResultView/+mobile/CheckResultView.qml +++ b/resources/qml/Governikus/CheckResultView/+mobile/CheckResultView.qml @@ -1,21 +1,18 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.ResultView 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.ResultView ResultView { id: root property alias model: resultRepeater.model - property int result + required property int result - ColumnLayout { - width: parent.width + Repeater { + id: resultRepeater - Repeater { - id: resultRepeater - } } } diff --git a/resources/qml/Governikus/CheckResultView/+mobile/ResultEntry.qml b/resources/qml/Governikus/CheckResultView/+mobile/ResultEntry.qml index db707bf12..1d5b934bc 100644 --- a/resources/qml/Governikus/CheckResultView/+mobile/ResultEntry.qml +++ b/resources/qml/Governikus/CheckResultView/+mobile/ResultEntry.qml @@ -1,62 +1,69 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.ResultView 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.ResultView RowLayout { id: root - property int resultType: ResultView.Type.IsSuccess + enum Type { + IsSuccess, + IsError, + IsInfo, + IsWait + } + + property int resultType: ResultEntry.Type.IsSuccess property alias text: textItem.text Accessible.focusable: true Accessible.name: text Accessible.role: Accessible.ListItem - Layout.alignment: Qt.AlignHCenter + Layout.alignment: Qt.AlignLeft Layout.fillWidth: true - Layout.maximumWidth: Style.dimens.max_text_width + Layout.maximumWidth: Math.ceil(implicitWidth) spacing: Constants.groupbox_spacing TintableIcon { Layout.alignment: Qt.AlignTop source: { switch (resultType) { - case ResultView.Type.IsSuccess: - return "qrc:///images/material_check.svg"; - case ResultView.Type.IsInfo: + case ResultEntry.Type.IsSuccess: + return "qrc:///images/status_ok_%1.svg".arg(Style.currentTheme.name); + case ResultEntry.Type.IsInfo: return "qrc:///images/info.svg"; - case ResultView.Type.IsError: - return "qrc:///images/material_clear.svg"; + case ResultEntry.Type.IsError: + return "qrc:///images/status_error_%1.svg".arg(Style.currentTheme.name); } } sourceSize.height: Style.dimens.small_icon_size tintColor: { switch (resultType) { - case ResultView.Type.IsSuccess: + case ResultEntry.Type.IsSuccess: return Style.color.success; - case ResultView.Type.IsInfo: - return Style.color.info_text; - case ResultView.Type.IsError: - return Style.color.warning_text; + case ResultEntry.Type.IsInfo: + return Style.color.text; + case ResultEntry.Type.IsError: + return Style.color.text_warning; } } } GText { id: textItem + Accessible.ignored: true - Layout.fillWidth: true elide: Text.ElideRight textStyle: { switch (resultType) { - case ResultView.Type.IsSuccess: + case ResultEntry.Type.IsSuccess: + return Style.text.normal; + case ResultEntry.Type.IsInfo: return Style.text.normal; - case ResultView.Type.IsInfo: - return Style.text.normal_info; - case ResultView.Type.IsError: + case ResultEntry.Type.IsError: return Style.text.normal_warning; } } diff --git a/resources/qml/Governikus/CheckResultView/+mobile/SuggestionData.qml b/resources/qml/Governikus/CheckResultView/+mobile/SuggestionData.qml index 66f696026..cddad9c7a 100644 --- a/resources/qml/Governikus/CheckResultView/+mobile/SuggestionData.qml +++ b/resources/qml/Governikus/CheckResultView/+mobile/SuggestionData.qml @@ -1,7 +1,9 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 +import QtQuick +import Governikus.ResultView +import Governikus.Style QtObject { property url actionButtonIcon @@ -11,6 +13,7 @@ QtObject { property string header property string hintButtonText property string hintText + property url icon: "qrc:///images/status_info_%1.svg".arg(Style.currentTheme.name) property string text property int textFormat: Text.AutoText property string title diff --git a/resources/qml/Governikus/CheckSmartView/+mobile/CheckSmartResultView.qml b/resources/qml/Governikus/CheckSmartView/+mobile/CheckSmartResultView.qml deleted file mode 100644 index 5bca187aa..000000000 --- a/resources/qml/Governikus/CheckSmartView/+mobile/CheckSmartResultView.qml +++ /dev/null @@ -1,117 +0,0 @@ -/** - * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQml.Models 2.15 -import Governikus.CheckResultView 1.0 -import Governikus.Global 1.0 -import Governikus.ResultView 1.0 -import Governikus.Style 1.0 -import Governikus.Type.SmartModel 1.0 - -CheckResultView { - id: root - signal checkDevice - signal runSmartSetup - signal startAuth - - buttonIcon: result === SmartModel.SMART_READY ? "qrc:///images/identify.svg" : "qrc:///images/material_help.svg" - buttonText: { - switch (result) { - case SmartModel.SMART_READY: - //: LABEL ANDROID IOS - return qsTr("Continue"); - case SmartModel.SMART_UPDATING_STATUS: - return ""; - default: - //: LABEL ANDROID IOS - return qsTr("What does that mean?"); - } - } - //: LABEL ANDROID IOS - header: qsTr("Result of Smart-eID check") - model: resultModel - resultType: { - switch (result) { - case SmartModel.SMART_UNAVAILABLE: - case SmartModel.SMART_UNUSABLE: - return ResultView.Type.IsError; - case SmartModel.SMART_NO_PROVISIONING: - case SmartModel.SMART_NO_PERSONALIZATION: - case SmartModel.SMART_UPDATING_STATUS: - return ResultView.Type.IsInfo; - default: - return ResultView.Type.IsSuccess; - } - } - //: LABEL ANDROID IOS - title: qsTr("Check Smart-eID") - titleBarColor: Style.color.accent_smart - - onContinueClicked: { - if (result === SmartModel.SMART_READY) { - root.startAuth(); - } else { - push(checkSmartSuggestionView, { - "result": root.result - }); - } - } - - GText { - text: result === SmartModel.SMART_READY ? qsTr("You may now try the function: \"See my personal data\". Press the Continue button to do so now.") : "" - textStyle: Style.text.normal_highlight - visible: text !== "" - width: parent.width - } - Component { - id: checkSmartSuggestionView - CheckSmartSuggestionView { - onCancelClicked: root.cancelClicked() - onCheckDevice: root.checkDevice() - onRunSmartSetup: root.runSmartSetup() - } - } - ObjectModel { - id: resultModel - ResultEntry { - resultType: result !== SmartModel.SMART_UNAVAILABLE ? ResultView.Type.IsSuccess : ResultView.Type.IsError - text: resultType === ResultView.Type.IsSuccess ? - //: LABEL ANDROID IOS - qsTr("Supported") : - //: LABEL ANDROID IOS - qsTr("Not supported") - } - ResultEntry { - resultType: result === SmartModel.SMART_NO_PROVISIONING ? ResultView.Type.IsError : ResultView.Type.IsSuccess - text: resultType === ResultView.Type.IsSuccess ? - //: LABEL ANDROID IOS - qsTr("Prepared") : - //: LABEL ANDROID IOS - qsTr("Not prepared") - visible: result >= SmartModel.SMART_NO_PROVISIONING - } - ResultEntry { - resultType: result === SmartModel.SMART_NO_PERSONALIZATION ? ResultView.Type.IsError : ResultView.Type.IsSuccess - text: resultType === ResultView.Type.IsSuccess ? - //: LABEL ANDROID IOS - qsTr("Set up") : - //: LABEL ANDROID IOS - qsTr("Not set up") - visible: result >= SmartModel.SMART_NO_PERSONALIZATION - } - ResultEntry { - resultType: ResultView.Type.IsError - - //: LABEL ANDROID IOS - text: qsTr("Invalid") - visible: result === SmartModel.SMART_UNUSABLE - } - ResultEntry { - - //: LABEL ANDROID IOS - text: qsTr("Ready for use") - visible: result === SmartModel.SMART_READY - } - } -} diff --git a/resources/qml/Governikus/CheckSmartView/+mobile/CheckSmartView.qml b/resources/qml/Governikus/CheckSmartView/+mobile/CheckSmartView.qml deleted file mode 100644 index d4e2d78cd..000000000 --- a/resources/qml/Governikus/CheckSmartView/+mobile/CheckSmartView.qml +++ /dev/null @@ -1,103 +0,0 @@ -/** - * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.ProgressView 1.0 -import Governikus.SmartView 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.Type.ReaderPlugIn 1.0 -import Governikus.Type.ReaderScanEnabler 1.0 -import Governikus.Type.SmartModel 1.0 -import Governikus.Type.UiModule 1.0 -import Governikus.View 1.0 - -SectionPage { - id: root - signal checkDevice - signal runSmartSetup - signal startAuth - - sectionPageFlickable: contentItem - - //: LABEL ANDROID IOS - title: qsTr("Check Smart-eID") - titleBarColor: Style.color.accent_smart - - navigationAction: NavigationAction { - action: NavigationAction.Action.Back - - onClicked: pop() - } - - Component { - id: checkSmartEidResultView - CheckSmartResultView { - result: SmartModel.smartState - - onCancelClicked: { - setLockedAndHidden(false); - popAll(); - } - onCheckDevice: root.checkDevice() - onRunSmartSetup: root.runSmartSetup() - onStartAuth: root.startAuth() - } - } - GFlickableColumnLayout { - id: contentItem - - readonly property var maxIconHeight: Style.dimens.header_icon_size - readonly property var minIconHeight: Style.dimens.medium_icon_size - - anchors.fill: parent - maximumContentWidth: Style.dimens.max_text_width - minimumContentHeight: implicitContentHeight - (maxIconHeight - minIconHeight) - spacing: Constants.component_spacing - - TintableIcon { - Layout.alignment: Qt.AlignHCenter - Layout.fillHeight: true - Layout.maximumHeight: contentItem.maxIconHeight - Layout.minimumHeight: contentItem.minIconHeight - Layout.preferredHeight: contentItem.maxIconHeight - source: "qrc:///images/mobile/phone_smart.svg" - sourceSize.height: contentItem.maxIconHeight - tintEnabled: false - } - GPane { - Layout.alignment: Qt.AlignHCenter - Layout.fillWidth: true - - GText { - - //: LABEL ANDROID IOS - text: qsTr("Your device needs to meet the technical requirements to use the Smart-eID function.") - width: parent.width - } - GText { - - //: LABEL ANDROID IOS - text: qsTr("Check here if your device is suitable to set up a Smart-eID.") - width: parent.width - } - } - GSpacer { - Layout.fillHeight: true - } - GButton { - Layout.alignment: Qt.AlignHCenter - icon.source: "qrc:///images/mobile/device.svg" - - //: LABEL ANDROID IOS - text: qsTr("Start check") - - onClicked: { - setLockedAndHidden(); - push(checkSmartEidResultView); - } - } - } -} diff --git a/resources/qml/Governikus/CheckSmartView/qmldir b/resources/qml/Governikus/CheckSmartView/qmldir deleted file mode 100644 index 5fd6e585a..000000000 --- a/resources/qml/Governikus/CheckSmartView/qmldir +++ /dev/null @@ -1,6 +0,0 @@ -module CheckSmartView - -internal CheckSmartResultView CheckSmartResultView.qml -internal CheckSmartSuggestionView CheckSmartSuggestionView.qml - -CheckSmartView 1.0 CheckSmartView.qml diff --git a/resources/qml/Governikus/EnterPasswordView/+desktop/EnterPasswordView.qml b/resources/qml/Governikus/EnterPasswordView/+desktop/EnterPasswordView.qml index 076fd4631..c1be16178 100644 --- a/resources/qml/Governikus/EnterPasswordView/+desktop/EnterPasswordView.qml +++ b/resources/qml/Governikus/EnterPasswordView/+desktop/EnterPasswordView.qml @@ -1,16 +1,16 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.AuthModel 1.0 -import Governikus.Type.NumberModel 1.0 -import Governikus.Type.PasswordType 1.0 -import Governikus.Type.RemoteServiceModel 1.0 +import QtQuick +import QtQuick.Controls +import Governikus.Global +import Governikus.Style +import Governikus.View +import Governikus.Type.ApplicationModel +import Governikus.Type.AuthModel +import Governikus.Type.NumberModel +import Governikus.Type.PasswordType +import Governikus.Type.RemoteServiceModel SectionPage { id: baseItem @@ -18,49 +18,56 @@ SectionPage { property string accessibleContinueText property alias moreInformationText: moreInformation.text property int passwordType: NumberModel.passwordType - property alias statusIcon: statusIcon.source - signal passwordEntered(bool pWasNewPin) + signal passwordEntered(var pPasswordType) signal requestPasswordInfo Keys.onPressed: event => { event.accepted = numberField.handleKeyEvent(event.key, event.modifiers); } - onPasswordTypeChanged: numberField.inputConfirmation = "" onVisibleChanged: if (!visible) numberField.number = "" QtObject { id: d + function setPassword() { - if (!numberField.validInput) { - return; - } - let wasNewPin = false; - if (passwordType === PasswordType.PIN || passwordType === PasswordType.TRANSPORT_PIN || passwordType === PasswordType.SMART_PIN) { + let currentPasswordType = passwordType; // The passwordType binding changes once we set any PIN/CAN/whatever + switch (currentPasswordType) { + case PasswordType.PIN: + case PasswordType.TRANSPORT_PIN: + case PasswordType.SMART_PIN: NumberModel.pin = numberField.number; - } else if (passwordType === PasswordType.CAN) { + baseItem.passwordEntered(currentPasswordType); + break; + case PasswordType.NEW_SMART_PIN: + case PasswordType.NEW_PIN: + NumberModel.newPin = numberField.number; + mainText.forceActiveFocus(Qt.MouseFocusReason); + baseItem.passwordEntered(currentPasswordType); + break; + case PasswordType.NEW_SMART_PIN_CONFIRMATION: + case PasswordType.NEW_PIN_CONFIRMATION: + NumberModel.newPinConfirmation = numberField.number; + mainText.forceActiveFocus(Qt.MouseFocusReason); + baseItem.passwordEntered(currentPasswordType); + break; + case PasswordType.CAN: NumberModel.can = numberField.number; - } else if (passwordType === PasswordType.PUK) { + baseItem.passwordEntered(currentPasswordType); + break; + case PasswordType.PUK: NumberModel.puk = numberField.number; - } else if (passwordType === PasswordType.NEW_PIN || passwordType === PasswordType.NEW_SMART_PIN) { - if (numberField.inputConfirmation === "") { - numberField.inputConfirmation = numberField.number; - mainText.forceActiveFocus(Qt.MouseFocusReason); - } else { - NumberModel.newPin = numberField.number; - numberField.inputConfirmation = ""; - wasNewPin = true; - } - } else if (passwordType === PasswordType.REMOTE_PIN) { + baseItem.passwordEntered(currentPasswordType); + break; + case PasswordType.REMOTE_PIN: RemoteServiceModel.connectToRememberedServer(numberField.number); + baseItem.passwordEntered(currentPasswordType); + break; } numberField.number = ""; if (!visible) mainText.forceActiveFocus(Qt.MouseFocusReason); - if (numberField.inputConfirmation === "") { - baseItem.passwordEntered(wasNewPin); - } } } GText { @@ -68,44 +75,55 @@ SectionPage { anchors.bottom: retryCounter.top anchors.bottomMargin: Constants.component_spacing anchors.horizontalCenter: retryCounter.horizontalCenter - + font.bold: true //: LABEL DESKTOP text: qsTr("Attempts") visible: retryCounter.visible } - StatusIcon { + RetryCounter { id: retryCounter - //: LABEL DESKTOP - Accessible.name: qsTr("Remaining ID card PIN attempts: %1").arg(NumberModel.retryCounter) - Accessible.role: Accessible.StaticText - activeFocusOnTab: true + anchors.left: parent.left anchors.margins: height anchors.top: parent.top - contentBackgroundColor: Style.color.accent - height: Style.dimens.status_icon_small - text: NumberModel.retryCounter - textStyle: Style.text.title_inverse visible: NumberModel.retryCounter >= 0 && (passwordType === PasswordType.PIN || passwordType === PasswordType.SMART_PIN) - - FocusFrame { - } } - StatusIcon { - id: statusIcon + TintableAnimation { + id: animatedIcon + anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.top anchors.verticalCenterOffset: parent.height / 4 - borderEnabled: false - busy: true - height: Style.dimens.status_icon_large - source: AuthModel.readerImage + height: Style.dimens.header_icon_size + source: switch (passwordType) { + case PasswordType.TRANSPORT_PIN: + return "qrc:///images/transportpin_%1.webp".arg(Style.currentTheme.name); + case PasswordType.CAN: + return "qrc:///images/can.webp"; + case PasswordType.SMART_PIN: + case PasswordType.NEW_SMART_PIN: + case PasswordType.NEW_SMART_PIN_CONFIRMATION: + case PasswordType.NEW_PIN_CONFIRMATION: + case PasswordType.NEW_PIN: + case PasswordType.PIN: + return "qrc:///images/pin_person.webp"; + case PasswordType.PUK: + return "qrc:///images/puk_%1.webp".arg(Style.currentTheme.name); + case PasswordType.REMOTE_PIN: + return "qrc:///images/pairingCode.webp"; + default: + return ""; + } + tintColor: Style.color.control + tintEnabled: passwordType !== PasswordType.PUK && passwordType !== PasswordType.TRANSPORT_PIN + visible: source.toString() !== "" } GText { id: mainText + activeFocusOnTab: true anchors.horizontalCenter: parent.horizontalCenter - anchors.top: statusIcon.bottom + anchors.top: animatedIcon.bottom anchors.topMargin: Constants.component_spacing horizontalAlignment: Text.AlignHCenter @@ -116,20 +134,20 @@ SectionPage { //: LABEL DESKTOP passwordType === PasswordType.REMOTE_PIN ? qsTr("Enter pairing code") : //: LABEL DESKTOP - passwordType === PasswordType.NEW_PIN && numberField.inputConfirmation === "" ? qsTr("Enter new ID card PIN") : + passwordType === PasswordType.NEW_PIN ? qsTr("Enter new ID card PIN") : //: LABEL DESKTOP - passwordType === PasswordType.NEW_PIN ? qsTr("Confirm new ID card PIN") : + passwordType === PasswordType.NEW_PIN_CONFIRMATION ? qsTr("Confirm new ID card PIN") : //: LABEL DESKTOP passwordType === PasswordType.TRANSPORT_PIN ? qsTr("Enter Transport PIN") : //: LABEL DESKTOP passwordType === PasswordType.SMART_PIN ? qsTr("Enter Smart-eID PIN") : //: LABEL DESKTOP - (passwordType === PasswordType.NEW_SMART_PIN && numberField.inputConfirmation === "") ? qsTr("Enter new Smart-eID PIN") : + passwordType === PasswordType.NEW_SMART_PIN ? qsTr("Enter new Smart-eID PIN") : //: LABEL DESKTOP - (passwordType === PasswordType.NEW_SMART_PIN) ? qsTr("Confirm new Smart-eID PIN") : + passwordType === PasswordType.NEW_SMART_PIN_CONFIRMATION ? qsTr("Confirm new Smart-eID PIN") : //: LABEL DESKTOP qsTr("Enter ID card PIN") - textStyle: Style.text.header + textStyle: Style.text.headline visible: text !== "" width: Math.min(parent.width - (2 * Constants.pane_padding), Style.dimens.max_text_width) @@ -138,18 +156,16 @@ SectionPage { } GText { id: subText + activeFocusOnTab: true anchors.horizontalCenter: parent.horizontalCenter anchors.top: mainText.bottom anchors.topMargin: Constants.text_spacing + color: NumberModel.inputError !== "" ? Style.color.text_warning : Style.color.text horizontalAlignment: Text.AlignHCenter text: { - if (!numberField.confirmedInput) { - return passwordType === PasswordType.NEW_SMART_PIN ? - //: INFO DESKTOP The changed Smart-eID PIN was entered wrongfully during the confirmation process. - qsTr("The new Smart-eID PIN and the confirmation do not match. Please correct your input.") : - //: INFO DESKTOP The changed ID card PIN was entered wrongfully during the confirmation process. - qsTr("The new ID card PIN and the confirmation do not match. Please correct your input."); + if (NumberModel.inputError !== "") { + return NumberModel.inputError; } if (passwordType === PasswordType.TRANSPORT_PIN) { //: INFO DESKTOP The AA2 expects the Transport PIN with five digits. @@ -185,18 +201,20 @@ SectionPage { return qsTr("You have entered an incorrect, six-digit ID card PIN thrice, your ID card PIN is now blocked. To remove the block, the ten-digit PUK must be entered first."); } if (passwordType === PasswordType.NEW_PIN) { - return numberField.inputConfirmation === "" ? //: INFO DESKTOP A new six-digit ID card PIN needs to be supplied. - qsTr("Please enter a new six-digit ID card PIN now.") : + return qsTr("Please enter a new six-digit ID card PIN now."); + } + if (passwordType === PasswordType.NEW_PIN_CONFIRMATION) { //: INFO DESKTOP The new ID card PIN needs to be entered again for verification. - qsTr("Please confirm your new six-digit ID card PIN."); + return qsTr("Please confirm your new six-digit ID card PIN."); } if (passwordType === PasswordType.NEW_SMART_PIN) { - return numberField.inputConfirmation === "" ? //: INFO DESKTOP A new six-digit Smart-eID PIN needs to be supplied. - qsTr("Please enter a new six-digit Smart-eID PIN now.") : + return qsTr("Please enter a new six-digit Smart-eID PIN now."); + } + if (passwordType === PasswordType.NEW_SMART_PIN_CONFIRMATION) { //: INFO DESKTOP The new Smart-eID PIN needs to be confirmed. - qsTr("Please confirm your new six-digit Smart-eID PIN."); + return qsTr("Please confirm your new six-digit Smart-eID PIN."); } if (passwordType === PasswordType.REMOTE_PIN) { //: INFO DESKTOP The pairing code needs to be supplied. @@ -206,8 +224,6 @@ SectionPage { //: INFO DESKTOP Error message during PIN/CAN/PUK input procedure, the requested password type is unknown; internal error. return qsTr("Unknown password type:") + " " + passwordType; } - textFormat: Text.StyledText - textStyle: numberField.confirmedInput ? Style.text.header_secondary : Style.text.header_warning visible: text !== "" width: Math.min(parent.width - (2 * Constants.pane_padding), Style.dimens.max_text_width) @@ -216,33 +232,80 @@ SectionPage { } MoreInformationLink { id: moreInformation + anchors.horizontalCenter: parent.horizontalCenter anchors.top: subText.bottom - anchors.topMargin: Constants.component_spacing - visible: numberField.confirmedInput + anchors.topMargin: Constants.component_spacing * 3 + visible: text !== "" && passwordType !== PasswordType.REMOTE_PIN onClicked: baseItem.requestPasswordInfo() } Item { - anchors.bottom: button.top - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: moreInformation.bottom + RoundedRectangle { + id: numberFieldContainer + + anchors.centerIn: parent + borderColor: Style.color.border + height: numberField.height + Constants.component_spacing + width: numberField.width + 2 * Constants.component_spacing - NumberField { - id: numberField - passwordLength: passwordType === PasswordType.TRANSPORT_PIN ? 5 : passwordType === PasswordType.PUK ? 10 : passwordType === PasswordType.REMOTE_PIN ? 4 : 6 + NumberField { + id: numberField - onAccepted: d.setPassword() + anchors.centerIn: parent + passwordLength: passwordType === PasswordType.TRANSPORT_PIN ? 5 : passwordType === PasswordType.PUK ? 10 : passwordType === PasswordType.REMOTE_PIN ? 4 : 6 + + onAccepted: d.setPassword() + } + } + anchors { + bottom: parent.bottom + horizontalCenter: parent.horizontalCenter + top: moreInformation.bottom + } + NavigationButton { + id: button + + accessibleText: baseItem.accessibleContinueText !== "" ? baseItem.accessibleContinueText : + //: LABEL DESKTOP + passwordType === PasswordType.CAN ? qsTr("Send CAN") : + //: LABEL DESKTOP + passwordType === PasswordType.PUK ? qsTr("Send PUK") : + //: LABEL DESKTOP + passwordType === PasswordType.REMOTE_PIN ? qsTr("Send pairing code") : + //: LABEL DESKTOP + passwordType === PasswordType.NEW_PIN ? qsTr("Send new ID card PIN") : + //: LABEL DESKTOP + passwordType === PasswordType.NEW_PIN_CONFIRMATION ? qsTr("Confirm new ID card PIN") : + //: LABEL DESKTOP + passwordType === PasswordType.TRANSPORT_PIN ? qsTr("Send Transport PIN") : + //: LABEL DESKTOP + passwordType === PasswordType.SMART_PIN ? qsTr("Send Smart-eID PIN") : + //: LABEL DESKTOP + passwordType === PasswordType.NEW_SMART_PIN ? qsTr("Send new Smart-eID PIN") : + //: LABEL DESKTOP + passwordType === PasswordType.NEW_SMART_PIN_CONFIRMATION ? qsTr("Confirm new Smart-eID PIN") : + //: LABEL DESKTOP + qsTr("Send ID card PIN") + activeFocusOnTab: true + buttonType: NavigationButton.Type.Forward + enabled: numberField.validInput + size: Style.dimens.huge_icon_size + + onClicked: { + d.setPassword(); + } anchors { - centerIn: parent - horizontalCenterOffset: eyeWidth / 2 + left: numberFieldContainer.right + leftMargin: Constants.component_spacing * 2 + verticalCenter: numberFieldContainer.verticalCenter } } } NumberPad { anchors.bottom: parent.bottom - anchors.right: parent.right + anchors.left: parent.left deleteEnabled: numberField.number.length > 0 submitAccessibleText: button.accessibleText submitEnabled: numberField.validInput @@ -255,41 +318,4 @@ SectionPage { onDigitPressed: digit => numberField.append(digit) onSubmitPressed: d.setPassword() } - NavigationButton { - id: button - accessibleText: baseItem.accessibleContinueText !== "" ? baseItem.accessibleContinueText : - //: LABEL DESKTOP - passwordType === PasswordType.CAN ? qsTr("Send CAN") : - //: LABEL DESKTOP - passwordType === PasswordType.PUK ? qsTr("Send PUK") : - //: LABEL DESKTOP - passwordType === PasswordType.REMOTE_PIN ? qsTr("Send pairing code") : - //: LABEL DESKTOP - passwordType === PasswordType.NEW_PIN && numberField.inputConfirmation === "" ? qsTr("Send new ID card PIN") : - //: LABEL DESKTOP - passwordType === PasswordType.NEW_PIN ? qsTr("Confirm new ID card PIN") : - //: LABEL DESKTOP - passwordType === PasswordType.TRANSPORT_PIN ? qsTr("Send Transport PIN") : - //: LABEL DESKTOP - passwordType === PasswordType.SMART_PIN ? qsTr("Send Smart-eID PIN") : - //: LABEL DESKTOP - (passwordType === PasswordType.NEW_SMART_PIN && numberField.inputConfirmation === "") ? qsTr("Send new Smart-eID PIN") : - //: LABEL DESKTOP - (passwordType === PasswordType.NEW_SMART_PIN) ? qsTr("Confirm new Smart-eID PIN") : - //: LABEL DESKTOP - qsTr("Send ID card PIN") - activeFocusOnTab: true - buttonType: NavigationButton.Type.Forward - enabled: numberField.validInput - - onClicked: { - d.setPassword(); - } - - anchors { - bottom: parent.bottom - horizontalCenter: parent.horizontalCenter - margins: Constants.component_spacing - } - } } diff --git a/resources/qml/Governikus/EnterPasswordView/+desktop/NumberPad.qml b/resources/qml/Governikus/EnterPasswordView/+desktop/NumberPad.qml index 6f804921f..ab73e2b05 100644 --- a/resources/qml/Governikus/EnterPasswordView/+desktop/NumberPad.qml +++ b/resources/qml/Governikus/EnterPasswordView/+desktop/NumberPad.qml @@ -1,11 +1,10 @@ /** * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.SettingsModel 1.0 +import QtQuick +import Governikus.Global +import Governikus.Style +import Governikus.Type.SettingsModel Item { id: baseItem @@ -22,7 +21,7 @@ Item { id: d readonly property var numbers: { - var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; + let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; if (visible && SettingsModel.shuffleScreenKeyboard) { Utils.shuffle(numbers); } @@ -31,57 +30,57 @@ Item { } Rectangle { id: numPadContainer + anchors.bottom: parent.bottom - anchors.right: parent.right - border.color: Style.color.accent - border.width: Math.max(1, ApplicationModel.scaleFactor * 3) - color: Qt.darker(Style.color.background, 1.05) + anchors.left: parent.left + border.color: Style.color.control + border.width: Math.max(1, plugin.scaleFactor * 3) + color: Style.color.pane height: grid.height + 2 * Constants.pane_padding visible: SettingsModel.useScreenKeyboard width: grid.width + 2 * Constants.pane_padding Grid { id: grid + anchors.centerIn: parent columns: 3 spacing: Constants.component_spacing Repeater { id: numberRepeater + model: 9 NumberPadButton { text: d.numbers[index] - visualPrivacy: SettingsModel.visualPrivacy onClicked: baseItem.digitPressed(text) } } NumberPadButton { id: deleteButton - color: Constants.red + enabled: baseItem.deleteEnabled fontScale: 0.75 text: "C" - visualPrivacy: SettingsModel.visualPrivacy onClicked: baseItem.deletePressed() } NumberPadButton { id: zeroButton + text: d.numbers[9] - visualPrivacy: SettingsModel.visualPrivacy onClicked: baseItem.digitPressed(text) } NumberPadButton { id: submitButton + Accessible.name: submitAccessibleText !== "" ? submitAccessibleText : text - color: Constants.green enabled: baseItem.submitEnabled fontScale: 0.75 text: "OK" - visualPrivacy: SettingsModel.visualPrivacy onClicked: baseItem.submitPressed() } diff --git a/resources/qml/Governikus/EnterPasswordView/+desktop/NumberPadButton.qml b/resources/qml/Governikus/EnterPasswordView/+desktop/NumberPadButton.qml index e24f1e76e..fb833fdd1 100644 --- a/resources/qml/Governikus/EnterPasswordView/+desktop/NumberPadButton.qml +++ b/resources/qml/Governikus/EnterPasswordView/+desktop/NumberPadButton.qml @@ -1,79 +1,49 @@ /** * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 +import QtQuick +import QtQuick.Controls +import Governikus.Global +import Governikus.Style +import Governikus.View +import Governikus.Type.SettingsModel Button { id: control - property alias color: circle.color property real fontScale: 1 - property bool visualPrivacy: false + property bool visualPrivacy: SettingsModel.visualPrivacy height: (1.5 * contentItem.font.pixelSize) / fontScale padding: 0 - width: height + width: height / d.aspectRatio background: Rectangle { id: circle - border.color: Style.text.header.textColor - border.width: !visualPrivacy && control.focus ? Math.max(1, ApplicationModel.scaleFactor * 2) : 0 - color: Style.color.accent - radius: control.height / 2 - visible: control.enabled - Rectangle { - anchors.centerIn: parent - color: Constants.black - opacity: 0.1 - radius: height / 2 + border.color: Style.text.headline.textColor + border.width: !visualPrivacy && control.focus ? Math.max(1, plugin.scaleFactor * 2) : 0 + color: control.enabled ? (control.down && !visualPrivacy ? Style.color.control : Style.color.pane_sublevel) : Style.color.control_disabled + radius: Style.dimens.control_radius - SequentialAnimation on height { - alwaysRunToEnd: true - running: !visualPrivacy && control.pressed - - NumberAnimation { - from: 0 - to: background.height - } - PauseAnimation { - duration: 100 - } - PropertyAction { - value: 0 - } - } - SequentialAnimation on width { - alwaysRunToEnd: true - running: !visualPrivacy && control.pressed - - NumberAnimation { - from: 0 - to: background.width - } - PauseAnimation { - duration: 100 - } - PropertyAction { - value: 0 - } - } + MouseArea { + anchors.fill: parent + cursorShape: enabled ? Qt.PointingHandCursor : undefined } } contentItem: GText { - font.pixelSize: fontScale * ApplicationModel.scaleFactor * 50 + color: control.down && !visualPrivacy ? Style.color.control_pressed : textStyle.textColor + font.pixelSize: fontScale * Style.dimens.text_headline horizontalAlignment: Text.AlignHCenter text: control.text - textStyle: Style.text.header_inverse - verticalAlignment: Text.AlignVCenter - visible: control.enabled + textStyle: Style.text.headline } FocusFrame { } + QtObject { + id: d + + readonly property real aspectRatio: 0.7 + } } diff --git a/resources/qml/Governikus/EnterPasswordView/+mobile/EnterPasswordView.qml b/resources/qml/Governikus/EnterPasswordView/+mobile/EnterPasswordView.qml index 60219163d..6dbd7aaa8 100644 --- a/resources/qml/Governikus/EnterPasswordView/+mobile/EnterPasswordView.qml +++ b/resources/qml/Governikus/EnterPasswordView/+mobile/EnterPasswordView.qml @@ -1,303 +1,266 @@ /** * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.RemoteServiceModel 1.0 -import Governikus.Type.NumberModel 1.0 -import Governikus.Type.PasswordType 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.View +import Governikus.Type.ApplicationModel +import Governikus.Type.RemoteServiceModel +import Governikus.Type.NumberModel +import Governikus.Type.PasswordType -SectionPage { +FlickableSectionPage { id: baseItem property string accessibleContinueText property alias enableTransportPinLink: transportPinLink.visible - property bool isConfirmation: false + property string inputError property alias moreInformationText: moreInformation.text - property int passwordType: NumberModel.passwordType + required property int passwordType signal changePinLength - signal passwordEntered(bool pWasNewPin) + signal passwordEntered(var pPasswordType) signal requestPasswordInfo + fillWidth: true + Keys.onPressed: event => { event.accepted = pinField.handleKeyEvent(event.key, event.modifiers); } - onVisibleChanged: { - pinField.number = ""; - if (!isConfirmation) { - pinField.inputConfirmation = ""; - } - } + onVisibleChanged: pinField.number = "" QtObject { id: d + function setPassword() { - if (!pinField.validInput) { - return; - } switch (passwordType) { case PasswordType.PIN: case PasswordType.TRANSPORT_PIN: case PasswordType.SMART_PIN: NumberModel.pin = pinField.number; - baseItem.passwordEntered(false); + baseItem.passwordEntered(passwordType); break; case PasswordType.NEW_SMART_PIN: case PasswordType.NEW_PIN: - if (isConfirmation) { - NumberModel.newPin = pinField.number; - baseItem.passwordEntered(true); - } else { - pinField.inputConfirmation = pinField.number; - pinField.number = ""; - } - isConfirmation = !isConfirmation; + NumberModel.newPin = pinField.number; + baseItem.passwordEntered(passwordType); + break; + case PasswordType.NEW_SMART_PIN_CONFIRMATION: + case PasswordType.NEW_PIN_CONFIRMATION: + NumberModel.newPinConfirmation = pinField.number; + baseItem.passwordEntered(passwordType); break; case PasswordType.CAN: NumberModel.can = pinField.number; - baseItem.passwordEntered(false); + baseItem.passwordEntered(passwordType); break; case PasswordType.PUK: NumberModel.puk = pinField.number; - baseItem.passwordEntered(false); + baseItem.passwordEntered(passwordType); break; case PasswordType.REMOTE_PIN: RemoteServiceModel.connectToRememberedServer(pinField.number); - baseItem.passwordEntered(false); + baseItem.passwordEntered(passwordType); break; } pinField.number = ""; - if (!isConfirmation) { - pinField.inputConfirmation = ""; - } } } - ColumnLayout { - id: infoLayout + GridLayout { + id: grid - readonly property real remainingHeight: Math.max(0, infoLayout.height - (infoLayout.children.length - 1) * infoLayout.spacing - infoText.implicitHeight - infoText.Layout.topMargin - infoText.Layout.bottomMargin - mainText.implicitHeight - mainText.Layout.topMargin - mainText.Layout.bottomMargin) + readonly property bool isLandscape: width > Math.max(infoLayout.Layout.minimumWidth, pinField.Layout.preferredWidth) + separator.effectiveImplicitWidth + numberPad.implicitWidth - spacing: 0 + Layout.maximumHeight: Number.POSITIVE_INFINITY + Layout.maximumWidth: Number.POSITIVE_INFINITY + Layout.minimumWidth: Math.max(infoLayout.Layout.minimumWidth, numberPad.Layout.minimumWidth) + columnSpacing: 0 + flow: isLandscape ? GridLayout.LeftToRight : GridLayout.TopToBottom + rowSpacing: Constants.component_spacing - anchors { - bottom: numberPadLayout.top - bottomMargin: 0 - left: parent.left - margins: Constants.pane_padding - right: parent.right - top: parent.top - } - StatusIcon { - id: statusIcon + ColumnLayout { + id: infoLayout - readonly property real bottomMargin: Constants.component_spacing + Layout.alignment: Qt.AlignCenter + Layout.maximumWidth: Style.dimens.max_text_width + spacing: 0 - Layout.alignment: Qt.AlignHCenter - Layout.bottomMargin: Layout.preferredHeight > 0 ? bottomMargin : 0 - Layout.fillHeight: true - Layout.maximumHeight: Style.dimens.header_icon_size - Layout.maximumWidth: Layout.maximumHeight - Layout.preferredHeight: infoLayout.remainingHeight - bottomMargin >= Style.dimens.icon_size ? infoLayout.remainingHeight - bottomMargin : 0 - Layout.preferredWidth: Layout.preferredHeight - borderEnabled: false - busy: visible - source: { - switch (passwordType) { - case PasswordType.REMOTE_PIN: - return "qrc:///images/icon_remote_inactive.svg"; - case PasswordType.SMART_PIN: - case PasswordType.NEW_SMART_PIN: - return "qrc:///images/mobile/phone_smart.svg"; - default: - return "qrc:///images/mobile/phone_nfc_with_card.svg"; - } + GText { + Layout.alignment: Qt.AlignHCenter + horizontalAlignment: Text.AlignHCenter + + //: LABEL ANDROID IOS + text: passwordType === PasswordType.CAN ? qsTr("Enter CAN") : + //: LABEL ANDROID IOS + passwordType === PasswordType.PUK ? qsTr("Enter PUK") : + //: LABEL ANDROID IOS + passwordType === PasswordType.REMOTE_PIN ? qsTr("Enter pairing code") : + //: LABEL ANDROID IOS + passwordType === PasswordType.NEW_PIN ? qsTr("Enter new ID card PIN") : + //: LABEL ANDROID IOS + passwordType === PasswordType.NEW_PIN_CONFIRMATION ? qsTr("Confirm new ID card PIN") : + //: LABEL ANDROID IOS + passwordType === PasswordType.TRANSPORT_PIN ? qsTr("Enter Transport PIN") : + //: LABEL ANDROID IOS + passwordType === PasswordType.SMART_PIN ? qsTr("Enter Smart-eID PIN") : + //: LABEL ANDROID IOS + passwordType === PasswordType.NEW_SMART_PIN ? qsTr("Enter new Smart-eID PIN") : + //: LABEL ANDROID IOS + passwordType === PasswordType.NEW_SMART_PIN_CONFIRMATION ? qsTr("Confirm new Smart-eID PIN") : + //: LABEL ANDROID IOS + qsTr("Enter ID card PIN") + textStyle: Style.text.headline } - } - GText { - id: mainText - Layout.alignment: Qt.AlignHCenter - Layout.fillWidth: true - Layout.maximumWidth: Style.dimens.max_text_width - horizontalAlignment: Text.AlignHCenter + GText { + id: infoText - //: LABEL ANDROID IOS - text: passwordType === PasswordType.CAN ? qsTr("Enter CAN") : - //: LABEL ANDROID IOS - passwordType === PasswordType.PUK ? qsTr("Enter PUK") : - //: LABEL ANDROID IOS - passwordType === PasswordType.REMOTE_PIN ? qsTr("Enter pairing code") : - //: LABEL ANDROID IOS - (passwordType === PasswordType.NEW_PIN && !isConfirmation) ? qsTr("Enter new ID card PIN") : - //: LABEL ANDROID IOS - (passwordType === PasswordType.NEW_PIN && isConfirmation) ? qsTr("Confirm new ID card PIN") : - //: LABEL ANDROID IOS - passwordType === PasswordType.TRANSPORT_PIN ? qsTr("Enter Transport PIN") : - //: LABEL ANDROID IOS - passwordType === PasswordType.SMART_PIN ? qsTr("Enter Smart-eID PIN") : - //: LABEL ANDROID IOS - (passwordType === PasswordType.NEW_SMART_PIN && !isConfirmation) ? qsTr("Enter new Smart-eID PIN") : - //: LABEL ANDROID IOS - (passwordType === PasswordType.NEW_SMART_PIN && isConfirmation) ? qsTr("Confirm new Smart-eID PIN") : - //: LABEL ANDROID IOS - qsTr("Enter ID card PIN") - textStyle: Style.text.header_accent - } - GText { - id: infoText - Layout.alignment: Qt.AlignHCenter - Layout.fillHeight: true - Layout.fillWidth: true - Layout.maximumWidth: Style.dimens.max_text_width - Layout.minimumHeight: textStyle.textSize - Layout.topMargin: Constants.text_spacing - elide: Text.ElideRight - horizontalAlignment: Text.AlignHCenter - text: { - if (!pinField.confirmedInput) { - return passwordType === PasswordType.NEW_SMART_PIN ? - //: INFO ANDROID IOS The changed Smart-eID PIN was entered wrongfully during confirmation. - qsTr("The new Smart-eID PIN and the confirmation do not match. Please correct your input.") : - //: INFO ANDROID IOS The changed ID card PIN was entered wrongfully during confirmation. - qsTr("The new ID card PIN and the confirmation do not match. Please correct your input."); - } - if (!!NumberModel.inputError) { - return NumberModel.inputError; - } - if (passwordType === PasswordType.SMART_PIN && NumberModel.retryCounter === 1) { - //: INFO ANDROID IOS The wrong Smart-eID PIN was entered twice on the Smart-eID - return qsTr("You have entered an incorrect, six-digit Smart-eID PIN twice. An incorrect third attempt will invalidate your Smart-eID and you will have to set it up again."); - } - if (passwordType === PasswordType.CAN) { - if (NumberModel.isCanAllowedMode) { - //: INFO ANDROID IOS The user is required to enter the six-digit CAN in CAN-allowed authentication. - return qsTr("Please enter the six-digit Card Access Number (CAN). You can find it in the bottom right on the front of the ID card."); + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: Constants.text_spacing + elide: Text.ElideRight + horizontalAlignment: Text.AlignHCenter + maximumLineCount: 3 + text: { + if (!!inputError) { + return inputError; + } + if (passwordType === PasswordType.SMART_PIN && NumberModel.retryCounter === 1) { + //: INFO ANDROID IOS The wrong Smart-eID PIN was entered twice on the Smart-eID + return qsTr("You have entered an incorrect, six-digit Smart-eID PIN twice. After the next failed attempt you will no longer be able to use your Smart-eID and will need to set it up again."); + } + if (passwordType === PasswordType.CAN) { + if (NumberModel.isCanAllowedMode) { + //: INFO ANDROID IOS The user is required to enter the six-digit CAN in CAN-allowed authentication. + return qsTr("Please enter the six-digit Card Access Number (CAN). You can find it in the bottom right on the front of the ID card."); + } + //: INFO ANDROID IOS The wrong ID card PIN was entered twice, the third attempt requires the CAN for additional verification, hint where the CAN is found. + return qsTr("A wrong ID card PIN has been entered twice on your ID card. For a third attempt, please first enter the six-digit Card Access Number (CAN). You can find your CAN in the bottom right on the front of your ID card."); + } + if (passwordType === PasswordType.PUK) { + //: INFO ANDROID IOS The PUK is required to unlock the ID card since the wrong ID card PIN entered three times. + return qsTr("You have entered an incorrect, six-digit ID card PIN thrice, your ID card PIN is now blocked. To remove the block, the ten-digit PUK must be entered first."); + } + if (passwordType === PasswordType.NEW_PIN) { + //: INFO ANDROID IOS A new six-digit ID card PIN needs to be supplied. + return qsTr("Please enter a new six-digit ID card PIN now."); + } + if (passwordType === PasswordType.NEW_PIN_CONFIRMATION) { + //: INFO ANDROID IOS The new ID card PIN needs to be confirmed. + return qsTr("Please confirm your new six-digit ID card PIN."); + } + if (passwordType === PasswordType.NEW_SMART_PIN) { + //: INFO ANDROID IOS A new six-digit Smart-eID PIN needs to be supplied. + return qsTr("Please enter a new six-digit Smart-eID PIN now."); + } + if (passwordType === PasswordType.NEW_SMART_PIN_CONFIRMATION) { + //: INFO ANDROID IOS The new Smart-eID PIN needs to be confirmed. + return qsTr("Please confirm your new six-digit Smart-eID PIN."); + } + if (passwordType === PasswordType.TRANSPORT_PIN) { + //: INFO ANDROID IOS The Transport PIN is required by AA2, it needs to be change to an actual PIN. + return qsTr("Please enter the five-digit Transport PIN."); + } + if (passwordType === PasswordType.REMOTE_PIN) { + //: INFO ANDROID IOS The pairing code for the smartphone is required. + return qsTr("Enter the pairing code shown on the device you want to pair."); + } + if (passwordType === PasswordType.SMART_PIN) { + return ApplicationModel.currentWorkflow === ApplicationModel.WORKFLOW_CHANGE_PIN ? + //: INFO ANDROID IOS The AA2 expects the current Smart-eID PIN with six digits in a PIN change. + qsTr("Please enter your current six-digit Smart-eID PIN.") : + //: INFO ANDROID IOS The AA2 expects a Smart-eID PIN with six digits in an authentication. + qsTr("Please enter your six-digit Smart-eID PIN."); } - //: INFO ANDROID IOS The wrong ID card PIN was entered twice, the third attempt requires the CAN for additional verification, hint where the CAN is found. - return qsTr("A wrong ID card PIN has been entered twice on your ID card. For a third attempt, please first enter the six-digit Card Access Number (CAN). You can find your CAN in the bottom right on the front of your ID card."); - } - if (passwordType === PasswordType.PUK) { - //: INFO ANDROID IOS The PUK is required to unlock the ID card since the wrong ID card PIN entered three times. - return qsTr("You have entered an incorrect, six-digit ID card PIN thrice, your ID card PIN is now blocked. To remove the block, the ten-digit PUK must be entered first."); - } - if (passwordType === PasswordType.NEW_PIN) { - return isConfirmation ? - //: INFO ANDROID IOS The new ID card PIN needs to be confirmed. - qsTr("Please confirm your new six-digit ID card PIN.") : - //: INFO ANDROID IOS A new six-digit ID card PIN needs to be supplied. - qsTr("Please enter a new six-digit ID card PIN now."); - } - if (passwordType === PasswordType.NEW_SMART_PIN) { - return isConfirmation ? - //: INFO ANDROID IOS The new Smart-eID PIN needs to be confirmed. - qsTr("Please confirm your new six-digit Smart-eID PIN.") : - //: INFO ANDROID IOS A new six-digit Smart-eID PIN needs to be supplied. - qsTr("Please enter a new six-digit Smart-eID PIN now."); - } - if (passwordType === PasswordType.TRANSPORT_PIN) { - //: INFO ANDROID IOS The Transport PIN is required by AA2, it needs to be change to an actual PIN. - return qsTr("Please enter the five-digit Transport PIN."); - } - if (passwordType === PasswordType.REMOTE_PIN) { - //: INFO ANDROID IOS The pairing code for the smartphone is required. - return qsTr("Enter the pairing code shown on the device you want to pair."); - } - if (passwordType === PasswordType.SMART_PIN) { return ApplicationModel.currentWorkflow === ApplicationModel.WORKFLOW_CHANGE_PIN ? - //: INFO ANDROID IOS The AA2 expects the current Smart-eID PIN with six digits in a PIN change. - qsTr("Please enter your current six-digit Smart-eID PIN.") : - //: INFO ANDROID IOS The AA2 expects a Smart-eID PIN with six digits in an authentication. - qsTr("Please enter your six-digit Smart-eID PIN."); + //: INFO ANDROID IOS The AA2 expects the current ID card PIN with six digits in a PIN change. + qsTr("Please enter your current six-digit ID card PIN.") : + //: INFO ANDROID IOS The AA2 expects a ID card PIN with six digits in an authentication. + qsTr("Please enter your six-digit ID card PIN."); } - return ApplicationModel.currentWorkflow === ApplicationModel.WORKFLOW_CHANGE_PIN ? - //: INFO ANDROID IOS The AA2 expects the current ID card PIN with six digits in a PIN change. - qsTr("Please enter your current six-digit ID card PIN.") : - //: INFO ANDROID IOS The AA2 expects a ID card PIN with six digits in an authentication. - qsTr("Please enter your six-digit ID card PIN."); - } - textStyle: { - if (!pinField.confirmedInput || !!NumberModel.inputError || (passwordType === PasswordType.CAN && !NumberModel.isCanAllowedMode) || passwordType === PasswordType.PUK) { - return Style.text.normal_warning; - } else { - return Style.text.normal_secondary; + textStyle: { + if (!!inputError || (passwordType === PasswordType.CAN && !NumberModel.isCanAllowedMode) || passwordType === PasswordType.PUK) { + return Style.text.normal_warning; + } else { + return Style.text.normal; + } } - } - MouseArea { - anchors.fill: parent - anchors.margins: -12 - enabled: infoText.truncated + MouseArea { + anchors.fill: parent + anchors.margins: -12 + enabled: infoText.truncated - onClicked: completeTextPopup.open() + onClicked: completeTextPopup.open() + } } - } - } - ColumnLayout { - id: numberPadLayout - spacing: 0 + GSpacer { + Layout.fillHeight: true + visible: !grid.isLandscape + } + MoreInformationLink { + id: transportPinLink - anchors { - bottom: parent.bottom - left: parent.left - margins: Constants.pane_padding - right: parent.right - } - MoreInformationLink { - id: transportPinLink - Layout.alignment: Qt.AlignHCenter - Layout.maximumWidth: numberPadLayout.width - Layout.topMargin: Constants.text_spacing - text: (passwordType === PasswordType.TRANSPORT_PIN ? - //: LABEL ANDROID IOS Button to switch to a six-digit ID card PIN. - qsTr("Do you have a six-digit ID card PIN?") : - //: LABEL ANDROID IOS Button to start a change of the Transport PIN. - qsTr("Do you have a five-digit Transport PIN?")) - visible: false + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: Constants.text_spacing + text: (passwordType === PasswordType.TRANSPORT_PIN ? + //: LABEL ANDROID IOS Button to switch to a six-digit ID card PIN. + qsTr("Do you have a six-digit ID card PIN?") : + //: LABEL ANDROID IOS Button to start a change of the Transport PIN. + qsTr("Do you have a five-digit Transport PIN?")) + visible: false - onClicked: baseItem.changePinLength() - } - MoreInformationLink { - id: moreInformation - Layout.alignment: Qt.AlignHCenter - Layout.maximumWidth: numberPadLayout.width - Layout.topMargin: Constants.text_spacing + onClicked: baseItem.changePinLength() + } + MoreInformationLink { + id: moreInformation - onClicked: baseItem.requestPasswordInfo() - } - Rectangle { - Layout.alignment: Qt.AlignHCenter - Layout.fillWidth: true - Layout.maximumWidth: Math.min(parent.width, Layout.preferredWidth) - Layout.preferredHeight: pinField.implicitHeight + Constants.component_spacing - Layout.preferredWidth: pinField.implicitWidth + Constants.component_spacing - Layout.topMargin: Constants.component_spacing - border.color: Style.color.border - border.width: Style.dimens.separator_size - radius: Style.dimens.button_radius + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: Constants.text_spacing + visible: text !== "" && passwordType !== PasswordType.REMOTE_PIN + onClicked: baseItem.requestPasswordInfo() + } NumberField { id: pinField - passwordLength: passwordType === PasswordType.REMOTE_PIN ? 4 : passwordType === PasswordType.TRANSPORT_PIN ? 5 : passwordType === PasswordType.PUK ? 10 : 6 - onAccepted: d.setPassword() + Layout.alignment: Qt.AlignHCenter + Layout.fillWidth: true + Layout.topMargin: Constants.component_spacing + padding: Constants.component_spacing / 2 + passwordLength: passwordType === PasswordType.REMOTE_PIN ? 4 : passwordType === PasswordType.TRANSPORT_PIN ? 5 : passwordType === PasswordType.PUK ? 10 : 6 - anchors { - fill: parent - margins: Constants.text_spacing + background: Rectangle { + border.color: Style.color.border + border.width: Style.dimens.separator_size + color: Style.color.transparent + radius: Style.dimens.control_radius } + + onAccepted: d.setPassword() } } + GSeparator { + id: separator + + readonly property real effectiveImplicitWidth: Layout.leftMargin + implicitWidth + Layout.rightMargin + + Layout.alignment: Qt.AlignCenter + Layout.leftMargin: Constants.component_spacing + Layout.preferredHeight: grid.height * 0.75 + Layout.rightMargin: Constants.component_spacing + orientation: Qt.Vertical + visible: grid.isLandscape + } + GSpacer { + Layout.fillWidth: true + visible: grid.isLandscape + } NumberPad { id: numberPad - Layout.alignment: Qt.AlignHCenter - Layout.preferredHeight: height - Layout.preferredWidth: width - Layout.topMargin: Constants.component_spacing + + Layout.alignment: grid.isLandscape ? Qt.AlignCenter : Qt.AlignHCenter | Qt.AlignTop deleteEnabled: pinField.number.length > 0 submitAccessibleText: baseItem.accessibleContinueText !== "" ? baseItem.accessibleContinueText : //: LABEL ANDROID IOS @@ -307,17 +270,17 @@ SectionPage { //: LABEL ANDROID IOS passwordType === PasswordType.REMOTE_PIN ? qsTr("Send pairing code") : //: LABEL ANDROID IOS - (passwordType === PasswordType.NEW_PIN && !isConfirmation) ? qsTr("Send new ID card PIN") : + passwordType === PasswordType.NEW_PIN ? qsTr("Send new ID card PIN") : //: LABEL ANDROID IOS - (passwordType === PasswordType.NEW_PIN && isConfirmation) ? qsTr("Confirm new ID card PIN") : + passwordType === PasswordType.NEW_PIN_CONFIRMATION ? qsTr("Send confirmation of new ID card PIN") : //: LABEL ANDROID IOS passwordType === PasswordType.TRANSPORT_PIN ? qsTr("Send Transport PIN") : //: LABEL ANDROID IOS passwordType === PasswordType.SMART_PIN ? qsTr("Send Smart-eID PIN") : //: LABEL ANDROID IOS - (passwordType === PasswordType.NEW_SMART_PIN && !isConfirmation) ? qsTr("Send new Smart-eID PIN") : + passwordType === PasswordType.NEW_SMART_PIN ? qsTr("Send new Smart-eID PIN") : //: LABEL ANDROID IOS - (passwordType === PasswordType.NEW_SMART_PIN && isConfirmation) ? qsTr("Confirm new Smart-eID PIN") : + passwordType === PasswordType.NEW_SMART_PIN_CONFIRMATION ? qsTr("Send confirmation of new Smart-eID PIN") : //: LABEL ANDROID IOS qsTr("Send ID card PIN") submitEnabled: pinField.validInput @@ -330,9 +293,14 @@ SectionPage { onDigitPressed: digit => pinField.append(digit) onSubmitPressed: d.setPassword() } + GSpacer { + Layout.fillWidth: true + visible: grid.isLandscape + } } ConfirmationPopup { id: completeTextPopup + style: ConfirmationPopup.PopupStyle.OkButton text: infoText.text } diff --git a/resources/qml/Governikus/EnterPasswordView/+mobile/NumberPad.qml b/resources/qml/Governikus/EnterPasswordView/+mobile/NumberPad.qml index 4ec9fcbd1..e19fd180f 100644 --- a/resources/qml/Governikus/EnterPasswordView/+mobile/NumberPad.qml +++ b/resources/qml/Governikus/EnterPasswordView/+mobile/NumberPad.qml @@ -1,10 +1,10 @@ /** * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Type.SettingsModel 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Type.SettingsModel GridLayout { id: baseItem @@ -21,19 +21,15 @@ GridLayout { Accessible.description: qsTr("Number pad") Accessible.focusable: true Accessible.role: Accessible.Grouping - Layout.fillHeight: false - Layout.fillWidth: false columnSpacing: 10 columns: 3 - height: width rowSpacing: columnSpacing - width: 250 QtObject { id: d readonly property var numbers: { - var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; + let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; if (visible && SettingsModel.shuffleScreenKeyboard) { Utils.shuffle(numbers); } @@ -42,40 +38,48 @@ GridLayout { } Repeater { id: numberRepeater + model: 9 NumberPadButton { + Layout.fillHeight: true + Layout.fillWidth: true text: d.numbers[index] - visualPrivacy: SettingsModel.visualPrivacy onClicked: baseItem.digitPressed(text) } } NumberPadButton { + Layout.fillHeight: true + Layout.fillWidth: true + + //: LABEL ANDROID IOS A11y text for the "delete" button text when the button is disabled. a11yDisabledText: qsTr("Delete last digit, disabled until input is present.") enabled: baseItem.deleteEnabled icon.source: "qrc:///images/mobile/material_backspace.svg" text: qsTr("Delete last digit") - visualPrivacy: SettingsModel.visualPrivacy onClicked: baseItem.deletePressed() } NumberPadButton { Layout.column: 1 + Layout.fillHeight: true + Layout.fillWidth: true Layout.row: 3 text: d.numbers[9] - visualPrivacy: SettingsModel.visualPrivacy onClicked: baseItem.digitPressed(text) } NumberPadButton { + Layout.fillHeight: true + Layout.fillWidth: true + //: LABEL ANDROID IOS A11y text, appended onto the "submit" button text when the button is disabled. a11yDisabledText: a11yText + qsTr(", disabled until input is complete.") a11yText: submitAccessibleText !== "" ? submitAccessibleText : text enabled: baseItem.submitEnabled icon.source: "qrc:///images/material_check.svg" text: qsTr("Submit") - visualPrivacy: SettingsModel.visualPrivacy onClicked: baseItem.submitPressed() } diff --git a/resources/qml/Governikus/EnterPasswordView/+mobile/NumberPadButton.qml b/resources/qml/Governikus/EnterPasswordView/+mobile/NumberPadButton.qml index 39f23be88..c541dfe6b 100644 --- a/resources/qml/Governikus/EnterPasswordView/+mobile/NumberPadButton.qml +++ b/resources/qml/Governikus/EnterPasswordView/+mobile/NumberPadButton.qml @@ -1,69 +1,60 @@ /** * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.Type.SettingsModel Button { id: numberPadButton property string a11yDisabledText: qsTr("Disabled") property string a11yText - property bool visualPrivacy: false + property bool visualPrivacy: SettingsModel.visualPrivacy Accessible.name: numberPadButton.enabled ? a11yText !== "" ? a11yText : text : a11yDisabledText - Layout.fillHeight: true - Layout.fillWidth: true - implicitHeight: 36 - implicitWidth: 36 - - background: TintableIcon { - anchors.centerIn: numberPadButton - source: numberPadButton.icon.source - sourceSize.height: numberPadButton.implicitHeight - visible: numberPadButton.icon.source != "" && numberPadButton.enabled + Layout.maximumHeight: implicitHeight + Layout.maximumWidth: implicitWidth + Layout.minimumHeight: Layout.minimumWidth * d.aspectRatio + Layout.minimumWidth: 36 + implicitHeight: implicitWidth * d.aspectRatio + implicitWidth: 75 + + background: Rectangle { + anchors.fill: numberPadButton + color: numberPadButton.enabled ? (numberPadButton.down && !visualPrivacy ? Style.color.control : Style.color.pane_sublevel) : Style.color.control_disabled + radius: Style.dimens.control_radius + + TintableIcon { + anchors.centerIn: parent + fillMode: Image.Pad + source: numberPadButton.icon.source + sourceSize.height: contentItem.font.pixelSize * 1.5 + tintColor: numberPadButton.down && !visualPrivacy ? Style.color.control_pressed : contentText.textStyle.textColor + tintEnabled: true + visible: numberPadButton.icon.source != "" + } } contentItem: GText { + id: contentText + Accessible.ignored: true + color: numberPadButton.down && !visualPrivacy ? Style.color.control_pressed : textStyle.textColor horizontalAlignment: Text.AlignHCenter text: numberPadButton.text - textStyle: Style.text.title - verticalAlignment: Text.AlignVCenter - visible: numberPadButton.icon.source == "" && numberPadButton.enabled + textStyle: Style.text.headline + visible: numberPadButton.icon.source == "" } Accessible.onPressAction: if (numberPadButton.enabled) clicked() - Rectangle { - id: darkLayer - anchors.centerIn: parent - color: Constants.black - height: width - opacity: 0.1 - radius: width / 2 + QtObject { + id: d - NumberAnimation on opacity { - from: 0.1 - running: !visualPrivacy && !numberPadButton.down - to: 0.0 - } - SequentialAnimation on width { - alwaysRunToEnd: true - running: !visualPrivacy && numberPadButton.down - - PropertyAction { - property: "opacity" - target: darkLayer - value: 0.1 - } - NumberAnimation { - from: 0 - to: Math.SQRT2 * numberPadButton.width - } - } + readonly property real aspectRatio: 0.7 } } diff --git a/resources/qml/Governikus/FeedbackView/+desktop/DetachedLogView.qml b/resources/qml/Governikus/FeedbackView/+desktop/DetachedLogView.qml index b3457d1b6..dbe7eca83 100644 --- a/resources/qml/Governikus/FeedbackView/+desktop/DetachedLogView.qml +++ b/resources/qml/Governikus/FeedbackView/+desktop/DetachedLogView.qml @@ -1,24 +1,27 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.LogModel 1.0 -import Governikus.Type.LogFilterModel 1.0 -import Governikus.View 1.0 - -Item { +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.Type.LogModel +import Governikus.Type.LogFilterModel +import Governikus.View + +Rectangle { id: root + + color: Style.color.background + Keys.onPressed: event => { listView.handleKeyPress(event.key); } LogFilterModel { id: filterModel + } ColumnLayout { anchors.fill: parent @@ -32,13 +35,12 @@ Item { GText { activeFocusOnTab: true text: qsTr("Select log:") - textStyle: Style.text.normal FocusFrame { } } GComboBox { - Layout.preferredWidth: ApplicationModel.scaleFactor * 350 + Layout.preferredWidth: plugin.scaleFactor * 350 model: LogModel.logFileNames onCurrentIndexChanged: LogModel.setLogFile(currentIndex) @@ -46,16 +48,16 @@ Item { GText { activeFocusOnTab: true text: qsTr("Font size:") - textStyle: Style.text.normal FocusFrame { } } SpinBox { id: fontSize + from: 8 to: 20 - value: 10 + value: 12 } GButton { id: filterButton @@ -67,7 +69,7 @@ Item { qsTr("Filter. Activated.") : //: LABEL DESKTOP qsTr("Filter. Deactivated.") - icon.source: filter ? "qrc:///images/material_filter_off.svg" : "qrc:///images/material_filter.svg" + icon.source: filter ? "qrc:///images/filter_off.svg" : "qrc:///images/filter.svg" //: LABEL DESKTOP text: qsTr("Filter") tintIcon: true @@ -78,7 +80,7 @@ Item { Layout.fillWidth: true } GButton { - icon.source: "qrc:///images/desktop/material_save.svg" + icon.source: "qrc:///images/desktop/save_icon.svg" //: LABEL DESKTOP text: qsTr("Save log") tintIcon: true @@ -90,6 +92,7 @@ Item { GFileDialog { id: fileDialog + defaultSuffix: "log" //: LABEL DESKTOP nameFilters: qsTr("Logfiles (*.log)") @@ -119,7 +122,6 @@ Item { //: LABEL DESKTOP text: qsTr("Select level:") - textStyle: Style.text.normal FocusFrame { } @@ -154,7 +156,6 @@ Item { //: LABEL DESKTOP text: qsTr("Select category:") - textStyle: Style.text.normal FocusFrame { } @@ -167,6 +168,7 @@ Item { GRepeater { id: repeater + model: filterModel.categories delegate: GCheckBox { @@ -186,6 +188,7 @@ Item { } GListView { id: listView + Layout.bottomMargin: Constants.groupbox_spacing Layout.fillHeight: true Layout.fillWidth: true @@ -200,10 +203,6 @@ Item { font.pixelSize: fontSize.value width: listView.width - Constants.groupbox_spacing } - highlight: LogViewHighLight { - currentItem: listView.currentItem - textSize: fontSize.value - } Connections { function onFireNewLogMsg() { @@ -215,14 +214,15 @@ Item { } GText { activeFocusOnTab: true - anchors.centerIn: parent horizontalAlignment: Text.AlignHCenter //: INFO DESKTOP No log entries, placeholder text. text: qsTr("Currently there are no log entries matching your filter.") - textStyle: Style.text.normal_secondary visible: listView.count === 0 - width: Math.min(parent.width, contentWidth) + anchors { + fill: parent + rightMargin: Constants.groupbox_spacing + } FocusFrame { } } diff --git a/resources/qml/Governikus/FeedbackView/+desktop/LogView.qml b/resources/qml/Governikus/FeedbackView/+desktop/LogView.qml index 05f38a975..3fe52b51a 100644 --- a/resources/qml/Governikus/FeedbackView/+desktop/LogView.qml +++ b/resources/qml/Governikus/FeedbackView/+desktop/LogView.qml @@ -1,22 +1,21 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.LogModel 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.TitleBar +import Governikus.View +import Governikus.Type.LogModel SectionPage { id: root + signal keyPressed(int key) titleBarAction: TitleBarAction { - helpTopic: "applicationLog" //: LABEL DESKTOP text: qsTr("Logs") } @@ -27,10 +26,10 @@ SectionPage { TabbedPane { id: tabbedPane + anchors.fill: parent - anchors.margins: Constants.pane_padding - contentDelegate: logSectionDelegate - contentPadding: 0 + contentDelegate: logContentDelegate + contentRightMargin: 0 sectionsModel: LogModel.logFileNames footerItem: Item { @@ -38,6 +37,7 @@ SectionPage { ColumnLayout { id: buttonLayout + spacing: Constants.groupbox_spacing anchors { @@ -47,9 +47,10 @@ SectionPage { } GButton { id: saveLog - Layout.fillWidth: true + + Layout.maximumWidth: Number.POSITIVE_INFINITY enabled: tabbedPane.sectionsModel.length > 0 - icon.source: "qrc:///images/desktop/material_save.svg" + icon.source: "qrc:///images/desktop/save_icon.svg" //: LABEL DESKTOP text: qsTr("Save log") tintIcon: true @@ -61,6 +62,7 @@ SectionPage { GFileDialog { id: fileDialog + defaultSuffix: "log" //: LABEL DESKTOP nameFilters: qsTr("Logfiles (*.log)") @@ -73,10 +75,11 @@ SectionPage { } GButton { id: removeLog - Layout.fillWidth: true + + Layout.maximumWidth: Number.POSITIVE_INFINITY disabledTooltipText: qsTr("The current log will be automatically deleted at exit.") enableButton: tabbedPane.currentIndex > 0 - icon.source: "qrc:///images/material_delete.svg" + icon.source: "qrc:///images/desktop/trash_icon_white.svg" //: LABEL DESKTOP text: qsTr("Delete log") tintIcon: true @@ -88,9 +91,10 @@ SectionPage { } GButton { id: removeAllLogs - Layout.fillWidth: true + + Layout.maximumWidth: Number.POSITIVE_INFINITY enableButton: tabbedPane.sectionsModel.length > 1 - icon.source: "qrc:///images/trash_icon_all.svg" + icon.source: "qrc:///images/trash_icon_old.svg" //: LABEL DESKTOP text: qsTr("Delete old logs") tintIcon: true @@ -103,7 +107,7 @@ SectionPage { GButton { property QtObject detachedLogViewItem: null - Layout.fillWidth: true + Layout.maximumWidth: Number.POSITIVE_INFINITY icon.source: "qrc:///images/desktop/material_open_in_browser.svg" text: qsTr("Detach log viewer") tintIcon: true @@ -116,47 +120,67 @@ SectionPage { onCurrentIndexChanged: LogModel.setLogFile(currentIndex) } Component { - id: logSectionDelegate - Item { - height: tabbedPane.availableHeight - width: parent.width - - GListView { - id: logView - activeFocusOnTab: true - displayMarginBeginning: Constants.pane_padding - displayMarginEnd: Constants.pane_padding - model: LogModel - spacing: Constants.text_spacing - - delegate: LogViewDelegate { - width: logView.width - 2 * Constants.pane_padding - } - highlight: LogViewHighLight { - currentItem: logView.currentItem + id: logContentDelegate + + GListView { + id: logView + + activeFocusOnTab: true + displayMarginBeginning: Constants.pane_padding + displayMarginEnd: Constants.pane_padding + implicitHeight: tabbedPane.availableHeight + model: LogModel + + delegate: FocusScope { + readonly property bool isFirstItem: index === 0 + readonly property bool isLastItem: index === ListView.view.count - 1 + + implicitHeight: logDelegate.implicitHeight + logDelegate.anchors.topMargin + logDelegate.anchors.bottomMargin + width: logView.width - Constants.pane_padding + + RoundedRectangle { + anchors.fill: parent + bottomLeftCorner: isLastItem + bottomRightCorner: isLastItem + color: Style.color.pane + topLeftCorner: isFirstItem + topRightCorner: isFirstItem } + LogViewDelegate { + id: logDelegate - anchors { - bottomMargin: Constants.component_spacing - fill: parent - leftMargin: Constants.component_spacing - topMargin: Constants.component_spacing - } - Connections { - function onFireNewLogMsg() { - if (logView.atYEnd) - logView.positionViewAtEnd(); + focus: true + + anchors { + bottomMargin: isLastItem ? Constants.pane_padding : 0 + fill: parent + leftMargin: Constants.pane_padding + rightMargin: Constants.pane_padding + topMargin: isFirstItem ? Constants.pane_padding : Constants.text_spacing } + } + } - target: LogModel + layer { + enabled: GraphicsInfo.api !== GraphicsInfo.Software + + effect: GDropShadow { + } + } + Connections { + function onFireNewLogMsg() { + if (logView.atYEnd) + logView.positionViewAtEnd(); } - Connections { - function onKeyPressed(pKey) { - logView.handleKeyPress(pKey); - } - target: root + target: LogModel + } + Connections { + function onKeyPressed(pKey) { + logView.handleKeyPress(pKey); } + + target: root } } } @@ -174,7 +198,7 @@ SectionPage { qsTr("Delete old logs") : //: LABEL DESKTOP qsTr("Delete selected log")) - width: ApplicationModel.scaleFactor * 600 + width: plugin.scaleFactor * 600 onConfirmed: deleteAll ? LogModel.removeOtherLogFiles() : LogModel.removeCurrentLogFile() } diff --git a/resources/qml/Governikus/FeedbackView/+desktop/LogViewDelegate.qml b/resources/qml/Governikus/FeedbackView/+desktop/LogViewDelegate.qml index 84dc649ac..661274c31 100644 --- a/resources/qml/Governikus/FeedbackView/+desktop/LogViewDelegate.qml +++ b/resources/qml/Governikus/FeedbackView/+desktop/LogViewDelegate.qml @@ -1,25 +1,37 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Style 1.0 +import QtQuick +import QtQuick.Controls +import Governikus.Global +import Governikus.Style +import Governikus.Type.ApplicationModel -TextEdit { - readonly property var textStyle: Style.text.hint +GText { + id: root - Accessible.name: text - Accessible.role: Accessible.StaticText - color: level === "C" ? Style.color.warning_text : (level === "W" ? Style.color.accent : textStyle.textColor) - readOnly: true - selectByMouse: true - selectedTextColor: Style.color.primary_text_inverse - selectionColor: Style.color.accent + function copyTextToClipboard() { + ApplicationModel.setClipboardText(root.text); + //: INFO DESKTOP Toast message used to confirm the copy of a log entry. + ApplicationModel.showFeedback(qsTr("The log entry was copied to the clipboard.")); + } + + color: level === "C" ? Style.color.text_warning : (level === "W" ? Style.color.control : textStyle.textColor) + font.bold: activeFocus + font.family: plugin.fixedFontFamily text: "%1 %2".arg(origin).arg(message) textFormat: Text.PlainText wrapMode: Text.Wrap - font { - family: plugin.fixedFontFamily - pixelSize: textStyle.textSize + Action { + enabled: root.activeFocus + shortcut: StandardKey.Copy + + onTriggered: root.copyTextToClipboard() + } + MouseArea { + anchors.fill: parent + + onPressAndHold: root.copyTextToClipboard() } } diff --git a/resources/qml/Governikus/FeedbackView/+desktop/LogViewHighLight.qml b/resources/qml/Governikus/FeedbackView/+desktop/LogViewHighLight.qml deleted file mode 100644 index d0cdf99dc..000000000 --- a/resources/qml/Governikus/FeedbackView/+desktop/LogViewHighLight.qml +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2022-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQml 2.15 -import QtQuick 2.15 -import Governikus.Style 1.0 - -Item { - property var currentItem: null - property int textSize: Style.text.hint.textSize - - visible: currentItem ? currentItem.activeFocus : false - - Rectangle { - color: plugin.showFocusIndicator && currentItem ? currentItem.color : Style.color.transparent - height: width / 4 - width: textSize / 1.6 - - anchors { - left: parent.left - top: parent.top - topMargin: textSize - } - Timer { - interval: 500 - repeat: true - running: visible - - onTriggered: parent.opacity = parent.opacity ? 0 : 1 - } - } -} diff --git a/resources/qml/Governikus/FeedbackView/+mobile/+android/StoreFeedbackPopup.qml b/resources/qml/Governikus/FeedbackView/+mobile/+android/StoreFeedbackPopup.qml index bff56d3b1..10cae5e69 100644 --- a/resources/qml/Governikus/FeedbackView/+mobile/+android/StoreFeedbackPopup.qml +++ b/resources/qml/Governikus/FeedbackView/+mobile/+android/StoreFeedbackPopup.qml @@ -1,11 +1,11 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.ApplicationModel 1.0 +import QtQuick +import QtQuick.Controls +import Governikus.Global +import Governikus.Style +import Governikus.Type.ApplicationModel ConfirmationPopup { //: LABEL ANDROID @@ -15,7 +15,7 @@ ConfirmationPopup { //: INFO ANDROID Content of the app rating popup. text: qsTr("We would be very grateful if you could leave a rating on the Google Play Store!") //: INFO ANDROID Header of the app rating popup. - title: qsTr("Are you satisfied with AusweisApp2?") + title: qsTr("Are you satisfied with %1?").arg(Qt.application.name) onConfirmed: Qt.openUrlExternally(ApplicationModel.storeUrl) } diff --git a/resources/qml/Governikus/FeedbackView/+mobile/+ios/StoreFeedbackPopup.qml b/resources/qml/Governikus/FeedbackView/+mobile/+ios/StoreFeedbackPopup.qml index eb9d2625a..f187c9720 100644 --- a/resources/qml/Governikus/FeedbackView/+mobile/+ios/StoreFeedbackPopup.qml +++ b/resources/qml/Governikus/FeedbackView/+mobile/+ios/StoreFeedbackPopup.qml @@ -1,8 +1,8 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Type.ApplicationModel 1.0 +import QtQuick +import Governikus.Type.ApplicationModel Item { function open() { diff --git a/resources/qml/Governikus/FeedbackView/+mobile/LogTitleBarControls.qml b/resources/qml/Governikus/FeedbackView/+mobile/LogTitleBarControls.qml index 18156a11e..d28f74305 100644 --- a/resources/qml/Governikus/FeedbackView/+mobile/LogTitleBarControls.qml +++ b/resources/qml/Governikus/FeedbackView/+mobile/LogTitleBarControls.qml @@ -1,43 +1,43 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 +import QtQuick +import QtQuick.Controls +import Governikus.Global +import Governikus.Style +import Governikus.TitleBar Row { id: logControls property alias allowRemove: removeButton.visible property alias allowRemoveAll: removeAllButton.visible - readonly property int contentWidth: width signal remove signal removeAll signal share(point popupPosition) - anchors.verticalCenter: parent ? parent.verticalCenter : undefined - spacing: 18 + spacing: Constants.component_spacing - TitleBarButton { + TitleBarAction { Accessible.name: qsTr("Share log") - source: "qrc:///images/mobile/platform_specific_share.svg" + icon: "qrc:///images/mobile/share.svg" onClicked: logControls.share(mapToGlobal(width / 2, height)) } - TitleBarButton { + TitleBarAction { id: removeButton + Accessible.name: qsTr("Delete log") - source: "qrc:///images/material_delete.svg" + icon: "qrc:///images/trash_icon.svg" onClicked: logControls.remove() } - TitleBarButton { + TitleBarAction { id: removeAllButton + Accessible.name: qsTr("Delete all logs") - source: "qrc:///images/trash_icon_all.svg" + icon: "qrc:///images/trash_icon_old.svg" onClicked: logControls.removeAll() } diff --git a/resources/qml/Governikus/FeedbackView/+mobile/LogView.qml b/resources/qml/Governikus/FeedbackView/+mobile/LogView.qml index 59bd50ccf..3ca4d4e88 100644 --- a/resources/qml/Governikus/FeedbackView/+mobile/LogView.qml +++ b/resources/qml/Governikus/FeedbackView/+mobile/LogView.qml @@ -1,20 +1,20 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 -import Governikus.Type.LogModel 1.0 -import Governikus.Type.LogFilterModel 1.0 -import Governikus.Type.ApplicationModel 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.TitleBar +import Governikus.View +import Governikus.Type.LogModel +import Governikus.Type.LogFilterModel +import Governikus.Type.ApplicationModel SectionPage { id: root - sectionPageFlickable: logView + //: LABEL ANDROID IOS title: qsTr("Log") @@ -40,8 +40,14 @@ SectionPage { } } + Connections { + function onActivate() { + logView.highlightScrollbar(); + } + } LogFilterModel { id: filterModel + } ColumnLayout { anchors.fill: parent @@ -49,12 +55,14 @@ SectionPage { Rectangle { id: logSelector + Layout.fillWidth: true - Layout.preferredHeight: comboBox.height + Constants.text_spacing - color: Style.color.accent + Layout.preferredHeight: comboBox.height + Constants.pane_padding * 2 + color: Style.color.pane_sublevel GComboBox { id: comboBox + Accessible.description: qsTr("Select log from list.") model: LogModel.logFileNames @@ -62,13 +70,14 @@ SectionPage { anchors { left: parent.left - leftMargin: Constants.text_spacing + leftMargin: Constants.pane_padding right: filterButton.left - rightMargin: Constants.text_spacing + rightMargin: Constants.component_spacing top: parent.top + topMargin: Constants.pane_padding } } - TitleBarButton { + TitleBarAction { id: filterButton property bool filter: false @@ -76,13 +85,14 @@ SectionPage { Accessible.checked: filter Accessible.name: qsTr("Filter") Accessible.role: Accessible.CheckBox - source: filter ? "qrc:///images/material_filter_off.svg" : "qrc:///images/material_filter.svg" + icon: filter ? "qrc:///images/filter_off.svg" : "qrc:///images/filter.svg" + iconTintColor: comboBox.textStyle.textColor onClicked: filter = !filter anchors { - margins: Constants.text_spacing right: parent.right + rightMargin: Constants.pane_padding verticalCenter: comboBox.verticalCenter } } @@ -94,69 +104,70 @@ SectionPage { spacing: Constants.text_spacing visible: filterButton.filter - TitledSeparator { + GOptionsContainer { Layout.fillWidth: true - contentMarginLeft: 0 - contentMarginRight: 0 - contentMarginTop: 0 - + containerPadding: Constants.pane_padding + containerSpacing: Constants.groupbox_spacing //: LABEL ANDROID IOS title: qsTr("Filter") - } - GText { - //: LABEL ANDROID IOS - text: qsTr("Level") - textStyle: Style.text.normal_accent - } - GridLayout { - Layout.fillWidth: true - columnSpacing: Constants.groupbox_spacing - columns: (width + columnSpacing) / (levelRepeater.maxItemWidth + columnSpacing) - rowSpacing: Constants.groupbox_spacing - GRepeater { - id: levelRepeater - model: filterModel.levels + GText { + font.bold: true + //: LABEL ANDROID IOS + text: qsTr("Level") + textStyle: Style.text.subline + } + Grid { + columnSpacing: Constants.groupbox_spacing + columns: (width + columnSpacing) / (levelRepeater.maxItemWidth + columnSpacing) + rowSpacing: Constants.groupbox_spacing + width: parent.width + + GRepeater { + id: levelRepeater + + model: filterModel.levels - delegate: GCheckBox { - Layout.fillWidth: true - checked: filterModel.selectedLevels.indexOf(text) !== -1 - text: modelData + delegate: GCheckBox { + checked: filterModel.selectedLevels.indexOf(text) !== -1 + text: modelData + width: levelRepeater.maxItemWidth - onCheckedChanged: filterModel.configureLevel(text, checked) + onCheckedChanged: filterModel.configureLevel(text, checked) + } } } - } - GText { - //: LABEL ANDROID IOS - text: qsTr("Category") - textStyle: Style.text.normal_accent - } - GridLayout { - Layout.fillWidth: true - columnSpacing: Constants.groupbox_spacing - columns: (width + columnSpacing) / (categoryRepeater.maxItemWidth + columnSpacing) - rowSpacing: Constants.groupbox_spacing + GText { + font.bold: true + //: LABEL ANDROID IOS + text: qsTr("Category") + textStyle: Style.text.subline + } + Grid { + columnSpacing: Constants.groupbox_spacing + columns: (width + columnSpacing) / (categoryRepeater.maxItemWidth + columnSpacing) + rowSpacing: Constants.groupbox_spacing + width: parent.width - GRepeater { - id: categoryRepeater - model: filterModel.categories + GRepeater { + id: categoryRepeater - delegate: GCheckBox { - Layout.fillWidth: true - checked: filterModel.selectedCategories.indexOf(text) !== -1 - text: modelData + model: filterModel.categories - onCheckedChanged: filterModel.configureCategory(text, checked) + delegate: GCheckBox { + checked: filterModel.selectedCategories.indexOf(text) !== -1 + text: modelData + width: categoryRepeater.maxItemWidth + + onCheckedChanged: filterModel.configureCategory(text, checked) + } } } } - GSpacer { - Layout.fillHeight: true - } } GListView { id: logView + Layout.fillHeight: true Layout.fillWidth: true clip: true @@ -194,7 +205,6 @@ SectionPage { horizontalAlignment: Text.AlignHCenter //: INFO ANDROID IOS No log entries, placeholder text. text: qsTr("Currently there are no log entries matching your filter.") - textStyle: Style.text.normal_secondary visible: logView.count === 0 width: parent.width - 2 * Constants.component_spacing } diff --git a/resources/qml/Governikus/FeedbackView/qmldir b/resources/qml/Governikus/FeedbackView/qmldir index 58f7330c4..35b13ba16 100644 --- a/resources/qml/Governikus/FeedbackView/qmldir +++ b/resources/qml/Governikus/FeedbackView/qmldir @@ -2,7 +2,6 @@ module FeedbackView internal LogTitleBarControls LogTitleBarControls.qml internal LogViewDelegate LogViewDelegate.qml -internal LogViewHighLight LogViewHighLight.qml DetachedLogView 1.0 DetachedLogView.qml LogView 1.0 LogView.qml diff --git a/resources/qml/Governikus/Global/+desktop/ConfirmationPopup.qml b/resources/qml/Governikus/Global/+desktop/ConfirmationPopup.qml index cfe2a05ba..4e479fbc7 100644 --- a/resources/qml/Governikus/Global/+desktop/ConfirmationPopup.qml +++ b/resources/qml/Governikus/Global/+desktop/ConfirmationPopup.qml @@ -1,18 +1,17 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style BaseConfirmationPopup { id: root + buttons: Row { - bottomPadding: Constants.pane_padding layoutDirection: Qt.RightToLeft - rightPadding: Constants.pane_padding spacing: Constants.component_spacing width: parent.width diff --git a/resources/qml/Governikus/Global/+desktop/DecisionView.qml b/resources/qml/Governikus/Global/+desktop/DecisionView.qml index c55f7073e..c095b6a78 100644 --- a/resources/qml/Governikus/Global/+desktop/DecisionView.qml +++ b/resources/qml/Governikus/Global/+desktop/DecisionView.qml @@ -1,21 +1,20 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.View 1.0 -import Governikus.Style 1.0 -import Governikus.Type.ApplicationModel 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.View +import Governikus.Style +import Governikus.Type.ApplicationModel SectionPage { id: baseItem + enum ButtonStyle { NoButtons, AgreeButton, - DisagreeButton, - NeutralButton = 4, - AllButtons = 7 // Combination of all button values + DisagreeButton } property alias agreeButton: agreeButton @@ -25,8 +24,6 @@ SectionPage { property alias mainIconSource: image.source property alias moreInformationText: moreInformation.text property alias moreInformationVisible: moreInformation.visible - property alias neutralButton: neutralButton - property alias neutralText: neutralButton.subText property alias questionSubText: subTextElement.text property alias questionText: mainTextElement.text property int style: DecisionView.ButtonStyle.AgreeButton | DecisionView.ButtonStyle.DisagreeButton @@ -35,107 +32,98 @@ SectionPage { signal agree signal disagree signal moreInformationClicked - signal neutral activeFocusOnTab: false - TintableIcon { - id: image - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.top - anchors.verticalCenterOffset: baseItem.height / 4 - height: Style.dimens.status_icon_large - source: "qrc:///images/info.svg" - sourceSize.height: Style.dimens.status_icon_large - tintColor: Style.color.accent - } - GText { - id: mainTextElement - activeFocusOnTab: true - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.verticalCenter - horizontalAlignment: Text.AlignHCenter - textStyle: Style.text.header - verticalAlignment: Text.AlignVCenter - visible: mainTextElement.text !== "" - width: Math.min(parent.width - (2 * Constants.pane_padding), Style.dimens.max_text_width) - - onLinkActivated: baseItem.mainTextLinkActivated() - - FocusFrame { - } - } - GText { - id: subTextElement - activeFocusOnTab: true - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: mainTextElement.bottom - anchors.topMargin: Constants.text_spacing - horizontalAlignment: Text.AlignHCenter - textStyle: Style.text.header_secondary - verticalAlignment: Text.AlignVCenter - visible: subTextElement.text !== "" - width: Math.min(parent.width - (2 * Constants.pane_padding), Style.dimens.max_text_width) - - onLinkActivated: baseItem.subTextLinkActivated() - - FocusFrame { - } - } - MoreInformationLink { - id: moreInformation - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: subTextElement.bottom - anchors.topMargin: Constants.component_spacing - visible: false - - onClicked: baseItem.moreInformationClicked() - } - RowLayout { - anchors { - bottom: parent.bottom - left: parent.left - margins: Constants.component_spacing - right: parent.right + ColumnLayout { + anchors.fill: parent + anchors.margins: Constants.pane_padding + spacing: Constants.component_spacing + + TintableIcon { + id: image + + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: Constants.pane_padding + source: "qrc:///images/info.svg" + sourceSize.height: Style.dimens.header_icon_size + tintColor: Style.color.control } - NavigationButton { - id: disagreeButton - Layout.fillWidth: true - Layout.preferredWidth: baseItem.width / 3 + GText { + id: mainTextElement + + Layout.alignment: Qt.AlignHCenter + Layout.maximumWidth: Style.dimens.max_text_width activeFocusOnTab: true - buttonType: NavigationButton.Type.Cancel + horizontalAlignment: Qt.AlignHCenter + textStyle: Style.text.headline + visible: mainTextElement.text !== "" - //: LABEL DESKTOP - subText: qsTr("No") - visible: style & DecisionView.ButtonStyle.DisagreeButton + onLinkActivated: baseItem.mainTextLinkActivated() - onClicked: baseItem.disagree() + FocusFrame { + } } - NavigationButton { - id: neutralButton - Layout.fillWidth: true - Layout.preferredWidth: baseItem.width / 3 + GText { + id: subTextElement + + Layout.alignment: Qt.AlignHCenter + Layout.maximumWidth: Style.dimens.max_text_width + Layout.topMargin: Constants.text_spacing activeFocusOnTab: true - buttonType: NavigationButton.Type.Check + horizontalAlignment: Qt.AlignHCenter + textStyle: Style.text.subline + visible: subTextElement.text !== "" - //: LABEL DESKTOP - subText: qsTr("Maybe") - visible: style & DecisionView.ButtonStyle.NeutralButton + onLinkActivated: baseItem.subTextLinkActivated() - onClicked: baseItem.neutral() + FocusFrame { + } } - NavigationButton { - id: agreeButton - Layout.fillWidth: true - Layout.preferredWidth: baseItem.width / 3 - activeFocusOnTab: true - buttonType: NavigationButton.Type.Check + MoreInformationLink { + id: moreInformation - //: LABEL DESKTOP - subText: qsTr("Yes") - visible: style & DecisionView.ButtonStyle.AgreeButton + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: Constants.component_spacing + visible: false - onClicked: baseItem.agree() + onClicked: baseItem.moreInformationClicked() + } + GSpacer { + Layout.fillHeight: true + } + RowLayout { + Layout.alignment: Qt.AlignHCenter + Layout.bottomMargin: Style.dimens.huge_icon_size + Layout.topMargin: Constants.component_spacing + spacing: Style.dimens.huge_icon_size + + NavigationButton { + id: disagreeButton + + activeFocusOnTab: true + buttonType: NavigationButton.Type.Cancel + size: Style.dimens.huge_icon_size + + //: LABEL DESKTOP + subText: qsTr("No") + visible: style & DecisionView.ButtonStyle.DisagreeButton + + onClicked: baseItem.disagree() + } + NavigationButton { + id: agreeButton + + activeFocusOnTab: true + buttonType: NavigationButton.Type.Check + size: Style.dimens.huge_icon_size + + //: LABEL DESKTOP + subText: qsTr("Yes") + visible: style & DecisionView.ButtonStyle.AgreeButton + + onClicked: baseItem.agree() + } } } } diff --git a/resources/qml/Governikus/Global/+desktop/GFileDialog.qml b/resources/qml/Governikus/Global/+desktop/GFileDialog.qml index 14d531125..c25107d1f 100644 --- a/resources/qml/Governikus/Global/+desktop/GFileDialog.qml +++ b/resources/qml/Governikus/Global/+desktop/GFileDialog.qml @@ -1,8 +1,8 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Qt.labs.platform 1.1 as Labs +import QtQuick +import Qt.labs.platform as Labs Labs.FileDialog { function selectFile(pDefaultFilename) { diff --git a/resources/qml/Governikus/Global/+desktop/GPane.qml b/resources/qml/Governikus/Global/+desktop/GPane.qml index a5aec4dfa..d72ea36f0 100644 --- a/resources/qml/Governikus/Global/+desktop/GPane.qml +++ b/resources/qml/Governikus/Global/+desktop/GPane.qml @@ -1,23 +1,19 @@ /** * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.View 1.0 -import Governikus.Style 1.0 -import Governikus.Type.ApplicationModel 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.View +import Governikus.Style +import Governikus.Type.ApplicationModel -Item { +GPaneBackground { id: root - readonly property int availableContentHeight: { - var availableHeight = height - containerCol.topPadding - containerCol.bottomPadding; - if (title === "") { - return availableHeight; - } - return availableHeight - titleText.height - containerCol.spacing; - } property alias content: paneContent default property alias data: paneContent.data + property bool drawShadow: true + property alias spacing: paneContent.spacing property alias title: titleText.text property alias titleTextStyle: titleText.textStyle @@ -28,11 +24,15 @@ Item { implicitHeight: containerCol.implicitHeight implicitWidth: containerCol.implicitWidth - GPaneBackground { - anchors.fill: parent + layer { + enabled: GraphicsInfo.api !== GraphicsInfo.Software && drawShadow + + effect: GDropShadow { + } } Column { id: containerCol + anchors.left: parent.left anchors.leftMargin: Constants.pane_padding anchors.right: parent.right @@ -43,17 +43,19 @@ Item { GText { id: titleText + elide: Text.ElideRight maximumLineCount: 1 - textStyle: Style.text.header_accent - width: Math.min(parent.width, implicitWidth) + textStyle: Style.text.subline + width: Math.min(parent.width, Math.ceil(implicitWidth)) FocusFrame { scope: root } } - Column { + ColumnLayout { id: paneContent + spacing: Constants.pane_spacing width: parent.width } diff --git a/resources/qml/Governikus/Global/+desktop/Hint.qml b/resources/qml/Governikus/Global/+desktop/Hint.qml new file mode 100644 index 000000000..8e5f97057 --- /dev/null +++ b/resources/qml/Governikus/Global/+desktop/Hint.qml @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.View + +GPane { + id: root + + property alias buttonIconSource: hintButton.icon.source + property alias buttonText: hintButton.text + property alias buttonTooltip: hintButton.enabledTooltipText + property alias text: hintText.text + + signal clicked + + color: Style.color.pane_sublevel + drawShadow: false + spacing: 0 + //: LABEL DESKTOP + title: qsTr("Hint") + + GText { + id: hintText + + Layout.topMargin: Constants.text_spacing + activeFocusOnTab: true + visible: text !== "" + + FocusFrame { + } + } + GButton { + id: hintButton + + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: Constants.component_spacing + icon.source: "qrc:///images/open_website.svg" + iconSize: Style.dimens.small_icon_size + tintIcon: hintText.color + visible: text !== "" + + onClicked: root.clicked() + } +} diff --git a/resources/qml/Governikus/Global/+desktop/LocationButton.qml b/resources/qml/Governikus/Global/+desktop/LocationButton.qml new file mode 100644 index 000000000..ad31089ef --- /dev/null +++ b/resources/qml/Governikus/Global/+desktop/LocationButton.qml @@ -0,0 +1,53 @@ +/** + * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.View +import Governikus.Type.ApplicationModel +import Governikus.Type.SettingsModel + +GButton { + id: root + + property alias image: icon.source + property string language + readonly property bool selected: SettingsModel.language === language + + Accessible.checkable: true + Accessible.checked: selected + Layout.maximumWidth: Number.POSITIVE_INFINITY + cursorShape: selected ? Qt.ArrowCursor : Qt.PointingHandCursor + padding: Constants.groupbox_spacing + + background: RoundedRectangle { + color: root.selected ? Style.color.pane_active : Style.color.pane + + FocusFrame { + borderColor: Style.color.control_border + marginFactor: 0.8 + radius: parent.radius * 1.2 + scope: root + } + } + contentItem: ColumnLayout { + spacing: Constants.component_spacing + + Image { + id: icon + + Layout.alignment: Qt.AlignHCenter + sourceSize.height: Style.dimens.icon_size + } + GText { + Layout.alignment: Qt.AlignHCenter + color: selected ? Style.color.control_content : Style.color.text + text: root.text + } + } + + onClicked: SettingsModel.language = language +} diff --git a/resources/qml/Governikus/Global/+desktop/NavigationButton.qml b/resources/qml/Governikus/Global/+desktop/NavigationButton.qml index 61955d06d..6277ca865 100644 --- a/resources/qml/Governikus/Global/+desktop/NavigationButton.qml +++ b/resources/qml/Governikus/Global/+desktop/NavigationButton.qml @@ -1,15 +1,15 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Style 1.0 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Style +import Governikus.View Button { id: control + enum Type { Forward, Back, @@ -21,6 +21,7 @@ Button { property int buttonType: NavigationButton.Type.Forward property string iconSource property string iconText + property double size: plugin.scaleFactor * 160 property string subText Accessible.name: accessibleText !== "" ? accessibleText : text @@ -36,15 +37,17 @@ Button { ColumnLayout { id: column + anchors.fill: parent spacing: Constants.component_spacing Rectangle { id: icon + Layout.alignment: Qt.AlignHCenter Layout.preferredHeight: Layout.preferredWidth - Layout.preferredWidth: ApplicationModel.scaleFactor * 160 - color: enabled ? Style.color.button : Style.color.button_disabled + Layout.preferredWidth: control.size + color: enabled ? Style.color.control : Style.color.control_disabled radius: height / 2 TintableIcon { @@ -60,22 +63,22 @@ Button { return buttonType === NavigationButton.Type.Check ? "qrc:///images/material_check.svg" : buttonType === NavigationButton.Type.Cancel ? "qrc:///images/material_clear.svg" : "qrc:///images/desktop/material_arrow_forward.svg"; } sourceSize.height: Style.dimens.large_icon_size - tintColor: Style.color.button_text - transformOrigin: Item.Center + tintColor: Style.color.control_content } GText { anchors.centerIn: parent text: iconText - textStyle: Style.text.title_inverse + textStyle: Style.text.headline visible: iconText !== "" } } GText { id: buttonText - Layout.fillWidth: true + + Layout.alignment: Qt.AlignHCenter horizontalAlignment: Text.AlignHCenter text: control.subText - textStyle: Style.text.header + textStyle: Style.text.headline visible: control.subText !== "" } } diff --git a/resources/qml/Governikus/Global/+desktop/PlatformConstants.qml b/resources/qml/Governikus/Global/+desktop/PlatformConstants.qml index 508253088..4f862f71e 100644 --- a/resources/qml/Governikus/Global/+desktop/PlatformConstants.qml +++ b/resources/qml/Governikus/Global/+desktop/PlatformConstants.qml @@ -1,14 +1,14 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Type.ApplicationModel 1.0 +import QtQuick Item { - readonly property int component_spacing: ApplicationModel.scaleFactor * 30 - readonly property int groupbox_spacing: ApplicationModel.scaleFactor * 20 + readonly property int component_spacing: plugin.scaleFactor * 30 + readonly property int groupbox_spacing: plugin.scaleFactor * 20 readonly property bool is_desktop: true - readonly property int pane_padding: ApplicationModel.scaleFactor * 30 - readonly property int pane_spacing: ApplicationModel.scaleFactor * 30 - readonly property int text_spacing: ApplicationModel.scaleFactor * 10 + readonly property int pane_padding: plugin.scaleFactor * 30 + readonly property int pane_spacing: plugin.scaleFactor * 30 + readonly property int subtext_spacing: Math.max(1, plugin.scaleFactor * 3) + readonly property int text_spacing: plugin.scaleFactor * 10 } diff --git a/resources/qml/Governikus/Global/+desktop/RetryCounter.qml b/resources/qml/Governikus/Global/+desktop/RetryCounter.qml new file mode 100644 index 000000000..50cddcdbd --- /dev/null +++ b/resources/qml/Governikus/Global/+desktop/RetryCounter.qml @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick +import QtQuick.Controls +import Governikus.Global +import Governikus.Style +import Governikus.Type.NumberModel +import Governikus.View + +Rectangle { + //: LABEL DESKTOP + Accessible.name: qsTr("Remaining ID card PIN attempts: %1").arg(iconText.text) + Accessible.role: Accessible.StaticText + activeFocusOnTab: true + border.color: Style.color.control + border.width: height / 40 + color: Style.color.transparent + implicitHeight: Style.dimens.status_icon_small + implicitWidth: implicitHeight + radius: height / 2 + width: height + + Rectangle { + id: content + + anchors.fill: parent + anchors.margins: parent.height / 8 + border.color: Style.color.pane_border + border.width: Style.dimens.border_width + color: Style.color.control + radius: height / 2 + + GText { + id: iconText + + Accessible.ignored: true + anchors.centerIn: parent + color: Style.color.control_content + text: NumberModel.retryCounter + textStyle: Style.text.headline + visible: text !== "" + } + } + FocusFrame { + } +} diff --git a/resources/qml/Governikus/Global/+desktop/ScrollGradients.qml b/resources/qml/Governikus/Global/+desktop/ScrollGradients.qml index e7e173642..5a0c304fa 100644 --- a/resources/qml/Governikus/Global/+desktop/ScrollGradients.qml +++ b/resources/qml/Governikus/Global/+desktop/ScrollGradients.qml @@ -1,9 +1,9 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import Governikus.Global +import Governikus.Style Item { id: baseItem diff --git a/resources/qml/Governikus/Global/+desktop/ScrollablePane.qml b/resources/qml/Governikus/Global/+desktop/ScrollablePane.qml index c3cfa33ec..392cedc29 100644 --- a/resources/qml/Governikus/Global/+desktop/ScrollablePane.qml +++ b/resources/qml/Governikus/Global/+desktop/ScrollablePane.qml @@ -1,24 +1,27 @@ /** * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.View +import Governikus.Type.ApplicationModel Item { id: root + property alias backgroundColor: background.color property alias content: paneContent default property alias data: paneContent.data + property bool enableDropShadow: false + property real minimumVisibleContentHeight: 0 property alias title: titleText.text function scrollYPositionIntoView(pYposition) { - var availableFlickableHeight = flickable.height - paneContent.anchors.margins; - var dy = pYposition - flickable.contentY - availableFlickableHeight; + let availableFlickableHeight = flickable.height - paneContent.anchors.margins; + let dy = pYposition - flickable.contentY - availableFlickableHeight; if (dy > 0 || flickable.contentY > 0) { flickable.contentY += dy; if (flickable.contentY < 0) @@ -31,57 +34,75 @@ Item { Accessible.focusable: true Accessible.name: titleText.text Accessible.role: Accessible.Grouping - implicitHeight: flickable.contentHeight + 2 * Constants.pane_padding + Layout.minimumHeight: content.Layout.minimumHeight + 2 * content.anchors.margins + implicitHeight: content.implicitHeight + 2 * content.anchors.margins + implicitWidth: content.implicitWidth + 2 * content.anchors.margins - Rectangle { + GPaneBackground { id: background + anchors.fill: parent - border.color: Style.color.high_contrast_item_border - border.width: Style.dimens.high_contrast_item_border - color: Style.color.background_pane - radius: Style.dimens.corner_radius + + layer { + enabled: GraphicsInfo.api !== GraphicsInfo.Software && enableDropShadow + + effect: GDropShadow { + } + } } - Item { + ColumnLayout { + id: content + anchors.fill: parent - anchors.margins: Style.dimens.high_contrast_item_border + anchors.margins: Style.dimens.border_width clip: true GFlickable { id: flickable - anchors.bottomMargin: Constants.pane_padding - anchors.fill: parent - anchors.leftMargin: Constants.pane_padding - anchors.topMargin: Constants.pane_padding + + readonly property real reservedTitleHeight: (root.title === "" ? 0 : titleText.height + Constants.pane_spacing) + + Layout.alignment: Qt.AlignTop + Layout.bottomMargin: Constants.pane_padding + Layout.fillHeight: true + Layout.fillWidth: true + Layout.leftMargin: Constants.pane_padding + Layout.maximumHeight: contentHeight + Layout.minimumHeight: root.minimumVisibleContentHeight ? reservedTitleHeight + root.minimumVisibleContentHeight : -1 + Layout.preferredHeight: contentColumn.implicitHeight + Layout.topMargin: Constants.pane_padding contentHeight: contentColumn.implicitHeight - Column { + ColumnLayout { id: contentColumn + anchors.fill: parent anchors.rightMargin: Constants.pane_padding spacing: Constants.pane_spacing GText { id: titleText + elide: Text.ElideRight - textStyle: Style.text.header_accent + textStyle: Style.text.headline visible: text !== "" - width: parent.width FocusFrame { scope: root } } - Column { + ColumnLayout { id: paneContent + + Layout.fillWidth: true spacing: Constants.pane_spacing - width: parent.width } } } - ScrollGradients { - anchors.fill: parent - anchors.margins: Style.dimens.high_contrast_item_border - color: background.color - } + } + ScrollGradients { + anchors.fill: parent + anchors.margins: Style.dimens.border_width + color: background.color } } diff --git a/resources/qml/Governikus/Global/+desktop/SearchBar.qml b/resources/qml/Governikus/Global/+desktop/SearchBar.qml deleted file mode 100644 index a4ad1a860..000000000 --- a/resources/qml/Governikus/Global/+desktop/SearchBar.qml +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 - -GTextField { - id: searchField - function clear() { - searchField.text = ""; - searchField.forceActiveFocus(Qt.MouseFocusReason); - } - - Accessible.name: placeholderText - isOnLightBackground: false - leftPadding: glassIcon.width + Constants.groupbox_spacing - //: LABEL DESKTOP - placeholderText: qsTr("Search") - rightPadding: iconItem.width + Constants.groupbox_spacing - textStyle: Style.text.normal - width: 400 * ApplicationModel.scaleFactor - - TintableIcon { - id: glassIcon - anchors.left: parent.left - anchors.leftMargin: parent.height / 8 - anchors.verticalCenter: parent.verticalCenter - source: "qrc:///images/material_search.svg" - sourceSize.height: parent.height - 2 * anchors.leftMargin - sourceSize.width: height - tintColor: Style.color.primary_text - } - TintableIcon { - id: iconItem - Accessible.name: qsTr("Clear") - Accessible.role: Accessible.Button - activeFocusOnTab: true - anchors.right: parent.right - anchors.rightMargin: parent.height / 8 - anchors.verticalCenter: parent.verticalCenter - source: "qrc:///images/material_close.svg" - sourceSize.height: parent.height - 2 * anchors.rightMargin - sourceSize.width: height - tintColor: Style.color.accent - visible: parent.displayText !== "" - - Keys.onSpacePressed: searchField.clear() - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - - onClicked: searchField.clear() - } - FocusFrame { - marginFactor: 0.1 - } - } -} diff --git a/resources/qml/Governikus/Global/+desktop/TabbedPane.qml b/resources/qml/Governikus/Global/+desktop/TabbedPane.qml index 42a564451..a91d83d10 100644 --- a/resources/qml/Governikus/Global/+desktop/TabbedPane.qml +++ b/resources/qml/Governikus/Global/+desktop/TabbedPane.qml @@ -1,34 +1,32 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.View 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.Type.ApplicationModel +import Governikus.Type.SettingsModel +import Governikus.View Item { id: root - readonly property int availableHeight: height - 2 * contentPadding - 2 * Style.dimens.high_contrast_item_border + readonly property int availableHeight: Math.floor(height - 2 * Constants.pane_spacing) property Component contentDelegate: null property var contentObjectModel: undefined - property int contentPadding: Constants.pane_padding + property alias contentRightMargin: flickable.rightMargin readonly property var currentContentItem: contentLoader.item property alias currentIndex: sectionNameList.currentIndex readonly property var currentItemModel: sectionNameList.currentItem ? sectionNameList.currentItem.itemModel : null property Component footerItem: null readonly property real relativeListViewWidth: 0.3 property alias sectionCount: sectionNameList.count - property Component sectionDelegate: TabbedPaneDelegateText { - sectionName: model ? (model.display ? model.display : model.modelData) : "" - } property var sectionsModel: undefined function scrollYPositionIntoView(pYposition) { - var dy = pYposition - flickable.contentY - flickable.height; + let dy = pYposition - flickable.contentY - flickable.height; if (dy > 0 || flickable.contentY > 0) { flickable.contentY += dy; if (flickable.contentY < 0) @@ -39,12 +37,18 @@ Item { } Item { + anchors.bottomMargin: Constants.pane_padding anchors.fill: parent + anchors.leftMargin: Constants.pane_padding + anchors.topMargin: Constants.pane_padding + opacity: SettingsModel.showBetaTesting ? 0.9 : 1.0 ColumnLayout { + id: leftSide + height: parent.height spacing: Constants.component_spacing - width: parent.width * relativeListViewWidth + 2 * Style.dimens.high_contrast_item_border + width: parent.width * relativeListViewWidth z: 1 anchors { @@ -52,22 +56,33 @@ Item { left: parent.left top: parent.top } - GListView { - id: sectionNameList + Item { Layout.fillHeight: true Layout.fillWidth: true - activeFocusOnTab: true - boundsBehavior: Flickable.StopAtBounds - clip: true - delegate: sectionNameDelegate - highlight: null - highlightFollowsCurrentItem: true - model: sectionsModel - scrollBarAutohide: true - scrollBarBottomPadding: Constants.text_spacing - scrollBarTopPadding: Constants.text_spacing - - onCurrentIndexChanged: flickable.positionViewAtBeginning() + + layer { + enabled: GraphicsInfo.api !== GraphicsInfo.Software + + effect: GDropShadow { + } + } + GListView { + id: sectionNameList + + activeFocusOnTab: true + anchors.fill: parent + boundsBehavior: Flickable.StopAtBounds + clip: true + delegate: sectionNameDelegate + highlight: null + highlightFollowsCurrentItem: true + model: sectionsModel + scrollBarAutohide: true + scrollBarBottomPadding: Constants.text_spacing + scrollBarTopPadding: Constants.text_spacing + + onCurrentIndexChanged: flickable.positionViewAtBeginning() + } } Loader { Layout.alignment: Qt.AlignLeft @@ -76,64 +91,46 @@ Item { sourceComponent: footerItem } } - RoundedRectangle { - anchors.right: parent.right - borderColor: Style.color.high_contrast_item_border - borderWidth: Style.dimens.high_contrast_item_border - bottomLeftCorner: sectionNameList.contentHeight < height - color: Style.color.background_pane - height: parent.height - radius: Style.dimens.corner_radius - topLeftCorner: false - width: parent.width * (1.0 - relativeListViewWidth) + GFlickableColumnLayout { + id: flickable - Item { - anchors.fill: parent - anchors.margins: Style.dimens.high_contrast_item_border - clip: true + bottomMargin: 0 + leftMargin: 0 + topMargin: 0 - GFlickable { - id: flickable - contentHeight: contentLoader.height + anchors { + bottom: parent.bottom + left: leftSide.right + leftMargin: Constants.pane_padding + right: parent.right + top: parent.top + } + Loader { + id: contentLoader - anchors { - bottomMargin: contentPadding - fill: parent - topMargin: contentPadding + Layout.fillWidth: true + Layout.maximumHeight: item ? item.Layout.maximumHeight : -1 + Layout.maximumWidth: item ? item.Layout.maximumWidth : -1 + Layout.minimumHeight: item ? item.Layout.minimumHeight : -1 + Layout.minimumWidth: item ? item.Layout.minimumWidth : -1 + Layout.preferredHeight: item ? item.Layout.preferredHeight : -1 + sourceComponent: { + if (contentDelegate !== null) { + return contentDelegate; } - Loader { - id: contentLoader - sourceComponent: { - if (contentDelegate !== null) { - return contentDelegate; - } - if (contentObjectModel === undefined) { - return null; - } - if (sectionNameList.currentIndex < contentObjectModel.count) { - return contentObjectModel.get(sectionNameList.currentIndex); - } - } - - anchors { - left: parent.left - leftMargin: contentPadding - right: parent.right - rightMargin: contentPadding - top: parent.top - } + if (contentObjectModel === undefined) { + return null; + } + if (sectionNameList.currentIndex < contentObjectModel.count) { + return contentObjectModel.get(sectionNameList.currentIndex); } } } - ScrollGradients { - anchors.fill: parent - anchors.margins: Style.dimens.high_contrast_item_border - color: parent.color - } } } Component { id: sectionNameDelegate + Item { id: delegateItem @@ -144,78 +141,64 @@ Item { readonly property var itemModel: model Accessible.focusable: true - Accessible.name: delegateLoader.item ? delegateLoader.item.sectionName : "" + Accessible.name: sectionName.text Accessible.role: Accessible.Button activeFocusOnTab: false - height: delegateLoader.height + 2 * Constants.pane_padding + height: sectionName.height + 2 * Constants.pane_padding width: sectionNameList.width RoundedRectangle { id: background - borderColor: Style.color.high_contrast_item_border - borderWidth: Style.dimens.high_contrast_item_border + + anchors.fill: parent + borderColor: Style.color.pane_border bottomLeftCorner: isLastItem - bottomRightCorner: false - color: isCurrentItem ? Style.color.background_pane : Style.color.background_pane_inactive - radius: Style.dimens.corner_radius + bottomRightCorner: isLastItem + color: isCurrentItem ? Style.color.control : Style.color.pane + radius: Style.dimens.pane_radius topLeftCorner: isFirstItem - topRightCorner: false + topRightCorner: isFirstItem + } + GText { + id: sectionName + + color: isCurrentItem ? Style.color.control_content : Style.color.text + elide: Text.ElideRight + maximumLineCount: 2 + text: model.display ? model.display : model.modelData + textStyle: Style.text.subline anchors { - bottomMargin: isCurrentItem && !isLastItem ? Style.dimens.tabbed_pane_separator_size : 0 - fill: parent - rightMargin: !isCurrentItem ? (Style.dimens.tabbed_pane_separator_size + 2 * Style.dimens.high_contrast_item_border) : 0 - topMargin: isCurrentItem && !isFirstItem ? Style.dimens.tabbed_pane_separator_size : 0 - } - Rectangle { - color: background.color - width: isCurrentItem ? Style.dimens.high_contrast_item_border : 0 - - anchors { - bottom: parent.bottom - bottomMargin: isLastItem ? Style.dimens.high_contrast_item_border : 0 - right: parent.right - top: parent.top - topMargin: isFirstItem ? Style.dimens.high_contrast_item_border : 0 - } + left: parent.left + leftMargin: Constants.pane_padding + right: parent.right + rightMargin: Constants.pane_padding + verticalCenter: parent.verticalCenter } } GSeparator { id: horizontalSeparator + visible: !isLastItem && !isCurrentItem && !isPreviousToCurrentItem anchors { bottom: parent.bottom left: parent.left - leftMargin: Style.dimens.high_contrast_item_border + leftMargin: Constants.pane_padding right: parent.right - rightMargin: (!isCurrentItem ? Style.dimens.tabbed_pane_separator_size : 0) + 2 * Style.dimens.high_contrast_item_border + rightMargin: Constants.pane_padding } } FocusFrame { - framee: delegateLoader - } - Loader { - id: delegateLoader - - property bool isCurrentItem: parent.isCurrentItem - property var model: itemModel - - sourceComponent: sectionDelegate - - anchors { - left: parent.left - leftMargin: Constants.pane_padding - right: parent.right - rightMargin: Constants.pane_padding + 2 * Style.dimens.high_contrast_item_border - verticalCenter: parent.verticalCenter - } + borderColor: sectionName.color + framee: sectionName } MouseArea { anchors.fill: parent cursorShape: index === currentIndex ? Qt.ArrowCursor : Qt.PointingHandCursor onClicked: { + delegateItem.ListView.view.itemAtIndex(index).forceActiveFocus(Qt.MouseFocusReason); delegateItem.ListView.view.currentIndex = index; } } diff --git a/resources/qml/Governikus/Global/+desktop/TabbedPaneDelegateIconAndText.qml b/resources/qml/Governikus/Global/+desktop/TabbedPaneDelegateIconAndText.qml deleted file mode 100644 index 1d31719a5..000000000 --- a/resources/qml/Governikus/Global/+desktop/TabbedPaneDelegateIconAndText.qml +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Style 1.0 -import Governikus.Type.ApplicationModel 1.0 - -Row { - id: root - - property string iconPath - property string sectionName - - spacing: Constants.groupbox_spacing - - Image { - id: sectionIcon - fillMode: Image.PreserveAspectFit - source: iconPath - sourceSize.height: Style.dimens.medium_icon_size - sourceSize.width: Style.dimens.medium_icon_size - visible: source !== "" - } - GText { - anchors.verticalCenter: parent.verticalCenter - elide: Text.ElideRight - maximumLineCount: 1 - text: sectionName - textStyle: isCurrentItem ? Style.text.header : Style.text.header_inverse - width: parent.width - sectionIcon.width - } -} diff --git a/resources/qml/Governikus/Global/+desktop/TabbedPaneDelegateIconAndThreeLineText.qml b/resources/qml/Governikus/Global/+desktop/TabbedPaneDelegateIconAndThreeLineText.qml deleted file mode 100644 index 66672e6f5..000000000 --- a/resources/qml/Governikus/Global/+desktop/TabbedPaneDelegateIconAndThreeLineText.qml +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Style 1.0 -import Governikus.Type.ApplicationModel 1.0 - -RowLayout { - id: root - - property string footerText - property string headerText - property string iconPath - property string sectionName - - spacing: Constants.groupbox_spacing - width: parent.width - - Image { - id: sectionIcon - fillMode: Image.PreserveAspectFit - source: iconPath - sourceSize.height: Style.dimens.medium_icon_size - sourceSize.width: Style.dimens.medium_icon_size - visible: source !== "" - } - Column { - Layout.fillWidth: true - spacing: Constants.text_spacing - - GText { - maximumLineCount: 1 - text: headerText - textStyle: isCurrentItem ? Style.text.normal : Style.text.normal_inverse - width: parent.width - } - GText { - elide: Text.ElideRight - maximumLineCount: 1 - text: sectionName - textStyle: isCurrentItem ? Style.text.header : Style.text.header_inverse - width: parent.width - } - GText { - elide: Text.ElideRight - maximumLineCount: 1 - text: footerText - textStyle: isCurrentItem ? Style.text.normal : Style.text.normal_inverse - width: parent.width - } - } -} diff --git a/resources/qml/Governikus/Global/+desktop/TabbedPaneDelegateText.qml b/resources/qml/Governikus/Global/+desktop/TabbedPaneDelegateText.qml deleted file mode 100644 index 0a6c1fbba..000000000 --- a/resources/qml/Governikus/Global/+desktop/TabbedPaneDelegateText.qml +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Style 1.0 - -GText { - id: root - - property string sectionName - - elide: Text.ElideRight - maximumLineCount: 2 - text: sectionName - textStyle: isCurrentItem ? Style.text.header : Style.text.header_inverse - width: parent.width -} diff --git a/resources/qml/Governikus/Global/+mobile/+android/+phone/DeviceConstants.qml b/resources/qml/Governikus/Global/+mobile/+android/+phone/DeviceConstants.qml deleted file mode 100644 index ff7f8bc05..000000000 --- a/resources/qml/Governikus/Global/+mobile/+android/+phone/DeviceConstants.qml +++ /dev/null @@ -1,8 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 - -Item { - readonly property bool is_tablet: false -} diff --git a/resources/qml/Governikus/Global/+mobile/+android/+tablet/DeviceConstants.qml b/resources/qml/Governikus/Global/+mobile/+android/+tablet/DeviceConstants.qml deleted file mode 100644 index 0728a8b2e..000000000 --- a/resources/qml/Governikus/Global/+mobile/+android/+tablet/DeviceConstants.qml +++ /dev/null @@ -1,8 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 - -Item { - readonly property bool is_tablet: true -} diff --git a/resources/qml/Governikus/Global/+mobile/+android/BrandConstants.qml b/resources/qml/Governikus/Global/+mobile/+android/BrandConstants.qml index a5f5ef7f5..990b7a8d4 100644 --- a/resources/qml/Governikus/Global/+mobile/+android/BrandConstants.qml +++ b/resources/qml/Governikus/Global/+mobile/+android/BrandConstants.qml @@ -1,9 +1,9 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 +import QtQuick -DeviceConstants { +Item { readonly property bool is_layout_android: true readonly property bool is_layout_ios: false readonly property string layout: "android" diff --git a/resources/qml/Governikus/Global/+mobile/+android/ConfirmationPopup.qml b/resources/qml/Governikus/Global/+mobile/+android/ConfirmationPopup.qml index 71fc17bf5..707653b97 100644 --- a/resources/qml/Governikus/Global/+mobile/+android/ConfirmationPopup.qml +++ b/resources/qml/Governikus/Global/+mobile/+android/ConfirmationPopup.qml @@ -1,32 +1,31 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import QtQuick.Controls +import Governikus.Global +import Governikus.Style BaseConfirmationPopup { id: root + buttons: Flow { - bottomPadding: Constants.groupbox_spacing / 2 layoutDirection: Qt.RightToLeft - rightPadding: Constants.groupbox_spacing / 2 spacing: 0 width: parent.width GButton { - buttonColor: Style.color.transparent + background: null text: root.okButtonText - textStyle: Style.text.normal_accent + textStyle: Style.text.normal visible: style & ConfirmationPopup.PopupStyle.OkButton onClicked: root.accept() } GButton { - buttonColor: Style.color.transparent + background: null text: root.cancelButtonText - textStyle: Style.text.normal_accent + textStyle: Style.text.normal visible: style & ConfirmationPopup.PopupStyle.CancelButton onClicked: root.cancel() diff --git a/resources/qml/Governikus/Global/+mobile/+android/SearchBar.qml b/resources/qml/Governikus/Global/+mobile/+android/SearchBar.qml deleted file mode 100644 index 684f6be5e..000000000 --- a/resources/qml/Governikus/Global/+mobile/+android/SearchBar.qml +++ /dev/null @@ -1,88 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 - -Row { - id: root - - property int availableWidth: 0 - readonly property int contentWidth: root.implicitWidth - readonly property alias searchText: searchField.displayText - - function reset() { - searchField.clear(); - if (searchField.visible) { - searchField.visible = false; - Qt.inputMethod.hide(); - } - } - - anchors.bottom: parent ? parent.bottom : undefined - anchors.bottomMargin: Style.dimens.titlebar_padding - anchors.right: parent ? parent.right : undefined - anchors.top: parent ? parent.top : undefined - anchors.topMargin: Style.dimens.titlebar_padding - spacing: Style.dimens.titlebar_padding - - GTextField { - id: searchField - //: LABEL ANDROID - Accessible.name: qsTr("Type provider to search for") - Accessible.role: Accessible.EditableText - enterKeyType: Qt.EnterKeySearch - height: parent.height - visible: false - width: root.availableWidth - parent.spacing - iconItem.width - Style.dimens.titlebar_padding - - Behavior on visible { - PropertyAnimation { - duration: 150 - } - } - - onAccepted: { - iconItem.forceActiveFocus(Qt.MouseFocusReason); - } - } - TintableIcon { - id: iconItem - //: LABEL ANDROID - Accessible.description: qsTr("Search provider list") - Accessible.name: searchField.visible ? - //: LABEL ANDROID - qsTr("Abort search") : - //: LABEL ANDROID - qsTr("Search") - Accessible.role: Accessible.Button - source: searchField.visible ? "qrc:///images/material_close.svg" : "qrc:///images/material_search.svg" - sourceSize.height: parent.height - tintColor: Style.color.button_text - - Accessible.onPressAction: button.clicked(null) - - MouseArea { - id: button - Accessible.ignored: true - anchors.fill: parent - - onClicked: { - // Storage of the new value is needed because the query - // of searchField.visible still delivers the old value. - var searchFieldVisible = !searchField.visible; - if (searchFieldVisible) { - searchField.forceActiveFocus(Qt.MouseFocusReason); - Qt.inputMethod.show(); - } else { - iconItem.forceActiveFocus(Qt.MouseFocusReason); - searchField.text = ""; - Qt.inputMethod.hide(); - } - searchField.visible = searchFieldVisible; - } - } - } -} diff --git a/resources/qml/Governikus/Global/+mobile/+ios/+phone/DeviceConstants.qml b/resources/qml/Governikus/Global/+mobile/+ios/+phone/DeviceConstants.qml deleted file mode 100644 index ff7f8bc05..000000000 --- a/resources/qml/Governikus/Global/+mobile/+ios/+phone/DeviceConstants.qml +++ /dev/null @@ -1,8 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 - -Item { - readonly property bool is_tablet: false -} diff --git a/resources/qml/Governikus/Global/+mobile/+ios/+tablet/DeviceConstants.qml b/resources/qml/Governikus/Global/+mobile/+ios/+tablet/DeviceConstants.qml deleted file mode 100644 index 0728a8b2e..000000000 --- a/resources/qml/Governikus/Global/+mobile/+ios/+tablet/DeviceConstants.qml +++ /dev/null @@ -1,8 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 - -Item { - readonly property bool is_tablet: true -} diff --git a/resources/qml/Governikus/Global/+mobile/+ios/BrandConstants.qml b/resources/qml/Governikus/Global/+mobile/+ios/BrandConstants.qml index be8d461a0..2a2e04d68 100644 --- a/resources/qml/Governikus/Global/+mobile/+ios/BrandConstants.qml +++ b/resources/qml/Governikus/Global/+mobile/+ios/BrandConstants.qml @@ -1,9 +1,9 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 +import QtQuick -DeviceConstants { +Item { readonly property bool is_layout_android: false readonly property bool is_layout_ios: true readonly property string layout: "ios" diff --git a/resources/qml/Governikus/Global/+mobile/+ios/ConfirmationPopup.qml b/resources/qml/Governikus/Global/+mobile/+ios/ConfirmationPopup.qml index 3463b0200..7c0bc2a26 100644 --- a/resources/qml/Governikus/Global/+mobile/+ios/ConfirmationPopup.qml +++ b/resources/qml/Governikus/Global/+mobile/+ios/ConfirmationPopup.qml @@ -1,14 +1,15 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style BaseConfirmationPopup { id: root + horizontalTextAlignment: Text.AlignHCenter buttons: ColumnLayout { @@ -25,9 +26,9 @@ BaseConfirmationPopup { GButton { Layout.fillWidth: true - buttonColor: Style.color.transparent + background: null text: root.cancelButtonText - textStyle: Style.text.normal_accent + textStyle: Style.text.normal visible: style & ConfirmationPopup.PopupStyle.CancelButton onClicked: root.cancel() @@ -39,9 +40,9 @@ BaseConfirmationPopup { } GButton { Layout.fillWidth: true - buttonColor: Style.color.transparent + background: null text: root.okButtonText - textStyle: Style.text.normal_accent + textStyle: Style.text.normal visible: style & ConfirmationPopup.PopupStyle.OkButton onClicked: root.accept() diff --git a/resources/qml/Governikus/Global/+mobile/+ios/SearchBar.qml b/resources/qml/Governikus/Global/+mobile/+ios/SearchBar.qml deleted file mode 100644 index a6d271eb6..000000000 --- a/resources/qml/Governikus/Global/+mobile/+ios/SearchBar.qml +++ /dev/null @@ -1,154 +0,0 @@ -/** - * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 - -Item { - id: baseItem - - readonly property alias searchText: searchField.displayText - - function reset() { - searchField.clear(); - if (searchField.visible) { - Qt.inputMethod.hide(); - } - } - - Accessible.description: qsTr("Enter search string") - Accessible.role: Accessible.EditableText - height: Style.dimens.searchbar_height - - states: [ - State { - name: "searchBarActive" - when: searchField.activeFocus || searchField.text.trim().length !== 0 - - PropertyChanges { - target: cancelButton - visible: true - } - }, - State { - name: "" - - StateChangeScript { - script: { - Qt.inputMethod.hide(); - } - } - PropertyChanges { - target: cancelButton - visible: false - } - } - ] - transitions: [ - Transition { - from: "*" - to: "*" - - AnchorAnimation { - duration: 200 - easing.type: Easing.InOutQuad - } - } - ] - - Rectangle { - border.color: searchField.valid ? Style.color.border : Constants.red - border.width: Style.dimens.separator_size - color: searchField.enabled ? Style.color.background_pane : Constants.grey - radius: Style.dimens.button_radius - - anchors { - bottom: parent.bottom - left: parent.left - margins: Constants.groupbox_spacing - right: cancelButton.left - top: parent.top - } - Image { - id: glassIcon - height: parent.height - 2 * anchors.leftMargin - source: "qrc:///images/material_search.svg" - sourceSize.width: width - width: height - - anchors { - left: parent.left - leftMargin: Constants.groupbox_spacing / 2 - verticalCenter: parent.verticalCenter - } - } - GTextField { - id: searchField - Accessible.name: displayText - Accessible.role: Accessible.EditableText - EnterKey.type: Qt.EnterKeySearch - horizontalAlignment: Text.AlignLeft - leftPadding: 0 - placeholderText: qsTr("Search providers") - rightPadding: 0 - - background: Item { - } - - onVisibleChanged: { - if (visible === false) { - Qt.inputMethod.hide(); - } - } - - anchors { - left: glassIcon.right - leftMargin: Constants.groupbox_spacing / 2 - right: textEditX.left - verticalCenter: parent.verticalCenter - } - } - MouseArea { - id: textEditX - Accessible.ignored: !visible - Accessible.name: qsTr("Clear search string") - Accessible.role: Accessible.Button - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - cursorShape: Qt.PointingHandCursor - height: parent.height - visible: searchField.length > 0 - width: height - - Accessible.onPressAction: textEditX.clicked(null) - onClicked: searchField.clear() - - Image { - anchors.fill: parent - anchors.margins: Constants.groupbox_spacing / 2 - source: "qrc:///images/ios/material_cancel.svg" - } - } - } - GButton { - id: cancelButton - buttonColor: Style.color.transparent - //: LABEL IOS - text: qsTr("Cancel") - visible: false - width: visible ? implicitWidth : 0 - - onClicked: { - searchField.clear(); - Qt.inputMethod.hide(); - } - - anchors { - right: parent.right - rightMargin: visible ? Constants.groupbox_spacing : 0 - verticalCenter: parent.verticalCenter - } - } -} diff --git a/resources/qml/Governikus/Global/+mobile/GCollapsibleSubButton.qml b/resources/qml/Governikus/Global/+mobile/GCollapsibleSubButton.qml new file mode 100644 index 000000000..3ed9b4b18 --- /dev/null +++ b/resources/qml/Governikus/Global/+mobile/GCollapsibleSubButton.qml @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.View +import Governikus.Type.ApplicationModel +import Governikus.Type.SettingsModel + +AbstractButton { + id: root + + property alias image: icon.source + property alias tintIcon: icon.tintEnabled + property alias title: label.text + + implicitHeight: layout.implicitHeight + Constants.component_spacing + implicitWidth: layout.implicitWidth + 2 * Constants.component_spacing + + background: Rectangle { + color: root.pressed ? Style.color.control_content_pressed : Style.color.transparent + } + contentItem: RowLayout { + id: layout + + anchors.left: parent.left + anchors.leftMargin: Constants.component_spacing * 2 + anchors.verticalCenter: parent.verticalCenter + spacing: Constants.component_spacing + + TintableIcon { + id: icon + + sourceSize.height: Style.dimens.small_icon_size + tintColor: label.color + tintEnabled: false + } + GText { + id: label + + Layout.maximumWidth: Number.POSITIVE_INFINITY + color: root.pressed ? Style.color.control_content_hover : Style.color.text + } + } +} diff --git a/resources/qml/Governikus/Global/+mobile/GOptionsContainer.qml b/resources/qml/Governikus/Global/+mobile/GOptionsContainer.qml new file mode 100644 index 000000000..2d2dc07b2 --- /dev/null +++ b/resources/qml/Governikus/Global/+mobile/GOptionsContainer.qml @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ + +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style + +ColumnLayout { + default property alias containerData: pane.paneData + property alias containerPadding: pane.padding + property alias containerSpacing: pane.spacing + property alias title: titleText.text + + spacing: Constants.component_spacing + + GText { + id: titleText + + Accessible.role: Accessible.Heading + textStyle: Style.text.headline + visible: text !== "" + } + GPane { + id: pane + + Layout.fillWidth: true + color: Style.color.pane + padding: 0 + spacing: 0 + } +} diff --git a/resources/qml/Governikus/Global/+mobile/GPane.qml b/resources/qml/Governikus/Global/+mobile/GPane.qml index 3cf033934..40288eff4 100644 --- a/resources/qml/Governikus/Global/+mobile/GPane.qml +++ b/resources/qml/Governikus/Global/+mobile/GPane.qml @@ -1,14 +1,21 @@ /** * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Style 1.0 +import QtQuick +import Governikus.Global +import Governikus.Style GPaneBackground { id: root + property alias bold: titleText.font.bold property alias contentSpacing: paneContent.spacing + property bool drawShadow: true + property alias horizontalTitleAlignment: titleText.horizontalAlignment + property int padding: Constants.pane_padding default property alias paneData: paneContent.data + property int spacing: Constants.pane_spacing + property alias textStyle: titleText.textStyle property alias title: titleText.text height: childrenRect.height @@ -16,22 +23,31 @@ GPaneBackground { Column { id: content + anchors.left: parent.left - anchors.leftMargin: Constants.pane_padding + anchors.leftMargin: root.padding anchors.right: parent.right - anchors.rightMargin: Constants.pane_padding - bottomPadding: Constants.pane_padding - spacing: Constants.pane_spacing - topPadding: Constants.pane_padding + anchors.rightMargin: root.padding + bottomPadding: root.padding + spacing: root.spacing + topPadding: root.padding PaneTitle { id: titleText + width: parent.width } Column { id: paneContent - spacing: Constants.pane_spacing + + spacing: root.spacing width: parent.width } } + layer { + enabled: GraphicsInfo.api !== GraphicsInfo.Software && drawShadow + + effect: GDropShadow { + } + } } diff --git a/resources/qml/Governikus/Global/+mobile/GSwitch.qml b/resources/qml/Governikus/Global/+mobile/GSwitch.qml deleted file mode 100644 index bf7c2d813..000000000 --- a/resources/qml/Governikus/Global/+mobile/GSwitch.qml +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Style 1.0 - -Switch { - id: control - - property color color: Style.color.switch_checked - - implicitHeight: indicator.implicitHeight - implicitWidth: indicator.implicitWidth - padding: 0 - - // Empty item since we don't want the text - contentItem: Item { - } - indicator: Item { - implicitHeight: 24 - implicitWidth: 48 - - Rectangle { - color: control.enabled ? (control.checked ? Qt.lighter(control.color, 1.3) : Qt.darker(Style.color.button_disabled, 1.4)) : Qt.darker(Style.color.button_disabled, 1.1) - height: parent.height / 2 - radius: height / 2 - width: parent.width - y: parent.height / 2 - height / 2 - } - Rectangle { - border.color: Style.color.border - border.width: control.enabled && !control.checked ? Style.dimens.separator_size : 0 - color: control.enabled ? (control.checked ? control.color : Style.color.switch_unchecked) : Style.color.button_disabled - height: parent.height - radius: height / 2 - width: parent.height - x: control.checked ? parent.width - width : 0 - - Behavior on x { - NumberAnimation { - duration: 200 - easing.type: Easing.InOutQuad - } - } - } - } - - Accessible.onPressAction: toggle() -} diff --git a/resources/qml/Governikus/Global/Hint.qml b/resources/qml/Governikus/Global/+mobile/Hint.qml similarity index 53% rename from resources/qml/Governikus/Global/Hint.qml rename to resources/qml/Governikus/Global/+mobile/Hint.qml index 351713654..6af6bb4c0 100644 --- a/resources/qml/Governikus/Global/Hint.qml +++ b/resources/qml/Governikus/Global/+mobile/Hint.qml @@ -1,11 +1,11 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.View 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.View GPane { id: root @@ -16,6 +16,11 @@ GPane { signal clicked + bold: true + color: Style.color.pane_sublevel + drawShadow: false + textStyle: Style.text.subline + //: LABEL ANDROID IOS title: qsTr("Hint") ColumnLayout { @@ -24,10 +29,8 @@ GPane { GText { id: hintText - Layout.fillWidth: true - Layout.topMargin: Constants.text_spacing + activeFocusOnTab: true - textStyle: Style.text.normal visible: text !== "" FocusFrame { @@ -35,9 +38,12 @@ GPane { } GButton { id: hintButton - Layout.alignment: Qt.AlignRight - Layout.topMargin: Constants.component_spacing - icon.source: "qrc:///images/material_open_in_new.svg" + + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: Constants.groupbox_spacing + icon.source: "qrc:///images/open_website.svg" + iconSize: Style.dimens.navigation_bar_icon_size + tintIcon: hintText.color visible: text !== "" onClicked: root.clicked() diff --git a/resources/qml/Governikus/Global/+mobile/IosBackGestureMouseArea.qml b/resources/qml/Governikus/Global/+mobile/IosBackGestureMouseArea.qml index 69aa028bb..81c27dba8 100644 --- a/resources/qml/Governikus/Global/+mobile/IosBackGestureMouseArea.qml +++ b/resources/qml/Governikus/Global/+mobile/IosBackGestureMouseArea.qml @@ -1,7 +1,7 @@ /** * Copyright (c) 2022-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 +import QtQuick MouseArea { id: root diff --git a/resources/qml/Governikus/Global/+mobile/LabeledSwitch.qml b/resources/qml/Governikus/Global/+mobile/LabeledSwitch.qml deleted file mode 100644 index 248fcd67a..000000000 --- a/resources/qml/Governikus/Global/+mobile/LabeledSwitch.qml +++ /dev/null @@ -1,68 +0,0 @@ -/** - * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 - -Rectangle { - property alias checked: entrySwitch.checked - property real contentMarginLeft: Constants.component_spacing - property real contentMarginRight: Constants.component_spacing - property real contentMarginVertical: Constants.component_spacing - property alias description: descriptionText.text - property alias title: titleText.text - - Accessible.checkable: enabled - Accessible.checked: checked - Accessible.name: title + ". " + description - Accessible.role: Accessible.CheckBox - color: mouseArea.pressed ? Style.color.background_item_pressed : Style.color.transparent - height: implicitHeight - implicitHeight: Math.max(textContainer.height, entrySwitch.height) + contentMarginVertical - - Accessible.onPressAction: entrySwitch.toggle() - Accessible.onToggleAction: entrySwitch.toggle() - - Item { - id: textContainer - anchors.left: parent.left - anchors.leftMargin: contentMarginLeft - anchors.right: entrySwitch.left - anchors.rightMargin: Constants.component_spacing * 2 - anchors.verticalCenter: parent.verticalCenter - height: titleText.height + descriptionText.height - - GText { - id: titleText - Accessible.ignored: true - anchors.left: parent.left - anchors.right: parent.right - textStyle: Style.text.normal_accent - } - GText { - id: descriptionText - Accessible.ignored: true - anchors.left: parent.left - anchors.right: parent.right - anchors.top: titleText.bottom - anchors.topMargin: 2 - textStyle: Style.text.normal_secondary - } - } - MouseArea { - id: mouseArea - anchors.fill: parent - - onClicked: entrySwitch.toggle() - } - GSwitch { - id: entrySwitch - Accessible.ignored: true - anchors.right: parent.right - anchors.rightMargin: contentMarginRight - anchors.verticalCenter: parent.verticalCenter - text: titleText.text - } -} diff --git a/resources/qml/Governikus/Global/+mobile/ListItem.qml b/resources/qml/Governikus/Global/+mobile/ListItem.qml index 9371efe17..413419f36 100644 --- a/resources/qml/Governikus/Global/+mobile/ListItem.qml +++ b/resources/qml/Governikus/Global/+mobile/ListItem.qml @@ -1,10 +1,10 @@ /** * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style Rectangle { id: baseItem @@ -15,7 +15,7 @@ Rectangle { property alias footerText: footerItem.text property alias headerText: headerItem.text property alias icon: imageItem.source - property string linkIconSource: "qrc:///images/mobile/material_arrow_right.svg" + property string linkIconSource: "qrc:///images/material_arrow_right.svg" property alias mouseAreaEnabled: mouseArea.enabled property bool pressed: mouseArea.pressed property bool showLinkIcon: Constants.is_layout_ios @@ -28,7 +28,7 @@ Rectangle { Accessible.name: headerText + ". " + text + ". " + footerText Accessible.role: Accessible.ListItem - color: pressed ? Style.color.background_pane_active : Style.color.background_pane + color: pressed ? Style.color.pane_active : Style.color.pane height: fixedHeight ? Style.dimens.list_item_height : (content.implicitHeight + Constants.text_spacing) width: parent ? parent.width : 0 @@ -43,6 +43,7 @@ Rectangle { } RowLayout { id: content + anchors.fill: parent anchors.leftMargin: contentMarginLeft anchors.rightMargin: contentMarginRight @@ -50,52 +51,60 @@ Rectangle { TintableIcon { id: imageItem + sourceSize.height: parent.height - 2 * Constants.groupbox_spacing - tintColor: Style.color.secondary_text + tintColor: Style.color.text tintEnabled: false visible: baseItem.icon !== "" } ColumnLayout { id: textLayout + Layout.fillWidth: true + Layout.maximumWidth: Number.POSITIVE_INFINITY spacing: 0 GText { id: headerItem + Accessible.ignored: true - Layout.fillWidth: true + Layout.alignment: Qt.AlignLeft + color: baseItem.pressed ? Style.color.text_pressed : Style.color.text_subline elide: Text.ElideRight maximumLineCount: fixedHeight ? 1 : 8 - textStyle: Style.text.hint_accent visible: baseItem.headerText !== "" } GText { id: textItem + Accessible.ignored: true - Layout.fillWidth: true + Layout.alignment: Qt.AlignLeft + color: baseItem.pressed ? Style.color.text_pressed : Style.color.text elide: Text.ElideRight maximumLineCount: fixedHeight ? (headerText === "" ? 2 : 1) : 64 visible: baseItem.text !== "" } GText { id: footerItem + Accessible.ignored: true - Layout.fillWidth: true + Layout.alignment: Qt.AlignLeft + color: baseItem.pressed ? Style.color.text_pressed : Style.color.text elide: Text.ElideRight maximumLineCount: fixedHeight ? (headerText === "" ? 2 : 1) : 8 - textStyle: Style.text.hint_secondary visible: baseItem.footerText !== "" } } TintableIcon { source: linkIconSource sourceSize.height: Style.dimens.small_icon_size - tintColor: Style.color.secondary_text + tintColor: Style.color.text visible: showLinkIcon } } MouseArea { id: mouseArea + anchors.fill: parent onClicked: baseItem.clicked() diff --git a/resources/qml/Governikus/Global/+mobile/MenuItem.qml b/resources/qml/Governikus/Global/+mobile/MenuItem.qml index 7e4df131a..57833df3e 100644 --- a/resources/qml/Governikus/Global/+mobile/MenuItem.qml +++ b/resources/qml/Governikus/Global/+mobile/MenuItem.qml @@ -1,19 +1,18 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style -Rectangle { +RoundedRectangle { id: baseItem - property real contentMarginLeft: Constants.component_spacing - property real contentMarginRight: Constants.component_spacing - property real contentMarginVertical: Constants.component_spacing property alias description: descriptionText.text - property var icon: "qrc:///images/mobile/material_arrow_right.svg" + property bool drawBottomCorners: false + property bool drawTopCorners: false + property var icon: "qrc:///images/material_arrow_right.svg" property alias tintIcon: iconItem.tintEnabled property alias title: titleText.text @@ -21,51 +20,54 @@ Rectangle { Accessible.name: title + ". " + description Accessible.role: Accessible.Button - color: mouseArea.pressed ? Style.color.background_item_pressed : Style.color.transparent - height: implicitHeight - implicitHeight: Math.max(textContainer.height, iconItem.height) + contentMarginVertical + bottomLeftCorner: drawBottomCorners + bottomRightCorner: drawBottomCorners + color: mouseArea.pressed ? Style.color.pane_active : Style.color.transparent + implicitHeight: layout.implicitHeight + layout.anchors.topMargin + layout.anchors.bottomMargin + implicitWidth: layout.implicitWidth + layout.anchors.leftMargin + layout.anchors.rightMargin + topLeftCorner: drawTopCorners + topRightCorner: drawTopCorners Accessible.onPressAction: clicked() - Item { - id: textContainer - anchors.left: parent.left - anchors.leftMargin: contentMarginLeft - anchors.right: iconItem.left - anchors.rightMargin: Constants.component_spacing * 2 - anchors.verticalCenter: parent.verticalCenter - height: titleText.height + descriptionText.height + RowLayout { + id: layout - GText { - id: titleText - Accessible.ignored: true - anchors.left: parent.left - anchors.right: parent.right - textStyle: Style.text.normal_accent + anchors.fill: parent + anchors.margins: Constants.pane_padding + spacing: 0 + + ColumnLayout { + GText { + id: titleText + + Accessible.ignored: true + color: mouseArea.pressed ? Style.color.text_subline_pressed : textStyle.textColor + textStyle: Style.text.subline + visible: text !== "" + } + GText { + id: descriptionText + + Accessible.ignored: true + color: mouseArea.pressed ? Style.color.text_pressed : textStyle.textColor + visible: text !== "" + } } - GText { - id: descriptionText + TintableIcon { + id: iconItem + Accessible.ignored: true - anchors.left: parent.left - anchors.right: parent.right - anchors.top: titleText.bottom - anchors.topMargin: 2 - textStyle: Style.text.normal_secondary + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + Layout.preferredWidth: Style.dimens.icon_size + source: baseItem.icon + sourceSize.height: Style.dimens.small_icon_size + tintColor: Style.color.text } } - TintableIcon { - id: iconItem - Accessible.ignored: true - anchors.right: parent.right - anchors.rightMargin: contentMarginRight - anchors.verticalCenter: parent.verticalCenter - source: baseItem.icon - sourceSize.height: Style.dimens.small_icon_size - tintColor: Style.color.secondary_text - width: Style.dimens.icon_size - } MouseArea { id: mouseArea + anchors.fill: parent onClicked: baseItem.clicked() diff --git a/resources/qml/Governikus/Global/+mobile/PaneTitle.qml b/resources/qml/Governikus/Global/+mobile/PaneTitle.qml index 3bf291b1d..da0c8de18 100644 --- a/resources/qml/Governikus/Global/+mobile/PaneTitle.qml +++ b/resources/qml/Governikus/Global/+mobile/PaneTitle.qml @@ -1,13 +1,13 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Style 1.0 +import QtQuick +import Governikus.Style GText { Accessible.name: text Accessible.role: Accessible.TitleBar elide: Text.ElideRight - textStyle: Style.text.header_accent + textStyle: Style.text.headline visible: text !== "" } diff --git a/resources/qml/Governikus/Global/+mobile/PlatformConstants.qml b/resources/qml/Governikus/Global/+mobile/PlatformConstants.qml index 0a7d6c5b5..2d13e8de7 100644 --- a/resources/qml/Governikus/Global/+mobile/PlatformConstants.qml +++ b/resources/qml/Governikus/Global/+mobile/PlatformConstants.qml @@ -1,7 +1,7 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 +import QtQuick BrandConstants { readonly property int component_spacing: 20 @@ -9,5 +9,6 @@ BrandConstants { readonly property bool is_desktop: false readonly property int pane_padding: 20 readonly property int pane_spacing: 20 + readonly property int subtext_spacing: 2 readonly property int text_spacing: 10 } diff --git a/resources/qml/Governikus/Global/+mobile/SwipeActionDelegate.qml b/resources/qml/Governikus/Global/+mobile/SwipeActionDelegate.qml index 18f580d72..566527ea4 100644 --- a/resources/qml/Governikus/Global/+mobile/SwipeActionDelegate.qml +++ b/resources/qml/Governikus/Global/+mobile/SwipeActionDelegate.qml @@ -1,9 +1,9 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 +import QtQuick +import QtQuick.Controls +import Governikus.Global Item { id: baseItem @@ -23,6 +23,7 @@ Item { Rectangle { id: actionBackground + width: Math.abs(mouseArea.contentX) anchors { @@ -33,6 +34,7 @@ Item { } TintableIcon { id: actionImage + Accessible.name: actionAccessibleName Accessible.role: Accessible.Button width: Math.abs(mouseArea.actionOpenOffset) - anchors.margins * 2 @@ -48,10 +50,11 @@ Item { } Item { id: content + height: parent.height width: parent.width - Behavior on x { + Behavior on x { NumberAnimation { duration: Constants.animation_duration diff --git a/resources/qml/Governikus/Global/+mobile/TitledSeparator.qml b/resources/qml/Governikus/Global/+mobile/TitledSeparator.qml index aa6fb85e0..1e186c458 100644 --- a/resources/qml/Governikus/Global/+mobile/TitledSeparator.qml +++ b/resources/qml/Governikus/Global/+mobile/TitledSeparator.qml @@ -1,17 +1,15 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style RowLayout { id: baseItem property real contentMarginBottom: Constants.component_spacing / 2 - property real contentMarginLeft: Constants.component_spacing - property real contentMarginRight: Constants.component_spacing property real contentMarginTop: Constants.component_spacing * 1.5 property real minimumSeperatorWidth: Constants.component_spacing property alias title: titleText.text @@ -23,19 +21,16 @@ RowLayout { GText { id: titleText + Accessible.ignored: true Layout.bottomMargin: baseItem.contentMarginBottom - Layout.fillWidth: true - Layout.leftMargin: baseItem.contentMarginLeft - Layout.maximumWidth: Math.ceil(titleText.implicitWidth) Layout.topMargin: baseItem.contentMarginTop - textStyle: Style.text.title + textStyle: Style.text.headline } GSeparator { Layout.bottomMargin: baseItem.contentMarginBottom Layout.fillWidth: true Layout.minimumWidth: baseItem.minimumSeperatorWidth - Layout.rightMargin: baseItem.contentMarginRight Layout.topMargin: baseItem.contentMarginTop } } diff --git a/resources/qml/Governikus/Global/+qt5/RegExpValidatorCompat.qml b/resources/qml/Governikus/Global/+qt5/RegExpValidatorCompat.qml index e8ff291aa..a3db7f245 100644 --- a/resources/qml/Governikus/Global/+qt5/RegExpValidatorCompat.qml +++ b/resources/qml/Governikus/Global/+qt5/RegExpValidatorCompat.qml @@ -1,7 +1,7 @@ /** * Copyright (c) 2022-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 +import QtQuick RegExpValidator { property var expression diff --git a/resources/qml/Governikus/Global/+qt6/RegExpValidatorCompat.qml b/resources/qml/Governikus/Global/+qt6/RegExpValidatorCompat.qml index a328c280a..6ef644281 100644 --- a/resources/qml/Governikus/Global/+qt6/RegExpValidatorCompat.qml +++ b/resources/qml/Governikus/Global/+qt6/RegExpValidatorCompat.qml @@ -1,7 +1,7 @@ /** * Copyright (c) 2022-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 +import QtQuick RegularExpressionValidator { property var expression diff --git a/resources/qml/Governikus/Global/BaseConfirmationPopup.qml b/resources/qml/Governikus/Global/BaseConfirmationPopup.qml index 62694baf3..df3e2394e 100644 --- a/resources/qml/Governikus/Global/BaseConfirmationPopup.qml +++ b/resources/qml/Governikus/Global/BaseConfirmationPopup.qml @@ -1,16 +1,17 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.View +import Governikus.Type.ApplicationModel Popup { id: root + enum PopupStyle { NoButtons, OkButton, @@ -21,7 +22,7 @@ Popup { //: LABEL ALL_PLATFORMS property string cancelButtonText: qsTr("Cancel") default property alias children: customContent.children - property var horizontalTextAlignment: Text.AlignLeft + property int horizontalTextAlignment: Text.AlignLeft //: LABEL ALL_PLATFORMS property string okButtonText: qsTr("OK") property int style: ConfirmationPopup.PopupStyle.OkButton | ConfirmationPopup.PopupStyle.CancelButton @@ -45,95 +46,73 @@ Popup { } anchors.centerIn: Overlay.overlay + bottomMargin: Overlay.overlay ? 0.125 * Overlay.overlay.height : 0 closePolicy: Popup.CloseOnPressOutside | Popup.CloseOnEscape - contentWidth: Overlay.overlay ? Math.min(0.75 * Overlay.overlay.width, Style.dimens.max_text_width) : 0 focus: true - margins: Constants.pane_padding + leftMargin: Overlay.overlay ? 0.125 * Overlay.overlay.width : 0 modal: true - padding: 0 + padding: Constants.pane_padding / 2 parent: Overlay.overlay - topPadding: Constants.pane_padding + rightMargin: leftMargin + rightPadding: 0 + topMargin: bottomMargin background: Rectangle { border.color: Style.color.border border.width: Style.dimens.popup_border - color: Style.color.background_popup - radius: Style.dimens.corner_radius_popup + color: Style.color.background + radius: Style.dimens.pane_radius } - - Item { - id: contentItem - implicitHeight: contentLayout.height - implicitWidth: root.availableWidth + contentItem: GFlickableColumnLayout { + bottomMargin: Constants.pane_padding / 2 + clip: true + leftMargin: Constants.pane_padding / 2 + rightMargin: Constants.pane_padding + spacing: Constants.component_spacing + topMargin: Constants.pane_padding / 2 + width: availableWidth Keys.onEnterPressed: if (style & ConfirmationPopup.PopupStyle.OkButton) root.accept() Keys.onReturnPressed: if (style & ConfirmationPopup.PopupStyle.OkButton) root.accept() - ColumnLayout { - id: contentLayout - spacing: Constants.pane_padding - width: parent.width + GText { + activeFocusOnTab: true + elide: Text.ElideRight + focus: true + font.bold: true + horizontalAlignment: root.horizontalTextAlignment + maximumLineCount: 5 + text: root.title + textStyle: Style.text.headline + visible: root.title !== "" - GText { - Layout.fillWidth: true - Layout.leftMargin: Constants.pane_padding - Layout.rightMargin: Constants.pane_padding - activeFocusOnTab: true - elide: Text.ElideRight - focus: true - horizontalAlignment: root.horizontalTextAlignment - maximumLineCount: 5 - text: root.title - textStyle: Style.text.header_highlight - visible: text !== "" + FocusFrame { + } + } + GText { + activeFocusOnTab: true + horizontalAlignment: root.horizontalTextAlignment + text: root.text + visible: root.text !== "" - FocusFrame { - } + FocusFrame { } - Item { - Layout.fillWidth: true - implicitHeight: infoTextFlickable.implicitHeight - visible: infoText.text !== "" + } + Item { + id: customContent - GFlickable { - id: infoTextFlickable - anchors.fill: parent - anchors.leftMargin: Constants.pane_padding - anchors.rightMargin: Constants.pane_padding - clip: true - contentHeight: infoText.implicitHeight - contentWidth: width - implicitHeight: root.Overlay.overlay ? Math.min(infoText.height, 0.5 * root.Overlay.overlay.height) : 0 + Layout.fillWidth: true + implicitHeight: childrenRect.height + visible: children.length > 0 + } + Item { + id: buttonContainer - GText { - id: infoText - activeFocusOnTab: true - height: implicitHeight - horizontalAlignment: root.horizontalTextAlignment - rightPadding: Constants.pane_padding - text: root.text - width: parent.width - } - } - FocusFrame { - framee: infoTextFlickable - scope: infoText - } - } - Column { - id: customContent - Layout.fillWidth: true - Layout.leftMargin: Constants.pane_padding - Layout.rightMargin: Constants.pane_padding - visible: children.length > 0 - } - Item { - id: buttonContainer - Layout.fillWidth: true - Layout.preferredHeight: childrenRect.height - } + Layout.fillWidth: true + implicitHeight: childrenRect.height + visible: style !== ConfirmationPopup.PopupStyle.NoButtons } } } diff --git a/resources/qml/Governikus/Global/Category.qml b/resources/qml/Governikus/Global/Category.qml deleted file mode 100644 index 7b27a7862..000000000 --- a/resources/qml/Governikus/Global/Category.qml +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany - */ -pragma Singleton -import QtQuick 2.15 - -QtObject { - readonly property color categoryColorAll: "#164a8c" - readonly property color categoryColorCitizen: "#851e6b" - readonly property color categoryColorFinance: "#693800" - readonly property color categoryColorInsurance: "#53428c" - readonly property color categoryColorNone: "#164a8c" - readonly property color categoryColorOther: "#00828a" - readonly property var categoryToColor: { - "": categoryColorAll, - "all": categoryColorAll, - "citizen": categoryColorCitizen, - "insurance": categoryColorInsurance, - "finance": categoryColorFinance, - "other": categoryColorOther - } - readonly property var categoryToImageName: { - "citizen": "citizen", - "insurance": "insurance", - "finance": "finance", - "other": "other", - "all": "general", - "": "default" - } - - function backgroundImageSource(cat) { - return "qrc:///images/provider/" + getPlatform() + imageName(cat) + "_bg.svg"; - } - function buttonImageSource(cat) { - return "qrc:///images/provider/" + getPlatform() + imageName(cat) + "_button.svg"; - } - function displayColor(cat) { - return getTableValue(categoryToColor, cat, categoryColorNone); - } - function displayString(cat) { - let categoryToDisplayString = { - "": qsTr("Provider"), - "all": qsTr("All"), - "citizen": qsTr("Citizen services"), - "insurance": qsTr("Insurances"), - "finance": qsTr("Financials"), - "other": qsTr("Other services") - }; - return getTableValue(categoryToDisplayString, cat, ""); - } - function getPlatform() { - return plugin.platformStyle.indexOf("ios") !== -1 ? "ios/" : ""; - } - function getTableValue(table, key, defaultValue) { - return key in table ? table[key] : defaultValue; - } - function imageName(cat) { - return getTableValue(categoryToImageName, cat, "default"); - } - function imageSource(cat) { - return "qrc:///images/provider/" + getPlatform() + imageName(cat) + ".svg"; - } -} diff --git a/resources/qml/Governikus/Global/Constants.qml b/resources/qml/Governikus/Global/Constants.qml index 2f0446a94..5b1b80eb0 100644 --- a/resources/qml/Governikus/Global/Constants.qml +++ b/resources/qml/Governikus/Global/Constants.qml @@ -2,7 +2,7 @@ * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany */ pragma Singleton -import QtQuick 2.15 +import QtQuick PlatformConstants { readonly property int animation_duration: 250 diff --git a/resources/qml/Governikus/Global/Crossed.qml b/resources/qml/Governikus/Global/Crossed.qml new file mode 100644 index 000000000..4479deab0 --- /dev/null +++ b/resources/qml/Governikus/Global/Crossed.qml @@ -0,0 +1,72 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick +import Governikus.Style + +Item { + opacity: 0.5 + + QtObject { + id: d + + readonly property double a: halfWidth - (gap * 2) + readonly property double b: halfHeight - (gap * 2) + readonly property double c: Math.sqrt(a * a + b * b) + readonly property int gap: 20 + readonly property double halfHeight: parent.height / 2 + readonly property double halfWidth: parent.width / 2 + readonly property double rotate: Math.atan(parent.height / parent.width) * 180 / Math.PI + } + Line { + x: d.halfWidth + d.gap + y: d.halfHeight + d.gap + + transform: Rotation { + angle: d.rotate + } + } + Line { + x: d.halfWidth + d.gap + y: d.halfHeight - d.gap + + transform: Rotation { + angle: -d.rotate + } + } + Line { + x: d.halfWidth - d.gap + y: d.halfHeight - d.gap + + transform: Rotation { + angle: d.rotate - 180 + } + } + Line { + width: d.c - warning.width + x: d.halfWidth - d.gap + y: d.halfHeight + d.gap + + transform: Rotation { + angle: -d.rotate + 180 + } + } + TintableIcon { + id: warning + + anchors.bottom: parent.bottom + anchors.bottomMargin: d.gap + anchors.left: parent.left + anchors.leftMargin: d.gap + source: "qrc:///images/desktop/warning.svg" + sourceSize.height: Style.dimens.huge_icon_size - 10 + tintColor: Style.color.text_warning + } + + component Line: Rectangle { + antialiasing: true + color: Style.color.text_warning + height: Style.dimens.separator_size_large + width: d.c + } +} diff --git a/resources/qml/Governikus/Global/GBusyIndicator.qml b/resources/qml/Governikus/Global/GBusyIndicator.qml index 905f27e25..75f98c882 100644 --- a/resources/qml/Governikus/Global/GBusyIndicator.qml +++ b/resources/qml/Governikus/Global/GBusyIndicator.qml @@ -1,12 +1,12 @@ /** * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany */ -import QtQml 2.2 -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.ApplicationModel 1.0 +import QtQml +import QtQuick +import QtQuick.Controls +import Governikus.Global +import Governikus.Style +import Governikus.Type.ApplicationModel BusyIndicator { id: root @@ -15,7 +15,8 @@ BusyIndicator { contentItem: Item { id: busyContent - Behavior on rotation { + + Behavior on rotation { NumberAnimation { duration: timer.interval easing.type: Easing.Linear @@ -24,6 +25,7 @@ BusyIndicator { Rectangle { id: rect + anchors.centerIn: parent color: Style.color.background height: parent.height * root.factor @@ -32,6 +34,7 @@ BusyIndicator { } Timer { id: timer + interval: 1000 repeat: true running: root.running @@ -45,6 +48,7 @@ BusyIndicator { } GConicalGradient { id: green + anchors.fill: rect source: rect @@ -66,7 +70,7 @@ BusyIndicator { position: 1.0 } } - Behavior on rotation { + Behavior on rotation { NumberAnimation { duration: timer.interval easing.type: Easing.InOutQuad @@ -75,6 +79,7 @@ BusyIndicator { } GConicalGradient { id: blue + anchors.fill: rect source: rect @@ -96,7 +101,7 @@ BusyIndicator { position: 1.0 } } - Behavior on rotation { + Behavior on rotation { NumberAnimation { duration: timer.interval easing.type: Easing.InOutQuad diff --git a/resources/qml/Governikus/Global/GButton.qml b/resources/qml/Governikus/Global/GButton.qml index 662c215f4..a550cc1ab 100644 --- a/resources/qml/Governikus/Global/GButton.qml +++ b/resources/qml/Governikus/Global/GButton.qml @@ -1,85 +1,99 @@ /** * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 - -Button { +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.View +import Governikus.Type.ApplicationModel + +AbstractButton { id: root - property bool animationsDisabled: false - property color buttonColor: Style.color.button - property int cursorShape: Qt.PointingHandCursor + property alias buttonColor: d.color + property alias cursorShape: mouseArea.cursorShape property string disabledTooltipText // Similar to "enabled", but tooltips will continue to work property bool enableButton: true property string enabledTooltipText + property alias iconSize: buttonIcon.sourceSize.height property alias maximumLineCount: buttonText.maximumLineCount - property color textHighlightColor: textStyle.textColor - property TextStyle textStyle: enabled && enableButton ? Style.text.button : Style.text.button_disabled + property color textDisabledColor: Style.color.control_content_disabled + property color textHighlightColor: Style.color.control_content_pressed + property TextStyle textStyle: Style.text.button property bool tintIcon: false Accessible.name: text + Layout.fillWidth: true + Layout.maximumWidth: Math.ceil(implicitWidth) + Layout.minimumWidth: Style.dimens.min_button_width ToolTip.delay: Constants.toolTipDelay ToolTip.text: enableButton ? enabledTooltipText : disabledTooltipText ToolTip.visible: hovered && ToolTip.text !== "" activeFocusOnTab: enableButton + font.pixelSize: textStyle.textSize + horizontalPadding: 8 + verticalPadding: 6 background: Rectangle { - readonly property color pressColor: Qt.darker(buttonColor, Constants.highlightDarkerFactor) + border.color: d.borderColor + border.width: Style.dimens.border_width + color: d.color + radius: Style.dimens.control_radius - border.color: Style.color.high_contrast_item_border - border.width: Style.dimens.high_contrast_item_border - color: { - if (!enabled || !enableButton) { - return Style.color.button_disabled; - } - return !animationsDisabled && pressed ? pressColor : buttonColor; + FocusFrame { + borderColor: Style.color.control_border + marginFactor: 0.8 + radius: parent.radius * 1.2 + scope: root } - radius: Style.dimens.button_radius } contentItem: RowLayout { - spacing: Constants.text_spacing - z: 1 + RowLayout { + id: contentLayout - TintableIcon { - id: buttonIcon + Layout.maximumWidth: Number.POSITIVE_INFINITY + Layout.minimumHeight: root.font.pixelSize + topPadding + bottomPadding + Layout.minimumWidth: Style.dimens.min_button_width - leftPadding - rightPadding + spacing: 0 + z: 1 - readonly property color iconColor: root.textStyle.textColor - readonly property color pressColor: Qt.darker(iconColor, Constants.highlightDarkerFactor) + TintableIcon { + id: buttonIcon - source: root.icon.source - sourceSize.height: root.textStyle.textSize + 2 * verticalPadding - tintColor: !animationsDisabled && root.pressed ? pressColor : iconColor - tintEnabled: tintIcon - visible: source != "" - width: height - } - GText { - id: buttonText - Accessible.ignored: true - Layout.fillWidth: true - Layout.minimumHeight: root.textStyle.textSize + 2 * verticalPadding - Layout.minimumWidth: Style.dimens.large_icon_size - x - color: !animationsDisabled && root.pressed ? root.textHighlightColor : root.textStyle.textColor - elide: Text.ElideRight - horizontalAlignment: buttonIcon.visible ? Text.AlignLeft : Text.AlignHCenter - maximumLineCount: 1 - text: root.text - textStyle: root.textStyle - verticalAlignment: Text.AlignVCenter - visible: text !== "" - - FocusFrame { - isOnLightBackground: !root.background - marginFactor: 0.7 - scope: root + Layout.rightMargin: Constants.text_spacing + source: root.icon.source + sourceSize.height: contentLayout.Layout.minimumHeight + tintColor: d.contentColor + tintEnabled: tintIcon + visible: source != "" + width: height + } + GText { + id: buttonText + + Accessible.ignored: true + Layout.alignment: Qt.AlignHCenter + color: d.contentColor + elide: Text.ElideRight + font: root.font + lineHeight: root.textStyle.lineHeight + maximumLineCount: 1 + text: root.text + visible: text !== "" + + FocusFrame { + marginFactor: 0.7 + scope: root + visible: !root.background + } + } + GSpacer { + Layout.fillWidth: true + visible: buttonIcon.visible } } } @@ -88,9 +102,64 @@ Button { onActiveFocusOnTabChanged: if (!activeFocusOnTab) focus = false + Item { + id: d + + property color borderColor: color === Style.color.control ? Style.color.control_border : color + property color color: Style.color.control + property color contentColor: root.textStyle === Style.text.button ? Style.color.control_content : root.textStyle.textColor + + states: [ + State { + name: "disabled" + when: !root.enabled || !root.enableButton + + PropertyChanges { + borderColor: Style.color.control_border_disabled + color: Style.color.control_disabled + contentColor: root.textDisabledColor + target: d + } + }, + State { + name: "pressed" + when: root.pressed + + PropertyChanges { + borderColor: Style.color.control_border_pressed + color: Style.color.control_pressed + contentColor: root.textHighlightColor + target: d + } + }, + State { + name: "hover" + when: root.hovered + + PropertyChanges { + borderColor: Style.color.control_border_hover + color: Style.color.control_hover + contentColor: root.textStyle === Style.text.button ? Style.color.control_content_hover : root.textHighlightColor + target: d + } + }, + State { + name: "unchecked" + when: !root.checked && checkable + + PropertyChanges { + borderColor: Style.color.control_border_unchecked + color: Style.color.control_unchecked + contentColor: Style.color.control_content_unchecked + target: d + } + } + ] + } MouseArea { + id: mouseArea + anchors.fill: parent - cursorShape: enableButton ? root.cursorShape : Qt.ArrowCursor z: 2 onPressed: mouse => { diff --git a/resources/qml/Governikus/Global/GCheckBox.qml b/resources/qml/Governikus/Global/GCheckBox.qml index 81fb73273..96772169e 100644 --- a/resources/qml/Governikus/Global/GCheckBox.qml +++ b/resources/qml/Governikus/Global/GCheckBox.qml @@ -1,47 +1,57 @@ /** * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.View 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.View CheckBox { id: control + property alias descriptionItem: descriptionItemLoader.sourceComponent property alias maximumLineCount: description.maximumLineCount property alias textStyle: description.textStyle - activeFocusOnTab: true padding: 0 - contentItem: GText { - id: description - Accessible.ignored: true - elide: Text.ElideRight - leftPadding: control.indicator.width + control.spacing - maximumLineCount: 1 - text: control.text - textStyle: enabled ? Style.text.normal : Style.text.normal_secondary - verticalAlignment: Text.AlignVCenter + contentItem: ColumnLayout { + spacing: Constants.text_spacing + + GText { + id: description + + Accessible.ignored: true + elide: Text.ElideRight + leftPadding: control.indicator.implicitWidth + control.spacing + maximumLineCount: 1 + text: control.text + textStyle: enabled ? Style.text.normal : Style.text.normal + } + Loader { + id: descriptionItemLoader + + Layout.fillWidth: true + Layout.leftMargin: description.leftPadding + visible: sourceComponent + } } indicator: Rectangle { - border.color: enabled ? Style.color.accent : Style.color.button_disabled - border.width: Math.max(ApplicationModel.scaleFactor * 4, 1) - color: enabled ? (control.checked ? Style.color.button : Style.color.transparent) : Style.color.button_disabled - implicitHeight: ApplicationModel.scaleFactor * 33 + border.color: enabled ? Style.color.control : Style.color.control_disabled + border.width: Math.max(plugin.scaleFactor * 4, 1) + color: enabled ? (control.checked ? Style.color.control : Style.color.transparent) : Style.color.control_disabled + implicitHeight: plugin.scaleFactor * 33 implicitWidth: implicitHeight - radius: Math.max(ApplicationModel.scaleFactor * 4, 1) + radius: Math.max(plugin.scaleFactor * 4, 1) TintableIcon { anchors.fill: parent - anchors.margins: Math.max(ApplicationModel.scaleFactor * 4, 1) + anchors.margins: Math.max(plugin.scaleFactor * 4, 1) fillMode: Image.PreserveAspectFit source: "qrc:///images/checkbox_indicator.svg" - tintColor: Style.color.button_text + tintColor: Style.color.control_content visible: control.checked } } @@ -58,5 +68,10 @@ CheckBox { onClicked: control.toggle() } FocusFrame { + anchors.fill: null + height: indicator.height - 2 * anchors.margins + width: description.x + description.width - 2 * anchors.margins + x: indicator.x + anchors.margins + y: indicator.y + anchors.margins } } diff --git a/resources/qml/Governikus/Global/GCollapsible.qml b/resources/qml/Governikus/Global/GCollapsible.qml new file mode 100644 index 000000000..d64f488c1 --- /dev/null +++ b/resources/qml/Governikus/Global/GCollapsible.qml @@ -0,0 +1,164 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style + +ColumnLayout { + id: root + + property bool alwaysReserveSelectionTitleHight: false + property alias backgroundColor: background.color + property int contentBottomMargin: Constants.groupbox_spacing + property alias contentSpacing: contentItem.spacing + property int contentTopMargin: Constants.groupbox_spacing + property bool drawBottomCorners: false + property bool drawTopCorners: false + default property alias expandableData: contentItem.data + property bool expanded: false + property int horizontalMargin: Constants.component_spacing + property alias selectionIcon: selectionIcon.source + property alias selectionTitle: selectionTitle.text + property alias tintIcon: selectionIcon.tintEnabled + property alias title: title.text + + spacing: 0 + + AbstractButton { + id: expandButton + + Accessible.name: root.title + ". " + + //: LABEL ANDROID IOS + (expanded ? qsTr("collapse") : + //: LABEL ANDROID IOS + qsTr("expand") + ". ") + + //: LABEL ANDROID IOS + (root.selectionTitle !== "" ? qsTr("Currently selected is %1").arg(root.selectionTitle) : "") + Accessible.role: Accessible.Button + Layout.fillWidth: true + implicitHeight: bannerLayout.implicitHeight + Constants.component_spacing * 2 + implicitWidth: bannerLayout.implicitWidth + + background: RoundedRectangle { + bottomLeftCorner: drawBottomCorners && !expanded + bottomRightCorner: drawBottomCorners && !expanded + color: expandButton.pressed ? Style.color.pane_active : Style.color.transparent + topLeftCorner: drawTopCorners + topRightCorner: drawTopCorners + } + contentItem: RowLayout { + id: bannerLayout + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + spacing: 0 + + ColumnLayout { + Layout.leftMargin: horizontalMargin + spacing: Constants.subtext_spacing + + GText { + id: title + + Accessible.ignored: true + color: expandButton.pressed ? Style.color.text_subline_pressed : textStyle.textColor + textStyle: Style.text.subline + visible: text !== "" + } + GText { + id: selectionTitle + + Accessible.ignored: true + color: expandButton.pressed ? Style.color.text_pressed : textStyle.textColor + visible: alwaysReserveSelectionTitleHight || text !== "" + + Behavior on text { + SequentialAnimation { + PropertyAnimation { + duration: Constants.animation_duration + easing.type: Easing.InCubic + property: "opacity" + target: selectionTitle + to: 0 + } + PropertyAction { + property: "text" + target: selectionTitle + } + PropertyAnimation { + duration: Constants.animation_duration + easing.type: Easing.OutCubic + property: "opacity" + target: selectionTitle + to: 1 + } + } + } + } + } + GSpacer { + Layout.fillWidth: true + } + TintableIcon { + id: selectionIcon + + Layout.maximumHeight: Style.dimens.small_icon_size + Layout.maximumWidth: Math.ceil(paintedWidth) + Layout.preferredHeight: Style.dimens.small_icon_size + tintColor: arrow.tintColor + tintEnabled: false + } + TintableIcon { + id: arrow + + Layout.maximumHeight: Style.dimens.small_icon_size + Layout.maximumWidth: Layout.maximumHeight + Layout.preferredHeight: Style.dimens.small_icon_size + Layout.preferredWidth: Layout.preferredHeight + Layout.rightMargin: horizontalMargin + source: expanded ? "qrc:///images/material_expand_less.svg" : "qrc:///images/material_expand_more.svg" + tintColor: expandButton.pressed ? Style.color.text_pressed : Style.color.text + tintEnabled: true + } + } + + onClicked: expanded = !expanded + } + RoundedRectangle { + id: background + + Layout.fillWidth: true + bottomLeftCorner: drawBottomCorners + bottomRightCorner: drawBottomCorners + clip: true + color: Style.color.pane_sublevel + implicitHeight: expanded ? (contentItem.implicitHeight + contentItem.anchors.topMargin + contentItem.anchors.bottomMargin) : 0 + implicitWidth: contentItem.implicitWidth + contentItem.anchors.leftMargin + contentItem.anchors.rightMargin + topLeftCorner: false + topRightCorner: false + + Behavior on implicitHeight { + NumberAnimation { + duration: Constants.animation_duration + } + } + + ColumnLayout { + id: contentItem + + spacing: Constants.groupbox_spacing + + anchors { + bottomMargin: contentBottomMargin + fill: parent + leftMargin: root.horizontalMargin + rightMargin: root.horizontalMargin + topMargin: contentTopMargin + } + } + } +} diff --git a/resources/qml/Governikus/Global/GComboBox.qml b/resources/qml/Governikus/Global/GComboBox.qml index ca9b33018..48b3bcd55 100644 --- a/resources/qml/Governikus/Global/GComboBox.qml +++ b/resources/qml/Governikus/Global/GComboBox.qml @@ -1,11 +1,11 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.View 1.0 -import Governikus.Style 1.0 -import Governikus.Type.ApplicationModel 1.0 +import QtQuick +import QtQuick.Controls +import Governikus.View +import Governikus.Style +import Governikus.Type.ApplicationModel ComboBox { id: control @@ -14,34 +14,33 @@ ComboBox { Accessible.name: displayText Accessible.role: Accessible.ComboBox - font.pixelSize: textStyle.fontSize + font.pixelSize: textStyle.textSize popup.bottomMargin: plugin.safeAreaMargins.bottom popup.leftMargin: plugin.safeAreaMargins.left popup.rightMargin: plugin.safeAreaMargins.right popup.topMargin: plugin.safeAreaMargins.top spacing: Constants.groupbox_spacing - background: Rectangle { - border.color: Style.color.border - border.width: control.visualFocus ? 2 : 1 - color: Style.color.background_pane - radius: Style.dimens.separator_size + background: GPaneBackground { + border.color: control.textStyle.textColor + border.width: Style.dimens.border_width + color: Style.color.transparent } contentItem: GText { elide: Text.ElideRight + leftPadding: Constants.pane_padding maximumLineCount: 1 padding: control.spacing - rightPadding: control.indicator.width + control.spacing + rightPadding: control.spacing text: control.displayText textStyle: control.textStyle - verticalAlignment: Text.AlignVCenter } delegate: ItemDelegate { highlighted: control.highlightedIndex === index width: control.width background: Rectangle { - color: highlighted ? Style.color.background_pane_active : Style.color.background_pane + color: highlighted ? Style.color.control : Style.color.pane_sublevel implicitHeight: Style.dimens.list_item_height implicitWidth: 100 @@ -54,19 +53,18 @@ ComboBox { } } contentItem: GText { + color: highlighted ? Style.color.control_content_hover : control.textStyle.textColor elide: Text.ElideRight text: modelData textStyle: control.textStyle - verticalAlignment: Text.AlignVCenter } } indicator: TintableIcon { - height: Math.round(control.height / 4) - source: "qrc:///images/triangle.svg" + height: control.height * 0.75 + source: down ? "qrc:///images/material_expand_less.svg" : "qrc:///images/material_expand_more.svg" tintColor: control.textStyle.textColor - visible: control.count > 1 width: height - x: Math.round(control.width - width - control.rightPadding) + x: Math.round(control.width - width - control.spacing) y: Math.round(control.topPadding + (control.availableHeight - height) / 2) } diff --git a/resources/qml/Governikus/Global/GConicalGradient.qml b/resources/qml/Governikus/Global/GConicalGradient.qml index 68c24d526..8a20aca1f 100644 --- a/resources/qml/Governikus/Global/GConicalGradient.qml +++ b/resources/qml/Governikus/Global/GConicalGradient.qml @@ -1,7 +1,7 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 +import QtQuick Item { id: root @@ -26,6 +26,7 @@ Item { ShaderEffectSource { id: baseSource + anchors.fill: parent smooth: true sourceItem: root.source diff --git a/resources/qml/Governikus/Global/GControl.qml b/resources/qml/Governikus/Global/GControl.qml new file mode 100644 index 000000000..ca7e07d52 --- /dev/null +++ b/resources/qml/Governikus/Global/GControl.qml @@ -0,0 +1,10 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick +import QtQuick.Controls + +Control { + implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, implicitContentHeight + topPadding + bottomPadding) + implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, implicitContentWidth + leftPadding + rightPadding) +} diff --git a/resources/qml/Governikus/Global/GDropShadow.qml b/resources/qml/Governikus/Global/GDropShadow.qml new file mode 100644 index 000000000..2c743e5d3 --- /dev/null +++ b/resources/qml/Governikus/Global/GDropShadow.qml @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick +import QtQuick.Effects + +MultiEffect { + property real verticalOffset: 7 + + shadowEnabled: true + shadowOpacity: 0.15 + shadowScale: 1.025 + + // Timer is necessary because shadowVerticalOffset does not get updated + // after initialization. Only an external update after the whole UI has + // been loaded leads to the expected result, else the drop shadow will + // be drawn too low. + Timer { + interval: 1 + running: true + + onTriggered: shadowVerticalOffset = Qt.binding(function () { + return verticalOffset; + }) + } +} diff --git a/resources/qml/Governikus/Global/GDropShadow_6.5.qml b/resources/qml/Governikus/Global/GDropShadow_6.5.qml new file mode 100644 index 000000000..b10061e6b --- /dev/null +++ b/resources/qml/Governikus/Global/GDropShadow_6.5.qml @@ -0,0 +1,10 @@ +/* Copyright (c) 2023 Governikus GmbH & Co. KG, Germany +*/ +import QtQuick + +ShaderEffect { + property bool autoPaddingEnabled + property rect paddingRect + property real shadowOpacity + property real verticalOffset +} diff --git a/resources/qml/Governikus/Global/GFlickable.qml b/resources/qml/Governikus/Global/GFlickable.qml index b7731bc68..799f2b64b 100644 --- a/resources/qml/Governikus/Global/GFlickable.qml +++ b/resources/qml/Governikus/Global/GFlickable.qml @@ -1,10 +1,10 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import QtQuick.Controls +import Governikus.Global +import Governikus.Style Flickable { id: baseItem @@ -56,6 +56,7 @@ Flickable { Component { id: scrollBar + GScrollBar { bottomPadding: baseItem.scrollBarBottomPadding + Style.dimens.scrollbar_padding_vertical topPadding: baseItem.scrollBarTopPadding + Style.dimens.scrollbar_padding_vertical diff --git a/resources/qml/Governikus/Global/GFlickableColumnLayout.qml b/resources/qml/Governikus/Global/GFlickableColumnLayout.qml index 20ecb3412..724730429 100644 --- a/resources/qml/Governikus/Global/GFlickableColumnLayout.qml +++ b/resources/qml/Governikus/Global/GFlickableColumnLayout.qml @@ -1,42 +1,37 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global GFlickable { id: root - default property alias children: contentLayout.children - readonly property real effectiveContentWidth: maximumContentWidth > 0 ? Math.min(contentWidth, maximumContentWidth) : contentWidth - property bool fillHeight: true - readonly property real implicitContentHeight: contentLayout.implicitHeight + default property alias data: contentLayout.data property real maximumContentWidth: -1 - property real minimumContentHeight: implicitContentHeight property alias spacing: contentLayout.spacing - bottomMargin: Constants.component_spacing - contentHeight: (fillHeight && d.contentHeightFitsOnScreen) ? d.availableContentHeight : root.minimumContentHeight - contentWidth: root.width - leftMargin - rightMargin - leftMargin: Constants.component_spacing - rightMargin: Constants.component_spacing - topMargin: Constants.component_spacing + bottomMargin: Constants.pane_padding + contentHeight: contentLayout.height + contentWidth: limitingLayout.width + implicitHeight: contentLayout.implicitHeight + topMargin + bottomMargin + implicitWidth: contentLayout.implicitWidth + leftMargin + rightMargin + leftMargin: Constants.pane_padding + rightMargin: Constants.pane_padding + topMargin: Constants.pane_padding - QtObject { - id: d - - property real availableContentHeight: root.height - topMargin - bottomMargin - property bool contentHeightFitsOnScreen: root.minimumContentHeight <= availableContentHeight - } ColumnLayout { - id: contentLayout - anchors.horizontalCenter: parent.horizontalCenter - width: effectiveContentWidth + id: limitingLayout + + height: root.height - root.topMargin - root.bottomMargin + width: root.width - root.leftMargin - root.rightMargin + + ColumnLayout { + id: contentLayout - Binding on height { - delayed: fillHeight - value: root.contentHeight + Layout.alignment: Qt.AlignHCenter | Qt.AlignTop + Layout.maximumWidth: root.maximumContentWidth } } } diff --git a/resources/qml/Governikus/Global/GGridView.qml b/resources/qml/Governikus/Global/GGridView.qml deleted file mode 100644 index 36ae8de66..000000000 --- a/resources/qml/Governikus/Global/GGridView.qml +++ /dev/null @@ -1,57 +0,0 @@ -/** - * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 - -GridView { - id: baseItem - - property real scrollBarBottomPadding: 0 - property bool scrollBarEnabled: true - property real scrollBarTopPadding: 0 - - function handleKeyPress(key) { - if (key === Qt.Key_PageDown) - baseItem.scrollPageDown(); - else if (key === Qt.Key_PageUp) - baseItem.scrollPageUp(); - else if (key === Qt.Key_End) - baseItem.positionViewAtEnd(); - else if (key === Qt.Key_Home) - baseItem.positionViewAtBeginning(); - } - function highlightScrollbar() { - if (ScrollBar.vertical) - ScrollBar.vertical.highlight(); - } - function scrollPageDown() { - Utils.scrollPageDown(baseItem); - } - function scrollPageUp() { - Utils.scrollPageUp(baseItem); - } - - ScrollBar.vertical: scrollBarEnabled ? scrollBar.createObject() : null - boundsBehavior: Constants.is_desktop ? Flickable.StopAtBounds : (contentHeight <= height ? Flickable.StopAtBounds : Flickable.DragAndOvershootBounds) - boundsMovement: Flickable.FollowBoundsBehavior - flickDeceleration: Constants.flickDeceleration - flickableDirection: Flickable.VerticalFlick - maximumFlickVelocity: Constants.scrolling_speed - - Keys.onPressed: event => { - handleKeyPress(event.key); - } - onVisibleChanged: if (visible) - highlightScrollbar() - - Component { - id: scrollBar - GScrollBar { - bottomPadding: baseItem.scrollBarBottomPadding + Style.dimens.scrollbar_padding_vertical - topPadding: baseItem.scrollBarTopPadding + Style.dimens.scrollbar_padding_vertical - } - } -} diff --git a/resources/qml/Governikus/Global/GInformativeButton.qml b/resources/qml/Governikus/Global/GInformativeButton.qml index 6c8c361d7..f5ba63acd 100644 --- a/resources/qml/Governikus/Global/GInformativeButton.qml +++ b/resources/qml/Governikus/Global/GInformativeButton.qml @@ -1,10 +1,10 @@ /** * Copyright (c) 2022-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Style 1.0 -import Governikus.View 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Style +import Governikus.View GButton { id: root @@ -13,11 +13,13 @@ GButton { property real scaleIcon: 1.0 Accessible.name: text + ". " + description + Layout.maximumWidth: Number.POSITIVE_INFINITY horizontalPadding: Constants.component_spacing - textStyle: Style.text.button verticalPadding: Constants.text_spacing contentItem: RowLayout { + readonly property color color: root.pressed ? Style.color.control_content_pressed : root.textStyle.textColor + spacing: Constants.component_spacing z: 1 @@ -27,7 +29,7 @@ GButton { fillMode: Image.Pad source: root.icon.source sourceSize.width: Layout.preferredWidth * scaleIcon - tintColor: root.textStyle.textColor + tintColor: contentItem.color tintEnabled: root.tintIcon } Item { @@ -37,34 +39,31 @@ GButton { ColumnLayout { id: textColumn + anchors.fill: parent spacing: Constants.text_spacing / 2 GText { Accessible.ignored: true Layout.alignment: Qt.AlignBottom - Layout.fillWidth: true + color: contentItem.color elide: Text.ElideRight + font.bold: true maximumLineCount: 1 text: root.text - textStyle: Style.text.button_highlight + textStyle: root.textStyle } GText { id: subText + Accessible.ignored: true Layout.alignment: Qt.AlignTop - Layout.fillWidth: true + color: contentItem.color elide: Text.ElideRight maximumLineCount: 2 textStyle: root.textStyle } } - FocusFrame { - framee: textColumn - isOnLightBackground: false - marginFactor: 0.7 - scope: root - } } } } diff --git a/resources/qml/Governikus/Global/GListView.qml b/resources/qml/Governikus/Global/GListView.qml index 3b87d4d4b..ab7621e1f 100644 --- a/resources/qml/Governikus/Global/GListView.qml +++ b/resources/qml/Governikus/Global/GListView.qml @@ -1,16 +1,17 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import QtQuick.Controls +import Governikus.Global +import Governikus.Style ListView { id: baseItem property bool scrollBarAutohide: !Constants.is_desktop property real scrollBarBottomPadding: 0 + property color scrollBarColor: Style.color.control property bool scrollBarEnabled: true property real scrollBarTopPadding: 0 @@ -54,9 +55,11 @@ ListView { Component { id: scrollBar + GScrollBar { autohide: scrollBarAutohide bottomPadding: baseItem.scrollBarBottomPadding + Style.dimens.scrollbar_padding_vertical + color: baseItem.scrollBarColor topPadding: baseItem.scrollBarTopPadding + Style.dimens.scrollbar_padding_vertical } } diff --git a/resources/qml/Governikus/Global/GPaneBackground.qml b/resources/qml/Governikus/Global/GPaneBackground.qml index 621d6bda3..b0b510b41 100644 --- a/resources/qml/Governikus/Global/GPaneBackground.qml +++ b/resources/qml/Governikus/Global/GPaneBackground.qml @@ -1,13 +1,14 @@ /** * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Style 1.0 +import QtQuick +import Governikus.Style Rectangle { id: root - border.color: Style.color.high_contrast_item_border - border.width: Style.dimens.high_contrast_item_border - color: Style.color.background_pane - radius: Style.dimens.corner_radius + + border.color: Style.color.pane_border + border.width: Style.dimens.border_width + color: Style.color.pane + radius: Style.dimens.pane_radius } diff --git a/resources/qml/Governikus/Global/GPaneBackgroundDelegate.qml b/resources/qml/Governikus/Global/GPaneBackgroundDelegate.qml new file mode 100644 index 000000000..14d1d7a2c --- /dev/null +++ b/resources/qml/Governikus/Global/GPaneBackgroundDelegate.qml @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick +import Governikus.Global +import Governikus.Style + +RoundedRectangle { + property int count: 0 + property int idx: -1 + readonly property bool isFirst: idx === 0 + readonly property bool isLast: idx === (count - 1) + readonly property bool isOnlyElement: count === 1 + + bottomLeftCorner: isLast || isOnlyElement + bottomRightCorner: isLast || isOnlyElement + color: Style.color.pane + topLeftCorner: isFirst || isOnlyElement + topRightCorner: isFirst || isOnlyElement +} diff --git a/resources/qml/Governikus/Global/GProgressBar.qml b/resources/qml/Governikus/Global/GProgressBar.qml index 089373ab0..e6e67ef9b 100644 --- a/resources/qml/Governikus/Global/GProgressBar.qml +++ b/resources/qml/Governikus/Global/GProgressBar.qml @@ -1,16 +1,16 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.View 1.0 +import QtQuick +import QtQuick.Controls +import Governikus.Global +import Governikus.Style +import Governikus.View ProgressBar { id: progressBar - property color backgroundColor: Constants.white + property color backgroundColor: Style.color.background property alias text: progressText.text Accessible.name: qsTr("%1 percent done").arg(value) @@ -19,42 +19,45 @@ ProgressBar { to: 100 background: Rectangle { - border.color: Style.color.border + border.color: Style.color.control_border border.width: Style.dimens.progress_bar_border - color: Style.color.border - radius: Style.dimens.button_radius + color: Style.color.transparent + radius: height / 2 } contentItem: Item { implicitHeight: Style.dimens.progress_bar_height Item { anchors.fill: parent - anchors.margins: Style.dimens.progress_bar_border + anchors.margins: Style.dimens.progress_bar_border * 3 Rectangle { color: progressBar.backgroundColor height: parent.height - radius: Style.dimens.button_radius + radius: height / 2 width: parent.width } Rectangle { - color: Constants.green + property real mutableVisualPosition: visualPosition + + color: Style.color.control height: parent.height - radius: Style.dimens.button_radius - width: parent.width * visualPosition + radius: height / 2 + width: parent.width * mutableVisualPosition - Behavior on width { + Behavior on mutableVisualPosition { SmoothedAnimation { + velocity: 0.5 } } } } GText { id: progressText + elide: Text.ElideMiddle horizontalAlignment: Text.AlignHCenter maximumLineCount: 1 - textStyle: Style.text.normal anchors { left: parent.left diff --git a/resources/qml/Governikus/Global/GRadioButton.qml b/resources/qml/Governikus/Global/GRadioButton.qml index f996f888e..dc8f264da 100644 --- a/resources/qml/Governikus/Global/GRadioButton.qml +++ b/resources/qml/Governikus/Global/GRadioButton.qml @@ -1,13 +1,12 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.View 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.View RadioButton { id: root @@ -17,6 +16,8 @@ RadioButton { property bool tintIcon: false Accessible.name: text + Layout.maximumWidth: contentItem ? contentItem.implicitWidth + leftPadding + rightPadding : -1 + indicator: null spacing: Constants.groupbox_spacing contentItem: RowLayout { @@ -25,14 +26,14 @@ RadioButton { Rectangle { Layout.preferredHeight: root.indicatorHeight Layout.preferredWidth: root.indicatorHeight - border.color: Style.color.accent - border.width: Math.max(ApplicationModel.scaleFactor * 3, 1) + border.color: Style.color.control + border.width: Math.max(plugin.scaleFactor * 3, 1) radius: height / 2 Rectangle { anchors.alignWhenCentered: false anchors.centerIn: parent - color: Style.color.accent + color: Style.color.control height: parent.height / 2 radius: height / 2 visible: root.checked @@ -45,17 +46,14 @@ RadioButton { sourceSize.height: root.indicatorHeight tintColor: root.textStyle.textColor tintEnabled: tintIcon - visible: source != "" + visible: source.toString() !== "" } GText { Accessible.ignored: true - Layout.fillWidth: true text: root.text textStyle: root.textStyle } } - indicator: Item { - } FocusFrame { scope: root diff --git a/resources/qml/Governikus/Global/GRepeater.qml b/resources/qml/Governikus/Global/GRepeater.qml index 89653a7b6..57e088444 100644 --- a/resources/qml/Governikus/Global/GRepeater.qml +++ b/resources/qml/Governikus/Global/GRepeater.qml @@ -1,8 +1,8 @@ /** * Copyright (c) 2022-2023 Governikus GmbH & Co. KG, Germany */ -import QtQml 2.15 -import QtQuick 2.15 +import QtQml +import QtQuick Repeater { id: root diff --git a/resources/qml/Governikus/Global/GScrollBar.qml b/resources/qml/Governikus/Global/GScrollBar.qml index c27672682..fdbfb419a 100644 --- a/resources/qml/Governikus/Global/GScrollBar.qml +++ b/resources/qml/Governikus/Global/GScrollBar.qml @@ -1,14 +1,15 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Style 1.0 +import QtQuick +import QtQuick.Controls +import Governikus.Style ScrollBar { id: baseItem property bool autohide: !Constants.is_desktop + property alias color: handler.color property bool highlighted: false function highlight() { @@ -27,7 +28,7 @@ ScrollBar { implicitWidth: Style.dimens.scrollbar_width + Style.dimens.scrollbar_padding_horizontal opacity: (!autohide || active || highlighted) ? 1.0 : 0.0 - Behavior on opacity { + Behavior on opacity { NumberAnimation { duration: Constants.animation_duration easing.type: Easing.InOutCubic @@ -36,8 +37,9 @@ ScrollBar { Rectangle { id: handler + anchors.left: parent.left - color: baseItem.pressed ? Style.color.button : Style.color.button_disabled + color: Style.color.control height: parent.height radius: width / 2 width: Style.dimens.scrollbar_width @@ -49,6 +51,7 @@ ScrollBar { Timer { id: highlightTimer + onTriggered: baseItem.highlighted = false } } diff --git a/resources/qml/Governikus/Global/GSeparator.qml b/resources/qml/Governikus/Global/GSeparator.qml index b1dc587f6..58554c11e 100644 --- a/resources/qml/Governikus/Global/GSeparator.qml +++ b/resources/qml/Governikus/Global/GSeparator.qml @@ -1,13 +1,13 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Style 1.0 +import QtQuick +import Governikus.Style Rectangle { property int orientation: Qt.Horizontal // Qt.Vertical color: Style.color.border - height: orientation === Qt.Horizontal ? Style.dimens.separator_size : undefined - width: orientation === Qt.Vertical ? Style.dimens.separator_size : undefined + implicitHeight: orientation === Qt.Horizontal ? Style.dimens.separator_size : 0 + implicitWidth: orientation === Qt.Vertical ? Style.dimens.separator_size : 0 } diff --git a/resources/qml/Governikus/Global/GSpacer.qml b/resources/qml/Governikus/Global/GSpacer.qml index f667b8e53..629577fbb 100644 --- a/resources/qml/Governikus/Global/GSpacer.qml +++ b/resources/qml/Governikus/Global/GSpacer.qml @@ -1,7 +1,7 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 +import QtQuick Item { } diff --git a/resources/qml/Governikus/Global/GSwitch.qml b/resources/qml/Governikus/Global/GSwitch.qml new file mode 100644 index 000000000..e0a9d7727 --- /dev/null +++ b/resources/qml/Governikus/Global/GSwitch.qml @@ -0,0 +1,109 @@ +/** + * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick +import QtQuick.Controls +import Governikus.Style +import Governikus.View + +Switch { + id: control + + property bool overwriteHovered: false + property bool overwritePressed: false + + implicitHeight: indicator.implicitHeight + implicitWidth: indicator.implicitWidth + padding: 0 + + // Empty item since we don't want the text + contentItem: Item { + } + indicator: Rectangle { + border.color: d.borderColor + color: d.controlColor + implicitHeight: implicitWidth / 2 + implicitWidth: Style.dimens.switch_width + radius: height / 2 + + Rectangle { + id: ball + + readonly property int distanceBallBorder: 3 + + anchors.verticalCenter: parent.verticalCenter + color: d.contentColor + height: parent.height - 2 * distanceBallBorder + radius: height / 2 + width: height + x: control.checked ? parent.width - width - distanceBallBorder : distanceBallBorder + + Behavior on x { + NumberAnimation { + duration: 200 + easing.type: Easing.InOutQuad + } + } + } + } + + Accessible.onPressAction: toggle() + + FocusFrame { + radius: height / 2 + } + Item { + id: d + + property color borderColor: Style.color.control_border + property color contentColor: Style.color.control_content + property color controlColor: Style.color.control + + states: [ + State { + name: "disabled" + when: !control.enabled + + PropertyChanges { + borderColor: Style.color.control_border_disabled + contentColor: Style.color.control_content_disabled + controlColor: Style.color.control_disabled + target: d + } + }, + State { + name: "hovered" + when: control.overwriteHovered || control.hovered + + PropertyChanges { + borderColor: Style.color.control_border_hover + contentColor: Style.color.control_content_hover + controlColor: Style.color.control_hover + target: d + } + }, + State { + name: "pressed" + when: control.overwritePressed || control.pressed + + PropertyChanges { + borderColor: Style.color.control_border_pressed + contentColor: Style.color.control_content_pressed + controlColor: Style.color.control_pressed + target: d + } + }, + State { + name: "unchecked" + when: !control.checked + + PropertyChanges { + borderColor: Style.color.control_border_unchecked + contentColor: Style.color.control_content_unchecked + controlColor: Style.color.control_unchecked + target: d + } + } + ] + } +} diff --git a/resources/qml/Governikus/Global/GText.qml b/resources/qml/Governikus/Global/GText.qml index 31b78eda2..c770f9fba 100644 --- a/resources/qml/Governikus/Global/GText.qml +++ b/resources/qml/Governikus/Global/GText.qml @@ -1,27 +1,32 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.ApplicationModel 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.Type.ApplicationModel Text { - id: baseItem + id: root + readonly property real effectiveFirstLineHeight: topPadding + Math.ceil(lineHeight) + bottomPadding + readonly property real effectiveMaxLinesHeight: topPadding + maximumLineCount * Math.ceil(lineHeight) + bottomPadding property TextStyle textStyle: Style.text.normal Accessible.ignored: text === "" //: INFO ALL_PLATFORMS Text read by screen reader if the text contains a weblink which may be opened. Accessible.name: ApplicationModel.stripHtmlTags(text) + (Constants.is_desktop && d.hasLink ? " " + qsTr("Press space to open link: %1").arg(d.link) : "") Accessible.role: Accessible.StaticText + Layout.fillWidth: true + Layout.maximumWidth: Math.ceil(implicitWidth) color: textStyle.textColor - font.bold: textStyle.bold - font.italic: textStyle.italic font.pixelSize: textStyle.textSize - font.underline: textStyle.underline - linkColor: textStyle.linkColor + lineHeight: textStyle.lineHeight + lineHeightMode: Text.FixedHeight + linkColor: color + verticalAlignment: Text.AlignVCenter wrapMode: d.nonMultilineElided ? Text.NoWrap : Text.Wrap Component.onCompleted: d.checkForLinks() @@ -34,11 +39,6 @@ Text { Qt.openUrlExternally(pLink); } onTextChanged: d.checkForLinks() - onTextStyleChanged: { - if (textStyle.textFamily !== "") { - font.family = textStyle.textFamily; - } - } QtObject { id: d @@ -64,6 +64,7 @@ Text { } MouseArea { id: mouseArea + acceptedButtons: Qt.NoButton anchors.fill: parent cursorShape: parent.hoveredLink !== "" ? Qt.PointingHandCursor : undefined @@ -72,8 +73,8 @@ Text { Item { ToolTip { delay: Constants.toolTipDelay - text: baseItem.hoveredLink - visible: Constants.is_desktop && baseItem.hoveredLink !== "" + text: root.hoveredLink + visible: Constants.is_desktop && root.hoveredLink !== "" onAboutToShow: { parent.x = mouseArea.mouseX; diff --git a/resources/qml/Governikus/Global/GTextField.qml b/resources/qml/Governikus/Global/GTextField.qml index 6e95ca20f..a9b79011a 100644 --- a/resources/qml/Governikus/Global/GTextField.qml +++ b/resources/qml/Governikus/Global/GTextField.qml @@ -1,16 +1,15 @@ /** * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Style 1.0 -import Governikus.View 1.0 +import QtQuick +import QtQuick.Controls +import Governikus.Style +import Governikus.View TextField { id: baseItem property int enterKeyType: Qt.EnterKeyDefault - property bool isOnLightBackground: true property var textStyle: Style.text.normal property bool valid: true @@ -23,20 +22,19 @@ TextField { activeFocusOnTab: true color: textStyle.textColor font.pixelSize: textStyle.textSize - placeholderTextColor: Style.color.secondary_text + placeholderTextColor: Style.color.text selectByMouse: true - selectedTextColor: Style.color.primary_text_inverse - selectionColor: Style.color.accent + selectedTextColor: Style.color.text + selectionColor: Style.color.control background: Rectangle { border.color: baseItem.valid ? Style.color.border : Constants.red border.width: Style.dimens.separator_size - color: baseItem.enabled ? Style.color.background_pane : Constants.grey - radius: Style.dimens.button_radius + color: baseItem.enabled ? Style.color.pane : Constants.grey + radius: Style.dimens.control_radius } FocusFrame { - isOnLightBackground: baseItem.isOnLightBackground scope: baseItem } } diff --git a/resources/qml/Governikus/Global/LabeledSwitch.qml b/resources/qml/Governikus/Global/LabeledSwitch.qml new file mode 100644 index 000000000..821c549ea --- /dev/null +++ b/resources/qml/Governikus/Global/LabeledSwitch.qml @@ -0,0 +1,89 @@ +/** + * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style + +FocusScope { + property alias checked: entrySwitch.checked + readonly property real contentMargin: Constants.is_desktop ? 0 : Constants.component_spacing + property alias description: descriptionText.text + property bool drawBottomCorners: false + property bool drawTopCorners: false + property alias title: titleText.text + + Accessible.checkable: enabled + Accessible.checked: checked + Accessible.name: title + ". " + description + Accessible.role: Accessible.CheckBox + Layout.fillWidth: true + activeFocusOnTab: true + height: implicitHeight + implicitHeight: contentItem.implicitHeight + 2 * contentMargin + implicitWidth: contentItem.implicitWidth + + Accessible.onPressAction: entrySwitch.toggle() + Accessible.onToggleAction: entrySwitch.toggle() + + RoundedRectangle { + anchors.fill: parent + bottomLeftCorner: parent.drawBottomCorners + bottomRightCorner: parent.drawBottomCorners + color: mouseArea.pressed ? Style.color.pane_active : Style.color.transparent + topLeftCorner: parent.drawTopCorners + topRightCorner: parent.drawTopCorners + + RowLayout { + id: contentItem + + anchors.fill: parent + anchors.leftMargin: contentMargin + anchors.rightMargin: contentMargin + layoutDirection: Constants.is_desktop ? Qt.RightToLeft : Qt.LeftToRight + spacing: Constants.component_spacing + + ColumnLayout { + spacing: Constants.subtext_spacing + + GText { + id: titleText + + Accessible.ignored: true + Layout.maximumWidth: Number.POSITIVE_INFINITY + Layout.preferredHeight: Constants.is_desktop ? Math.max(entrySwitch.implicitHeight, implicitHeight) : -1 + color: entrySwitch.enabled ? (mouseArea.pressed ? Style.color.text_subline_pressed : textStyle.textColor) : Style.color.text_subline_disabled + textStyle: Style.text.subline + } + GText { + id: descriptionText + + Accessible.ignored: true + Layout.maximumWidth: Number.POSITIVE_INFINITY + color: entrySwitch.enabled ? (mouseArea.pressed ? Style.color.text_pressed : textStyle.textColor) : Style.color.text_disabled + visible: text !== "" + } + } + GSwitch { + id: entrySwitch + + Accessible.ignored: true + Layout.alignment: Constants.is_desktop ? Qt.AlignTop : Qt.AlignVCenter + activeFocusOnTab: false + focus: true + overwriteHovered: mouseArea.containsMouse + overwritePressed: mouseArea.pressed + text: titleText.text + } + } + MouseArea { + id: mouseArea + + anchors.fill: parent + hoverEnabled: true + + onClicked: entrySwitch.toggle() + } + } +} diff --git a/resources/qml/Governikus/Global/LabeledText.qml b/resources/qml/Governikus/Global/LabeledText.qml index f4ee9d770..97ddaaff9 100644 --- a/resources/qml/Governikus/Global/LabeledText.qml +++ b/resources/qml/Governikus/Global/LabeledText.qml @@ -1,11 +1,12 @@ /** * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Style 1.0 -import Governikus.View 1.0 +import QtQuick +import Governikus.Style +import Governikus.View Item { + property int alignment: Text.AlignLeft property alias bodyElide: bodyText.elide readonly property double focusFrameMargins: focusFrame.anchors.margins property alias label: labelText.text @@ -31,24 +32,31 @@ Item { } FocusFrame { id: focusFrame + } Column { id: column + + spacing: Constants.subtext_spacing + anchors { left: parent.left right: parent.right } GText { id: labelText + Accessible.ignored: true - textStyle: Style.text.normal_accent + horizontalAlignment: alignment + textStyle: Style.text.subline visible: !!text width: parent.width } GText { id: bodyText + Accessible.ignored: true - textStyle: Constants.is_desktop ? Style.text.normal : Style.text.normal_secondary + horizontalAlignment: alignment visible: !!text width: parent.width diff --git a/resources/qml/Governikus/Global/LocationButton.qml b/resources/qml/Governikus/Global/LocationButton.qml deleted file mode 100644 index 3b57da092..000000000 --- a/resources/qml/Governikus/Global/LocationButton.qml +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.SettingsModel 1.0 - -GRadioButton { - id: root - - property alias image: root.icon.source - property string language - - checked: SettingsModel.language === language - - onCheckedChanged: if (checked) - SettingsModel.language = language -} diff --git a/resources/qml/Governikus/Global/MoreInformationLink.qml b/resources/qml/Governikus/Global/MoreInformationLink.qml index c295983ec..3fabdc075 100644 --- a/resources/qml/Governikus/Global/MoreInformationLink.qml +++ b/resources/qml/Governikus/Global/MoreInformationLink.qml @@ -1,23 +1,26 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.View 1.0 -import Governikus.Style 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.View +import Governikus.Style GButton { id: root property bool iconVisible: true + Layout.fillWidth: true background: null + font.underline: true horizontalPadding: 0 icon.source: iconVisible ? "qrc:///images/info.svg" : "" maximumLineCount: 2 //: LABEL ALL_PLATFORMS text: qsTr("More information") - textStyle: Style.text.link_accent + textStyle: Style.text.link tintIcon: true verticalPadding: 2 } diff --git a/resources/qml/Governikus/Global/NumberField.qml b/resources/qml/Governikus/Global/NumberField.qml index 4ff7ea2aa..43e6b8fff 100644 --- a/resources/qml/Governikus/Global/NumberField.qml +++ b/resources/qml/Governikus/Global/NumberField.qml @@ -1,20 +1,17 @@ /** * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 - -Item { +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.View + +GControl { id: root - readonly property bool confirmedInput: inputConfirmation.length !== number.length || inputConfirmation === number readonly property real eyeWidth: eye.width + eye.Layout.leftMargin + eye.Layout.rightMargin - property string inputConfirmation property alias number: echoField.text property alias passwordLength: echoField.maximumLength @@ -22,7 +19,7 @@ Item { readonly property string passwordState: qsTr("You entered %1 of %2 digits.").arg(number.length).arg(passwordLength) readonly property var text: if (Qt.platform.os === "windows") passwordState - readonly property bool validInput: echoField.acceptableInput && confirmedInput + readonly property bool validInput: echoField.acceptableInput signal accepted @@ -38,7 +35,7 @@ Item { echoField.clear(); } else if (eventKey === Qt.Key_Paste || (eventKey === Qt.Key_V) && (eventModifiers & Qt.ControlModifier)) { echoField.paste(); - } else if (eventKey === Qt.Key_Enter || eventKey === Qt.Key_Return) { + } else if ((eventKey === Qt.Key_Enter || eventKey === Qt.Key_Return) && validInput) { root.accepted(); return true; } else { @@ -61,90 +58,70 @@ Item { //: LABEL DESKTOP Screenreader text for the password field qsTr("The password is hidden.")) + (text === undefined ? " " + passwordState : "") Accessible.role: Accessible.EditableText + Layout.maximumWidth: contentItem.Layout.maximumWidth + leftPadding + rightPadding + Layout.minimumWidth: contentItem.Layout.minimumWidth + leftPadding + rightPadding + Layout.preferredWidth: implicitWidth activeFocusOnTab: true - implicitHeight: layout.implicitHeight - implicitWidth: layout.implicitWidth + implicitHeight: Math.max(grid.implicitHeight, eye.Layout.preferredHeight) + topPadding + bottomPadding - Keys.onPressed: event => { - event.accepted = root.handleKeyEvent(event.key, event.modifiers); - } - onPasswordLengthChanged: root.number = "" - - FontMetrics { - id: fontMetrics - font.bold: true - font.pixelSize: Constants.is_desktop ? ApplicationModel.scaleFactor * 65 : 24 - } - TextInput { - id: echoField - maximumLength: 6 - visible: false - - validator: RegExpValidatorCompat { - expression: new RegExp("[0-9]{" + echoField.maximumLength + "}") - } - } - FocusFrame { - framee: layout - - MouseArea { - acceptedButtons: Qt.AllButtons - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - - onClicked: mouse => { - root.forceActiveFocus(); - if (mouse.button === Qt.RightButton || mouse.button === Qt.MiddleButton) { - echoField.paste(); - } - } - onPressAndHold: root.handleKeyEvent(Qt.Key_Paste) - } - } - RowLayout { + contentItem: RowLayout { id: layout - anchors.fill: parent - spacing: 0 - - Repeater { - model: root.passwordLength - - Text { - readonly property real markerWidth: fontMetrics.averageCharacterWidth * 1.4 - - Layout.fillWidth: true - Layout.maximumWidth: Layout.preferredWidth - Layout.minimumWidth: markerWidth - Layout.preferredHeight: fontMetrics.height + Constants.text_spacing - Layout.preferredWidth: markerWidth + (Constants.is_desktop ? Constants.component_spacing : Constants.groupbox_spacing) - color: Style.color.primary_text - font: fontMetrics.font - horizontalAlignment: Text.AlignHCenter - text: eye.activated ? root.number.substr(index, 1) : "" - verticalAlignment: Text.AlignTop - - Rectangle { - readonly property int normalHeight: Constants.is_desktop ? Math.max(ApplicationModel.scaleFactor * 4, 1) : 1 - - color: parent.color - height: index === root.number.length ? normalHeight * 3 : normalHeight - width: parent.markerWidth - - anchors { - bottom: parent.bottom - horizontalCenter: parent.horizontalCenter + + spacing: Constants.text_spacing + z: 2 + + GridLayout { + id: grid + + readonly property int markerWidth: Math.ceil(fontMetrics.averageCharacterWidth * 1.4) + + Layout.maximumWidth: Layout.preferredWidth + Layout.minimumWidth: markerWidth + Layout.preferredWidth: markerWidth + (markerWidth + columnSpacing) * Math.max(5, root.passwordLength - 1) + columnSpacing: Constants.is_desktop ? Constants.component_spacing : 5 + columns: Math.max(1, Math.min(1 + (width - markerWidth) / (markerWidth + columnSpacing), root.passwordLength)) + rowSpacing: columnSpacing + + Repeater { + model: root.passwordLength + + Text { + Layout.alignment: Qt.AlignHCenter + Layout.maximumHeight: Layout.preferredHeight + Layout.maximumWidth: Layout.preferredWidth + Layout.minimumHeight: Layout.preferredHeight + Layout.minimumWidth: Layout.preferredWidth + Layout.preferredHeight: fontMetrics.height + Constants.text_spacing + Layout.preferredWidth: grid.markerWidth + color: Style.color.text + font: fontMetrics.font + horizontalAlignment: Text.AlignHCenter + text: eye.activated ? root.number.substr(index, 1) : "" + verticalAlignment: Text.AlignTop + + Rectangle { + readonly property int normalHeight: Constants.is_desktop ? Math.max(plugin.scaleFactor * 4, 1) : 1 + + color: parent.color + height: index === root.number.length ? normalHeight * 3 : normalHeight + width: grid.markerWidth + + anchors { + bottom: parent.bottom + horizontalCenter: parent.horizontalCenter + } } - } - Rectangle { - color: parent.color - height: width - radius: height / 2 - visible: !eye.activated && root.number.charAt(index) !== "" - width: fontMetrics.averageCharacterWidth - - anchors { - centerIn: parent - verticalCenterOffset: -Constants.text_spacing / 2 + Rectangle { + color: parent.color + height: width + radius: height / 2 + visible: !eye.activated && root.number.charAt(index) !== "" + width: fontMetrics.averageCharacterWidth + + anchors { + centerIn: parent + verticalCenterOffset: -Constants.text_spacing / 2 + } } } } @@ -154,9 +131,12 @@ Item { property bool activated: false - Layout.leftMargin: Constants.text_spacing - Layout.preferredHeight: implicitHeight + (Constants.is_desktop ? 0 : Constants.text_spacing) - Layout.preferredWidth: implicitWidth + (Constants.is_desktop ? 0 : Constants.text_spacing) + Layout.maximumHeight: Layout.preferredHeight + Layout.maximumWidth: Layout.preferredWidth + Layout.minimumHeight: Layout.preferredHeight + Layout.minimumWidth: Layout.preferredWidth + Layout.preferredHeight: implicitBackgroundHeight + (Constants.is_desktop ? 0 : Constants.text_spacing) + Layout.preferredWidth: implicitBackgroundWidth + (Constants.is_desktop ? 0 : Constants.text_spacing) text: (activated ? //: LABEL DESKTOP Screenreader text for the eye icon to change the password visibility qsTr("Press to hide the password") : @@ -165,9 +145,9 @@ Item { background: TintableIcon { fillMode: Image.Pad - source: eye.activated ? "qrc:///images/material_visibility.svg" : "qrc:///images/material_visibility_off.svg" - sourceSize.height: Constants.is_desktop ? Style.dimens.large_icon_size : Style.dimens.small_icon_size - tintColor: Style.color.secondary_text + source: eye.activated ? "qrc:///images/eye_visibility_on.svg" : "qrc:///images/eye_visibility_off.svg" + sourceSize.height: Constants.is_desktop ? Style.dimens.icon_size : Style.dimens.small_icon_size + tintColor: Style.color.text } contentItem: Item { } @@ -186,4 +166,44 @@ Item { } } } + + Keys.onPressed: event => { + event.accepted = root.handleKeyEvent(event.key, event.modifiers); + } + onPasswordLengthChanged: root.number = "" + + FontMetrics { + id: fontMetrics + + font.bold: true + font.pixelSize: Constants.is_desktop ? plugin.scaleFactor * 50 : 24 + } + TextInput { + id: echoField + + maximumLength: 6 + visible: false + + validator: RegExpValidatorCompat { + expression: new RegExp("[0-9]{" + echoField.maximumLength + "}") + } + } + FocusFrame { + framee: layout + z: 1 + + MouseArea { + acceptedButtons: Qt.AllButtons + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + + onClicked: mouse => { + root.forceActiveFocus(); + if (mouse.button === Qt.RightButton || mouse.button === Qt.MiddleButton) { + echoField.paste(); + } + } + onPressAndHold: root.handleKeyEvent(Qt.Key_Paste) + } + } } diff --git a/resources/qml/Governikus/Global/PkiSwitch.qml b/resources/qml/Governikus/Global/PkiSwitch.qml index 735e9e59d..d207561f9 100644 --- a/resources/qml/Governikus/Global/PkiSwitch.qml +++ b/resources/qml/Governikus/Global/PkiSwitch.qml @@ -1,12 +1,20 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQml 2.15 -import QtQuick 2.15 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.SettingsModel 1.0 +import QtQml +import QtQuick +import Governikus.Type.ApplicationModel +import Governikus.Type.SettingsModel MouseArea { + id: root + + required property string functionName + + Accessible.name: functionName + Accessible.role: Accessible.Button + + Accessible.onPressAction: root.clicked(null) onClicked: { d.counter += 1; switch (d.counter) { diff --git a/resources/qml/Governikus/Global/PrivacyStatement.qml b/resources/qml/Governikus/Global/PrivacyStatement.qml index c1a84752b..f2eeab2f1 100644 --- a/resources/qml/Governikus/Global/PrivacyStatement.qml +++ b/resources/qml/Governikus/Global/PrivacyStatement.qml @@ -1,11 +1,11 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.SettingsModel 1.0 -import Governikus.Style 1.0 +import QtQuick +import Governikus.Global +import Governikus.Type.ApplicationModel +import Governikus.Type.SettingsModel +import Governikus.Style GText { readonly property string privacyStatementDescription: smart ? @@ -22,7 +22,7 @@ GText { readonly property string privacyStatementUrl: smart ? "https://www.ausweisapp.bund.de/%1/aa2/bmi/privacy".arg(SettingsModel.language) : "https://www.ausweisapp.bund.de/%1/aa2/privacy".arg(SettingsModel.language) property bool smart: false + font.bold: true text: privacyStatementText.arg(privacyStatementLink) - textStyle: Style.text.normal_highlight wrapMode: Text.WordWrap } diff --git a/resources/qml/Governikus/Global/ProxyCredentialsPopup.qml b/resources/qml/Governikus/Global/ProxyCredentialsPopup.qml index 4ae01a916..e82c2b46d 100644 --- a/resources/qml/Governikus/Global/ProxyCredentialsPopup.qml +++ b/resources/qml/Governikus/Global/ProxyCredentialsPopup.qml @@ -1,11 +1,10 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 +import QtQuick +import Governikus.Global +import Governikus.Style +import Governikus.View ConfirmationPopup { id: proxyCredentials @@ -39,6 +38,7 @@ ConfirmationPopup { Grid { id: formGrid + columns: 2 spacing: Constants.component_spacing verticalItemAlignment: Text.AlignVCenter @@ -56,8 +56,8 @@ ConfirmationPopup { } GTextField { id: userInput - textStyle: Style.text.normal - width: 500 * ApplicationModel.scaleFactor + + width: 500 * plugin.scaleFactor } GText { //: LABEL DESKTOP Accessible name. @@ -72,9 +72,9 @@ ConfirmationPopup { } GTextField { id: passwordInput + echoMode: TextInput.Password - textStyle: Style.text.normal - width: 500 * ApplicationModel.scaleFactor + width: 500 * plugin.scaleFactor } } } diff --git a/resources/qml/Governikus/Global/RoundedRectangle.qml b/resources/qml/Governikus/Global/RoundedRectangle.qml index bc3c216f1..778281b56 100644 --- a/resources/qml/Governikus/Global/RoundedRectangle.qml +++ b/resources/qml/Governikus/Global/RoundedRectangle.qml @@ -1,19 +1,20 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import Governikus.Global +import Governikus.Style Item { id: roundedRectangle - property color borderColor: Style.color.border - property real borderWidth: 0 + property color borderColor: color + property real borderWidth: Style.dimens.border_width property bool bottomLeftCorner: true property bool bottomRightCorner: true property color color: Style.color.background - property real radius: Style.dimens.corner_radius + property color gradientColor: color + property real radius: Style.dimens.pane_radius property bool topLeftCorner: true property bool topRightCorner: true @@ -29,6 +30,7 @@ Item { Canvas { id: canvas + anchors.fill: parent onPaint: { @@ -36,10 +38,11 @@ Item { if (context === null) { return; } + let oddHeight = height + (Constants.is_desktop || height % 2 ? 0 : 1); context.save(); context.reset(); context.beginPath(); - context.moveTo(0, height / 2); + context.moveTo(0, oddHeight / 2); if (topLeftCorner) { context.lineTo(0, radius); context.arcTo(0, 0, radius, 0, radius); @@ -53,20 +56,27 @@ Item { context.lineTo(width, 0); } if (bottomRightCorner) { - context.lineTo(width, height - radius); - context.arcTo(width, height, width - radius, height, radius); + context.lineTo(width, oddHeight - radius); + context.arcTo(width, oddHeight, width - radius, oddHeight, radius); } else { - context.lineTo(width, height); + context.lineTo(width, oddHeight); } if (bottomLeftCorner) { - context.lineTo(radius, height); - context.arcTo(0, height, 0, height - radius, radius); + context.lineTo(radius, oddHeight); + context.arcTo(0, oddHeight, 0, oddHeight - radius, radius); } else { - context.lineTo(0, height); + context.lineTo(0, oddHeight); } - context.lineTo(height / 2); + context.lineTo(oddHeight / 2); context.closePath(); - context.fillStyle = color; + if (gradientColor != color) { + let gradient = context.createLinearGradient(0, 0, 0, 100); + gradient.addColorStop(0.0, color); + gradient.addColorStop(1.0, gradientColor); + context.fillStyle = gradient; + } else { + context.fillStyle = color; + } context.fill(); if (borderWidth > 0) { context.clip(); diff --git a/resources/qml/Governikus/Global/StatusIcon.qml b/resources/qml/Governikus/Global/StatusIcon.qml deleted file mode 100644 index 14b27c5b3..000000000 --- a/resources/qml/Governikus/Global/StatusIcon.qml +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 - -Rectangle { - property bool borderEnabled: true - property alias busy: busyIndicator.visible - property alias contentBackgroundColor: content.color - property alias source: image.source - property alias text: iconText.text - property alias textStyle: iconText.textStyle - - border.color: borderEnabled ? Style.color.accent : Style.color.transparent - border.width: height / 40 - color: Style.color.transparent - radius: height / 2 - width: height - - GBusyIndicator { - id: busyIndicator - anchors.fill: parent - factor: 1.0 - running: parent.visible - visible: false - } - Rectangle { - id: content - anchors.fill: parent - anchors.margins: parent.height / 8 - border.color: Style.color.high_contrast_item_border - border.width: Style.dimens.high_contrast_item_border - color: Style.color.background_pane - radius: height / 2 - - Image { - id: image - - readonly property string sourceSuffix: source.toString().slice(-3) - - anchors.fill: parent - anchors.margins: parent.height / 8 - fillMode: Image.PreserveAspectFit - sourceSize.height: Constants.is_desktop && sourceSuffix === "svg" ? height : undefined - visible: source.toString().length > 0 - } - GText { - id: iconText - Accessible.ignored: true - anchors.centerIn: parent - textStyle: Style.text.title_accent - visible: text !== "" - } - } -} diff --git a/resources/qml/Governikus/Global/TintableAnimation.qml b/resources/qml/Governikus/Global/TintableAnimation.qml new file mode 100644 index 000000000..2fd6f8891 --- /dev/null +++ b/resources/qml/Governikus/Global/TintableAnimation.qml @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick +import Governikus.Style + +Item { + id: root + + property alias asynchronous: image.asynchronous + property bool desaturate: false + property alias fillMode: image.fillMode + property alias paintedHeight: image.paintedHeight + property alias paintedWidth: image.paintedWidth + property alias playAnimation: animation.enabled + property alias source: image.source + property color tintColor: Style.color.text + property bool tintEnabled: true + + implicitHeight: image.implicitHeight + implicitWidth: image.implicitWidth + width: height * implicitWidth / implicitHeight + + AnimatedImage { + id: image + + anchors.fill: parent + fillMode: Image.PreserveAspectFit + layer.enabled: root.tintEnabled && GraphicsInfo.api !== GraphicsInfo.Software + + layer.effect: ShaderEffect { + property color color: root.tintColor + + fragmentShader: root.desaturate ? "qrc:/shader/DesaturateShader.frag" : "qrc:/shader/ColorOverlayShader.frag" + } + Behavior on source { + id: animation + + enabled: false + + SequentialAnimation { + PropertyAnimation { + duration: Constants.animation_duration + easing.type: Easing.InCubic + property: "opacity" + targets: image + to: 0 + } + PropertyAction { + property: "source" + target: image + } + PropertyAnimation { + duration: Constants.animation_duration + easing.type: Easing.OutCubic + property: "opacity" + targets: image + to: 1 + } + } + } + } +} diff --git a/resources/qml/Governikus/Global/TintableIcon.qml b/resources/qml/Governikus/Global/TintableIcon.qml index b7e9bf0e9..a9912175f 100644 --- a/resources/qml/Governikus/Global/TintableIcon.qml +++ b/resources/qml/Governikus/Global/TintableIcon.qml @@ -1,12 +1,13 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Style 1.0 +import QtQuick +import Governikus.Style Item { id: root + property alias asynchronous: image.asynchronous property bool desaturate: false property alias fillMode: image.fillMode property alias paintedHeight: image.paintedHeight @@ -14,17 +15,16 @@ Item { property alias playAnimation: animation.enabled property alias source: image.source property alias sourceSize: image.sourceSize - property color tintColor: Style.color.primary_text + property color tintColor: Style.color.text property bool tintEnabled: true - property alias transformOrigin: image.transformOrigin implicitHeight: image.implicitHeight implicitWidth: image.implicitWidth Image { id: image + anchors.fill: parent - asynchronous: true fillMode: Image.PreserveAspectFit layer.enabled: root.tintEnabled && GraphicsInfo.api !== GraphicsInfo.Software @@ -33,8 +33,9 @@ Item { fragmentShader: root.desaturate ? "qrc:/shader/DesaturateShader.frag" : "qrc:/shader/ColorOverlayShader.frag" } - Behavior on source { + Behavior on source { id: animation + enabled: false SequentialAnimation { diff --git a/resources/qml/Governikus/Global/Utils.qml b/resources/qml/Governikus/Global/Utils.qml index 916ee9149..5a9b185eb 100644 --- a/resources/qml/Governikus/Global/Utils.qml +++ b/resources/qml/Governikus/Global/Utils.qml @@ -2,46 +2,29 @@ * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ pragma Singleton -import QtQuick 2.15 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.SettingsModel 1.0 +import QtQuick +import Governikus.Type.ApplicationModel +import Governikus.Type.SettingsModel QtObject { function escapeHtml(pStr) { return String(pStr).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); } - function helpTopicOf(pComponent, pDefaultHelpTopic) { - if (pComponent && typeof (pComponent.helpTopic) !== "undefined") { - return pComponent.helpTopic; - } else { - return pDefaultHelpTopic; - } - } - function historyDateString(pDate) { - //: LABEL ALL_PLATFORMS - return (isToday(pDate) ? qsTr("today") : - //: LABEL ALL_PLATFORMS - isYesterday(pDate) ? qsTr("yesterday") : - // dddd is without translation because we want the long day name with every language - isThisWeek(pDate) ? pDate.toLocaleString(Qt.locale(SettingsModel.language), "dddd") : - //: LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString - pDate.toLocaleString(Qt.locale(), qsTr("dd.MM.yyyy"))); - } function isSameDate(pOne, pAnother) { return pOne.getFullYear() === pAnother.getFullYear() && pOne.getMonth() === pAnother.getMonth() && pOne.getDate() === pAnother.getDate(); } function isThisWeek(pDate) { - var monday = new Date; + let monday = new Date; monday.setDate(monday.getDate() - monday.getDay()); pDate.setDate(pDate.getDate() - pDate.getDay()); return isSameDate(monday, pDate); } function isToday(pDate) { - var today = new Date; + let today = new Date; return isSameDate(today, pDate); } function isYesterday(pDate) { - var yesterday = new Date; + let yesterday = new Date; yesterday.setDate(yesterday.getDate() - 1); return isSameDate(yesterday, pDate); } diff --git a/resources/qml/Governikus/Global/qmldir b/resources/qml/Governikus/Global/qmldir index d7e635c71..8b20cd24b 100644 --- a/resources/qml/Governikus/Global/qmldir +++ b/resources/qml/Governikus/Global/qmldir @@ -5,11 +5,11 @@ internal BrandConstants BrandConstants.qml internal DeviceConstants DeviceConstants.qml internal PlatformConstants PlatformConstants.qml -singleton Category 1.0 Category.qml singleton Constants 1.0 Constants.qml singleton Utils 1.0 Utils.qml ConfirmationPopup 1.0 ConfirmationPopup.qml +Crossed 1.0 Crossed.qml DecisionView 1.0 DecisionView.qml GBusyIndicator 1.0 GBusyIndicator.qml @@ -18,6 +18,7 @@ GInformativeButton 1.0 GInformativeButton.qml GCheckBox 1.0 GCheckBox.qml GComboBox 1.0 GComboBox.qml GConicalGradient 1.0 GConicalGradient.qml +GControl 1.0 GControl.qml GFileDialog 1.0 GFileDialog.qml GFlickable 1.0 GFlickable.qml GFlickableColumnLayout 1.0 GFlickableColumnLayout.qml @@ -25,6 +26,7 @@ GGridView 1.0 GGridView.qml GListView 1.0 GListView.qml GPane 1.0 GPane.qml GPaneBackground 1.0 GPaneBackground.qml +GPaneBackgroundDelegate 1.0 GPaneBackgroundDelegate.qml GProgressBar 1.0 GProgressBar.qml GRadioButton 1.0 GRadioButton.qml GRepeater 1.0 GRepeater.qml @@ -44,20 +46,21 @@ NavigationButton 1.0 NavigationButton.qml NumberField 1.0 NumberField.qml PaneTitle 1.0 PaneTitle.qml ProxyCredentialsPopup 1.0 ProxyCredentialsPopup.qml +RetryCounter 1.0 RetryCounter.qml RoundedRectangle 1.0 RoundedRectangle.qml RegExpValidatorCompat 1.0 RegExpValidatorCompat.qml ScrollGradients 1.0 ScrollGradients.qml ScrollablePane 1.0 ScrollablePane.qml -SearchBar 1.0 SearchBar.qml -StatusIcon 1.0 StatusIcon.qml SwipeActionDelegate 1.0 SwipeActionDelegate.qml TabbedPane 1.0 TabbedPane.qml -TabbedPaneDelegateIconAndText 1.0 TabbedPaneDelegateIconAndText.qml -TabbedPaneDelegateIconAndThreeLineText 1.0 TabbedPaneDelegateIconAndThreeLineText.qml -TabbedPaneDelegateText 1.0 TabbedPaneDelegateText.qml PkiSwitch 1.0 PkiSwitch.qml +TintableAnimation 1.0 TintableAnimation.qml TintableIcon 1.0 TintableIcon.qml TitledSeparator 1.0 TitledSeparator.qml PrivacyStatement 1.0 PrivacyStatement.qml Hint 1.0 Hint.qml MoreInformationLink 1.0 MoreInformationLink.qml +GDropShadow 1.0 GDropShadow.qml +GCollapsible 1.0 GCollapsible.qml +GCollapsibleSubButton 1.0 GCollapsibleSubButton.qml +GOptionsContainer 1.0 GOptionsContainer.qml diff --git a/resources/qml/Governikus/HistoryView/+desktop/HistoryRemovalTimePeriodControl.qml b/resources/qml/Governikus/HistoryView/+desktop/HistoryRemovalTimePeriodControl.qml deleted file mode 100644 index c1cb85cea..000000000 --- a/resources/qml/Governikus/HistoryView/+desktop/HistoryRemovalTimePeriodControl.qml +++ /dev/null @@ -1,71 +0,0 @@ -/** - * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 - -RowLayout { - id: root - - property alias description: description - property string period - property alias removalPeriod: removalPeriod - - Accessible.name: description.text - Accessible.role: Accessible.Grouping - spacing: Constants.groupbox_spacing - - GText { - id: description - activeFocusOnTab: true - - //: LABEL DESKTOP - text: qsTr("Time period") - textStyle: Style.text.normal - - FocusFrame { - } - } - GComboBox { - id: removalPeriod - Layout.fillWidth: true - activeFocusOnTab: true - height: ApplicationModel.scaleFactor * 50 - - model: ListModel { - id: timePeriods - - //: LABEL DESKTOP - ListElement { - modelData: qsTr("Past hour") - value: "PAST_HOUR" - } - //: LABEL DESKTOP - ListElement { - modelData: qsTr("Past day") - value: "PAST_DAY" - } - //: LABEL DESKTOP - ListElement { - modelData: qsTr("Past week") - value: "PAST_WEEK" - } - //: LABEL DESKTOP - ListElement { - modelData: qsTr("Last four weeks") - value: "LAST_FOUR_WEEKS" - } - //: LABEL DESKTOP - ListElement { - modelData: qsTr("All history") - value: "ALL_HISTORY" - } - } - - onCurrentIndexChanged: root.period = timePeriods.get(currentIndex).value - } -} diff --git a/resources/qml/Governikus/HistoryView/+desktop/HistoryView.qml b/resources/qml/Governikus/HistoryView/+desktop/HistoryView.qml deleted file mode 100644 index 1af1d0382..000000000 --- a/resources/qml/Governikus/HistoryView/+desktop/HistoryView.qml +++ /dev/null @@ -1,139 +0,0 @@ -/** - * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQml 2.15 -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.HistoryModel 1.0 -import Governikus.Type.SettingsModel 1.0 -import Governikus.View 1.0 - -SectionPage { - id: root - titleBarAction: TitleBarAction { - helpTopic: "history" - //: LABEL DESKTOP - text: qsTr("History") - - customSubAction: SearchBar { - id: searchBar - anchors.verticalCenter: parent ? parent.verticalCenter : undefined - - //: LABEL DESKTOP - placeholderText: qsTr("Search in history") - visible: HistoryModel.rowCount() > 0 - - onDisplayTextChanged: HistoryModel.searchFilter.setFilterString(displayText) - } - } - - onVisibleChanged: if (!visible) - deleteHistoryConfirmationPopup.close() - - ConfirmationPopup { - id: deleteHistoryConfirmationPopup - //: INFO DESKTOP Content of the confirmation dialog to clear the entire authentication history. - text: qsTr("All history entries will be deleted.") - - //: INFO DESKTOP Header of the confirmation dialog to clear the entire authentication history. - title: qsTr("Delete history?") - width: ApplicationModel.scaleFactor * 600 - - onConfirmed: { - var timePeriod = removalPeriod.period; - var removedItemCount = SettingsModel.removeHistory(timePeriod); - tabbedPane.currentIndex = tabbedPane.sectionCount > 0 ? 0 : -1; - //: INFO DESKTOP Feedback how many history entries were removed. - ApplicationModel.showFeedback(qsTr("Deleted %1 entries from the history.").arg(removedItemCount)); - } - - HistoryRemovalTimePeriodControl { - id: removalPeriod - width: parent.width - } - } - TabbedPane { - id: tabbedPane - anchors.fill: parent - anchors.margins: Constants.pane_padding - sectionsModel: HistoryModel.searchFilter - visible: sectionCount > 0 - - contentDelegate: HistoryViewDetails { - activeFocusOnTab: true - historyModelItem: tabbedPane.currentItemModel ? tabbedPane.currentItemModel.model : undefined - } - footerItem: Item { - height: buttonLayout.implicitHeight - - ColumnLayout { - id: buttonLayout - anchors.fill: parent - anchors.rightMargin: Constants.groupbox_spacing - spacing: Constants.groupbox_spacing - - GButton { - id: clearHistoryButton - Layout.fillWidth: true - icon.source: "qrc:///images/material_delete.svg" - //: LABEL DESKTOP - text: qsTr("Clear history") - tintIcon: true - - onClicked: deleteHistoryConfirmationPopup.open() - } - GButton { - id: saveHistoryToPdf - Layout.fillWidth: true - icon.source: "qrc:///images/desktop/material_save.svg" - //: LABEL DESKTOP - text: qsTr("Save as PDF...") - tintIcon: true - - onClicked: { - let now = new Date().toLocaleDateString(Qt.locale(), "yyyy-MM-dd"); - let filenameSuggestion = "%1.%2.%3.pdf".arg(Qt.application.name).arg(qsTr("History")).arg(now); - fileDialog.selectFile(filenameSuggestion); - } - - GFileDialog { - id: fileDialog - defaultSuffix: "pdf" - //: LABEL DESKTOP - nameFilters: qsTr("Portable Document Format (*.pdf)") - - //: LABEL DESKTOP - title: qsTr("Save history") - - onAccepted: HistoryModel.exportHistory(file) - } - } - } - } - sectionDelegate: TabbedPaneDelegateIconAndThreeLineText { - footerText: model ? model.purpose : "" - headerText: model ? Utils.historyDateString(model.dateTime) : "" - iconPath: model ? model.providerIcon : "" - sectionName: model ? model.subject : "" - } - } - GText { - activeFocusOnTab: true - anchors.centerIn: parent - text: HistoryModel.rowCount() === 0 ? - //: INFO DESKTOP No authentication history, placeholder text. - qsTr("Currently there are no history entries.") : - //: INFO DESKTOP No authentication history entries match the search, placeholder text. - qsTr("No history entries match your search term.") - textStyle: Style.text.header - visible: tabbedPane.sectionCount === 0 - - FocusFrame { - } - } -} diff --git a/resources/qml/Governikus/HistoryView/+desktop/HistoryViewDetails.qml b/resources/qml/Governikus/HistoryView/+desktop/HistoryViewDetails.qml deleted file mode 100644 index aaa85d4cf..000000000 --- a/resources/qml/Governikus/HistoryView/+desktop/HistoryViewDetails.qml +++ /dev/null @@ -1,89 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 - -Item { - id: root - - property var historyModelItem - - Accessible.name: qsTr("Details for history entry") - height: columnLayout.height - - ColumnLayout { - id: columnLayout - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - spacing: Constants.pane_spacing - - GText { - text: qsTr("Provider Information") - textStyle: Style.text.header_accent - } - LabeledText { - id: providerName - Layout.fillWidth: true - - //: LABEL DESKTOP - label: qsTr("Provider name") - text: historyModelItem ? historyModelItem.subject : "" - } - LabeledText { - id: purpose - Layout.fillWidth: true - - //: LABEL DESKTOP - label: qsTr("Purpose") - text: historyModelItem ? historyModelItem.purpose : "" - visible: text !== "" - } - LabeledText { - id: date - Layout.fillWidth: true - - //: LABEL DESKTOP - label: qsTr("Date") - text: { - if (!historyModelItem) { - return ""; - } - //: LABEL DESKTOP Date format according to https://doc.qt.io/qt/qdate.html#toString - return historyModelItem.dateTime.toLocaleString(Qt.locale(), qsTr("dd.MM.yyyy")); - } - textUppercase: Font.AllUppercase - } - LabeledText { - id: writtenData - Layout.fillWidth: true - - //: LABEL DESKTOP - label: qsTr("Write access (update)") - text: historyModelItem ? historyModelItem.writtenData : "" - visible: text !== "" - } - LabeledText { - id: requestedData - Layout.fillWidth: true - - //: LABEL DESKTOP - label: qsTr("Read access") - text: historyModelItem ? historyModelItem.requestedData : "" - } - LabeledText { - id: termsOfUsage - Layout.fillWidth: true - - //: LABEL DESKTOP - label: qsTr("Terms of usage") - text: historyModelItem ? historyModelItem.termsOfUsage : "" - } - } -} diff --git a/resources/qml/Governikus/HistoryView/+mobile/+android/HistoryListViewDelegate.qml b/resources/qml/Governikus/HistoryView/+mobile/+android/HistoryListViewDelegate.qml deleted file mode 100644 index 6c454f3e8..000000000 --- a/resources/qml/Governikus/HistoryView/+mobile/+android/HistoryListViewDelegate.qml +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.HistoryModel 1.0 - -HistoryListItem { - id: listItem - contentMarginRight: deleteButton.width + deleteButton.anchors.leftMargin + deleteButton.anchors.rightMargin - width: parent.width - - TintableIcon { - id: deleteButton - anchors.margins: Constants.groupbox_spacing - anchors.right: parent.right - anchors.rightMargin: Style.dimens.titlebar_padding - anchors.verticalCenter: parent.verticalCenter - source: "qrc:///images/material_delete.svg" - sourceSize.width: Style.dimens.small_icon_size - tintColor: Style.color.accent - } - MouseArea { - - //: LABEL ANDROID - Accessible.name: qsTr("Delete entry") - Accessible.role: Accessible.Button - anchors.left: deleteButton.left - anchors.leftMargin: -Constants.groupbox_spacing - anchors.right: parent.right - height: parent.height - - Accessible.onPressAction: clicked(null) - onClicked: HistoryModel.removeRows(index, 1) - } -} diff --git a/resources/qml/Governikus/HistoryView/+mobile/+android/HistoryView.qml b/resources/qml/Governikus/HistoryView/+mobile/+android/HistoryView.qml deleted file mode 100644 index 34fb61648..000000000 --- a/resources/qml/Governikus/HistoryView/+mobile/+android/HistoryView.qml +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.View 1.0 - -BaseHistoryView { - id: baseItem - rightTitleBarAction: HistoryViewTitleBarControls { - showDeleteAll: baseItem.historyItemCount !== 0 - } -} diff --git a/resources/qml/Governikus/HistoryView/+mobile/+android/HistoryViewTitleBarControls.qml b/resources/qml/Governikus/HistoryView/+mobile/+android/HistoryViewTitleBarControls.qml deleted file mode 100644 index 60fd2133b..000000000 --- a/resources/qml/Governikus/HistoryView/+mobile/+android/HistoryViewTitleBarControls.qml +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 - -Row { - id: baseItem - - property alias showDeleteAll: deleteEntriesButtonImage.visible - - height: Style.dimens.titlebar_height - spacing: Constants.component_spacing - - HistoryViewConfirmationPopup { - id: deleteHistoryConfirmationPopup - } - TintableIcon { - id: deleteEntriesButtonImage - anchors.verticalCenter: parent.verticalCenter - height: Style.dimens.small_icon_size - source: "qrc:///images/material_delete.svg" - sourceSize.height: height - tintColor: Style.color.button_text - - MouseArea { - - //: LABEL ANDROID - Accessible.name: qsTr("Delete all entries") - Accessible.role: Accessible.Button - anchors.fill: parent - - Accessible.onPressAction: clicked(null) - onClicked: deleteHistoryConfirmationPopup.open() - } - } -} diff --git a/resources/qml/Governikus/HistoryView/+mobile/+ios/HistoryListViewDelegate.qml b/resources/qml/Governikus/HistoryView/+mobile/+ios/HistoryListViewDelegate.qml deleted file mode 100644 index c5101f1cf..000000000 --- a/resources/qml/Governikus/HistoryView/+mobile/+ios/HistoryListViewDelegate.qml +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.HistoryModel 1.0 - -SwipeActionDelegate { - id: swipeComponent - - property var historyModelItem - property bool showSeparator: true - - //: INFO IOS Accessible name for the trash icon of a history entry. - actionAccessibleName: qsTr("Delete history entry: %1").arg(historyModelItem.subject) - actionColor: Constants.red - actionIcon: "qrc:///images/material_delete.svg" - actionIconTintColor: Style.color.button_text - - contentItem: HistoryListItem { - historyModelItem: swipeComponent.historyModelItem - mouseAreaEnabled: false - pressed: swipeComponent.pressed - showSeparator: swipeComponent.showSeparator - } - - onActionClicked: HistoryModel.removeRows(index, 1) -} diff --git a/resources/qml/Governikus/HistoryView/+mobile/+ios/HistoryView.qml b/resources/qml/Governikus/HistoryView/+mobile/+ios/HistoryView.qml deleted file mode 100644 index 9fc723eec..000000000 --- a/resources/qml/Governikus/HistoryView/+mobile/+ios/HistoryView.qml +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 -import Governikus.Type.HistoryModel 1.0 - -BaseHistoryView { - id: baseItem - rightTitleBarAction: TitleBarAction { - //: LABEL IOS - text: baseItem.historyItemCount > 0 ? qsTr("Delete all entries") : "" - - onClicked: deleteHistoryConfirmationPopup.open() - } - - HistoryViewConfirmationPopup { - id: deleteHistoryConfirmationPopup - } -} diff --git a/resources/qml/Governikus/HistoryView/+mobile/BaseHistoryView.qml b/resources/qml/Governikus/HistoryView/+mobile/BaseHistoryView.qml deleted file mode 100644 index fe4cc72c0..000000000 --- a/resources/qml/Governikus/HistoryView/+mobile/BaseHistoryView.qml +++ /dev/null @@ -1,84 +0,0 @@ -/** - * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 -import Governikus.Type.HistoryModel 1.0 - -SectionPage { - id: rootPage - - property alias historyItemCount: listView.count - property alias listViewModel: listView.model - - sectionPageFlickable: listView - - //: INFO ANDROID IOS - title: qsTr("History") - - navigationAction: NavigationAction { - action: enabled ? NavigationAction.Action.Back : NavigationAction.Action.None - enabled: stackView && stackView.depth > 1 - - onClicked: pop() - } - - GText { - anchors.centerIn: parent - //: INFO ANDROID IOS No authentication history, placeholder text. - text: qsTr("Currently there are no history entries.") - textStyle: Style.text.normal_secondary - visible: listView.count === 0 - } - GListView { - id: listView - anchors.fill: parent - model: HistoryModel - - delegate: HistoryListViewDelegate { - historyModelItem: model - showSeparator: index < listView.count - 1 - width: listView.width - - Accessible.onScrollDownAction: historyListView.positionViewAtIndex(index, ListView.Beginning) - Accessible.onScrollUpAction: historyListView.positionViewAtIndex(index, ListView.End) - onClicked: push(detailsHistoryView, { - "historyModelItem": historyModelItem - }) - } - footer: Component { - GSeparator { - width: parent.width - } - } - remove: Transition { - NumberAnimation { - duration: Constants.animation_duration / 2 - from: 1.0 - property: "opacity" - to: 0 - } - } - removeDisplaced: Transition { - SequentialAnimation { - PauseAnimation { - duration: Constants.animation_duration / 2 - } - NumberAnimation { - duration: Constants.animation_duration / 2 - properties: "y" - } - } - } - } - Component { - id: detailsHistoryView - HistoryViewDetails { - } - } -} diff --git a/resources/qml/Governikus/HistoryView/+mobile/HistoryListItem.qml b/resources/qml/Governikus/HistoryView/+mobile/HistoryListItem.qml deleted file mode 100644 index f34fe535e..000000000 --- a/resources/qml/Governikus/HistoryView/+mobile/HistoryListItem.qml +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Type.HistoryModel 1.0 -import Governikus.Type.SettingsModel 1.0 - -ListItem { - property var historyModelItem - - //: LABEL ANDROID IOS - Accessible.description: qsTr("Click to view details of history entry.") - //: LABEL ANDROID IOS - footerText: historyModelItem.purpose !== "" ? historyModelItem.purpose : qsTr("Tap for more details") - headerText: Utils.historyDateString(dateTime) - height: 72 - icon: providerIcon !== "" ? providerIcon : (historyModelItem ? Category.imageSource(historyModelItem.providerCategory) : Category.imageSource("unknown")) - text: subject -} diff --git a/resources/qml/Governikus/HistoryView/+mobile/HistoryViewConfirmationPopup.qml b/resources/qml/Governikus/HistoryView/+mobile/HistoryViewConfirmationPopup.qml deleted file mode 100644 index e5d3a70b8..000000000 --- a/resources/qml/Governikus/HistoryView/+mobile/HistoryViewConfirmationPopup.qml +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.SettingsModel 1.0 - -ConfirmationPopup { - //: LABEL ANDROID IOS - okButtonText: qsTr("Delete") - //: LABEL ANDROID IOS Confirmaton popup to clear all history entries. - text: qsTr("All history entries will be deleted.") - //: LABEL ANDROID IOS - title: qsTr("Delete history") - - onConfirmed: SettingsModel.removeHistory("ALL_HISTORY") -} diff --git a/resources/qml/Governikus/HistoryView/+mobile/HistoryViewDetails.qml b/resources/qml/Governikus/HistoryView/+mobile/HistoryViewDetails.qml deleted file mode 100644 index e684ef1fa..000000000 --- a/resources/qml/Governikus/HistoryView/+mobile/HistoryViewDetails.qml +++ /dev/null @@ -1,112 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 - -SectionPage { - id: root - - property var historyModelItem - - title: historyModelItem ? historyModelItem.subject : "" - titleBarColor: Category.displayColor(historyModelItem ? historyModelItem.providerCategory : "") - - content: Item { - height: pane.height + 2 * Constants.component_spacing - width: root.width - - Column { - anchors.fill: parent - anchors.margins: Constants.component_spacing - - GPane { - id: pane - //: LABEL ANDROID IOS - title: qsTr("Provider Information") - - anchors { - left: parent.left - right: parent.right - } - LabeledText { - - //: LABEL ANDROID IOS - label: qsTr("Provider name") - text: historyModelItem ? historyModelItem.subject : "" - width: parent.width - - Accessible.onScrollDownAction: scrollPageDown() - Accessible.onScrollUpAction: scrollPageUp() - } - LabeledText { - - //: LABEL ANDROID IOS - label: qsTr("Purpose") - text: historyModelItem ? historyModelItem.purpose : "" - visible: text !== "" - width: parent.width - - Accessible.onScrollDownAction: scrollPageDown() - Accessible.onScrollUpAction: scrollPageUp() - } - LabeledText { - - //: LABEL ANDROID IOS - label: qsTr("Date") - text: { - if (!historyModelItem) { - return ""; - } - //: LABEL ANDROID IOS Date format according to https://doc.qt.io/qt/qdate.html#toString - return historyModelItem.dateTime.toLocaleString(Qt.locale(), qsTr("dd.MM.yyyy")); - } - width: parent.width - - Accessible.onScrollDownAction: scrollPageDown() - Accessible.onScrollUpAction: scrollPageUp() - } - LabeledText { - - //: LABEL ANDROID IOS - label: qsTr("Write access (update)") - text: historyModelItem ? historyModelItem.writtenData : "" - visible: text !== "" - width: parent.width - - Accessible.onScrollDownAction: scrollPageDown() - Accessible.onScrollUpAction: scrollPageUp() - } - LabeledText { - - //: LABEL ANDROID IOS - label: qsTr("Read access") - text: historyModelItem ? historyModelItem.requestedData : "" - width: parent.width - - Accessible.onScrollDownAction: scrollPageDown() - Accessible.onScrollUpAction: scrollPageUp() - } - LabeledText { - - //: LABEL ANDROID IOS - label: qsTr("Terms of usage") - text: historyModelItem ? historyModelItem.termsOfUsage : "" - width: parent.width - - Accessible.onScrollDownAction: scrollPageDown() - Accessible.onScrollUpAction: scrollPageUp() - } - } - } - } - navigationAction: NavigationAction { - action: NavigationAction.Action.Back - - onClicked: pop() - } -} diff --git a/resources/qml/Governikus/HistoryView/qmldir b/resources/qml/Governikus/HistoryView/qmldir deleted file mode 100644 index 74d6bcb57..000000000 --- a/resources/qml/Governikus/HistoryView/qmldir +++ /dev/null @@ -1,11 +0,0 @@ -module HistoryView - -internal BaseHistoryView BaseHistoryView.qml -internal HistoryListItem HistoryListItem.qml -internal HistoryListViewDelegate HistoryListViewDelegate.qml -internal HistoryRemovalTimePeriodControl HistoryRemovalTimePeriodControl.qml -internal HistoryViewConfirmationPopup HistoryViewConfirmationPopup.qml -internal HistoryViewDetails HistoryViewDetails.qml -internal HistoryViewTitleBarControls HistoryViewTitleBarControls.qml - -HistoryView 1.0 HistoryView.qml diff --git a/resources/qml/Governikus/InformationView/+desktop/DiagnosisView.qml b/resources/qml/Governikus/InformationView/+desktop/DiagnosisView.qml index 1311aa91f..9811c4742 100644 --- a/resources/qml/Governikus/InformationView/+desktop/DiagnosisView.qml +++ b/resources/qml/Governikus/InformationView/+desktop/DiagnosisView.qml @@ -1,58 +1,63 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.View 1.0 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.SelfDiagnosisModel 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.View +import Governikus.Global +import Governikus.Style +import Governikus.TitleBar +import Governikus.Type.ApplicationModel +import Governikus.Type.DiagnosisModel SectionPage { id: sectionPage + anchors.centerIn: parent titleBarAction: TitleBarAction { - helpTopic: "diagnosis" //: LABEL DESKTOP - text: qsTr("Diagnosis") + text: qsTr("System data") } - Component.onCompleted: SelfDiagnosisModel.startController() - Component.onDestruction: SelfDiagnosisModel.stopController() + DiagnosisModel { + id: diagnosisModel + } TabbedPane { id: sectionContent + anchors.fill: parent - anchors.margins: Constants.pane_padding - contentDelegate: sectionDelegate + contentDelegate: diagnosisContentDelegate footerItem: footerDelegate - sectionsModel: SelfDiagnosisModel.sectionsModel + sectionsModel: diagnosisModel } Component { - id: sectionDelegate - Column { - height: implicitHeight - spacing: Constants.pane_spacing - - Repeater { - model: sectionContent.currentItemModel.content - - delegate: LabeledText { - activeFocusOnTab: true - label: title - labelStyle: (title !== "" && content === "") ? Style.text.header_accent : Style.text.normal_accent - text: content - width: parent.width - - onActiveFocusChanged: { - if (activeFocus) { - if (focusFrameMargins < 0) - sectionContent.scrollYPositionIntoView(y + height - focusFrameMargins); - else - sectionContent.scrollYPositionIntoView(y + height); + id: diagnosisContentDelegate + + GPane { + Column { + Layout.fillWidth: true + spacing: Constants.pane_spacing + + Repeater { + model: sectionContent.currentItemModel.content + + delegate: LabeledText { + activeFocusOnTab: true + label: title + labelStyle: (title !== "" && content === "") ? Style.text.headline : Style.text.subline + text: content + width: parent.width + + onActiveFocusChanged: { + if (activeFocus) { + if (focusFrameMargins < 0) + sectionContent.scrollYPositionIntoView(y + height - focusFrameMargins); + else + sectionContent.scrollYPositionIntoView(y + height); + } } } } @@ -61,43 +66,47 @@ SectionPage { } Component { id: footerDelegate + Item { height: saveToFile.height GButton { id: saveToFile - Accessible.description: qsTr("Save diagnosis to textfile") + + Accessible.description: qsTr("Save system data to textfile") anchors.fill: parent anchors.rightMargin: Constants.groupbox_spacing //: LABEL DESKTOP disabledTooltipText: qsTr("Diagnosis is still running") - enableButton: !SelfDiagnosisModel.running || !timeout.running + enableButton: !diagnosisModel.running || !timeout.running //: LABEL DESKTOP - enabledTooltipText: SelfDiagnosisModel.running ? qsTr("Diagnosis may be incomplete") : "" - icon.source: "qrc:///images/desktop/material_save.svg" + enabledTooltipText: diagnosisModel.running ? qsTr("Diagnosis may be incomplete") : "" + icon.source: "qrc:///images/desktop/save_icon.svg" //: LABEL DESKTOP text: qsTr("Save to file") tintIcon: true onClicked: { - var filenameSuggestion = "%1.%2.%3.txt".arg(Qt.application.name).arg(qsTr("Diagnosis")).arg(SelfDiagnosisModel.getCreationTime()); + let filenameSuggestion = "%1.%2.%3.txt".arg(Qt.application.name).arg(qsTr("SystemData")).arg(diagnosisModel.getCreationTime()); fileDialog.selectFile(filenameSuggestion); } GFileDialog { id: fileDialog + defaultSuffix: "txt" //: LABEL DESKTOP nameFilters: qsTr("Textfiles (*.txt)") //: LABEL DESKTOP - title: qsTr("Save diagnosis") + title: qsTr("Save system data") - onAccepted: SelfDiagnosisModel.saveToFile(file) + onAccepted: diagnosisModel.saveToFile(file) } } Timer { id: timeout + interval: 10000 repeat: false running: true diff --git a/resources/qml/Governikus/InformationView/+desktop/LicenseInformation.qml b/resources/qml/Governikus/InformationView/+desktop/LicenseInformation.qml index c0922d587..d0ef38f46 100644 --- a/resources/qml/Governikus/InformationView/+desktop/LicenseInformation.qml +++ b/resources/qml/Governikus/InformationView/+desktop/LicenseInformation.qml @@ -1,29 +1,51 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.View 1.0 -import Governikus.Style 1.0 -import Governikus.Type.ApplicationModel 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.View +import Governikus.Style +import Governikus.Type.ApplicationModel GListView { id: listView - readonly property string helpTopic: "helpLicenseinformation" - activeFocusOnTab: true + anchors.fill: parent displayMarginBeginning: Constants.pane_padding displayMarginEnd: Constants.pane_padding model: ApplicationModel.getLicenseText() - delegate: GText { - Accessible.ignored: text === "" - text: model.modelData - textStyle: Style.text.normal + delegate: RoundedRectangle { + readonly property bool isFirstItem: index === 0 + readonly property bool isLastItem: index === ListView.view.count - 1 + + bottomLeftCorner: isLastItem + bottomRightCorner: isLastItem + color: Style.color.pane + implicitHeight: delegateText.implicitHeight + delegateText.anchors.bottomMargin + delegateText.anchors.topMargin + topLeftCorner: isFirstItem + topRightCorner: isFirstItem width: listView.width - Constants.pane_padding + z: currentIndex === index ? 1 : 0 + + GText { + id: delegateText + Accessible.ignored: text === "" + text: model.modelData + + anchors { + bottomMargin: isLastItem ? Constants.pane_padding : 0 + fill: parent + leftMargin: Constants.pane_padding + rightMargin: Constants.pane_padding + topMargin: isFirstItem ? Constants.pane_padding : Constants.text_spacing + } + } FocusFrame { + framee: delegateText } } @@ -37,4 +59,11 @@ GListView { listView.decrementCurrentIndex(); } while (currentItem.text === "") } + + layer { + enabled: GraphicsInfo.api !== GraphicsInfo.Software + + effect: GDropShadow { + } + } } diff --git a/resources/qml/Governikus/InformationView/+desktop/ReleaseNotes.qml b/resources/qml/Governikus/InformationView/+desktop/ReleaseNotes.qml index cadaa9fe7..9bcc78b74 100644 --- a/resources/qml/Governikus/InformationView/+desktop/ReleaseNotes.qml +++ b/resources/qml/Governikus/InformationView/+desktop/ReleaseNotes.qml @@ -1,24 +1,33 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.View 1.0 -import Governikus.Style 1.0 -import Governikus.Type.ReleaseInformationModel 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.View +import Governikus.Style +import Governikus.Type.ReleaseInformationModel ColumnLayout { id: root + Component.onCompleted: releaseInformationModel.update() ReleaseInformationModel { id: releaseInformationModel + } ReleaseNotesView { Layout.fillHeight: true Layout.fillWidth: true model: releaseInformationModel.currentRelease + + layer { + enabled: GraphicsInfo.api !== GraphicsInfo.Software + + effect: GDropShadow { + } + } } GButton { Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom diff --git a/resources/qml/Governikus/InformationView/+desktop/VersionInformation.qml b/resources/qml/Governikus/InformationView/+desktop/VersionInformation.qml index 129b52ed2..ad8dd94d6 100644 --- a/resources/qml/Governikus/InformationView/+desktop/VersionInformation.qml +++ b/resources/qml/Governikus/InformationView/+desktop/VersionInformation.qml @@ -1,34 +1,35 @@ /** * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.SettingsModel 1.0 -import Governikus.Type.VersionInformationModel 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.View +import Governikus.Type.ApplicationModel +import Governikus.Type.SettingsModel +import Governikus.Type.VersionInformationModel Item { id: baseItem - readonly property string helpTopic: "helpVersioninformation" - implicitHeight: column.implicitHeight implicitWidth: column.implicitWidth - ColumnLayout { + GPane { id: column + anchors.fill: parent spacing: Constants.component_spacing Repeater { id: repeater + model: VersionInformationModel delegate: LabeledText { id: delegate + Accessible.name: model.label + ": " + model.text label: model.label text: model.text diff --git a/resources/qml/Governikus/InformationView/+mobile/LicenseInformation.qml b/resources/qml/Governikus/InformationView/+mobile/LicenseInformation.qml index 9965e9e8d..84adec3ce 100644 --- a/resources/qml/Governikus/InformationView/+mobile/LicenseInformation.qml +++ b/resources/qml/Governikus/InformationView/+mobile/LicenseInformation.qml @@ -1,15 +1,18 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 +import QtQuick +import Governikus.Global +import Governikus.Style +import Governikus.TitleBar +import Governikus.View +import Governikus.Type.ApplicationModel SectionPage { id: root - sectionPageFlickable: listView + + contentIsScrolled: !listView.atYBeginning + //: LABEL ANDROID IOS title: qsTr("Software license") @@ -19,26 +22,54 @@ SectionPage { onClicked: pop() } - GPane { - id: pane - clip: true + Connections { + function onActivate() { + listView.highlightScrollbar(); + } + } + GListView { + id: listView + + displayMarginBeginning: Constants.pane_padding + displayMarginEnd: Constants.pane_padding + model: ApplicationModel.getLicenseText() + + delegate: Item { + implicitHeight: delegateText.implicitHeight + implicitWidth: root.width + + GPaneBackgroundDelegate { + anchors.centerIn: parent + anchors.horizontalCenterOffset: -Constants.pane_padding + count: listView.count + height: delegateText.implicitHeight + idx: index + width: Math.min(listView.width - Constants.pane_padding, Style.dimens.max_text_width) + + GText { + id: delegateText + + anchors.fill: parent + bottomPadding: parent.isLast ? Constants.pane_padding : 0 + leftPadding: Constants.pane_padding + rightPadding: Constants.pane_padding + text: modelData + topPadding: parent.isFirst ? Constants.pane_padding : 0 + } + } + } anchors { + bottomMargin: Constants.pane_padding fill: parent - margins: Constants.pane_padding + leftMargin: Constants.pane_padding + topMargin: Constants.pane_padding } - GListView { - id: listView - displayMarginBeginning: Constants.pane_padding - displayMarginEnd: Constants.pane_padding - height: pane.height - 2 * Constants.pane_padding - model: ApplicationModel.getLicenseText() - width: pane.width - Constants.pane_padding - - delegate: GText { - text: model.modelData - width: listView.width - Constants.pane_padding - } + } + layer { + enabled: true + + effect: GDropShadow { } } } diff --git a/resources/qml/Governikus/InformationView/+mobile/ReleaseNotes.qml b/resources/qml/Governikus/InformationView/+mobile/ReleaseNotes.qml index aab8cc290..d787280c5 100644 --- a/resources/qml/Governikus/InformationView/+mobile/ReleaseNotes.qml +++ b/resources/qml/Governikus/InformationView/+mobile/ReleaseNotes.qml @@ -1,17 +1,19 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 -import Governikus.Type.ReleaseInformationModel 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.TitleBar +import Governikus.View +import Governikus.Type.ReleaseInformationModel SectionPage { id: root - sectionPageFlickable: releaseNotes + + contentIsScrolled: !releaseNotes.atYBeginning + //: LABEL ANDROID IOS title: qsTr("Release notes") @@ -23,39 +25,45 @@ SectionPage { Component.onCompleted: releaseInformationModel.update() + Connections { + function onActivate() { + releaseNotes.highlightScrollbar(); + } + } ReleaseInformationModel { id: releaseInformationModel + } - GPane { - id: pane - clip: true + ColumnLayout { + ReleaseNotesView { + id: releaseNotes + Layout.fillHeight: true + Layout.fillWidth: true + maximumContentWidth: Style.dimens.max_text_width + model: releaseInformationModel.currentRelease + } + GSpacer { + Layout.fillHeight: retryButton.visible + } + GButton { + id: retryButton + + Layout.alignment: Qt.AlignHCenter + Layout.rightMargin: Constants.pane_padding + icon.source: "qrc:///images/material_refresh.svg" + //: LABEL ANDROID IOS + text: qsTr("Retry") + tintIcon: true + visible: releaseInformationModel.allowRetry + + onClicked: releaseInformationModel.update() + } anchors { + bottomMargin: Constants.pane_padding fill: parent - margins: Constants.pane_padding - } - ColumnLayout { - height: pane.height - pane.anchors.topMargin - pane.anchors.bottomMargin - width: pane.width - pane.anchors.leftMargin - - ReleaseNotesView { - id: releaseNotes - Layout.fillHeight: true - Layout.fillWidth: true - model: releaseInformationModel.currentRelease - } - GButton { - Layout.alignment: Qt.AlignHCenter - Layout.rightMargin: pane.anchors.rightMargin - icon.source: "qrc:///images/material_refresh.svg" - - //: LABEL ANDROID IOS - text: qsTr("Retry") - tintIcon: true - visible: releaseInformationModel.allowRetry - - onClicked: releaseInformationModel.update() - } + leftMargin: Constants.pane_padding + topMargin: Constants.pane_padding } } } diff --git a/resources/qml/Governikus/InformationView/+mobile/VersionInformation.qml b/resources/qml/Governikus/InformationView/+mobile/VersionInformation.qml index f8ca7cf5b..c4460c776 100644 --- a/resources/qml/Governikus/InformationView/+mobile/VersionInformation.qml +++ b/resources/qml/Governikus/InformationView/+mobile/VersionInformation.qml @@ -1,77 +1,73 @@ /** * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.SettingsModel 1.0 -import Governikus.Type.VersionInformationModel 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.TitleBar +import Governikus.View +import Governikus.Type.ApplicationModel +import Governikus.Type.SettingsModel +import Governikus.Type.VersionInformationModel -SectionPage { +FlickableSectionPage { id: root + //: LABEL ANDROID IOS title: qsTr("Version Information") - content: Item { - height: pane.height + 2 * Constants.component_spacing - width: root.width + navigationAction: NavigationAction { + action: NavigationAction.Action.Back + + onClicked: pop() + } - Column { - id: column - anchors.fill: parent - anchors.margins: Constants.component_spacing + MouseArea { + property int advancedSettingsCounter: 0 - GPane { - id: pane - anchors { - left: parent.left - right: parent.right - } - Repeater { - model: VersionInformationModel + Layout.fillWidth: true + implicitHeight: pane.implicitHeight - LabeledText { - id: delegate - anchors.left: parent.left - anchors.right: parent.right - label: model.label - text: model.text - } - } + onClicked: { + advancedSettingsCounter += 1; + switch (advancedSettingsCounter) { + case 7: + case 8: + case 9: + //: INFO ANDROID IOS Used in notifications when the user taps the version information + ApplicationModel.showFeedback(qsTr("%1 more presses to toggle the advanced settings.").arg(10 - advancedSettingsCounter), true); + break; + case 10: + SettingsModel.advancedSettings = !SettingsModel.advancedSettings; + ApplicationModel.showFeedback(SettingsModel.advancedSettings ? + //: LABEL ANDROID IOS + qsTr("Advanced settings activated.") : + //: LABEL ANDROID IOS + qsTr("Advanced settings deactivated."), true); + advancedSettingsCounter = 0; + break; } } - MouseArea { - property int advancedSettingsCounter: 0 - anchors.fill: column + GPane { + id: pane - onClicked: { - advancedSettingsCounter += 1; - switch (advancedSettingsCounter) { - case 7: - case 8: - case 9: - //: INFO ANDROID IOS Used in notifications when the user taps the version information - ApplicationModel.showFeedback(qsTr("%1 more presses to toggle the advanced settings.").arg(10 - advancedSettingsCounter), true); - break; - case 10: - SettingsModel.advancedSettings = !SettingsModel.advancedSettings; - ApplicationModel.showFeedback(SettingsModel.advancedSettings ? - //: LABEL ANDROID IOS - qsTr("Advanced settings activated.") : - //: LABEL ANDROID IOS - qsTr("Advanced settings deactivated.")); - advancedSettingsCounter = 0; - break; + anchors { + left: parent.left + right: parent.right + } + Repeater { + model: VersionInformationModel + + LabeledText { + id: delegate + + anchors.left: parent.left + anchors.right: parent.right + label: model.label + text: model.text } } } } - navigationAction: NavigationAction { - action: NavigationAction.Action.Back - - onClicked: pop() - } } diff --git a/resources/qml/Governikus/InformationView/ReleaseNotesView.qml b/resources/qml/Governikus/InformationView/ReleaseNotesView.qml index 5c7080c1b..eb60a096d 100644 --- a/resources/qml/Governikus/InformationView/ReleaseNotesView.qml +++ b/resources/qml/Governikus/InformationView/ReleaseNotesView.qml @@ -1,55 +1,84 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.View 1.0 -import Governikus.Style 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.FormattedTextModel 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.View +import Governikus.Style +import Governikus.Type.ApplicationModel +import Governikus.Type.FormattedTextModel GListView { id: root + + property real maximumContentWidth: Number.POSITIVE_INFINITY + activeFocusOnTab: true displayMarginBeginning: Constants.pane_padding displayMarginEnd: Constants.pane_padding - delegate: RowLayout { - id: row + delegate: Item { + height: row.implicitHeight + width: root.width - readonly property alias text: contentText.text + GPaneBackgroundDelegate { + id: delegate - Accessible.ignored: contentText.text === "" - Accessible.name: ApplicationModel.stripHtmlTags(contentText.text) - Accessible.role: Accessible.StaticText - width: root.width - Constants.pane_padding + anchors.centerIn: parent + anchors.horizontalCenterOffset: -Constants.pane_padding / 2 + count: root.count + idx: index + implicitHeight: row.implicitHeight + implicitWidth: Math.min(root.width - Constants.pane_padding, root.maximumContentWidth) - GText { - Accessible.ignored: true - Layout.fillHeight: true - fontSizeMode: Text.Fit - text: "•" - textStyle: contentText.textStyle - verticalAlignment: Text.AlignTop - visible: lineType === LineType.LISTITEM - } - GText { - id: contentText - Accessible.ignored: true - Layout.fillWidth: true - font.underline: lineType === LineType.SECTION - text: content - textStyle: { - switch (lineType) { - case LineType.HEADER: - return Style.text.title; - case LineType.SECTION: - return Style.text.header; - case LineType.SUBSECTION: - return Style.text.header_accent; - default: - return Style.text.normal; + RowLayout { + id: row + + readonly property int horizontalPadding: Constants.pane_padding + readonly property alias text: contentText.text + + Accessible.ignored: contentText.text === "" + Accessible.name: ApplicationModel.stripHtmlTags(contentText.text) + Accessible.role: Accessible.StaticText + anchors.fill: parent + implicitHeight: Math.max(prefix.implicitHeight, contentText.implicitHeight) + + GText { + id: prefix + + Accessible.ignored: true + Layout.fillHeight: true + fontSizeMode: Text.Fit + leftPadding: row.horizontalPadding + text: "•" + textStyle: contentText.textStyle + verticalAlignment: Text.AlignTop + visible: lineType === LineType.LISTITEM + } + GText { + id: contentText + + Accessible.ignored: true + Layout.maximumWidth: Number.POSITIVE_INFINITY + bottomPadding: delegate.isLast ? Constants.pane_padding : 0 + font.underline: lineType === LineType.SECTION + leftPadding: prefix.visible ? 0 : row.horizontalPadding + rightPadding: row.horizontalPadding + text: content + textStyle: { + switch (lineType) { + case LineType.HEADER: + return Style.text.title; + case LineType.SECTION: + return Style.text.headline; + case LineType.SUBSECTION: + return Style.text.subline; + default: + return Style.text.normal; + } + } + topPadding: delegate.isFirst ? Constants.pane_padding : 0 } } } @@ -70,4 +99,11 @@ GListView { root.decrementCurrentIndex(); } while (currentItem.text === "") } + + layer { + enabled: true + + effect: GDropShadow { + } + } } diff --git a/resources/qml/Governikus/InformationView/qmldir b/resources/qml/Governikus/InformationView/qmldir index 0c4f06f98..73919d641 100644 --- a/resources/qml/Governikus/InformationView/qmldir +++ b/resources/qml/Governikus/InformationView/qmldir @@ -1,5 +1,6 @@ module InformationView + DiagnosisView 1.0 DiagnosisView.qml LicenseInformation 1.0 LicenseInformation.qml ReleaseNotes 1.0 ReleaseNotes.qml diff --git a/resources/qml/Governikus/MainView/+desktop/MainView.qml b/resources/qml/Governikus/MainView/+desktop/MainView.qml index 82f4ef294..7fff5d202 100644 --- a/resources/qml/Governikus/MainView/+desktop/MainView.qml +++ b/resources/qml/Governikus/MainView/+desktop/MainView.qml @@ -1,111 +1,70 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.SelfAuthModel 1.0 -import Governikus.Type.UiModule 1.0 +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import Governikus.Global +import Governikus.Style +import Governikus.View +import Governikus.Type.ApplicationModel +import Governikus.Type.SelfAuthModel +import Governikus.Type.UiModule SectionPage { id: sectionPage + GridLayout { - anchors.fill: parent - anchors.margins: Constants.component_spacing * 2 columnSpacing: Constants.component_spacing - columns: 5 - rowSpacing: Constants.component_spacing * 2 - rows: 3 + columns: 2 + rowSpacing: Constants.component_spacing + rows: 2 - Tile { - Layout.fillHeight: true - Layout.fillWidth: true - activeFocusOnTab: true - image: "qrc:/images/mydata.svg" - - //: LABEL DESKTOP - title: qsTr("See my
personal data") - - onClicked: sectionPage.nextView(UiModule.SELF_AUTHENTICATION) - } - GSeparator { - Layout.fillHeight: true - Layout.preferredWidth: Style.dimens.separator_size_large - orientation: Qt.Vertical + anchors { + bottomMargin: anchors.topMargin + fill: parent + leftMargin: anchors.rightMargin + rightMargin: Constants.component_spacing + Math.max(0, (sectionPage.width - sectionPage.height) / 2) + topMargin: Constants.component_spacing + Math.max(0, (sectionPage.height - sectionPage.width) / 2) } Tile { Layout.fillHeight: true Layout.fillWidth: true activeFocusOnTab: true - image: "qrc:/images/provider.svg" + image: "qrc:/images/lock.svg" //: LABEL DESKTOP - title: qsTr("Provider") + title: qsTr("Change PIN") - onClicked: sectionPage.nextView(UiModule.PROVIDER) - } - GSeparator { - Layout.fillHeight: true - Layout.preferredWidth: Style.dimens.separator_size_large - orientation: Qt.Vertical + onClicked: sectionPage.nextView(UiModule.PINMANAGEMENT) } Tile { Layout.fillHeight: true Layout.fillWidth: true activeFocusOnTab: true - image: "qrc:/images/material_history.svg" + image: "qrc:/images/mydata.svg" //: LABEL DESKTOP - title: qsTr("History") + title: qsTr("See my
personal data") - onClicked: sectionPage.nextView(UiModule.HISTORY) - } - GSeparator { - Layout.columnSpan: 5 - Layout.fillWidth: true - Layout.preferredHeight: Style.dimens.separator_size_large + onClicked: sectionPage.nextView(UiModule.SELF_AUTHENTICATION) } Tile { Layout.fillHeight: true Layout.fillWidth: true activeFocusOnTab: true - image: "qrc:/images/material_settings.svg" + image: "qrc:/images/desktop/settings.svg" //: LABEL DESKTOP title: qsTr("Settings") onClicked: sectionPage.nextView(UiModule.SETTINGS) } - GSeparator { - Layout.fillHeight: true - Layout.preferredWidth: Style.dimens.separator_size_large - orientation: Qt.Vertical - } - Tile { - Layout.fillHeight: true - Layout.fillWidth: true - activeFocusOnTab: true - image: "qrc:/images/material_lock.svg" - - //: LABEL DESKTOP - title: qsTr("Change my
(Transport) PIN") - - onClicked: sectionPage.nextView(UiModule.PINMANAGEMENT) - } - GSeparator { - Layout.fillHeight: true - Layout.preferredWidth: Style.dimens.separator_size_large - orientation: Qt.Vertical - } Tile { Layout.fillHeight: true Layout.fillWidth: true activeFocusOnTab: true - image: "qrc:/images/material_help.svg" + image: "qrc:/images/desktop/help.svg" //: LABEL DESKTOP title: qsTr("Help") diff --git a/resources/qml/Governikus/MainView/+desktop/Tile.qml b/resources/qml/Governikus/MainView/+desktop/Tile.qml index 9a8041b48..32f4bce85 100644 --- a/resources/qml/Governikus/MainView/+desktop/Tile.qml +++ b/resources/qml/Governikus/MainView/+desktop/Tile.qml @@ -1,14 +1,15 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 +import QtQuick +import Governikus.Global +import Governikus.Style +import Governikus.View +import Governikus.Type.ApplicationModel +import Governikus.Type.SettingsModel -FocusScope { - id: tile +RoundedRectangle { + id: root property alias image: image.source property alias title: text.text @@ -17,42 +18,50 @@ FocusScope { Accessible.name: ApplicationModel.stripHtmlTags(title) Accessible.role: Accessible.Button + borderColor: Style.color.pane_border + color: mouseArea.pressed ? Style.color.control : Style.color.pane + layer.enabled: GraphicsInfo.api !== GraphicsInfo.Software + opacity: SettingsModel.showBetaTesting ? 0.9 : 1.0 - Keys.onSpacePressed: tile.clicked() + layer.effect: GDropShadow { + } + + Keys.onSpacePressed: clicked() MouseArea { + id: mouseArea + anchors.fill: parent cursorShape: Qt.PointingHandCursor - onClicked: tile.clicked() - onPressed: tile.focus = true + onClicked: root.clicked() } FocusFrame { } - TintableIcon { - id: image + Column { + spacing: Constants.component_spacing - readonly property int imageHeight: Style.dimens.huge_icon_size + anchors { + left: parent.left + margins: 2 * Constants.pane_padding + right: parent.right + top: parent.top + } + TintableIcon { + id: image - sourceSize.height: imageHeight - tintColor: text.textStyle.textColor + readonly property int imageHeight: Style.dimens.huge_icon_size - anchors { - bottom: parent.verticalCenter - bottomMargin: imageHeight * -(1 / 4) - horizontalCenter: parent.horizontalCenter + sourceSize.height: imageHeight + tintColor: mouseArea.pressed ? Style.color.mainbutton_content_pressed : Style.color.text_subline } - } - GText { - id: text - horizontalAlignment: Text.AlignHCenter - textStyle: Style.text.title_accent_highlight + GText { + id: text - anchors { - left: parent.left - right: parent.right - top: image.bottom - topMargin: Constants.component_spacing + color: mouseArea.pressed ? Style.color.mainbutton_content_pressed : Style.color.text_title + horizontalAlignment: Text.AlignLeft + textStyle: Style.text.navigation + width: parent.width } } } diff --git a/resources/qml/Governikus/MainView/+mobile/+phone/Tile.qml b/resources/qml/Governikus/MainView/+mobile/+phone/Tile.qml deleted file mode 100644 index 72527d49a..000000000 --- a/resources/qml/Governikus/MainView/+mobile/+phone/Tile.qml +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 - -GPaneBackground { - id: root - - property alias image: image.source - property alias title: text.text - - signal clicked - - Accessible.name: title - Accessible.role: Accessible.Button - color: Qt.darker(Style.color.accent, mouseArea.pressed ? Constants.highlightDarkerFactor : 1) - - Accessible.onPressAction: clicked() - - MouseArea { - id: mouseArea - anchors.fill: root - - onClicked: root.clicked() - } - TintableIcon { - id: image - Accessible.ignored: true - height: root.height - Constants.pane_padding - sourceSize.height: Style.dimens.large_icon_size - tintColor: text.color - - anchors { - left: root.left - leftMargin: Constants.component_spacing - verticalCenter: root.verticalCenter - } - } - GText { - id: text - Accessible.ignored: true - color: Qt.darker(textStyle.textColor, mouseArea.pressed ? Constants.highlightDarkerFactor : 1) - elide: Text.ElideRight - horizontalAlignment: Text.AlignHCenter - textStyle: Style.text.title_inverse_highlight - verticalAlignment: Text.AlignVCenter - - anchors { - bottom: root.bottom - left: image.right - leftMargin: Constants.text_spacing - right: root.right - rightMargin: Constants.text_spacing - top: root.top - } - } -} diff --git a/resources/qml/Governikus/MainView/+mobile/+tablet/Tile.qml b/resources/qml/Governikus/MainView/+mobile/+tablet/Tile.qml deleted file mode 100644 index 2f844edd0..000000000 --- a/resources/qml/Governikus/MainView/+mobile/+tablet/Tile.qml +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 - -GPaneBackground { - id: root - - property alias image: image.source - property alias title: text.text - - signal clicked - - Accessible.name: title - Accessible.role: Accessible.Button - color: Qt.darker(Style.color.accent, mouseArea.pressed ? Constants.highlightDarkerFactor : 1) - - Accessible.onPressAction: clicked() - - MouseArea { - id: mouseArea - anchors.fill: root - - onClicked: root.clicked() - } - ColumnLayout { - anchors.fill: parent - anchors.margins: Constants.pane_spacing - spacing: Constants.text_spacing - - GSpacer { - Layout.fillHeight: true - } - TintableIcon { - id: image - Accessible.ignored: true - Layout.alignment: Qt.AlignHCenter - Layout.fillHeight: true - Layout.maximumHeight: Style.dimens.huge_icon_size - Layout.preferredHeight: Style.dimens.huge_icon_size - sourceSize.height: Style.dimens.huge_icon_size - tintColor: text.color - } - GText { - id: text - Accessible.ignored: true - Layout.fillHeight: true - Layout.fillWidth: true - Layout.minimumHeight: lineHeight - color: Qt.darker(textStyle.textColor, mouseArea.pressed ? Constants.highlightDarkerFactor : 1) - elide: Text.ElideRight - horizontalAlignment: Text.AlignHCenter - textStyle: Style.text.title_inverse_highlight - verticalAlignment: Text.AlignVCenter - } - GSpacer { - Layout.fillHeight: true - } - } -} diff --git a/resources/qml/Governikus/MainView/+mobile/MainView.qml b/resources/qml/Governikus/MainView/+mobile/MainView.qml index 6fbd3fef5..8a5d59753 100644 --- a/resources/qml/Governikus/MainView/+mobile/MainView.qml +++ b/resources/qml/Governikus/MainView/+mobile/MainView.qml @@ -1,87 +1,149 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.View 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.Type.UiModule 1.0 -import Governikus.Type.WorkflowModel 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.View +import Governikus.Style +import Governikus.TitleBar +import Governikus.Type.UiModule +import Governikus.Type.ApplicationModel +import Governikus.Type.WorkflowModel -SectionPage { - id: sectionPage +FlickableSectionPage { + id: root + + fillWidth: true + margins: 0 //: LABEL ANDROID IOS title: qsTr("Start page") - GridLayout { - columnSpacing: Constants.component_spacing - flow: GridLayout.TopToBottom - rowSpacing: Constants.component_spacing - rows: Constants.is_tablet ? 2 : 4 - - anchors { - fill: parent - margins: Constants.pane_padding + Component.onCompleted: { + if (WorkflowModel.isSmartSupported) { + tileModel.append({ + "imagePath": "qrc:///images/mobile/smarteid.svg", + "module": UiModule.SMART_EID, + //: LABEL ANDROID IOS + "titleText": qsTr("Smart-eID") + }); } - Tile { - Layout.alignment: Qt.AlignHCenter - Layout.fillHeight: true - Layout.fillWidth: true - image: "qrc:///images/mobile/device.svg" + } - //: LABEL ANDROID IOS - title: qsTr("Check device and ID card") + ListModel { + id: tileModel - onClicked: show(UiModule.CHECK_ID_CARD) + ListElement { + imagePath: "qrc:///images/mobile/device.svg" + module: UiModule.CHECK_ID_CARD + //: LABEL ANDROID IOS + titleText: qsTr("Check device and ID card") } - Tile { - Layout.alignment: Qt.AlignHCenter - Layout.fillHeight: true - Layout.fillWidth: true - image: "qrc:///images/material_lock.svg" - + ListElement { + imagePath: "qrc:///images/lock.svg" + module: UiModule.PINMANAGEMENT //: LABEL ANDROID IOS - title: qsTr("Change my (Transport) PIN") - - onClicked: show(UiModule.PINMANAGEMENT) + titleText: qsTr("Change PIN") } - Tile { - Layout.alignment: Qt.AlignHCenter - Layout.fillHeight: true - Layout.fillWidth: true - image: "qrc:///images/mydata.svg" - + ListElement { + imagePath: "qrc:///images/mydata.svg" + module: UiModule.SELF_AUTHENTICATION //: LABEL ANDROID IOS - title: qsTr("See my personal data") + titleText: qsTr("See my personal data") + } + } + GSpacer { + Layout.fillHeight: true + Layout.minimumHeight: Constants.pane_padding + } + GListView { + id: tileView + + readonly property bool allItemsVisible: root.width > allItemsWidth + readonly property int allItemsWidth: count * (itemWidth + spacing) - spacing + readonly property bool isIos: Qt.platform.os === "ios" + readonly property real itemWidth: Math.min(maximumItemWidth, Math.ceil(width * overlapFactor)) + property real maximumItemWidth: 1 + property real minItemHeight: 1 + property real minItemWidth: 1 + readonly property real overlapFactor: 0.72 + readonly property string scrollHint: qsTr("Two finger swipe to scroll.") - onClicked: show(UiModule.SELF_AUTHENTICATION) + function updateTileLimits() { + var newMaximumItemWidth = -1; + for (var index = 0; index < tileView.count; index++) { + let item = tileView.itemAtIndex(index); + if (!item) + continue; + if (index === 0) { + tileView.minItemHeight = item.Layout.minimumHeight; + tileView.minItemWidth = item.Layout.minimumWidth; + } + newMaximumItemWidth = Math.max(newMaximumItemWidth, item.implicitWidth); + } + if (newMaximumItemWidth >= 0) { + tileView.maximumItemWidth = Math.ceil(newMaximumItemWidth); + } } - Tile { - Layout.alignment: Qt.AlignHCenter - Layout.fillHeight: true - Layout.fillWidth: true - image: "qrc:///images/identify.svg" - //: LABEL ANDROID IOS - title: qsTr("Smart-eID") - visible: WorkflowModel.isSmartSupported + Layout.bottomMargin: Constants.component_spacing + Layout.fillHeight: true + Layout.fillWidth: true + Layout.maximumHeight: 400 + Layout.maximumWidth: allItemsVisible ? allItemsWidth : Number.POSITIVE_INFINITY + Layout.minimumHeight: minItemHeight + Layout.minimumWidth: Math.ceil(minItemWidth / overlapFactor) + activeFocusOnTab: true + boundsBehavior: Flickable.DragAndOvershootBounds + cacheBuffer: Number.POSITIVE_INFINITY + clip: true + highlightMoveDuration: 250 + highlightRangeMode: allItemsVisible ? ListView.NoHighlightRange : ListView.StrictlyEnforceRange + interactive: !allItemsVisible + maximumFlickVelocity: 4 * width + model: tileModel + orientation: Qt.Horizontal + preferredHighlightBegin: width / 2 - itemWidth / 2 + preferredHighlightEnd: width / 2 + itemWidth / 2 + snapMode: ListView.SnapOneItem - onClicked: show(UiModule.SMART) + delegate: Tile { + Accessible.ignored: tileView.isIos ? false : index !== tileView.currentIndex + Accessible.name: titleText + ". " + qsTr("Item %1 of %2").arg(index + 1).arg(tileView.count) + (tileView.isIos ? "" : " . " + tileView.scrollHint) + height: ListView.view.height + image: imagePath + title: titleText + width: tileView.itemWidth + + onClicked: show(module) } - Tile { - Layout.alignment: Qt.AlignHCenter - Layout.fillHeight: true - Layout.fillWidth: true - image: "qrc:///images/provider.svg" - //: LABEL ANDROID IOS - title: qsTr("Provider") - visible: !WorkflowModel.isSmartSupported + Component.onCompleted: { + updateTileLimits(); + currentIndex = ApplicationModel.isScreenReaderRunning() && isIos ? 1 : 0; + } + onHeightChanged: updateTileLimits() + onWidthChanged: updateTileLimits() + } + PageIndicator { + id: indicator - onClicked: show(UiModule.PROVIDER) + Layout.alignment: Qt.AlignCenter + count: tileView.count + currentIndex: tileView.currentIndex + opacity: tileView.allItemsVisible ? 0 : 1 + + delegate: Rectangle { + color: index === indicator.currentIndex ? Style.color.control_border : Style.color.control_border_disabled + implicitHeight: Style.dimens.pageindicator_size + implicitWidth: Style.dimens.pageindicator_size + radius: width / 2 } } + GSpacer { + Layout.fillHeight: true + Layout.minimumHeight: Constants.pane_padding + } } diff --git a/resources/qml/Governikus/MainView/+mobile/Tile.qml b/resources/qml/Governikus/MainView/+mobile/Tile.qml new file mode 100644 index 000000000..666ebbadc --- /dev/null +++ b/resources/qml/Governikus/MainView/+mobile/Tile.qml @@ -0,0 +1,80 @@ +/** + * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style + +AbstractButton { + id: root + + readonly property bool flowVertically: height > topPadding + image.implicitHeight + layout.spacing + text.effectiveMaxLinesHeight + bottomPadding + property alias image: image.source + readonly property int insetBaseValue: Constants.component_spacing + readonly property int paddingBaseValue: Constants.component_spacing + property alias title: text.text + + Accessible.name: title + Accessible.role: Accessible.Button + Layout.maximumHeight: Number.POSITIVE_INFINITY + Layout.maximumWidth: leftPadding + image.implicitWidth + layout.spacing + Math.ceil(text.implicitWidth) + rightPadding + Layout.minimumHeight: topPadding + Math.max(image.implicitHeight, text.effectiveMaxLinesHeight) + bottomPadding + Layout.minimumWidth: leftPadding + image.implicitWidth + rightPadding + bottomInset: Math.ceil(insetBaseValue * 1.5) + bottomPadding: bottomInset + paddingBaseValue + implicitHeight: topPadding + layout.implicitHeight + bottomPadding + implicitWidth: flowVertically ? 300 : Layout.maximumWidth + leftInset: insetBaseValue + leftPadding: leftInset + paddingBaseValue + rightInset: insetBaseValue + rightPadding: rightInset + paddingBaseValue + topInset: insetBaseValue + topPadding: topInset + paddingBaseValue + + background: GPaneBackground { + Accessible.ignored: true + color: root.pressed ? Style.color.control : Style.color.pane + layer.enabled: GraphicsInfo.api !== GraphicsInfo.Software + + layer.effect: GDropShadow { + } + + Accessible.onPressAction: clicked() + } + contentItem: GridLayout { + id: layout + + readonly property int spacing: Constants.component_spacing + + columnSpacing: spacing + columns: 3 + flow: root.flowVertically ? GridLayout.TopToBottom : GridLayout.LeftToRight + rowSpacing: spacing + rows: 3 + + TintableIcon { + id: image + + Accessible.ignored: true + sourceSize.height: Style.dimens.medium_icon_size + tintColor: root.pressed ? Style.color.mainbutton_content_pressed : Style.color.text_subline + } + GText { + id: text + + Accessible.ignored: true + color: root.pressed ? Style.color.mainbutton_content_pressed : Style.color.text_title + elide: Text.ElideRight + horizontalAlignment: Text.AlignLeft + maximumLineCount: 3 + rightPadding: root.flowVertically ? paddingBaseValue : 0 + textStyle: Style.text.title + } + GSpacer { + Layout.fillHeight: true + visible: root.flowVertically + } + } +} diff --git a/resources/qml/Governikus/MoreView/+desktop/MoreView.qml b/resources/qml/Governikus/MoreView/+desktop/MoreView.qml index a2e54b218..eef81e978 100644 --- a/resources/qml/Governikus/MoreView/+desktop/MoreView.qml +++ b/resources/qml/Governikus/MoreView/+desktop/MoreView.qml @@ -1,18 +1,20 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQml.Models 2.15 -import Governikus.Global 1.0 -import Governikus.View 1.0 -import Governikus.TitleBar 1.0 -import Governikus.FeedbackView 1.0 -import Governikus.InformationView 1.0 -import Governikus.Type.ApplicationModel 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQml.Models +import Governikus.Global +import Governikus.View +import Governikus.TitleBar +import Governikus.FeedbackView +import Governikus.InformationView +import Governikus.Type.ApplicationModel SectionPage { id: sectionPage + enum SubViews { None, Diagnosis, @@ -22,7 +24,6 @@ SectionPage { property int activeSubView titleBarAction: TitleBarAction { - helpTopic: Utils.helpTopicOf(tabbedPane.currentContentItem, "helpSection") //: LABEL DESKTOP text: qsTr("Help") @@ -39,13 +40,14 @@ SectionPage { TabbedPane { id: tabbedPane + anchors.fill: parent - anchors.margins: Constants.pane_spacing + contentRightMargin: currentContentItem instanceof LicenseInformation || currentContentItem instanceof ReleaseNotes ? 0 : Constants.pane_padding sectionsModel: [ //: LABEL DESKTOP qsTr("General"), //: LABEL DESKTOP - qsTr("Diagnosis and logs"), + qsTr("Data and logs"), //: LABEL DESKTOP qsTr("Version information"), //: LABEL DESKTOP @@ -61,6 +63,8 @@ SectionPage { } Component { MoreViewDiagnosis { + onShowDiagnosis: sectionPage.activeSubView = MoreView.SubViews.Diagnosis + onShowLogs: sectionPage.activeSubView = MoreView.SubViews.ApplicationLog } } Component { @@ -69,43 +73,30 @@ SectionPage { } Component { LicenseInformation { - height: tabbedPane.availableHeight - - anchors { - left: parent.left - right: parent.right - rightMargin: -Constants.pane_padding - } + Layout.preferredHeight: tabbedPane.availableHeight } } Component { ReleaseNotes { - height: tabbedPane.availableHeight - - anchors { - left: parent.left - right: parent.right - rightMargin: -Constants.pane_padding - } + Layout.preferredHeight: tabbedPane.availableHeight } } } - sectionDelegate: TabbedPaneDelegateText { - sectionName: model ? model.modelData : "" - } } Component { id: diagnosisView + DiagnosisView { } } Component { id: logFileView + LogView { } } Loader { - readonly property bool sectionPageTypeMarker: true + readonly property bool breadcrumpSearchPath: true property var titleBarAction: item ? item.titleBarAction : undefined anchors.fill: parent diff --git a/resources/qml/Governikus/MoreView/+desktop/MoreViewDiagnosis.qml b/resources/qml/Governikus/MoreView/+desktop/MoreViewDiagnosis.qml index 30f3f2002..46f32f26d 100644 --- a/resources/qml/Governikus/MoreView/+desktop/MoreViewDiagnosis.qml +++ b/resources/qml/Governikus/MoreView/+desktop/MoreViewDiagnosis.qml @@ -1,27 +1,28 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.View 1.0 -import Governikus.Type.SettingsModel 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.View +import Governikus.Type.SettingsModel + +GPane { + signal showDiagnosis + signal showLogs -ColumnLayout { spacing: Constants.component_spacing MoreViewMenuItem { Layout.fillWidth: true //: LABEL DESKTOP - buttonText: qsTr("Show diagnosis") - //: LABEL DESKTOP - description: qsTr("You can view and save the diagnosis information of the AusweisApp2 and your system here.") - iconSource: "qrc:/images/desktop/material_highlight.svg" + buttonText: qsTr("Show system data") + iconSource: "qrc:/images/info.svg" //: LABEL DESKTOP - title: qsTr("Diagnosis") + title: qsTr("System data") - onClicked: sectionPage.activeSubView = MoreView.SubViews.Diagnosis + onClicked: showDiagnosis() } GSeparator { Layout.fillWidth: true @@ -30,31 +31,11 @@ ColumnLayout { Layout.fillWidth: true //: LABEL DESKTOP buttonText: qsTr("Show logs") - //: LABEL DESKTOP - description: qsTr("Do you want to view the logs of %1?").arg(Qt.application.name) - iconSource: "qrc:/images/desktop/material_view_list.svg" + iconSource: "qrc:/images/desktop/list_icon.svg" //: LABEL DESKTOP title: qsTr("Logs") - onClicked: sectionPage.activeSubView = MoreView.SubViews.ApplicationLog - } - GSeparator { - Layout.fillWidth: true - } - MoreViewMenuItem { - Layout.fillWidth: true - buttonIconSource: "qrc:///images/material_open_in_new.svg" - //: LABEL DESKTOP - buttonText: qsTr("Open website") - buttonTooltip: "https://www.ausweisapp.bund.de/%1/aa2/report".arg(SettingsModel.language) - //: LABEL DESKTOP - description: qsTr("Did you find a bug? Please help us by sending us the log file together with a description of the error.") - iconSource: "qrc:/images/desktop/material_bug_report.svg" - - //: LABEL DESKTOP - title: qsTr("Report error") - - onClicked: Qt.openUrlExternally(buttonTooltip) + onClicked: showLogs() } } diff --git a/resources/qml/Governikus/MoreView/+desktop/MoreViewGeneral.qml b/resources/qml/Governikus/MoreView/+desktop/MoreViewGeneral.qml index b22f1e66a..59e8b01fe 100644 --- a/resources/qml/Governikus/MoreView/+desktop/MoreViewGeneral.qml +++ b/resources/qml/Governikus/MoreView/+desktop/MoreViewGeneral.qml @@ -1,65 +1,27 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.SettingsModel 1.0 -import Governikus.Type.UiModule 1.0 - -ColumnLayout { +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.View +import Governikus.Type.ApplicationModel +import Governikus.Type.SettingsModel +import Governikus.Type.UiModule + +GPane { spacing: Constants.component_spacing MoreViewMenuItem { Layout.fillWidth: true - buttonIconSource: "qrc:///images/material_open_in_new.svg" - //: LABEL DESKTOP - buttonText: qsTr("Open website") - buttonTooltip: ApplicationModel.onlineHelpUrl("index") - //: LABEL DESKTOP - description: qsTr("Do you have questions about %1?").arg(Qt.application.name) - iconSource: "qrc:/images/desktop/material_menu_book.svg" - - //: LABEL DESKTOP - title: qsTr("Online help") - - onClicked: ApplicationModel.openOnlineHelp("index") - } - GSeparator { - Layout.fillWidth: true - } - MoreViewMenuItem { - Layout.fillWidth: true - buttonIconSource: "qrc:///images/material_open_in_new.svg" - //: LABEL DESKTOP - buttonText: qsTr("Open website") - buttonTooltip: "https://www.ausweisapp.bund.de/%1/aa2/videotutorials".arg(SettingsModel.language) - //: LABEL DESKTOP - description: qsTr("Do you want to see the video tutorials?") - iconSource: "qrc:///images/desktop/material_video.svg" - - //: LABEL DESKTOP - title: qsTr("Video tutorials") - - onClicked: Qt.openUrlExternally(buttonTooltip) - } - GSeparator { - Layout.fillWidth: true - } - MoreViewMenuItem { - Layout.fillWidth: true - buttonIconSource: "qrc:///images/material_open_in_new.svg" + buttonIconSource: "qrc:///images/open_website.svg" //: LABEL DESKTOP buttonText: qsTr("Open website") buttonTooltip: "https://www.ausweisapp.bund.de/%1/aa2/faq".arg(SettingsModel.language) - //: LABEL DESKTOP - description: qsTr("Do you have further questions about %1?").arg(Qt.application.name) - iconSource: "qrc:/images/material_live_help.svg" + iconSource: "qrc:/images/faq_icon.svg" //: LABEL DESKTOP - title: qsTr("FAQ") + title: qsTr("FAQ - Frequently asked questions") onClicked: Qt.openUrlExternally(buttonTooltip) } @@ -68,16 +30,14 @@ ColumnLayout { } MoreViewMenuItem { Layout.fillWidth: true - buttonIconSource: "qrc:///images/material_open_in_new.svg" + buttonIconSource: "qrc:///images/open_website.svg" //: LABEL DESKTOP buttonText: qsTr("Open website") buttonTooltip: "https://www.ausweisapp.bund.de/%1/aa2/support".arg(SettingsModel.language) - //: LABEL DESKTOP - description: qsTr("Do you need further support?") - iconSource: "qrc:/images/material_help.svg" + iconSource: "qrc:/images/desktop/help_icon.svg" //: LABEL DESKTOP - title: qsTr("Support") + title: qsTr("Contact") onClicked: Qt.openUrlExternally(buttonTooltip) } @@ -86,13 +46,11 @@ ColumnLayout { } MoreViewMenuItem { Layout.fillWidth: true - buttonIconSource: "qrc:///images/material_open_in_new.svg" + buttonIconSource: "qrc:///images/open_website.svg" //: LABEL DESKTOP buttonText: qsTr("Open website") buttonTooltip: "https://www.ausweisapp.bund.de/%1/aa2/privacy".arg(SettingsModel.language) - //: LABEL DESKTOP - description: qsTr("Do you want to read the privacy statement?") - iconSource: "qrc:/images/desktop/material_privacy.svg" + iconSource: "qrc:/images/desktop/privacy_icon.svg" //: LABEL DESKTOP title: qsTr("Privacy statement") @@ -104,13 +62,11 @@ ColumnLayout { } MoreViewMenuItem { Layout.fillWidth: true - buttonIconSource: "qrc:///images/material_open_in_new.svg" + buttonIconSource: "qrc:///images/open_website.svg" //: LABEL DESKTOP buttonText: qsTr("Open website") buttonTooltip: "https://www.ausweisapp.bund.de/%1/aa2/a11y".arg(SettingsModel.language) - //: LABEL DESKTOP - description: qsTr("Do you want to read the accessibility statement?") - iconSource: "qrc:/images/desktop/material_a11y.svg" + iconSource: "qrc:/images/desktop/a11y_icon.svg" //: LABEL DESKTOP title: qsTr("Accessibility statement") @@ -122,15 +78,17 @@ ColumnLayout { } MoreViewMenuItem { Layout.fillWidth: true + buttonIconSource: "qrc:///images/open_website.svg" //: LABEL DESKTOP - buttonText: qsTr("Start setup assistant") + buttonText: qsTr("Open website") + buttonTooltip: "https://www.ausweisapp.bund.de/%1/aa2/providerlist".arg(SettingsModel.language) //: LABEL DESKTOP - description: qsTr("Do you want to run the setup assistant again?") - iconSource: "qrc:/images/desktop/material_assistant.svg" + description: qsTr("Do you want to see a list of service providers?") + iconSource: "qrc:/images/identify.svg" //: LABEL DESKTOP - title: qsTr("Setup assistant") + title: qsTr("List of Providers") - onClicked: sectionPage.nextView(UiModule.TUTORIAL) + onClicked: Qt.openUrlExternally(buttonTooltip) } } diff --git a/resources/qml/Governikus/MoreView/+desktop/MoreViewMenuItem.qml b/resources/qml/Governikus/MoreView/+desktop/MoreViewMenuItem.qml index f7f0e768c..39a9e77f5 100644 --- a/resources/qml/Governikus/MoreView/+desktop/MoreViewMenuItem.qml +++ b/resources/qml/Governikus/MoreView/+desktop/MoreViewMenuItem.qml @@ -1,10 +1,10 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style RowLayout { id: baseItem @@ -22,15 +22,19 @@ RowLayout { TintableIcon { id: icon + sourceSize.width: Style.dimens.icon_size - tintColor: Style.color.accent + tintColor: Style.color.text_subline } LabeledText { id: labeledText + Layout.fillWidth: true } GButton { id: button + + iconSize: Style.dimens.small_icon_size tintIcon: true onClicked: baseItem.clicked() diff --git a/resources/qml/Governikus/MoreView/+mobile/MoreView.qml b/resources/qml/Governikus/MoreView/+mobile/MoreView.qml index 77e4a4db6..43d14fcd6 100644 --- a/resources/qml/Governikus/MoreView/+mobile/MoreView.qml +++ b/resources/qml/Governikus/MoreView/+mobile/MoreView.qml @@ -1,197 +1,212 @@ /** * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 -import Governikus.TutorialView 1.0 -import Governikus.FeedbackView 1.0 -import Governikus.InformationView 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.LogModel 1.0 -import Governikus.Type.SettingsModel 1.0 -import Governikus.SettingsView 1.0 -import Governikus.HistoryView 1.0 -import Governikus.Type.UiModule 1.0 - -SectionPage { +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import Governikus.Global +import Governikus.Style +import Governikus.TitleBar +import Governikus.View +import Governikus.FeedbackView +import Governikus.InformationView +import Governikus.Type.ApplicationModel +import Governikus.Type.LogModel +import Governikus.Type.SettingsModel +import Governikus.SettingsView +import Governikus.Type.UiModule + +FlickableSectionPage { id: baseItem //: LABEL ANDROID IOS title: qsTr("Help") - content: Column { - spacing: 0 - width: baseItem.width + Column { + Layout.fillWidth: true + spacing: Constants.component_spacing - TitledSeparator { - contentMarginTop: Constants.component_spacing + GOptionsContainer { //: LABEL ANDROID IOS title: qsTr("Help & Feedback") width: parent.width - } - MenuItem { - //: LABEL ANDROID IOS - description: qsTr("Do you want to know how to use %1?").arg(Qt.application.name) - //: LABEL ANDROID IOS - title: qsTr("Tutorial") - width: parent.width - onClicked: push(tutorialView) + MenuItem { + drawTopCorners: true + icon: "qrc:///images/open_website.svg" + //: LABEL ANDROID IOS + title: qsTr("FAQ - Frequently asked questions") + width: parent.width - Component { - id: tutorialView - TutorialView { - Component.onDestruction: { - show(UiModule.HELP); - } - onLeave: { - pop(); - } - } + onClicked: Qt.openUrlExternally("https://www.ausweisapp.bund.de/%1/aa2/faq".arg(SettingsModel.language)) } - } - MenuItem { - //: LABEL ANDROID IOS - description: qsTr("Do you want to see the video tutorials?") - icon: "qrc:///images/material_open_in_new.svg" - //: LABEL ANDROID IOS - title: qsTr("Video tutorials") - width: parent.width + GSeparator { + anchors.left: parent.left + anchors.leftMargin: Constants.component_spacing + anchors.right: parent.right + anchors.rightMargin: Constants.component_spacing + } + MenuItem { + icon: "qrc:///images/open_website.svg" + //: LABEL ANDROID IOS + title: qsTr("Contact") + width: parent.width - onClicked: Qt.openUrlExternally("https://www.ausweisapp.bund.de/%1/aa2/videotutorials".arg(SettingsModel.language)) - } - MenuItem { - //: LABEL ANDROID IOS - description: qsTr("Do you have further questions about %1?").arg(Qt.application.name) - icon: "qrc:///images/material_open_in_new.svg" - //: LABEL ANDROID IOS - title: qsTr("FAQ") - width: parent.width + onClicked: Qt.openUrlExternally("https://www.ausweisapp.bund.de/%1/aa2/support".arg(SettingsModel.language)) + } + GSeparator { + anchors.left: parent.left + anchors.leftMargin: Constants.component_spacing + anchors.right: parent.right + anchors.rightMargin: Constants.component_spacing + } + MenuItem { + icon: "qrc:///images/open_website.svg" + //: LABEL ANDROID IOS + title: qsTr("Privacy statement") + width: parent.width - onClicked: Qt.openUrlExternally("https://www.ausweisapp.bund.de/%1/aa2/faq".arg(SettingsModel.language)) - } - MenuItem { - //: LABEL ANDROID IOS - description: qsTr("Do you need further support?") - icon: "qrc:///images/material_open_in_new.svg" - //: LABEL ANDROID IOS - title: qsTr("Support") - width: parent.width + onClicked: Qt.openUrlExternally("https://www.ausweisapp.bund.de/%1/aa2/privacy".arg(SettingsModel.language)) + } + GSeparator { + anchors.left: parent.left + anchors.leftMargin: Constants.component_spacing + anchors.right: parent.right + anchors.rightMargin: Constants.component_spacing + } + MenuItem { + icon: "qrc:///images/open_website.svg" + //: LABEL ANDROID IOS + title: qsTr("Accessibility statement") + width: parent.width - onClicked: Qt.openUrlExternally("https://www.ausweisapp.bund.de/%1/aa2/support".arg(SettingsModel.language)) - } - MenuItem { - //: LABEL ANDROID IOS - description: qsTr("Do you want to read the privacy statement?") - icon: "qrc:///images/material_open_in_new.svg" - //: LABEL ANDROID IOS - title: qsTr("Privacy statement") - width: parent.width + onClicked: Qt.openUrlExternally("https://www.ausweisapp.bund.de/%1/aa2/a11y".arg(SettingsModel.language)) + } + GSeparator { + anchors.left: parent.left + anchors.leftMargin: Constants.component_spacing + anchors.right: parent.right + anchors.rightMargin: Constants.component_spacing + } + MenuItem { + icon: "qrc:///images/open_website.svg" + //: LABEL ANDROID IOS + title: qsTr("List of Providers") + width: parent.width - onClicked: Qt.openUrlExternally("https://www.ausweisapp.bund.de/%1/aa2/privacy".arg(SettingsModel.language)) + onClicked: Qt.openUrlExternally("https://www.ausweisapp.bund.de/%1/aa2/providerlist".arg(SettingsModel.language)) + } + GSeparator { + anchors.left: parent.left + anchors.leftMargin: Constants.component_spacing + anchors.right: parent.right + anchors.rightMargin: Constants.component_spacing + } + MenuItem { + drawBottomCorners: true + icon: "qrc:///images/open_website.svg" + //: LABEL ANDROID IOS + title: qsTr("Rate %1").arg(Qt.application.name) + width: parent.width + + onClicked: Qt.openUrlExternally(ApplicationModel.storeUrl) + } } - MenuItem { - //: LABEL ANDROID IOS - description: qsTr("Do you want to read the accessibility statement?") - icon: "qrc:///images/material_open_in_new.svg" + GOptionsContainer { //: LABEL ANDROID IOS - title: qsTr("Accessibility statement") + title: qsTr("Logs") width: parent.width - onClicked: Qt.openUrlExternally("https://www.ausweisapp.bund.de/%1/aa2/a11y".arg(SettingsModel.language)) - } - MenuItem { - //: LABEL ANDROID IOS - description: Constants.is_layout_ios ? qsTr("Do you want to rate us in the App Store?") : qsTr("Do you want to rate us in the Google Play Store?") - icon: "qrc:///images/material_open_in_new.svg" - //: LABEL ANDROID IOS - title: qsTr("Rate %1").arg(Qt.application.name) - width: parent.width + MenuItem { + drawTopCorners: true + //: LABEL ANDROID IOS + title: qsTr("Show Logs") + width: parent.width - onClicked: Qt.openUrlExternally(ApplicationModel.storeUrl) - } - TitledSeparator { - //: LABEL ANDROID IOS - title: qsTr("Diagnosis") - width: parent.width - } - MenuItem { - //: LABEL ANDROID IOS - description: qsTr("Do you want to view the logs of %1?").arg(Qt.application.name) - //: LABEL ANDROID IOS - title: qsTr("Logs") - width: parent.width + onClicked: push(logPage) - onClicked: push(logPage) + Component { + id: logPage - Component { - id: logPage - LogView { + LogView { + } } } + GSeparator { + anchors.left: parent.left + anchors.leftMargin: Constants.component_spacing + anchors.right: parent.right + anchors.rightMargin: Constants.component_spacing + } + MenuItem { + drawBottomCorners: true + icon: "qrc:///images/material_mail.svg" + //: LABEL ANDROID IOS + title: qsTr("Send log to the support") + width: parent.width + + onClicked: LogModel.mailLog() + } } - MenuItem { - //: LABEL ANDROID IOS - description: qsTr("Did you find a bug? Please help us by sending us the log file together with a description of the error.") - icon: "qrc:///images/material_mail.svg" - //: LABEL ANDROID IOS - title: qsTr("Report error") - width: parent.width - - onClicked: LogModel.mailLog() - } - TitledSeparator { + GOptionsContainer { //: LABEL ANDROID IOS title: qsTr("Information") width: parent.width - } - MenuItem { - //: LABEL ANDROID IOS - description: qsTr("Do you want to see detailed information about %1?").arg(Qt.application.name) - //: LABEL ANDROID IOS - title: qsTr("Version information") - width: parent.width - onClicked: push(versionInformation) + MenuItem { + drawTopCorners: true + //: LABEL ANDROID IOS + title: qsTr("Version information") + width: parent.width + + onClicked: push(versionInformation) - Component { - id: versionInformation - VersionInformation { + Component { + id: versionInformation + + VersionInformation { + } } } - } - MenuItem { - //: LABEL ANDROID IOS - description: qsTr("Do you want to read the software licenses?") - //: LABEL ANDROID IOS - title: qsTr("Software license") - width: parent.width + GSeparator { + anchors.left: parent.left + anchors.leftMargin: Constants.component_spacing + anchors.right: parent.right + anchors.rightMargin: Constants.component_spacing + } + MenuItem { + //: LABEL ANDROID IOS + title: qsTr("Terms of use and software license") + width: parent.width - onClicked: push(licenseInformation) + onClicked: push(licenseInformation) - Component { - id: licenseInformation - LicenseInformation { + Component { + id: licenseInformation + + LicenseInformation { + } } } - } - MenuItem { - //: LABEL ANDROID IOS - description: qsTr("Do you want to view the release notes of %1?").arg(Qt.application.name) - //: LABEL ANDROID IOS - title: qsTr("Release notes") - width: parent.width + GSeparator { + anchors.left: parent.left + anchors.leftMargin: Constants.component_spacing + anchors.right: parent.right + anchors.rightMargin: Constants.component_spacing + } + MenuItem { + drawBottomCorners: true + //: LABEL ANDROID IOS + title: qsTr("Release notes") + width: parent.width - onClicked: push(releaseNotes) + onClicked: push(releaseNotes) - Component { - id: releaseNotes - ReleaseNotes { + Component { + id: releaseNotes + + ReleaseNotes { + } } } } diff --git a/resources/qml/Governikus/Navigation/+mobile/Navigation.qml b/resources/qml/Governikus/Navigation/+mobile/Navigation.qml index b52bbb97e..66b56d331 100644 --- a/resources/qml/Governikus/Navigation/+mobile/Navigation.qml +++ b/resources/qml/Governikus/Navigation/+mobile/Navigation.qml @@ -1,15 +1,16 @@ /** * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.SettingsModel 1.0 -import Governikus.Type.UiModule 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.Type.ApplicationModel +import Governikus.Type.SettingsModel +import Governikus.Type.UiModule -Rectangle { - id: baseItem +RowLayout { + id: navigation readonly property int activeModule: d.activeModule readonly property bool lockedAndHidden: d.lockedAndHidden @@ -27,13 +28,13 @@ Rectangle { } } - color: Style.color.background_pane enabled: !lockedAndHidden - height: lockedAndHidden ? 0 : (Style.dimens.navigation_bar_height + plugin.safeAreaMargins.bottom) + height: lockedAndHidden ? 0 : (navigationView.height + plugin.safeAreaMargins.bottom) visible: height > 0 - Behavior on height { + Behavior on height { id: heightAnimation + enabled: !ApplicationModel.isScreenReaderRunning() NumberAnimation { @@ -53,15 +54,12 @@ Rectangle { } NavigationView { id: navigationView - Accessible.ignored: lockedAndHidden - height: Style.dimens.navigation_bar_height - anchors { - left: parent.left - leftMargin: plugin.safeAreaMargins.left - right: parent.right - rightMargin: plugin.safeAreaMargins.right - top: parent.top - } + Accessible.ignored: lockedAndHidden + Layout.alignment: Qt.AlignHCenter | Qt.AlignTop + Layout.fillWidth: true + Layout.minimumHeight: Style.dimens.navigation_bar_min_height + Layout.minimumWidth: Math.min(navigation.width, Style.dimens.max_text_width) + Layout.preferredHeight: Math.ceil(implicitHeight) } } diff --git a/resources/qml/Governikus/Navigation/+mobile/NavigationItem.qml b/resources/qml/Governikus/Navigation/+mobile/NavigationItem.qml index 3386f7c94..aab0fd48f 100644 --- a/resources/qml/Governikus/Navigation/+mobile/NavigationItem.qml +++ b/resources/qml/Governikus/Navigation/+mobile/NavigationItem.qml @@ -1,51 +1,68 @@ /** * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style -Item { - readonly property color itemColor: selected ? Style.text.hint_accent.textColor : Style.text.hint_secondary.textColor - property var selected: false - property alias source: tabImage.source - property alias text: tabText.text +AbstractButton { + id: root - signal clicked + property bool flowHorizontally: true + readonly property color itemColor: selected ? Style.color.text_navigation : Style.color.text_navigation_unchecked + property bool selected: false + property alias source: tabImage.source Accessible.name: text Accessible.role: Accessible.Button + Layout.minimumWidth: tabImage.implicitWidth + leftPadding + rightPadding + padding: Constants.text_spacing / 2 - Accessible.onPressAction: clicked() + background: Rectangle { + color: selected ? Style.color.control : Style.color.transparent + radius: Style.dimens.control_radius + } + contentItem: Item { + implicitHeight: grid.implicitHeight + implicitWidth: Math.ceil(tabImage.implicitWidth + grid.columnSpacing + tabText.implicitWidth) - TintableIcon { - id: tabImage - sourceSize.height: Style.dimens.navigation_bar_height - tintColor: parent.itemColor + GridLayout { + id: grid - anchors { - bottom: tabText.top - bottomMargin: Style.dimens.navigation_bar_text_padding - left: parent.left - right: parent.right - top: parent.top - } - } - GText { - id: tabText - Accessible.ignored: true - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - color: parent.itemColor - elide: Text.ElideRight - horizontalAlignment: Text.AlignHCenter - maximumLineCount: 1 - textStyle: Style.text.navigation - width: parent.width - } - MouseArea { - anchors.fill: parent + Accessible.ignored: true + anchors.centerIn: parent + columnSpacing: Constants.text_spacing + columns: 2 + flow: root.flowHorizontally ? GridLayout.LeftToRight : GridLayout.TopToBottom + rowSpacing: Style.dimens.navigation_bar_text_padding + rows: 2 + + Accessible.onPressAction: root.clicked() + + TintableIcon { + id: tabImage - onClicked: parent.clicked() + Accessible.ignored: true + Layout.alignment: root.flowHorizontally ? Qt.AlignRight : Qt.AlignCenter + Layout.maximumWidth: implicitWidth + sourceSize.height: Style.dimens.navigation_bar_icon_size + tintColor: root.itemColor + } + GText { + id: tabText + + Accessible.ignored: true + Layout.alignment: root.flowHorizontally ? Qt.AlignLeft : Qt.AlignCenter + Layout.preferredWidth: Math.min(Math.ceil(implicitWidth), root.contentItem.width) + color: root.itemColor + elide: Text.ElideRight + horizontalAlignment: Text.AlignHCenter + maximumLineCount: 1 + text: root.text + textStyle: Style.text.navigation + } + } } } diff --git a/resources/qml/Governikus/Navigation/+mobile/NavigationView.qml b/resources/qml/Governikus/Navigation/+mobile/NavigationView.qml index 64bbeaed9..2f9f74662 100644 --- a/resources/qml/Governikus/Navigation/+mobile/NavigationView.qml +++ b/resources/qml/Governikus/Navigation/+mobile/NavigationView.qml @@ -1,35 +1,75 @@ /** * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.UiModule 1.0 -import Governikus.Type.WorkflowModel 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.Type.UiModule +import Governikus.Type.WorkflowModel -Item { - id: content - Component.onCompleted: if (!WorkflowModel.isSmartSupported) { - navModel.set(1, { - "image": "qrc:///images/material_history.svg", - "desc": QT_TR_NOOP("History"), - "module": UiModule.HISTORY - }); +GControl { + id: root + + Layout.maximumWidth: Math.max(Layout.preferredWidth, Style.dimens.max_text_width) + Layout.minimumWidth: navigationRow.Layout.minimumWidth + leftPadding + rightPadding + Layout.preferredWidth: contentItem.Layout.preferredWidth + leftPadding + rightPadding + bottomInset: -plugin.safeAreaMargins.bottom + bottomPadding: Constants.is_layout_android ? Style.dimens.navigation_bar_padding : Style.dimens.navigation_bar_text_padding + horizontalPadding: Style.dimens.navigation_bar_padding + topPadding: Style.dimens.navigation_bar_padding + + background: RoundedRectangle { + bottomLeftCorner: false + bottomRightCorner: false + color: Style.color.pane + layer.enabled: GraphicsInfo.api !== GraphicsInfo.Software + radius: Style.dimens.pane_radius + + layer.effect: GDropShadow { + verticalOffset: -3 + } + } + contentItem: RowLayout { + id: navigationRow + + readonly property bool horizontalIcons: width >= Layout.preferredWidth + + Layout.preferredWidth: repeater.maxItemWidth * visibleChildren.length + spacing * (visibleChildren.length - 1) + + GRepeater { + id: repeater + + model: navModel + + delegate: NavigationItem { + readonly property var mainViewSubViews: [UiModule.IDENTIFY, UiModule.SELF_AUTHENTICATION, UiModule.PINMANAGEMENT, UiModule.CHECK_ID_CARD, UiModule.SMART_EID] + + Accessible.ignored: root.Accessible.ignored + Layout.fillHeight: true + Layout.fillWidth: true + Layout.preferredWidth: repeater.maxItemWidth + flowHorizontally: navigationRow.horizontalIcons + selected: navigation.activeModule === module || (module === UiModule.DEFAULT && mainViewSubViews.includes(navigation.activeModule)) + source: image + text: qsTr(desc) + + onClicked: { + navigation.resetContentArea(); + navigation.show(module); + } + } + } } ListModel { id: navModel + ListElement { desc: QT_TR_NOOP("Start") - image: "qrc:///images/mobile/material_home.svg" + image: "qrc:///images/mobile/home.svg" module: UiModule.DEFAULT } - ListElement { - desc: QT_TR_NOOP("Provider") - image: "qrc:///images/provider.svg" - module: UiModule.PROVIDER - } ListElement { desc: QT_TR_NOOP("Card reader") image: "qrc:///images/mobile/phone_card_reader.svg" @@ -37,53 +77,13 @@ Item { } ListElement { desc: QT_TR_NOOP("Settings") - image: "qrc:///images/material_settings.svg" + image: "qrc:///images/mobile/settings.svg" module: UiModule.SETTINGS } ListElement { desc: QT_TR_NOOP("Help") - image: "qrc:///images/material_help.svg" + image: "qrc:///images/mobile/help.svg" module: UiModule.HELP } } - GSeparator { - id: topBorderLine - width: parent.width - } - RowLayout { - anchors { - bottom: parent.bottom - bottomMargin: Constants.is_layout_android ? Style.dimens.navigation_bar_padding : Style.dimens.navigation_bar_text_padding - left: parent.left - leftMargin: Style.dimens.navigation_bar_padding - right: parent.right - rightMargin: Style.dimens.navigation_bar_padding - top: topBorderLine.bottom - topMargin: Style.dimens.navigation_bar_padding - } - Repeater { - id: repeater - model: navModel - - delegate: NavigationItem { - readonly property var mainViewSubViews: { - let subViews = [UiModule.IDENTIFY, UiModule.SELF_AUTHENTICATION, UiModule.PINMANAGEMENT, UiModule.CHECK_ID_CARD]; - subViews.push(WorkflowModel.isSmartSupported ? UiModule.SMART : UiModule.PROVIDER); - return subViews; - } - - Accessible.ignored: content.Accessible.ignored - Layout.fillHeight: true - Layout.fillWidth: true - selected: baseItem.activeModule === module || (module === UiModule.DEFAULT && mainViewSubViews.includes(baseItem.activeModule)) - source: image - text: qsTr(desc) - - onClicked: { - baseItem.resetContentArea(); - baseItem.show(module); - } - } - } - } } diff --git a/resources/qml/Governikus/PasswordInfoView/+desktop/PasswordInfoView.qml b/resources/qml/Governikus/PasswordInfoView/+desktop/PasswordInfoView.qml index b278d560f..9b19c3eaa 100644 --- a/resources/qml/Governikus/PasswordInfoView/+desktop/PasswordInfoView.qml +++ b/resources/qml/Governikus/PasswordInfoView/+desktop/PasswordInfoView.qml @@ -1,15 +1,15 @@ /** * Copyright (c) 2022-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.PinResetInformationModel 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.TitleBar +import Governikus.View +import Governikus.Type.ApplicationModel +import Governikus.Type.PinResetInformationModel SectionPage { id: root @@ -18,7 +18,7 @@ SectionPage { readonly property string buttonText: infoContent.buttonText readonly property var contentList: infoContent.contentList readonly property string hint: infoContent.hint - readonly property int imageType: infoContent.imageType + readonly property string hintButtonText: infoContent.hintButtonText property var infoContent: PasswordInfoContent { } property alias rootEnabled: titleBarAction.rootEnabled @@ -29,6 +29,7 @@ SectionPage { titleBarAction: TitleBarAction { id: titleBarAction + rootEnabled: ApplicationModel.currentWorkflow === ApplicationModel.WORKFLOW_NONE showHelp: false showSettings: false @@ -42,109 +43,77 @@ SectionPage { GFlickableColumnLayout { anchors.fill: parent anchors.margins: Constants.pane_padding - spacing: Constants.groupbox_spacing + maximumContentWidth: Style.dimens.max_text_width + spacing: Constants.pane_spacing - GridLayout { - Layout.alignment: Qt.AlignTop | Qt.AlignHCenter - Layout.fillWidth: true - columnSpacing: Constants.groupbox_spacing - columns: 2 - rowSpacing: Constants.groupbox_spacing - - ColumnLayout { - id: contentLayout - Layout.alignment: Qt.AlignTop - Layout.fillWidth: true - Layout.maximumWidth: Style.dimens.max_text_width - spacing: Constants.component_spacing - - Repeater { - model: root.contentList - - delegate: ColumnLayout { - Layout.alignment: Qt.AlignTop - Layout.fillWidth: true - spacing: Constants.component_spacing - - PasswordInfoImage { - Layout.alignment: Qt.AlignHCenter - imageType: blockHeaderImageType - scaleFactorCan: 1 * ApplicationModel.scaleFactor - scaleFactorGeneral: 1.35 * ApplicationModel.scaleFactor - visible: blockHeaderImageType !== PasswordInfoImage.Type.NONE + Repeater { + model: root.contentList + + delegate: RowLayout { + Layout.alignment: headline ? Qt.AlignHCenter : Qt.AlignLeft + spacing: 2 * Constants.component_spacing + + PasswordInfoImage { + Layout.alignment: Qt.AlignTop + imageType: blockHeaderImageType + scaleFactorGeneral: plugin.scaleFactor + visible: blockHeaderImageType !== PasswordInfoImage.Type.NONE + } + ColumnLayout { + Layout.alignment: Qt.AlignTop + spacing: Constants.groupbox_spacing + + GText { + Layout.alignment: headline ? Qt.AlignHCenter : Qt.AlignLeft + activeFocusOnTab: true + font.bold: true + horizontalAlignment: headline ? Text.AlignHCenter : Text.AlignLeft + text: blockTitle + textStyle: headline ? Style.text.headline : Style.text.subline + visible: text !== "" + + FocusFrame { } - ColumnLayout { - Layout.alignment: Qt.AlignTop - Layout.fillWidth: true - spacing: Constants.groupbox_spacing - - GText { - Layout.alignment: Qt.AlignTop - Layout.fillWidth: true - Layout.maximumWidth: Style.dimens.max_text_width - activeFocusOnTab: true - horizontalAlignment: Text.AlignLeft - text: blockTitle - textStyle: Style.text.header_highlight - visible: text !== "" - wrapMode: Text.WordWrap - - FocusFrame { - } - } - Repeater { - model: paragraphList - - delegate: GText { - Layout.alignment: Qt.AlignTop - Layout.fillWidth: true - Layout.maximumWidth: Style.dimens.max_text_width - activeFocusOnTab: true - horizontalAlignment: Text.AlignJustify - text: modelData - textStyle: Style.text.header - - FocusFrame { - } - } + } + Repeater { + model: paragraphList + + delegate: GText { + Layout.alignment: headline ? Qt.AlignHCenter : Qt.AlignLeft + activeFocusOnTab: true + horizontalAlignment: headline ? Text.AlignHCenter : Text.AlignLeft + text: modelData + + FocusFrame { } } } } - GButton { - Layout.alignment: Qt.AlignRight - Layout.topMargin: Constants.component_spacing - icon.source: "qrc:///images/material_open_in_new.svg" - text: root.buttonText - visible: text !== "" - - onClicked: Qt.openUrlExternally(root.buttonLink) - } - } - PasswordInfoImage { - imageType: root.imageType - scaleFactorCan: 1.5 * ApplicationModel.scaleFactor - scaleFactorGeneral: 2.7 * ApplicationModel.scaleFactor - visible: root.imageType !== PasswordInfoImage.Type.NONE } - GSpacer { - Layout.columnSpan: 2 - Layout.fillHeight: true - Layout.row: 1 - } - Hint { - Layout.alignment: Qt.AlignHCenter - Layout.fillWidth: true - Layout.maximumWidth: contentLayout.width - Layout.row: 2 - buttonText: PinResetInformationModel.pinResetActionText - text: root.hint - visible: text !== "" - - onClicked: { - abortCurrentWorkflow(); - Qt.openUrlExternally(PinResetInformationModel.pinResetUrl); - } + } + GButton { + Layout.alignment: Qt.AlignRight + Layout.topMargin: Constants.component_spacing + icon.source: "qrc:///images/open_website.svg" + text: root.buttonText + visible: text !== "" + + onClicked: Qt.openUrlExternally(root.buttonLink) + } + GSpacer { + Layout.fillHeight: true + } + Hint { + Layout.alignment: Qt.AlignHCenter + Layout.fillWidth: true + buttonText: root.hintButtonText + buttonTooltip: PinResetInformationModel.pinResetUrl + text: root.hint + visible: text !== "" + + onClicked: { + abortCurrentWorkflow(); + Qt.openUrlExternally(PinResetInformationModel.pinResetUrl); } } NavigationButton { diff --git a/resources/qml/Governikus/PasswordInfoView/+mobile/PasswordInfoView.qml b/resources/qml/Governikus/PasswordInfoView/+mobile/PasswordInfoView.qml index a82a71ea9..37c781978 100644 --- a/resources/qml/Governikus/PasswordInfoView/+mobile/PasswordInfoView.qml +++ b/resources/qml/Governikus/PasswordInfoView/+mobile/PasswordInfoView.qml @@ -1,22 +1,22 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.View 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.Type.PinResetInformationModel 1.0 - -SectionPage { +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.View +import Governikus.Style +import Governikus.TitleBar +import Governikus.Type.PinResetInformationModel + +FlickableSectionPage { id: root readonly property url buttonLink: infoContent.buttonLink readonly property string buttonText: infoContent.buttonText readonly property var contentList: infoContent.contentList readonly property string hint: infoContent.hint - readonly property int imageType: infoContent.imageType + readonly property string hintButtonText: infoContent.hintButtonText property var infoContent: PasswordInfoContent { } readonly property string infoContentTitle: infoContent.title @@ -24,7 +24,7 @@ SectionPage { signal abortCurrentWorkflow signal close - sectionPageFlickable: contentItem + spacing: Constants.component_spacing title: infoContentTitle navigationAction: NavigationAction { @@ -33,90 +33,69 @@ SectionPage { onClicked: close() } - GFlickableColumnLayout { - id: contentItem - anchors.fill: parent - fillHeight: false - maximumContentWidth: Style.dimens.max_text_width + Column { + Layout.fillWidth: true + Layout.margins: Constants.pane_padding spacing: Constants.component_spacing - PasswordInfoImage { - Layout.fillWidth: true - Layout.topMargin: Constants.pane_padding - imageType: root.imageType - visible: root.imageType !== PasswordInfoImage.Type.NONE - } - GPane { - Layout.alignment: Qt.AlignHCenter - Layout.fillWidth: true - Layout.maximumWidth: Style.dimens.max_text_width + Repeater { + model: root.contentList + width: parent.width - Column { + delegate: Column { spacing: Constants.component_spacing width: parent.width - Repeater { - model: root.contentList + PasswordInfoImage { + anchors.horizontalCenter: parent.horizontalCenter + imageType: blockHeaderImageType + visible: blockHeaderImageType !== PasswordInfoImage.Type.NONE + width: parent.width * 0.3 + } + Column { + spacing: Constants.groupbox_spacing width: parent.width - delegate: Column { - spacing: Constants.component_spacing + GText { + font.bold: true + text: blockTitle + textStyle: headline ? Style.text.headline : Style.text.subline + width: parent.width + wrapMode: Text.WordWrap + } + Repeater { + model: paragraphList width: parent.width - PasswordInfoImage { - anchors.horizontalCenter: parent.horizontalCenter - imageType: blockHeaderImageType - visible: blockHeaderImageType !== PasswordInfoImage.Type.NONE - width: parent.width * 0.3 - } - Column { - spacing: Constants.groupbox_spacing + delegate: GText { + text: modelData width: parent.width - - GText { - text: blockTitle - textStyle: Style.text.header_secondary_highlight - width: parent.width - wrapMode: Text.WordWrap - } - Repeater { - model: paragraphList - width: parent.width - - delegate: GText { - text: modelData - width: parent.width - } - } } } } - GButton { - Layout.alignment: Qt.AlignRight - Layout.topMargin: Constants.component_spacing - icon.source: "qrc:///images/material_open_in_new.svg" - text: root.buttonText - visible: text !== "" - - onClicked: Qt.openUrlExternally(root.buttonLink) - } } } - GSpacer { - Layout.fillHeight: true - } - Hint { - Layout.alignment: Qt.AlignHCenter - Layout.fillWidth: true - Layout.maximumWidth: Style.dimens.max_text_width - buttonText: PinResetInformationModel.pinResetActionText - text: root.hint + GButton { + Layout.alignment: Qt.AlignRight + Layout.topMargin: Constants.component_spacing + icon.source: "qrc:///images/open_website.svg" + text: root.buttonText visible: text !== "" - onClicked: { - abortCurrentWorkflow(); - Qt.openUrlExternally(PinResetInformationModel.pinResetUrl); - } + onClicked: Qt.openUrlExternally(root.buttonLink) + } + } + Hint { + Layout.alignment: Qt.AlignHCenter + Layout.fillWidth: true + Layout.topMargin: Constants.component_spacing + buttonText: root.hintButtonText + text: root.hint + visible: text !== "" + + onClicked: { + abortCurrentWorkflow(); + Qt.openUrlExternally(PinResetInformationModel.pinResetUrl); } } } diff --git a/resources/qml/Governikus/PasswordInfoView/PasswordInfoContent.qml b/resources/qml/Governikus/PasswordInfoView/PasswordInfoContent.qml index 2d1f449a8..223c0c522 100644 --- a/resources/qml/Governikus/PasswordInfoView/PasswordInfoContent.qml +++ b/resources/qml/Governikus/PasswordInfoView/PasswordInfoContent.qml @@ -1,27 +1,29 @@ /** * Copyright (c) 2022-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 +import QtQuick QtObject { enum Type { PIN, + SMART_PIN, CHOOSE_PIN, + CHOOSE_SMART_PIN, TRANSPORT_PIN, - SMARTPHONE_AS_CARD_READER, PUK, CAN, CAN_ALLOWED, CHANGE_PIN, SMART_BLOCKING_CODE, - NO_PIN + NO_PIN, + EMPTY } property url buttonLink: "" property string buttonText: "" property list contentList property string hint: "" - property int imageType: PasswordInfoImage.Type.NONE + property string hintButtonText: "" //: LABEL ALL_PLATFORMS property string linkText: qsTr("More information") diff --git a/resources/qml/Governikus/PasswordInfoView/PasswordInfoContentBlock.qml b/resources/qml/Governikus/PasswordInfoView/PasswordInfoContentBlock.qml index 4e647b5a2..f55cf04f9 100644 --- a/resources/qml/Governikus/PasswordInfoView/PasswordInfoContentBlock.qml +++ b/resources/qml/Governikus/PasswordInfoView/PasswordInfoContentBlock.qml @@ -1,10 +1,11 @@ /** * Copyright (c) 2022-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 +import QtQuick QtObject { property int blockHeaderImageType: PasswordInfoImage.Type.NONE property string blockTitle + property bool headline: false property var paragraphList } diff --git a/resources/qml/Governikus/PasswordInfoView/PasswordInfoData.qml b/resources/qml/Governikus/PasswordInfoView/PasswordInfoData.qml index 7f5c4034f..678b2e731 100644 --- a/resources/qml/Governikus/PasswordInfoView/PasswordInfoData.qml +++ b/resources/qml/Governikus/PasswordInfoView/PasswordInfoData.qml @@ -1,11 +1,11 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Type.PasswordType 1.0 -import Governikus.Type.PinResetInformationModel 1.0 -import Governikus.Type.WorkflowModel 1.0 +import QtQuick +import Governikus.Global +import Governikus.Type.PasswordType +import Governikus.Type.PinResetInformationModel +import Governikus.Type.WorkflowModel Item { id: root @@ -15,17 +15,19 @@ Item { readonly property var contentList: infoContent.contentList property int contentType readonly property string hint: infoContent.hint - readonly property int imageType: infoContent.imageType + readonly property string hintButtonText: infoContent.hintButtonText readonly property PasswordInfoContent infoContent: { switch (contentType) { case PasswordInfoContent.Type.PIN: return pinInfo; + case PasswordInfoContent.Type.SMART_PIN: + return smartPinInfo; case PasswordInfoContent.Type.CHOOSE_PIN: return choosePinInfo; + case PasswordInfoContent.Type.CHOOSE_SMART_PIN: + return chooseSmartPinInfo; case PasswordInfoContent.Type.TRANSPORT_PIN: return transportPinInfo; - case PasswordInfoContent.Type.SMARTPHONE_AS_CARD_READER: - return smartphoneAsCardReaderInfo; case PasswordInfoContent.Type.PUK: return pukInfo; case PasswordInfoContent.Type.CAN: @@ -38,6 +40,8 @@ Item { return smartBlockingCodeInfo; case PasswordInfoContent.Type.NO_PIN: return noPin; + case PasswordInfoContent.Type.EMPTY: + return empty; default: return pinInfo; } @@ -49,23 +53,39 @@ Item { switch (pPasswordType) { case PasswordType.PIN: return PasswordInfoContent.Type.PIN; + case PasswordType.SMART_PIN: + return PasswordInfoContent.Type.SMART_PIN; case PasswordType.CAN: return pIsCanAllowedMode ? PasswordInfoContent.Type.CAN_ALLOWED : PasswordInfoContent.Type.CAN; case PasswordType.PUK: return PasswordInfoContent.Type.PUK; case PasswordType.NEW_PIN: return PasswordInfoContent.Type.CHOOSE_PIN; + case PasswordType.NEW_SMART_PIN: + return PasswordInfoContent.Type.CHOOSE_SMART_PIN; + case PasswordType.NEW_PIN_CONFIRMATION: + case PasswordType.NEW_SMART_PIN_CONFIRMATION: + return PasswordInfoContent.Type.EMPTY; case PasswordType.TRANSPORT_PIN: return PasswordInfoContent.Type.TRANSPORT_PIN; + case PasswordType.SMART_BLOCKING_CODE: + return PasswordInfoContent.Type.SMART_BLOCKING_CODE; default: return PasswordInfoContent.Type.PIN; } } + PasswordInfoContent { + id: empty + + linkText: "" + } PasswordInfoContent { id: pinInfo + //: LABEL ALL_PLATFORMS Hint text for PIN but it is unknown. hint: qsTr("If you have forgotten your card PIN, you can request a new PIN free of charge using the PIN Reset Service.") + hintButtonText: PinResetInformationModel.pinResetActionText //: LABEL ALL_PLATFORMS linkText: qsTr("What is the card PIN?") @@ -74,18 +94,46 @@ Item { contentList: [ PasswordInfoContentBlock { + blockHeaderImageType: PasswordInfoImage.PIN //: LABEL ALL_PLATFORMS blockTitle: qsTr("What is the card PIN?") paragraphList: [ //: INFO ALL_PLATFORMS Answer to the question 'what is the card pin?' - qsTr("The card PIN is a six-digit PIN that you set yourself. You always need this PIN if you want to use the eID function.")] + qsTr("The card PIN is a six-digit PIN that you set yourself. You always need this PIN if you want to use the eID function with your ID card.")] }, PasswordInfoContentBlock { //: LABEL ALL_PLATFORMS blockTitle: qsTr("Where can I find the card PIN?") paragraphList: [ - //: INFO ALL_PLATFORMS Answer to the question 'Where can I find the card PIN?' - qsTr("You set the card PIN either directly when you picked up your ID card at the citizens' office (Bürgeramt) or later in AusweisApp2 using the five-digit Transport PIN. Only when you have set a six-digit PIN of your own choice can you use the eID function.")] + //: INFO ALL_PLATFORMS Answer to the question 'Where can I find the card PIN?' (%1 is replaced with the application name) + qsTr("You set the card PIN either directly when you picked up your ID card at the citizens' office (Bürgeramt) or later in %1 using the five-digit Transport PIN. Only when you have set a six-digit PIN of your own choice can you use the eID function and set up a Smart-eID.").arg(Qt.application.name)] + } + ] + } + PasswordInfoContent { + id: smartPinInfo + + //: LABEL ALL_PLATFORMS Hint text for PIN but it is unknown. + hint: qsTr("If you have forgotten your Smart-eID PIN, you can renew your Smart-eID and thereby set a new PIN.") + //: LABEL ALL_PLATFORMS + linkText: qsTr("What is the Smart-eID PIN?") + //: LABEL ALL_PLATFORMS + title: qsTr("PIN information") + + contentList: [ + PasswordInfoContentBlock { + //: LABEL ALL_PLATFORMS + blockTitle: qsTr("What is the Smart-eID PIN?") + paragraphList: [ + //: INFO ALL_PLATFORMS Answer to the question 'what is the Smart-eID pin?' + qsTr("The Smart-eID PIN is a six-digit PIN that you set yourself. You always need this PIN if you want to use your Smart-eID.")] + }, + PasswordInfoContentBlock { + //: LABEL ALL_PLATFORMS + blockTitle: qsTr("Where can I find the Smart-eID PIN?") + paragraphList: [ + //: INFO ALL_PLATFORMS Answer to the question 'Where can I find the Smart-eID PIN?' + qsTr("You have set the Smart-eID PIN while setting up the Smart-eID.")] } ] } @@ -112,11 +160,42 @@ Item { } ] } + PasswordInfoContent { + id: chooseSmartPinInfo + + //: LABEL ALL_PLATFORMS + linkText: qsTr("What is the Smart-eID PIN?") + + //: LABEL ALL_PLATFORMS + title: qsTr("Set up Smart-eID") + + contentList: [ + PasswordInfoContentBlock { + //: LABEL ALL_PLATFORMS + blockTitle: qsTr("What is the Smart-eID PIN?") + paragraphList: [ + //: INFO ALL_PLATFORMS Answer to the question 'what is the Smart-eID pin?' + qsTr("The Smart-eID PIN is a six-digit PIN that you set yourself. You always need this PIN if you want to use your Smart-eID.")] + }, + PasswordInfoContentBlock { + //: LABEL ALL_PLATFORMS + blockTitle: qsTr("How do I choose a secure PIN?") + paragraphList: [ + //: INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure (Smart-eID) PIN?' paragraph 1/3 + qsTr("For your six-digit Smart-eID PIN, choose a combination of numbers that cannot be guessed - i.e. neither \"123456\", nor your date of birth, nor any other numbers printed on your ID card."), + //: INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure (Smart-eID) PIN?' paragraph 2/3 + qsTr("You can change your six-digit Smart-eID PIN at any time and an unlimited number of times as long as you know your valid Smart-eID PIN."), + //: INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure (Smart-eID) PIN?' paragraph 3/3 + qsTr("Keep your PIN secret and change it if another person becomes aware of it.")] + } + ] + } PasswordInfoContent { id: transportPinInfo + //: LABEL ALL_PLATFORMS Hint text for requested Transport PIN but both, Transport PIN and PIN, are not known. hint: qsTr("If you do not know either your Transport PIN or your card PIN, you can request a new PIN free of charge using the PIN Reset Service.") - imageType: PasswordInfoImage.LETTER + hintButtonText: PinResetInformationModel.pinResetActionText //: LABEL ALL_PLATFORMS linkText: qsTr("What is the Transport PIN?") @@ -125,6 +204,7 @@ Item { contentList: [ PasswordInfoContentBlock { + blockHeaderImageType: PasswordInfoImage.LETTER //: LABEL ALL_PLATFORMS blockTitle: qsTr("What is the Transport PIN?") paragraphList: [ @@ -137,29 +217,11 @@ Item { } ] } - PasswordInfoContent { - id: smartphoneAsCardReaderInfo - imageType: PasswordInfoImage.SMARTPHONE_AS_CARD_READER - - //: LABEL ALL_PLATFORMS - title: qsTr("Smartphone as card reader information") - - contentList: [ - PasswordInfoContentBlock { - //: LABEL ALL_PLATFORMS - blockTitle: qsTr("Smartphone as card reader information") - paragraphList: [ - //: INFO ALL_PLATFORMS Description text of SaC pairing - qsTr("You may use your smartphone as a card reader with AusweisApp2. The smartphone needs to feature a supported NFC chipset and both devices, your smartphone and this machine, need to be connected to the same WiFi network."), - //: INFO ALL_PLATFORMS Description text of SaC pairing - qsTr("To use your smartphone as a card reader you'll always need to activate the remote service in the AusweisApp2 on the smartphone. For the first time you'll also need to start the pairing mode on your smartphone, select the device from the list of available devices on this machine and then enter the pairing code shown on the phone.")] - } - ] - } PasswordInfoContent { id: pukInfo + hint: PinResetInformationModel.noPinAndNoPukHint - imageType: PasswordInfoImage.LETTER_PUK + hintButtonText: PinResetInformationModel.pinResetActionText //: LABEL ALL_PLATFORMS linkText: qsTr("Where do I find the PUK?") @@ -168,6 +230,7 @@ Item { contentList: [ PasswordInfoContentBlock { + blockHeaderImageType: PasswordInfoImage.LETTER_PUK //: LABEL ALL_PLATFORMS blockTitle: qsTr("Where do I find the PUK?") paragraphList: [ @@ -192,7 +255,6 @@ Item { } PasswordInfoContent { id: canInfo - imageType: PasswordInfoImage.CAN //: LABEL ALL_PLATFORMS linkText: qsTr("Why is the CAN required?") @@ -201,6 +263,7 @@ Item { contentList: [ PasswordInfoContentBlock { + blockHeaderImageType: PasswordInfoImage.CAN //: LABEL ALL_PLATFORMS blockTitle: qsTr("When is the card access number (CAN) required?") paragraphList: [ @@ -225,7 +288,6 @@ Item { } PasswordInfoContent { id: canAllowedInfo - imageType: PasswordInfoImage.CAN //: LABEL ALL_PLATFORMS linkText: qsTr("Why is the CAN required?") @@ -234,6 +296,8 @@ Item { contentList: [ PasswordInfoContentBlock { + blockHeaderImageType: PasswordInfoImage.CAN + //: LABEL ALL_PLATFORMS blockTitle: qsTr("CAN information") paragraphList: [ @@ -254,8 +318,9 @@ Item { PasswordInfoContentBlock { //: LABEL ALL_PLATFORMS blockTitle: qsTr("Learn more about the two types of PIN") + headline: true paragraphList: [ - //: INFO ALL_PLATFORMS Description text explaining the PINs 1/6 + //: INFO ALL_PLATFORMS Description text explaining the PINs 1/7 qsTr("Your ID card comes with a five-digit 'Transport PIN' which you need to replace with a six-digit PIN that you choose yourself.")] }, PasswordInfoContentBlock { @@ -263,22 +328,32 @@ Item { //: LABEL ALL_PLATFORMS blockTitle: qsTr("Five-digit Transport PIN") paragraphList: [ - //: INFO ALL_PLATFORMS Description text explaining the PINs 2/6 - qsTr("The five-digit Transport PIN was sent to you by post after you applied for your ID card."), - //: INFO ALL_PLATFORMS Description text explaining the PINs 3/6 - qsTr("The PIN can only be used once. When you set up the eID function, you will replace this five-digit PIN with a six-digit PIN that you choose yourself.")] + //: INFO ALL_PLATFORMS Description text explaining the PINs 2/7 + qsTr("The five-digit Transport PIN was sent to you by mail after you applied for your ID card."), + //: INFO ALL_PLATFORMS Description text explaining the PINs 3/7 + qsTr("The PIN can only be used once. When you set up the eID function, you will replace this five-digit Transport PIN with a six-digit card PIN that you choose yourself.")] }, PasswordInfoContentBlock { blockHeaderImageType: PasswordInfoImage.Type.PIN //: LABEL ALL_PLATFORMS blockTitle: qsTr("Six-digit PIN") - paragraphList: [ - //: INFO ALL_PLATFORMS Description text explaining the PINs 4/6 - qsTr("This is a number that you choose yourself when you set up the eID function for the first time. It replaces your five-digit Transport PIN."), - //: INFO ALL_PLATFORMS Description text explaining the PINs 5/6 - qsTr("This PIN allows you to prove online that the ID card belongs to you. No one can use your ID card online without this PIN."), - //: INFO ALL_PLATFORMS Description text explaining the PINs 6/6 - qsTr("You can change your six-digit PIN at any time in AusweisApp2.")] + paragraphList: WorkflowModel.isSmartSupported ? [ + + //: INFO ALL_PLATFORMS Description text explaining the PINs 4/7 + qsTr("The six-digit card PIN is a number that you choose yourself when you set up the eID function for the first time. It replaces your five-digit Transport PIN."), + //: INFO ALL_PLATFORMS Description text explaining the PINs 5/7 + qsTr("The Smart-eID PIN also has six digits. You also choose that PIN yourself while setting up the Smart-eID for the first time."), + //: INFO ALL_PLATFORMS Description text explaining the PINs 6/7 + qsTr("With this six-digit PIN you prove online that the ID card or Smart-eID belongs to you. No one can use the eID function without this PIN."), + //: INFO ALL_PLATFORMS Description text explaining the PINs (%1 is replaced with the application name) 7/7 + qsTr("You can change your card PIN and your Smart-eID PIN at any time in %1.").arg(Qt.application.name)] : [ + + //: INFO ALL_PLATFORMS Description text explaining the PINs 4/7 + qsTr("The six-digit card PIN is a number that you choose yourself when you set up the eID function for the first time. It replaces your five-digit Transport PIN."), + //: INFO ALL_PLATFORMS Description text explaining the PINs 6/7 + qsTr("With this six-digit PIN you prove online that the ID card belongs to you. No one can use the eID function without this PIN."), + //: INFO ALL_PLATFORMS Description text explaining the PINs (%1 is replaced with the application name) 7/7 + qsTr("You can change your card PIN at any time in %1.").arg(Qt.application.name)] } ] } @@ -302,15 +377,18 @@ Item { } PasswordInfoContent { id: noPin + //: LABEL ALL_PLATFORMS hint: qsTr("You can use the PIN Reset Service to request a new card PIN free of charge.") - imageType: Constants.is_desktop ? PasswordInfoImage.NONE : PasswordInfoImage.NO_PIN + hintButtonText: PinResetInformationModel.pinResetActionText //: LABEL ALL_PLATFORMS title: qsTr("No PIN known") contentList: [ PasswordInfoContentBlock { + blockHeaderImageType: PasswordInfoImage.NO_PIN + //: LABEL ALL_PLATFORMS blockTitle: qsTr("You do not know your PIN?") paragraphList: [ diff --git a/resources/qml/Governikus/PasswordInfoView/PasswordInfoImage.qml b/resources/qml/Governikus/PasswordInfoView/PasswordInfoImage.qml index 2e0b847e0..630634b1a 100644 --- a/resources/qml/Governikus/PasswordInfoView/PasswordInfoImage.qml +++ b/resources/qml/Governikus/PasswordInfoView/PasswordInfoImage.qml @@ -1,26 +1,25 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import Governikus.Global +import Governikus.Style Item { id: root + enum Type { NONE, LETTER, LETTER_PUK, CAN, - SMARTPHONE_AS_CARD_READER, SMART, NO_PIN, PIN } property int imageType: PasswordInfoImage.Type.LETTER - property real scaleFactorCan: 1 - property real scaleFactorGeneral: 1 + property real scaleFactorGeneral: 0.8 height: root.implicitHeight implicitHeight: infoImageContainer.height @@ -30,59 +29,34 @@ Item { Item { id: infoImageContainer + anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top - height: imageType == PasswordInfoImage.Type.CAN ? (Constants.is_desktop ? 255 : 159) * scaleFactorCan : infoImage.implicitHeight - width: imageType == PasswordInfoImage.Type.CAN ? (Constants.is_desktop ? 400 : 250) * scaleFactorCan : infoImage.implicitWidth + height: infoImage.implicitHeight + width: infoImage.implicitWidth TintableIcon { id: infoImage + anchors.fill: parent source: switch (imageType) { case PasswordInfoImage.Type.CAN: - return "qrc:///images/id_card.png"; - case PasswordInfoImage.Type.SMARTPHONE_AS_CARD_READER: - return "qrc:///images/phone_to_pc.svg"; + return "qrc:///images/can.svg"; case PasswordInfoImage.Type.SMART: return ""; case PasswordInfoImage.Type.LETTER_PUK: - return "qrc:///images/pin_letter_pinpuk_red_bar_puk.svg"; + return "qrc:///images/puk_%1.svg".arg(Style.currentTheme.name); case PasswordInfoImage.Type.NO_PIN: - return "qrc:///images/material_live_help.svg"; + return "qrc:///images/pin_unknown.svg"; case PasswordInfoImage.Type.PIN: return "qrc:///images/pin_person.svg"; default: - return "qrc:///images/pin_letter_pinpuk_red_bar.svg"; - } - sourceSize.width: { - switch (imageType) { - case PasswordInfoImage.Type.CAN: - return undefined; - case PasswordInfoImage.Type.NO_PIN: - return 100 * scaleFactorGeneral; - default: - return 200 * scaleFactorGeneral; - } + return "qrc:///images/transportpin_%1.svg".arg(Style.currentTheme.name); } - tintColor: Style.color.accent - tintEnabled: imageType == PasswordInfoImage.Type.NO_PIN + sourceSize.width: 200 * scaleFactorGeneral + tintColor: Style.color.control + tintEnabled: imageType === PasswordInfoImage.Type.NO_PIN || imageType === PasswordInfoImage.Type.CAN || imageType === PasswordInfoImage.Type.PIN width: parent.width - - Rectangle { - readonly property real leftEdge: (parent.width - parent.paintedWidth) / 2.0 - readonly property real topEdge: (parent.height - parent.paintedHeight) / 2.0 - - anchors.left: parent.left - anchors.leftMargin: parent.paintedWidth * 0.7475 + leftEdge - anchors.top: parent.top - anchors.topMargin: parent.paintedWidth * 0.4175 + topEdge - border.color: Constants.red - border.width: Math.max(1, parent.paintedWidth * 0.015) - color: Style.color.transparent - height: parent.paintedWidth * 0.0625 - visible: imageType == PasswordInfoImage.Type.CAN - width: parent.paintedWidth * 0.2 - } } } } diff --git a/resources/qml/Governikus/ProgressView/+desktop/ProgressView.qml b/resources/qml/Governikus/ProgressView/+desktop/ProgressView.qml index ec0fcda2e..e21fd9806 100644 --- a/resources/qml/Governikus/ProgressView/+desktop/ProgressView.qml +++ b/resources/qml/Governikus/ProgressView/+desktop/ProgressView.qml @@ -1,13 +1,12 @@ /** * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.View SectionPage { id: baseItem @@ -19,24 +18,24 @@ SectionPage { property alias subTextColor: subText.color property alias text: text.text - StatusIcon { - id: circle + TintableAnimation { anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.top anchors.verticalCenterOffset: baseItem.height / 4 - borderEnabled: false - busy: true - height: Style.dimens.status_icon_large - source: "qrc:///images/sandglass.svg" + fillMode: Image.PreserveAspectFit + height: Style.dimens.header_icon_size + source: "qrc:///images/sandglass.webp" + tintColor: Style.color.control } GText { id: text + Accessible.name: text.text activeFocusOnTab: true anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.verticalCenter horizontalAlignment: Text.AlignHCenter - textStyle: Style.text.header + textStyle: Style.text.headline visible: text.text !== "" width: Math.min(parent.width - (2 * Constants.pane_padding), Style.dimens.max_text_width) @@ -45,13 +44,14 @@ SectionPage { } GText { id: subText + Accessible.name: subText.text activeFocusOnTab: true anchors.horizontalCenter: parent.horizontalCenter anchors.top: text.bottom anchors.topMargin: Constants.text_spacing horizontalAlignment: Text.AlignHCenter - textStyle: Style.text.header_secondary + textStyle: Style.text.subline visible: subText.text !== "" width: Math.min(parent.width - (2 * Constants.pane_padding), Style.dimens.max_text_width) @@ -60,6 +60,7 @@ SectionPage { } GText { id: progressText + Accessible.name: progressText.text activeFocusOnTab: true anchors.bottom: progressBar.top @@ -74,6 +75,7 @@ SectionPage { } GProgressBar { id: progressBar + activeFocusOnTab: true value: progressValue visible: false @@ -81,7 +83,7 @@ SectionPage { anchors { bottom: parent.bottom left: parent.left - margins: ApplicationModel.scaleFactor * 80 + margins: plugin.scaleFactor * 80 right: parent.right } } diff --git a/resources/qml/Governikus/ProgressView/+mobile/ProgressView.qml b/resources/qml/Governikus/ProgressView/+mobile/ProgressView.qml index ff745ab2b..57fc1f3d7 100644 --- a/resources/qml/Governikus/ProgressView/+mobile/ProgressView.qml +++ b/resources/qml/Governikus/ProgressView/+mobile/ProgressView.qml @@ -1,16 +1,17 @@ /** * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.View 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.View -SectionPage { +FlickableSectionPage { id: root + property alias icon: statusIcon.source property alias progressBarVisible: progressBar.visible property alias progressText: progressText.text property int progressValue @@ -18,66 +19,48 @@ SectionPage { property alias subTextColor: subText.color property alias text: text.text - sectionPageFlickable: contentItem + AnimatedImage { + id: statusIcon - GFlickableColumnLayout { - id: contentItem + Layout.alignment: Qt.AlignHCenter + Layout.preferredHeight: Style.dimens.header_icon_size + fillMode: Image.PreserveAspectFit + source: "qrc:///images/sandglass.webp" + } + GText { + id: text + + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: Constants.component_spacing + horizontalAlignment: Text.AlignHCenter + textStyle: Style.text.headline + } + GText { + id: subText - readonly property var maxIconHeight: Style.dimens.header_icon_size - readonly property var minIconHeight: Style.dimens.medium_icon_size + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: Constants.text_spacing + horizontalAlignment: Text.AlignHCenter + textStyle: Style.text.subline + } + GSpacer { + Layout.fillHeight: true + } + GProgressBar { + id: progressBar - anchors.fill: parent - maximumContentWidth: Style.dimens.max_text_width - minimumContentHeight: implicitContentHeight - (maxIconHeight - minIconHeight) - spacing: 0 + Layout.alignment: Qt.AlignHCenter + Layout.fillWidth: true + Layout.topMargin: 2 * Constants.component_spacing + value: progressValue + visible: false + } + GText { + id: progressText - StatusIcon { - id: statusIcon - Layout.alignment: Qt.AlignHCenter - Layout.fillHeight: true - Layout.maximumHeight: contentItem.maxIconHeight - Layout.minimumHeight: contentItem.minIconHeight - Layout.preferredHeight: contentItem.maxIconHeight - borderEnabled: false - busy: root.visible - implicitWidth: height - source: "qrc:///images/sandglass.svg" - } - GText { - id: text - Layout.alignment: Qt.AlignHCenter - Layout.fillWidth: true - Layout.topMargin: Constants.component_spacing - horizontalAlignment: Text.AlignHCenter - textStyle: Style.text.header_accent - } - GText { - id: subText - Layout.alignment: Qt.AlignHCenter - Layout.fillWidth: true - Layout.topMargin: Constants.text_spacing - horizontalAlignment: Text.AlignHCenter - textStyle: Style.text.normal_secondary - } - GSpacer { - Layout.fillHeight: true - } - GProgressBar { - id: progressBar - Layout.alignment: Qt.AlignHCenter - Layout.fillWidth: true - Layout.topMargin: 2 * Constants.component_spacing - value: progressValue - visible: false - } - GText { - id: progressText - Layout.alignment: Qt.AlignHCenter - Layout.fillWidth: true - Layout.topMargin: Constants.text_spacing - horizontalAlignment: Text.AlignHCenter - textStyle: Style.text.normal_secondary - visible: progressBar.visible - } + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: Constants.text_spacing + horizontalAlignment: Text.AlignHCenter + visible: progressBar.visible } } diff --git a/resources/qml/Governikus/Provider/+desktop/ProviderDetailButtonBar.qml b/resources/qml/Governikus/Provider/+desktop/ProviderDetailButtonBar.qml deleted file mode 100644 index 569d822a1..000000000 --- a/resources/qml/Governikus/Provider/+desktop/ProviderDetailButtonBar.qml +++ /dev/null @@ -1,107 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.View 1.0 - -Rectangle { - id: baseItem - - property string address: "" - property alias buttonColor: button.buttonColor - property string longName: "" - property string providerIcon: "" - property string selectedCategory: "" - property string shortName: "" - - function clickButton() { - if (baseItem.address !== "") { - Qt.openUrlExternally(baseItem.address); - } - } - - color: Style.color.background_pane - height: button.height + 2 * Constants.pane_padding - width: parent.width - - Keys.onSpacePressed: clickButton() - - GSeparator { - color: Style.color.high_contrast_item_border - height: Style.dimens.high_contrast_item_border - - anchors { - left: parent.left - right: parent.right - top: parent.top - } - } - GSeparator { - color: Style.color.high_contrast_item_border - height: Style.dimens.high_contrast_item_border - - anchors { - bottom: parent.bottom - left: parent.left - right: parent.right - } - } - Rectangle { - id: iconContainer - anchors.left: parent.left - anchors.leftMargin: Constants.component_spacing - anchors.verticalCenter: baseItem.top - border.color: Style.color.border - border.width: Style.dimens.separator_size - color: Constants.white - height: ApplicationModel.scaleFactor * 135 - radius: Style.dimens.corner_radius - width: height - - Image { - id: icon - anchors.fill: parent - anchors.margins: iconContainer.radius / 2 - asynchronous: true - fillMode: Image.PreserveAspectFit - source: baseItem.providerIcon - sourceSize.height: height - } - } - GText { - activeFocusOnTab: true - anchors.left: iconContainer.right - anchors.leftMargin: Constants.component_spacing - anchors.right: button.left - anchors.rightMargin: Constants.component_spacing - anchors.verticalCenter: parent.verticalCenter - elide: Text.ElideRight - maximumLineCount: 2 - text: longName - textStyle: Style.text.header - width: parent.width / 2 - - FocusFrame { - } - } - GButton { - id: button - anchors.right: parent.right - anchors.rightMargin: Constants.pane_padding - anchors.verticalCenter: parent.verticalCenter - buttonColor: categoryColor - enabled: baseItem.address !== "" - enabledTooltipText: baseItem.address - icon.source: "qrc:///images/material_open_in_new.svg" - - //: LABEL DESKTOP - text: qsTr("To provider") - tintIcon: true - - onClicked: baseItem.clickButton() - } -} diff --git a/resources/qml/Governikus/Provider/+desktop/ProviderDetailHistory.qml b/resources/qml/Governikus/Provider/+desktop/ProviderDetailHistory.qml deleted file mode 100644 index 57bbe4b63..000000000 --- a/resources/qml/Governikus/Provider/+desktop/ProviderDetailHistory.qml +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.Provider 1.0 -import Governikus.Type.HistoryModel 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.View 1.0 - -Item { - id: baseItem - Accessible.description: HistoryModel.nameFilter.count === 0 ? qsTr("The list is empty, no recorded interaction with this provider.") : "" - Accessible.name: qsTr("List of your past interactions with this provider") - Accessible.role: Accessible.List - height: columnLayout.height - - ColumnLayout { - id: columnLayout - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - spacing: Constants.text_spacing - - Repeater { - id: repeater - model: HistoryModel.nameFilter - - ColumnLayout { - Layout.fillWidth: true - spacing: columnLayout.spacing - - GSeparator { - Layout.fillWidth: true - visible: index !== 0 - } - ProviderDetailHistoryItem { - id: historyItem - Layout.fillWidth: true - activeFocusOnTab: true - providerName: subject - purposeText: purpose - } - } - } - GText { - activeFocusOnTab: true - - //: INFO DESKTOP No authentication history, placeholder text. - text: qsTr("Currently there are no history entries.") - textStyle: Style.text.normal - visible: repeater.count === 0 - width: parent.width - - FocusFrame { - } - } - } -} diff --git a/resources/qml/Governikus/Provider/+desktop/ProviderDetailHistoryItem.qml b/resources/qml/Governikus/Provider/+desktop/ProviderDetailHistoryItem.qml deleted file mode 100644 index 85f434e9b..000000000 --- a/resources/qml/Governikus/Provider/+desktop/ProviderDetailHistoryItem.qml +++ /dev/null @@ -1,69 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.View 1.0 -import Governikus.Type.SettingsModel 1.0 - -Item { - id: baseItem - - property string providerName: "" - property string purposeText: "" - - Accessible.name: date.text + ". " + providerName + ". " + purposeText - Accessible.role: Accessible.ListItem - height: columnLayout.height - - ColumnLayout { - id: columnLayout - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - spacing: Constants.text_spacing - - GText { - id: date - font.capitalization: Font.AllUppercase - text: Utils.historyDateString(dateTime) - textStyle: Style.text.normal - } - GridLayout { - Layout.fillWidth: true - columnSpacing: Constants.text_spacing - columns: 2 - - GText { - maximumLineCount: 1 - //: LABEL DESKTOP - text: qsTr("Service:") - textStyle: Style.text.normal_highlight - } - GText { - Layout.fillWidth: true - elide: Text.ElideRight - maximumLineCount: 1 - text: purposeText - textStyle: Style.text.normal - } - GText { - maximumLineCount: 1 - //: LABEL DESKTOP - text: qsTr("Provider:") - textStyle: Style.text.normal_highlight - } - GText { - Layout.fillWidth: true - elide: Text.ElideRight - maximumLineCount: 1 - text: providerName - textStyle: Style.text.normal - } - } - } - FocusFrame { - } -} diff --git a/resources/qml/Governikus/Provider/+desktop/ProviderDetailView.qml b/resources/qml/Governikus/Provider/+desktop/ProviderDetailView.qml deleted file mode 100644 index 4a274835d..000000000 --- a/resources/qml/Governikus/Provider/+desktop/ProviderDetailView.qml +++ /dev/null @@ -1,133 +0,0 @@ -/** - * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 - -SectionPage { - id: baseItem - - property alias historyModelItem: provider.modelItem - property alias providerModelItem: provider.modelItem - readonly property color titleBarColor: Style.currentTheme.highContrast ? Style.color.background_pane : Category.displayColor(provider.category) - - signal showDetailView(var pModel) - - titleBarAction: TitleBarAction { - helpTopic: "providerDetails" - text: provider.shortName - } - - ProviderModelItem { - id: provider - } - Item { - id: mainContent - anchors.fill: parent - - Rectangle { - id: imageHeader - anchors.top: parent.top - color: baseItem.titleBarColor - height: Math.floor(baseItem.height * 0.5) - width: parent.width - - RowLayout { - anchors.fill: parent - spacing: 0 - - Image { - Layout.fillHeight: true - Layout.preferredWidth: Math.floor(parent.width * 0.6) - asynchronous: true - fillMode: Image.PreserveAspectCrop - source: provider.image - sourceSize.height: height - } - ProviderContactInfo { - Layout.fillHeight: true - Layout.fillWidth: true - Layout.leftMargin: Constants.pane_spacing * 2 - Layout.margins: Constants.pane_spacing - Layout.rightMargin: Constants.pane_spacing * 2 - activeFocusOnTab: true - contactModel: provider.contactModel - } - } - } - ProviderDetailButtonBar { - id: buttonBar - address: provider.address - anchors.top: imageHeader.bottom - buttonColor: baseItem.titleBarColor - longName: provider.longName - providerIcon: provider.icon - selectedCategory: provider.category - shortName: provider.shortName - } - RowLayout { - id: lowerRow - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.margins: Constants.component_spacing - anchors.right: parent.right - anchors.top: buttonBar.bottom - spacing: Constants.component_spacing - - Item { - Layout.fillHeight: true - Layout.fillWidth: true - - ScrollablePane { - id: leftPane - activeFocusOnTab: true - anchors.fill: parent - - //: LABEL DESKTOP - title: qsTr("Description") - - onVisibleChanged: scrollYPositionIntoView(0) - - GText { - id: leftColumn - activeFocusOnTab: true - - //: LABEL DESKTOP - text: !!provider.longDescription ? provider.longDescription : qsTr("The provider did not provide a description.") - textFormat: Text.RichText - textStyle: Style.text.normal - width: parent.width - - FocusFrame { - } - } - } - } - Item { - Layout.fillHeight: true - Layout.fillWidth: true - - ScrollablePane { - id: rightPane - activeFocusOnTab: true - anchors.fill: parent - - //: LABEL DESKTOP - title: qsTr("History") - - onVisibleChanged: scrollYPositionIntoView(0) - - ProviderDetailHistory { - id: rightColumn - width: parent.width - } - } - } - } - } -} diff --git a/resources/qml/Governikus/Provider/+desktop/ProviderInfoSection.qml b/resources/qml/Governikus/Provider/+desktop/ProviderInfoSection.qml deleted file mode 100644 index bd732e15f..000000000 --- a/resources/qml/Governikus/Provider/+desktop/ProviderInfoSection.qml +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 - -Item { - id: baseItem - - property alias image: icon.source - property string name: "" - property alias title: text.label - - Accessible.name: text.Accessible.name - Accessible.role: Accessible.StaticText - height: contentRow.height - width: contentRow.width - - Row { - id: contentRow - height: text.height - spacing: Constants.groupbox_spacing - - Image { - id: icon - anchors.verticalCenter: text.verticalCenter - sourceSize.height: Style.dimens.icon_size - } - LabeledText { - id: text - activeFocusOnTab: false - bodyElide: Text.ElideRight - maximumBodyLineCount: 1 - - //: LABEL DESKTOP - text: name.length > 0 ? name : qsTr("See details under \"more...\"") - width: baseItem.width - icon.width - Constants.groupbox_spacing - } - } - FocusFrame { - } -} diff --git a/resources/qml/Governikus/Provider/+mobile/+phone/ProviderDetailView.qml b/resources/qml/Governikus/Provider/+mobile/+phone/ProviderDetailView.qml deleted file mode 100644 index a97370549..000000000 --- a/resources/qml/Governikus/Provider/+mobile/+phone/ProviderDetailView.qml +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Provider 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 - -SectionPage { - id: baseItem - - property alias providerModelItem: provider.modelItem - readonly property real tabBarSpacing: Constants.is_layout_ios ? Constants.component_spacing : 0 - - contentBehindTitlebar: true - title: provider.shortName - titleBarColor: Category.displayColor(provider.category) - titleBarOpacity: header.titleBarOpacity - - content: Column { - bottomPadding: Constants.pane_padding - spacing: Constants.pane_padding - - ProviderHeader { - id: header - selectedProvider: provider - width: baseItem.width - } - GPaneBackground { - implicitHeight: description.implicitHeight + 2 * Constants.pane_padding - - anchors { - left: parent.left - margins: Constants.pane_padding - right: parent.right - } - ProviderDetailDescription { - id: description - anchors.fill: parent - anchors.margins: Constants.pane_padding - description: provider.longDescription - } - } - GPaneBackground { - implicitHeight: contactInfo.implicitHeight + 2 * Constants.pane_padding - - anchors { - left: parent.left - margins: Constants.pane_padding - right: parent.right - } - ProviderContactInfo { - id: contactInfo - anchors.fill: parent - anchors.margins: Constants.pane_padding - contactModel: provider.contactModel - textStyle: Style.text.normal_accent - titleTextStyle: Style.text.header_accent - } - } - } - navigationAction: NavigationAction { - action: NavigationAction.Action.Back - - onClicked: pop() - } - - ProviderModelItem { - id: provider - } -} diff --git a/resources/qml/Governikus/Provider/+mobile/+phone/ProviderHeader.qml b/resources/qml/Governikus/Provider/+mobile/+phone/ProviderHeader.qml deleted file mode 100644 index 1e0318884..000000000 --- a/resources/qml/Governikus/Provider/+mobile/+phone/ProviderHeader.qml +++ /dev/null @@ -1,151 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.SettingsModel 1.0 -import Governikus.Type.ProviderCategoryFilterModel 1.0 - -Rectangle { - id: baseItem - - readonly property string backgroundImage: customProviderImage ? selectedProvider.image : Category.backgroundImageSource(selectedCategory) - readonly property bool customProviderImage: !!selectedProvider && !!selectedProvider.image - readonly property real headerOffsetY: sectionPageFlickable.contentY - sectionPageFlickable.originY - readonly property double iconHeightRatio: 0.3 - readonly property double iconVerticalMarginRatio: 0.2 - property int maxContentY: if (withButtons && parent !== null) { - return parent.height * (iconHeightRatio + iconVerticalMarginRatio); - } else { - return height / 2; - } - - // Properties that are set by ProviderView or ProviderDetailView - property string selectedCategory: selectedProvider ? selectedProvider.category : "" - property var selectedProvider - - // Internal vars - readonly property color shadowColor: Category.displayColor(selectedCategory) - readonly property real shadowOpacity: Math.min(1, headerOffsetY / (backgroundImage.height - Style.dimens.titlebar_height)) - - // This is interpreted by the SectionPage component - readonly property real titleBarOpacity: shadow.opacity === 1 ? 1 : (customProviderImage ? Math.max(0, 0.5 - shadow.opacity) : 0) - readonly property real titleBarTopBounce: sectionPageFlickable.verticalOvershoot < 0.0 ? -sectionPageFlickable.verticalOvershoot : 0.0 - readonly property bool withButtons: selectedCategory === "" && !selectedProvider - - signal categorySelected(string category) - - color: providerInfo.color - height: backgroundImage.height + providerInfo.height - titleBarTopBounce - - Image { - id: backgroundImage - anchors.left: parent.left - anchors.top: parent.top - anchors.topMargin: -titleBarTopBounce // When flicking over the top, scale the image (similar to native iOS apps) - fillMode: Image.PreserveAspectCrop - height: width / 1.80 + titleBarTopBounce - source: baseItem.backgroundImage - width: parent.width - - Rectangle { - id: iconContainer - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.margins: Constants.component_spacing - border.color: Style.color.border - border.width: Style.dimens.separator_size - color: Constants.white - height: 70 - radius: Style.dimens.corner_radius - visible: !!selectedProvider - width: height - - Image { - id: icon - anchors.fill: parent - anchors.margins: iconContainer.radius / 2 - asynchronous: true - fillMode: Image.PreserveAspectFit - source: selectedProvider ? selectedProvider.icon : "" - } - } - } - Row { - id: iconsRow - anchors.bottom: backgroundImage.bottom - anchors.bottomMargin: backgroundImage.height / 2 - iconsRow.height - titleBarTopBounce - headerOffsetY / (headerOffsetY < 0.0 ? 1.0 : 2.0) - anchors.horizontalCenter: parent.horizontalCenter - height: backgroundImage.height * iconHeightRatio - visible: withButtons - width: backgroundImage.width * 0.9 - - Repeater { - model: ["citizen", "finance", "insurance", "other"] - - Item { - height: parent.height - width: parent.width * 0.25 - - Image { - Accessible.name: Category.displayString(modelData) - Accessible.role: Accessible.Button - anchors.fill: parent - asynchronous: true - fillMode: Image.PreserveAspectFit - source: Category.buttonImageSource(modelData) - } - MouseArea { - anchors.fill: parent - - onClicked: baseItem.categorySelected(modelData) - } - } - } - } - Rectangle { - id: shadow - anchors.fill: backgroundImage - color: baseItem.shadowColor - opacity: shadowOpacity - } - Rectangle { - id: providerInfo - anchors.left: parent.left - anchors.top: backgroundImage.bottom - color: Style.color.background_pane - height: visible ? column.height + 2 * Constants.pane_padding : 0 - visible: !!selectedProvider - width: parent.width - - Column { - id: column - anchors.left: parent.left - anchors.margins: Constants.pane_padding - anchors.right: parent.right - anchors.top: parent.top - spacing: Constants.pane_spacing - - GText { - id: providerText - text: selectedProvider ? selectedProvider.longName : "" - visible: text.length > 0 - width: parent.width - } - GButton { - id: providerButton - anchors.right: parent.right - buttonColor: shadowColor - icon.source: "qrc:///images/material_open_in_new.svg" - //: LABEL ANDROID IOS - text: qsTr("To provider") - tintIcon: true - - onClicked: { - Qt.openUrlExternally(selectedProvider ? selectedProvider.address : ""); - } - } - } - } -} diff --git a/resources/qml/Governikus/Provider/+mobile/+tablet/ProviderDetailButtonBar.qml b/resources/qml/Governikus/Provider/+mobile/+tablet/ProviderDetailButtonBar.qml deleted file mode 100644 index df759e248..000000000 --- a/resources/qml/Governikus/Provider/+mobile/+tablet/ProviderDetailButtonBar.qml +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 - -Item { - id: baseItem - - property string address: "" - property string providerIcon: "" - property string selectedCategory: "" - property color titleBarColor - - height: button.height + Constants.component_spacing - width: parent.width - - Rectangle { - id: iconContainer - anchors.left: parent.left - anchors.leftMargin: Constants.component_spacing - anchors.verticalCenter: baseItem.top - border.color: Style.color.border - border.width: Style.dimens.separator_size - color: Constants.white - height: 2 * baseItem.height - radius: Style.dimens.corner_radius - width: height - - Image { - id: icon - anchors.fill: parent - anchors.margins: iconContainer.radius / 2 - asynchronous: true - fillMode: Image.PreserveAspectFit - source: baseItem.providerIcon - sourceSize.height: height - } - } - GButton { - id: button - anchors.bottom: iconContainer.bottom - anchors.left: iconContainer.right - anchors.leftMargin: Constants.component_spacing - buttonColor: baseItem.titleBarColor - enabled: baseItem.address !== "" - icon.source: "qrc:///images/material_open_in_new.svg" - - //: LABEL ANDROID_TABLET IOS_TABLET - text: qsTr("To provider") - tintIcon: true - - onClicked: { - if (baseItem.address !== "") { - Qt.openUrlExternally(baseItem.address); - } - } - } -} diff --git a/resources/qml/Governikus/Provider/+mobile/+tablet/ProviderDetailHistory.qml b/resources/qml/Governikus/Provider/+mobile/+tablet/ProviderDetailHistory.qml deleted file mode 100644 index 2e47d6dd7..000000000 --- a/resources/qml/Governikus/Provider/+mobile/+tablet/ProviderDetailHistory.qml +++ /dev/null @@ -1,57 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Provider 1.0 -import Governikus.Type.HistoryModel 1.0 - -Column { - id: baseItem - - property var openHistoryInfoFunc: function () {} - - signal scrollHistoryDown - signal scrollHistoryUp - - spacing: Constants.pane_spacing - - GText { - id: headerText - Accessible.name: text - Accessible.role: Accessible.StaticText - - //: LABEL ANDROID_TABLET IOS_TABLET - text: qsTr("History") - textStyle: Style.text.header_accent - } - Repeater { - id: historyItemRepeater - model: HistoryModel.nameFilter - - ProviderDetailHistoryItem { - dateTime: model.dateTime - //: LABEL ANDROID_TABLET IOS_TABLET - infoText: qsTr("Purpose for reading out requested data") - openInfoFunction: baseItem.openHistoryInfoFunc - providerName: subject - providerPostalAddress: providerPostalAddress - purposeText: purpose - requestedDataText: requestedData - termsOfUsageText: termsOfUsage - width: parent.width - - Accessible.onScrollDownAction: baseItem.scrollHistoryDown() - Accessible.onScrollUpAction: baseItem.scrollHistoryUp() - } - } - GText { - activeFocusOnTab: true - - //: INFO ANDROID_TABLET IOS_TABLET No authentication history, placeholder text. - text: qsTr("Currently there are no history entries.") - visible: historyItemRepeater.count === 0 - width: parent.width - } -} diff --git a/resources/qml/Governikus/Provider/+mobile/+tablet/ProviderDetailHistoryInfo.qml b/resources/qml/Governikus/Provider/+mobile/+tablet/ProviderDetailHistoryInfo.qml deleted file mode 100644 index 425747973..000000000 --- a/resources/qml/Governikus/Provider/+mobile/+tablet/ProviderDetailHistoryInfo.qml +++ /dev/null @@ -1,144 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Provider 1.0 - -Item { - id: baseItem - - property string internalState: "off" - property string providerName: "" - property string providerPostalAddress: "" - property string purposeText: "" - property string requestedDataText: "" - property string termsOfUsageText: "" - - Rectangle { - anchors.fill: baseItem - color: "black" - opacity: 0.4 - } - GFlickable { - anchors.fill: baseItem - anchors.margins: Constants.component_spacing - contentHeight: infoRow.height - - onContentYChanged: { - if (contentY < 0) { - contentY = 0; /* prevent flicking over the top */ - } - } - - Row { - id: infoRow - height: Math.max(leftColumn.height, rightColumn.height) + 2 * Constants.pane_padding - spacing: Constants.component_spacing - - Item { - height: 1 - width: baseItem.width / 3 - - GPane { - id: leftPane - height: infoRow.height - - anchors { - left: parent.left - right: parent.right - } - } - Column { - id: leftColumn - anchors.left: parent.left - anchors.margins: Constants.pane_padding - anchors.right: parent.right - anchors.top: parent.top - spacing: Constants.pane_spacing - - ProviderInfoSection { - imageSource: "qrc:///images/provider/information.svg" - name: baseItem.providerName - //: LABEL ANDROID_TABLET IOS_TABLET - title: qsTr("Provider") - } - ProviderInfoSection { - imageSource: "qrc:///images/provider/purpose.svg" - name: baseItem.purposeText - //: LABEL ANDROID_TABLET IOS_TABLET - title: qsTr("Purpose for reading out requested data") - } - GText { - id: readDataTitle - //: LABEL ANDROID_TABLET IOS_TABLET - text: qsTr("Read data") - textStyle: Style.text.header_accent - width: parent.width - } - Column { - id: infoTable - spacing: 1 - width: parent.width - - Repeater { - model: baseItem.requestedDataText.split(",") - - Item { - id: textItem - height: 32 - width: infoTable.width - - Rectangle { - anchors.fill: textItem - color: Constants.white - } - GText { - anchors.verticalCenter: parent.verticalCenter - text: modelData.trim() - textStyle: Style.text.normal_secondary - } - } - } - } - } - } - Item { - height: 1 - width: baseItem.width / 3 * 2 - 3 * Constants.component_spacing - - GPane { - id: rightPane - height: infoRow.height - - anchors { - left: parent.left - right: parent.right - } - } - Column { - id: rightColumn - anchors.left: parent.left - anchors.margins: Constants.pane_padding - anchors.right: parent.right - anchors.top: parent.top - spacing: Constants.pane_spacing - - GText { - id: termsOfUsageTitle - //: LABEL ANDROID_TABLET IOS_TABLET - text: qsTr("Terms of usage") - textStyle: Style.text.header_accent - } - GText { - id: termsOfUsageTextItem - text: baseItem.termsOfUsageText - textStyle: Style.text.normal_secondary - width: parent.width - } - } - } - } - } -} diff --git a/resources/qml/Governikus/Provider/+mobile/+tablet/ProviderDetailHistoryItem.qml b/resources/qml/Governikus/Provider/+mobile/+tablet/ProviderDetailHistoryItem.qml deleted file mode 100644 index 3a973ca49..000000000 --- a/resources/qml/Governikus/Provider/+mobile/+tablet/ProviderDetailHistoryItem.qml +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.SettingsModel 1.0 - -ListItem { - id: baseItem - - property var dateTime: "" - property string infoText: "" - property var openInfoFunction: function () {} - property string providerName: "" - property string providerPostalAddress: "" - property string purposeText: "" - property string requestedDataText: "" - property string termsOfUsageText: "" - - Accessible.description: qsTr("Click to view details of history entry.") - contentMarginLeft: 0 - contentMarginRight: 0 - //: LABEL ANDROID IOS - footerText: purposeText !== "" ? purposeText : qsTr("Touch for more details") - headerText: Utils.historyDateString(dateTime) - height: 72 - //: LABEL ANDROID IOS - text: (!!providerName ? providerName : qsTr("Touch for more details")) - - onClicked: baseItem.openInfoFunction({ - "providerName": baseItem.providerName, - "providerPostalAddress": baseItem.providerPostalAddress, - "purposeText": baseItem.purposeText, - "requestedDataText": baseItem.requestedDataText, - "termsOfUsageText": baseItem.termsOfUsageText - }) -} diff --git a/resources/qml/Governikus/Provider/+mobile/+tablet/ProviderDetailView.qml b/resources/qml/Governikus/Provider/+mobile/+tablet/ProviderDetailView.qml deleted file mode 100644 index 35baf63ba..000000000 --- a/resources/qml/Governikus/Provider/+mobile/+tablet/ProviderDetailView.qml +++ /dev/null @@ -1,182 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Provider 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 - -SectionPage { - id: baseItem - - property alias historyModelItem: provider.modelItem - property var openHistoryInfoFunc: function (entryInfo) { - providerDetailsHistoryInfo.visible = true; - providerDetailsHistoryInfo.providerName = entryInfo['providerName']; - providerDetailsHistoryInfo.providerPostalAddress = entryInfo['providerPostalAddress']; - providerDetailsHistoryInfo.purposeText = entryInfo['purposeText']; - providerDetailsHistoryInfo.requestedDataText = entryInfo['requestedDataText']; - providerDetailsHistoryInfo.termsOfUsageText = entryInfo['termsOfUsageText']; - } - property alias providerModelItem: provider.modelItem - readonly property real titleBarOpacity: 1 - - title: historyModelItem && historyModelItem.subject ? historyModelItem.subject : provider.shortName - titleBarColor: Category.displayColor(provider.category) - - content: Column { - height: childrenRect.height + Constants.component_spacing - width: baseItem.width - - Rectangle { - color: baseItem.titleBarColor - height: baseItem.height / 2 - width: parent.width - - RowLayout { - anchors.fill: parent - spacing: 0 - - Item { - Layout.fillHeight: true - Layout.preferredWidth: baseItem.width * 2 / 3 - - Image { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - asynchronous: true - fillMode: Image.PreserveAspectFit - height: parent.height - source: provider.image - - Rectangle { - width: parent.width / 4 - - gradient: Gradient { - orientation: Gradient.Horizontal - - GradientStop { - color: Style.color.transparent - position: 0.0 - } - GradientStop { - color: Category.displayColor(provider.category) - position: 0.95 - } - } - - anchors { - bottom: parent.bottom - right: parent.right - top: parent.top - } - } - } - } - ProviderContactInfo { - Layout.fillHeight: true - Layout.fillWidth: true - Layout.margins: Constants.groupbox_spacing - contactModel: provider.contactModel - } - } - } - Row { - id: lowerRow - height: Math.max(buttonBar.height + leftColumn.height, rightColumn.height) + 3 * Constants.pane_padding - width: parent.width - - Item { - height: 1 - width: lowerRow.width * 2 / 3 - - ProviderDetailButtonBar { - id: buttonBar - address: provider.address - providerIcon: provider.icon - selectedCategory: provider.category - titleBarColor: baseItem.titleBarColor - } - GPane { - id: leftPane - height: lowerRow.height - (buttonBar.height + Constants.pane_padding) - - anchors { - left: parent.left - margins: Constants.component_spacing - right: parent.right - top: buttonBar.bottom - } - } - ProviderDetailDescription { - id: leftColumn - anchors.left: parent.left - anchors.margins: 2 * Constants.pane_padding - anchors.right: parent.right - anchors.top: buttonBar.bottom - description: provider.longDescription - - onScrollDescriptionDown: baseItem.scrollPageDown() - onScrollDescriptionUp: baseItem.scrollPageUp() - } - } - Item { - height: 1 - width: lowerRow.width / 3 - Constants.component_spacing - - GPane { - id: rightPane - height: lowerRow.height - Constants.pane_padding - - anchors { - left: parent.left - right: parent.right - top: parent.top - topMargin: Constants.component_spacing - } - } - ProviderDetailHistory { - id: rightColumn - anchors.left: parent.left - anchors.leftMargin: Constants.pane_padding - anchors.right: parent.right - anchors.rightMargin: Constants.pane_padding - anchors.top: parent.top - anchors.topMargin: 2 * Constants.pane_padding - openHistoryInfoFunc: baseItem.openHistoryInfoFunc - - onScrollHistoryDown: baseItem.scrollPageDown() - onScrollHistoryUp: baseItem.scrollPageUp() - } - } - } - } - navigationAction: NavigationAction { - action: NavigationAction.Action.Back - - onClicked: { - if (providerDetailsHistoryInfo.visible) { - providerDetailsHistoryInfo.visible = false; - } else { - pop(); - } - } - } - rightTitleBarAction: Item { - } - - ProviderModelItem { - id: provider - } - ProviderDetailHistoryInfo { - id: providerDetailsHistoryInfo - anchors.left: baseItem.left - anchors.top: baseItem.top - height: parent.height - visible: false - width: parent.width - } -} diff --git a/resources/qml/Governikus/Provider/+mobile/ProviderDetailDescription.qml b/resources/qml/Governikus/Provider/+mobile/ProviderDetailDescription.qml deleted file mode 100644 index c44a554c6..000000000 --- a/resources/qml/Governikus/Provider/+mobile/ProviderDetailDescription.qml +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 - -Column { - id: baseItem - - property string description: "" - - signal scrollDescriptionDown - signal scrollDescriptionUp - - spacing: Constants.pane_spacing - - GText { - //: LABEL ANDROID_TABLET IOS_TABLET - text: qsTr("Description") - textStyle: Style.text.header_accent - } - GText { - horizontalAlignment: Text.AlignLeft - //: LABEL ANDROID_TABLET IOS_TABLET - text: (!!baseItem.description ? baseItem.description : qsTr("The provider did not provide a description.")) - textFormat: Text.RichText - textStyle: Style.text.normal_secondary - width: parent.width - - Accessible.onScrollDownAction: baseItem.scrollDescriptionDown() - Accessible.onScrollUpAction: baseItem.scrollDescriptionUp() - } -} diff --git a/resources/qml/Governikus/Provider/ProviderContactInfo.qml b/resources/qml/Governikus/Provider/ProviderContactInfo.qml deleted file mode 100644 index 9899263e6..000000000 --- a/resources/qml/Governikus/Provider/ProviderContactInfo.qml +++ /dev/null @@ -1,83 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.View 1.0 - -Item { - id: baseItem - - property alias contactModel: repeater.model - property var textStyle: Style.text.normal_inverse - property var titleTextStyle: Style.text.title_inverse - - Accessible.description: qsTr("Contact information of the selected provider.") - Accessible.focusable: true - Accessible.name: qsTr("Provider contact information") - Accessible.role: Accessible.Grouping - implicitHeight: layout.implicitHeight - implicitWidth: layout.implicitWidth - - ColumnLayout { - id: layout - anchors.fill: parent - spacing: Constants.text_spacing - - GText { - Layout.bottomMargin: Constants.groupbox_spacing - - //: LABEL DESKTOP - text: qsTr("Contact") - textStyle: baseItem.titleTextStyle - - FocusFrame { - isOnLightBackground: false - scope: baseItem - } - } - Repeater { - id: repeater - Item { - readonly property bool showSeparator: index !== 0 - - Layout.fillHeight: true - Layout.fillWidth: true - Layout.maximumHeight: contactItem.implicitHeight + (showSeparator ? layout.spacing : 0) - Layout.preferredHeight: contactItem.implicitHeight + (showSeparator ? layout.spacing : 0) - - GSeparator { - color: baseItem.textStyle.textColor - visible: showSeparator - - anchors { - left: parent.left - right: parent.right - } - } - ProviderContactInfoItem { - id: contactItem - //: LABEL DESKTOP - accessibleText: (!!model.accessibleText ? model.accessibleText : qsTr("Unknown")) - imageSource: Qt.resolvedUrl(model.iconSource) - //: LABEL DESKTOP - itemText: (!!model.text ? model.text : qsTr("Unknown")) - label: qsTranslate("ProviderModelItem", model.label) - link: model.link - textStyle: baseItem.textStyle - - anchors { - fill: parent - topMargin: showSeparator ? layout.spacing : 0 - } - } - } - } - GSpacer { - Layout.fillHeight: true - } - } -} diff --git a/resources/qml/Governikus/Provider/ProviderContactInfoItem.qml b/resources/qml/Governikus/Provider/ProviderContactInfoItem.qml deleted file mode 100644 index 04e4924cf..000000000 --- a/resources/qml/Governikus/Provider/ProviderContactInfoItem.qml +++ /dev/null @@ -1,59 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Style 1.0 -import Governikus.View 1.0 - -Item { - id: baseItem - - property string accessibleText - property alias imageSource: image.source - property alias itemText: text.text - property string label - property url link - property alias textStyle: text.textStyle - - Accessible.name: label + " . " + accessibleText - Accessible.role: Accessible.ListItem - activeFocusOnTab: true - implicitHeight: Math.max(image.implicitHeight, text.implicitHeight) - implicitWidth: image.implicitWidth + text.implicitWidth + Constants.groupbox_spacing - - Keys.onSpacePressed: Qt.openUrlExternally(link) - - TintableIcon { - id: image - sourceSize.height: Constants.is_desktop ? Style.dimens.icon_size : Style.dimens.small_icon_size - tintColor: text.textStyle.textColor - - anchors { - left: parent.left - verticalCenter: parent.verticalCenter - } - } - GText { - id: text - Accessible.ignored: true - elide: Text.ElideRight - fontSizeMode: Text.Fit - linkColor: color - minimumPixelSize: Style.dimens.hint_font_size - verticalAlignment: Text.AlignVCenter - - anchors { - bottom: parent.bottom - left: image.right - leftMargin: Constants.groupbox_spacing - right: parent.right - top: parent.top - } - } - FocusFrame { - isOnLightBackground: false - } -} diff --git a/resources/qml/Governikus/Provider/ProviderModelItem.qml b/resources/qml/Governikus/Provider/ProviderModelItem.qml deleted file mode 100644 index 30c6a5550..000000000 --- a/resources/qml/Governikus/Provider/ProviderModelItem.qml +++ /dev/null @@ -1,120 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Type.ApplicationModel 1.0 - -/* - * Convenience utility to access properties of a ProviderModel item - * This ensures having always a defined string, i.e. a non-null string object. - */ -Item { - id: baseItem - - readonly property string address: !!modelItem && !!modelItem.providerAddress ? modelItem.providerAddress : "" - readonly property string addressDomain: !!modelItem && !!modelItem.providerAddressDomain ? modelItem.providerAddressDomain : "" - readonly property string category: !!modelItem && !!modelItem.providerCategory ? modelItem.providerCategory : "" - readonly property ListModel contactModel: ListModel { - readonly property alias email: baseItem.email - readonly property alias homepage: baseItem.homepage - readonly property alias homepageBase: baseItem.homepageBase - readonly property alias phone: baseItem.phone - readonly property alias phoneCost: baseItem.phoneCost - readonly property string phoneDisplayString: { - var s = ""; - if (!!phone) { - s = '' + phone + ""; - if (!!phoneCost) { - s += "
" + phoneCost; - } - } - return s; - } - readonly property alias postalAddress: baseItem.postalAddress - - function updateHomepage() { - setProperty(0, "text", !!homepage ? '' + homepageBase + "" : ""); - setProperty(0, "accessibleText", !!homepageBase ? - //: INFO ALL_PLATFORMS A11y action text appended to provider homepage to be read read by screen reader. - homepageBase + " . " + qsTr("Click to open homepage.") : ""); - setProperty(0, "link", homepage); - } - - onEmailChanged: { - setProperty(1, "text", !!email ? '' + email + "" : ""); - setProperty(1, "accessibleText", email ? - //: INFO ALL_PLATFORMS A11y action text appended to provider mail to be read read by screen reader. - email + " . " + qsTr("Click to send email.") : ""); - setProperty(1, "link", !!email ? "mailto:" + email : ""); - } - onHomepageBaseChanged: updateHomepage() - onHomepageChanged: updateHomepage() - onPhoneDisplayStringChanged: { - setProperty(2, "text", phoneDisplayString); - //: LABEL DESKTOP - var coststring = !!phoneCost ? ", " + qsTr("Costs") + ": " + phoneCost : ""; - setProperty(2, "accessibleText", !!phone ? - //: INFO ALL_PLATFORMS A11y action text appended to provider phone number to be read read by screen reader. - phone + coststring + " . " + qsTr("Click to call.") : ""); - setProperty(2, "link", !!phone ? "tel:" + phone : ""); - } - onPostalAddressChanged: { - var dest; - if (Qt.platform.os === "android") { - dest = 'geo:0,0?q='; - } else if (Qt.platform.os === "ios") { - dest = 'maps:0,0?q='; - } else { - dest = 'https://www.google.com/maps?q='; - } - let nonHtmlAddress = !!postalAddress ? postalAddress.replace(//gi, ", ") : ""; - dest = !!nonHtmlAddress ? dest + encodeURIComponent(nonHtmlAddress) : ""; - setProperty(3, "text", !!postalAddress ? '' + postalAddress + "" : ""); - setProperty(3, "accessibleText", !!nonHtmlAddress ? - //: INFO ALL_PLATFORMS A11y action text appended to provider address maps url to be read read by screen reader. - nonHtmlAddress + " . " + qsTr("Click to open map.") : ""); - setProperty(3, "link", dest); - } - - ListElement { - accessibleText: "" - iconSource: "qrc:///images/material_open_in_new.svg" - label: QT_TR_NOOP("Homepage") - link: "" - text: "" - } - ListElement { - accessibleText: "" - iconSource: "qrc:///images/material_mail.svg" - label: QT_TR_NOOP("E-Mail") - link: "" - text: "" - } - ListElement { - accessibleText: "" - iconSource: "qrc:///images/material_phone.svg" - label: QT_TR_NOOP("Phone") - link: "" - text: "" - } - ListElement { - accessibleText: "" - iconSource: "qrc:///images/material_location.svg" - label: QT_TR_NOOP("Address") - link: "" - text: "" - } - } - readonly property string email: !!modelItem && !!modelItem.providerEmail ? modelItem.providerEmail : "" - readonly property string homepage: !!modelItem && !!modelItem.providerHomepage ? modelItem.providerHomepage : "" - readonly property string homepageBase: !!modelItem && !!modelItem.providerHomepageBase ? modelItem.providerHomepageBase : "" - readonly property string icon: !!modelItem && !!modelItem.providerIcon ? modelItem.providerIcon : "" - readonly property string image: !!modelItem && !!modelItem.providerImage ? modelItem.providerImage : "" - readonly property string longDescription: !!modelItem && !!modelItem.providerLongDescription ? modelItem.providerLongDescription : "" - readonly property string longName: !!modelItem && !!modelItem.providerLongName ? modelItem.providerLongName : "" - property var modelItem - readonly property string phone: !!modelItem && !!modelItem.providerPhone ? modelItem.providerPhone : "" - readonly property string phoneCost: !!modelItem && !!modelItem.providerPhoneCost ? modelItem.providerPhoneCost : "" - readonly property string postalAddress: !!modelItem && !!modelItem.providerPostalAddress ? modelItem.providerPostalAddress : "" - readonly property string shortName: !!modelItem && !!modelItem.providerShortName ? modelItem.providerShortName : "" -} diff --git a/resources/qml/Governikus/Provider/qmldir b/resources/qml/Governikus/Provider/qmldir deleted file mode 100644 index 60cb74aca..000000000 --- a/resources/qml/Governikus/Provider/qmldir +++ /dev/null @@ -1,15 +0,0 @@ -module ProviderInfo - -internal ProviderContactInfo ProviderContactInfo.qml -internal ProviderContactInfoItem ProviderContactInfoItem.qml -internal ProviderDetailButtonBar ProviderDetailButtonBar.qml -internal ProviderDetailDescription ProviderDetailDescription.qml -internal ProviderDetailHistory ProviderDetailHistory.qml -internal ProviderDetailHistoryInfo ProviderDetailHistoryInfo.qml -internal ProviderDetailHistoryItem ProviderDetailHistoryItem.qml - -ProviderDetailView 1.0 ProviderDetailView.qml -ProviderHeader 1.0 ProviderHeader.qml -ProviderInfoSection 1.0 ProviderInfoSection.qml -ProviderModelItem 1.0 ProviderModelItem.qml -ProviderViewDelegate 1.0 ProviderViewDelegate.qml diff --git a/resources/qml/Governikus/ProviderView/+desktop/ProviderOverview.qml b/resources/qml/Governikus/ProviderView/+desktop/ProviderOverview.qml deleted file mode 100644 index 6a4e0aa71..000000000 --- a/resources/qml/Governikus/ProviderView/+desktop/ProviderOverview.qml +++ /dev/null @@ -1,81 +0,0 @@ -/** - * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Provider 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 -import Governikus.Type.ProviderCategoryFilterModel 1.0 -import Governikus.Type.ApplicationModel 1.0 - -SectionPage { - id: baseItem - signal showDetailView(var pModelItem) - - Component.onCompleted: { - ProviderCategoryFilterModel.setCategorySelection("all"); - ProviderCategoryFilterModel.searchString = ""; - tabbedPane.currentIndex = 0; - } - - TabbedPane { - id: tabbedPane - anchors.fill: parent - anchors.margins: Constants.pane_padding - contentDelegate: content - contentPadding: 0 - sectionsModel: [{ - //: LABEL DESKTOP - "categoryName": qsTr("All provider"), - "category": "all" - }, { - //: LABEL DESKTOP - "categoryName": qsTr("Citizen services"), - "category": "citizen" - }, { - //: LABEL DESKTOP - "categoryName": qsTr("Financials"), - "category": "finance" - }, { - //: LABEL DESKTOP - "categoryName": qsTr("Insurances"), - "category": "insurance" - }, { - //: LABEL DESKTOP - "categoryName": qsTr("Other services"), - "category": "other" - }] - - sectionDelegate: TabbedPaneDelegateIconAndText { - iconPath: Category.buttonImageSource(model.modelData.category) - sectionName: model.modelData.categoryName - } - - onCurrentItemModelChanged: { - if (currentItemModel === null) { - return; - } - ProviderCategoryFilterModel.setCategorySelection(currentItemModel.modelData.category); - } - - Component { - id: content - ProviderGridView { - height: tabbedPane.availableHeight - width: parent.width - - onShowAdditionalResults: { - ProviderCategoryFilterModel.setCategorySelection("all"); - tabbedPane.currentIndex = 0; - } - onShowDetails: pModelItem => { - baseItem.showDetailView(pModelItem); - } - } - } - } -} diff --git a/resources/qml/Governikus/ProviderView/+desktop/ProviderView.qml b/resources/qml/Governikus/ProviderView/+desktop/ProviderView.qml deleted file mode 100644 index 0607f503e..000000000 --- a/resources/qml/Governikus/ProviderView/+desktop/ProviderView.qml +++ /dev/null @@ -1,78 +0,0 @@ -/** - * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Provider 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 -import Governikus.Type.ProviderCategoryFilterModel 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.HistoryModel 1.0 - -SectionPage { - id: baseItem - enum SubViews { - None, - Detail - } - - isAbstract: true - - titleBarAction: TitleBarAction { - helpTopic: "provider" - //: LABEL DESKTOP - text: qsTr("Provider") - - customSubAction: SearchBar { - anchors.verticalCenter: parent ? parent.verticalCenter : undefined - - //: LABEL DESKTOP - placeholderText: qsTr("Search providers") - - onDisplayTextChanged: ProviderCategoryFilterModel.searchString = displayText - } - - onClicked: { - d.activeView = ProviderView.SubViews.None; - } - } - - Keys.onEscapePressed: event => { - if (d.activeView === ProviderView.SubViews.None) { - event.accepted = false; - return; - } - d.activeView = ProviderView.SubViews.None; - } - - QtObject { - id: d - - property int activeView: ProviderView.SubViews.None - } - ProviderDetailView { - id: detailView - visible: d.activeView === ProviderView.SubViews.Detail - - onNextView: pName => { - d.activeView = ProviderView.SubViews.None; - baseItem.nextView(pName); - } - } - ProviderOverview { - id: overviewView - visible: d.activeView === ProviderView.SubViews.None - - Component.onCompleted: setActive() - onNextView: pName => { - baseItem.nextView(pName); - } - onShowDetailView: pModelItem => { - HistoryModel.nameFilter.setProviderAddress(pModelItem.providerAddress); - detailView.providerModelItem = pModelItem; - d.activeView = ProviderView.SubViews.Detail; - } - } -} diff --git a/resources/qml/Governikus/ProviderView/+mobile/+android/+phone/ProviderView.qml b/resources/qml/Governikus/ProviderView/+mobile/+android/+phone/ProviderView.qml deleted file mode 100644 index 3dcf783a8..000000000 --- a/resources/qml/Governikus/ProviderView/+mobile/+android/+phone/ProviderView.qml +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.View 1.0 -import Governikus.Type.ProviderCategoryFilterModel 1.0 -import Governikus.Provider 1.0 - -BaseProviderView { - id: baseItem - contentBehindTitlebar: true - rightTitleBarAction: searchBar - titleBarOpacity: headerItem.titleBarOpacity - - headerComponent: Component { - ProviderHeader { - selectedCategory: baseItem.category - width: baseItem.width - - onCategorySelected: ProviderCategoryFilterModel.setCategorySelection(category) - } - } - searchBar: SearchBar { - availableWidth: baseItem.width - Style.dimens.menubar_width - } -} diff --git a/resources/qml/Governikus/ProviderView/+mobile/+android/+tablet/ProviderView.qml b/resources/qml/Governikus/ProviderView/+mobile/+android/+tablet/ProviderView.qml deleted file mode 100644 index 263603107..000000000 --- a/resources/qml/Governikus/ProviderView/+mobile/+android/+tablet/ProviderView.qml +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.Type.ProviderCategoryFilterModel 1.0 - -BaseProviderView { - id: baseItem - rightTitleBarAction: SearchBar { - availableWidth: baseItem.width - Style.dimens.menubar_width - - onSearchTextChanged: ProviderCategoryFilterModel.searchString = searchText - } -} diff --git a/resources/qml/Governikus/ProviderView/+mobile/+ios/+phone/ProviderView.qml b/resources/qml/Governikus/ProviderView/+mobile/+ios/+phone/ProviderView.qml deleted file mode 100644 index a422feb7b..000000000 --- a/resources/qml/Governikus/ProviderView/+mobile/+ios/+phone/ProviderView.qml +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.View 1.0 - -BaseProviderView { - id: baseItem - additionalProviderListTopPadding: searchBarHeader.height - searchBar: providerSearchBar - - Rectangle { - id: searchBarHeader - - readonly property var menuBar: ApplicationWindow.menuBar - - color: menuBar && menuBar.color ? menuBar.color : titleBarColor - height: providerSearchBar.height - width: baseItem.width - - Behavior on color { - ColorAnimation { - duration: Constants.animation_duration - } - } - - SearchBar { - id: providerSearchBar - width: parent.width - } - } -} diff --git a/resources/qml/Governikus/ProviderView/+mobile/+ios/+tablet/ProviderView.qml b/resources/qml/Governikus/ProviderView/+mobile/+ios/+tablet/ProviderView.qml deleted file mode 100644 index 3441f6a4e..000000000 --- a/resources/qml/Governikus/ProviderView/+mobile/+ios/+tablet/ProviderView.qml +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Type.ProviderCategoryFilterModel 1.0 - -BaseProviderView { - id: baseItem - additionalProviderListTopPadding: searchBarHeader.height - - Rectangle { - id: searchBarHeader - - readonly property var menuBar: ApplicationWindow.menuBar - - color: menuBar && menuBar.color ? menuBar.color : titleBarColor - height: providerSearchBar.height - width: baseItem.width - - Behavior on color { - ColorAnimation { - duration: Constants.animation_duration - } - } - - SearchBar { - id: providerSearchBar - width: parent.width - - onSearchTextChanged: ProviderCategoryFilterModel.searchString = searchText - } - } -} diff --git a/resources/qml/Governikus/ProviderView/+mobile/+phone/AdditionalResultsItem.qml b/resources/qml/Governikus/ProviderView/+mobile/+phone/AdditionalResultsItem.qml deleted file mode 100644 index 1f9fca024..000000000 --- a/resources/qml/Governikus/ProviderView/+mobile/+phone/AdditionalResultsItem.qml +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 - -ListItem { - property int totalHits: 0 - - Accessible.description: qsTr("Click to remove category filter and show additional results.") - Accessible.name: qsTr("%1 additional results in other categories").arg(totalHits) - icon: Category.imageSource("all") - showLinkIcon: false - showSeparator: false - text: qsTr("Additional results:") + ' ' + totalHits -} diff --git a/resources/qml/Governikus/ProviderView/+mobile/+phone/BaseProviderView.qml b/resources/qml/Governikus/ProviderView/+mobile/+phone/BaseProviderView.qml deleted file mode 100644 index c6ce793af..000000000 --- a/resources/qml/Governikus/ProviderView/+mobile/+phone/BaseProviderView.qml +++ /dev/null @@ -1,116 +0,0 @@ -/** - * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Provider 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 -import Governikus.Type.ProviderCategoryFilterModel 1.0 -import Governikus.Type.UiModule 1.0 - -SectionPage { - id: baseItem - - property real additionalProviderListTopPadding: 0 - readonly property bool additionalResultsItemVisible: ProviderCategoryFilterModel.additionalResultCount > 0 && ProviderCategoryFilterModel.categories.length > 0 && ProviderCategoryFilterModel.categories.indexOf("all") === -1 - readonly property string category: ProviderCategoryFilterModel.categories.length === 0 ? "" : ProviderCategoryFilterModel.categories[0] - property var headerComponent: null - property alias headerItem: providerList.headerItem - property var searchBar - readonly property bool showCategories: category === "" - - sectionPageFlickable: providerList - title: Category.displayString(category) - titleBarColor: Category.displayColor(category) - - navigationAction: NavigationAction { - action: category !== "" ? NavigationAction.Action.Back : NavigationAction.Action.None - - onClicked: { - if (category !== "") { - ProviderCategoryFilterModel.setCategorySelection(""); - } else if (Qt.platform.os !== "osx") { - reset(); - show(UiModule.DEFAULT); - } - } - } - - onCategoryChanged: highlightScrollbar() - onReset: { - ProviderCategoryFilterModel.setCategorySelection(""); - searchBar.reset(); - } - onShowCategoriesChanged: { - ProviderCategoryFilterModel.setIncludeCategoriesInModel(showCategories); - ProviderCategoryFilterModel.sortByCategoryFirst(showCategories); - } - - Connections { - function onSearchStringChanged() { - sectionPageFlickable.positionViewAtBeginning(); - } - - target: ProviderCategoryFilterModel - } - Connections { - function onSearchTextChanged() { - ProviderCategoryFilterModel.searchString = searchBar.searchText; - } - - target: searchBar - } - Component { - id: providerDetailView - ProviderDetailView { - } - } - GText { - anchors.centerIn: parent - //: LABEL IOS_PHONE ANDROID_PHONE The text entered into the provider search field results in no matches - text: qsTr("No results matching your search query found") - visible: ProviderCategoryFilterModel.rowCount === 0 && ProviderCategoryFilterModel.additionalResultCount === 0 - } - GListView { - id: providerList - Accessible.role: Accessible.List - anchors.bottom: parent.bottom - header: headerComponent - height: contentBehindTitlebar ? (parent.height + Style.dimens.titlebar_height) : (parent.height - additionalProviderListTopPadding) - model: ProviderCategoryFilterModel - scrollBarTopPadding: contentBehindTitlebar ? Style.dimens.titlebar_height : 0 - width: parent.width - - delegate: ProviderListItemDelegate { - showSeparator: index < providerList.count - 1 || additionalResultsItemVisible - - Accessible.onScrollDownAction: providerList.scrollPageDown() - Accessible.onScrollUpAction: providerList.scrollPageUp() - onClicked: isProvider ? push(providerDetailView, { - "providerModelItem": model - }) : ProviderCategoryFilterModel.setCategorySelection(providerCategory) - } - footer: Component { - Item { - height: additionalResults.height + separator.height - width: parent.width - - AdditionalResultsItem { - id: additionalResults - height: visible ? Style.dimens.list_item_height : 0 - totalHits: ProviderCategoryFilterModel.additionalResultCount - visible: additionalResultsItemVisible - - onClicked: ProviderCategoryFilterModel.setCategorySelection("") - } - GSeparator { - id: separator - anchors.top: additionalResults.bottom - width: parent.width - } - } - } - } -} diff --git a/resources/qml/Governikus/ProviderView/+mobile/+phone/ProviderListItemDelegate.qml b/resources/qml/Governikus/ProviderView/+mobile/+phone/ProviderListItemDelegate.qml deleted file mode 100644 index c70d02f62..000000000 --- a/resources/qml/Governikus/ProviderView/+mobile/+phone/ProviderListItemDelegate.qml +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Type.ProviderCategoryFilterModel 1.0 - -ListItem { - readonly property bool isProvider: itemType === "provider" - readonly property string providerDisplayName: !!display ? display : "" - - Accessible.description: (isProvider ? qsTr("Open provider details for %1").arg(display) : qsTr("Click to set category filter to %1").arg(text)) - icon: isProvider ? "" : Category.imageSource(providerCategory) - text: (isProvider ? providerDisplayName : Category.displayString(providerCategory)) -} diff --git a/resources/qml/Governikus/ProviderView/+mobile/+tablet/BaseProviderView.qml b/resources/qml/Governikus/ProviderView/+mobile/+tablet/BaseProviderView.qml deleted file mode 100644 index f401a015f..000000000 --- a/resources/qml/Governikus/ProviderView/+mobile/+tablet/BaseProviderView.qml +++ /dev/null @@ -1,123 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Provider 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 -import Governikus.Type.HistoryModel 1.0 -import Governikus.Type.SettingsModel 1.0 -import Governikus.Type.ProviderCategoryFilterModel 1.0 -import Governikus.Type.UiModule 1.0 - -SectionPage { - id: baseItem - - property real additionalProviderListTopPadding: 0 - readonly property int headerHeight: 54 - readonly property int separatorHeight: 2 - property bool wasVisible: false - - function pushProviderDetails(pModel) { - HistoryModel.nameFilter.setProviderAddress(pModel.providerAddress); - push(providerDetailView, { - "providerModelItem": pModel - }); - } - - //: LABEL IOS_TABLET ANDROID_TABLET - title: qsTr("Provider") - titleBarColor: Style.color.accent - visible: false - - navigationAction: NavigationAction { - action: NavigationAction.Action.Back - - onClicked: { - baseItem.reset(); - show(UiModule.DEFAULT); - } - } - - onReset: { - ProviderCategoryFilterModel.setCategorySelection(""); - if (rightTitleBarAction) - rightTitleBarAction.reset(); - } - onVisibleChanged: wasVisible = true - - Component { - id: providerDetailView - ProviderDetailView { - } - } - Column { - id: content - anchors { - fill: parent - topMargin: additionalProviderListTopPadding - } - Rectangle { - color: Constants.white - height: baseItem.headerHeight - width: parent.width - z: 1 - - Row { - id: checkBoxesItem - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.verticalCenter - height: parent.height - padding: 30 - scale: Math.min(parent.width / width, 1) - spacing: 30 - transformOrigin: Item.Center - - CategoryCheckbox { - id: checkBoxCitizen - category: "citizen" - imageSource: Category.imageSource("citizen") - //: LABEL IOS_TABLET ANDROID_TABLET - text: qsTr("Citizen services") - } - CategoryCheckbox { - id: checkBoxFinance - category: "finance" - imageSource: Category.imageSource("finance") - //: LABEL IOS_TABLET ANDROID_TABLET - text: qsTr("Financials") - } - CategoryCheckbox { - id: checkBoxInsurance - category: "insurance" - imageSource: Category.imageSource("insurance") - //: LABEL IOS_TABLET ANDROID_TABLET - text: qsTr("Insurances") - } - CategoryCheckbox { - id: checkBoxOther - category: "other" - imageSource: Category.imageSource("other") - //: LABEL IOS_TABLET ANDROID_TABLET - text: qsTr("Other services") - } - } - } - GSeparator { - width: parent.width - z: 1 - } - ProviderGridView { - anchors.horizontalCenter: parent.horizontalCenter - height: baseItem.height - (baseItem.headerHeight + baseItem.separatorHeight) - additionalProviderListTopPadding - width: parent.width - - onShowAdditionalResults: ProviderCategoryFilterModel.addAdditionalResultCategories() - onShowDetails: pModelItem => { - baseItem.pushProviderDetails(pModelItem); - } - } - } -} diff --git a/resources/qml/Governikus/ProviderView/+mobile/+tablet/CategoryCheckbox.qml b/resources/qml/Governikus/ProviderView/+mobile/+tablet/CategoryCheckbox.qml deleted file mode 100644 index 04fdd04ca..000000000 --- a/resources/qml/Governikus/ProviderView/+mobile/+tablet/CategoryCheckbox.qml +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.ProviderCategoryFilterModel 1.0 - -Item { - id: baseItem - - property string category: "" - property alias imageSource: icon.source - property alias text: label.text - - Accessible.checkable: true - Accessible.checked: checkBox.checked - Accessible.name: text - Accessible.role: Accessible.CheckBox - anchors.verticalCenter: parent.verticalCenter - height: parent.height - width: mainContent.width - - Accessible.onPressAction: mouseArea.clicked(null) - - Row { - id: mainContent - anchors.verticalCenter: parent.verticalCenter - height: parent.height - spacing: 5 - - Image { - id: icon - anchors.verticalCenter: parent.verticalCenter - fillMode: Image.PreserveAspectFit - height: baseItem.height * 0.7 - width: height - } - GText { - id: label - Accessible.ignored: true - anchors.verticalCenter: parent.verticalCenter - } - GCheckBox { - id: checkBox - Accessible.ignored: true - anchors.verticalCenter: parent.verticalCenter - checked: ProviderCategoryFilterModel.categories.indexOf(baseItem.category) !== -1 - visible: true - } - } - MouseArea { - id: mouseArea - anchors.fill: parent - - onClicked: ProviderCategoryFilterModel.updateCategorySelection(category, !checkBox.checked) - } -} diff --git a/resources/qml/Governikus/ProviderView/AdditionalResultsFooterItem.qml b/resources/qml/Governikus/ProviderView/AdditionalResultsFooterItem.qml deleted file mode 100644 index 4a2320ee4..000000000 --- a/resources/qml/Governikus/ProviderView/AdditionalResultsFooterItem.qml +++ /dev/null @@ -1,70 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.SettingsModel 1.0 -import Governikus.Type.ProviderCategoryFilterModel 1.0 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 - -Item { - id: baseItem - - property int totalHits: ProviderCategoryFilterModel.additionalResultCount - - signal clicked - - Accessible.name: qsTr("Additional results in other categories: %1. Click here to remove filter.").arg(totalHits) - Accessible.role: Accessible.Button - implicitHeight: row.implicitHeight + 2 * Constants.groupbox_spacing - - Keys.onSpacePressed: mouseArea.clicked(undefined) - - Rectangle { - id: background - anchors.fill: parent - color: Category.displayColor("all") - radius: Style.dimens.corner_radius - } - RowLayout { - id: row - anchors.fill: parent - anchors.margins: Constants.groupbox_spacing - spacing: Constants.groupbox_spacing - - Image { - id: icon - asynchronous: true - fillMode: Image.PreserveAspectFit - source: Category.imageSource("all") - sourceSize.height: Style.dimens.medium_icon_size - sourceSize.width: Style.dimens.medium_icon_size - } - GText { - id: nameText - Layout.fillWidth: true - - //: LABEL DESKTOP IOS_TABLET ANDROID_TABLET - text: qsTr("Additional results in other categories:") + " " + baseItem.totalHits - textStyle: Style.text.normal_inverse - verticalAlignment: Text.AlignVCenter - } - GText { - padding: Constants.text_spacing - text: qsTr("Show") - textStyle: Style.text.normal_inverse - } - } - MouseArea { - id: mouseArea - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - - onClicked: baseItem.clicked() - } - FocusFrame { - } -} diff --git a/resources/qml/Governikus/ProviderView/ProviderCard.qml b/resources/qml/Governikus/ProviderView/ProviderCard.qml deleted file mode 100644 index b95c1a854..000000000 --- a/resources/qml/Governikus/ProviderView/ProviderCard.qml +++ /dev/null @@ -1,114 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Window 2.10 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Provider 1.0 -import Governikus.Type.SettingsModel 1.0 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 - -Item { - id: baseItem - - property alias providerModelItem: provider.modelItem - - signal showDetailView(var pModelItem) - - Accessible.name: nameText.text - Accessible.role: Accessible.Button - height: Math.floor(width * 0.84) // Set a fixed aspect ratio which best fits the view - - Keys.onSpacePressed: mouseArea.clicked(undefined) - - ProviderModelItem { - id: provider - } - Column { - id: column - width: baseItem.width - - Image { - id: image - asynchronous: true - fillMode: Image.PreserveAspectFit - height: Math.floor(baseItem.width * 0.56) // Image aspect ratio 16:9 - layer.enabled: GraphicsInfo.api !== GraphicsInfo.Software - mipmap: true - source: provider.image - // Set a fixed size for width and height, so it doesn't have to resize the source when the window size changes -> way faster - sourceSize.width: Screen.devicePixelRatio * 512 - width: baseItem.width - - layer.effect: ShaderEffect { - property var maskSource: ShaderEffectSource { - height: image.height - width: image.width - - sourceItem: RoundedRectangle { - bottomLeftCorner: false - bottomRightCorner: false - height: image.height - radius: Style.dimens.corner_radius - width: image.width - } - } - - fragmentShader: "qrc:/shader/OpacityMaskShader.frag" - } - } - Rectangle { - color: Style.color.background_pane - height: Math.floor(baseItem.width * 0.2) - width: baseItem.width - - GText { - id: nameText - anchors.fill: parent - anchors.leftMargin: Constants.text_spacing - anchors.rightMargin: Constants.text_spacing - elide: Text.ElideRight - horizontalAlignment: Text.AlignHCenter - maximumLineCount: 2 - text: provider.longName - textStyle: Style.text.normal - verticalAlignment: Text.AlignVCenter - } - } - RoundedRectangle { - color: Style.currentTheme.highContrast ? Style.color.background_pane : Category.displayColor(provider.category) - height: Math.floor(baseItem.width * 0.08) - radius: Style.dimens.corner_radius - topLeftCorner: false - topRightCorner: false - width: baseItem.width - - GSeparator { - color: Style.color.high_contrast_item_border - height: Style.dimens.high_contrast_item_border - - anchors { - left: parent.left - right: parent.right - top: parent.top - } - } - } - } - RoundedRectangle { - anchors.fill: column - borderColor: Style.color.border - borderWidth: ApplicationModel.scaleFactor * 1 - color: Style.color.transparent - } - MouseArea { - id: mouseArea - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - - onClicked: baseItem.showDetailView(providerModelItem) - } -} diff --git a/resources/qml/Governikus/ProviderView/ProviderGridView.qml b/resources/qml/Governikus/ProviderView/ProviderGridView.qml deleted file mode 100644 index 4efb23dd8..000000000 --- a/resources/qml/Governikus/ProviderView/ProviderGridView.qml +++ /dev/null @@ -1,107 +0,0 @@ -/** - * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Provider 1.0 -import Governikus.View 1.0 -import Governikus.Type.SettingsModel 1.0 -import Governikus.Type.ProviderCategoryFilterModel 1.0 -import Governikus.Type.ApplicationModel 1.0 - -Item { - id: baseItem - signal showAdditionalResults - signal showDetails(var pModelItem) - - GGridView { - id: gridView - - property int columns: Math.floor(width / (ApplicationModel.scaleFactor * 400)) - property bool hasResults: gridView.count > 0 || ProviderCategoryFilterModel.additionalResultCount > 0 - property real spacing: Constants.component_spacing - - activeFocusOnTab: true - cellHeight: Math.floor(cellWidth * 0.84) // Set aspect ratio from ProviderCard - cellWidth: Math.floor((width - spacing / 2) / columns) - displayMarginBeginning: spacing - displayMarginEnd: additionalResults.height + spacing - highlightFollowsCurrentItem: true - model: ProviderCategoryFilterModel - scrollBarBottomPadding: spacing / 2 - scrollBarTopPadding: spacing / 2 - - delegate: Item { - Accessible.name: card.Accessible.name - Accessible.role: card.Accessible.role - Keys.forwardTo: children - height: gridView.cellHeight - width: gridView.cellWidth - - ProviderCard { - id: card - anchors.fill: parent - anchors.margins: Math.floor(gridView.spacing / 2) - providerModelItem: model - - onShowDetailView: pModelItem => { - baseItem.showDetails(pModelItem); - } - } - } - highlight: Item { - FocusFrame { - marginFactor: -0.75 - radius: Style.dimens.corner_radius - scope: gridView - } - } - - anchors { - bottom: additionalResults.top - bottomMargin: Math.floor(spacing / 2) - left: parent.left - leftMargin: Math.floor(spacing / 2) - right: parent.right - top: parent.top - topMargin: Math.floor(spacing / 2) - } - Connections { - function onFireCriteriaChanged() { - gridView.currentIndex = 0; - gridView.contentY = gridView.originY; - } - - target: ProviderCategoryFilterModel - } - } - AdditionalResultsFooterItem { - id: additionalResults - activeFocusOnTab: true - height: visible ? implicitHeight : 0 - visible: ProviderCategoryFilterModel.additionalResultCount > 0 && ProviderCategoryFilterModel.categories.length > 0 && ProviderCategoryFilterModel.categories.indexOf("all") === -1 - width: gridView.columns * gridView.cellWidth - - onClicked: baseItem.showAdditionalResults() - - anchors { - bottom: parent.bottom - bottomMargin: visible ? gridView.spacing : 0 - left: parent.left - leftMargin: Math.floor(gridView.spacing * 2) - right: parent.right - rightMargin: Math.floor(gridView.spacing * 2) - topMargin: visible ? gridView.spacing : 0 - } - } - GText { - anchors.centerIn: parent - //: LABEL DESKTOP IOS_TABLET ANDROID_TABLET The text entered into the provider search field results in no matches - text: qsTr("No results matching your search query found") - textStyle: Style.text.normal - visible: ProviderCategoryFilterModel.rowCount === 0 && !additionalResults.visible - } -} diff --git a/resources/qml/Governikus/ProviderView/qmldir b/resources/qml/Governikus/ProviderView/qmldir deleted file mode 100644 index b88122f8e..000000000 --- a/resources/qml/Governikus/ProviderView/qmldir +++ /dev/null @@ -1,15 +0,0 @@ -module ProviderView - -internal AdditionalResultsFooterItem AdditionalResultsFooterItem.qml -internal AdditionalResultsItem AdditionalResultsItem.qml -internal BaseProviderView BaseProviderView.qml -internal CategoryCheckbox CategoryCheckbox.qml -internal ProviderCard ProviderCard.qml -internal ProviderCardNameRow ProviderCardNameRow.qml -internal ProviderContactInfoItem ProviderContactInfoItem.qml -internal ProviderGridView ProviderGridView.qml -internal ProviderListItemDelegate ProviderListItemDelegate.qml -internal ProviderOverview ProviderOverview.qml -internal ProviderSectionDelegate ProviderSectionDelegate.qml - -ProviderView 1.0 ProviderView.qml diff --git a/resources/qml/Governikus/RemoteServiceView/+mobile/DevicesListDelegate.qml b/resources/qml/Governikus/RemoteServiceView/+mobile/DevicesListDelegate.qml index 9030c3fb1..c80fa867b 100644 --- a/resources/qml/Governikus/RemoteServiceView/+mobile/DevicesListDelegate.qml +++ b/resources/qml/Governikus/RemoteServiceView/+mobile/DevicesListDelegate.qml @@ -1,17 +1,17 @@ /** * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style MouseArea { id: root property alias description: descriptionText.text - property bool highlightTitle: false + property alias highlightTitle: titleText.font.bold property alias linkInactive: linkQualityItem.inactive property alias linkQuality: linkQualityItem.percent property alias linkQualityVisible: linkQualityItem.visible @@ -26,6 +26,7 @@ MouseArea { RowLayout { id: content + anchors.fill: parent spacing: Constants.groupbox_spacing @@ -35,24 +36,27 @@ MouseArea { GText { id: titleText + Accessible.ignored: true - Layout.fillWidth: true elide: Text.ElideRight maximumLineCount: 1 - textStyle: root.highlightTitle ? Style.text.normal_accent_highlight : Style.text.normal_accent + textStyle: Style.text.subline } GText { id: descriptionText + Accessible.ignored: true - Layout.fillWidth: true elide: Text.ElideRight maximumLineCount: 1 - textStyle: Style.text.hint_secondary visible: text !== "" } } + GSpacer { + Layout.fillWidth: true + } LinkQuality { id: linkQualityItem + } } } diff --git a/resources/qml/Governikus/RemoteServiceView/+mobile/LocalNetworkInfo.qml b/resources/qml/Governikus/RemoteServiceView/+mobile/LocalNetworkInfo.qml index a8de0a7de..5b4faf64e 100644 --- a/resources/qml/Governikus/RemoteServiceView/+mobile/LocalNetworkInfo.qml +++ b/resources/qml/Governikus/RemoteServiceView/+mobile/LocalNetworkInfo.qml @@ -1,11 +1,11 @@ /** * Copyright (c) 2022-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import QtQuick.Controls +import Governikus.Type.ApplicationModel +import Governikus.Global +import Governikus.Style Column { spacing: Constants.text_spacing @@ -14,7 +14,6 @@ Column { horizontalAlignment: Text.AlignHCenter //: INFO IOS Let user know to check the application settings for local network permission text: qsTr("Ensure that access to the local network is allowed in your settings.") - textStyle: Style.text.normal_secondary width: parent.width } MoreInformationLink { @@ -22,7 +21,6 @@ Column { iconVisible: false //: INFO IOS Link to application settings text: qsTr("Go to application settings") - textStyle: Style.text.normal_accent onClicked: ApplicationModel.showSettings(ApplicationModel.SETTING_APP) } diff --git a/resources/qml/Governikus/RemoteServiceView/+mobile/PairingCodeInfoView.qml b/resources/qml/Governikus/RemoteServiceView/+mobile/PairingCodeInfoView.qml index a04e8b112..06578fbce 100644 --- a/resources/qml/Governikus/RemoteServiceView/+mobile/PairingCodeInfoView.qml +++ b/resources/qml/Governikus/RemoteServiceView/+mobile/PairingCodeInfoView.qml @@ -1,83 +1,73 @@ /** * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.TitleBar 1.0 -import Governikus.Style 1.0 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.TitleBar +import Governikus.Style +import Governikus.View +import Governikus.Type.ApplicationModel -SectionPage { - property alias text: description.text +FlickableSectionPage { + property alias text: descriptionContainer.title signal navActionClicked hiddenNavbarPadding: true + spacing: Constants.component_spacing //: LABEL ANDROID IOS title: qsTr("Pairing Information") - content: ColumnLayout { - anchors.left: parent.left - anchors.margins: Constants.pane_padding - anchors.right: parent.right - spacing: Constants.component_spacing + navigationAction: NavigationAction { + id: navAction - Image { - Layout.alignment: Qt.AlignHCenter - Layout.preferredHeight: Style.dimens.medium_icon_size - Layout.topMargin: Constants.pane_padding - fillMode: Image.PreserveAspectFit - source: "qrc:///images/phone_to_pc.svg" - sourceSize.height: Style.dimens.medium_icon_size - } - GText { - id: description - Layout.alignment: Qt.AlignCenter - Layout.topMargin: Constants.component_spacing - //: LABEL ANDROID IOS - textStyle: Style.text.header_accent - } - Repeater { - model: [ - //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 3 - qsTr("Open %1 on your %2other device%3.").arg(Qt.application.name).arg("").arg(""), - //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 3. %1 and %2 are surrounding tags for bold font. - qsTr("On that device go to %1Settings%2 and then %1Smartphone as card reader%2 resp. %1Manage pairings%2.").arg("").arg(""), - //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 3 - qsTr("Choose this smartphone in the list to pair it.")] + action: NavigationAction.Action.Back - RowLayout { - Layout.topMargin: Constants.component_spacing - spacing: Constants.text_spacing - width: parent.width + onClicked: navActionClicked() + } + + GOptionsContainer { + id: descriptionContainer + + containerPadding: Constants.pane_padding + + ColumnLayout { + spacing: Constants.component_spacing + width: parent.width + + TintableIcon { + Layout.alignment: Qt.AlignHCenter + Layout.maximumWidth: parent.width + Layout.preferredHeight: Style.dimens.medium_icon_size + fillMode: Image.PreserveAspectFit + source: "qrc:///images/phone_to_pc.svg" + sourceSize.height: Style.dimens.medium_icon_size + tintColor: Style.color.control + } + Repeater { + model: [ + //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 3 + qsTr("Open %1 on your %2other device%3.").arg(Qt.application.name).arg("").arg(""), + //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 3. %1 and %2 are surrounding tags for bold font. + qsTr("On that device go to %1Settings%2 and then %1Smartphone as card reader%2 resp. %1Manage pairings%2.").arg("").arg(""), + //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 3 + qsTr("Choose this smartphone in the list to pair it.")] GText { - Accessible.ignored: true - Layout.alignment: Qt.AlignTop - Layout.preferredWidth: Style.dimens.small_icon_size - text: (index + 1) + "." - } - GText { - Accessible.name: (index + 1) + ". " + ApplicationModel.stripHtmlTags(modelData) + Accessible.name: ApplicationModel.stripHtmlTags(text) Layout.alignment: Qt.AlignTop - Layout.fillWidth: true - text: modelData + text: (index + 1) + ". " + modelData } } } - RemoteServiceWifiInfo { - Layout.fillWidth: true - Layout.topMargin: Constants.component_spacing - } } - navigationAction: NavigationAction { - id: navAction - action: NavigationAction.Action.Back - - onClicked: navActionClicked() + GSpacer { + Layout.fillHeight: true + } + RemoteServiceWifiInfo { + Layout.fillWidth: true } } diff --git a/resources/qml/Governikus/RemoteServiceView/+mobile/PairingProcessInfo.qml b/resources/qml/Governikus/RemoteServiceView/+mobile/PairingProcessInfo.qml index ed089d9e0..ef2f177e4 100644 --- a/resources/qml/Governikus/RemoteServiceView/+mobile/PairingProcessInfo.qml +++ b/resources/qml/Governikus/RemoteServiceView/+mobile/PairingProcessInfo.qml @@ -1,17 +1,17 @@ /** * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.ApplicationModel 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.Type.ApplicationModel ColumnLayout { Repeater { model: [ //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 4. %1 is a placeholder-tag for the app name. - qsTr("Ensure that the %1 on your Smartphone as card reader has at least version %2.").arg(Qt.application.name).arg(Qt.application.version), + qsTr("Ensure that the %1 on your Smartphone as card reader has at least version %2.").arg(Qt.application.name).arg("1.26.5"), //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 4. %1 is a placeholder-tag for the app name. qsTr("Open %1 on your smartphone as card reader.").arg(Qt.application.name), //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 4. %1 and %2 are surrounding tags for bold font. @@ -19,23 +19,10 @@ ColumnLayout { //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 4 of 4 qsTr("Choose the smartphone in the list shown here to pair it.")] - RowLayout { - Layout.fillWidth: true - Layout.topMargin: Constants.component_spacing - spacing: Constants.text_spacing - - GText { - Accessible.ignored: true - Layout.alignment: Qt.AlignTop - Layout.preferredWidth: Style.dimens.small_icon_size - text: (index + 1) + "." - } - GText { - Accessible.name: (index + 1) + ". " + ApplicationModel.stripHtmlTags(modelData) - Layout.alignment: Qt.AlignTop - Layout.fillWidth: true - text: modelData - } + GText { + Accessible.name: ApplicationModel.stripHtmlTags(text) + Layout.alignment: Qt.AlignTop + text: (index + 1) + ". " + modelData } } } diff --git a/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceView.qml b/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceView.qml index 019c2077f..965dfefb6 100644 --- a/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceView.qml +++ b/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceView.qml @@ -1,20 +1,20 @@ /** * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.TitleBar 1.0 -import Governikus.Style 1.0 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.RemoteServiceModel 1.0 - -SectionPage { +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.TitleBar +import Governikus.Style +import Governikus.View +import Governikus.Type.ApplicationModel +import Governikus.Type.RemoteServiceModel + +FlickableSectionPage { id: baseItem + hiddenNavbarPadding: true - sectionPageFlickable: contentItem //: LABEL ANDROID IOS title: qsTr("Card reader") @@ -24,6 +24,38 @@ SectionPage { onClicked: RemoteServiceModel.setRunning(false) } + states: [ + State { + name: "PAIRING" + when: RemoteServiceModel.running && RemoteServiceModel.isPairing + + PropertyChanges { + target: knownDevicesContainer + visible: false + } + PropertyChanges { + target: pairingCode + visible: true + } + PropertyChanges { + target: paringCodeLink + visible: true + } + }, + State { + name: "CONNECTED_OR_STOPPED" + when: !RemoteServiceModel.running || (RemoteServiceModel.running && RemoteServiceModel.connectedToPairedDevice) + + PropertyChanges { + target: wifiInfo + visible: false + } + PropertyChanges { + target: networkPermissionText + visible: false + } + } + ] Connections { function onFireIsRunningChanged() { @@ -38,158 +70,162 @@ SectionPage { } RemoteServiceController { id: controller + + stackView: baseItem.stackView } - GFlickableColumnLayout { - id: contentItem - anchors.fill: parent - maximumContentWidth: Style.dimens.max_text_width - spacing: 0 + GOptionsContainer { + containerPadding: Constants.pane_padding + //: LABEL ANDROID IOS + title: !ApplicationModel.wifiEnabled ? qsTr("WiFi not active") : + //: LABEL ANDROID IOS + RemoteServiceModel.canEnableNfc ? qsTr("NFC not active") : + //: LABEL ANDROID IOS + !RemoteServiceModel.runnable ? qsTr("Remote service not available") : + //: LABEL ANDROID IOS + RemoteServiceModel.connectedToPairedDevice ? qsTr("Card access in progress") : + //: LABEL ANDROID IOS + RemoteServiceModel.isPairing ? qsTr("Waiting for pairing") : + //: LABEL ANDROID IOS + RemoteServiceModel.running ? qsTr("Waiting for connection") : "" - states: [ - State { - name: "PAIRING" - when: RemoteServiceModel.running && RemoteServiceModel.isPairing + ColumnLayout { + spacing: Constants.component_spacing + width: parent.width + + TintableIcon { + Layout.alignment: Qt.AlignHCenter + Layout.preferredHeight: Style.dimens.medium_icon_size + fillMode: Image.PreserveAspectFit + source: "qrc:///images/phone_to_pc.svg" + sourceSize.height: Style.dimens.medium_icon_size + tintColor: Style.color.control + } + GText { + id: infoText - PropertyChanges { - target: knownDevices - visible: false - } - PropertyChanges { - target: pairingCode - visible: true - } - PropertyChanges { - target: paringCodeLink - visible: true - } - }, - State { - name: "CONNECTED_OR_STOPPED" - when: !RemoteServiceModel.running || (RemoteServiceModel.running && RemoteServiceModel.connectedToPairedDevice) + readonly property string currentPin: RemoteServiceModel.psk + //: INFO ANDROID IOS + readonly property string enterCodeString: qsTr("Enter the pairing code %1 in the %2 on your other device.") - PropertyChanges { - target: wifiInfo - visible: false - } - PropertyChanges { - target: networkPermissionText - visible: false - } + Accessible.name: text + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: Constants.text_spacing + horizontalAlignment: Text.AlignHCenter + //: INFO ANDROID IOS + text: qsTr("You can use this Smartphone as a card reader for the %1 on other devices e.g. a laptop.\n\nTo do this you first have to pair that device with this smartphone.").arg(Qt.application.name) + textStyle: RemoteServiceModel.runnable ? Style.text.normal : Style.text.normal_warning + + states: [ + State { + when: !RemoteServiceModel.runnable && RemoteServiceModel.errorMessage !== "" + + PropertyChanges { + target: infoText + text: RemoteServiceModel.errorMessage + } + }, + State { + when: RemoteServiceModel.running && RemoteServiceModel.connectedToPairedDevice + + PropertyChanges { + target: infoText + text: RemoteServiceModel.connectionInfo + } + }, + State { + when: RemoteServiceModel.isPairing + + PropertyChanges { + Accessible.name: enterCodeString.arg(currentPin.split("").join(" ")).arg(Qt.application.name) + target: infoText + text: enterCodeString.arg(currentPin).arg(Qt.application.name) + } + }, + State { + when: !RemoteServiceModel.running && knownDeviceList.count > 0 + + PropertyChanges { + target: infoText + //: INFO ANDROID IOS + text: qsTr("Allow a connection with paired devices to use this Smartphone as a card reader or pair another device.") + } + }, + State { + when: RemoteServiceModel.running && knownDeviceList.count > 0 + + PropertyChanges { + target: infoText + //: INFO ANDROID IOS + text: qsTr("Paired devices may use this Smartphone as a card reader now.") + } + }, + State { + when: RemoteServiceModel.running + + PropertyChanges { + target: infoText + //: INFO ANDROID IOS + text: qsTr("Waiting for connection from a paired device...") + } + } + ] } - ] + GText { + id: pairingCode - Image { - Layout.alignment: Qt.AlignHCenter - Layout.maximumWidth: contentItem.effectiveContentWidth - Layout.preferredHeight: Style.dimens.medium_icon_size - fillMode: Image.PreserveAspectFit - source: "qrc:///images/phone_to_pc.svg" - sourceSize.height: Style.dimens.medium_icon_size - } - GText { - Layout.fillWidth: true - Layout.topMargin: Constants.component_spacing - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: !ApplicationModel.wifiEnabled ? qsTr("WiFi not active") : - //: LABEL ANDROID IOS - RemoteServiceModel.canEnableNfc ? qsTr("NFC not active") : - //: LABEL ANDROID IOS - !RemoteServiceModel.runnable ? qsTr("Remote service not available") : - //: LABEL ANDROID IOS - RemoteServiceModel.connectedToPairedDevice ? qsTr("Card access in progress") : - //: LABEL ANDROID IOS - RemoteServiceModel.isPairing ? qsTr("Waiting for pairing") : - //: LABEL ANDROID IOS - RemoteServiceModel.running ? qsTr("Waiting for connection") : "" - textStyle: Style.text.header_accent - } - GText { - id: infoText - - readonly property string currentPin: RemoteServiceModel.psk - //: INFO ANDROID IOS - readonly property string enterCodeString: qsTr("Enter the pairing code %1 in the %2 on your other device.") - - Accessible.name: text - Layout.fillWidth: true - Layout.topMargin: Constants.text_spacing - horizontalAlignment: Text.AlignHCenter - //: INFO ANDROID IOS - text: qsTr("You can use this Smartphone as a card reader for the %1 on other devices e.g. a laptop.\n\nTo do this you first have to pair that device with this smartphone.").arg(Qt.application.name) - textStyle: RemoteServiceModel.runnable ? Style.text.normal_secondary : Style.text.normal_warning - - states: [ - State { - when: !RemoteServiceModel.runnable - - PropertyChanges { - target: infoText - text: RemoteServiceModel.errorMessage - } - }, - State { - when: RemoteServiceModel.running && RemoteServiceModel.connectedToPairedDevice + readonly property string currentPin: RemoteServiceModel.psk.toString() - PropertyChanges { - target: infoText - text: RemoteServiceModel.connectionInfo - } - }, - State { - when: RemoteServiceModel.isPairing - - PropertyChanges { - Accessible.name: enterCodeString.arg(currentPin.split("").join(" ")).arg(Qt.application.name) - target: infoText - text: enterCodeString.arg(currentPin).arg(Qt.application.name) - } - }, - State { - when: !RemoteServiceModel.running && knownDeviceList.count > 0 - - PropertyChanges { - target: infoText - //: INFO ANDROID IOS - text: qsTr("Allow a connection with paired devices to use this Smartphone as a card reader or pair another device.") - } - }, - State { - when: RemoteServiceModel.running && knownDeviceList.count > 0 - - PropertyChanges { - target: infoText - //: INFO ANDROID IOS - text: qsTr("Paired devices may use this Smartphone as a card reader now.") - } - }, - State { - when: RemoteServiceModel.running - - PropertyChanges { - target: infoText - //: INFO ANDROID IOS - text: qsTr("Waiting for connection from a paired device...") + Accessible.ignored: true + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: Constants.component_spacing + horizontalAlignment: Text.AlignHCenter + + //: LABEL ANDROID IOS + text: qsTr("Pairing code: %1").arg(RemoteServiceModel.isPairing ? currentPin : "0000") + textStyle: Style.text.headline + visible: false + } + MoreInformationLink { + id: paringCodeLink + + Layout.alignment: Qt.AlignCenter + Layout.topMargin: Constants.component_spacing + //: LABEL ANDROID IOS + text: qsTr("Where do I enter the pairing code?") + visible: false + + onClicked: push(pairingCodeInfoView) + + Component { + id: pairingCodeInfoView + + PairingCodeInfoView { + text: paringCodeLink.text + + onNavActionClicked: pop() } } - ] + } } + } + GOptionsContainer { + id: knownDevicesContainer + + Layout.topMargin: Constants.component_spacing + containerPadding: Constants.pane_padding + //: LABEL ANDROID IOS + title: qsTr("Paired Devices") + visible: RemoteServiceModel.runnable && knownDeviceList.count > 0 + ColumnLayout { id: knownDevices - Layout.alignment: Qt.AlignLeft - Layout.fillWidth: true - Layout.topMargin: Constants.pane_padding + spacing: Constants.text_spacing - visible: RemoteServiceModel.runnable && knownDeviceList.count > 0 + width: parent.width - GText { - //: INFO ANDROID IOS - text: qsTr("Paired Devices") - textStyle: Style.text.header - } Repeater { id: knownDeviceList + model: RemoteServiceModel.allDevices delegate: DevicesListDelegate { @@ -203,149 +239,119 @@ SectionPage { Accessible.name: qsTr("Start pairing of a new device") Layout.alignment: Qt.AlignLeft Layout.topMargin: knownDevices.spacing - buttonColor: Style.color.transparent + background: null icon.source: "qrc:///images/material_add.svg" padding: 0 //: LABEL ANDROID IOS text: qsTr("Pair new device") - textStyle: Style.text.normal_accent_highlight + textStyle: Style.text.link + tintIcon: true visible: !RemoteServiceModel.isPairing && !RemoteServiceModel.running onClicked: RemoteServiceModel.setRunning(!RemoteServiceModel.running, !RemoteServiceModel.isPairing) } } - GText { - id: pairingCode + } + GSpacer { + Layout.fillHeight: true + } + RemoteServiceWifiInfo { + id: wifiInfo - readonly property string currentPin: RemoteServiceModel.psk.toString() + Layout.fillWidth: true + Layout.topMargin: Constants.component_spacing + } + LocalNetworkInfo { + id: networkPermissionText - Accessible.ignored: true - Layout.fillWidth: true - Layout.topMargin: Constants.component_spacing - horizontalAlignment: Text.AlignHCenter + Layout.bottomMargin: Constants.text_spacing + Layout.fillWidth: true + Layout.topMargin: Constants.component_spacing + visible: RemoteServiceModel.requiresLocalNetworkPermission + } + GProgressBar { + id: progressBar - //: LABEL ANDROID IOS - text: qsTr("Pairing code: %1").arg(RemoteServiceModel.isPairing ? currentPin : "0000") - textStyle: Style.text.title_accent - visible: false - } - MoreInformationLink { - id: paringCodeLink - Layout.alignment: Qt.AlignCenter - Layout.topMargin: Constants.component_spacing - //: LABEL ANDROID IOS - text: qsTr("Where do I enter the pairing code?") - visible: false - - onClicked: push(pairingCodeInfoView) - - Component { - id: pairingCodeInfoView - PairingCodeInfoView { - text: paringCodeLink.text - - onNavActionClicked: pop() + Layout.fillWidth: true + Layout.topMargin: Constants.component_spacing + value: RemoteServiceModel.percentage + visible: progressText.visible + } + GText { + id: progressText + + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: Constants.text_spacing + text: RemoteServiceModel.displayText + visible: text !== "" + } + GButton { + id: pairConnectButton + + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: Constants.component_spacing + enabled: !RemoteServiceModel.isStarting + visible: text !== "" + + states: [ + State { + when: !ApplicationModel.wifiEnabled + + PropertyChanges { + target: pairConnectButton + //: LABEL ANDROID IOS + text: qsTr("Enable WiFi") + + onClicked: ApplicationModel.enableWifi() } - } - } - GSpacer { - Layout.fillHeight: true - } - RemoteServiceWifiInfo { - id: wifiInfo - Layout.fillWidth: true - Layout.topMargin: Constants.component_spacing - } - LocalNetworkInfo { - id: networkPermissionText - Layout.bottomMargin: Constants.text_spacing - Layout.fillWidth: true - Layout.topMargin: Constants.component_spacing - visible: RemoteServiceModel.requiresLocalNetworkPermission - } - GProgressBar { - id: progressBar - Layout.fillWidth: true - Layout.topMargin: Constants.component_spacing - value: RemoteServiceModel.percentage - visible: progressText.visible - } - GText { - id: progressText - Layout.alignment: Qt.AlignHCenter - Layout.topMargin: Constants.text_spacing - text: RemoteServiceModel.displayText - textStyle: Style.text.normal_secondary - visible: text !== "" - } - GButton { - id: pairConnectButton - Layout.alignment: Qt.AlignHCenter - Layout.topMargin: Constants.component_spacing - enabled: !RemoteServiceModel.isStarting - visible: text !== "" - - states: [ - State { - when: !ApplicationModel.wifiEnabled - - PropertyChanges { - target: pairConnectButton - //: LABEL ANDROID IOS - text: qsTr("Enable WiFi") - - onClicked: ApplicationModel.enableWifi() - } - }, - State { - when: RemoteServiceModel.canEnableNfc + }, + State { + when: RemoteServiceModel.canEnableNfc - PropertyChanges { - target: pairConnectButton - //: LABEL ANDROID IOS - text: qsTr("Enable NFC") + PropertyChanges { + target: pairConnectButton + //: LABEL ANDROID IOS + text: qsTr("Enable NFC") - onClicked: ApplicationModel.showSettings(ApplicationModel.SETTING_NFC) - } - }, - State { - when: RemoteServiceModel.runnable && knownDeviceList.count > 0 && !RemoteServiceModel.isPairing && !RemoteServiceModel.running + onClicked: ApplicationModel.showSettings(ApplicationModel.SETTING_NFC) + } + }, + State { + when: RemoteServiceModel.runnable && knownDeviceList.count > 0 && !RemoteServiceModel.isPairing && !RemoteServiceModel.running - PropertyChanges { - buttonColor: Constants.green - target: pairConnectButton - //: LABEL ANDROID IOS - text: qsTr("Allow connection") + PropertyChanges { + target: pairConnectButton + //: LABEL ANDROID IOS + text: qsTr("Allow connection") - onClicked: RemoteServiceModel.setRunning(true) - } - }, - State { - when: RemoteServiceModel.runnable && knownDeviceList.count < 1 && !RemoteServiceModel.isPairing + onClicked: RemoteServiceModel.setRunning(true) + } + }, + State { + when: RemoteServiceModel.runnable && knownDeviceList.count < 1 && !RemoteServiceModel.isPairing - PropertyChanges { - target: pairConnectButton - //: LABEL ANDROID IOS - text: qsTr("Pair device") + PropertyChanges { + target: pairConnectButton + //: LABEL ANDROID IOS + text: qsTr("Pair device") - onClicked: RemoteServiceModel.setRunning(true, true) - } - }, - State { - when: RemoteServiceModel.isPairing + onClicked: RemoteServiceModel.setRunning(true, true) + } + }, + State { + when: RemoteServiceModel.isPairing - PropertyChanges { - target: pairConnectButton - //: LABEL ANDROID IOS - text: qsTr("Cancel pairing") - visible: true + PropertyChanges { + target: pairConnectButton + //: LABEL ANDROID IOS + text: qsTr("Cancel pairing") + visible: true - onClicked: RemoteServiceModel.setRunning(false, false) - } + onClicked: RemoteServiceModel.setRunning(false, false) } - ] + } + ] - onClicked: RemoteServiceModel.setRunning(true, !RemoteServiceModel.isPairing) - } + onClicked: RemoteServiceModel.setRunning(true, !RemoteServiceModel.isPairing) } } diff --git a/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceViewRemote.qml b/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceViewRemote.qml index 022420db0..f3494155d 100644 --- a/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceViewRemote.qml +++ b/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceViewRemote.qml @@ -1,20 +1,22 @@ /** * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.EnterPasswordView 1.0 -import Governikus.Global 1.0 -import Governikus.PasswordInfoView 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.PasswordType 1.0 -import Governikus.Type.RemoteServiceModel 1.0 +import QtQuick +import QtQuick.Controls +import Governikus.EnterPasswordView +import Governikus.Global +import Governikus.PasswordInfoView +import Governikus.Style +import Governikus.TitleBar +import Governikus.Type.ApplicationModel +import Governikus.Type.NumberModel +import Governikus.Type.PasswordType +import Governikus.Type.RemoteServiceModel Item { id: baseItem - height: mainColumn.height + + implicitHeight: mainColumn.implicitHeight QtObject { id: d @@ -26,26 +28,19 @@ Item { readonly property int usableWidth: width - leftPadding - rightPadding - leftPadding: Constants.pane_padding - rightPadding: Constants.pane_padding spacing: Constants.component_spacing width: baseItem.width - Column { - spacing: Constants.component_spacing + GOptionsContainer { + containerPadding: Constants.pane_padding + //: LABEL ANDROID IOS + title: qsTr("Paired devices") visible: availablePairedDeviceList.count > 0 width: parent.usableWidth - TitledSeparator { - contentMarginBottom: 0 - contentMarginLeft: 0 - contentMarginRight: 0 - //: LABEL ANDROID IOS - title: qsTr("Paired devices") - width: parent.width - } ListView { id: availablePairedDeviceList + height: childrenRect.height interactive: false model: RemoteServiceModel.availablePairedDevices @@ -68,21 +63,16 @@ Item { } } } - Column { - spacing: Constants.component_spacing + GOptionsContainer { + containerPadding: Constants.pane_padding + //: LABEL ANDROID IOS + title: qsTr("Last connected") visible: unavailablePairedDeviceList.count > 0 width: parent.usableWidth - TitledSeparator { - contentMarginBottom: 0 - contentMarginLeft: 0 - contentMarginRight: 0 - //: LABEL ANDROID IOS - title: qsTr("Last connected") - width: parent.width - } ListView { id: unavailablePairedDeviceList + height: childrenRect.height interactive: false model: RemoteServiceModel.unavailablePairedDevices @@ -121,20 +111,16 @@ Item { onConfirmed: RemoteServiceModel.forgetDevice(deviceId) } - Column { - spacing: Constants.component_spacing + GOptionsContainer { + containerPadding: Constants.pane_padding + containerSpacing: Constants.component_spacing + //: LABEL ANDROID IOS + title: qsTr("Add pairing") width: parent.usableWidth - TitledSeparator { - contentMarginBottom: 0 - contentMarginLeft: 0 - contentMarginRight: 0 - //: LABEL ANDROID IOS - title: qsTr("Add pairing") - width: parent.width - } GListView { id: searchDeviceList + height: childrenRect.height model: RemoteServiceModel.availableDevicesInPairingMode spacing: Constants.component_spacing @@ -188,27 +174,15 @@ Item { } } } - PasswordInfoData { - id: infoData - contentType: PasswordInfoContent.Type.SMARTPHONE_AS_CARD_READER - } - Component { - id: passwordInfoView - PasswordInfoView { - infoContent: infoData - - onClose: pop() - } - } Component { id: enterPinView + EnterPasswordView { function close() { setLockedAndHidden(d.oldLockedAndHiddenStatus); pop(); } - moreInformationText: infoData.linkText passwordType: PasswordType.REMOTE_PIN //: LABEL ANDROID IOS title: qsTr("Pairing code") @@ -220,7 +194,6 @@ Item { } onPasswordEntered: close() - onRequestPasswordInfo: push(passwordInfoView) } } } diff --git a/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceWifiInfo.qml b/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceWifiInfo.qml index ab03cc225..1add943ea 100644 --- a/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceWifiInfo.qml +++ b/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceWifiInfo.qml @@ -1,21 +1,25 @@ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style RowLayout { spacing: Constants.text_spacing TintableIcon { source: "qrc:/images/info.svg" - sourceSize.width: Style.dimens.small_icon_size - tintColor: Style.text.normal_secondary.textColor + sourceSize.width: Style.dimens.medium_icon_size + tintColor: infoText.color } GText { - Layout.fillWidth: true + id: infoText + + color: Style.color.text_subline //: INFO ANDROID IOS The remote service is active. Hint that both devices need to be connected to the same network. text: qsTr("Both devices have to be connected to the same WiFi.") - textStyle: Style.text.normal_secondary + } + GSpacer { + Layout.fillWidth: true } } diff --git a/resources/qml/Governikus/RemoteServiceView/LinkQuality.qml b/resources/qml/Governikus/RemoteServiceView/LinkQuality.qml index 42684021e..b99e10c02 100644 --- a/resources/qml/Governikus/RemoteServiceView/LinkQuality.qml +++ b/resources/qml/Governikus/RemoteServiceView/LinkQuality.qml @@ -1,8 +1,8 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Style 1.0 +import QtQuick +import Governikus.Style Image { id: img @@ -13,21 +13,21 @@ Image { fillMode: Image.PreserveAspectFit source: { if (inactive) { - return "qrc:///images/icon_remote_inactive.svg"; + return "qrc:///images/icon_remote_inactive_%1.svg".arg(Style.currentTheme.name); } if (percent >= 80) { - return "qrc:///images/icon_remote_100.svg"; + return "qrc:///images/icon_remote_100_%1.svg".arg(Style.currentTheme.name); } if (percent >= 60) { - return "qrc:///images/icon_remote_75.svg"; + return "qrc:///images/icon_remote_75_%1.svg".arg(Style.currentTheme.name); } if (percent >= 40) { - return "qrc:///images/icon_remote_50.svg"; + return "qrc:///images/icon_remote_50_%1.svg".arg(Style.currentTheme.name); } if (percent >= 20) { - return "qrc:///images/icon_remote_25.svg"; + return "qrc:///images/icon_remote_25_%1.svg".arg(Style.currentTheme.name); } - return "qrc:///images/icon_remote_0.svg"; + return "qrc:///images/icon_remote_inactive_%1.svg".arg(Style.currentTheme.name); } sourceSize.width: Style.dimens.icon_size } diff --git a/resources/qml/Governikus/RemoteServiceView/RemoteServiceController.qml b/resources/qml/Governikus/RemoteServiceView/RemoteServiceController.qml index d3abf4966..d30fbbd52 100644 --- a/resources/qml/Governikus/RemoteServiceView/RemoteServiceController.qml +++ b/resources/qml/Governikus/RemoteServiceView/RemoteServiceController.qml @@ -1,28 +1,59 @@ /** * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.AuthView 1.0 -import Governikus.EnterPasswordView 1.0 -import Governikus.PasswordInfoView 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 -import Governikus.Workflow 1.0 -import Governikus.Type.ChatModel 1.0 -import Governikus.Type.NumberModel 1.0 -import Governikus.Type.PasswordType 1.0 -import Governikus.Type.ReaderPlugIn 1.0 -import Governikus.Type.RemoteServiceModel 1.0 -import Governikus.Type.SettingsModel 1.0 +import QtQuick +import QtQuick.Controls +import Governikus.AuthView +import Governikus.EnterPasswordView +import Governikus.PasswordInfoView +import Governikus.Style +import Governikus.TitleBar +import Governikus.View +import Governikus.Workflow +import Governikus.Type.ChatModel +import Governikus.Type.NumberModel +import Governikus.Type.PasswordType +import Governikus.Type.ReaderPlugIn +import Governikus.Type.RemoteServiceModel +import Governikus.Type.SettingsModel Controller { id: controller + readonly property bool editRightsShown: stackView.currentItem instanceof EditRights readonly property bool enterPasswordShown: stackView.currentItem instanceof EnterPasswordView + readonly property bool isSmartWorkflow: RemoteServiceModel.readerPlugInType === ReaderPlugIn.SMART readonly property bool workflowShown: stackView.currentItem instanceof GeneralWorkflow + function processStateChange(pState) { + switch (pState) { + case "StateStartIfdService": + setLockedAndHidden(); + RemoteServiceModel.continueWorkflow(); + break; + case "StateEnterPacePasswordIfd": + if (SettingsModel.showAccessRights && RemoteServiceModel.isPinAuthentication()) { + push(editRights); + } else { + requestInput(); + } + break; + case "StateEstablishPaceChannelIfd": + case "StateChangePinIfd": + requestCard(); + RemoteServiceModel.continueWorkflow(); + break; + case "StateEnterNewPacePinIfd": + requestInput(); + break; + case "FinalState": + RemoteServiceModel.continueWorkflow(); + setLockedAndHidden(false); + break; + default: + RemoteServiceModel.continueWorkflow(); + } + } function requestCard() { if (RemoteServiceModel.hasCard && workflowShown) { pop(); @@ -32,7 +63,10 @@ Controller { } function requestInput(pState) { if (RemoteServiceModel.isBasicReader && RemoteServiceModel.pinPadModeOn()) { - push(enterPinView); + push(enterPinView, { + "passwordType": NumberModel.passwordType, + "inputError": NumberModel.inputError + }); } else { RemoteServiceModel.continueWorkflow(); } @@ -41,57 +75,30 @@ Controller { Connections { function onFireConnectedChanged() { if (RemoteServiceModel.connectedToPairedDevice && !workflowShown) { - RemoteServiceModel.setInitialPluginType(); requestCard(); - } else if (!RemoteServiceModel.connectedToPairedDevice && workflowShown) { + RemoteServiceModel.setInitialPluginType(); + } else if (!RemoteServiceModel.connectedToPairedDevice && (workflowShown || enterPasswordShown || editRightsShown)) { pop(); } } - function onFireCurrentStateChanged() { - switch (RemoteServiceModel.currentState) { - case "Initial": - break; - case "StateStartIfdService": - setLockedAndHidden(); - RemoteServiceModel.continueWorkflow(); - break; - case "StateEnterPacePasswordIfd": - if (SettingsModel.showAccessRights) { - push(editRights); - } else { - requestInput(); - } - break; - case "StateEstablishPaceChannelIfd": - case "StateChangePinIfd": - requestCard(); - RemoteServiceModel.continueWorkflow(); - break; - case "StateEnterNewPacePinIfd": - requestInput(); - break; - case "FinalState": - RemoteServiceModel.continueWorkflow(); - setLockedAndHidden(false); - break; - default: - RemoteServiceModel.continueWorkflow(); - } - } function onFireHasCardChanged() { if (!RemoteServiceModel.connectedToPairedDevice) { return; } - if (enterPasswordShown) { + if (enterPasswordShown || editRightsShown) { return; } requestCard(); } + function onFireStateEntered(pState) { + processStateChange(pState); + } target: RemoteServiceModel } Component { id: editRights + EditRights { //: LABEL ANDROID IOS actionText: qsTr("You are about to identify yourself towards the following provider using the device \"%1\":").arg(RemoteServiceModel.connectedClientName) @@ -117,8 +124,9 @@ Controller { } Component { id: generalWorkflow + GeneralWorkflow { - titleBarColor: RemoteServiceModel.readerPlugInType === ReaderPlugIn.SMART ? Style.color.accent_smart : Style.color.accent + smartEidUsed: RemoteServiceModel.readerPlugInType === ReaderPlugIn.SMART workflowModel: RemoteServiceModel //: LABEL ANDROID IOS workflowTitle: qsTr("Remote service") @@ -134,10 +142,12 @@ Controller { } PasswordInfoData { id: infoData + contentType: fromPasswordType(NumberModel.passwordType) } Component { id: passwordInfoView + PasswordInfoView { infoContent: infoData @@ -150,10 +160,13 @@ Controller { } Component { id: enterPinView + EnterPasswordView { id: passwordView + enableTransportPinLink: RemoteServiceModel.enableTransportPinLink moreInformationText: infoData.linkText + smartEidUsed: isSmartWorkflow //: LABEL ANDROID IOS title: qsTr("Card reader") @@ -168,11 +181,29 @@ Controller { onChangePinLength: { RemoteServiceModel.changePinLength(); + passwordView.passwordType = NumberModel.passwordType; } - onPasswordEntered: { - pop(); - RemoteServiceModel.startScanExplicitly(); - RemoteServiceModel.continueWorkflow(); + onPasswordEntered: pPasswordType => { + switch (pPasswordType) { + case PasswordType.NEW_PIN: + case PasswordType.NEW_SMART_PIN: + controller.processStateChange(RemoteServiceModel.currentState); + break; + case PasswordType.NEW_PIN_CONFIRMATION: + case PasswordType.NEW_SMART_PIN_CONFIRMATION: + if (NumberModel.commitNewPin()) { + popAll(); + RemoteServiceModel.startScanExplicitly(); + RemoteServiceModel.continueWorkflow(); + } else { + controller.processStateChange(RemoteServiceModel.currentState); + } + break; + default: + pop(); + RemoteServiceModel.startScanExplicitly(); + RemoteServiceModel.continueWorkflow(); + } } onRequestPasswordInfo: push(passwordInfoView) diff --git a/resources/qml/Governikus/RemoteServiceView/RemoteServiceSettings.qml b/resources/qml/Governikus/RemoteServiceView/RemoteServiceSettings.qml index e801577d7..aa8110f20 100644 --- a/resources/qml/Governikus/RemoteServiceView/RemoteServiceSettings.qml +++ b/resources/qml/Governikus/RemoteServiceView/RemoteServiceSettings.qml @@ -1,24 +1,26 @@ /** * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.TitleBar +import Governikus.View -SectionPage { +FlickableSectionPage { id: rootPage + //: LABEL ANDROID IOS title: qsTr("Manage pairings") - content: RemoteServiceViewRemote { - width: rootPage.width - } navigationAction: NavigationAction { action: NavigationAction.Action.Back onClicked: pop() } + + RemoteServiceViewRemote { + Layout.fillWidth: true + } } diff --git a/resources/qml/Governikus/ResultView/+desktop/ResultView.qml b/resources/qml/Governikus/ResultView/+desktop/ResultView.qml index 7447e9df7..1d2f2a2f7 100644 --- a/resources/qml/Governikus/ResultView/+desktop/ResultView.qml +++ b/resources/qml/Governikus/ResultView/+desktop/ResultView.qml @@ -1,34 +1,30 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.TitleBar 1.0 -import Governikus.Style 1.0 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.LogModel 1.0 -import Governikus.Type.UiModule 1.0 +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import Governikus.Global +import Governikus.TitleBar +import Governikus.Style +import Governikus.View +import Governikus.Type.ApplicationModel +import Governikus.Type.LogModel +import Governikus.Type.UiModule SectionPage { id: baseItem - enum Type { - IsSuccess, - IsError, - IsInfo - } + property alias animatedIcon: animation.source property alias buttonText: button.text property alias buttonType: button.buttonType property alias header: resultHeader.text property alias hintButtonText: hintItem.buttonText property alias hintText: hintItem.text + property alias icon: customIcon.source property alias mailButtonVisible: mailButton.visible - property alias popupText: detailedResultPopup.text - property alias popupTitle: detailedResultPopup.title - property int resultType: ResultView.Type.IsSuccess + property string popupText + property string popupTitle property alias text: resultText.text signal emailButtonPressed @@ -41,34 +37,35 @@ SectionPage { GFlickableColumnLayout { anchors.fill: parent anchors.margins: Constants.pane_padding + maximumContentWidth: Style.dimens.max_text_width spacing: Constants.pane_spacing - StatusIcon { + TintableAnimation { + id: animation + Layout.alignment: Qt.AlignHCenter - Layout.preferredHeight: Style.dimens.status_icon_large - Layout.preferredWidth: Style.dimens.status_icon_large - source: { - switch (resultType) { - case ResultView.Type.IsSuccess: - return "qrc:///images/status_ok.svg"; - case ResultView.Type.IsInfo: - return "qrc:///images/status_info.svg"; - case ResultView.Type.IsError: - return "qrc:///images/status_error.svg"; - } - } + Layout.preferredHeight: Style.dimens.header_icon_size + tintEnabled: false + visible: source.toString() !== "" + } + TintableIcon { + id: customIcon + + Layout.alignment: Qt.AlignHCenter + sourceSize.height: Style.dimens.header_icon_size + tintEnabled: false + visible: source.toString() !== "" } GSpacer { Layout.fillHeight: true } GText { id: resultHeader + Layout.alignment: Qt.AlignHCenter - Layout.maximumWidth: Style.dimens.max_text_width activeFocusOnTab: true horizontalAlignment: Text.AlignHCenter - textStyle: Style.text.header - verticalAlignment: Text.AlignVCenter + textStyle: Style.text.headline visible: text !== "" FocusFrame { @@ -76,12 +73,10 @@ SectionPage { } GText { id: resultText + Layout.alignment: Qt.AlignHCenter - Layout.maximumWidth: Style.dimens.max_text_width activeFocusOnTab: true horizontalAlignment: Text.AlignHCenter - textStyle: resultHeader.visible ? Style.text.header_secondary : Style.text.header - verticalAlignment: Text.AlignVCenter visible: text !== "" FocusFrame { @@ -95,6 +90,7 @@ SectionPage { GButton { id: mailButton + icon.source: "qrc:///images/material_mail.svg" //: LABEL DESKTOP text: qsTr("Send email") @@ -104,7 +100,7 @@ SectionPage { onClicked: baseItem.emailButtonPressed() } GButton { - icon.source: "qrc:/images/desktop/material_save.svg" + icon.source: "qrc:/images/desktop/save_icon.svg" //: LABEL DESKTOP text: qsTr("Save log") tintIcon: true @@ -117,6 +113,7 @@ SectionPage { GFileDialog { id: fileDialog + defaultSuffix: "log" //: LABEL DESKTOP nameFilters: qsTr("Logfiles (*.log)") @@ -134,7 +131,13 @@ SectionPage { tintIcon: true visible: popupTitle !== "" || popupText !== "" - onClicked: detailedResultPopup.open() + onClicked: { + let popup = detailedResultPopup.createObject(baseItem, { + "text": popupText, + "title": popupTitle + }); + popup.open(); + } } } GSpacer { @@ -142,26 +145,39 @@ SectionPage { } Hint { id: hintItem - Layout.alignment: Qt.AlignHCenter + Layout.fillWidth: true - Layout.maximumWidth: Style.dimens.max_text_width visible: text !== "" onClicked: baseItem.hintClicked() } NavigationButton { id: button + + Layout.alignment: Qt.AlignHCenter + Layout.preferredHeight: height + Layout.preferredWidth: width + activeFocusOnTab: true + visible: buttonType !== NavigationButton.Type.Forward + + onClicked: baseItem.nextView(UiModule.DEFAULT) + } + GButton { Layout.alignment: Qt.AlignHCenter Layout.preferredHeight: height Layout.preferredWidth: width activeFocusOnTab: true - buttonType: NavigationButton.Type.Forward + text: qsTr("OK") + visible: !button.visible onClicked: baseItem.nextView(UiModule.DEFAULT) } } - ConfirmationPopup { + Component { id: detailedResultPopup - style: ConfirmationPopup.PopupStyle.OkButton + + ConfirmationPopup { + style: ConfirmationPopup.PopupStyle.OkButton + } } } diff --git a/resources/qml/Governikus/ResultView/+mobile/ResultErrorView.qml b/resources/qml/Governikus/ResultView/+mobile/ResultErrorView.qml index 825e9dbad..1c6430d6f 100644 --- a/resources/qml/Governikus/ResultView/+mobile/ResultErrorView.qml +++ b/resources/qml/Governikus/ResultView/+mobile/ResultErrorView.qml @@ -1,9 +1,10 @@ /** * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style ResultView { id: baseItem @@ -19,48 +20,28 @@ ResultView { onCancelClicked: continueClicked() onVisibleChanged: errorDetailsShown = false - GButton { - Accessible.name: qsTr("Show error details") - anchors.horizontalCenter: parent.horizontalCenter - buttonColor: Style.color.transparent - text: qsTr("Details") + (baseItem.errorDetailsShown ? "▲" : "▼") - textStyle: Style.text.normal_accent - visible: baseItem.hasErrorDetails - - onClicked: baseItem.errorDetailsShown = !baseItem.errorDetailsShown - } - GSeparator { - visible: baseItem.errorDetailsShown - - anchors { - left: parent.left - right: parent.right + GCollapsible { + Layout.fillWidth: true + Layout.leftMargin: -Constants.pane_padding * 2 + Layout.rightMargin: -Constants.pane_padding * 2 + horizontalMargin: Constants.pane_padding * 2 + title: qsTr("Details") + visible: hasErrorDetails + + GText { + font.bold: true + //: LABEL ANDROID IOS + text: "%1 %2".arg(qsTr("Error code:")).arg(errorCode) } - } - GText { - //: LABEL ANDROID IOS - text: "%1 %2".arg(qsTr("Error code:")).arg(errorCode) - textStyle: Style.text.normal_highlight - visible: baseItem.errorDetailsShown + GText { + id: textErrorDescription - anchors { - left: parent.left - right: parent.right - } - } - GText { - id: textErrorDescription - visible: baseItem.errorDetailsShown - - anchors { - left: parent.left - right: parent.right - topMargin: Constants.pane_spacing } } GButton { id: mailButton - anchors.horizontalCenter: parent.horizontalCenter + + Layout.alignment: Qt.AlignHCenter icon.source: "qrc:///images/material_mail.svg" tintIcon: true visible: text !== "" diff --git a/resources/qml/Governikus/ResultView/+mobile/ResultView.qml b/resources/qml/Governikus/ResultView/+mobile/ResultView.qml index 6bc3964d0..3c54b3fa8 100644 --- a/resources/qml/Governikus/ResultView/+mobile/ResultView.qml +++ b/resources/qml/Governikus/ResultView/+mobile/ResultView.qml @@ -1,28 +1,23 @@ /** * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 - -SectionPage { +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.TitleBar +import Governikus.View + +FlickableSectionPage { id: baseItem - enum Type { - IsSuccess, - IsError, - IsInfo - } property alias buttonIcon: buttonContinue.icon.source property alias buttonText: buttonContinue.text - default property alias children: pane.paneData - property alias header: pane.title + default property alias children: layout.data + property alias header: paneTitle.text property alias hintButtonText: hintItem.buttonText property alias hintText: hintItem.text - property int resultType: ResultView.Type.IsSuccess + property alias icon: customIcon.source property alias text: resultText.text property alias textFormat: resultText.textFormat @@ -30,84 +25,64 @@ SectionPage { signal continueClicked signal hintClicked - sectionPageFlickable: contentItem - navigationAction: NavigationAction { action: NavigationAction.Action.Cancel onClicked: cancelClicked() } - GFlickableColumnLayout { - id: contentItem - - readonly property var maxIconHeight: Style.dimens.header_icon_size - readonly property var minIconHeight: Style.dimens.large_icon_size - - anchors.fill: parent - minimumContentHeight: implicitContentHeight - (maxIconHeight - minIconHeight) - spacing: 0 - - StatusIcon { - id: resultIcon - Layout.alignment: Qt.AlignHCenter - Layout.fillHeight: true - Layout.maximumHeight: contentItem.maxIconHeight - Layout.minimumHeight: contentItem.minIconHeight - Layout.preferredHeight: contentItem.maxIconHeight - implicitWidth: height - source: { - switch (resultType) { - case ResultView.Type.IsSuccess: - return "qrc:///images/status_ok.svg"; - case ResultView.Type.IsInfo: - return "qrc:///images/status_info.svg"; - case ResultView.Type.IsError: - return "qrc:///images/status_error.svg"; - } - } - } - GPane { - id: pane - Layout.alignment: Qt.AlignCenter | Qt.AlignTop - Layout.fillWidth: true - Layout.maximumWidth: Style.dimens.max_text_width - Layout.topMargin: Constants.component_spacing + TintableIcon { + id: customIcon - GText { - id: resultText - visible: text !== "" + Layout.alignment: Qt.AlignHCenter + sourceSize.height: Style.dimens.header_icon_size + tintEnabled: false + visible: source.toString() !== "" + } + ColumnLayout { + id: layout + + Layout.margins: Constants.pane_padding + spacing: Constants.pane_spacing + + PaneTitle { + id: paneTitle - anchors { - left: parent.left - right: parent.right - } - } - } - GSpacer { - Layout.fillHeight: true } - Hint { - id: hintItem - Layout.alignment: Qt.AlignHCenter - Layout.fillWidth: true + GText { + id: resultText + + Layout.alignment: Qt.AlignCenter | Qt.AlignTop Layout.maximumWidth: Style.dimens.max_text_width Layout.topMargin: Constants.component_spacing visible: text !== "" - - onClicked: hintClicked() } - GButton { - id: buttonContinue - Layout.alignment: Qt.AlignHCenter - Layout.topMargin: Constants.component_spacing + } + GSpacer { + Layout.fillHeight: true + } + Hint { + id: hintItem - //: LABEL ANDROID IOS - text: qsTr("OK") - tintIcon: true - visible: text !== "" + Layout.alignment: Qt.AlignHCenter + Layout.fillWidth: true + Layout.maximumWidth: Style.dimens.max_text_width + Layout.topMargin: Constants.component_spacing + visible: text !== "" - onClicked: continueClicked() - } + onClicked: hintClicked() + } + GButton { + id: buttonContinue + + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: Constants.component_spacing + + //: LABEL ANDROID IOS + text: qsTr("OK") + tintIcon: true + visible: text !== "" + + onClicked: continueClicked() } } diff --git a/resources/qml/Governikus/SelfAuthenticationView/+desktop/SelfAuthenticationView.qml b/resources/qml/Governikus/SelfAuthenticationView/+desktop/SelfAuthenticationView.qml index 8943a37dd..2e7bf0db9 100644 --- a/resources/qml/Governikus/SelfAuthenticationView/+desktop/SelfAuthenticationView.qml +++ b/resources/qml/Governikus/SelfAuthenticationView/+desktop/SelfAuthenticationView.qml @@ -1,18 +1,17 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.SettingsModel 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.TitleBar 1.0 -import Governikus.Type.SelfAuthModel 1.0 -import Governikus.View 1.0 -import QtQuick 2.15 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.Type.SettingsModel +import Governikus.TitleBar +import Governikus.Type.SelfAuthModel +import Governikus.View SectionPage { titleBarAction: TitleBarAction { - helpTopic: "selfauthentication" //: LABEL DESKTOP text: qsTr("Identify") } @@ -26,17 +25,19 @@ SectionPage { width: Style.dimens.max_text_width Item { + anchors.horizontalCenter: parent.horizontalCenter height: childrenRect.height - width: parent.width + width: parent.width * 0.8 Image { id: useNpa + anchors.left: parent.left fillMode: Image.PreserveAspectFit - height: width + height: Style.dimens.header_icon_size mipmap: true - source: "qrc:///images/siteWithLogo.png" - width: ApplicationModel.scaleFactor * 400 + source: "qrc:///images/siteWithLogo_%1.svg".arg(Style.currentTheme.name) + width: height } GText { //: LABEL DESKTOP A11y description of eID logo displayed next to the logo itself @@ -50,7 +51,6 @@ SectionPage { //: LABEL DESKTOP text: qsTr("You can use your ID card anywhere you see this logo.") - textStyle: Style.text.header FocusFrame { } @@ -58,31 +58,35 @@ SectionPage { } GPane { id: textPane + + color: Style.color.pane_sublevel + drawShadow: false + anchors { left: parent.left right: parent.right } GText { activeFocusOnTab: true + horizontalAlignment: Text.AlignHCenter //: LABEL DESKTOP text: qsTr("Use the button \"See my personal data\" to start the self-authentication service of the manufacturer of the %1 to display the data stored in the chip of your ID card.").arg(Qt.application.name) - textStyle: Style.text.normal - width: parent.width FocusFrame { } } PrivacyStatement { activeFocusOnTab: true - width: parent.width + horizontalAlignment: Text.AlignHCenter FocusFrame { } } GButton { id: startWorkflowButton - anchors.right: parent.right - buttonColor: SettingsModel.useSelfauthenticationTestUri ? Constants.red : Style.color.button + + Layout.alignment: Qt.AlignHCenter + buttonColor: SettingsModel.useSelfauthenticationTestUri ? Constants.red : Style.color.control icon.source: "qrc:///images/identify.svg" //: LABEL DESKTOP text: qsTr("See my personal data") diff --git a/resources/qml/Governikus/SelfAuthenticationView/+mobile/SelfAuthenticationView.qml b/resources/qml/Governikus/SelfAuthenticationView/+mobile/SelfAuthenticationView.qml index c5d288826..fe2944a8f 100644 --- a/resources/qml/Governikus/SelfAuthenticationView/+mobile/SelfAuthenticationView.qml +++ b/resources/qml/Governikus/SelfAuthenticationView/+mobile/SelfAuthenticationView.qml @@ -1,107 +1,124 @@ /** * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 -import Governikus.Type.SettingsModel 1.0 -import Governikus.Type.SelfAuthModel 1.0 -import Governikus.Type.UiModule 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.AuthView +import Governikus.Global +import Governikus.Style +import Governikus.TitleBar +import Governikus.View +import Governikus.Type.ReaderPlugIn +import Governikus.Type.SettingsModel +import Governikus.Type.SelfAuthModel +import Governikus.Type.UiModule -SectionPage { +FlickableSectionPage { id: root - sectionPageFlickable: contentItem + + property bool autoInsertCard: false + property bool hideTechnologySwitch: false + property var initialPlugIn + + signal back + + spacing: Constants.pane_spacing //: LABEL ANDROID IOS title: qsTr("Identify") navigationAction: NavigationAction { action: NavigationAction.Action.Back - onClicked: show(UiModule.DEFAULT) + onClicked: root.back() } - GFlickableColumnLayout { - id: contentItem - - readonly property var maxIconHeight: Style.dimens.header_icon_size - readonly property var minIconHeight: Style.dimens.medium_icon_size + Component { + id: authView - anchors.fill: parent - maximumContentWidth: Style.dimens.max_text_width - minimumContentHeight: implicitContentHeight - (maxIconHeight - minIconHeight) - spacing: 0 + AuthView { + autoInsertCard: root.autoInsertCard + hideTechnologySwitch: root.hideTechnologySwitch + initialPlugIn: root.initialPlugIn - TintableIcon { - Layout.alignment: Qt.AlignHCenter - Layout.fillHeight: true - Layout.maximumHeight: contentItem.maxIconHeight - Layout.minimumHeight: contentItem.minIconHeight - source: "qrc:///images/mydata.svg" - sourceSize.height: contentItem.maxIconHeight - tintColor: Style.color.accent - - PkiSwitch { - anchors.fill: parent + Component.onCompleted: SelfAuthModel.startWorkflow(false) + onShowChangePinView: { + show(UiModule.PINMANAGEMENT); + popAll(); } + onWorkflowFinished: popAll() } - GPane { - Layout.alignment: Qt.AlignHCenter - Layout.fillWidth: true - Layout.topMargin: Constants.component_spacing + } + TintableIcon { + Layout.alignment: Qt.AlignHCenter + source: "qrc:///images/mydata.svg" + sourceSize.height: Style.dimens.large_icon_size + tintColor: Style.color.control - GText { - //: LABEL ANDROID IOS - text: qsTr("Use the button \"See my personal data\" to start the self-authentication service of the manufacturer of the %1 to display the data stored in the chip of your ID card.").arg(Qt.application.name) - width: parent.width - wrapMode: Text.WordWrap - } - PrivacyStatement { - width: parent.width - } - } - GSpacer { - Layout.fillHeight: true + PkiSwitch { + anchors.fill: parent + //: LABEL ANDROID IOS + functionName: qsTr("Self-authentication") } - Hint { - Layout.fillWidth: true - Layout.topMargin: Constants.component_spacing - - RowLayout { - spacing: Constants.text_spacing - width: parent.width - - Image { - Layout.fillWidth: true - Layout.preferredHeight: Style.dimens.medium_icon_size - asynchronous: true - fillMode: Image.PreserveAspectFit - source: "qrc:///images/siteWithLogo.png" - sourceSize.height: Style.dimens.large_icon_size - } - GText { - - //: LABEL ANDROID IOS A11y description of eID logo displayed next to the logo itself - Accessible.name: qsTr("You can use your ID card anywhere you find the logo of the electronic identification function.") - Layout.fillWidth: true + } + GText { + Layout.alignment: Qt.AlignHCenter + Layout.leftMargin: Constants.pane_padding + Layout.rightMargin: Constants.pane_padding + horizontalAlignment: Text.AlignHCenter + //: LABEL ANDROID IOS + text: qsTr("Use the button \"See my personal data\" to start the self-authentication service of the manufacturer of the %1 to display the data stored in the chip of your ID card.").arg(Qt.application.name) + width: parent.width + wrapMode: Text.WordWrap + } + PrivacyStatement { + Layout.fillWidth: true + Layout.leftMargin: Constants.pane_padding + Layout.rightMargin: Constants.pane_padding + horizontalAlignment: Text.AlignHCenter + } + GSeparator { + Layout.fillWidth: true + } + GridLayout { + Layout.fillWidth: true + Layout.leftMargin: Constants.pane_padding + Layout.rightMargin: Layout.leftMargin + columnSpacing: rowSpacing + columns: 2 + rowSpacing: Constants.groupbox_spacing + rows: 2 - //: LABEL ANDROID IOS - text: qsTr("You can use your ID card anywhere you see this logo.") - } - } - } - GButton { - Layout.alignment: Qt.AlignHCenter - Layout.topMargin: Constants.component_spacing - buttonColor: SettingsModel.useSelfauthenticationTestUri ? Style.color.warning_text : Style.color.accent - icon.source: "qrc:///images/identify.svg" + GText { + Layout.columnSpan: 2 //: LABEL ANDROID IOS - text: qsTr("See my personal data") - tintIcon: true + text: qsTr("Hint") + textStyle: Style.text.subline + } + Image { + fillMode: Image.PreserveAspectFit + source: "qrc:///images/siteWithLogo_%1.svg".arg(Style.currentTheme.name) + sourceSize.height: Style.dimens.large_icon_size + } + GText { + //: LABEL ANDROID IOS A11y description of eID logo displayed next to the logo itself + Accessible.name: qsTr("You can use your ID card anywhere you find the logo of the electronic identification function.") - onClicked: SelfAuthModel.startWorkflow() + //: LABEL ANDROID IOS + text: qsTr("You can use your ID card anywhere you see this logo.") } } + GSeparator { + Layout.fillWidth: true + } + GButton { + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: Constants.component_spacing + buttonColor: SettingsModel.useSelfauthenticationTestUri ? Style.color.text_warning : Style.color.control + icon.source: "qrc:///images/identify.svg" + //: LABEL ANDROID IOS + text: qsTr("See my personal data") + tintIcon: true + + onClicked: push(authView) + } } diff --git a/resources/qml/Governikus/SettingsView/+desktop/CardReaderDelegate.qml b/resources/qml/Governikus/SettingsView/+desktop/CardReaderDelegate.qml index eee0fce89..db204976d 100644 --- a/resources/qml/Governikus/SettingsView/+desktop/CardReaderDelegate.qml +++ b/resources/qml/Governikus/SettingsView/+desktop/CardReaderDelegate.qml @@ -1,26 +1,29 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.View 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.View -Item { - property int iconHeight: ApplicationModel.scaleFactor * 175 +RoundedRectangle { + property int iconHeight: plugin.scaleFactor * 175 Accessible.name: readerName + ". " + readerHTMLDescription Accessible.role: Accessible.Button activeFocusOnTab: true + color: Style.color.pane_sublevel implicitHeight: rowLayout.implicitHeight + implicitWidth: rowLayout.implicitWidth FocusFrame { } RowLayout { id: rowLayout - spacing: 0 + + anchors.fill: parent + spacing: Constants.component_spacing state: { if (readerInstalled) { if (readerSupported) { @@ -30,96 +33,89 @@ Item { } return "ERROR"; } - width: parent.width states: [ State { name: "OK" PropertyChanges { - source: "qrc:///images/status_ok.svg" + source: "qrc:///images/status_ok_%1.svg".arg(Style.currentTheme.name) target: statusIcon } PropertyChanges { target: statusIcon tintColor: Style.color.success } - PropertyChanges { - target: textDescription - textStyle: Style.text.normal - } }, State { name: "WARNING" PropertyChanges { - source: "qrc:///images/material_alert.svg" + source: "qrc:///images/status_warning.svg" target: statusIcon } PropertyChanges { target: statusIcon - tintColor: "#e68a00" - } - PropertyChanges { - target: textDescription - textStyle: Style.text.normal_highlight + tintColor: Style.color.fail } }, State { name: "ERROR" PropertyChanges { - source: "qrc:///images/status_error.svg" + source: "qrc:///images/status_error_%1.svg".arg(Style.currentTheme.name) target: statusIcon } PropertyChanges { target: statusIcon - tintColor: Style.color.warning_text - } - PropertyChanges { - target: textDescription - textStyle: Style.text.normal + tintColor: Style.color.text_warning } } ] - Rectangle { - Layout.preferredHeight: iconHeight - Layout.preferredWidth: iconHeight + RoundedRectangle { + Layout.fillHeight: true + Layout.preferredHeight: iconHeight + 2 * Constants.pane_padding + Layout.preferredWidth: iconHeight + Constants.pane_padding + bottomRightCorner: false + color: Style.color.pane_sublevel + gradientColor: Style.color.pane + topRightCorner: false - border { - color: Style.color.border - width: Style.dimens.separator_size - } Image { id: readerIcon - anchors.fill: parent - anchors.margins: iconHeight * 0.05 + + anchors.centerIn: parent asynchronous: true fillMode: Image.PreserveAspectFit + height: iconHeight * 0.95 source: readerImagePath + width: iconHeight * 0.95 } } - GSpacer { - height: Constants.component_spacing - width: Constants.component_spacing - } ColumnLayout { id: textColumn + Layout.alignment: Qt.AlignLeft + Layout.bottomMargin: Constants.pane_padding Layout.fillHeight: true + Layout.fillWidth: true + Layout.leftMargin: 0 + Layout.preferredWidth: parent.width + Layout.topMargin: Constants.pane_padding spacing: Constants.text_spacing GText { - Layout.fillWidth: true + Layout.alignment: Qt.AlignLeft clip: true text: readerName - textStyle: Style.text.header + textStyle: Style.text.headline } GText { id: textDescription + Accessible.description: qsTr("Press space to open the link in your browser") - Layout.fillWidth: true + Layout.alignment: Qt.AlignLeft activeFocusOnTab: true text: readerHTMLDescription @@ -129,6 +125,8 @@ Item { } TintableIcon { id: statusIcon + + Layout.rightMargin: Constants.pane_padding sourceSize.height: iconHeight * 0.33 } } diff --git a/resources/qml/Governikus/SettingsView/+desktop/CardReaderView.qml b/resources/qml/Governikus/SettingsView/+desktop/CardReaderView.qml index b3cc1d100..7c3ed5abf 100644 --- a/resources/qml/Governikus/SettingsView/+desktop/CardReaderView.qml +++ b/resources/qml/Governikus/SettingsView/+desktop/CardReaderView.qml @@ -1,111 +1,103 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.ReaderModel 1.0 -import Governikus.Type.ReaderScanEnabler 1.0 -import Governikus.Type.ReaderPlugIn 1.0 -import Governikus.View 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.Type.ApplicationModel +import Governikus.Type.ReaderModel +import Governikus.Type.ReaderScanEnabler +import Governikus.Type.ReaderPlugIn +import Governikus.View Column { id: root - readonly property string helpTopic: "settingsPcscReader" - spacing: Constants.component_spacing ReaderScanEnabler { id: readerScanEnabler + plugInType: ReaderPlugIn.PCSC } - GText { - activeFocusOnTab: true - text: qsTr("Connected USB card readers") - textStyle: Style.text.header_accent + GPane { + //: LABEL DESKTOP + title: qsTr("Connected USB card readers") width: parent.width - FocusFrame { - } - } - Column { - spacing: Constants.component_spacing - visible: readerRepeater.count > 0 - width: parent.width + Column { + Layout.fillWidth: true + spacing: Constants.component_spacing + visible: readerRepeater.count > 0 - Repeater { - id: readerRepeater - model: ReaderModel.sortedModel + Repeater { + id: readerRepeater - delegate: CardReaderDelegate { - width: parent.width + model: ReaderModel.sortedModel - GSeparator { - anchors.bottom: parent.bottom + delegate: CardReaderDelegate { width: parent.width } } } - } - RowLayout { - visible: !readerScanEnabler.scanRunning - width: parent.width + RowLayout { + spacing: Constants.component_spacing + visible: !readerScanEnabler.scanRunning + width: parent.width - TintableIcon { - source: "qrc:///images/material_alert.svg" - sourceSize.height: Style.dimens.icon_size - tintColor: Style.color.warning_text + TintableIcon { + source: "qrc:///images/status_warning.svg" + sourceSize.height: Style.dimens.large_icon_size + tintColor: Style.color.text_warning + } + GText { + text: qsTr("The connection to your system's smartcard service could not be established. You can try to resolve this issue and restart the scan.") + } + GButton { + text: qsTr("Restart smartcard scan") + + onClicked: readerScanEnabler.restartScan() + } } GText { - Layout.fillWidth: true - text: qsTr("The connection to your system's smartcard service could not be established. You can try to resolve this issue and restart the scan.") - textStyle: Style.text.hint - } - GButton { - text: qsTr("Restart smartcard scan") + id: placeHolderText - onClicked: readerScanEnabler.restartScan() - } - } - GText { - id: placeHolderText - activeFocusOnTab: true - text: ReaderModel.emptyListDescriptionString - textStyle: Style.text.normal - verticalAlignment: Text.AlignVCenter - visible: readerRepeater.count === 0 - width: parent.width + activeFocusOnTab: true + text: qsTr("No connected card reader found.") + visible: readerRepeater.count === 0 + width: parent.width - FocusFrame { + FocusFrame { + } } - } - GSeparator { - visible: readerRepeater.count === 0 - width: parent.width - } - RowLayout { - id: hintAndDateText - spacing: Constants.text_spacing - width: parent.width - - TintableIcon { - source: "qrc:/images/info.svg" - sourceSize.height: Style.dimens.icon_size - tintColor: Style.color.accent + GSeparator { + visible: readerRepeater.count === 0 + width: parent.width } - GText { - id: hintText - Layout.alignment: Qt.AlignVCenter - Layout.fillWidth: true - activeFocusOnTab: true - text: qsTr("After connecting a new card reader it may take a few seconds to recognize the driver. It may be necessary to restart your system after installing the driver. Only connected card readers are shown here. %1").arg(ReaderModel.lastUpdatedInformation) - textStyle: Style.text.hint - verticalAlignment: Text.AlignBottom + RowLayout { + id: hintAndDateText - FocusFrame { + Layout.topMargin: Constants.component_spacing + spacing: Constants.component_spacing + width: parent.width + + TintableIcon { + source: "qrc:/images/info.svg" + sourceSize.height: Style.dimens.large_icon_size + tintColor: Style.color.control + } + GText { + id: hintText + + Layout.alignment: Qt.AlignVCenter + activeFocusOnTab: true + color: Style.color.control + text: qsTr("After connecting a new card reader it may take a few seconds to recognize the driver. It may be necessary to restart your system after installing the driver. Only connected card readers are shown here. %1").arg(ReaderModel.lastUpdatedInformation) + verticalAlignment: Text.AlignBottom + + FocusFrame { + } } } } diff --git a/resources/qml/Governikus/SettingsView/+desktop/ConnectSacView.qml b/resources/qml/Governikus/SettingsView/+desktop/ConnectSacView.qml index 779e0a185..2268fee01 100644 --- a/resources/qml/Governikus/SettingsView/+desktop/ConnectSacView.qml +++ b/resources/qml/Governikus/SettingsView/+desktop/ConnectSacView.qml @@ -1,24 +1,25 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.EnterPasswordView 1.0 -import Governikus.PasswordInfoView 1.0 -import Governikus.ProgressView 1.0 -import Governikus.ResultView 1.0 -import Governikus.TitleBar 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.PasswordType 1.0 -import Governikus.Type.RemoteServiceModel 1.0 -import Governikus.View 1.0 +import QtQuick +import QtQuick.Controls +import Governikus.EnterPasswordView +import Governikus.PasswordInfoView +import Governikus.ProgressView +import Governikus.ResultView +import Governikus.Style +import Governikus.TitleBar +import Governikus.Type.ApplicationModel +import Governikus.Type.PasswordType +import Governikus.Type.RemoteServiceModel +import Governikus.View SectionPage { id: root + enum SubView { None, EnterPassword, - PairingInfo, WaitForPairing, PairingFailed } @@ -27,30 +28,18 @@ SectionPage { signal closeView - function showPairingInformation() { - d.view = ConnectSacView.SubView.PairingInfo; - d.externalMoreInformation = true; - } - titleBarAction: TitleBarAction { id: mainTitleBarAction - helpTopic: "settingsRemoteReader" + rootEnabled: false //: LABEL DESKTOP text: qsTr("Pairing") - visible: d.view !== ConnectSacView.SubView.PairingInfo || !d.externalMoreInformation - customSubAction: CancelAction { + customSubAction: NavigationAction { visible: true onClicked: root.closeView() } - - onClicked: { - if (d.view === ConnectSacView.SubView.PairingInfo && !d.externalMoreInformation) { - d.view = ConnectSacView.SubView.EnterPassword; - } - } } onVisibleChanged: { @@ -58,7 +47,6 @@ SectionPage { d.view = ConnectSacView.SubView.EnterPassword; } else { d.view = ConnectSacView.SubView.None; - d.externalMoreInformation = false; } updateTitleBarActions(); } @@ -66,37 +54,13 @@ SectionPage { QtObject { id: d - property bool externalMoreInformation: false property int view } EnterPasswordView { passwordType: PasswordType.REMOTE_PIN - statusIcon: "qrc:///images/phone_to_pc.svg" visible: d.view === ConnectSacView.SubView.EnterPassword onPasswordEntered: d.view = ConnectSacView.SubView.WaitForPairing - onRequestPasswordInfo: { - d.view = ConnectSacView.SubView.PairingInfo; - updateTitleBarActions(); - } - } - PasswordInfoView { - rootEnabled: mainTitleBarAction.rootEnabled - visible: d.view === ConnectSacView.SubView.PairingInfo - - infoContent: PasswordInfoData { - contentType: PasswordInfoContent.Type.SMARTPHONE_AS_CARD_READER - } - - onClose: { - if (d.externalMoreInformation) { - root.closeView(); - d.externalMoreInformation = false; - } else { - d.view = ConnectSacView.SubView.EnterPassword; - } - updateTitleBarActions(); - } } ProgressView { @@ -124,7 +88,7 @@ SectionPage { property string deviceName property string errorMessage - resultType: ResultView.Type.IsError + icon: "qrc:///images/desktop/workflow_error_sak_connection_%1.svg".arg(Style.currentTheme.name) //: ERROR DESKTOP An error occurred while pairing the device. text: qsTr("Pairing to \"%1\" failed:").arg(deviceName) + "
\"%2\"".arg(errorMessage) diff --git a/resources/qml/Governikus/SettingsView/+desktop/DarkModeButtons.qml b/resources/qml/Governikus/SettingsView/+desktop/DarkModeButtons.qml new file mode 100644 index 000000000..868d5a7c9 --- /dev/null +++ b/resources/qml/Governikus/SettingsView/+desktop/DarkModeButtons.qml @@ -0,0 +1,81 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Type.SettingsModel +import Governikus.Type.ModeOption + +ColumnLayout { + id: root + + readonly property var checkedButton: system.checked ? system : dark.checked ? dark : light + readonly property string selectedIconPath: checkedButton.icon.source + readonly property string selectedText: checkedButton.text + + signal buttonClicked + + function onChanged(checked, mode) { + if (!checked || SettingsModel.userDarkMode === mode) + return; + SettingsModel.userDarkMode = mode; + root.buttonClicked(); + } + + spacing: Constants.component_spacing + + Component.onCompleted: { + if (!plugin.osDarkModeSupported) + system.visible = false; + } + + GRadioButton { + id: system + + readonly property var mode: ModeOption.AUTO + + //: LABEL ALL_PLATFORMS + Accessible.description: qsTr("Set the app appearance to system mode") + Layout.fillWidth: true + checked: SettingsModel.userDarkMode === mode + icon.source: "qrc:///images/appearance_system_mode.svg" + //: LABEL ALL_PLATFORMS + text: qsTr("System") + tintIcon: true + + onCheckedChanged: root.onChanged(checked, mode) + } + GRadioButton { + id: dark + + readonly property var mode: ModeOption.ON + + //: LABEL ALL_PLATFORMS + Accessible.description: qsTr("Set the app appearance to dark mode") + Layout.fillWidth: true + checked: SettingsModel.userDarkMode === mode + icon.source: "qrc:///images/appearance_dark_mode.svg" + //: LABEL ALL_PLATFORMS + text: qsTr("Dark") + tintIcon: true + + onCheckedChanged: root.onChanged(checked, mode) + } + GRadioButton { + id: light + + readonly property var mode: ModeOption.OFF + + //: LABEL ALL_PLATFORMS + Accessible.description: qsTr("Set the app appearance to light mode") + Layout.fillWidth: true + checked: SettingsModel.userDarkMode === mode + icon.source: "qrc:///images/appearance_light_mode.svg" + //: LABEL ALL_PLATFORMS + text: qsTr("Light") + tintIcon: true + + onCheckedChanged: root.onChanged(checked, mode) + } +} diff --git a/resources/qml/Governikus/SettingsView/+desktop/DebugSettings.qml b/resources/qml/Governikus/SettingsView/+desktop/DebugSettings.qml index d3269efe3..ef35d68e8 100644 --- a/resources/qml/Governikus/SettingsView/+desktop/DebugSettings.qml +++ b/resources/qml/Governikus/SettingsView/+desktop/DebugSettings.qml @@ -1,63 +1,72 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.View 1.0 -import Governikus.Style 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.HistoryModel 1.0 -import Governikus.Type.LogModel 1.0 -import Governikus.Type.SettingsModel 1.0 +import QtQuick.Layouts +import Governikus.Global +import Governikus.View +import Governikus.Style +import Governikus.Type.ApplicationModel +import Governikus.Type.LogModel +import Governikus.Type.SettingsModel ColumnLayout { spacing: Constants.component_spacing - GText { + GPane { + Layout.fillWidth: true + spacing: Constants.component_spacing + //: LABEL DESKTOP - text: qsTr("Create dummy entries") - textStyle: Style.text.header_accent - } - RowLayout { - GButton { - //: LABEL DESKTOP - text: qsTr("Logfile") + title: qsTr("Create dummy entries") - onClicked: { - LogModel.saveDummyLogFile(); - ApplicationModel.showFeedback("Created new logfile."); + RowLayout { + GButton { + //: LABEL DESKTOP + text: qsTr("Logfile") + + onClicked: { + LogModel.saveDummyLogFile(); + ApplicationModel.showFeedback("Created new logfile."); + } } } + LabeledSwitch { + checked: SettingsModel.showBetaTesting + //: LABEL DESKTOP + title: qsTr("Show beta testing image") + + onCheckedChanged: SettingsModel.showBetaTesting = checked + } + LabeledSwitch { + checked: SettingsModel.enableCanAllowed + //: LABEL DESKTOP + title: qsTr("Support CAN allowed mode") + + onCheckedChanged: SettingsModel.enableCanAllowed = checked + } + LabeledSwitch { + checked: SettingsModel.skipRightsOnCanAllowed + enabled: SettingsModel.enableCanAllowed + //: LABEL DESKTOP + title: qsTr("Skip rights page in CAN allowed mode") + + onCheckedChanged: SettingsModel.skipRightsOnCanAllowed = checked + } GButton { //: LABEL DESKTOP - text: qsTr("History") + text: qsTr("Reset hideable dialogs") onClicked: { - HistoryModel.createDummyEntry(); - ApplicationModel.showFeedback("Created new history entry."); + SettingsModel.resetHideableDialogs(); } } - } - GCheckBox { - checked: SettingsModel.showBetaTesting - //: LABEL DESKTOP - text: qsTr("Show beta testing image") - - onCheckedChanged: SettingsModel.showBetaTesting = checked - } - GCheckBox { - checked: SettingsModel.enableCanAllowed - //: LABEL DESKTOP - text: qsTr("Support CAN allowed mode") - - onCheckedChanged: SettingsModel.enableCanAllowed = checked - } - GCheckBox { - checked: SettingsModel.skipRightsOnCanAllowed - enabled: SettingsModel.enableCanAllowed - //: LABEL DESKTOP - text: qsTr("Skip rights page in CAN allowed mode") + GText { + activeFocusOnTab: true + //: LABEL DESKTOP + text: qsTr("Show Transport PIN reminder, store feedback and close reminder dialogs.") - onCheckedChanged: SettingsModel.skipRightsOnCanAllowed = checked + FocusFrame { + } + } } } diff --git a/resources/qml/Governikus/SettingsView/+desktop/DeveloperSettings.qml b/resources/qml/Governikus/SettingsView/+desktop/DeveloperSettings.qml index 01fa608b9..e797698cf 100644 --- a/resources/qml/Governikus/SettingsView/+desktop/DeveloperSettings.qml +++ b/resources/qml/Governikus/SettingsView/+desktop/DeveloperSettings.qml @@ -1,124 +1,96 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.View 1.0 -import Governikus.Style 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.HistoryModel 1.0 -import Governikus.Type.LogModel 1.0 -import Governikus.Type.SettingsModel 1.0 +import QtQml +import QtQuick.Layouts +import Governikus.Global +import Governikus.View +import Governikus.Style +import Governikus.Type.ApplicationModel +import Governikus.Type.LogModel +import Governikus.Type.SettingsModel ColumnLayout { - readonly property string helpTopic: "settingsDeveloper" - spacing: Constants.component_spacing - GText { - activeFocusOnTab: true - + GPane { + Layout.fillWidth: true + spacing: Constants.component_spacing //: LABEL DESKTOP - text: qsTr("Developer options") - textStyle: Style.text.header_accent + title: qsTr("Developer options") - FocusFrame { - } - } - GCheckBox { - checked: SettingsModel.useSelfauthenticationTestUri + LabeledSwitch { + checked: SettingsModel.useSelfauthenticationTestUri + //: LABEL DESKTOP + description: qsTr("Allow test sample card usage") - //: LABEL DESKTOP - text: qsTr("Testmode for the self-authentication") + //: LABEL DESKTOP + title: qsTr("Testmode for the self-authentication") - onCheckedChanged: SettingsModel.useSelfauthenticationTestUri = checked - } - GCheckBox { - checked: SettingsModel.enableSimulator - //: LABEL DESKTOP - text: qsTr("Enable internal card simulator") + onCheckedChanged: SettingsModel.useSelfauthenticationTestUri = checked + } + LabeledSwitch { + checked: SettingsModel.enableSimulator - onCheckedChanged: SettingsModel.enableSimulator = checked - } - GText { - Layout.fillWidth: true - activeFocusOnTab: true - //: LABEL DESKTOP - text: qsTr("The internal card simulator allows to run an authentication in the test PKI without any ID card or card reader. Note that no other card reader can be used while the simulator is activated.") - textStyle: Style.text.hint_warning + //: LABEL DESKTOP + description: qsTr("The internal card simulator allows to run an authentication in the test PKI without any ID card or card reader. Note that no other card reader can be used while the simulator is activated.") + //: LABEL DESKTOP + title: qsTr("Internal card simulator") - FocusFrame { + onCheckedChanged: SettingsModel.enableSimulator = checked } - } - GCheckBox { - checked: SettingsModel.developerMode - - //: LABEL DESKTOP - text: qsTr("Developer mode") + LabeledSwitch { + checked: SettingsModel.developerMode - onCheckedChanged: SettingsModel.developerMode = checked - } - GText { - Layout.fillWidth: true - activeFocusOnTab: true - //: LABEL DESKTOP - text: qsTr("The developer mode is aimed at integrators / developers for new service applications. For this reason, the developer mode works only in the test PKI. By activating the developer mode, some safety tests are deactivated. This means that the authentication process continues although the AusweisApp2 would usually abort the process with an error message when used in normal operation mode. Information on the disregarded error in the developer mode is displayed in the attached window below the AusweisApp2.") - textStyle: Style.text.hint_warning + //: LABEL DESKTOP + description: qsTr("The developer mode deactivates some security checks and the authentication process will continue even if some errors occur. Skipped errors will be shown as notifications. The developer mode is only usable with the test PKI.").arg(Qt.application.name) + //: LABEL DESKTOP + title: qsTr("Developer mode") - FocusFrame { + onCheckedChanged: SettingsModel.developerMode = checked } } - GSeparator { + GPane { Layout.fillWidth: true - } - GText { - activeFocusOnTab: true - + spacing: Constants.component_spacing //: LABEL DESKTOP - text: qsTr("Custom config.json") - textStyle: Style.text.header_accent + title: qsTr("Custom config.json") - FocusFrame { - } - } - GText { - Layout.fillWidth: true - activeFocusOnTab: true + GText { + activeFocusOnTab: true - //: LABEL DESKTOP - text: qsTr("Place the config.json into the application folder to override the embedded config.") - textStyle: Style.text.normal + //: LABEL DESKTOP + text: qsTr("Place the config.json into the application folder to override the embedded config.") - FocusFrame { + FocusFrame { + } } - } - GText { - Layout.fillWidth: true + GText { + //: LABEL DESKTOP + text: qsTr("Application folder: %1").arg(ApplicationModel.customConfigPath) + } + GButton { + //: LABEL DESKTOP + text: qsTr("Save config.json") - //: LABEL DESKTOP - text: qsTr("Application folder: %1").arg(ApplicationModel.customConfigPath) - textStyle: Style.text.hint_secondary - } - GButton { - //: LABEL DESKTOP - text: qsTr("Save config.json") + onClicked: { + let filenameSuggestion = "config"; + fileDialog.selectFile(filenameSuggestion); + } - onClicked: { - let filenameSuggestion = "config"; - fileDialog.selectFile(filenameSuggestion); - } + GFileDialog { + id: fileDialog - GFileDialog { - id: fileDialog - defaultSuffix: "json" - folder: ApplicationModel.customConfigPath - //: LABEL DESKTOP - nameFilters: qsTr("JSON config (*.json)") + defaultSuffix: "json" + folder: ApplicationModel.customConfigPath + //: LABEL DESKTOP + nameFilters: qsTr("JSON config (*.json)") - //: LABEL DESKTOP - title: qsTr("Save config.json") + //: LABEL DESKTOP + title: qsTr("Save config.json") - onAccepted: ApplicationModel.saveEmbeddedConfig(file) + onAccepted: ApplicationModel.saveEmbeddedConfig(file) + } } } } diff --git a/resources/qml/Governikus/SettingsView/+desktop/GeneralSettings.qml b/resources/qml/Governikus/SettingsView/+desktop/GeneralSettings.qml index 410cd3cb5..e0d9550e9 100644 --- a/resources/qml/Governikus/SettingsView/+desktop/GeneralSettings.qml +++ b/resources/qml/Governikus/SettingsView/+desktop/GeneralSettings.qml @@ -1,109 +1,97 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.View 1.0 -import Governikus.Type.SettingsModel 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.View +import Governikus.Type.SettingsModel ColumnLayout { - readonly property string helpTopic: "settingsGeneral" - spacing: Constants.component_spacing - GText { - activeFocusOnTab: true - + GPane { + Layout.fillWidth: true + spacing: Constants.component_spacing //: LABEL DESKTOP - text: qsTr("Language selection") - textStyle: Style.text.header_accent + title: qsTr("Language selection") - FocusFrame { + LanguageButtons { + columns: 4 } } - LanguageButtons { - columns: 2 - } - GSeparator { + GPane { Layout.fillWidth: true - } - GText { - activeFocusOnTab: true - + spacing: Constants.component_spacing //: LABEL DESKTOP - text: qsTr("Behavior") - textStyle: Style.text.header_accent + title: qsTr("Appearance") - FocusFrame { + DarkModeButtons { + } + LabeledSwitch { + checked: SettingsModel.useSystemFont + + //: LABEL DESKTOP + description: qsTr("Toggling will restart the %1").arg(Qt.application.name) + //: LABEL DESKTOP + title: qsTr("Use the system font") + + onCheckedChanged: SettingsModel.useSystemFont = checked } } - GCheckBox { + GPane { Layout.fillWidth: true - checked: SettingsModel.autoStartApp - enabled: !SettingsModel.autoStartSetByAdmin && SettingsModel.autoStartAvailable - maximumLineCount: 2 - text: Qt.platform.os === "osx" ? - //: LABEL MACOS Text for auto-start option - qsTr("Auto-start %1 after boot and add to menu bar").arg(Qt.application.name) : - //: LABEL WINDOWS Text for auto-start option - qsTr("Auto-start %1 after boot").arg(Qt.application.name) - - onCheckedChanged: SettingsModel.autoStartApp = checked - } - GCheckBox { - checked: SettingsModel.autoCloseWindowAfterAuthentication - + spacing: Constants.component_spacing //: LABEL DESKTOP - text: qsTr("Close after authentication") + title: qsTr("Behavior") + + LabeledSwitch { + checked: SettingsModel.autoStartApp + enabled: !SettingsModel.autoStartSetByAdmin && SettingsModel.autoStartAvailable + title: Qt.platform.os === "osx" ? + //: LABEL MACOS Text for auto-start option + qsTr("Auto-start %1 after boot and add to menu bar").arg(Qt.application.name) : + //: LABEL WINDOWS Text for auto-start option + qsTr("Auto-start %1 after boot and add a tray icon").arg(Qt.application.name) + + onCheckedChanged: SettingsModel.autoStartApp = checked + } + LabeledSwitch { + checked: SettingsModel.autoCloseWindowAfterAuthentication - onCheckedChanged: SettingsModel.autoCloseWindowAfterAuthentication = checked - } - GCheckBox { - checked: SettingsModel.showInAppNotifications - enabled: !SettingsModel.developerMode + //: LABEL DESKTOP + title: qsTr("Close %1 after authentication").arg(Qt.application.name) - //: LABEL DESKTOP - text: qsTr("Use internal notifications") + onCheckedChanged: SettingsModel.autoCloseWindowAfterAuthentication = checked + } + LabeledSwitch { + checked: SettingsModel.showInAppNotifications - onCheckedChanged: SettingsModel.showInAppNotifications = checked - } - GText { - Layout.fillWidth: true - activeFocusOnTab: true + //: LABEL DESKTOP Only visible when the user activates the developer mode in the settings. + description: SettingsModel.developerMode ? qsTr("Using the developer mode forces the notifications to be enabled.") : "" + enabled: !SettingsModel.developerMode - //: LABEL DESKTOP Only visible when the user activates the developer mode in the settings. - text: qsTr("Using the developer mode forces the notifications to be enabled.") - textStyle: Style.text.hint_warning - visible: SettingsModel.developerMode + //: LABEL DESKTOP + title: qsTr("Show notifications inside of %1").arg(Qt.application.name) - FocusFrame { + onCheckedChanged: SettingsModel.showInAppNotifications = checked } } - GSeparator { + GPane { Layout.fillWidth: true - visible: customProxySetting.visible - } - GText { - activeFocusOnTab: true - + spacing: Constants.component_spacing //: LABEL DESKTOP - text: qsTr("Network") - textStyle: Style.text.header_accent - visible: customProxySetting.visible + title: qsTr("Network") + visible: SettingsModel.customProxyAttributesPresent - FocusFrame { - } - } - GCheckBox { - id: customProxySetting - checked: SettingsModel.useCustomProxy + LabeledSwitch { + checked: SettingsModel.useCustomProxy - //: LABEL DESKTOP - text: qsTr("Use the proxy (%1) specified during the installation.").arg(SettingsModel.customProxyUrl) - visible: SettingsModel.customProxyAttributesPresent + //: LABEL DESKTOP + title: qsTr("Use the proxy (%1) specified during the installation.").arg(SettingsModel.customProxyUrl) - onCheckedChanged: SettingsModel.useCustomProxy = checked + onCheckedChanged: SettingsModel.useCustomProxy = checked + } } } diff --git a/resources/qml/Governikus/SettingsView/+desktop/LanguageButtons.qml b/resources/qml/Governikus/SettingsView/+desktop/LanguageButtons.qml new file mode 100644 index 000000000..aee2e9c75 --- /dev/null +++ b/resources/qml/Governikus/SettingsView/+desktop/LanguageButtons.qml @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2022-2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick +import QtQuick.Layouts +import Governikus.Global + +GridLayout { + id: root + + signal buttonClicked + + columnSpacing: Constants.component_spacing + rowSpacing: Constants.component_spacing + + GRepeater { + id: repeater + + delegate: LocationButton { + Accessible.description: model.a11yDescription + Accessible.name: model.a11yName + Layout.fillWidth: true + Layout.preferredWidth: Constants.is_desktop ? repeater.maxItemWidth : -1 + image: model.image + language: model.language + text: model.text + + onClicked: root.buttonClicked() + } + model: LanguageButtonData { + } + } +} diff --git a/resources/qml/Governikus/SettingsView/+desktop/RemoteReaderDelegate.qml b/resources/qml/Governikus/SettingsView/+desktop/RemoteReaderDelegate.qml index 3b092bb3f..8c3c9f3cf 100644 --- a/resources/qml/Governikus/SettingsView/+desktop/RemoteReaderDelegate.qml +++ b/resources/qml/Governikus/SettingsView/+desktop/RemoteReaderDelegate.qml @@ -1,25 +1,24 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.RemoteServiceView 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.View 1.0 - -Item { +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.RemoteServiceView +import Governikus.View + +RoundedRectangle { id: root - property int iconHeight: ApplicationModel.scaleFactor * 80 + property int iconHeight: Style.dimens.icon_size signal pairDevice(string pDeviceId) signal unpairDevice(string pDeviceId) Accessible.name: { - var msg = qsTr("Smartphone named \"%1\"").arg(remoteDeviceName) + subtext.text; + let msg = qsTr("Smartphone named \"%1\"").arg(remoteDeviceName) + subtext.text; if (isPaired) { return msg + qsTr("Press space to unpair the smartphone \"%1\".").arg(remoteDeviceName); } @@ -27,7 +26,9 @@ Item { } Accessible.role: Accessible.Button activeFocusOnTab: true - implicitHeight: rowLayout.implicitHeight + color: Style.color.pane_sublevel + implicitHeight: rowLayout.implicitHeight + 2 * rowLayout.anchors.margins + implicitWidth: rowLayout.implicitWidth + 2 * rowLayout.anchors.margins Keys.onSpacePressed: isPaired ? unpairDevice(deviceId) : pairDevice(deviceId) @@ -35,8 +36,10 @@ Item { } RowLayout { id: rowLayout + + anchors.fill: parent + anchors.margins: Constants.pane_padding spacing: Constants.component_spacing - width: parent.width Column { Layout.fillWidth: true @@ -45,17 +48,18 @@ Item { elide: Text.ElideRight maximumLineCount: 1 text: remoteDeviceName - textStyle: Style.text.header + textStyle: Style.text.headline width: parent.width } GText { id: subtext + text: remoteDeviceStatus - textStyle: Style.text.normal width: parent.width } } Row { + Layout.alignment: Qt.AlignVCenter Layout.preferredHeight: iconHeight spacing: Constants.component_spacing @@ -66,14 +70,16 @@ Item { } TintableIcon { id: removeIcon + fillMode: Image.PreserveAspectFit - source: "qrc:///images/material_delete.svg" + source: "qrc:///images/trash_icon.svg" sourceSize.height: iconHeight - tintColor: Style.color.accent + tintColor: Style.color.control visible: isPaired && !isPairing MouseArea { id: trashMouse + ToolTip.delay: Constants.toolTipDelay ToolTip.text: qsTr("Remove remote device") ToolTip.visible: trashMouse.containsMouse diff --git a/resources/qml/Governikus/SettingsView/+desktop/RemoteReaderView.qml b/resources/qml/Governikus/SettingsView/+desktop/RemoteReaderView.qml index 397f2430c..f7b591d4d 100644 --- a/resources/qml/Governikus/SettingsView/+desktop/RemoteReaderView.qml +++ b/resources/qml/Governikus/SettingsView/+desktop/RemoteReaderView.qml @@ -1,23 +1,21 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.NumberModel 1.0 -import Governikus.Type.RemoteServiceModel 1.0 -import Governikus.Type.ReaderScanEnabler 1.0 -import Governikus.Type.ReaderPlugIn 1.0 -import Governikus.View 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.TitleBar +import Governikus.Type.ApplicationModel +import Governikus.Type.NumberModel +import Governikus.Type.RemoteServiceModel +import Governikus.Type.ReaderScanEnabler +import Governikus.Type.ReaderPlugIn +import Governikus.View Item { id: root - readonly property string helpTopic: "settingsRemoteReader" - signal pairDevice(string pDeviceId) signal unpairDevice(string pDeviceId) @@ -29,143 +27,132 @@ Item { } Column { id: column + anchors.fill: parent spacing: Constants.component_spacing - Column { + GPane { spacing: Constants.component_spacing + //: LABEL DESKTOP + title: qsTr("Paired devices") visible: availablePairedDevices.count > 0 width: parent.width - GText { - activeFocusOnTab: true - text: qsTr("Paired devices") - textStyle: Style.text.header_accent - width: parent.width - - FocusFrame { - } - } Repeater { id: availablePairedDevices + model: RemoteServiceModel.availablePairedDevices delegate: RemoteReaderDelegate { - width: parent.width + Layout.fillWidth: true onUnpairDevice: pDeviceId => root.unpairDevice(pDeviceId) } } } - Column { + GPane { spacing: Constants.component_spacing + + //: LABEL DESKTOP + title: qsTr("Last connected") visible: unavailablePairedDevices.count > 0 width: parent.width - GText { - activeFocusOnTab: true - text: qsTr("Last connected") - textStyle: Style.text.header_accent - width: parent.width - - FocusFrame { - } - } Repeater { id: unavailablePairedDevices + model: RemoteServiceModel.unavailablePairedDevices delegate: RemoteReaderDelegate { - width: parent.width + Layout.fillWidth: true onUnpairDevice: pDeviceId => root.unpairDevice(pDeviceId) } } } - GSeparator { - visible: availablePairedDevices.count > 0 || unavailablePairedDevices.count > 0 - width: parent.width - } - GText { - activeFocusOnTab: true - text: qsTr("Add pairing") - textStyle: Style.text.header_accent - width: parent.width + GPane { + spacing: Constants.component_spacing - FocusFrame { - } - } - GListView { - id: availableDevices - height: contentHeight - model: RemoteServiceModel.availableDevicesInPairingMode + //: LABEL DESKTOP + title: qsTr("Add pairing") width: parent.width - delegate: RemoteReaderDelegate { - height: implicitHeight + Constants.pane_padding - width: availableDevices.width + GListView { + id: availableDevices - onPairDevice: pDeviceId => root.pairDevice(pDeviceId) - } - } - Column { - spacing: Constants.text_spacing - visible: availableDevices.count === 0 - width: parent.width + Layout.fillWidth: true + implicitHeight: contentHeight + model: RemoteServiceModel.availableDevicesInPairingMode - Repeater { - model: [ - //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 4. %1 is a placeholder-tag for the app name. - qsTr("Ensure that the %1 on your Smartphone as card reader has at least version %2.").arg(Qt.application.name).arg(Qt.application.version), - //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 4. %1 is a placeholder-tag for the app name. - qsTr("Open the %1 on your Smartphone as card reader.").arg(Qt.application.name), - //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 4. %1 and %2 are surrounding tags for bold font - qsTr("On that device go to %1Card reader%2 and then %1Pair device%2 rsp. %1Pair new device%2.").arg("").arg(""), - //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 4 of 4 - qsTr("Choose the device in the list to pair it.")] - - RowLayout { - spacing: Constants.component_spacing - width: parent.width - - GText { - Accessible.ignored: true - Layout.alignment: Qt.AlignTop - text: (index + 1) + "." - } - GText { - Accessible.name: (index + 1) + ". " + ApplicationModel.stripHtmlTags(modelData) - Layout.alignment: Qt.AlignTop - Layout.fillWidth: true - activeFocusOnTab: true - text: modelData - - FocusFrame { + delegate: RemoteReaderDelegate { + height: implicitHeight + Constants.pane_padding + width: availableDevices.width + + onPairDevice: pDeviceId => root.pairDevice(pDeviceId) + } + } + Column { + Layout.fillWidth: true + spacing: Constants.text_spacing + visible: availableDevices.count === 0 + + Repeater { + model: [ + //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 4. %1 is a placeholder-tag for the app name. + qsTr("Ensure that the %1 on your Smartphone as card reader has at least version %2.").arg(Qt.application.name).arg("1.26.5"), + //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 4. %1 is a placeholder-tag for the app name. + qsTr("Open the %1 on your Smartphone as card reader.").arg(Qt.application.name), + //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 4. %1 and %2 are surrounding tags for bold font + qsTr("On that device go to %1Card reader%2 and then %1Pair device%2 rsp. %1Pair new device%2.").arg("").arg(""), + //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 4 of 4 + qsTr("Choose the device in the list to pair it.")] + + RowLayout { + spacing: Constants.component_spacing + width: parent.width + + GText { + Accessible.ignored: true + Layout.alignment: Qt.AlignTop + text: (index + 1) + "." + } + GText { + Accessible.name: (index + 1) + ". " + ApplicationModel.stripHtmlTags(modelData) + Layout.alignment: Qt.AlignTop + Layout.maximumWidth: Number.POSITIVE_INFINITY + activeFocusOnTab: true + text: modelData + + FocusFrame { + } } } } } - } - RowLayout { - spacing: Constants.text_spacing - visible: availableDevices.count === 0 - width: parent.width - - TintableIcon { - source: "qrc:/images/info.svg" - sourceSize.height: Style.dimens.icon_size - tintColor: Style.color.accent + GSeparator { + Layout.fillWidth: true + visible: availableDevices.count === 0 } - GText { - Layout.alignment: Qt.AlignVCenter + RowLayout { Layout.fillWidth: true - activeFocusOnTab: true - text: qsTr("Both devices have to be connected to the same WiFi.") - textStyle: Style.text.hint - verticalAlignment: Text.AlignBottom - wrapMode: Text.WordWrap + spacing: Constants.component_spacing + visible: availableDevices.count === 0 - FocusFrame { + TintableIcon { + source: "qrc:/images/info.svg" + sourceSize.height: Style.dimens.large_icon_size + tintColor: Style.color.control + } + GText { + Layout.alignment: Qt.AlignVCenter + activeFocusOnTab: true + color: Style.color.control + text: qsTr("Both devices have to be connected to the same WiFi.") + verticalAlignment: Text.AlignBottom + wrapMode: Text.WordWrap + + FocusFrame { + } } } } diff --git a/resources/qml/Governikus/SettingsView/+desktop/SecurityAndPrivacySettings.qml b/resources/qml/Governikus/SettingsView/+desktop/SecurityAndPrivacySettings.qml index 229ef7474..681b72df2 100644 --- a/resources/qml/Governikus/SettingsView/+desktop/SecurityAndPrivacySettings.qml +++ b/resources/qml/Governikus/SettingsView/+desktop/SecurityAndPrivacySettings.qml @@ -1,164 +1,108 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.SettingsModel 1.0 -import Governikus.Type.HistoryModel 1.0 -import Governikus.View 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.Type.ApplicationModel +import Governikus.Type.SettingsModel +import Governikus.View ColumnLayout { - readonly property string helpTopic: "settingsSecurityPrivacy" - spacing: Constants.component_spacing - GText { - activeFocusOnTab: true - - //: LABEL DESKTOP - text: qsTr("History") - textStyle: Style.text.header_accent - - FocusFrame { - } - } - GCheckBox { - checked: SettingsModel.historyEnabled - - //: LABEL DESKTOP - text: qsTr("Save authentication history") - - onCheckedChanged: SettingsModel.historyEnabled = checked - } - GButton { - disabledTooltipText: qsTr("History is empty") - enableButton: !HistoryModel.empty - //: LABEL DESKTOP - text: qsTr("Clear entire history") - - onClicked: confirmationPopup.open() - } - GSeparator { + GPane { Layout.fillWidth: true - } - GText { - activeFocusOnTab: true - + spacing: Constants.component_spacing //: LABEL DESKTOP - text: qsTr("Onscreen keypad") - textStyle: Style.text.header_accent + title: qsTr("Onscreen keypad") - FocusFrame { - } - } - GCheckBox { - checked: SettingsModel.useScreenKeyboard + LabeledSwitch { + checked: SettingsModel.useScreenKeyboard - //: LABEL DESKTOP - text: qsTr("Use on screen keypad for PIN entry") + //: LABEL DESKTOP + title: qsTr("Use on screen keypad for PIN entry") - onCheckedChanged: SettingsModel.useScreenKeyboard = checked - } - GCheckBox { - checked: SettingsModel.shuffleScreenKeyboard - enabled: SettingsModel.useScreenKeyboard + onCheckedChanged: SettingsModel.useScreenKeyboard = checked + } + LabeledSwitch { + checked: SettingsModel.shuffleScreenKeyboard + enabled: SettingsModel.useScreenKeyboard - //: LABEL DESKTOP - text: qsTr("Shuffle keypad buttons") + //: LABEL DESKTOP + title: qsTr("Shuffle digits of on screen keypad") - onCheckedChanged: SettingsModel.shuffleScreenKeyboard = checked - } - GCheckBox { - checked: !SettingsModel.visualPrivacy - enabled: SettingsModel.useScreenKeyboard + onCheckedChanged: SettingsModel.shuffleScreenKeyboard = checked + } + LabeledSwitch { + checked: !SettingsModel.visualPrivacy + //: LABEL DESKTOP + description: qsTr("Visually highlight key presses on screen keypad") + enabled: SettingsModel.useScreenKeyboard - //: LABEL DESKTOP - text: qsTr("Visual feedback when pressing keypad buttons") + //: LABEL DESKTOP + title: qsTr("Button animation") - onCheckedChanged: SettingsModel.visualPrivacy = !checked + onCheckedChanged: SettingsModel.visualPrivacy = !checked + } } - GSeparator { + GPane { Layout.fillWidth: true - visible: SettingsModel.autoUpdateAvailable - } - GText { - activeFocusOnTab: true - + spacing: Constants.component_spacing //: LABEL DESKTOP - text: qsTr("Software updates") - textStyle: Style.text.header_accent + title: qsTr("Software updates") visible: SettingsModel.autoUpdateAvailable - FocusFrame { - } - } - GCheckBox { - checked: SettingsModel.autoUpdateCheck - enabled: !SettingsModel.autoUpdateCheckSetByAdmin + LabeledSwitch { + checked: SettingsModel.autoUpdateCheck + enabled: !SettingsModel.autoUpdateCheckSetByAdmin - //: LABEL DESKTOP - text: qsTr("Check at program start") - visible: SettingsModel.autoUpdateAvailable + //: LABEL DESKTOP + title: qsTr("Check at program start") - onCheckedChanged: SettingsModel.autoUpdateCheck = checked - } - RowLayout { - readonly property bool updateAvailable: SettingsModel.appUpdateData.updateAvailable - readonly property bool updateValid: SettingsModel.appUpdateData.valid + onCheckedChanged: SettingsModel.autoUpdateCheck = checked + } + RowLayout { + readonly property bool updateAvailable: SettingsModel.appUpdateData.updateAvailable + readonly property bool updateValid: SettingsModel.appUpdateData.valid - Layout.fillWidth: true - spacing: Constants.component_spacing - visible: SettingsModel.autoUpdateAvailable + Layout.fillWidth: true + spacing: Constants.component_spacing - GButton { - text: (parent.updateAvailable ? - //: LABEL DESKTOP - qsTr("Show update") : - //: LABEL DESKTOP - qsTr("Check now")) + GButton { + text: (parent.updateAvailable ? + //: LABEL DESKTOP + qsTr("Show update") : + //: LABEL DESKTOP + qsTr("Check now")) - onClicked: SettingsModel.updateAppcast() - } - GText { - Layout.fillWidth: true - activeFocusOnTab: true - text: { - if (parent.updateAvailable && parent.updateValid) { - //: LABEL DESKTOP An update is available, the new version is supplied to the user. - return qsTr("An update is available (version %1)!").arg(SettingsModel.appUpdateData.version); - } else if (parent.updateAvailable && !parent.updateValid) { - //: LABEL DESKTOP The updater found an update but not all required update information are valid, this should be a very rare case. - return qsTr("An update is available but retrieving the information failed."); - } else if (!parent.updateAvailable && parent.updateValid) { - //: LABEL DESKTOP The current version is up to date, no user action is required. - return qsTr("Your version %1 of %2 is up to date.").arg(Qt.application.version).arg(Qt.application.name); - } else { - //: LABEL DESKTOP The automatic update check is disabled (or no network connection was present during app start), a manual check for update is required. - return qsTr("No update information available, please check for update manually."); - } + onClicked: SettingsModel.updateAppcast() } - textStyle: (parent.updateAvailable || !parent.updateValid) ? Style.text.normal_warning : Style.text.normal_accent + GText { + activeFocusOnTab: true + color: (parent.updateAvailable || !parent.updateValid) ? Style.color.text_warning : Style.color.control + text: { + if (parent.updateAvailable && parent.updateValid) { + //: LABEL DESKTOP An update is available, the new version is supplied to the user. + return qsTr("An update is available (version %1)!").arg(SettingsModel.appUpdateData.version); + } else if (parent.updateAvailable && !parent.updateValid) { + //: LABEL DESKTOP The updater found an update but not all required update information are valid, this should be a very rare case. + return qsTr("An update is available but retrieving the information failed."); + } else if (!parent.updateAvailable && parent.updateValid) { + //: LABEL DESKTOP The current version is up to date, no user action is required. + return qsTr("Your version %1 of %2 is up to date.").arg(Qt.application.version).arg(Qt.application.name); + } else { + //: LABEL DESKTOP The automatic update check is disabled (or no network connection was present during app start), a manual check for update is required. + return qsTr("No update information available, please check for update manually."); + } + } + textStyle: Style.text.normal - FocusFrame { + FocusFrame { + } } } } - ConfirmationPopup { - id: confirmationPopup - //: INFO DESKTOP The current history is about to be removed, user confirmation required. - text: qsTr("All history entries will be deleted.") - - //: LABEL DESKTOP - title: qsTr("Delete history") - - onConfirmed: { - let removedItemCount = SettingsModel.removeEntireHistory(); - //: INFO DESKTOP Feedback how many history entries were removed. - ApplicationModel.showFeedback(qsTr("Deleted %1 entries from the history.").arg(removedItemCount)); - } - } } diff --git a/resources/qml/Governikus/SettingsView/+desktop/SettingsView.qml b/resources/qml/Governikus/SettingsView/+desktop/SettingsView.qml index 0a8b60764..08b8dbff4 100644 --- a/resources/qml/Governikus/SettingsView/+desktop/SettingsView.qml +++ b/resources/qml/Governikus/SettingsView/+desktop/SettingsView.qml @@ -1,19 +1,20 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQml.Models 2.15 -import Governikus.Global 1.0 -import Governikus.View 1.0 -import Governikus.TitleBar 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.SettingsModel 1.0 -import Governikus.Type.UiModule 1.0 -import Governikus.Type.RemoteServiceModel 1.0 -import Governikus.UpdateView 1.0 +import QtQuick +import QtQml.Models +import Governikus.Global +import Governikus.View +import Governikus.TitleBar +import Governikus.Type.ApplicationModel +import Governikus.Type.SettingsModel +import Governikus.Type.UiModule +import Governikus.Type.RemoteServiceModel +import Governikus.UpdateView SectionPage { id: sectionPage + enum SubView { None, ConnectSacView, @@ -22,17 +23,10 @@ SectionPage { titleBarAction: TitleBarAction { id: titleBarAction - helpTopic: Utils.helpTopicOf(tabbedPane.currentContentItem, "settings") //: LABEL DESKTOP text: qsTr("Settings") - customSubAction: CancelAction { - visible: d.view === SettingsView.SubView.EnterPassword || d.view === SettingsView.SubView.WaitForPairing - - onClicked: d.view = SettingsView.SubView.None - } - onClicked: { d.view = SettingsView.SubView.None; } @@ -61,10 +55,10 @@ SectionPage { } TabbedPane { id: tabbedPane + anchors.fill: parent - anchors.margins: Constants.pane_spacing sectionsModel: { - var model = [ + let model = [ //: LABEL DESKTOP qsTr("General"), //: LABEL DESKTOP @@ -90,13 +84,17 @@ SectionPage { contentObjectModel: ObjectModel { Component { GeneralSettings { + Connections { + function onFireUseSystemFontChanged() { + sectionPage.nextView(UiModule.DEFAULT); + } + + target: SettingsModel + } } } Component { RemoteReaderView { - height: Math.max(implicitHeight, tabbedPane.availableHeight) - width: parent.width - onPairDevice: pDeviceId => { if (RemoteServiceModel.rememberServer(pDeviceId)) { d.view = SettingsView.SubView.ConnectSacView; @@ -108,8 +106,6 @@ SectionPage { } Component { CardReaderView { - height: Math.max(implicitHeight, tabbedPane.availableHeight) - width: parent.width } } Component { @@ -117,9 +113,6 @@ SectionPage { } } } - sectionDelegate: TabbedPaneDelegateText { - sectionName: model ? model.modelData : "" - } Component.onCompleted: { if (plugin.debugBuild) { @@ -132,11 +125,13 @@ SectionPage { Component { id: debugSettings + DebugSettings { } } Component { id: developerSettings + DeveloperSettings { } } @@ -149,6 +144,7 @@ SectionPage { } ConnectSacView { id: connectSacView + rootEnabled: titleBarAction.rootEnabled visible: d.view === SettingsView.SubView.ConnectSacView diff --git a/resources/qml/Governikus/SettingsView/+desktop/TabbedReaderView.qml b/resources/qml/Governikus/SettingsView/+desktop/TabbedReaderView.qml index e91d03cdf..16d088124 100644 --- a/resources/qml/Governikus/SettingsView/+desktop/TabbedReaderView.qml +++ b/resources/qml/Governikus/SettingsView/+desktop/TabbedReaderView.qml @@ -1,17 +1,18 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQml.Models 2.15 -import Governikus.Global 1.0 -import Governikus.TitleBar 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.NumberModel 1.0 -import Governikus.Type.RemoteServiceModel 1.0 -import Governikus.View 1.0 +import QtQuick +import QtQml.Models +import Governikus.Global +import Governikus.TitleBar +import Governikus.Type.ApplicationModel +import Governikus.Type.NumberModel +import Governikus.Type.RemoteServiceModel +import Governikus.View SectionPage { id: root + enum SubView { None, ConnectSacView @@ -27,13 +28,13 @@ SectionPage { titleBarAction: TitleBarAction { id: titleBarAction - helpTopic: Utils.helpTopicOf(tabbedPane.currentContentItem, "settings") + rootEnabled: false //: LABEL DESKTOP text: qsTr("Card Readers") - customSubAction: CancelAction { + customSubAction: NavigationAction { onClicked: closeView() } @@ -57,6 +58,7 @@ SectionPage { } TabbedPane { id: tabbedPane + sectionsModel: [qsTr("Smartphone as card reader"), qsTr("USB card reader")] visible: d.view === TabbedReaderView.SubView.None @@ -105,6 +107,7 @@ SectionPage { } ConnectSacView { id: connectSacView + rootEnabled: root.rootEnabled visible: d.view === TabbedReaderView.SubView.ConnectSacView diff --git a/resources/qml/Governikus/SettingsView/+mobile/DarkModeButtons.qml b/resources/qml/Governikus/SettingsView/+mobile/DarkModeButtons.qml new file mode 100644 index 000000000..4fdeb6d6c --- /dev/null +++ b/resources/qml/Governikus/SettingsView/+mobile/DarkModeButtons.qml @@ -0,0 +1,78 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Type.SettingsModel +import Governikus.Type.ModeOption + +ColumnLayout { + id: root + + readonly property var checkedButton: system.mode === SettingsModel.userDarkMode ? system : dark.mode === SettingsModel.userDarkMode ? dark : light + readonly property string selectedIconPath: checkedButton.image + readonly property string selectedText: checkedButton.title + + signal buttonClicked + + function onAppearanceButtonClicked(mode) { + if (SettingsModel.userDarkMode === mode) + return; + SettingsModel.userDarkMode = mode; + root.buttonClicked(); + } + + spacing: Constants.groupbox_spacing + + Component.onCompleted: { + if (!plugin.osDarkModeSupported) + system.visible = false; + } + + GCollapsibleSubButton { + id: system + + readonly property var mode: ModeOption.AUTO + + //: LABEL ALL_PLATFORMS + Accessible.description: qsTr("Set the app appearance to system mode") + Layout.fillWidth: true + image: "qrc:///images/appearance_system_mode.svg" + tintIcon: true + //: LABEL ALL_PLATFORMS + title: qsTr("System") + + onClicked: root.onAppearanceButtonClicked(mode) + } + GCollapsibleSubButton { + id: dark + + readonly property var mode: ModeOption.ON + + //: LABEL ALL_PLATFORMS + Accessible.description: qsTr("Set the app appearance to dark mode") + Layout.fillWidth: true + image: "qrc:///images/appearance_dark_mode.svg" + tintIcon: true + //: LABEL ALL_PLATFORMS + title: qsTr("Dark") + + onClicked: root.onAppearanceButtonClicked(mode) + } + GCollapsibleSubButton { + id: light + + readonly property var mode: ModeOption.OFF + + //: LABEL ALL_PLATFORMS + Accessible.description: qsTr("Set the app appearance to light mode") + Layout.fillWidth: true + image: "qrc:///images/appearance_light_mode.svg" + tintIcon: true + //: LABEL ALL_PLATFORMS + title: qsTr("Light") + + onClicked: root.onAppearanceButtonClicked(mode) + } +} diff --git a/resources/qml/Governikus/SettingsView/+mobile/LanguageSelectionPopup.qml b/resources/qml/Governikus/SettingsView/+mobile/LanguageSelectionPopup.qml deleted file mode 100644 index 752f86068..000000000 --- a/resources/qml/Governikus/SettingsView/+mobile/LanguageSelectionPopup.qml +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.SettingsView 1.0 -import Governikus.Style 1.0 - -ConfirmationPopup { - id: baseItem - style: ConfirmationPopup.PopupStyle.CancelButton - - //: LABEL ANDROID IOS - title: qsTr("Select language") - - LanguageButtons { - columns: 1 - - onButtonClicked: baseItem.close() - } -} diff --git a/resources/qml/Governikus/SettingsView/+mobile/ScreenOrientationSelectionPopup.qml b/resources/qml/Governikus/SettingsView/+mobile/ScreenOrientationSelectionPopup.qml deleted file mode 100644 index f025bce9d..000000000 --- a/resources/qml/Governikus/SettingsView/+mobile/ScreenOrientationSelectionPopup.qml +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import QtQuick.Window 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 - -ConfirmationPopup { - style: ConfirmationPopup.PopupStyle.OkButton - //: LABEL ANDROID - title: qsTr("Select screen orientation") - - onConfirmed: { - if (phone.checked && plugin.isTabletLayout) { - plugin.applyPlatformStyle("mobile,phone," + Qt.platform.os); - } - if (tablet.checked && !plugin.isTabletLayout) { - plugin.applyPlatformStyle("mobile,tablet," + Qt.platform.os); - } - } - - Column { - spacing: Constants.component_spacing - width: parent.width - - GRadioButton { - id: phone - - //: LABEL ANDROID - Accessible.description: qsTr("Set screen orientation to portrait") - checked: !plugin.isTabletLayout - icon.source: "qrc:///images/android/stay_primary_portrait-24px.svg" - //: LABEL ANDROID - text: qsTr("Portrait") + (plugin.tablet ? "" : (" (%1)".arg(qsTr("recommended")))) - tintIcon: true - width: parent.width - } - GRadioButton { - id: tablet - - //: LABEL ANDROID - Accessible.description: qsTr("Set screen orientation to landscape") - checked: plugin.isTabletLayout - icon.source: "qrc:///images/android/stay_primary_landscape-24px.svg" - //: LABEL ANDROID - text: qsTr("Landscape") + (plugin.tablet ? (" (%1)".arg(qsTr("recommended"))) : "") - tintIcon: true - width: parent.width - } - GText { - - //: LABEL ANDROID - text: qsTr("Using a screen orientation unfit for your device may result in display errors.") - textStyle: Style.text.normal_warning - visible: tablet.checked && !plugin.tablet - width: parent.width - } - } -} diff --git a/resources/qml/Governikus/SettingsView/+mobile/SettingsView.qml b/resources/qml/Governikus/SettingsView/+mobile/SettingsView.qml index e72033ddd..f0b3896bf 100644 --- a/resources/qml/Governikus/SettingsView/+mobile/SettingsView.qml +++ b/resources/qml/Governikus/SettingsView/+mobile/SettingsView.qml @@ -1,25 +1,27 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import QtQuick.Window 2.15 -import Governikus.Global 1.0 -import Governikus.HistoryView 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 -import Governikus.RemoteServiceView 1.0 -import Governikus.Type.SettingsModel 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.RemoteServiceModel 1.0 -import Governikus.Type.HistoryModel 1.0 -import Governikus.Type.LogModel 1.0 -import Governikus.Type.WorkflowModel 1.0 - -SectionPage { +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Window +import Governikus.Global +import Governikus.Style +import Governikus.TitleBar +import Governikus.View +import Governikus.RemoteServiceView +import Governikus.SmartView +import Governikus.Type.SettingsModel +import Governikus.Type.ApplicationModel +import Governikus.Type.RemoteServiceModel +import Governikus.Type.LogModel +import Governikus.Type.ModeOption +import Governikus.Type.WorkflowModel +import Governikus.Type.SmartModel + +FlickableSectionPage { id: baseItem + function platformId(pName) { return "mobile," + pName.replace(" ", "").toLowerCase(); } @@ -27,227 +29,284 @@ SectionPage { //: LABEL ANDROID IOS title: qsTr("Settings") - content: Column { - id: mainColumn - spacing: 0 - width: baseItem.width + ColumnLayout { + Layout.fillWidth: true + spacing: Constants.component_spacing - TitledSeparator { - contentMarginTop: Constants.component_spacing + GOptionsContainer { + Layout.fillWidth: true //: LABEL ANDROID IOS title: qsTr("General") - width: parent.width - } - MenuItem { - description: { - switch (SettingsModel.language) { - case "de": - return "Deutsch"; - case "ru": - return "Русский"; - case "uk": - return "Українська"; - default: - return "English"; + + GCollapsible { + id: languageCollapsible + + contentBottomMargin: 0 + contentSpacing: 0 + contentTopMargin: 0 + drawTopCorners: true + selectionIcon: "qrc:///images/location_flag_%1.svg".arg(SettingsModel.language) + selectionTitle: { + switch (SettingsModel.language) { + case "de": + return "Deutsch"; + case "ru": + return "Русский"; + case "uk": + return "Українська"; + default: + return "English"; + } + } + //: LABEL ANDROID IOS + title: qsTr("Change language") + width: parent.width + + GRepeater { + id: repeater + + delegate: GCollapsibleSubButton { + Accessible.description: model.a11yDescription + Accessible.name: model.a11yName + Layout.fillWidth: true + image: model.image + title: model.text + + onClicked: { + SettingsModel.language = model.language; + languageCollapsible.expanded = false; + } + } + model: LanguageButtonData { + } } } - icon: "qrc:///images/location_flag_%1.svg".arg(SettingsModel.language) - tintIcon: false - //: LABEL ANDROID IOS - title: qsTr("Change language") - width: parent.width + GSeparator { + anchors.left: parent.left + anchors.leftMargin: Constants.component_spacing + anchors.right: parent.right + anchors.rightMargin: Constants.component_spacing + } + GCollapsible { + id: appearanceCollapsible + + contentBottomMargin: 0 + contentSpacing: 0 + contentTopMargin: 0 + selectionIcon: modeButtons.selectedIconPath + selectionTitle: modeButtons.selectedText + tintIcon: true + //: LABEL ANDROID IOS + title: qsTr("Appearance") + width: parent.width + + DarkModeButtons { + id: modeButtons - onClicked: popup.open() + width: parent.width - LanguageSelectionPopup { - id: popup + onButtonClicked: appearanceCollapsible.expanded = false + } } - } - MenuItem { - description: (plugin.isTabletLayout ? - //: LABEL ANDROID - qsTr("Landscape") : - //: LABEL ANDROID - qsTr("Portrait")) - icon: plugin.isTabletLayout ? "qrc:///images/android/stay_primary_landscape-24px.svg" : "qrc:///images/android/stay_primary_portrait-24px.svg" - tintIcon: true - //: LABEL ANDROID - title: qsTr("Screen orientation") - visible: Constants.is_layout_android - width: parent.width - - onClicked: orientationPopup.open() - - ScreenOrientationSelectionPopup { - id: orientationPopup + GSeparator { + anchors.left: parent.left + anchors.leftMargin: Constants.component_spacing + anchors.right: parent.right + anchors.rightMargin: Constants.component_spacing + } + LabeledSwitch { + //: LABEL ANDROID IOS + description: qsTr("Toggling will restart the %1").arg(Qt.application.name) + drawBottomCorners: true + + //: LABEL ANDROID IOS + title: qsTr("Use system font") + width: parent.width + + Component.onCompleted: { + checked = SettingsModel.useSystemFont; + } + onCheckedChanged: { + if (checked !== SettingsModel.useSystemFont) { + SettingsModel.useSystemFont = checked; + plugin.doRefresh(); + } + } } } - TitledSeparator { + GOptionsContainer { + Layout.fillWidth: true //: LABEL ANDROID IOS title: qsTr("Smartphone as card reader") - width: parent.width - } - ColumnLayout { - id: serverNameBase - Accessible.focusable: true - Accessible.name: serverNameText.text - Accessible.role: Accessible.Grouping - width: parent.width - - GText { - id: serverNameText - Accessible.ignored: true - Layout.fillWidth: true - Layout.leftMargin: Constants.component_spacing - Layout.rightMargin: Constants.component_spacing - Layout.topMargin: Constants.component_spacing / 2 + GCollapsible { + alwaysReserveSelectionTitleHight: true + contentBottomMargin: 0 + contentTopMargin: 0 + drawTopCorners: true + selectionTitle: expanded ? "" : SettingsModel.serverName //: LABEL ANDROID IOS - text: qsTr("Device name") - textStyle: Style.text.normal_accent - } - GTextField { - id: serverName - function saveInput() { - focus = false; - SettingsModel.serverName = text; - } + title: qsTr("Device name") + width: parent.width + + GTextField { + id: serverName + + function saveInput() { + focus = false; + SettingsModel.serverName = text; + } - Layout.bottomMargin: Constants.component_spacing / 2 - Layout.fillWidth: true - Layout.leftMargin: Constants.component_spacing - Layout.rightMargin: Constants.component_spacing - maximumLength: Constants.maximumDeviceNameLength - text: SettingsModel.serverName + Layout.fillWidth: true + Layout.margins: Constants.component_spacing + maximumLength: Constants.maximumDeviceNameLength + text: SettingsModel.serverName - onAccepted: saveInput() - onFocusChanged: if (!focus) - saveInput() + onAccepted: saveInput() + onFocusChanged: if (!focus) + saveInput() + } } - } - LabeledSwitch { - checked: SettingsModel.pinPadMode - //: LABEL ANDROID IOS - description: qsTr("Enter PIN on this device") + GSeparator { + anchors.left: parent.left + anchors.leftMargin: Constants.component_spacing + anchors.right: parent.right + anchors.rightMargin: Constants.component_spacing + } + LabeledSwitch { + checked: SettingsModel.pinPadMode - //: LABEL ANDROID IOS - title: qsTr("PIN pad mode") - width: parent.width + //: LABEL ANDROID IOS + title: qsTr("Enter PIN on this device") + width: parent.width - onCheckedChanged: SettingsModel.pinPadMode = checked - } - LabeledSwitch { - checked: SettingsModel.showAccessRights - //: LABEL ANDROID IOS - description: qsTr("Show requested rights on this device as well") - enabled: SettingsModel.pinPadMode + onCheckedChanged: SettingsModel.pinPadMode = checked + } + GSeparator { + anchors.left: parent.left + anchors.leftMargin: Constants.component_spacing + anchors.right: parent.right + anchors.rightMargin: Constants.component_spacing + } + LabeledSwitch { + checked: SettingsModel.showAccessRights + enabled: SettingsModel.pinPadMode - //: LABEL ANDROID IOS - title: qsTr("Show access rights") - width: parent.width + //: LABEL ANDROID IOS + title: qsTr("Show requested rights on this device as well") + width: parent.width - onCheckedChanged: SettingsModel.showAccessRights = checked - } - MenuItem { - //: LABEL ANDROID IOS - description: qsTr("Manage paired devices and add new devices") + onCheckedChanged: SettingsModel.showAccessRights = checked + } + GSeparator { + anchors.left: parent.left + anchors.leftMargin: Constants.component_spacing + anchors.right: parent.right + anchors.rightMargin: Constants.component_spacing + } + MenuItem { + //: LABEL ANDROID IOS + description: qsTr("Add and remove devices") + drawBottomCorners: true - //: LABEL ANDROID IOS - title: qsTr("Manage pairings") - width: parent.width + //: LABEL ANDROID IOS + title: qsTr("Manage pairings") + width: parent.width + + onClicked: push(remoteServiceSettings) - onClicked: push(remoteServiceSettings) + Component { + id: remoteServiceSettings - Component { - id: remoteServiceSettings - RemoteServiceSettings { - Component.onCompleted: RemoteServiceModel.detectRemoteDevices = true - Component.onDestruction: RemoteServiceModel.detectRemoteDevices = false + RemoteServiceSettings { + Component.onCompleted: RemoteServiceModel.detectRemoteDevices = true + Component.onDestruction: RemoteServiceModel.detectRemoteDevices = false + } } } } - TitledSeparator { - + GOptionsContainer { + Layout.fillWidth: true //: LABEL ANDROID IOS title: qsTr("Security and privacy") - width: parent.width - } - LabeledSwitch { - checked: SettingsModel.historyEnabled - //: LABEL ANDROID IOS - description: qsTr("Save authentication history") - //: LABEL ANDROID IOS - title: qsTr("Save history") - width: parent.width + LabeledSwitch { + checked: SettingsModel.shuffleScreenKeyboard + drawTopCorners: true - onCheckedChanged: SettingsModel.historyEnabled = checked - } - MenuItem { - //: LABEL ANDROID IOS - description: qsTr("View authentication history") + //: LABEL ANDROID IOS + title: qsTr("Randomize the order of the on screen keypad buttons") + width: parent.width - //: LABEL ANDROID IOS - title: qsTr("History") - visible: WorkflowModel.isSmartSupported - width: parent.width + onCheckedChanged: SettingsModel.shuffleScreenKeyboard = checked + } + GSeparator { + anchors.left: parent.left + anchors.leftMargin: Constants.component_spacing + anchors.right: parent.right + anchors.rightMargin: Constants.component_spacing + } + LabeledSwitch { + checked: !SettingsModel.visualPrivacy + //: LABEL ANDROID IOS + description: qsTr("Visually highlight key presses on screen keypad") + drawBottomCorners: true - onClicked: push(historyView) + //: LABEL ANDROID IOS + title: qsTr("Keypad animations") + width: parent.width - Component { - id: historyView - HistoryView { - } + onCheckedChanged: SettingsModel.visualPrivacy = !checked } } - LabeledSwitch { - checked: SettingsModel.shuffleScreenKeyboard + GOptionsContainer { + Layout.fillWidth: true //: LABEL ANDROID IOS - description: qsTr("Randomize the order of the on screen keypad buttons") + title: qsTr("Smart-eID") + visible: WorkflowModel.isSmartSupported - //: LABEL ANDROID IOS - title: qsTr("Shuffle keypad buttons") - width: parent.width + MenuItem { + //: LABEL ANDROID IOS + description: qsTr("Reset Smart-eID data on your device") + //: LABEL ANDROID IOS + title: qsTr("Reset Smart-eID") + width: parent.width - onCheckedChanged: SettingsModel.shuffleScreenKeyboard = checked - } - LabeledSwitch { - checked: !SettingsModel.visualPrivacy - //: LABEL ANDROID IOS - description: qsTr("Visual feedback when pressing keypad buttons") + onClicked: push(smartDeleteView) - //: LABEL ANDROID IOS - title: qsTr("Keypad animations") - width: parent.width + Component { + id: smartDeleteView - onCheckedChanged: SettingsModel.visualPrivacy = !checked + SmartResetView { + } + } + } } - Column { - spacing: parent.spacing + GOptionsContainer { + Layout.fillWidth: true + //: LABEL ANDROID IOS + title: qsTr("On-site reading") visible: SettingsModel.advancedSettings - width: parent.width - TitledSeparator { - - //: LABEL ANDROID IOS - title: qsTr("CAN allowed mode") - width: parent.width - } LabeledSwitch { checked: SettingsModel.enableCanAllowed - //: LABEL ANDROID IOS - description: qsTr("Allow the id card to be used with only the CAN") + drawTopCorners: true //: LABEL ANDROID IOS - title: qsTr("Support CAN allowed mode") + title: qsTr("Support CAN allowed mode for on-site reading") width: parent.width onCheckedChanged: SettingsModel.enableCanAllowed = checked } + GSeparator { + anchors.left: parent.left + anchors.leftMargin: Constants.component_spacing + anchors.right: parent.right + anchors.rightMargin: Constants.component_spacing + } LabeledSwitch { checked: SettingsModel.skipRightsOnCanAllowed - //: LABEL ANDROID IOS - description: qsTr("Do not show the rights page, when in can allowed mode") + drawBottomCorners: true enabled: SettingsModel.enableCanAllowed //: LABEL ANDROID IOS @@ -256,17 +315,20 @@ SectionPage { onCheckedChanged: SettingsModel.skipRightsOnCanAllowed = checked } - TitledSeparator { + } + GOptionsContainer { + Layout.fillWidth: true + //: LABEL ANDROID IOS + title: qsTr("Developer options") + visible: SettingsModel.advancedSettings - //: LABEL ANDROID IOS - title: qsTr("Developer options") - width: parent.width - } LabeledSwitch { id: testUriSwitch + checked: SettingsModel.useSelfauthenticationTestUri //: LABEL ANDROID IOS - description: qsTr("Use the test environment during a self-authentication") + description: qsTr("Allow test sample card usage") + drawTopCorners: true //: LABEL ANDROID IOS title: qsTr("Testmode for the self-authentication") @@ -274,10 +336,17 @@ SectionPage { onCheckedChanged: SettingsModel.useSelfauthenticationTestUri = checked } + GSeparator { + anchors.left: parent.left + anchors.leftMargin: Constants.component_spacing + anchors.right: parent.right + anchors.rightMargin: Constants.component_spacing + } LabeledSwitch { checked: SettingsModel.enableSimulator //: LABEL ANDROID IOS - description: qsTr("Enable internal card simulator") + description: qsTr("Simulate a test sample card in authentications") + drawBottomCorners: true //: LABEL ANDROID IOS title: qsTr("Internal card simulator") @@ -286,21 +355,18 @@ SectionPage { onCheckedChanged: SettingsModel.enableSimulator = checked } } - Column { - spacing: parent.spacing - visible: plugin.debugBuild - width: parent.width + GOptionsContainer { + Layout.fillWidth: true - TitledSeparator { + //: LABEL ANDROID IOS + title: qsTr("Debug options") + visible: plugin.debugBuild - //: LABEL ANDROID IOS - title: qsTr("Debug options") - width: parent.width - } LabeledSwitch { checked: SettingsModel.developerMode //: LABEL ANDROID IOS description: qsTr("Use a more tolerant mode") + drawTopCorners: true //: LABEL ANDROID IOS title: qsTr("Developer mode") @@ -308,30 +374,40 @@ SectionPage { onCheckedChanged: SettingsModel.developerMode = checked } - TitledSeparator { - + GSeparator { + anchors.left: parent.left + anchors.leftMargin: Constants.component_spacing + anchors.right: parent.right + anchors.rightMargin: Constants.component_spacing + } + MenuItem { + //: LABEL ANDROID IOS + description: qsTr("Show Transport PIN reminder, store feedback and close reminder dialogs.") + drawBottomCorners: true + icon: "qrc:///images/material_refresh.svg" //: LABEL ANDROID IOS - title: qsTr("Layout style") + title: qsTr("Reset hideable dialogs") width: parent.width + + onClicked: { + SettingsModel.resetHideableDialogs(); + } } + } + GOptionsContainer { + Layout.fillWidth: true + + //: LABEL ANDROID IOS + title: qsTr("Layout style") + visible: plugin.debugBuild + Column { - bottomPadding: Constants.component_spacing / 2 - leftPadding: Constants.component_spacing - rightPadding: Constants.component_spacing - topPadding: Constants.component_spacing / 2 + padding: Constants.pane_padding width: parent.width GRadioButton { checked: plugin.platformStyle === baseItem.platformId(text) - text: "Phone, iOS" - - onCheckedChanged: if (checked) { - plugin.applyPlatformStyle(baseItem.platformId(text)); - } - } - GRadioButton { - checked: plugin.platformStyle === baseItem.platformId(text) - text: "Phone, Android" + text: "iOS" onCheckedChanged: if (checked) { plugin.applyPlatformStyle(baseItem.platformId(text)); @@ -339,35 +415,30 @@ SectionPage { } GRadioButton { checked: plugin.platformStyle === baseItem.platformId(text) - text: "Tablet, iOS" - - onCheckedChanged: if (checked) { - plugin.applyPlatformStyle(baseItem.platformId(text)); - } - } - GRadioButton { - checked: plugin.platformStyle === baseItem.platformId(text) - text: "Tablet, Android" + text: "Android" onCheckedChanged: if (checked) { plugin.applyPlatformStyle(baseItem.platformId(text)); } } } - TitledSeparator { + } + GOptionsContainer { + Layout.fillWidth: true + + //: LABEL ANDROID IOS + title: qsTr("Create dummy entries") + visible: plugin.debugBuild - //: LABEL ANDROID IOS - title: qsTr("Create dummy entries") - width: parent.width - } ColumnLayout { - spacing: 0 + spacing: Constants.component_spacing width: parent.width GButton { Layout.fillWidth: true - Layout.margins: Constants.component_spacing - Layout.topMargin: Constants.component_spacing / 2 + Layout.leftMargin: Constants.pane_padding + Layout.rightMargin: Constants.pane_padding + Layout.topMargin: Constants.pane_padding //: LABEL ALL_PLATFORMS text: qsTr("New Logfile") @@ -378,9 +449,10 @@ SectionPage { } } GButton { + Layout.bottomMargin: Constants.pane_padding Layout.fillWidth: true - Layout.margins: Constants.component_spacing - Layout.topMargin: 0 + Layout.leftMargin: Constants.pane_padding + Layout.rightMargin: Constants.pane_padding //: LABEL ALL_PLATFORMS text: qsTr("15 days old Logfile") @@ -392,19 +464,6 @@ SectionPage { ApplicationModel.showFeedback("Created old logfile."); } } - GButton { - Layout.fillWidth: true - Layout.margins: Constants.component_spacing - Layout.topMargin: 0 - - //: LABEL ALL_PLATFORMS - text: qsTr("History") - - onClicked: { - HistoryModel.createDummyEntry(); - ApplicationModel.showFeedback("Created new history entry."); - } - } } } } diff --git a/resources/qml/Governikus/SettingsView/LanguageButtonData.qml b/resources/qml/Governikus/SettingsView/LanguageButtonData.qml new file mode 100644 index 000000000..2ac1ddc39 --- /dev/null +++ b/resources/qml/Governikus/SettingsView/LanguageButtonData.qml @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2022-2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick + +ListModel { + ListElement { + //: LABEL ALL_PLATFORMS + a11yDescription: qsTr("Set language to german") + //: LABEL ALL_PLATFORMS + a11yName: qsTr("German") + image: "qrc:///images/location_flag_de.svg" + language: "de" + text: "Deutsch" + } + ListElement { + //: LABEL ALL_PLATFORMS + a11yDescription: qsTr("Set language to english") + //: LABEL ALL_PLATFORMS + a11yName: qsTr("English") + image: "qrc:///images/location_flag_en.svg" + language: "en" + text: "English" + } + ListElement { + //: LABEL ALL_PLATFORMS + a11yDescription: qsTr("Set language to ukrainian") + //: LABEL ALL_PLATFORMS + a11yName: qsTr("Ukrainian") + image: "qrc:///images/location_flag_uk.svg" + language: "uk" + text: "Українська" + } + ListElement { + //: LABEL ALL_PLATFORMS + a11yDescription: qsTr("Set language to russian") + //: LABEL ALL_PLATFORMS + a11yName: qsTr("Russian") + image: "qrc:///images/location_flag_ru.svg" + language: "ru" + text: "Русский" + } +} diff --git a/resources/qml/Governikus/SettingsView/LanguageButtons.qml b/resources/qml/Governikus/SettingsView/LanguageButtons.qml deleted file mode 100644 index 79c8be09f..000000000 --- a/resources/qml/Governikus/SettingsView/LanguageButtons.qml +++ /dev/null @@ -1,59 +0,0 @@ -/** - * Copyright (c) 2022-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 - -GridLayout { - id: root - signal buttonClicked - - columnSpacing: Constants.component_spacing - rowSpacing: Constants.component_spacing - - LocationButton { - //: LABEL ALL_PLATFORMS - Accessible.description: qsTr("Set language to german") - //: LABEL ALL_PLATFORMS - Accessible.name: qsTr("German") - image: "qrc:///images/location_flag_de.svg" - language: "de" - text: "Deutsch" - - onClicked: root.buttonClicked() - } - LocationButton { - //: LABEL ALL_PLATFORMS - Accessible.description: qsTr("Set language to english") - //: LABEL ALL_PLATFORMS - Accessible.name: qsTr("English") - image: "qrc:///images/location_flag_en.svg" - language: "en" - text: "English" - - onClicked: root.buttonClicked() - } - LocationButton { - //: LABEL ALL_PLATFORMS - Accessible.description: qsTr("Set language to ukrainian") - //: LABEL ALL_PLATFORMS - Accessible.name: qsTr("Ukrainian") - image: "qrc:///images/location_flag_uk.svg" - language: "uk" - text: "Українська" - - onClicked: root.buttonClicked() - } - LocationButton { - //: LABEL ALL_PLATFORMS - Accessible.description: qsTr("Set language to russian") - //: LABEL ALL_PLATFORMS - Accessible.name: qsTr("Russian") - image: "qrc:///images/location_flag_ru.svg" - language: "ru" - text: "Русский" - - onClicked: root.buttonClicked() - } -} diff --git a/resources/qml/Governikus/SettingsView/qmldir b/resources/qml/Governikus/SettingsView/qmldir index 093f1ca8e..d81631a29 100644 --- a/resources/qml/Governikus/SettingsView/qmldir +++ b/resources/qml/Governikus/SettingsView/qmldir @@ -5,12 +5,12 @@ internal ConnectSacView ConnectSacView.qml internal DebugSettings DebugSettings.qml internal DeveloperSettings DeveloperSettings.qml internal GeneralSettings GeneralSettings.qml -internal LanguageSelectionPopup LanguageSelectionPopup.qml internal RemoteReaderDelegate RemoteReaderDelegate.qml internal ScreenOrientationSelectionPopup ScreenOrientationSelectionPopup.qml internal SecurityAndPrivacySettings SecurityAndPrivacySettings.qml CardReaderView 1.0 CardReaderView.qml +DarkModeButtons 1.0 DarkModeButtons.qml LanguageButtons 1.0 LanguageButtons.qml RemoteReaderView 1.0 RemoteReaderView.qml SettingsView 1.0 SettingsView.qml diff --git a/resources/qml/Governikus/SetupAssistantView/+desktop/SetupAutostartView.qml b/resources/qml/Governikus/SetupAssistantView/+desktop/SetupAutostartView.qml new file mode 100644 index 000000000..e9f2d6b65 --- /dev/null +++ b/resources/qml/Governikus/SetupAssistantView/+desktop/SetupAutostartView.qml @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick +import Governikus.Global +import Governikus.TitleBar +import Governikus.View +import Governikus.Type.SettingsModel +import Governikus.Type.UiModule + +DecisionView { + mainIconSource: "qrc:///images/desktop/autostart.svg" + questionSubText: { + //: INFO DESKTOP Information text why autostart of the App is advisable + let subText = qsTr("In order to successfully use the eID function, %1 has to be running. It is therefore advisable to activate the auto-start after system startup.").arg(Qt.application.name); + if (Qt.platform.os === "osx") { + //: INFO MACOS Additional information that macOS auto-start adds a symbol to the menu bar + subText += " " + qsTr("The launch will add an icon to the menu bar."); + } else { + //: INFO WINDOWS Additional information that Windows auto-start adds a symbol to the notification area. + subText += " " + qsTr("The launch will add a tray icon to the notification area."); + } + return subText; + } + //: INFO DESKTOP Question if the App shall be started automatically after boot + questionText: qsTr("Do you want to automatically start the %1 after boot?").arg(Qt.application.name) + + titleBarAction: TitleBarAction { + rootEnabled: false + showSettings: false + //: LABEL DESKTOP + text: qsTr("Autostart Settings") + + customSubAction: Item { + } + } + + onAgree: { + SettingsModel.autoStartApp = true; + SettingsModel.startupModule = UiModule.DEFAULT; + nextView(UiModule.DEFAULT); + } + onDisagree: { + SettingsModel.autoStartApp = false; + SettingsModel.startupModule = UiModule.DEFAULT; + nextView(UiModule.DEFAULT); + } +} diff --git a/resources/qml/Governikus/SetupAssistantView/qmldir b/resources/qml/Governikus/SetupAssistantView/qmldir new file mode 100644 index 000000000..337820c89 --- /dev/null +++ b/resources/qml/Governikus/SetupAssistantView/qmldir @@ -0,0 +1,3 @@ +module SetupAssistantView + +SetupAutostartView 1.0 SetupAutostartView.qml diff --git a/resources/qml/Governikus/CheckSmartView/+mobile/CheckSmartSuggestionView.qml b/resources/qml/Governikus/SmartView/+mobile/CheckSmartResultView.qml similarity index 65% rename from resources/qml/Governikus/CheckSmartView/+mobile/CheckSmartSuggestionView.qml rename to resources/qml/Governikus/SmartView/+mobile/CheckSmartResultView.qml index 621b94a42..c3828237c 100644 --- a/resources/qml/Governikus/CheckSmartView/+mobile/CheckSmartSuggestionView.qml +++ b/resources/qml/Governikus/SmartView/+mobile/CheckSmartResultView.qml @@ -1,10 +1,11 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.CheckResultView 1.0 -import Governikus.Style 1.0 -import Governikus.Type.SmartModel 1.0 +import QtQuick +import Governikus.CheckResultView +import Governikus.ResultView +import Governikus.Style +import Governikus.Type.SmartModel CheckResultSuggestionView { id: root @@ -15,24 +16,38 @@ CheckResultSuggestionView { signal runSmartSetup Accessible.name: suggestionData.title + smartEidUsed: true suggestionData: { + if (SmartModel.errorString !== "") { + return updateCheckError; + } switch (result) { case SmartModel.SMART_UPDATING_STATUS: return smartUpdatingData; case SmartModel.SMART_UNAVAILABLE: return smartUnvailableData; case SmartModel.SMART_UNUSABLE: - return smartUnsuableData; + return smartUnusableData; case SmartModel.SMART_NO_PROVISIONING: - return noProvsioningData; case SmartModel.SMART_NO_PERSONALIZATION: - return noPersonalizationData; + return smartNotSetupData; default: return empty; } } - titleBarColor: Style.color.accent_smart + SuggestionData { + id: updateCheckError + + //: LABEL ANDROID IOS + continueButtonText: qsTr("Back") + icon: "qrc:///images/status_error_%1.svg".arg(Style.currentTheme.name) + text: SmartModel.errorString + //: LABEL ANDROID IOS + title: qsTr("Smart-eID check failed") + + onContinueClicked: cancelClicked() + } SuggestionData { id: empty @@ -41,6 +56,8 @@ CheckResultSuggestionView { } SuggestionData { id: smartUpdatingData + + icon: "qrc:///images/sandglass.svg" //: LABEL ANDROID IOS text: qsTr("Please wait a moment.") @@ -49,9 +66,11 @@ CheckResultSuggestionView { } SuggestionData { id: smartUnvailableData - continueButtonIcon: "qrc:///images/mobile/device.svg" + + continueButtonIcon: "qrc:///images/mobile/device_button.svg" //: LABEL ANDROID IOS continueButtonText: qsTr("Check device and ID card") + icon: "qrc:///images/status_error_%1.svg".arg(Style.currentTheme.name) //: LABEL ANDROID IOS text: qsTr("Your mobile device does not meet the technical requirements for Smart-eID.

You may check if your device and ID card are suitable to use the eID function.") @@ -61,10 +80,11 @@ CheckResultSuggestionView { onContinueClicked: checkDevice() } SuggestionData { - id: smartUnsuableData + id: smartUnusableData + continueButtonIcon: "qrc:///images/identify.svg" //: LABEL ANDROID IOS - continueButtonText: qsTr("Set up Smart-eID") + continueButtonText: qsTr("Continue") //: LABEL ANDROID IOS text: "" + //: LABEL ANDROID IOS @@ -74,13 +94,11 @@ CheckResultSuggestionView { //: LABEL ANDROID IOS qsTr("The setup has not been completed.") + "
  • " + //: LABEL ANDROID IOS - qsTr("The preparation for the Smart-eID is defective.") + "
  • " + - //: LABEL ANDROID IOS qsTr("The Smart-eID PIN has been entered incorrectly three times.") + "
  • " + //: LABEL ANDROID IOS - qsTr("The AusweisApp2 has been uninstalled temporarily.") + "
  • " + "
    " + + qsTr("The %1 has been uninstalled temporarily.").arg(Qt.application.name) + "" + "
    " + //: LABEL ANDROID IOS - qsTr("Please restart the setup of the Smart-eID.") + qsTr("You may continue with the setup of the Smart-eID.") textFormat: Text.RichText //: LABEL ANDROID IOS @@ -89,29 +107,17 @@ CheckResultSuggestionView { onContinueClicked: runSmartSetup() } SuggestionData { - id: noProvsioningData - continueButtonIcon: "qrc:///images/identify.svg" - //: LABEL ANDROID IOS - continueButtonText: qsTr("Set up Smart-eID") - //: LABEL ANDROID IOS - text: qsTr("Your device meets the technical requirements for Smart-eID, but is not yet provisioned for setup. The provisioning is done automatically during the Smart-eID setup process.") + id: smartNotSetupData - //: LABEL ANDROID IOS - title: qsTr("Smart-eID not prepared") - - onContinueClicked: runSmartSetup() - } - SuggestionData { - id: noPersonalizationData continueButtonIcon: "qrc:///images/identify.svg" //: LABEL ANDROID IOS - continueButtonText: qsTr("Set up Smart-eID") + continueButtonText: qsTr("Continue") //: LABEL ANDROID IOS - text: qsTr("Your device meets the technical requirements for Smart-eID and is already provisioned for setup. You can now start the Smart-eID setup.") + text: qsTr("Your device meets the technical requirements for Smart-eID. You may now continue the setup process.") //: LABEL ANDROID IOS - title: qsTr("Smart-eID not set up") + title: qsTr("Smart-eID supported") onContinueClicked: runSmartSetup() } diff --git a/resources/qml/Governikus/SmartView/+mobile/PersonalizationController.qml b/resources/qml/Governikus/SmartView/+mobile/PersonalizationController.qml index 4948272db..b32e741d3 100644 --- a/resources/qml/Governikus/SmartView/+mobile/PersonalizationController.qml +++ b/resources/qml/Governikus/SmartView/+mobile/PersonalizationController.qml @@ -1,28 +1,29 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.AuthView 1.0 -import Governikus.EnterPasswordView 1.0 -import Governikus.ResultView 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.PasswordInfoView 1.0 -import Governikus.View 1.0 -import Governikus.WhiteListClient 1.0 -import Governikus.Workflow 1.0 -import Governikus.Type.ConnectivityManager 1.0 -import Governikus.Type.ChatModel 1.0 -import Governikus.Type.NumberModel 1.0 -import Governikus.Type.PasswordType 1.0 -import Governikus.Type.PersonalizationModel 1.0 -import Governikus.Type.ReaderPlugIn 1.0 -import Governikus.Type.SettingsModel 1.0 -import Governikus.Type.SurveyModel 1.0 -import Governikus.Type.UiModule 1.0 +import QtQuick +import Governikus.AuthView +import Governikus.EnterPasswordView +import Governikus.ResultView +import Governikus.Style +import Governikus.TitleBar +import Governikus.PasswordInfoView +import Governikus.View +import Governikus.WhiteListClient +import Governikus.Workflow +import Governikus.Type.ConnectivityManager +import Governikus.Type.ChatModel +import Governikus.Type.NumberModel +import Governikus.Type.PasswordType +import Governikus.Type.PersonalizationModel +import Governikus.Type.ReaderPlugIn +import Governikus.Type.SettingsModel +import Governikus.Type.SurveyModel +import Governikus.Type.UiModule Controller { id: controller + enum WorkflowStates { Initial, CheckStatus, @@ -37,7 +38,6 @@ Controller { Abort } - readonly property string currentState: PersonalizationModel.currentState property bool skipSelectReader: false //: LABEL ANDROID IOS readonly property string smartEidTitle: qsTr("Smart-eID") @@ -47,25 +47,21 @@ Controller { function done() { PersonalizationModel.continueWorkflow(); popAll(); - show(UiModule.SMART); + show(UiModule.SMART_EID); } - function processStateChange() { - switch (currentState) { - case "Initial": - popAll(); - skipSelectReader = false; - break; + function processStateChange(pState) { + switch (pState) { case "StateCheckStatus": - show(UiModule.SMART, true); + show(UiModule.SMART_EID, true); popAll(); - if (!ConnectivityManager.networkInterfaceActive) { - push(checkConnectivityView); - } else { + if (connectivityManager.networkInterfaceActive) { push(smartProgress); setWorkflowStateAndContinue(PersonalizationController.WorkflowStates.CheckStatus); + } else { + push(checkConnectivityView); } break; - case "StatePrepareApplet": + case "StateCheckApplet": setWorkflowStateAndContinue(PersonalizationController.WorkflowStates.InstallApplet); workflowProgressVisible = true; break; @@ -128,10 +124,9 @@ Controller { break; case "StateEnterNewPacePin": setWorkflowStateAndRequestInput(PersonalizationController.WorkflowStates.SmartPinNew); - break; - case "StateGetChallenge": - setWorkflowStateAndContinue(PersonalizationController.WorkflowStates.Personalization); - replace(smartProgress); + if (PersonalizationModel.applet) { + PersonalizationModel.continueWorkflow(); + } break; case "StateShowResult": if (!PersonalizationModel.error) @@ -168,7 +163,10 @@ Controller { function setWorkflowStateAndRequestInput(pState) { controller.workflowState = pState; if (PersonalizationModel.isBasicReader) { - replace(enterPinView); + replace(enterPinView, { + "passwordType": NumberModel.passwordType, + "inputError": NumberModel.inputError + }); } else { replace(smartProgress); PersonalizationModel.continueWorkflow(); @@ -176,28 +174,35 @@ Controller { } Connections { - // This is necessary because onCurrentStateChanged is not - // working, when we need to process a state a second time - function onFireCurrentStateChanged() { - processStateChange(); + function onFireStateEntered(pState) { + processStateChange(pState); + } + function onFireWorkflowFinished() { + connectivityManager.watching = false; + } + function onFireWorkflowStarted() { + popAll(); + skipSelectReader = false; + connectivityManager.watching = true; } target: PersonalizationModel } - Connections { - function onFireNetworkInterfaceActiveChanged() { - processStateChange(); - } + ConnectivityManager { + id: connectivityManager - enabled: currentState === "StateCheckStatus" - target: ConnectivityManager + onNetworkInterfaceActiveChanged: { + if (PersonalizationModel.currentState === "StateCheckStatus") + processStateChange(PersonalizationModel.currentState); + } } Component { id: transportPinReminder + TransportPinReminderView { moreInformationText: transportPinReminderInfoData.linkText + smartEidUsed: false title: smartEidTitle - titleBarColor: Style.color.accent onCancel: PersonalizationModel.cancelWorkflow() onPinKnown: { @@ -209,36 +214,41 @@ Controller { PersonalizationModel.cancelWorkflowToChangePin(); } onShowInfoView: { - push(transportPinReminderInfoDataView); + push(transportPinReminderInfoView); } } } PasswordInfoData { id: transportPinReminderInfoData + contentType: PasswordInfoContent.Type.CHANGE_PIN } Component { id: transportPinReminderInfoView + PasswordInfoView { infoContent: transportPinReminderInfoData + smartEidUsed: workflowState !== PersonalizationController.WorkflowStates.ProcessingPhysicalEid onClose: pop() } } Component { id: checkConnectivityView + CheckConnectivityView { + smartEidUsed: true title: smartEidTitle - titleBarColor: Style.color.accent_smart onCancel: PersonalizationModel.cancelWorkflow() } } Component { id: cardPositionView + CardPositionView { + smartEidUsed: PersonalizationModel.readerPlugInType === ReaderPlugIn.SMART title: smartEidTitle - titleBarColor: PersonalizationModel.readerPlugInType === ReaderPlugIn.SMART ? Style.color.accent_smart : Style.color.accent onCancelClicked: PersonalizationModel.cancelWorkflow() onContinueClicked: { @@ -249,8 +259,10 @@ Controller { } Component { id: smartProgress + PersonalizationProgressView { progressBarVisible: workflowProgressVisible + title: smartEidTitle workflowState: controller.workflowState onAbortWorkflow: { @@ -261,14 +273,15 @@ Controller { } Component { id: editRights + EditRights { //: INFO ANDROID IOS The user is informed that the ID card needs to be read to create a Smart-eID. actionText: qsTr("The Smart-eID issuing authority needs to read your ID card's data in order to store it on this device:") //: LABEL IOS_PHONE ANDROID_PHONE dataText: qsTr("By entering your ID card PIN, access to the following data of your ID card will be allowed to the mentioned provider:") + smartEidUsed: true //: LABEL ANDROID IOS title: qsTr("Set up Smart-eID") - titleBarColor: Style.color.accent_smart workflowModel: PersonalizationModel onRightsAccepted: { @@ -279,18 +292,36 @@ Controller { } Component { id: smartWorkflow + GeneralWorkflow { - titleBarColor: Style.color.accent + smartEidUsed: false workflowModel: PersonalizationModel workflowTitle: smartEidTitle } } + PasswordInfoData { + id: infoData + + contentType: fromPasswordType(NumberModel.passwordType, NumberModel.isCanAllowedMode) + } + Component { + id: passwordInfoView + + PasswordInfoView { + infoContent: infoData + smartEidUsed: workflowState !== PersonalizationController.WorkflowStates.ProcessingPhysicalEid + + onClose: pop() + } + } Component { id: enterPinView + EnterPasswordView { + moreInformationText: infoData.linkText + smartEidUsed: workflowState !== PersonalizationController.WorkflowStates.Pin //: LABEL ANDROID IOS title: qsTr("Set up Smart-eID") - titleBarColor: workflowState === PersonalizationController.WorkflowStates.Pin ? Style.color.accent : Style.color.accent_smart navigationAction: NavigationAction { action: NavigationAction.Action.Cancel @@ -300,24 +331,47 @@ Controller { } } - onPasswordEntered: { - replace(smartProgress); - PersonalizationModel.continueWorkflow(); + onPasswordEntered: pPasswordType => { + switch (pPasswordType) { + case PasswordType.NEW_SMART_PIN: + setWorkflowStateAndRequestInput(PersonalizationController.WorkflowStates.SmartPinNew); + break; + case PasswordType.NEW_SMART_PIN_CONFIRMATION: + if (NumberModel.commitNewPin()) { + replace(smartProgress); + if (PersonalizationModel.applet) { + controller.workflowState = PersonalizationController.WorkflowStates.Personalization; + } else { + setWorkflowStateAndContinue(PersonalizationController.WorkflowStates.Personalization); + } + } else { + setWorkflowStateAndRequestInput(PersonalizationController.WorkflowStates.SmartPinNew); + } + break; + default: + replace(smartProgress); + PersonalizationModel.continueWorkflow(); + } } + onRequestPasswordInfo: push(passwordInfoView) } } Component { id: abortedProgressView + AbortedProgressView { - titleBarColor: workflowState === PersonalizationController.WorkflowStates.ProcessingPhysicalEid ? Style.color.accent : Style.color.accent_smart + networkInterfaceActive: connectivityManager.networkInterfaceActive + smartEidUsed: workflowState !== PersonalizationController.WorkflowStates.ProcessingPhysicalEid + title: smartEidTitle onCancel: PersonalizationModel.cancelWorkflow() } } Component { id: resultView + PersonalizationResultView { - titleBarColor: workflowState === PersonalizationController.WorkflowStates.ProcessingPhysicalEid ? Style.color.accent : Style.color.accent_smart + smartEidUsed: workflowState !== PersonalizationController.WorkflowStates.ProcessingPhysicalEid onContinueClicked: { if (PersonalizationModel.error) { @@ -330,14 +384,16 @@ Controller { } Component { id: legalInformation + PersonalizationLegalInformationView { onContinueClicked: done() } } Component { id: whiteListSurveyView + WhiteListSurveyView { - titleBarColor: root.titleBarColor + smartEidUsed: root.smartEidUsed onDone: pUserAccepted => { SurveyModel.setDeviceSurveyPending(pUserAccepted); diff --git a/resources/qml/Governikus/SmartView/+mobile/PersonalizationLegalInformationView.qml b/resources/qml/Governikus/SmartView/+mobile/PersonalizationLegalInformationView.qml index 34d2e3b3c..0e1d29f2b 100644 --- a/resources/qml/Governikus/SmartView/+mobile/PersonalizationLegalInformationView.qml +++ b/resources/qml/Governikus/SmartView/+mobile/PersonalizationLegalInformationView.qml @@ -1,15 +1,17 @@ /** * Copyright (c) 2022-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Style 1.0 -import Governikus.ResultView 1.0 +import QtQuick +import Governikus.Style +import Governikus.ResultView ResultView { id: root + //: LABEL ANDROID IOS header: qsTr("Important Notice") - resultType: ResultView.Type.IsInfo + icon: "qrc:///images/status_info_%1.svg".arg(Style.currentTheme.name) + smartEidUsed: true text: "" + "
    • " + //: LABEL ANDROID IOS qsTr("Do not give your smartphone to third parties unattended, especially if it is already unlocked.") + "
    • " + @@ -22,11 +24,12 @@ ResultView { //: LABEL ANDROID IOS qsTr("If your smartphone with the Smart-eID is lost or stolen, please block the Smart-eID immediately by calling the blocking hotline (+49 116 116) and providing your blocking code.") + "
    • " + //: LABEL ANDROID IOS - qsTr("Delete your Smart-eID before you give away or sell your smartphone.") + "
    " + qsTr("Delete your Smart-eID before you give away or sell your smartphone.") + "
  • " + + //: LABEL ANDROID IOS + qsTr("If you uninstall the %1 or reset your smartphone, the Smart-eID must be set up again.").arg(Qt.application.name) + "
  • " textFormat: Text.RichText //: LABEL ANDROID IOS title: qsTr("Set up Smart-eID") - titleBarColor: Style.color.accent_smart onCancelClicked: continueClicked() } diff --git a/resources/qml/Governikus/SmartView/+mobile/PersonalizationProgressView.qml b/resources/qml/Governikus/SmartView/+mobile/PersonalizationProgressView.qml index 10ca09719..b4688c1c6 100644 --- a/resources/qml/Governikus/SmartView/+mobile/PersonalizationProgressView.qml +++ b/resources/qml/Governikus/SmartView/+mobile/PersonalizationProgressView.qml @@ -1,14 +1,14 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.ProgressView 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 -import Governikus.Type.AuthModel 1.0 -import Governikus.Type.PersonalizationModel 1.0 +import QtQuick +import Governikus.Global +import Governikus.ProgressView +import Governikus.Style +import Governikus.TitleBar +import Governikus.View +import Governikus.Type.AuthModel +import Governikus.Type.PersonalizationModel ProgressView { id: root @@ -19,14 +19,17 @@ ProgressView { progressText: PersonalizationModel.progressMessage progressValue: PersonalizationModel.progressValue + smartEidUsed: workflowState !== PersonalizationController.WorkflowStates.ProcessingPhysicalEid subText: { switch (workflowState) { case PersonalizationController.WorkflowStates.CheckStatus: case PersonalizationController.WorkflowStates.InstallApplet: case PersonalizationController.WorkflowStates.TcToken: - case PersonalizationController.WorkflowStates.Abort: //: LABEL ANDROID IOS return qsTr("Please wait a moment."); + case PersonalizationController.WorkflowStates.Abort: + //: LABEL ANDROID IOS + return qsTr("Please wait a moment, the current process is being finished."); case PersonalizationController.WorkflowStates.ProcessingPhysicalEid: return PersonalizationModel.isBasicReader ? //: LABEL ANDROID IOS @@ -65,7 +68,6 @@ ProgressView { //: LABEL ANDROID IOS title: qsTr("Smart-eID") - titleBarColor: workflowState === PersonalizationController.WorkflowStates.ProcessingPhysicalEid ? Style.color.accent : Style.color.accent_smart navigationAction: NavigationAction { action: workflowState === PersonalizationController.WorkflowStates.Abort ? NavigationAction.Action.None : NavigationAction.Action.Cancel diff --git a/resources/qml/Governikus/SmartView/+mobile/PersonalizationResultView.qml b/resources/qml/Governikus/SmartView/+mobile/PersonalizationResultView.qml index dfebebbbb..8a64671b8 100644 --- a/resources/qml/Governikus/SmartView/+mobile/PersonalizationResultView.qml +++ b/resources/qml/Governikus/SmartView/+mobile/PersonalizationResultView.qml @@ -1,18 +1,19 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.PasswordInfoView 1.0 -import Governikus.ResultView 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.Type.PasswordType 1.0 -import Governikus.Type.PersonalizationModel 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.PasswordInfoView +import Governikus.ResultView +import Governikus.Style +import Governikus.TitleBar +import Governikus.Type.PasswordType +import Governikus.Type.PersonalizationModel ResultErrorView { id: root + buttonText: PersonalizationModel.error ? //: LABEL ANDROID IOS qsTr("OK") : @@ -21,7 +22,7 @@ ResultErrorView { errorCode: PersonalizationModel.error ? PersonalizationModel.statusCodeString : "" errorDescription: PersonalizationModel.error ? PersonalizationModel.errorText : "" header: PersonalizationModel.error ? PersonalizationModel.errorHeader : "" - resultType: PersonalizationModel.error ? ResultView.Type.IsError : ResultView.Type.IsSuccess + icon: PersonalizationModel.error ? "qrc:///images/status_error_%1.svg".arg(Style.currentTheme.name) : "qrc:///images/status_ok_%1.svg".arg(Style.currentTheme.name) //: INFO ANDROID IOS Success message that the Smart-eID was created. text: PersonalizationModel.error ? PersonalizationModel.resultString : qsTr("You have successfully set up your Smart-eID.") @@ -34,30 +35,27 @@ ResultErrorView { width: parent.width GText { - Layout.fillWidth: true - //: INFO ANDROID IOS Explanation text of the Smart-eID blocking code text: qsTr("Please write down your blocking code:") } GText { - Layout.fillWidth: true + Layout.alignment: Qt.AlignHCenter + font.bold: true horizontalAlignment: Text.AlignHCenter text: PersonalizationModel.blockingCode - textStyle: Style.text.header_highlight + textStyle: Style.text.headline visible: text !== "" } GText { - Layout.fillWidth: true - //: LABEL ANDROID IOS text: qsTr("You will shortly receive the blocking password and further information about your Smart-eID by letter.") visible: PersonalizationModel.blockingCode !== "" } GText { - Layout.fillWidth: true + font.bold: true //: INFO ANDROID IOS Placeholder (error) text if the Smart-eID setup finished successfully but for some reason no blocking code was retrieved text: qsTr("The Smart-eID setup finished successfully but no blocking code was retrieved. For security reasons, you should delete your Smart-eID and restart the setup.") - textStyle: Style.text.normal_warning_highlight + textStyle: Style.text.normal_warning visible: PersonalizationModel.blockingCode === "" } MoreInformationLink { @@ -67,12 +65,10 @@ ResultErrorView { onClicked: push(passwordInfoView) } GText { - Layout.fillWidth: true text: { switch (PersonalizationModel.remainingAttempts) { case 0: - //: LABEL ANDROID IOS - return qsTr("You have reached the allowed amount of Smart-eID setups for the current period. You may set up another Smart-eID with your ID card on %1.").arg(PersonalizationModel.restrictionDate); + return PersonalizationModel.blockingPeriodMessage; case 1: //: LABEL ANDROID IOS return qsTr("Attention: you may only set up one more Smart-eID with your ID card. Further setups may be carried out on %1.").arg(PersonalizationModel.restrictionDate); @@ -86,13 +82,15 @@ ResultErrorView { } PasswordInfoData { id: infoData + contentType: PasswordInfoContent.Type.SMART_BLOCKING_CODE } Component { id: passwordInfoView + PasswordInfoView { infoContent: infoData - titleBarColor: root.titleBarColor + smartEidUsed: root.smartEidUsed navigationAction: NavigationAction { action: NavigationAction.Action.Back diff --git a/resources/qml/Governikus/SmartView/+mobile/SmartCardView.qml b/resources/qml/Governikus/SmartView/+mobile/SmartCardView.qml index f8cdb5dc9..b0f342ed7 100644 --- a/resources/qml/Governikus/SmartView/+mobile/SmartCardView.qml +++ b/resources/qml/Governikus/SmartView/+mobile/SmartCardView.qml @@ -1,10 +1,10 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.SmartModel 1.0 +import QtQuick +import Governikus.Global +import Governikus.Style +import Governikus.Type.SmartModel Item { id: root @@ -17,6 +17,7 @@ Item { TintableIcon { id: cardIcon + anchors.fill: parent anchors.margins: root.padding desaturate: true @@ -24,42 +25,12 @@ Item { sourceSize.height: Style.dimens.header_icon_size - 2 * root.padding tintEnabled: root.smartState !== SmartModel.SMART_READY } - TintableIcon { + TintableAnimation { anchors.bottom: parent.bottom anchors.right: parent.right - source: "qrc:///images/material_alert.svg" - sourceSize.width: Style.dimens.medium_icon_size - tintColor: Style.color.warning_text - visible: root.smartState === SmartModel.SMART_UNUSABLE - } - TintableIcon { - anchors.bottom: parent.bottom - anchors.right: parent.right - source: "qrc:///images/sandglass.svg" - sourceSize.height: Style.dimens.medium_icon_size - tintColor: Style.color.accent + height: Style.dimens.medium_icon_size + source: "qrc:///images/sandglass.webp" + tintColor: Style.color.control visible: root.smartState === SmartModel.SMART_UPDATING_STATUS } - Canvas { - id: canvas - anchors.fill: parent - visible: smartState === SmartModel.SMART_UNAVAILABLE - - onPaint: { - var context = canvas.getContext('2d'); - if (context === null) { - return; - } - context.save(); - context.reset(); - context.strokeStyle = Style.color.warning_text; - context.lineWidth = root.padding; - context.lineCap = "round"; - context.beginPath(); - context.moveTo(context.lineWidth, height - context.lineWidth); - context.lineTo(width - context.lineWidth, context.lineWidth); - context.stroke(); - context.restore(); - } - } } diff --git a/resources/qml/Governikus/SmartView/+mobile/SmartDeleteBaseView.qml b/resources/qml/Governikus/SmartView/+mobile/SmartDeleteBaseView.qml new file mode 100644 index 000000000..f5da16696 --- /dev/null +++ b/resources/qml/Governikus/SmartView/+mobile/SmartDeleteBaseView.qml @@ -0,0 +1,119 @@ +/** + * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.ProgressView +import Governikus.ResultView +import Governikus.Style +import Governikus.View +import Governikus.TitleBar +import Governikus.Type.LogModel +import Governikus.Type.SmartModel +import Governikus.Type.UiModule +import Governikus.Type.WorkflowModel + +FlickableSectionPage { + id: root + + property alias buttonText: deleteButton.text + property alias deleteDescriptionText: deleteDescription.text + property alias popupButtonText: deleteConfirmation.okButtonText + property alias popupText: deleteConfirmation.text + property alias popupTitle: deleteConfirmation.title + + signal close + signal deleteConfirmed + + function pushProgressView(pProperties) { + push(progressView, pProperties); + } + function pushResultView(pProperties) { + push(resultView, pProperties); + } + + smartEidUsed: true + spacing: Constants.component_spacing + + navigationAction: NavigationAction { + action: NavigationAction.Action.Back + + onClicked: pop() + } + + Component { + id: progressView + + ProgressView { + progressValue: SmartModel.progress + smartEidUsed: root.smartEidUsed + //: LABEL ANDROID IOS + subText: qsTr("Please wait a moment.") + //: LABEL ANDROID IOS + title: qsTr("Smart-eID") + } + } + Component { + id: resultView + + ResultErrorView { + property bool success: false + + icon: success ? "qrc:///images/status_ok_%1.svg".arg(Style.currentTheme.name) : "qrc:///images/status_error_%1.svg".arg(Style.currentTheme.name) + mailButtonText: success ? "" : + //: LABEL ANDROID IOS + qsTr("Send log") + smartEidUsed: root.smartEidUsed + //: LABEL ANDROID IOS + title: qsTr("Smart-eID") + + onCancelClicked: root.close() + onContinueClicked: root.close() + onMailClicked: LogModel.mailLog("support@ausweisapp.de", WorkflowModel.getEmailHeader(), WorkflowModel.getEmailBody()) + } + } + TintableIcon { + Layout.alignment: Qt.AlignHCenter + source: "qrc:///images/identify.svg" + sourceSize.height: Style.dimens.header_icon_size + tintColor: Style.color.control + } + GPane { + Layout.alignment: Qt.AlignHCenter + Layout.fillWidth: true + + GText { + id: deleteDescription + + width: parent.width + } + GText { + + //: LABEL ANDROID IOS + text: qsTr("If you want to use that functionality again, you need to set up a new Smart-eID first.") + width: parent.width + } + } + GSpacer { + Layout.fillHeight: true + } + GButton { + id: deleteButton + + Layout.alignment: Qt.AlignHCenter + buttonColor: Style.color.text_warning + icon.source: "qrc:///images/identify.svg" + + //: LABEL ANDROID IOS + text: qsTr("Reset Smart-eID") + + onClicked: deleteConfirmation.open() + } + ConfirmationPopup { + id: deleteConfirmation + + onConfirmed: root.deleteConfirmed() + } +} diff --git a/resources/qml/Governikus/SmartView/+mobile/SmartDeleteStartView.qml b/resources/qml/Governikus/SmartView/+mobile/SmartDeleteStartView.qml deleted file mode 100644 index 57756c939..000000000 --- a/resources/qml/Governikus/SmartView/+mobile/SmartDeleteStartView.qml +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.View 1.0 -import Governikus.TitleBar 1.0 -import Governikus.Type.UiModule 1.0 - -SectionPage { - id: root - - property alias buttonText: deleteButton.text - property alias deleteDescriptionText: deleteDescription.text - - signal deleteConfirmed - - sectionPageFlickable: contentItem - - //: LABEL ANDROID IOS - title: qsTr("Smart-eID") - titleBarColor: Style.color.accent_smart - - navigationAction: NavigationAction { - action: NavigationAction.Action.Back - - onClicked: pop() - } - - ConfirmationPopup { - id: deleteConfirmation - //: LABEL ANDROID IOS - okButtonText: qsTr("Delete") - //: LABEL ANDROID IOS - text: qsTr("Are you sure you want to delete the Smart-eID?") - - //: LABEL ANDROID IOS - title: qsTr("Delete Smart-eID") - - onConfirmed: root.deleteConfirmed() - } - GFlickableColumnLayout { - id: contentItem - - readonly property var maxIconHeight: Style.dimens.header_icon_size - readonly property var minIconHeight: Style.dimens.medium_icon_size - - anchors.fill: parent - maximumContentWidth: Style.dimens.max_text_width - minimumContentHeight: implicitContentHeight - (maxIconHeight - minIconHeight) - spacing: Constants.component_spacing - - TintableIcon { - Layout.alignment: Qt.AlignHCenter - Layout.fillHeight: true - Layout.maximumHeight: contentItem.maxIconHeight - Layout.minimumHeight: contentItem.minIconHeight - Layout.preferredHeight: contentItem.maxIconHeight - source: "qrc:///images/identify.svg" - sourceSize.height: contentItem.maxIconHeight - tintColor: Style.color.accent - } - GPane { - Layout.alignment: Qt.AlignHCenter - Layout.fillWidth: true - - GText { - id: deleteDescription - width: parent.width - } - GText { - - //: LABEL ANDROID IOS - text: qsTr("If you want to use that functionality again, you need to set up a new Smart-eID first.") - width: parent.width - } - } - GSpacer { - Layout.fillHeight: true - } - GButton { - id: deleteButton - Layout.alignment: Qt.AlignHCenter - buttonColor: Style.color.warning_text - icon.source: "qrc:///images/identify.svg" - - //: LABEL ANDROID IOS - text: qsTr("Reset Smart-eID") - - onClicked: deleteConfirmation.open() - } - } -} diff --git a/resources/qml/Governikus/SmartView/+mobile/SmartDeleteView.qml b/resources/qml/Governikus/SmartView/+mobile/SmartDeleteView.qml new file mode 100644 index 000000000..c52367524 --- /dev/null +++ b/resources/qml/Governikus/SmartView/+mobile/SmartDeleteView.qml @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany + */ +import QtQml +import Governikus.Type.SmartModel +import Governikus.Type.UiModule + +SmartDeleteBaseView { + id: root + + //: LABEL ANDROID IOS + buttonText: qsTr("Delete Smart-eID") + //: LABEL ANDROID IOS + deleteDescriptionText: qsTr("You are about to delete the Smart-eID data that is currently stored on your device.") + //: LABEL ANDROID IOS + popupButtonText: qsTr("Delete") + //: LABEL ANDROID IOS + popupText: qsTr("Are you sure you want to delete the Smart-eID?") + popupTitle: title + //: LABEL ANDROID IOS + title: qsTr("Delete the Smart-eID") + + onClose: { + show(UiModule.DEFAULT); + popAll(); + } + onDeleteConfirmed: { + setLockedAndHidden(); + pushProgressView({ + "title": root.title, + //: LABEL ANDROID IOS + "text": qsTr("Deleting Smart-eID") + }); + SmartModel.deletePersonalization(); + } + + Connections { + function onFireDeletePersonalizationDone(pSuccess) { + pushResultView({ + "success": pSuccess, + "title": root.title, + "text": pSuccess ? + //: LABEL ANDROID IOS + qsTr("You have successfuly deleted your Smart-eID.") : + //: LABEL ANDROID IOS + qsTr("The Smart-eID could not be successfully deleted from your device."), + //: LABEL ANDROID IOS + "buttonText": qsTr("Back to start page") + }); + } + + target: SmartModel + } +} diff --git a/resources/qml/Governikus/SmartView/+mobile/SmartMainView.qml b/resources/qml/Governikus/SmartView/+mobile/SmartMainView.qml index b829f63ab..7cd74d0c3 100644 --- a/resources/qml/Governikus/SmartView/+mobile/SmartMainView.qml +++ b/resources/qml/Governikus/SmartView/+mobile/SmartMainView.qml @@ -1,67 +1,56 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 -import Governikus.Type.SmartModel 1.0 -import Governikus.Type.PersonalizationModel 1.0 -import Governikus.Type.UiModule 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.TitleBar +import Governikus.View +import Governikus.Type.SmartModel +import Governikus.Type.PersonalizationModel +import Governikus.Type.UiModule -GFlickableColumnLayout { +ColumnLayout { id: root + readonly property bool showCheck: smartState !== SmartModel.SMART_UPDATING_STATUS && smartState !== SmartModel.SMART_READY readonly property int smartState: SmartModel.smartState - signal checkSmart + signal changePin signal deletePersonalization - signal deleteSmart - signal setupSmart + signal showCheckResult + signal startSelfAuth signal updateSmart - fillHeight: false spacing: 0 SmartCardView { Layout.alignment: Qt.AlignHCenter + Layout.bottomMargin: Constants.component_spacing Layout.maximumHeight: Style.dimens.header_icon_size - Layout.maximumWidth: Style.dimens.max_text_width } GText { - Layout.alignment: Qt.AlignCenter - Layout.fillWidth: true - Layout.maximumWidth: Style.dimens.max_text_width - Layout.topMargin: Constants.component_spacing + Layout.alignment: Qt.AlignHCenter horizontalAlignment: Text.AlignHCenter text: { switch (root.smartState) { case SmartModel.SMART_UPDATING_STATUS: //: LABEL ANDROID IOS return qsTr("Updating Smart-eID status..."); - case SmartModel.SMART_UNAVAILABLE: - //: LABEL ANDROID IOS - return qsTr("Smart-eID not supported"); - case SmartModel.SMART_UNUSABLE: - //: LABEL ANDROID IOS - return qsTr("Smart-eID invalid"); case SmartModel.SMART_READY: //: LABEL ANDROID IOS return qsTr("Smart-eID ready for use"); default: - //: LABEL ANDROID IOS - return qsTr("Smart-eID supported"); + return ""; } } - textStyle: Style.text.header_accent + textStyle: Style.text.headline + visible: !root.showCheck wrapMode: Text.WordWrap } GText { - Layout.alignment: Qt.AlignCenter - Layout.fillWidth: true - Layout.maximumWidth: Style.dimens.max_text_width + Layout.alignment: Qt.AlignHCenter Layout.topMargin: Constants.text_spacing horizontalAlignment: Text.AlignHCenter text: { @@ -69,32 +58,55 @@ GFlickableColumnLayout { case SmartModel.SMART_UPDATING_STATUS: //: LABEL ANDROID IOS return qsTr("Please wait a moment."); - case SmartModel.SMART_UNAVAILABLE: - //: LABEL ANDROID IOS - return qsTr("Unfortunately, this functionality is not supported by your device."); - case SmartModel.SMART_UNUSABLE: - //: LABEL ANDROID IOS - return qsTr("Your Smart-eID is in an invalid state. You need to set it up again to perform online identifications without your ID card."); case SmartModel.SMART_READY: //: LABEL ANDROID IOS return qsTr("Your Smart-eID is set up and ready for use. You can now perform online identifications without your ID card if supported by the provider."); default: - //: LABEL ANDROID IOS - return qsTr("Set up a Smart-eID in order to perform online identifications without your ID card if supported by the provider."); + return ""; } } - textStyle: Style.text.normal_secondary + visible: !root.showCheck wrapMode: Text.WordWrap } SmartSettingsView { - Layout.fillWidth: true Layout.topMargin: Constants.component_spacing - visible: root.smartState !== SmartModel.SMART_UPDATING_STATUS + visible: root.smartState === SmartModel.SMART_READY - onCheckSmart: root.checkSmart() + onChangePin: root.changePin() onDeletePersonalization: root.deletePersonalization() - onDeleteSmart: root.deleteSmart() - onSetupSmart: root.setupSmart() + onStartSelfAuth: root.startSelfAuth() onUpdateSmart: root.updateSmart() } + GPane { + Layout.alignment: Qt.AlignHCenter + Layout.fillWidth: true + visible: root.showCheck + + GText { + + //: LABEL ANDROID IOS + text: qsTr("With the Smart-eID you may also use the online identification function without the ID card.") + width: parent.width + } + GText { + + //: LABEL ANDROID IOS + text: qsTr("Check here if your device is suitable to set up a Smart-eID.") + width: parent.width + } + } + GSpacer { + Layout.fillHeight: true + } + GButton { + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: Constants.component_spacing + icon.source: "qrc:///images/mobile/device_button.svg" + //: LABEL ANDROID IOS + text: qsTr("Start check") + tintIcon: true + visible: root.showCheck + + onClicked: root.showCheckResult() + } } diff --git a/resources/qml/Governikus/SmartView/+mobile/SmartResetView.qml b/resources/qml/Governikus/SmartView/+mobile/SmartResetView.qml new file mode 100644 index 000000000..becbfd929 --- /dev/null +++ b/resources/qml/Governikus/SmartView/+mobile/SmartResetView.qml @@ -0,0 +1,82 @@ +/** + * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany + */ +import QtQml +import Governikus.AuthView +import Governikus.Type.ConnectivityManager +import Governikus.Type.SmartModel + +SmartDeleteBaseView { + id: root + + //: LABEL ANDROID IOS + buttonText: qsTr("Reset Smart-eID") + //: LABEL ANDROID IOS + deleteDescriptionText: qsTr("You are about to reset your Smart-eID data. This can also be used for troubleshooting as well.") + //: LABEL ANDROID IOS + popupButtonText: qsTr("Reset") + //: LABEL ANDROID IOS + popupText: qsTr("Are you sure you want to reset the Smart-eID?") + popupTitle: title + //: LABEL ANDROID IOS + title: qsTr("Reset the Smart-eID") + + onClose: { + setLockedAndHidden(false); + popAll(); + } + onDeleteConfirmed: { + setLockedAndHidden(); + pushProgressView({ + "title": root.title, + //: LABEL ANDROID IOS + "text": qsTr("Resetting Smart-eID"), + "progressBarVisible": true, + //: LABEL ANDROID IOS + "progressText": qsTr("Resetting Smart-eID") + }); + if (connectivityManager.checkConnectivity()) { + SmartModel.deleteSmart(); + } else { + push(checkConnectivityView); + } + } + + ConnectivityManager { + id: connectivityManager + + onNetworkInterfaceActiveChanged: { + if (networkInterfaceActive) { + pop(); + SmartModel.deleteSmart(); + } + } + } + Connections { + function onFireDeleteSmartDone() { + pushResultView({ + "success": SmartModel.errorString === "", + "title": root.title, + //: LABEL ANDROID IOS + "text": SmartModel.errorString === "" ? qsTr("You have successfully reset your Smart-eID.") : SmartModel.errorString + }); + } + + target: SmartModel + } + Component { + id: checkConnectivityView + + CheckConnectivityView { + smartEidUsed: root.smartEidUsed + title: root.title + + Component.onCompleted: connectivityManager.watching = true + Component.onDestruction: connectivityManager.watching = false + onCancel: { + setLockedAndHidden(false); + pop(root); + } + } + } +} diff --git a/resources/qml/Governikus/SmartView/+mobile/SmartSettingsView.qml b/resources/qml/Governikus/SmartView/+mobile/SmartSettingsView.qml index 898b337b9..627a64629 100644 --- a/resources/qml/Governikus/SmartView/+mobile/SmartSettingsView.qml +++ b/resources/qml/Governikus/SmartView/+mobile/SmartSettingsView.qml @@ -1,113 +1,93 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 -import Governikus.Type.SmartModel 1.0 -import Governikus.Type.PersonalizationModel 1.0 - -Item { - id: root +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.TitleBar +import Governikus.View +import Governikus.Type.SmartModel +import Governikus.Type.PersonalizationModel + +ColumnLayout { + id: contentLayout readonly property int smartState: SmartModel.smartState - signal checkSmart + signal changePin signal deletePersonalization - signal deleteSmart - signal setupSmart + signal startSelfAuth signal updateSmart - implicitHeight: contentLayout.implicitHeight - implicitWidth: contentLayout.implicitWidth - - ColumnLayout { - id: contentLayout - anchors.fill: parent + GOptionsContainer { + Layout.fillWidth: true spacing: Constants.component_spacing - TitledSeparator { - Layout.fillWidth: true - contentMarginBottom: 0 - contentMarginLeft: 0 - contentMarginRight: 0 - contentMarginTop: 0 + //: LABEL ANDROID IOS + title: qsTr("Smart-eID") - //: LABEL ANDROID IOS - title: qsTr("Smart-eID") - } MenuItem { - Layout.fillWidth: true - contentMarginLeft: 0 - contentMarginRight: 0 - contentMarginVertical: 0 //: LABEL ANDROID IOS - description: qsTr("Check device compatibility and the current state of any present Smart-eID") + description: qsTr("Show Smart-eID data") //: LABEL ANDROID IOS - title: qsTr("Check Smart-eID status") - visible: smartState > SmartModel.SMART_UPDATING_STATUS + title: qsTr("Try Smart-eID") + visible: smartState === SmartModel.SMART_READY + width: parent.width - onClicked: checkSmart() + onClicked: startSelfAuth() + } + GSeparator { + anchors.left: parent.left + anchors.leftMargin: Constants.component_spacing + anchors.right: parent.right + anchors.rightMargin: Constants.component_spacing } MenuItem { - Layout.fillWidth: true - contentMarginLeft: 0 - contentMarginRight: 0 - contentMarginVertical: 0 //: LABEL ANDROID IOS - description: qsTr("Set up Smart-eID on this device") + description: qsTr("Change the chosen Smart-eID PIN") //: LABEL ANDROID IOS - title: qsTr("Set up Smart-eID") - visible: smartState > SmartModel.SMART_UNAVAILABLE && smartState < SmartModel.SMART_READY + title: qsTr("Change Smart-eID PIN") + visible: smartState === SmartModel.SMART_READY + width: parent.width - onClicked: setupSmart() + onClicked: changePin() + } + GSeparator { + anchors.left: parent.left + anchors.leftMargin: Constants.component_spacing + anchors.right: parent.right + anchors.rightMargin: Constants.component_spacing } MenuItem { - Layout.fillWidth: true - contentMarginLeft: 0 - contentMarginRight: 0 - contentMarginVertical: 0 //: LABEL ANDROID IOS description: qsTr("Renew your Smart-eID with current data") //: LABEL ANDROID IOS title: qsTr("Renew Smart-eID") visible: smartState === SmartModel.SMART_READY + width: parent.width onClicked: updateSmart() } + GSeparator { + anchors.left: parent.left + anchors.leftMargin: Constants.component_spacing + anchors.right: parent.right + anchors.rightMargin: Constants.component_spacing + } MenuItem { - Layout.fillWidth: true - contentMarginLeft: 0 - contentMarginRight: 0 - contentMarginVertical: 0 //: LABEL ANDROID IOS - description: qsTr("Remove Smart-eID data from your device") + description: qsTr("Delete Smart-eID data from your device") //: LABEL ANDROID IOS title: qsTr("Delete Smart-eID") visible: smartState === SmartModel.SMART_READY + width: parent.width onClicked: deletePersonalization() } - MenuItem { - Layout.fillWidth: true - contentMarginLeft: 0 - contentMarginRight: 0 - contentMarginVertical: 0 - //: LABEL ANDROID IOS - description: qsTr("Remove Smart-eID data and provisioning from your device") - - //: LABEL ANDROID IOS - title: qsTr("Reset Smart-eID") - visible: smartState > SmartModel.SMART_UPDATING_STATUS - - onClicked: deleteSmart() - } } } diff --git a/resources/qml/Governikus/SmartView/+mobile/SmartSetupStartView.qml b/resources/qml/Governikus/SmartView/+mobile/SmartSetupStartView.qml index a00517101..a05160d14 100644 --- a/resources/qml/Governikus/SmartView/+mobile/SmartSetupStartView.qml +++ b/resources/qml/Governikus/SmartView/+mobile/SmartSetupStartView.qml @@ -1,21 +1,23 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.View 1.0 -import Governikus.TitleBar 1.0 -import Governikus.Type.PersonalizationModel 1.0 -import Governikus.Type.SettingsModel 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.View +import Governikus.TitleBar +import Governikus.Type.PersonalizationModel +import Governikus.Type.SettingsModel -SectionPage { +FlickableSectionPage { id: root + smartEidUsed: true + spacing: Constants.component_spacing + //: LABEL ANDROID IOS title: qsTr("Smart-eID") - titleBarColor: Style.color.accent_smart navigationAction: NavigationAction { action: NavigationAction.Action.Back @@ -23,50 +25,43 @@ SectionPage { onClicked: pop() } - ColumnLayout { - anchors.fill: parent - anchors.margins: Constants.component_spacing - spacing: Constants.component_spacing - - TintableIcon { - Layout.alignment: Qt.AlignHCenter - Layout.fillHeight: true - Layout.maximumHeight: Style.dimens.header_icon_size - source: "qrc:///images/identify.svg" - tintColor: Style.color.accent + TintableIcon { + Layout.alignment: Qt.AlignHCenter + source: "qrc:///images/identify.svg" + sourceSize.height: Style.dimens.header_icon_size + tintColor: Style.color.control - PkiSwitch { - anchors.fill: parent - } + PkiSwitch { + anchors.fill: parent + //: LABEL ANDROID IOS + functionName: qsTr("Smart-eID setup") } - GPane { - Layout.alignment: Qt.AlignHCenter - Layout.fillWidth: true - Layout.maximumWidth: Style.dimens.max_text_width + } + GPane { + Layout.fillWidth: true - GText { + GText { - //: LABEL ANDROID IOS - text: qsTr("You are about to set up a Smart-eID on your device. In order to proceed, you need you ID card, your six-digit ID card PIN and an internet connection.") - width: parent.width - } - PrivacyStatement { - smart: true - width: parent.width - } + //: LABEL ANDROID IOS + text: qsTr("You are about to set up a Smart-eID on your device. In order to proceed, you need you ID card, your six-digit ID card PIN and an internet connection.") + width: parent.width } - GSpacer { - Layout.fillHeight: true + PrivacyStatement { + smart: true + width: parent.width } - GButton { - Layout.alignment: Qt.AlignHCenter - buttonColor: SettingsModel.useSelfauthenticationTestUri ? Style.color.warning_text : Style.color.accent - icon.source: "qrc:///images/identify.svg" + } + GSpacer { + Layout.fillHeight: true + } + GButton { + Layout.alignment: Qt.AlignHCenter + buttonColor: SettingsModel.useSelfauthenticationTestUri ? Style.color.text_warning : Style.color.control + icon.source: "qrc:///images/identify.svg" - //: LABEL ANDROID IOS - text: qsTr("Set up Smart-eID") + //: LABEL ANDROID IOS + text: qsTr("Set up Smart-eID") - onClicked: PersonalizationModel.startWorkflow() - } + onClicked: PersonalizationModel.startWorkflow() } } diff --git a/resources/qml/Governikus/SmartView/+mobile/SmartUpdateStartView.qml b/resources/qml/Governikus/SmartView/+mobile/SmartUpdateStartView.qml index d116fa71d..4e1e1593a 100644 --- a/resources/qml/Governikus/SmartView/+mobile/SmartUpdateStartView.qml +++ b/resources/qml/Governikus/SmartView/+mobile/SmartUpdateStartView.qml @@ -1,22 +1,23 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.View 1.0 -import Governikus.TitleBar 1.0 -import Governikus.Type.PersonalizationModel 1.0 -import Governikus.Type.SettingsModel 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.View +import Governikus.TitleBar +import Governikus.Type.PersonalizationModel +import Governikus.Type.SettingsModel -SectionPage { +FlickableSectionPage { id: root - sectionPageFlickable: contentItem + + smartEidUsed: true + spacing: Constants.component_spacing //: LABEL ANDROID IOS - title: qsTr("Smart-eID") - titleBarColor: Style.color.accent_smart + title: qsTr("Renew the Smart-eID") navigationAction: NavigationAction { action: NavigationAction.Action.Back @@ -24,65 +25,51 @@ SectionPage { onClicked: pop() } - GFlickableColumnLayout { - id: contentItem - - readonly property var maxIconHeight: Style.dimens.header_icon_size - readonly property var minIconHeight: Style.dimens.medium_icon_size - - anchors.fill: parent - maximumContentWidth: Style.dimens.max_text_width - minimumContentHeight: implicitContentHeight - (maxIconHeight - minIconHeight) - spacing: Constants.component_spacing - - TintableIcon { - Layout.alignment: Qt.AlignHCenter - Layout.fillHeight: true - Layout.maximumHeight: contentItem.maxIconHeight - Layout.minimumHeight: contentItem.minIconHeight - Layout.preferredHeight: contentItem.maxIconHeight - source: "qrc:///images/identify.svg" - sourceSize.height: contentItem.maxIconHeight - tintColor: Style.color.accent + TintableIcon { + Layout.alignment: Qt.AlignHCenter + source: "qrc:///images/identify.svg" + sourceSize.height: Style.dimens.header_icon_size + tintColor: Style.color.control - PkiSwitch { - anchors.fill: parent - } + PkiSwitch { + anchors.fill: parent + //: LABEL ANDROID IOS + functionName: qsTr("Smart-eID renewal") } - GPane { - Layout.alignment: Qt.AlignHCenter - Layout.fillWidth: true + } + GPane { + Layout.alignment: Qt.AlignHCenter + Layout.fillWidth: true - GText { + GText { - //: LABEL ANDROID IOS - text: qsTr("You are about to renew your Smart-eID. In order to proceed, you need your ID card, your six-digit ID card PIN and an internet connection.") - width: parent.width - } - GText { + //: LABEL ANDROID IOS + text: qsTr("You are about to renew your Smart-eID. In order to proceed, you need your ID card, your six-digit ID card PIN and an internet connection.") + width: parent.width + } + GText { + font.bold: true - //: LABEL ANDROID IOS - text: qsTr("Please note that your current Smart-eID is invalidated during the process and will not be usable until the update process is completed.") - textStyle: Style.text.normal_highlight - width: parent.width - } - PrivacyStatement { - smart: true - width: parent.width - } + //: LABEL ANDROID IOS + text: qsTr("Please note that your current Smart-eID is invalidated during the process and will not be usable until the update process is completed.") + width: parent.width } - GSpacer { - Layout.fillHeight: true + PrivacyStatement { + smart: true + width: parent.width } - GButton { - Layout.alignment: Qt.AlignHCenter - buttonColor: SettingsModel.useSelfauthenticationTestUri ? Style.color.warning_text : Style.color.accent - icon.source: "qrc:///images/identify.svg" + } + GSpacer { + Layout.fillHeight: true + } + GButton { + Layout.alignment: Qt.AlignHCenter + buttonColor: SettingsModel.useSelfauthenticationTestUri ? Style.color.text_warning : Style.color.control + icon.source: "qrc:///images/identify.svg" - //: LABEL ANDROID IOS - text: qsTr("Renew Smart-eID") + //: LABEL ANDROID IOS + text: qsTr("Renew Smart-eID") - onClicked: PersonalizationModel.startWorkflow() - } + onClicked: PersonalizationModel.startWorkflow() } } diff --git a/resources/qml/Governikus/SmartView/+mobile/SmartView.qml b/resources/qml/Governikus/SmartView/+mobile/SmartView.qml index fc2a8fbc6..a42531439 100644 --- a/resources/qml/Governikus/SmartView/+mobile/SmartView.qml +++ b/resources/qml/Governikus/SmartView/+mobile/SmartView.qml @@ -1,24 +1,29 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.CheckSmartView 1.0 -import Governikus.Global 1.0 -import Governikus.ProgressView 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.Type.SmartModel 1.0 -import Governikus.Type.UiModule 1.0 -import Governikus.View 1.0 - -SectionPage { +import QtQuick +import Governikus.AuthView +import Governikus.ChangePinView +import Governikus.Global +import Governikus.SelfAuthenticationView +import Governikus.Style +import Governikus.TitleBar +import Governikus.View +import Governikus.Type.ChangePinModel +import Governikus.Type.ConnectivityManager +import Governikus.Type.ReaderPlugIn +import Governikus.Type.SmartModel +import Governikus.Type.UiModule + +FlickableSectionPage { id: root - sectionPageFlickable: smartMainView + smartEidUsed: true + title: smartMainView.visible ? + //: LABEL ANDROID IOS + qsTr("Smart-eID") : //: LABEL ANDROID IOS - title: qsTr("Smart-eID") - titleBarColor: Style.color.accent_smart + qsTr("Check Smart-eID") navigationAction: NavigationAction { action: NavigationAction.Action.Back @@ -28,108 +33,108 @@ SectionPage { PersonalizationController { id: controller + + stackView: root.stackView } Component { id: setupStartView + SmartSetupStartView { } } Component { id: updateStartView + SmartUpdateStartView { } } Component { - id: deleteProgressView - ProgressView { - progressValue: SmartModel.progress - //: LABEL ANDROID IOS - subText: qsTr("Please wait a moment.") - title: qsTr("Smart-eID") - titleBarColor: Style.color.accent_smart + id: deletePersonalizationStartview + + SmartDeleteView { } } Component { - id: deletePersonalizationStartview - SmartDeleteStartView { - //: LABEL ANDROID IOS - buttonText: qsTr("Delete Smart-eID") - - //: LABEL ANDROID IOS - deleteDescriptionText: qsTr("You are about to delete the Smart-eID data that is currently stored on your device.") - - onDeleteConfirmed: { - setLockedAndHidden(); - //: LABEL ANDROID IOS - push(deleteProgressView, { - "text": qsTr("Deleting Smart-eID") - }); - SmartModel.deletePersonalization(); - } + id: changePinView - Connections { - function onFireDeletePersonalizationDone() { - setLockedAndHidden(false); - popAll(); - } + ChangePinView { + autoInsertCard: true + hidePinTypeSelection: true + hideTechnologySwitch: true + initialPlugIn: ReaderPlugIn.SMART - target: SmartModel - } + Component.onCompleted: ChangePinModel.startWorkflow(false, false) + onWorkflowFinished: popAll() } } Component { - id: deleteStartview - SmartDeleteStartView { - //: LABEL ANDROID IOS - buttonText: qsTr("Reset Smart-eID") - - //: LABEL ANDROID IOS - deleteDescriptionText: qsTr("You are about to delete the Smart-eID data from your device and also remove the Smart-eID provisioning. This can a be used for troubleshooting as well.") - - onDeleteConfirmed: { - setLockedAndHidden(); - push(deleteProgressView, { - //: LABEL ANDROID IOS - "text": qsTr("Resetting Smart-eID"), - "progressBarVisible": true, - //: LABEL ANDROID IOS - "progressText": qsTr("Resetting Smart-eID") - }); - SmartModel.deleteSmart(); - } + id: selfAuthView - Connections { - function onFireDeleteSmartDone() { - setLockedAndHidden(false); - popAll(); - } + SelfAuthenticationView { + autoInsertCard: true + hideTechnologySwitch: true + initialPlugIn: ReaderPlugIn.SMART - target: SmartModel + onBack: pop() + } + } + Component { + id: checkConnectivityView + + CheckConnectivityView { + smartEidUsed: root.smartEidUsed + title: root.title + + Component.onCompleted: connectivityManager.watching = true + Component.onDestruction: connectivityManager.watching = false + onCancel: { + setLockedAndHidden(false); + popAll(); } } } Component { - id: checkSmartView - CheckSmartView { + id: checkSmartResultView + + CheckSmartResultView { + result: SmartModel.smartState + + onCancelClicked: { + setLockedAndHidden(false); + popAll(); + } onCheckDevice: { show(UiModule.CHECK_ID_CARD); popAll(); } onRunSmartSetup: push(setupStartView) - onStartAuth: { - show(UiModule.SELF_AUTHENTICATION); - popAll(); + } + } + ConnectivityManager { + id: connectivityManager + + onNetworkInterfaceActiveChanged: { + if (networkInterfaceActive) { + pop(); + SmartModel.updateSupportInfo(); } } } SmartMainView { id: smartMainView - anchors.fill: parent - onCheckSmart: push(checkSmartView) + onChangePin: push(changePinView) onDeletePersonalization: push(deletePersonalizationStartview) - onDeleteSmart: push(deleteStartview) - onSetupSmart: push(setupStartView) + onShowCheckResult: { + setLockedAndHidden(); + push(checkSmartResultView); + if (connectivityManager.checkConnectivity()) { + SmartModel.updateSupportInfo(); + } else { + push(checkConnectivityView); + } + } + onStartSelfAuth: push(selfAuthView) onUpdateSmart: push(updateStartView) } } diff --git a/resources/qml/Governikus/SmartView/qmldir b/resources/qml/Governikus/SmartView/qmldir index fdb908af7..5a1328108 100644 --- a/resources/qml/Governikus/SmartView/qmldir +++ b/resources/qml/Governikus/SmartView/qmldir @@ -1,14 +1,17 @@ module SmartView +internal CheckSmartResultView CheckSmartResultView.qml internal PersonalizationController PersonalizationController.qml internal PersonalizationLegalInformationView PersonalizationLegalInformationView.qml internal PersonalizationProgressView PersonalizationProgressView.qml internal PersonalizationResultView PersonalizationResultView.qml internal SmartCardView SmartCardView.qml -internal SmartDeleteStartView SmartDeleteStartView.qml +internal SmartDeleteBaseView SmartDeleteBaseView.qml internal SmartMainView SmartMainView.qml internal SmartSettingsView SmartSettingsView.qml internal SmartSetupStartView SmartSetupStartView.qml internal SmartUpdateStartView SmartUpdateStartView.qml SmartView 1.0 SmartView.qml +SmartResetView 1.0 SmartResetView.qml +SmartDeleteView 1.0 SmartDeleteView.qml diff --git a/resources/qml/Governikus/Style/+desktop/HighContrastColors.qml b/resources/qml/Governikus/Style/+desktop/HighContrastColors.qml index 67fbec7c5..f51a7c912 100644 --- a/resources/qml/Governikus/Style/+desktop/HighContrastColors.qml +++ b/resources/qml/Governikus/Style/+desktop/HighContrastColors.qml @@ -1,36 +1,47 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 +import QtQuick Colors { - readonly property color accent: palette.highlight - readonly property color accent_text: palette.text - readonly property color accent_text_inverse: palette.text readonly property color background: palette.base - readonly property color background_pane: background - readonly property color background_pane_active: background - readonly property color background_pane_inactive: background - readonly property color background_popup: background readonly property color border: palette.text - readonly property color button: palette.button - readonly property color button_disabled: disabledPalette.button - readonly property color button_text: palette.text - readonly property color button_text_disabled: disabledPalette.text + readonly property color control: palette.button + readonly property color control_border: palette.text + readonly property color control_border_disabled: disabledPalette.text + readonly property color control_border_hover: palette.text + readonly property color control_border_pressed: palette.text + readonly property color control_border_unchecked: palette.text + readonly property color control_content: palette.text + readonly property color control_content_disabled: disabledPalette.text + readonly property color control_content_hover: palette.text + readonly property color control_content_pressed: palette.text + readonly property color control_content_unchecked: palette.text + readonly property color control_disabled: disabledPalette.button + readonly property color control_hover: palette.button + readonly property color control_pressed: palette.button + readonly property color control_unchecked: palette.button readonly property var disabledPalette: SystemPalette { colorGroup: SystemPalette.Disabled } - readonly property color focus_indicator: primary_text - readonly property color focus_indicator_inverse: primary_text_inverse - readonly property color high_contrast_item_border: palette.text - readonly property color navigation: background_pane + readonly property color fail: "#ff0000" + readonly property color focus_indicator: text + readonly property color mainbutton_content_pressed: palette.text readonly property var palette: SystemPalette { colorGroup: SystemPalette.Active } - readonly property color primary_text: palette.text - readonly property color primary_text_inverse: palette.text - readonly property color secondary_text: palette.text - readonly property color secondary_text_inverse: palette.text - readonly property color shadow: transparent - readonly property color warning_text: "#ff0000" + readonly property color pane: background + readonly property color pane_active: background + readonly property color pane_border: palette.text + readonly property color pane_sublevel: background + readonly property color success: "#00ff00" + readonly property color text: palette.text + readonly property color text_disabled: disabledPalette.text + readonly property color text_headline: palette.text + readonly property color text_pressed: palette.text + readonly property color text_subline: palette.text + readonly property color text_subline_disabled: disabledPalette.text + readonly property color text_subline_pressed: palette.text + readonly property color text_title: palette.text + readonly property color text_warning: "#ff0000" } diff --git a/resources/qml/Governikus/Style/+desktop/HighContrastDimensions.qml b/resources/qml/Governikus/Style/+desktop/HighContrastDimensions.qml deleted file mode 100644 index 15545ea46..000000000 --- a/resources/qml/Governikus/Style/+desktop/HighContrastDimensions.qml +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQml 2.15 -import Governikus.Type.ApplicationModel 1.0 - -Dimensions { - readonly property int high_contrast_item_border: Math.max(ApplicationModel.scaleFactor * 2, 1) - readonly property int tabbed_pane_separator_size: 0 -} diff --git a/resources/qml/Governikus/Style/+desktop/PlatformColors.qml b/resources/qml/Governikus/Style/+desktop/PlatformColors.qml deleted file mode 100644 index d22cd0538..000000000 --- a/resources/qml/Governikus/Style/+desktop/PlatformColors.qml +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQml 2.15 - -QtObject { - readonly property color background_pane: "#ffffff" - readonly property color background_pane_active: "#d5d5dc" - readonly property color background_pane_inactive: accent - readonly property color background_popup: background - readonly property color border: "#bbbbbb" - readonly property color navigation: accent -} diff --git a/resources/qml/Governikus/Style/+desktop/PlatformDimensions.qml b/resources/qml/Governikus/Style/+desktop/PlatformDimensions.qml index ca3350f3f..e3000872c 100644 --- a/resources/qml/Governikus/Style/+desktop/PlatformDimensions.qml +++ b/resources/qml/Governikus/Style/+desktop/PlatformDimensions.qml @@ -1,38 +1,45 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQml 2.15 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.SettingsModel 1.0 +import QtQml +import Governikus.Type.SettingsModel QtObject { - readonly property int button_radius: ApplicationModel.scaleFactor * 15 - readonly property int corner_radius: ApplicationModel.scaleFactor * 20 - readonly property int corner_radius_popup: corner_radius - readonly property int header_font_size: ApplicationModel.scaleFactor * 32 - readonly property int high_contrast_item_border: ApplicationModel.scaleFactor * 0 - readonly property int hint_font_size: ApplicationModel.scaleFactor * 22 - readonly property int huge_icon_size: ApplicationModel.scaleFactor * 200 - readonly property int icon_size: ApplicationModel.scaleFactor * 48 + readonly property real border_width: Math.max(plugin.scaleFactor * 2, 1) + readonly property real control_radius: plugin.scaleFactor * 26 + readonly property real header_icon_size: plugin.scaleFactor * 200 + readonly property real huge_icon_size: plugin.scaleFactor * 125 + readonly property real icon_size: plugin.scaleFactor * 48 readonly property bool isLongLanguage: SettingsModel.language === "uk" || SettingsModel.language === "ru" - readonly property int large_icon_size: ApplicationModel.scaleFactor * 72 - readonly property int list_item_height: ApplicationModel.scaleFactor * 64 - readonly property real max_text_width: ApplicationModel.scaleFactor * (isLongLanguage ? 1250 : 1000) - readonly property int medium_icon_size: ApplicationModel.scaleFactor * 64 - readonly property int navigation_font_size: header_font_size - readonly property int normal_font_size: ApplicationModel.scaleFactor * 26 - readonly property int popup_border: Math.max(ApplicationModel.scaleFactor * 2, 1) - readonly property int progress_bar_border: separator_size_large - readonly property int progress_bar_height: ApplicationModel.scaleFactor * 48 - readonly property int scrollbar_padding_horizontal: ApplicationModel.scaleFactor * 5 - readonly property int scrollbar_padding_vertical: ApplicationModel.scaleFactor * 0 - readonly property int scrollbar_width: ApplicationModel.scaleFactor * 10 - readonly property int separator_size: Math.max(ApplicationModel.scaleFactor * 2, 1) - readonly property int separator_size_large: Math.max(ApplicationModel.scaleFactor * 4, 1) - readonly property int status_icon_large: ApplicationModel.scaleFactor * 350 - readonly property int status_icon_medium: ApplicationModel.scaleFactor * 200 - readonly property int status_icon_small: ApplicationModel.scaleFactor * 100 - readonly property int tabbed_pane_separator_size: separator_size_large - readonly property int title_font_size: ApplicationModel.scaleFactor * 42 - readonly property int titlebar_padding: ApplicationModel.scaleFactor * 20 + readonly property real large_icon_size: plugin.scaleFactor * 72 + readonly property real lineHeight: plugin.scaleFactor * 40 + readonly property real lineHeight_button: plugin.scaleFactor * 27 + readonly property real lineHeight_headline: plugin.scaleFactor * 47 + readonly property real lineHeight_navigation: plugin.scaleFactor * 63 + readonly property real lineHeight_subline: plugin.scaleFactor * 42 + readonly property real lineHeight_title: plugin.scaleFactor * 70 + readonly property real list_item_height: plugin.scaleFactor * 64 + readonly property real max_text_width: plugin.scaleFactor * (isLongLanguage ? 1250 : 1000) + readonly property real medium_icon_size: plugin.scaleFactor * 64 + readonly property real min_button_width: plugin.scaleFactor * 200 + readonly property real pane_radius: plugin.scaleFactor * 34 + readonly property real popup_border: Math.max(plugin.scaleFactor * 2, 1) + readonly property real progress_bar_border: separator_size_large + readonly property real progress_bar_height: plugin.scaleFactor * 48 + readonly property real scrollbar_padding_horizontal: plugin.scaleFactor * 5 + readonly property real scrollbar_padding_vertical: plugin.scaleFactor * 0 + readonly property real scrollbar_width: plugin.scaleFactor * 10 + readonly property real separator_size: Math.max(plugin.scaleFactor * 2, 1) + readonly property real separator_size_large: Math.max(plugin.scaleFactor * 4, 1) + readonly property real small_icon_size: plugin.scaleFactor * 32 + readonly property real status_icon_medium: plugin.scaleFactor * 200 + readonly property real status_icon_small: plugin.scaleFactor * 100 + readonly property real switch_width: plugin.scaleFactor * 97 + readonly property real text: plugin.scaleFactor * 27 + readonly property real text_headline: plugin.scaleFactor * 40 + readonly property real text_navigation: plugin.scaleFactor * 50 + readonly property real text_subline: plugin.scaleFactor * 30 + readonly property real text_title: plugin.scaleFactor * 60 + readonly property real titlebar_padding: plugin.scaleFactor * 20 + readonly property real titlepane_radius: plugin.scaleFactor * 50 } diff --git a/resources/qml/Governikus/Style/+desktop/PlatformTextStyles.qml b/resources/qml/Governikus/Style/+desktop/PlatformTextStyles.qml deleted file mode 100644 index 3a6c56d3b..000000000 --- a/resources/qml/Governikus/Style/+desktop/PlatformTextStyles.qml +++ /dev/null @@ -1,7 +0,0 @@ -/** - * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 - -QtObject { -} diff --git a/resources/qml/Governikus/Style/+mobile/+android/BrandColors.qml b/resources/qml/Governikus/Style/+mobile/+android/BrandColors.qml deleted file mode 100644 index feb589038..000000000 --- a/resources/qml/Governikus/Style/+mobile/+android/BrandColors.qml +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQml 2.15 - -QtObject { - readonly property color menu_icon_tint_color: "#86858A" -} diff --git a/resources/qml/Governikus/Style/+mobile/+android/BrandDimensions.qml b/resources/qml/Governikus/Style/+mobile/+android/BrandDimensions.qml index d997f4d94..d0c0d9dab 100644 --- a/resources/qml/Governikus/Style/+mobile/+android/BrandDimensions.qml +++ b/resources/qml/Governikus/Style/+mobile/+android/BrandDimensions.qml @@ -1,15 +1,13 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 +import QtQuick +import Governikus.Global QtObject { - readonly property int corner_radius_popup: 2 - readonly property int header_font_size: 20 - readonly property int hint_font_size: 14 - readonly property int menubar_width: 64 - readonly property int navigation_font_size: 12 - readonly property int normal_font_size: 16 - readonly property int title_font_size: 22 + readonly property real text: 15 * plugin.fontScaleFactor + readonly property real text_headline: 26 * plugin.fontScaleFactor + readonly property real text_navigation: 12 * plugin.fontScaleFactor + readonly property real text_subline: 18 * plugin.fontScaleFactor + readonly property real text_title: 30 * plugin.fontScaleFactor } diff --git a/resources/qml/Governikus/Style/+mobile/+android/PlatformTextStyles.qml b/resources/qml/Governikus/Style/+mobile/+android/PlatformTextStyles.qml deleted file mode 100644 index 9fb1f20ab..000000000 --- a/resources/qml/Governikus/Style/+mobile/+android/PlatformTextStyles.qml +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 - -QtObject { - readonly property var tutorial_content: TextStyle { - textFamily: "Noto Serif" - textSize: Style.dimens.normal_font_size - } - readonly property var tutorial_content_highlight: TextStyle { - bold: true - textFamily: "Noto Serif" - textSize: Style.dimens.normal_font_size - } - readonly property var tutorial_header: TextStyle { - textFamily: "Noto Serif" - textSize: Style.dimens.tutorial_header_font_size - } - readonly property var tutorial_header_accent: TextStyle { - italic: true - textFamily: "Noto Serif" - textSize: Style.dimens.tutorial_header_font_size - } - readonly property var tutorial_header_highlight: TextStyle { - bold: true - textFamily: "Noto Serif" - textSize: Style.dimens.tutorial_header_font_size - } - readonly property var tutorial_header_secondary: TextStyle { - textFamily: "Noto Serif" - textSize: Style.dimens.header_font_size - } - readonly property var tutorial_header_secondary_highlight: TextStyle { - bold: true - textFamily: "Noto Serif" - textSize: Style.dimens.header_font_size - } - readonly property var tutorial_title_highlight: TextStyle { - bold: true - textSize: Style.dimens.tutorial_title_font_size - } -} diff --git a/resources/qml/Governikus/Style/+mobile/+ios/BrandColors.qml b/resources/qml/Governikus/Style/+mobile/+ios/BrandColors.qml deleted file mode 100644 index 7cb633e97..000000000 --- a/resources/qml/Governikus/Style/+mobile/+ios/BrandColors.qml +++ /dev/null @@ -1,7 +0,0 @@ -/** - * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQml 2.15 - -QtObject { -} diff --git a/resources/qml/Governikus/Style/+mobile/+ios/BrandDimensions.qml b/resources/qml/Governikus/Style/+mobile/+ios/BrandDimensions.qml index c5471a525..2735cee61 100644 --- a/resources/qml/Governikus/Style/+mobile/+ios/BrandDimensions.qml +++ b/resources/qml/Governikus/Style/+mobile/+ios/BrandDimensions.qml @@ -1,22 +1,21 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Window 2.2 -import Governikus.Global 1.0 +import QtQuick +import QtQuick.Window +import Governikus.Global QtObject { - readonly property int corner_radius_popup: corner_radius - readonly property int header_font_size: scaleText(20) - readonly property int hint_font_size: scaleText(14) - readonly property int navigation_font_size: scaleText(12) - readonly property int normal_font_size: scaleText(16) - readonly property int searchbar_height: 52 - readonly property int title_font_size: scaleText(22) + // If this font size changes, it has to be changed in UIPlugInQml, too. + readonly property real text: scaleText(15) * plugin.fontScaleFactor + readonly property real text_headline: scaleText(26) * plugin.fontScaleFactor + readonly property real text_navigation: scaleText(12) * plugin.fontScaleFactor + readonly property real text_subline: scaleText(18) * plugin.fontScaleFactor + readonly property real text_title: scaleText(30) * plugin.fontScaleFactor // Scale the text on small devices like the iPhone SE function scaleText(value) { - var w = Screen.width; + let w = Screen.width; if (w > 415) { return value; } diff --git a/resources/qml/Governikus/Style/+mobile/+ios/PlatformTextStyles.qml b/resources/qml/Governikus/Style/+mobile/+ios/PlatformTextStyles.qml deleted file mode 100644 index 62c5a0683..000000000 --- a/resources/qml/Governikus/Style/+mobile/+ios/PlatformTextStyles.qml +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 - -QtObject { - readonly property var tutorial_content: TextStyle { - textFamily: "Charter" - textSize: Style.dimens.normal_font_size - } - readonly property var tutorial_content_highlight: TextStyle { - bold: true - textFamily: "Charter" - textSize: Style.dimens.normal_font_size - } - readonly property var tutorial_header: TextStyle { - textFamily: "Charter" - textSize: Style.dimens.tutorial_header_font_size - } - readonly property var tutorial_header_accent: TextStyle { - italic: true - textFamily: "Charter" - textSize: Style.dimens.tutorial_header_font_size - } - readonly property var tutorial_header_highlight: TextStyle { - bold: true - textFamily: "Charter" - textSize: Style.dimens.tutorial_header_font_size - } - readonly property var tutorial_header_secondary: TextStyle { - textFamily: "Charter" - textSize: Style.dimens.header_font_size - } - readonly property var tutorial_header_secondary_highlight: TextStyle { - bold: true - textFamily: "Charter" - textSize: Style.dimens.header_font_size - } - readonly property var tutorial_title_highlight: TextStyle { - bold: true - textSize: Style.dimens.tutorial_title_font_size - } -} diff --git a/resources/qml/Governikus/Style/+mobile/HighContrastColors.qml b/resources/qml/Governikus/Style/+mobile/HighContrastColors.qml index 349931c5d..b785a2b26 100644 --- a/resources/qml/Governikus/Style/+mobile/HighContrastColors.qml +++ b/resources/qml/Governikus/Style/+mobile/HighContrastColors.qml @@ -1,7 +1,7 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 +import QtQuick Colors { } diff --git a/resources/qml/Governikus/Style/+mobile/HighContrastDimensions.qml b/resources/qml/Governikus/Style/+mobile/HighContrastDimensions.qml deleted file mode 100644 index 49902e99f..000000000 --- a/resources/qml/Governikus/Style/+mobile/HighContrastDimensions.qml +++ /dev/null @@ -1,7 +0,0 @@ -/** - * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQml 2.15 - -Dimensions { -} diff --git a/resources/qml/Governikus/Style/+mobile/PlatformColors.qml b/resources/qml/Governikus/Style/+mobile/PlatformColors.qml deleted file mode 100644 index 10cffce4d..000000000 --- a/resources/qml/Governikus/Style/+mobile/PlatformColors.qml +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 - -BrandColors { - readonly property color background_item_pressed: "#bacdde" - readonly property color background_pane: "#ffffff" - readonly property color background_pane_active: "#d5d5dc" - readonly property color background_popup: "#ffffff" - readonly property color border: "#a0858585" - readonly property color card_reader: "#444445" - readonly property color switch_checked: accent - readonly property color switch_unchecked: "#ffffff" - readonly property color tutorial_box_background: "#f2f2f2" - readonly property color tutorial_how: "#164a8c" - readonly property color tutorial_important: "#fb7a59" - readonly property color tutorial_what: "#f9a501" - readonly property color tutorial_where: "#73d7b3" -} diff --git a/resources/qml/Governikus/Style/+mobile/PlatformDimensions.qml b/resources/qml/Governikus/Style/+mobile/PlatformDimensions.qml index 3b7d6b830..0939d63c7 100644 --- a/resources/qml/Governikus/Style/+mobile/PlatformDimensions.qml +++ b/resources/qml/Governikus/Style/+mobile/PlatformDimensions.qml @@ -1,38 +1,43 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQml 2.15 -import Governikus.Global 1.0 -import Governikus.Type.SettingsModel 1.0 -import QtQuick.Window 2.15 +import QtQml +import Governikus.Global +import Governikus.Type.SettingsModel BrandDimensions { - readonly property int button_radius: 6 - readonly property int corner_radius: 10 - readonly property int header_icon_size: Constants.is_tablet ? Math.min(Screen.height / 5, 240) : huge_icon_size - readonly property int high_contrast_item_border: 0 - readonly property int huge_icon_size: 160 + readonly property int border_width: 1 + readonly property int control_radius: 12 + readonly property real header_icon_size: screenHeight / 7 readonly property int icon_size: 48 readonly property bool isLongLanguage: SettingsModel.language === "uk" || SettingsModel.language === "ru" readonly property int large_icon_size: 96 + readonly property int lineHeight: 21 + readonly property int lineHeight_button: 15 + readonly property int lineHeight_headline: 34 + readonly property int lineHeight_navigation: 12 + readonly property int lineHeight_subline: 25 + readonly property int lineHeight_title: 36 readonly property int list_item_height: 64 - readonly property real max_text_width: isLongLanguage ? 800 : 700 + readonly property int max_text_width: isLongLanguage ? 800 : 700 readonly property int medium_icon_size: 64 - readonly property int navigation_bar_height: 49 - readonly property int navigation_bar_padding: 5 + readonly property int min_button_width: 80 + readonly property int navigation_bar_icon_size: 20 + readonly property int navigation_bar_min_height: 49 + readonly property int navigation_bar_padding: 10 readonly property int navigation_bar_text_padding: 1 + readonly property int pageindicator_size: 8 + readonly property int pane_radius: 22 readonly property int popup_border: 0 readonly property int progress_bar_border: 2 readonly property int progress_bar_height: 32 + property int screenHeight: 0 readonly property int scrollbar_padding_horizontal: 0 readonly property int scrollbar_padding_vertical: 5 readonly property int scrollbar_width: 5 readonly property int separator_size: 1 readonly property int small_icon_size: 24 - readonly property int titlebar_height: 48 - readonly property int titlebar_padding: 8 - readonly property int tutorial_component_spacing: 40 - readonly property int tutorial_header_font_size: 26 - readonly property int tutorial_title_font_size: 60 - readonly property int workflow_progress_indicator_size: 1.5 * header_icon_size + readonly property int switch_width: 58 + readonly property int titlebar_padding: 20 + readonly property real workflow_progress_indicator_size: 1.5 * header_icon_size } diff --git a/resources/qml/Governikus/Style/Colors.qml b/resources/qml/Governikus/Style/Colors.qml index 3a3ebd6a0..9231eebc8 100644 --- a/resources/qml/Governikus/Style/Colors.qml +++ b/resources/qml/Governikus/Style/Colors.qml @@ -1,28 +1,49 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 +import QtQuick -PlatformColors { - readonly property color accent: "#164a8c" - readonly property color accent_smart: "#327509" - readonly property color accent_text: accent - readonly property color accent_text_inverse: "#cde1f3" - readonly property color background: "#ebf3fd" - readonly property color button: accent - readonly property color button_disabled: "#757575" - readonly property color button_text: primary_text_inverse - readonly property color button_text_disabled: primary_text_inverse - readonly property color focus_indicator: primary_text - readonly property color focus_indicator_inverse: primary_text_inverse - readonly property color high_contrast_item_border: transparent - readonly property color info_text: "#b25e2a" - readonly property color primary_text: "#242424" - readonly property color primary_text_inverse: "#ffffff" - readonly property color secondary_text: "#404040" - readonly property color secondary_text_inverse: "#aaaaaa" - readonly property color shadow: "#808080" - readonly property color success: "#3e843e" +QtObject { + readonly property color background: "#ffffff" + readonly property color border: "#bbbbbb" + readonly property color card_eid: "#0077b6" + readonly property color card_reader: "#444445" + readonly property color card_smart: "#327509" + readonly property color control: "#0077b6" + readonly property color control_border: "#0077b6" + readonly property color control_border_disabled: "#bcc0c1" + readonly property color control_border_hover: "#80cdec" + readonly property color control_border_pressed: "#0077b6" + readonly property color control_border_unchecked: "#576164" + readonly property color control_content: "#ffffff" + readonly property color control_content_disabled: "#ffffff" + readonly property color control_content_hover: "#ffffff" + readonly property color control_content_pressed: "#0077b6" + readonly property color control_content_unchecked: "#576164" + readonly property color control_disabled: "#bcc0c1" + readonly property color control_hover: "#80cdec" + readonly property color control_pressed: "#ffffff" + readonly property color control_unchecked: "#ffffff" + readonly property color fail: "#db6a00" + readonly property color focus_indicator: "#242424" + readonly property color mainbutton_content_pressed: "#ffffff" + readonly property color pane: "#ffffff" + readonly property color pane_active: "#0077b6" + readonly property color pane_border: software_renderer ? border : transparent + readonly property color pane_sublevel: "#f2f3f4" + readonly property color pane_title: "#f2f3f4" + property bool software_renderer: false + readonly property color success: "#3e8401" + readonly property color text: "#576164" + readonly property color text_disabled: "#bcc0c1" + readonly property color text_headline: "#576164" + readonly property color text_navigation: "#ffffff" + readonly property color text_navigation_unchecked: "#576164" + readonly property color text_pressed: "#ffffff" + readonly property color text_subline: "#0077b6" + readonly property color text_subline_disabled: "#80cdec" + readonly property color text_subline_pressed: "#ffffff" + readonly property color text_title: "#004b76" + readonly property color text_warning: "#eb0000" readonly property color transparent: "transparent" - readonly property color warning_text: "#9d0100" } diff --git a/resources/qml/Governikus/Style/DarkModeColors.qml b/resources/qml/Governikus/Style/DarkModeColors.qml new file mode 100644 index 000000000..3827c2269 --- /dev/null +++ b/resources/qml/Governikus/Style/DarkModeColors.qml @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick + +QtObject { + readonly property color background: "#232323" + readonly property color border: "#ffffff" + readonly property color card_eid: "#0077b6" + readonly property color card_reader: "#444445" + readonly property color card_smart: "#327509" + readonly property color control: "#0098eb" + readonly property color control_border: "#0098eb" + readonly property color control_border_disabled: "#798183" + readonly property color control_border_hover: "#80cdec" + readonly property color control_border_pressed: "#0098eb" + readonly property color control_border_unchecked: "#ffffff" + readonly property color control_content: "#ffffff" + readonly property color control_content_disabled: "#798183" + readonly property color control_content_hover: "#ffffff" + readonly property color control_content_pressed: "#0098eb" + readonly property color control_content_unchecked: "#ffffff" + readonly property color control_disabled: "#303030" + readonly property color control_hover: "#80cdec" + readonly property color control_pressed: "#ffffff" + readonly property color control_unchecked: "#232323" + readonly property color fail: "#ff9b29" + readonly property color focus_indicator: "#0098eb" + readonly property color mainbutton_content_pressed: "#ffffff" + readonly property color pane: "#303030" + readonly property color pane_active: "#0098eb" + readonly property color pane_border: software_renderer ? border : transparent + readonly property color pane_sublevel: "#576164" + readonly property color pane_title: "#576164" + property bool software_renderer: false + readonly property color success: "#5fcb01" + readonly property color text: "#ffffff" + readonly property color text_disabled: "#bcc0c1" + readonly property color text_headline: "#ffffff" + readonly property color text_navigation: "#232323" + readonly property color text_navigation_unchecked: "#80cdec" + readonly property color text_pressed: "#000000" + readonly property color text_subline: "#80cdec" + readonly property color text_subline_disabled: "#798183" + readonly property color text_subline_pressed: "#000000" + readonly property color text_title: "#80cdec" + readonly property color text_warning: "#eb0000" + readonly property color transparent: "transparent" +} diff --git a/resources/qml/Governikus/Style/Style.qml b/resources/qml/Governikus/Style/Style.qml index f2c3d6e54..523fc2973 100644 --- a/resources/qml/Governikus/Style/Style.qml +++ b/resources/qml/Governikus/Style/Style.qml @@ -2,36 +2,59 @@ * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ pragma Singleton -import QtQuick 2.15 +import QtQuick +import Governikus.Type.SettingsModel +import Governikus.Type.ModeOption Item { id: style readonly property var color: currentTheme.color - readonly property var currentTheme: plugin.highContrastEnabled ? highContrastTheme : defaultTheme + readonly property var currentTheme: plugin.highContrastEnabled ? highContrastTheme : useDarkMode ? darkTheme : defaultTheme readonly property var dimens: currentTheme.dimens + property bool software_renderer: false readonly property var text: currentTheme.text + readonly property bool useDarkMode: (plugin.osDarkModeEnabled && SettingsModel.userDarkMode === ModeOption.AUTO) || SettingsModel.userDarkMode === ModeOption.ON + QtObject { + id: darkTheme + + readonly property var color: DarkModeColors { + software_renderer: style.software_renderer + } + readonly property alias dimens: dimensions + readonly property bool highContrast: false + readonly property string name: "darkmode" + readonly property alias text: textStyles + } QtObject { id: highContrastTheme readonly property var color: HighContrastColors { + software_renderer: style.software_renderer } - readonly property var dimens: HighContrastDimensions { - } + readonly property alias dimens: dimensions property bool highContrast: true - readonly property var text: TextStyles { - } + readonly property string name: "highcontrast" + readonly property alias text: textStyles } QtObject { id: defaultTheme readonly property var color: Colors { + software_renderer: style.software_renderer } - readonly property var dimens: Dimensions { - } + readonly property alias dimens: dimensions readonly property bool highContrast: false - readonly property var text: TextStyles { - } + readonly property string name: "lightmode" + readonly property alias text: textStyles + } + Dimensions { + id: dimensions + + } + TextStyles { + id: textStyles + } } diff --git a/resources/qml/Governikus/Style/TextStyle.qml b/resources/qml/Governikus/Style/TextStyle.qml index e66133689..48f50d930 100644 --- a/resources/qml/Governikus/Style/TextStyle.qml +++ b/resources/qml/Governikus/Style/TextStyle.qml @@ -1,16 +1,10 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 +import QtQuick QtObject { - property bool bold: false - property bool italic: false - property color linkColor: Style.color.accent_text - property color textColor: Style.color.primary_text - - // An empty string means "unspecified" - property string textFamily - property int textSize: Style.dimens.normal_font_size - property bool underline: false + property real lineHeight: Style.dimens.lineHeight + property color textColor: Style.color.text + property real textSize: Style.dimens.text } diff --git a/resources/qml/Governikus/Style/TextStyles.qml b/resources/qml/Governikus/Style/TextStyles.qml index e697fce34..c226a407f 100644 --- a/resources/qml/Governikus/Style/TextStyles.qml +++ b/resources/qml/Governikus/Style/TextStyles.qml @@ -1,166 +1,39 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 +import QtQuick -PlatformTextStyles { +QtObject { readonly property var button: TextStyle { - textColor: Style.color.button_text + lineHeight: Style.dimens.lineHeight_button + textColor: Style.color.control_content } - readonly property var button_disabled: TextStyle { - textColor: Style.color.button_text_disabled + readonly property var headline: TextStyle { + lineHeight: Style.dimens.lineHeight_headline + textColor: Style.color.text_headline + textSize: Style.dimens.text_headline } - readonly property var button_highlight: TextStyle { - bold: true - textColor: Style.color.button_text - } - readonly property var header: TextStyle { - textSize: Style.dimens.header_font_size - } - readonly property var header_accent: TextStyle { - textColor: Style.color.accent_text - textSize: Style.dimens.header_font_size - } - readonly property var header_accent_highlight: TextStyle { - bold: true - textColor: Style.color.accent_text - textSize: Style.dimens.header_font_size - } - readonly property var header_highlight: TextStyle { - bold: true - textSize: Style.dimens.header_font_size - } - readonly property var header_inverse: TextStyle { - linkColor: Style.color.accent_text_inverse - textColor: Style.color.primary_text_inverse - textSize: Style.dimens.header_font_size - } - readonly property var header_inverse_highlight: TextStyle { - bold: true - linkColor: Style.color.accent_text_inverse - textColor: Style.color.primary_text_inverse - textSize: Style.dimens.header_font_size - } - readonly property var header_secondary: TextStyle { - textColor: Style.color.secondary_text - textSize: Style.dimens.header_font_size - } - readonly property var header_secondary_highlight: TextStyle { - bold: true - textColor: Style.color.secondary_text - textSize: Style.dimens.header_font_size - } - readonly property var header_secondary_inverse: TextStyle { - linkColor: Style.color.accent_text_inverse - textColor: Style.color.secondary_text_inverse - textSize: Style.dimens.header_font_size - } - readonly property var header_warning: TextStyle { - textColor: Style.color.warning_text - textSize: Style.dimens.header_font_size - } - readonly property var hint: TextStyle { - textSize: Style.dimens.hint_font_size - } - readonly property var hint_accent: TextStyle { - textColor: Style.color.accent_text - textSize: Style.dimens.hint_font_size - } - readonly property var hint_inverse: TextStyle { - linkColor: Style.color.accent_text_inverse - textColor: Style.color.primary_text_inverse - textSize: Style.dimens.hint_font_size - } - readonly property var hint_secondary: TextStyle { - textColor: Style.color.secondary_text - textSize: Style.dimens.hint_font_size - } - readonly property var hint_secondary_inverse: TextStyle { - linkColor: Style.color.accent_text_inverse - textColor: Style.color.secondary_text_inverse - textSize: Style.dimens.hint_font_size - } - readonly property var hint_warning: TextStyle { - textColor: Style.color.warning_text - textSize: Style.dimens.hint_font_size - } - readonly property var link_accent: TextStyle { - textColor: Style.color.accent_text - underline: true + readonly property var link: TextStyle { + textColor: Style.color.text_subline } readonly property var navigation: TextStyle { - textSize: Style.dimens.navigation_font_size - } - readonly property var navigation_highlight: TextStyle { - bold: true - textSize: Style.dimens.navigation_font_size + lineHeight: Style.dimens.lineHeight_navigation + textColor: Style.color.text_title + textSize: Style.dimens.text_navigation } readonly property var normal: TextStyle { } - readonly property var normal_accent: TextStyle { - textColor: Style.color.accent_text - } - readonly property var normal_accent_highlight: TextStyle { - bold: true - textColor: Style.color.accent_text - } - readonly property var normal_highlight: TextStyle { - bold: true - } - readonly property var normal_info: TextStyle { - textColor: Style.color.info_text - } - readonly property var normal_inverse: TextStyle { - linkColor: Style.color.accent_text_inverse - textColor: Style.color.primary_text_inverse - } - readonly property var normal_secondary: TextStyle { - textColor: Style.color.secondary_text - } - readonly property var normal_secondary_inverse: TextStyle { - linkColor: Style.color.accent_text_inverse - textColor: Style.color.secondary_text_inverse - } readonly property var normal_warning: TextStyle { - textColor: Style.color.warning_text + textColor: Style.color.text_warning } - readonly property var normal_warning_highlight: TextStyle { - bold: true - textColor: Style.color.warning_text + readonly property var subline: TextStyle { + lineHeight: Style.dimens.lineHeight_subline + textColor: Style.color.text_subline + textSize: Style.dimens.text_subline } readonly property var title: TextStyle { - textSize: Style.dimens.title_font_size - } - readonly property var title_accent: TextStyle { - textColor: Style.color.accent_text - textSize: Style.dimens.title_font_size - } - readonly property var title_accent_highlight: TextStyle { - bold: true - textColor: Style.color.accent_text - textSize: Style.dimens.title_font_size - } - readonly property var title_highlight: TextStyle { - bold: true - textSize: Style.dimens.title_font_size - } - readonly property var title_inverse: TextStyle { - linkColor: Style.color.accent_text_inverse - textColor: Style.color.primary_text_inverse - textSize: Style.dimens.title_font_size - } - readonly property var title_inverse_highlight: TextStyle { - bold: true - linkColor: Style.color.accent_text_inverse - textColor: Style.color.primary_text_inverse - textSize: Style.dimens.title_font_size - } - readonly property var title_secondary: TextStyle { - textColor: Style.color.secondary_text - textSize: Style.dimens.title_font_size - } - readonly property var title_warning: TextStyle { - textColor: Style.color.warning_text - textSize: Style.dimens.title_font_size + lineHeight: Style.dimens.lineHeight_title + textColor: Style.color.text_title + textSize: Style.dimens.text_title } } diff --git a/resources/qml/Governikus/Style/qmldir b/resources/qml/Governikus/Style/qmldir index cecc68faa..a47404b33 100644 --- a/resources/qml/Governikus/Style/qmldir +++ b/resources/qml/Governikus/Style/qmldir @@ -1,14 +1,11 @@ module Style -internal BrandColors BrandColors.qml internal BrandDimensions BrandDimensions.qml internal Colors Colors.qml +internal DarkModeColors DarkModeColors.qml internal Dimensions Dimensions.qml internal HighContrastColors HighContrastColors.qml -internal HighContrastDimensions HighContrastDimensions.qml -internal PlatformColors PlatformColors.qml internal PlatformDimensions PlatformDimensions.qml -internal PlatformTextStyles PlatformTextStyles.qml internal TextStyles TextStyles.qml singleton Style 1.0 Style.qml diff --git a/resources/qml/Governikus/TechnologyInfo/+mobile/TechnologyInfo.qml b/resources/qml/Governikus/TechnologyInfo/+mobile/TechnologyInfo.qml index bda44945d..c99eb6f5f 100644 --- a/resources/qml/Governikus/TechnologyInfo/+mobile/TechnologyInfo.qml +++ b/resources/qml/Governikus/TechnologyInfo/+mobile/TechnologyInfo.qml @@ -1,14 +1,14 @@ /** * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.NumberModel 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.Type.ApplicationModel +import Governikus.Type.NumberModel -Item { +ColumnLayout { id: root property alias additionalContent: additionalContentItem.data @@ -19,63 +19,49 @@ Item { signal enableClicked - clip: true + spacing: Constants.component_spacing - GFlickableColumnLayout { - anchors.fill: parent - spacing: 0 - topMargin: 0 + GText { + id: title - GText { - id: title - Layout.alignment: Qt.AlignHCenter - Layout.bottomMargin: Constants.text_spacing - Layout.fillWidth: true - Layout.maximumWidth: Style.dimens.max_text_width - horizontalAlignment: Text.AlignHCenter - textStyle: Style.text.header_accent - visible: text !== "" - } - GText { - id: subTitle - Layout.alignment: Qt.AlignHCenter - Layout.bottomMargin: Constants.component_spacing - Layout.fillWidth: true - Layout.maximumWidth: Style.dimens.max_text_width - horizontalAlignment: Text.AlignHCenter - textStyle: Style.text.normal_secondary - verticalAlignment: Text.AlignTop - visible: text !== "" - } - GText { - id: enableInfo - Layout.alignment: Qt.AlignHCenter - Layout.bottomMargin: Constants.component_spacing - Layout.fillWidth: true - Layout.maximumWidth: Style.dimens.max_text_width - horizontalAlignment: Text.AlignHCenter - textStyle: Style.text.normal_warning - verticalAlignment: Text.AlignBottom - visible: text !== "" - } - Column { - id: additionalContentItem - Layout.alignment: Qt.AlignHCenter - Layout.bottomMargin: Constants.component_spacing - Layout.fillWidth: true - Layout.maximumWidth: Style.dimens.max_text_width - visible: children.length !== 0 - } - GSpacer { - Layout.fillHeight: true - } - GButton { - id: enableButton - Layout.alignment: Qt.AlignHCenter - Layout.bottomMargin: Constants.component_spacing - visible: text !== "" + Layout.alignment: Qt.AlignHCenter + horizontalAlignment: Text.AlignHCenter + textStyle: Style.text.headline + visible: text !== "" + } + GText { + id: subTitle + + Layout.alignment: Qt.AlignHCenter + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignTop + visible: text !== "" + } + GText { + id: enableInfo + + Layout.alignment: Qt.AlignHCenter + horizontalAlignment: Text.AlignHCenter + textStyle: Style.text.normal_warning + verticalAlignment: Text.AlignBottom + visible: text !== "" + } + Column { + id: additionalContentItem + + Layout.fillWidth: true + visible: children.length !== 0 + } + GSpacer { + Layout.fillHeight: true + visible: enableButton.visible + } + GButton { + id: enableButton + + Layout.alignment: Qt.AlignHCenter + visible: text !== "" - onClicked: enableClicked() - } + onClicked: enableClicked() } } diff --git a/resources/qml/Governikus/TechnologyInfo/+mobile/TechnologySwitch.qml b/resources/qml/Governikus/TechnologyInfo/+mobile/TechnologySwitch.qml index 1884c18bd..7c8bccf84 100644 --- a/resources/qml/Governikus/TechnologyInfo/+mobile/TechnologySwitch.qml +++ b/resources/qml/Governikus/TechnologyInfo/+mobile/TechnologySwitch.qml @@ -1,70 +1,98 @@ /** * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.ReaderPlugIn 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.Type.ReaderPlugIn -Item { +GFlickableColumnLayout { id: baseItem + property bool flowVertically: false + readonly property int maxItemHeight: Math.max(nfc.implicitHeight, smart.implicitHeight, remote.implicitHeight, sim.implicitHeight) + readonly property int maxItemWidth: Math.max(nfc.implicitWidth, smart.implicitWidth, remote.implicitWidth, sim.implicitWidth) property int selectedTechnology property var supportedTechnologies signal requestPluginType(int pReaderPlugInType) - height: technologyRow.height + clip: true + implicitHeight: maxItemHeight + 2 * Constants.pane_padding + implicitWidth: maxItemWidth + 2 * Constants.pane_padding + leftMargin: 0 + rightMargin: 0 - Row { - id: technologyRow - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - spacing: Constants.component_spacing * 2 + GSpacer { + Layout.fillHeight: true + visible: flowVertically + } + GridLayout { + id: switcher + + readonly property int columnCount: 1 + (baseItem.width - maxItemWidth) / (maxItemWidth + columnSpacing) + + Layout.alignment: Qt.AlignCenter + columnSpacing: Constants.component_spacing * 2 + columns: flowVertically ? 1 : columnCount + rowSpacing: Constants.component_spacing - TechnologySwitchButton { - buttonActive: selectedTechnology !== ReaderPlugIn.NFC - imageSource: "qrc:///images/mobile/icon_nfc.svg" + GButton { + id: nfc + + checkable: !checked + checked: selectedTechnology === ReaderPlugIn.NFC + icon.source: "qrc:///images/mobile/icon_nfc.svg" //: LABEL ANDROID IOS text: qsTr("NFC") + tintIcon: true visible: supportedTechnologies.includes(ReaderPlugIn.NFC) onClicked: baseItem.requestPluginType(ReaderPlugIn.NFC) } - TechnologySwitchButton { - buttonActive: selectedTechnology !== ReaderPlugIn.SMART - imageSource: "qrc:///images/mobile/icon_smart.svg" + GButton { + id: smart + + checkable: !checked + checked: selectedTechnology === ReaderPlugIn.SMART + icon.source: "qrc:///images/mobile/icon_smart.svg" //: LABEL ANDROID IOS text: qsTr("SMART") + tintIcon: true visible: supportedTechnologies.includes(ReaderPlugIn.SMART) onClicked: baseItem.requestPluginType(ReaderPlugIn.SMART) } - TechnologySwitchButton { - buttonActive: selectedTechnology !== ReaderPlugIn.REMOTE_IFD - imageSource: "qrc:///images/mobile/icon_remote.svg" + GButton { + id: remote + + checkable: !checked + checked: selectedTechnology === ReaderPlugIn.REMOTE_IFD + icon.source: "qrc:///images/mobile/icon_remote.svg" //: LABEL ANDROID IOS text: qsTr("WiFi") + tintIcon: true visible: supportedTechnologies.includes(ReaderPlugIn.REMOTE_IFD) onClicked: baseItem.requestPluginType(ReaderPlugIn.REMOTE_IFD) } - TechnologySwitchButton { - buttonActive: selectedTechnology !== ReaderPlugIn.SIMULATOR - imageSource: "qrc:///images/mobile/icon_simulator.svg" + GButton { + id: sim + + checkable: !checked + checked: selectedTechnology === ReaderPlugIn.SIMULATOR + icon.source: "qrc:///images/mobile/icon_simulator.svg" //: LABEL ANDROID IOS text: qsTr("SIM") + tintIcon: true visible: supportedTechnologies.includes(ReaderPlugIn.SIMULATOR) onClicked: baseItem.requestPluginType(ReaderPlugIn.SIMULATOR) } } - GSeparator { - width: technologyRow.width * 1.5 - - anchors { - horizontalCenter: technologyRow.horizontalCenter - top: technologyRow.top - } + GSpacer { + Layout.fillHeight: true + visible: flowVertically } } diff --git a/resources/qml/Governikus/TechnologyInfo/+mobile/TechnologySwitchButton.qml b/resources/qml/Governikus/TechnologyInfo/+mobile/TechnologySwitchButton.qml deleted file mode 100644 index 03bf6508e..000000000 --- a/resources/qml/Governikus/TechnologyInfo/+mobile/TechnologySwitchButton.qml +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 - -MouseArea { - id: root - - property bool buttonActive - property alias imageSource: img.source - property alias text: infoText.text - - Accessible.name: text - Accessible.role: Accessible.Button - height: img.height + infoText.height + img.anchors.topMargin + infoText.anchors.topMargin + infoText.anchors.bottomMargin - width: Math.max(img.width, infoText.width) - - Accessible.onPressAction: clicked(null) - - TintableIcon { - id: img - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - anchors.topMargin: Constants.component_spacing - desaturate: true - sourceSize.height: Style.dimens.icon_size - tintEnabled: !parent.enabled || buttonActive - } - GText { - id: infoText - Accessible.ignored: true - anchors.bottomMargin: anchors.topMargin - anchors.horizontalCenter: img.horizontalCenter - anchors.top: img.bottom - anchors.topMargin: Constants.text_spacing - textStyle: (!parent.enabled || buttonActive) ? Style.text.normal_secondary : Style.text.normal_accent - } -} diff --git a/resources/qml/Governikus/TechnologyInfo/qmldir b/resources/qml/Governikus/TechnologyInfo/qmldir index 10c61449f..87243218e 100644 --- a/resources/qml/Governikus/TechnologyInfo/qmldir +++ b/resources/qml/Governikus/TechnologyInfo/qmldir @@ -2,4 +2,3 @@ module TechnologyInfo TechnologyInfo 1.0 TechnologyInfo.qml TechnologySwitch 1.0 TechnologySwitch.qml -TechnologySwitchButton 1.0 TechnologySwitchButton.qml diff --git a/resources/qml/Governikus/TitleBar/+desktop/CancelAction.qml b/resources/qml/Governikus/TitleBar/+desktop/CancelAction.qml deleted file mode 100644 index 85b741f69..000000000 --- a/resources/qml/Governikus/TitleBar/+desktop/CancelAction.qml +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 - -GButton { - id: root - - readonly property color pressColor: Qt.darker(textStyle.textColor, Constants.highlightDarkerFactor) - - buttonColor: Style.color.transparent - height: if (parent) - parent.height - icon.source: "qrc:///images/material_close.svg" - text: qsTr("Cancel") - textHighlightColor: pressed ? pressColor : textStyle.textColor - textStyle: Style.text.header_inverse_highlight - tintIcon: true - verticalPadding: 0 - visible: ApplicationModel.currentWorkflow !== ApplicationModel.WORKFLOW_NONE - - GSeparator { - color: root.textStyle.textColor - height: parent.height - orientation: Qt.Vertical - visible: !Style.currentTheme.highContrast - } -} diff --git a/resources/qml/Governikus/TitleBar/+desktop/NavigationAction.qml b/resources/qml/Governikus/TitleBar/+desktop/NavigationAction.qml new file mode 100644 index 000000000..f4c3e674e --- /dev/null +++ b/resources/qml/Governikus/TitleBar/+desktop/NavigationAction.qml @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick +import QtQuick.Controls +import Governikus.Global +import Governikus.Style +import Governikus.View +import Governikus.Type.ApplicationModel + +GButton { + id: root + + enum Action { + Cancel, + Back + } + + readonly property color pressColor: Qt.darker(Style.color.text_title, Constants.highlightDarkerFactor) + property int type: NavigationAction.Action.Cancel + + background: null + height: if (parent) + parent.height + icon.source: root.type === NavigationAction.Action.Cancel ? "qrc:///images/material_close.svg" : "qrc:///images/material_arrow_back.svg" + iconSize: Style.dimens.icon_size + text: root.type === NavigationAction.Action.Cancel ? qsTr("Cancel") : qsTr("Back") + textDisabledColor: Style.color.text_subline_disabled + textStyle: Style.text.normal + tintIcon: true + verticalPadding: 0 + visible: ApplicationModel.currentWorkflow !== ApplicationModel.WORKFLOW_NONE +} diff --git a/resources/qml/Governikus/TitleBar/+desktop/Notifications.qml b/resources/qml/Governikus/TitleBar/+desktop/Notifications.qml index 82d8e195e..ac916e502 100644 --- a/resources/qml/Governikus/TitleBar/+desktop/Notifications.qml +++ b/resources/qml/Governikus/TitleBar/+desktop/Notifications.qml @@ -1,14 +1,13 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.NotificationModel 1.0 -import Governikus.Type.SettingsModel 1.0 -import Governikus.View 1.0 +import QtQuick +import QtQuick.Controls +import Governikus.Global +import Governikus.Style +import Governikus.Type.NotificationModel +import Governikus.Type.SettingsModel +import Governikus.View Item { id: baseItem @@ -17,11 +16,11 @@ Item { if (d.unreadMsg) { if (NotificationModel.lastType === "developermode") return Constants.red; - if (NotificationModel.lastType === "feedback") - return Constants.green; + return Style.color.text_subline; } - return Style.text.header_inverse.textColor; + return Style.color.text; } + readonly property bool unreadMessages: d.unreadMsg signal newNotification @@ -45,26 +44,28 @@ Item { } Timer { id: fadeOutTimer + interval: 1800 // The notification button blinks 3 times for 600ms onTriggered: d.fadeIn = false } Rectangle { id: logList - anchors.bottom: parent.bottom - anchors.bottomMargin: d.fadeIn ? radius - height : 0 - anchors.right: parent.right - anchors.rightMargin: -radius - border.color: Constants.blue - border.width: Math.max(1, ApplicationModel.scaleFactor * 3) - color: Style.color.background - height: ApplicationModel.scaleFactor * 200 - radius: logEntryList.spacing - width: ApplicationModel.scaleFactor * 800 - - Behavior on anchors.bottomMargin { + + anchors.left: parent.left + anchors.leftMargin: d.fadeIn ? -(width + Constants.pane_spacing) : 0 + anchors.top: parent.top + border.color: Style.color.control_border + border.width: Style.dimens.border_width + color: Style.color.control + height: plugin.scaleFactor * 200 + radius: Style.dimens.control_radius + width: plugin.scaleFactor * 800 + + Behavior on anchors.leftMargin { PropertyAnimation { id: fadingAnimation + duration: Constants.animation_duration easing.type: Easing.InOutQuad } @@ -75,18 +76,17 @@ Item { } GListView { id: logEntryList - anchors.bottomMargin: logList.border.width + anchors.fill: parent - anchors.rightMargin: spacing - anchors.topMargin: logList.radius - bottomMargin: spacing + anchors.leftMargin: Constants.pane_padding + bottomMargin: Constants.pane_padding clip: true - leftMargin: spacing model: NotificationModel scrollBarBottomPadding: spacing + scrollBarColor: Style.color.control_content scrollBarTopPadding: spacing spacing: Constants.text_spacing - topMargin: spacing + topMargin: Constants.pane_padding delegate: Item { Accessible.name: notificationTime.text + " " + notificationBody.text @@ -96,6 +96,7 @@ Item { Row { id: row + spacing: logEntryList.spacing Component.onCompleted: { @@ -114,12 +115,15 @@ Item { GText { id: notificationTime + text: model.time + textStyle: Style.text.button } GText { id: notificationBody + text: model.text - textStyle: model.type === "developermode" ? Style.text.normal_warning : Style.text.normal + textStyle: model.type === "developermode" ? Style.text.normal_warning : Style.text.button width: logEntryList.width - notificationTime.width - 3 * logEntryList.spacing } } @@ -129,6 +133,7 @@ Item { Timer { id: positionViewAtEndTimer + interval: 1 onTriggered: logEntryList.positionViewAtEnd() diff --git a/resources/qml/Governikus/TitleBar/+desktop/TitleBar.qml b/resources/qml/Governikus/TitleBar/+desktop/TitleBar.qml index bd5e40354..80c392aaf 100644 --- a/resources/qml/Governikus/TitleBar/+desktop/TitleBar.qml +++ b/resources/qml/Governikus/TitleBar/+desktop/TitleBar.qml @@ -1,202 +1,165 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.SettingsModel 1.0 - -Item { +import QtQuick +import Governikus.Global +import Governikus.Style +import Governikus.View +import Governikus.Type.ApplicationModel +import Governikus.Type.SettingsModel + +Rectangle { id: titleBar property var contentRoot - property var rightMostAction: actionRow.lastAction + readonly property alias title: title.text signal rootClicked - function addRecursive(root) { - for (var i in root.children) { - var child = root.children[i]; - if (child.sectionPageTypeMarker && child.visible) { - if (child.titleBarAction) { - actionRow.children.push(child.titleBarAction); - } - addRecursive(child); - } - } - } - function buildAccessibleName(visibleActionsCount) { - //: LABEL DESKTOP - var accessible_name = qsTr("Navigation bar") + ", "; - //: LABEL DESKTOP - accessible_name += qsTr("List") + ", "; - if (actionRow.children.length > 1) { - //: LABEL DESKTOP - accessible_name += qsTr("%1 elements").arg(visibleActionsCount); - } else { - //: LABEL DESKTOP - accessible_name += qsTr("1 element"); - } - return accessible_name; - } - function getVisibleTitleBarActionCount() { - var count = 0; - for (var i = 0; i < actionRow.children.length; i++) { - if (actionRow.children[i].visible) { - count += 1; - } - } - return count; - } function setActiveFocus() { forceActiveFocus(Qt.MouseFocusReason); } function updateActions() { - actionRow.children = [rootAction]; - addRecursive(contentRoot); - let visibleActionsCount = getVisibleTitleBarActionCount(); - Accessible.name = buildAccessibleName(visibleActionsCount); - updateListIndexAndLength(visibleActionsCount); - } - function updateListIndexAndLength(visibleActionsCount) { - var idx = 1; - for (var i = 0; i < actionRow.children.length; i++) { - if (actionRow.children[i].visible) { - actionRow.children[i].list_index = idx; - actionRow.children[i].list_length = visibleActionsCount; - idx += 1; - } - } + d.actions = [rootAction]; + d.addRecursive(contentRoot); } + //: LABEL DESKTOP + Accessible.name: qsTr("Title bar") Accessible.role: Accessible.Grouping activeFocusOnTab: true - height: actionRow.height + 2 * Style.dimens.titlebar_padding - - Rectangle { - anchors.fill: parent - color: Style.color.navigation - - GSeparator { - color: Style.color.high_contrast_item_border - height: Style.dimens.high_contrast_item_border - - anchors { - bottom: parent.bottom - left: parent.left - right: parent.right + color: Style.color.background + height: titleBarColumn.height + + QtObject { + id: d + + property list actions + readonly property TitleBarAction currentAction: actions && actions.length > 0 ? actions[actions.length - 1] : rootAction + readonly property TitleBarAction prevAction: actions && actions.length > 1 ? actions[actions.length - 2] : rootAction + + function addRecursive(root) { + for (let i in root.children) { + let child = root.children[i]; + if (child.breadcrumpSearchPath && child.visible) { + if (child instanceof SectionPage && child.titleBarAction) { + actions.push(child.titleBarAction); + } + addRecursive(child); + } } } - FocusPoint { - isOnLightBackground: false - scope: titleBar - } + } + FocusPoint { + } + Column { + id: titleBarColumn + + width: parent.width + Item { - anchors.left: parent.left - anchors.right: rightTitleBarActions.left - anchors.rightMargin: Style.dimens.titlebar_padding - clip: true - height: parent.height + id: firstRow - Row { - id: actionRow + height: rootAction.height + 2 * Style.dimens.titlebar_padding + width: parent.width - readonly property bool childrenFitSpace: childrenRect.width <= width - readonly property Item lastAction: children && children.length > 0 ? children[children.length - 1] : rootAction + TitleBarAction { + id: rootAction + activeFocusOnTab: true anchors.left: parent.left - anchors.leftMargin: Style.dimens.titlebar_padding - anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter - height: rootAction.height + enabled: d.currentAction.rootEnabled + icon.source: "qrc:///images/desktop/home.svg" + //: LABEL DESKTOP + text: qsTr("Start page") + + onClicked: titleBar.rootClicked() + } + Row { + id: rightTitleBarActions + + anchors.bottom: parent.bottom + anchors.margins: Style.dimens.titlebar_padding + anchors.right: parent.right + anchors.top: parent.top spacing: Style.dimens.titlebar_padding - TitleBarAction { - id: rootAction - active: rightMostAction.rootEnabled - activeFocusOnTab: true - helpTopic: "applicationOverview" - showArrow: false - //: LABEL DESKTOP - text: qsTr("Start page") + TitleBarButton { + Accessible.description: qsTr("Open settings view of %1").arg(Qt.application.name) + height: rightTitleBarActions.height + source: "qrc:///images/desktop/material_settings_white.svg" + text: qsTr("Settings") + visible: d.currentAction.showSettings - onClicked: titleBar.rootClicked() + onClicked: d.currentAction.settingsHandler() } - } - } - Rectangle { - anchors.right: rightTitleBarActions.left - anchors.rightMargin: Style.dimens.titlebar_padding - height: parent.height - visible: !actionRow.childrenFitSpace - width: Constants.pane_padding - - gradient: Gradient { - orientation: Gradient.Horizontal - - GradientStop { - color: Style.color.transparent - position: 0.0 - } - GradientStop { - color: Style.color.navigation - position: 1.0 + TitleBarButton { + id: notifyButton + + Accessible.description: qsTr("Show in-app notifications of %1").arg(Qt.application.name) + height: rightTitleBarActions.height + iconColor: notifications.iconColor + source: notifications.unreadMessages ? "qrc:///images/desktop/notifications_on.svg" : "qrc:///images/desktop/notifications_off.svg" + text: qsTr("Notifications") + visible: SettingsModel.showInAppNotifications + + onClicked: notifications.toggle() } } } + TitlePane { + id: titlePane + + visible: d.actions.length > 1 + width: parent.width + } Row { - id: rightTitleBarActions - anchors.bottom: parent.bottom - anchors.margins: Style.dimens.titlebar_padding - anchors.right: parent.right - anchors.top: parent.top - spacing: Style.dimens.titlebar_padding + height: title.height + leftPadding: Constants.pane_padding + visible: titlePane.visible + width: parent.width Item { - data: rightMostAction.customSubAction + data: d.currentAction.customSubAction height: parent.height - width: childrenRect.width - } - TitleBarButton { - id: settingsButton - Accessible.description: qsTr("Open settings view of %1").arg(Qt.application.name) - height: rightTitleBarActions.height - source: "qrc:///images/desktop/material_settings_white.svg" - text: qsTr("Settings") - visible: rightMostAction.showSettings - - onClicked: rightMostAction.settingsHandler() + width: d.currentAction.customSubAction.visible ? Math.max(childrenRect.width, backAction.width) : 0 } - TitleBarButton { - id: helpButton - Accessible.description: qsTr("Open online help of %1 in browser").arg(Qt.application.name) - height: rightTitleBarActions.height - source: "qrc:///images/desktop/material_menu_book_white.svg" - text: qsTr("Open online help in browser") - visible: rightMostAction.showHelp - - onClicked: ApplicationModel.openOnlineHelp(rightMostAction.helpTopic) + NavigationAction { + id: backAction + + height: parent.height + type: NavigationAction.Action.Back + visible: !d.currentAction.customSubAction.visible + width: 1.5 * implicitWidth + + onClicked: d.prevAction.clicked() } - TitleBarButton { - id: notifyButton - Accessible.description: qsTr("Show in-app notifications of %1").arg(Qt.application.name) - height: rightTitleBarActions.height - iconColor: notifications.iconColor - source: "qrc:///images/desktop/material_notifications.svg" - text: qsTr("Notifications") - visible: SettingsModel.showInAppNotifications - - onClicked: notifications.toggle() + GText { + id: title + + font.bold: true + text: d.currentAction.text + textStyle: Style.text.title } } } + GSeparator { + color: Style.color.pane_border + height: Style.dimens.border_width + + anchors { + bottom: parent.bottom + left: parent.left + right: parent.right + } + } Notifications { id: notifications - anchors.right: parent.right - anchors.top: parent.bottom - z: -1 // Draw below the title bar, but place Notifications after the notifyButton, so that the tab order makes sense + + anchors.left: parent.right + anchors.top: parent.top + anchors.topMargin: firstRow.height onNewNotification: notifyButton.notify() } diff --git a/resources/qml/Governikus/TitleBar/+desktop/TitleBarAction.qml b/resources/qml/Governikus/TitleBar/+desktop/TitleBarAction.qml index b8e3c3029..a101be84a 100644 --- a/resources/qml/Governikus/TitleBar/+desktop/TitleBarAction.qml +++ b/resources/qml/Governikus/TitleBar/+desktop/TitleBarAction.qml @@ -1,92 +1,24 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.View 1.0 +import QtQuick +import Governikus.Global +import Governikus.Style +import Governikus.View -FocusScope { - id: scope - - property bool active: true +GButton { property var customSettingsHandler property Item customSubAction: Item { visible: false } - property string helpTopic: "applicationPage" - readonly property bool isClickable: active && !isLastElement - readonly property bool isLastElement: list_index === list_length - property int list_index: 1 - property int list_length: 1 property bool rootEnabled: true readonly property var settingsHandler: customSettingsHandler ? customSettingsHandler : function () {} - property alias showArrow: arrow.visible property bool showHelp: true property bool showSettings: false - property alias text: text.text - - signal clicked - - Accessible.name: !scope.active ? - //: LABEL DESKTOP - qsTr("Navigating to %1 in current context disabled").arg(text.text) + ", " + - //: LABEL DESKTOP - qsTr("element %1 of %2").arg(list_index).arg(list_length) : isLastElement ? - //: LABEL DESKTOP - qsTr("Current context: %1").arg(text.text) + ", " + - //: LABEL DESKTOP - qsTr("element %1 of %2").arg(list_index).arg(list_length) : - //: LABEL DESKTOP - qsTr("Navigate to %1").arg(text.text) + ", " + - //: LABEL DESKTOP - qsTr("element %1 of %2").arg(list_index).arg(list_length) - Accessible.role: Accessible.Button - activeFocusOnTab: true - height: row.height - width: row.width - - Keys.onSpacePressed: if (isClickable) - scope.clicked() - - Row { - id: row - height: text.height - spacing: Style.dimens.titlebar_padding - TintableIcon { - id: arrow - anchors.bottom: text.baseline - anchors.bottomMargin: 1 * ApplicationModel.scaleFactor - source: "qrc:///images/desktop/titlebar_arrow.svg" - sourceSize.width: Style.dimens.icon_size - tintColor: Style.text.header_inverse.textColor - } - GText { - id: text - - readonly property color pressColor: Qt.darker(textColor, Constants.highlightDarkerFactor) - readonly property color textColor: scope.active ? Style.text.header_inverse.textColor : Style.text.header_secondary_inverse.textColor - - Accessible.name: text.text - Accessible.role: Accessible.Button - color: mouseArea.containsPress ? pressColor : textColor - textStyle: isLastElement ? Style.text.navigation_highlight : Style.text.navigation - - FocusFrame { - isOnLightBackground: false - scope: scope - } - MouseArea { - id: mouseArea - anchors.fill: parent - cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor - enabled: scope.isClickable - - onClicked: scope.clicked() - onPressed: scope.focus = true - } - } - } + background: null + textDisabledColor: Style.color.text_subline_disabled + textStyle: Style.text.navigation + tintIcon: true + verticalPadding: 0 } diff --git a/resources/qml/Governikus/TitleBar/+desktop/TitleBarButton.qml b/resources/qml/Governikus/TitleBar/+desktop/TitleBarButton.qml index 20a0f5f0b..3c76ee213 100644 --- a/resources/qml/Governikus/TitleBar/+desktop/TitleBarButton.qml +++ b/resources/qml/Governikus/TitleBar/+desktop/TitleBarButton.qml @@ -1,17 +1,17 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.View 1.0 -import Governikus.Style 1.0 -import Governikus.Type.NotificationModel 1.0 +import QtQuick +import QtQuick.Controls +import Governikus.Global +import Governikus.View +import Governikus.Style +import Governikus.Type.NotificationModel Button { id: button - property color iconColor: Style.text.header_inverse.textColor + property color iconColor: Style.text.headline.textColor property alias source: image.source function notify() { @@ -41,6 +41,7 @@ Button { } Rectangle { id: blinker + anchors.fill: parent anchors.margins: image.height / -4 color: NotificationModel.lastType === "developermode" ? Constants.red : Constants.green @@ -49,6 +50,7 @@ Button { SequentialAnimation { id: blinkerAnimation + loops: 3 PropertyAnimation { @@ -70,10 +72,10 @@ Button { } FocusFrame { - isOnLightBackground: false } MouseArea { id: mouseArea + anchors.fill: parent cursorShape: Qt.PointingHandCursor hoverEnabled: true diff --git a/resources/qml/Governikus/TitleBar/+desktop/TitlePane.qml b/resources/qml/Governikus/TitleBar/+desktop/TitlePane.qml new file mode 100644 index 000000000..cc4b5dd81 --- /dev/null +++ b/resources/qml/Governikus/TitleBar/+desktop/TitlePane.qml @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick +import Governikus.Global +import Governikus.Style + +Item { + id: root + + implicitHeight: topRectangle.height + bottomRectangle.height + + RoundedRectangle { + id: topRectangle + + bottomLeftCorner: false + bottomRightCorner: false + color: Style.color.pane_title + height: bottomRectangle.height / 2 + radius: Style.dimens.titlepane_radius + width: bottomRectangle.width - 2 * Style.dimens.titlepane_radius + + anchors { + bottom: bottomRectangle.top + horizontalCenter: root.horizontalCenter + } + } + RoundedRectangle { + id: bottomRectangle + + anchors.bottom: root.bottom + borderColor: Style.color.pane_border + bottomLeftCorner: false + bottomRightCorner: false + color: Style.color.background + height: Style.dimens.titlepane_radius + radius: Style.dimens.titlepane_radius + width: root.width + + layer { + enabled: GraphicsInfo.api !== GraphicsInfo.Software + + effect: GDropShadow { + autoPaddingEnabled: false + paddingRect: Qt.rect(0, root.height, 0, 0) + verticalOffset: -3 + } + } + } +} diff --git a/resources/qml/Governikus/TitleBar/+mobile/NavigationAction.qml b/resources/qml/Governikus/TitleBar/+mobile/NavigationAction.qml index 87a7ad560..640745ca8 100644 --- a/resources/qml/Governikus/TitleBar/+mobile/NavigationAction.qml +++ b/resources/qml/Governikus/TitleBar/+mobile/NavigationAction.qml @@ -1,7 +1,7 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 +import QtQuick Item { enum Action { diff --git a/resources/qml/Governikus/TitleBar/+mobile/TitleBar.qml b/resources/qml/Governikus/TitleBar/+mobile/TitleBar.qml index daae8b927..5d48d6aed 100644 --- a/resources/qml/Governikus/TitleBar/+mobile/TitleBar.qml +++ b/resources/qml/Governikus/TitleBar/+mobile/TitleBar.qml @@ -1,19 +1,19 @@ /** * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import Governikus.Global +import Governikus.Style Item { id: titleBar - property var color - property alias contentHeight: contentLayout.height - property bool enableTitleMoveAnimation: Constants.is_layout_ios property NavigationAction navigationAction property var rightAction + property bool showSeparator: false + property bool smartEidUsed: false property alias title: titleText.text property alias titleBarOpacity: background.opacity property var topSafeAreaMargin: plugin.safeAreaMargins.top @@ -22,14 +22,15 @@ Item { titleText.forceActiveFocus(Qt.MouseFocusReason); } - height: contentLayout.height + topSafeAreaMargin + height: contentLayout.implicitHeight + topSafeAreaMargin + Style.dimens.titlebar_padding Rectangle { id: safeAreaBackground - color: titleBar.color ? titleBar.color : Style.color.accent + + color: smartEidUsed ? Style.color.card_smart : Style.color.card_eid height: topSafeAreaMargin - Behavior on color { + Behavior on color { ColorAnimation { duration: Constants.animation_duration } @@ -43,9 +44,10 @@ Item { } Rectangle { id: background - color: titleBar.color ? titleBar.color : Style.color.accent - Behavior on color { + color: Style.color.background + + Behavior on color { ColorAnimation { duration: Constants.animation_duration } @@ -58,57 +60,40 @@ Item { top: safeAreaBackground.bottom } } - Column { + ColumnLayout { id: contentLayout + + spacing: Constants.text_spacing + width: Math.min(parent.width - 2 * Style.dimens.titlebar_padding - plugin.safeAreaMargins.left - plugin.safeAreaMargins.right, Style.dimens.max_text_width) + anchors { bottom: parent.bottom - left: parent.left - leftMargin: plugin.safeAreaMargins.left - right: parent.right - rightMargin: plugin.safeAreaMargins.right + horizontalCenter: parent.horizontalCenter + horizontalCenterOffset: (plugin.safeAreaMargins.left - plugin.safeAreaMargins.right) / 2 } - Item { - id: firstLine - height: Style.dimens.titlebar_height - width: parent.width - - TitleBarNavigation { - id: leftAction - action: titleBar.navigationAction ? titleBar.navigationAction.action : NavigationAction.Action.None - enabled: titleBar.navigationAction ? titleBar.navigationAction.enabled : false - width: titleText.moreSpacePreferred ? minimumWidth : implicitWidth - - onClicked: titleBar.navigationAction.clicked() - - anchors { - bottom: parent.bottom - left: parent.left - top: parent.top - } - } + TitleBarNavigation { + id: leftAction + + Layout.minimumHeight: Style.dimens.small_icon_size + action: titleBar.navigationAction ? titleBar.navigationAction.action : NavigationAction.Action.None + enabled: titleBar.navigationAction ? titleBar.navigationAction.enabled : false + + onClicked: titleBar.navigationAction.clicked() + } + RowLayout { + spacing: Constants.component_spacing + GText { id: titleText - readonly property int availableWidth: parent.width - leftAction.width - rightActionStack.width - readonly property int centerX: (parent.width / 2) - (width / 2) - readonly property int implicitAvailableWidth: parent.width - leftAction.implicitWidth - rightActionStack.implicitWidth - readonly property int leftX: leftAction.width - readonly property bool moreSpacePreferred: implicitWidth > implicitAvailableWidth - Accessible.focusable: true Accessible.role: Accessible.Heading + Layout.maximumWidth: Style.dimens.max_text_width elide: Text.ElideRight - height: Style.dimens.titlebar_height - leftPadding: Style.dimens.titlebar_padding - maximumLineCount: 1 - rightPadding: Style.dimens.titlebar_padding - textStyle: Style.text.header_inverse_highlight - verticalAlignment: Text.AlignVCenter - width: Math.min(implicitWidth, availableWidth) - wrapMode: Text.NoWrap - x: Math.max(leftX, centerX) - - Behavior on text { + maximumLineCount: 2 + textStyle: Style.text.title + + Behavior on text { SequentialAnimation { PropertyAnimation { duration: Constants.animation_duration @@ -130,20 +115,9 @@ Item { } } } - Behavior on x { - enabled: enableTitleMoveAnimation - - NumberAnimation { - duration: Constants.animation_duration - easing.type: Easing.OutQuart - from: parent.width * 0.75 - } - } - - anchors { - bottom: parent.bottom - top: parent.top - } + } + GSpacer { + Layout.fillWidth: true } Item { id: rightActionStack @@ -151,21 +125,18 @@ Item { property var actionItem: rightAction property var activeActionItem + Layout.alignment: Qt.AlignRight children: activeActionItem ? [activeActionItem] : [] + implicitHeight: activeActionItem ? activeActionItem.implicitHeight : 0 implicitWidth: activeActionItem ? activeActionItem.implicitWidth : 0 - width: activeActionItem ? activeActionItem.width : 0 + width: activeActionItem ? activeActionItem.implicitWidth : 0 onActionItemChanged: rightActionStackAnimateOut.start() onActiveActionItemChanged: rightActionStackAnimateIn.start() - anchors { - bottom: parent.bottom - right: parent.right - rightMargin: Style.dimens.titlebar_padding - top: parent.top - } PropertyAnimation { id: rightActionStackAnimateOut + duration: Constants.animation_duration easing.type: Easing.InCubic property: "opacity" @@ -176,6 +147,7 @@ Item { } PropertyAnimation { id: rightActionStackAnimateIn + duration: Constants.animation_duration easing.type: Easing.OutCubic property: "opacity" @@ -185,4 +157,13 @@ Item { } } } + GSeparator { + visible: titleBar.showSeparator + width: contentLayout.width + + anchors { + horizontalCenter: contentLayout.horizontalCenter + top: parent.bottom + } + } } diff --git a/resources/qml/Governikus/TitleBar/+mobile/TitleBarAction.qml b/resources/qml/Governikus/TitleBar/+mobile/TitleBarAction.qml index 85105857b..fd27ac70f 100644 --- a/resources/qml/Governikus/TitleBar/+mobile/TitleBarAction.qml +++ b/resources/qml/Governikus/TitleBar/+mobile/TitleBarAction.qml @@ -1,100 +1,90 @@ /** * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style Item { id: baseItem property alias icon: imageItem.source - readonly property real minimumWidth: d.isEmpty ? 0 : Math.max(implicitHeight, d.textWidth) + property alias iconTintColor: imageItem.tintColor property alias text: textItem.text signal clicked Accessible.focusable: true - Accessible.ignored: d.isEmpty + Accessible.ignored: imageItem.source == "" && textItem.text === "" Accessible.name: text Accessible.role: Accessible.Button - height: implicitHeight - implicitHeight: Style.dimens.titlebar_height - implicitWidth: d.isEmpty ? 0 : Math.max(implicitHeight, d.imageWidth + d.textWidth) - width: implicitWidth + implicitHeight: contentLayout.implicitHeight + implicitWidth: contentLayout.implicitWidth Accessible.onPressAction: clicked() - QtObject { - id: d + RowLayout { + id: contentLayout - readonly property int imageWidth: imageItem.visible ? imageItem.x + imageItem.width : 0 - readonly property bool isEmpty: imageItem.source == "" && textItem.text === "" - readonly property int textWidth: textItem.anchors.leftMargin + textItem.implicitWidth - } - TintableIcon { - id: imageItem - height: width - playAnimation: true - sourceSize.width: width - tintColor: Style.color.primary_text_inverse - visible: imageItem.source != "" - width: Style.dimens.small_icon_size - - anchors { - horizontalCenter: baseItem.left - horizontalCenterOffset: baseItem.implicitHeight / 2 - verticalCenter: parent.verticalCenter + anchors.fill: parent + spacing: 0 + + TintableIcon { + id: imageItem + + Layout.preferredHeight: Layout.preferredWidth + implicitWidth: Style.dimens.small_icon_size + playAnimation: true + sourceSize.width: width + tintColor: textItem.color + visible: imageItem.source != "" } - } - GText { - id: textItem - Accessible.ignored: true - elide: Text.ElideRight - maximumLineCount: 1 - textStyle: Style.text.normal_inverse - verticalAlignment: Text.AlignVCenter - visible: !imageItem.visible || baseItem.width >= baseItem.implicitWidth - wrapMode: Text.NoWrap - - Behavior on text { - SequentialAnimation { - PropertyAnimation { - duration: Constants.animation_duration - easing.type: Easing.InCubic - property: "opacity" - target: textItem - to: 0 - } - PropertyAction { - property: "text" - target: textItem - } - PropertyAnimation { - duration: Constants.animation_duration - easing.type: Easing.OutCubic - property: "opacity" - target: textItem - to: 1 + GText { + id: textItem + + Accessible.ignored: true + color: Style.color.text + elide: Text.ElideRight + maximumLineCount: 1 + textStyle: Style.text.navigation + visible: textItem.text !== "" + wrapMode: Text.NoWrap + + Behavior on text { + SequentialAnimation { + PropertyAnimation { + duration: Constants.animation_duration + easing.type: Easing.InCubic + property: "opacity" + target: textItem + to: 0 + } + PropertyAction { + property: "text" + target: textItem + } + PropertyAnimation { + duration: Constants.animation_duration + easing.type: Easing.OutCubic + property: "opacity" + target: textItem + to: 1 + } } } - } - onVisibleChanged: { - if (visible) { - fadeIn.start(); - } else { - fadeOut.start(); + onVisibleChanged: { + if (visible) { + fadeIn.start(); + } else { + fadeOut.start(); + } } } - - anchors { - left: imageItem.visible ? imageItem.right : parent.left - leftMargin: imageItem.visible || text === "" ? 0 : Style.dimens.titlebar_padding - verticalCenter: parent.verticalCenter - } PropertyAnimation { id: fadeOut + duration: Constants.animation_duration easing.type: Easing.InCubic property: "opacity" @@ -103,6 +93,7 @@ Item { } PropertyAnimation { id: fadeIn + duration: Constants.animation_duration easing.type: Easing.OutCubic property: "opacity" @@ -112,6 +103,7 @@ Item { } MouseArea { id: mouseArea + anchors.fill: parent onClicked: baseItem.clicked() diff --git a/resources/qml/Governikus/TitleBar/+mobile/TitleBarButton.qml b/resources/qml/Governikus/TitleBar/+mobile/TitleBarButton.qml deleted file mode 100644 index 8defc4afb..000000000 --- a/resources/qml/Governikus/TitleBar/+mobile/TitleBarButton.qml +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 - -TintableIcon { - id: root - signal clicked - - Accessible.role: Accessible.Button - anchors.verticalCenter: parent ? parent.verticalCenter : undefined - height: Style.dimens.small_icon_size - sourceSize.height: height - tintColor: Style.color.button_text - width: height - - Accessible.onPressAction: mouseArea.clicked(null) - - MouseArea { - id: mouseArea - anchors.fill: parent - anchors.margins: -8 - - onClicked: root.clicked() - } -} diff --git a/resources/qml/Governikus/TitleBar/+mobile/TitleBarNavigation.qml b/resources/qml/Governikus/TitleBar/+mobile/TitleBarNavigation.qml index 38abb3581..13b2a6c81 100644 --- a/resources/qml/Governikus/TitleBar/+mobile/TitleBarNavigation.qml +++ b/resources/qml/Governikus/TitleBar/+mobile/TitleBarNavigation.qml @@ -1,45 +1,36 @@ /** * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import Governikus.Global +import Governikus.Style TitleBarAction { id: baseItem - property int action - readonly property string rawText: { - switch (baseItem.action) { - //: LABEL ANDROID IOS - case NavigationAction.Action.Cancel: - return qsTr("Cancel"); - //: LABEL ANDROID IOS - case NavigationAction.Action.Back: - return qsTr("Back"); - default: - return ""; - } - } + property int action: navigationAction.Action.None - Accessible.name: rawText + Accessible.name: text icon: { - if (Constants.is_layout_ios) { - return baseItem.action === NavigationAction.Action.Back ? "qrc:///images/ios/material_arrow_left.svg" : ""; - } switch (baseItem.action) { case NavigationAction.Action.Cancel: return "qrc:///images/material_close.svg"; case NavigationAction.Action.Back: - return "qrc:///images/mobile/material_arrow_back.svg"; + return "qrc:///images/mobile/material_arrow_left.svg"; default: return ""; } } text: { - if (Constants.is_layout_android) { + switch (baseItem.action) { + //: LABEL ANDROID IOS + case NavigationAction.Action.Cancel: + return qsTr("Cancel"); + //: LABEL ANDROID IOS + case NavigationAction.Action.Back: + return qsTr("Back"); + default: return ""; } - return rawText; } } diff --git a/resources/qml/Governikus/TitleBar/qmldir b/resources/qml/Governikus/TitleBar/qmldir index e56c10eb8..1943f9ae3 100644 --- a/resources/qml/Governikus/TitleBar/qmldir +++ b/resources/qml/Governikus/TitleBar/qmldir @@ -2,8 +2,8 @@ module TitleBar internal BackCloseAction BackCloseAction.qml internal TitleBarNavigation TitleBarNavigation.qml +internal TitlePane TitlePane.qml -CancelAction 1.0 CancelAction.qml NavigationAction 1.0 NavigationAction.qml Notifications 1.0 Notifications.qml TitleBar 1.0 TitleBar.qml diff --git a/resources/qml/Governikus/TutorialView/+desktop/SetupAssistantView.qml b/resources/qml/Governikus/TutorialView/+desktop/SetupAssistantView.qml deleted file mode 100644 index 0311ba165..000000000 --- a/resources/qml/Governikus/TutorialView/+desktop/SetupAssistantView.qml +++ /dev/null @@ -1,194 +0,0 @@ -/** - * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.ResultView 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 -import Governikus.SettingsView 1.0 -import Governikus.Type.SettingsModel 1.0 -import Governikus.Type.ChangePinModel 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.NumberModel 1.0 -import Governikus.Type.UiModule 1.0 - -SectionPage { - id: baseItem - enum SubViews { - Welcome, - AutoStartSetting, - HistorySetting, - CardReaderInfo, - CardReader, - TransportPin, - PasswordInfo, - Finished - } - - isAbstract: true - - titleBarAction: TitleBarAction { - helpTopic: "setupAssistant" - rootEnabled: d.allowNavigation - showSettings: false - //: LABEL DESKTOP - text: qsTr("Setup Assistant") - - onClicked: d.reset() - } - - onVisibleChanged: if (visible) - d.reset() - - QtObject { - id: d - - property int activeView: SetupAssistantView.SubViews.Welcome - readonly property bool allowNavigation: startupModule !== UiModule.TUTORIAL - readonly property int startupModule: SettingsModel.startupModule - - function reset() { - d.activeView = SetupAssistantView.SubViews.Welcome; - } - } - DecisionView { - agreeButton.iconSource: "qrc:///images/desktop/material_arrow_forward.svg" - agreeText: "" - mainIconSource: "qrc:///images/status_info.svg" - //: INFO DESKTOP Welcome message when starting the setup assistant. - questionText: qsTr("Welcome to the AusweisApp2. Please take a few moments to set up the environment to your needs. Every decision you make can later be changed in the settings menu.") - style: DecisionView.ButtonStyle.AgreeButton - visible: d.activeView === SetupAssistantView.SubViews.Welcome - - Component.onCompleted: setActive() - onAgree: d.activeView = (SettingsModel.autoStartAvailable && !SettingsModel.autoStartSetByAdmin) ? SetupAssistantView.SubViews.AutoStartSetting : SetupAssistantView.SubViews.HistorySetting - } - DecisionView { - mainIconSource: "qrc:///images/status_info.svg" - //: INFO DESKTOP Information text why autostart of the App is advisable - questionSubText: { - let subText = qsTr("In order to successfully use the eID function, %1 has to be running. It is therefore advisable to activate the auto-start after system startup.").arg(Qt.application.name); - if (Qt.platform.os === "osx") { - //: INFO MACOS Additional information that macOS auto-start add a symbol to the menu bar - subText += " " + qsTr("The launch will add an icon to the menu bar."); - } - return subText; - } - //: INFO DESKTOP Question if the App shall be started automatically after boot - questionText: qsTr("Do you want to automatically start the %1 after boot?").arg(Qt.application.name) - visible: d.activeView === SetupAssistantView.SubViews.AutoStartSetting - - titleBarAction: TitleBarAction { - helpTopic: "setupAssistant" - rootEnabled: d.allowNavigation - showSettings: false - //: LABEL DESKTOP - text: qsTr("Auto-start Setting") - } - - onAgree: { - SettingsModel.autoStartApp = true; - d.activeView = SetupAssistantView.SubViews.HistorySetting; - } - onDisagree: { - SettingsModel.autoStartApp = false; - d.activeView = SetupAssistantView.SubViews.HistorySetting; - } - } - DecisionView { - mainIconSource: "qrc:///images/material_history.svg" - //: INFO DESKTOP Information text which data is stored in the history record. - questionSubText: qsTr("The history is only saved locally. You can use it to see on what date you transmitted which data to which party. After enabling the history you can view and delete the entries anytime.") - //: INFO DESKTOP Question if the authentication history shall be stored. - questionText: qsTr("Do you want to save a history of performed authentications on your device?") - visible: d.activeView === SetupAssistantView.SubViews.HistorySetting - - titleBarAction: TitleBarAction { - helpTopic: "setupAssistant" - rootEnabled: d.allowNavigation - showSettings: false - //: LABEL DESKTOP - text: qsTr("History Setting") - } - - onAgree: { - SettingsModel.historyEnabled = true; - d.activeView = SetupAssistantView.SubViews.CardReaderInfo; - } - onDisagree: { - SettingsModel.historyEnabled = false; - d.activeView = SetupAssistantView.SubViews.CardReaderInfo; - } - } - DecisionView { - mainIconSource: "qrc:///images/reader/default_reader.png" - //: INFO DESKTOP Information text why a card reader is required to use the online - questionSubText: qsTr("In order to use the online identification feature on the computer, you need to set up a suitable smartphone or card reader before the first authentication process.") - //: INFO DESKTOP Question if the the user wants to setup any card readers now. - questionText: qsTr("Do you want to set up a card reader now?") - tintEnabled: false - visible: d.activeView === SetupAssistantView.SubViews.CardReaderInfo - - titleBarAction: TitleBarAction { - helpTopic: "setupAssistant" - rootEnabled: d.allowNavigation - showSettings: false - //: LABEL DESKTOP - text: qsTr("Card Readers") - } - - onAgree: d.activeView = SetupAssistantView.SubViews.CardReader - onDisagree: d.activeView = SetupAssistantView.SubViews.TransportPin - } - TabbedReaderView { - id: readerView - paneAnchors.bottom: forwardButton.top - rootEnabled: d.allowNavigation - visible: d.activeView === SetupAssistantView.SubViews.CardReader - - onCloseView: d.activeView = SetupAssistantView.SubViews.CardReaderInfo - - NavigationButton { - id: forwardButton - buttonType: NavigationButton.Type.Forward - visible: readerView.currentView === TabbedReaderView.SubView.None - - onClicked: d.activeView = SetupAssistantView.SubViews.TransportPin - - anchors { - bottom: parent.bottom - margins: Constants.pane_padding - right: parent.right - } - } - } - TransportPinAssistantView { - rootEnabled: d.allowNavigation - visible: d.activeView === SetupAssistantView.SubViews.TransportPin - - onAgree: { - SettingsModel.startupModule = UiModule.DEFAULT; // We don't want to show the setup assistant again, as the only subview left is "Setup assistant done" - SettingsModel.transportPinReminder = false; - baseItem.nextView(UiModule.PINMANAGEMENT); - } - onDisagree: { - SettingsModel.startupModule = UiModule.DEFAULT; - d.activeView = SetupAssistantView.SubViews.Finished; - } - } - ResultView { - //: INFO DESKTOP A11y button text to exit the setup assistant. - buttonText: qsTr("Proceed to start page") - resultType: ResultView.Type.IsSuccess - //: INFO DESKTOP Success message after completing the setup assistant. - text: qsTr("You have completed the setup of the AusweisApp2 successfully.") - visible: d.activeView === SetupAssistantView.SubViews.Finished - - onNextView: pName => { - baseItem.nextView(pName); - } - } -} diff --git a/resources/qml/Governikus/TutorialView/+desktop/TransportPinAssistantView.qml b/resources/qml/Governikus/TutorialView/+desktop/TransportPinAssistantView.qml deleted file mode 100644 index 824454109..000000000 --- a/resources/qml/Governikus/TutorialView/+desktop/TransportPinAssistantView.qml +++ /dev/null @@ -1,68 +0,0 @@ -/** - * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.View 1.0 -import Governikus.TitleBar 1.0 -import Governikus.PasswordInfoView 1.0 -import Governikus.Type.PasswordType 1.0 - -SectionPage { - id: root - - property bool rootEnabled: true - property bool showPasswordInfo: false - - signal agree - signal disagree - - titleBarAction: TitleBarAction { - helpTopic: "setupAssistant" - rootEnabled: root.rootEnabled - showSettings: false - //: LABEL DESKTOP - text: qsTr("Transport PIN") - - onClicked: { - showPasswordInfo = false; - updateTitleBarActions(); - } - } - - onVisibleChanged: if (visible) - showPasswordInfo = false - - DecisionView { - mainIconSource: "qrc:///images/material_lock.svg" - moreInformationText: infoData.linkText - moreInformationVisible: true - //: INFO DESKTOP Hint that a six-digit PIN is required to use the online identification feature of the ID card. - questionSubText: qsTr("If you have not already done so you have to change your five-digit Transport PIN to a six-digit PIN before you can use the online-ID function.") - //: INFO DESKTOP Inquiry message if the five-digit Transport PIN should be changed to an ordinary PIN (now). - questionText: qsTr("Do you want to change your (Transport) PIN now?") - visible: !showPasswordInfo - - onAgree: root.agree() - onDisagree: root.disagree() - onMoreInformationClicked: { - showPasswordInfo = true; - updateTitleBarActions(); - } - } - PasswordInfoData { - id: infoData - contentType: PasswordInfoContent.Type.TRANSPORT_PIN - } - PasswordInfoView { - id: passwordInfoView - infoContent: infoData - rootEnabled: root.rootEnabled - visible: showPasswordInfo - - onClose: { - showPasswordInfo = false; - updateTitleBarActions(); - } - } -} diff --git a/resources/qml/Governikus/TutorialView/+mobile/TutorialCollapseAnimation.qml b/resources/qml/Governikus/TutorialView/+mobile/TutorialCollapseAnimation.qml deleted file mode 100644 index b110ec84b..000000000 --- a/resources/qml/Governikus/TutorialView/+mobile/TutorialCollapseAnimation.qml +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 - -SequentialAnimation { - id: collapseAnimation - - property real duration: 500 - property var targetContent - - ParallelAnimation { - NumberAnimation { - duration: collapseAnimation.duration - easing.type: Easing.InOutQuad - property: "height" - target: collapseAnimation.targetContent - to: 0 - } - } - PropertyAction { - property: "visible" - target: collapseAnimation.targetContent - value: false - } -} diff --git a/resources/qml/Governikus/TutorialView/+mobile/TutorialContent.qml b/resources/qml/Governikus/TutorialView/+mobile/TutorialContent.qml deleted file mode 100644 index b00e6a5e7..000000000 --- a/resources/qml/Governikus/TutorialView/+mobile/TutorialContent.qml +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 - -Rectangle { - id: contentBackground - - default property alias columnChildren: contentColumn.children - readonly property alias contentHeight: contentColumn.height - - color: Constants.white - height: 0 - visible: false - width: parent.width - - Column { - id: contentColumn - anchors.top: parent.top - bottomPadding: Constants.component_spacing - spacing: Style.dimens.tutorial_component_spacing - topPadding: parent.width * 0.15 - width: parent.width - } -} diff --git a/resources/qml/Governikus/TutorialView/+mobile/TutorialExpandAnimation.qml b/resources/qml/Governikus/TutorialView/+mobile/TutorialExpandAnimation.qml deleted file mode 100644 index e753d8bb5..000000000 --- a/resources/qml/Governikus/TutorialView/+mobile/TutorialExpandAnimation.qml +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 - -SequentialAnimation { - id: expandAnimation - - property real duration: 500 - property var targetContent - property var targetHeader - - PropertyAction { - property: "visible" - target: expandAnimation.targetContent - value: true - } - ParallelAnimation { - NumberAnimation { - duration: expandAnimation.duration - easing.type: Easing.InOutQuad - property: "contentY" - target: flickable - to: expandAnimation.targetHeader.initY - } - NumberAnimation { - duration: expandAnimation.duration - easing.type: Easing.InOutQuad - from: 0 - property: "height" - target: expandAnimation.targetContent - to: expandAnimation.targetContent.contentHeight - } - } -} diff --git a/resources/qml/Governikus/TutorialView/+mobile/TutorialFooter.qml b/resources/qml/Governikus/TutorialView/+mobile/TutorialFooter.qml deleted file mode 100644 index d54cbdb54..000000000 --- a/resources/qml/Governikus/TutorialView/+mobile/TutorialFooter.qml +++ /dev/null @@ -1,121 +0,0 @@ -/** - * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 - -Rectangle { - id: baseItem - - property alias backRotation: backToMenu.imageRotation - property alias backText: backToMenu.text - property bool backToMenuActive: true - - signal menuClicked - signal quitTutorialClicked - - color: footer.color - height: plugin.safeAreaMargins.bottom + buttonRow.height - state: "showOnlyQuit" - - Behavior on color { - ColorAnimation { - duration: Constants.animation_duration - } - } - states: [ - State { - name: "showBothOptions" - when: baseItem.backToMenuActive - - PropertyChanges { - opacity: 1 - target: backToMenu - } - PropertyChanges { - Layout.alignment: Qt.AlignVCenter | Qt.AlignRight - target: quitTutorial - } - }, - State { - name: "showOnlyQuit" - when: !baseItem.backToMenuActive - - PropertyChanges { - opacity: 0 - target: backToMenu - } - PropertyChanges { - Layout.alignment: Qt.AlignCenter - target: quitTutorial - } - } - ] - transitions: [ - Transition { - PropertyAnimation { - duration: 500 - property: "opacity" - target: backToMenu - } - PropertyAnimation { - duration: 500 - easing.type: Easing.InOutQuad - property: "Layout.alignment" - target: quitTutorial - } - } - ] - - onVisibleChanged: if (visible) { - // When the user quits the tutorial on iOS while we're in the "showBothOptions" state, the - // animation will finish when the MoreView is already active. This results in quitTutorial - // being wrongly positioned the next time the users enters the tutorial. The following lines - // work around this issue: - if (state === "showOnlyQuit") { - quitTutorial.anchors.horizontalCenter = baseItem.horizontalCenter; - } - } - - RowLayout { - id: buttonRow - spacing: Constants.component_spacing - - anchors { - left: parent.left - leftMargin: Constants.component_spacing - right: parent.right - rightMargin: Constants.component_spacing - top: parent.top - } - TutorialFooterButton { - id: backToMenu - Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft - Layout.fillWidth: true - Layout.maximumWidth: implicitWidth * opacity - direction: Qt.LeftToRight - imageRotation: -90 - imageSource: "qrc:///images/tutorial/arrows.svg" - - //: LABEL ANDROID IOS - text: qsTr("Fold in") - visible: opacity > 0.0 - - onClicked: baseItem.menuClicked() - } - TutorialFooterButton { - id: quitTutorial - Layout.fillWidth: true - Layout.maximumWidth: implicitWidth - direction: Qt.RightToLeft - imageSource: "qrc:///images/tutorial/cross.svg" - - //: LABEL ANDROID IOS - text: qsTr("Quit tutorial") - - onClicked: baseItem.quitTutorialClicked() - } - } -} diff --git a/resources/qml/Governikus/TutorialView/+mobile/TutorialFooterButton.qml b/resources/qml/Governikus/TutorialView/+mobile/TutorialFooterButton.qml deleted file mode 100644 index f36f35ffd..000000000 --- a/resources/qml/Governikus/TutorialView/+mobile/TutorialFooterButton.qml +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Copyright (c) 2022-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 - -Item { - id: root - - property alias direction: contentRow.layoutDirection - property alias imageRotation: contentImage.rotation - property alias imageSource: contentImage.source - property alias text: contentText.text - - signal clicked - - Accessible.name: contentText.text - Accessible.role: Accessible.Button - height: contentRow.height + 2 * Constants.component_spacing - implicitWidth: contentImage.width + Math.ceil(contentText.implicitWidth) + Constants.component_spacing - - Accessible.onPressAction: clicked() - - MouseArea { - anchors.fill: contentRow - preventStealing: true - - onClicked: root.clicked() - } - RowLayout { - id: contentRow - height: contentText.height - spacing: Constants.component_spacing - width: parent.width - - anchors { - left: parent.left - right: parent.right - verticalCenter: parent.verticalCenter - } - Image { - id: contentImage - Layout.alignment: Qt.AlignVCenter - Layout.preferredHeight: height - Layout.preferredWidth: width - fillMode: Image.PreserveAspectFit - height: contentText.height - width: height * (sourceSize.width / sourceSize.height) - } - GText { - id: contentText - Accessible.ignored: true - Layout.alignment: Qt.AlignVCenter - Layout.fillWidth: true - Layout.maximumWidth: Math.ceil(implicitWidth) - elide: Text.ElideRight - textStyle: Style.text.normal_inverse - wrapMode: Text.NoWrap - } - } -} diff --git a/resources/qml/Governikus/TutorialView/+mobile/TutorialHeader.qml b/resources/qml/Governikus/TutorialView/+mobile/TutorialHeader.qml deleted file mode 100644 index e66b8ea56..000000000 --- a/resources/qml/Governikus/TutorialView/+mobile/TutorialHeader.qml +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 - -Item { - id: baseItem - - property bool categoryAbove: true - property alias headerImageSource: headerImage.source - property real initY - property alias miniIconCoordinates: backgroundIcons.model - property string miniIconSource - property bool overlapping: true - property real overlappingHeight: overlapping ? height * (4.0 / 3.0) : height - property alias titleText: title.text - - signal clicked - - Accessible.name: title.text - width: parent.width - - Accessible.onPressAction: clicked() - - Image { - id: headerImage - fillMode: Image.Stretch - height: baseItem.overlappingHeight - width: parent.width - - MouseArea { - anchors.fill: parent - - onClicked: baseItem.clicked() - } - Repeater { - id: backgroundIcons - Image { - height: 0.125 * baseItem.overlappingHeight - source: baseItem.miniIconSource - width: height - x: modelData.x * baseItem.width - y: modelData.y * baseItem.overlappingHeight - } - } - GText { - id: title - Accessible.ignored: true - anchors.horizontalCenter: parent.horizontalCenter - style: Text.Outline - styleColor: Constants.white - textStyle: Style.text.tutorial_title_highlight - y: ((categoryAbove ? 0.575 : 0.5) * parent.height) - (0.5 * height) - } - } -} diff --git a/resources/qml/Governikus/TutorialView/+mobile/TutorialHow.qml b/resources/qml/Governikus/TutorialView/+mobile/TutorialHow.qml deleted file mode 100644 index 1e9680822..000000000 --- a/resources/qml/Governikus/TutorialView/+mobile/TutorialHow.qml +++ /dev/null @@ -1,543 +0,0 @@ -/** - * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.SettingsModel 1.0 - -TutorialContent { - id: baseItem - signal firePush(var pSectionPage) - signal quitTutorialClicked - - Item { - Component { - id: readerMethodNfc - TutorialReaderMethodNfc { - onQuitTutorialClicked: baseItem.quitTutorialClicked() - } - } - Component { - id: readerMethodSacMobile - TutorialReaderMethodSacMobile { - onQuitTutorialClicked: baseItem.quitTutorialClicked() - } - } - Component { - id: readerMethodSacDesktop - TutorialReaderMethodSacDesktop { - onQuitTutorialClicked: baseItem.quitTutorialClicked() - } - } - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: INFO ANDROID IOS - text: (Constants.is_layout_ios ? qsTr("How can I use the AusweisApp2 on my iPhone?") : qsTr("How can I use the AusweisApp2 on my smartphone?")) - textStyle: Style.text.tutorial_header_accent - width: parent.width * 0.9 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - } - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/how_questions_everywhere.svg" - width: parent.width * 0.9 - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - } - Column { - spacing: Constants.component_spacing - width: parent.width - - Item { - height: Math.max(noticeText.height, noticeImage.height) - width: parent.width - - TutorialImage { - id: noticeImage - centerX: 0.2 - centerY: 0.5 - source: "qrc:///images/tutorial/hint.svg" - width: parent.width * 0.2 - } - GText { - id: noticeText - horizontalAlignment: Text.AlignLeft - - //: INFO ANDROID IOS - text: (Constants.is_layout_ios ? qsTr("Many iPhones (iPhone 7 and newer) can access the ID card via the built-in NFC interface.") : qsTr("Many Android devices can access the ID card via the built-in NFC interface.")) - textStyle: Style.text.tutorial_content_highlight - width: parent.width * 0.6 - x: (parent.width * 0.65) - (width / 2) - y: (parent.height * 0.5) - (height / 2) - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - //: LABEL ANDROID IOS - text: qsTr("You can test the capabilities of your device and your card by choosing \"Check device and ID card\" on the start page:") - textStyle: Style.text.tutorial_header_secondary - width: parent.width * 0.9 - } - TutorialShowMenuPath { - backgroundIcon: "qrc:///images/tutorial/background_icon_how.svg" - newSectionImage: "qrc:///images/tutorial/screenshot_check_id_card_%1_%2.png".arg(Constants.layout).arg(SettingsModel.language) - newSectionPointerY: Constants.is_layout_android ? 0.3 : 0.29 - width: parent.width - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - //: LABEL ANDROID IOS - text: qsTr("You can also find a list of compatible NFC-capable smartphones here:") - textStyle: Style.text.tutorial_header_secondary - width: parent.width * 0.9 - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - text: "%1".arg("https://www.ausweisapp.bund.de/%1/aa2/mobile-devices".arg(SettingsModel.language)) - textStyle: Style.text.tutorial_content - width: parent.width * 0.9 - } - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/how_device_lineup.svg" - width: parent.width - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("The AusweisApp2 offers the following options to access your ID card:") - textStyle: Style.text.tutorial_header_accent - width: parent.width * 0.9 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - } - Rectangle { - anchors.horizontalCenter: parent.horizontalCenter - border.color: Style.color.tutorial_how - border.width: 3 - color: Constants.white - height: methodNfcSection.height - width: parent.width * 0.95 - - MouseArea { - - //: LABEL ANDROID IOS - Accessible.name: qsTr("Direct connection via NFC chip tutorial") - Accessible.role: Accessible.Button - anchors.fill: parent - - Accessible.onPressAction: firePush(readerMethodNfc) - onClicked: firePush(readerMethodNfc) - } - Column { - id: methodNfcSection - padding: 10 - spacing: Constants.component_spacing - width: parent.width - - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("Direct connection via NFC chip") - textStyle: Style.text.tutorial_header_secondary_highlight - width: parent.width * 0.9 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - Rectangle { - anchors.horizontalCenter: parent.horizontalCenter - border.color: Style.color.tutorial_how - border.width: 3 - height: radius * 2 - radius: numberOne.height - width: radius * 2 - - GText { - id: numberOne - anchors.centerIn: parent - horizontalAlignment: Text.AlignHCenter - text: "1" - textStyle: Style.text.tutorial_header_secondary_highlight - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/how_method_nfc.svg" - width: parent.width * 0.8 - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: (Constants.is_layout_ios ? qsTr("App on iPhone with NFC chip as card reader") : qsTr("App on Android smartphone with NFC chip as card reader")) - textStyle: Style.text.tutorial_content - width: parent.width * 0.6 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/arrow_blue.svg" - width: parent.width * 0.2 - } - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - } - Rectangle { - anchors.horizontalCenter: parent.horizontalCenter - border.color: Style.color.tutorial_how - border.width: 3 - color: Constants.white - height: methodSacDesktopSection.height - width: parent.width * 0.95 - - MouseArea { - - //: LABEL ANDROID IOS - Accessible.name: qsTr("Smartphone as card reader tutorial") - Accessible.role: Accessible.Button - anchors.fill: parent - - Accessible.onPressAction: firePush(readerMethodSacDesktop) - onClicked: firePush(readerMethodSacDesktop) - } - Column { - id: methodSacDesktopSection - padding: 10 - spacing: Constants.component_spacing - width: parent.width - - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("Smartphone as card reader") - textStyle: Style.text.tutorial_header_secondary_highlight - width: parent.width * 0.9 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - Rectangle { - anchors.horizontalCenter: parent.horizontalCenter - border.color: Style.color.tutorial_how - border.width: 3 - height: radius * 2 - radius: numberTwo.height - width: radius * 2 - - GText { - id: numberTwo - anchors.centerIn: parent - horizontalAlignment: Text.AlignHCenter - text: "2" - textStyle: Style.text.tutorial_header_secondary_highlight - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - Item { - height: sacStationaryImage.height - width: parent.width - - Rectangle { - anchors.horizontalCenter: parent.horizontalCenter - border.color: Style.color.tutorial_how - border.width: 3 - height: radius * 2 - radius: parent.width * 0.06 - width: radius * 2 - x: (parent.width * 0.5) - (width / 2) - y: (parent.height * 0.4) - (height / 2) - - TutorialImage { - centerX: 0.5 - centerY: 0.5 - source: "qrc:///images/tutorial/wifi.svg" - width: parent.width * 0.8 - } - } - TutorialImage { - id: sacStationaryImage - centerX: 0.5 - centerY: 0.5 - source: "qrc:///images/tutorial/how_method_sac_desktop.svg" - width: parent.width - } - GText { - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("App on computer without NFC chip") - textStyle: Style.text.tutorial_content - width: parent.width * 0.4 - x: (parent.width * 0.25) - (width / 2) - y: (parent.height * 0.95) - (height / 2) - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - GText { - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("Smartphone with NFC chip as card reader") - textStyle: Style.text.tutorial_content - width: parent.width * 0.4 - x: (parent.width * 0.75) - (width / 2) - y: (parent.height * 0.95) - (height / 2) - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/arrow_blue.svg" - width: parent.width * 0.2 - } - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - } - Rectangle { - anchors.horizontalCenter: parent.horizontalCenter - border.color: Style.color.tutorial_how - border.width: 3 - color: Constants.white - height: methodSacMobileSection.height - width: parent.width * 0.95 - - MouseArea { - - //: LABEL ANDROID IOS - Accessible.name: qsTr("Smartphone as card reader mobile tutorial") - Accessible.role: Accessible.Button - anchors.fill: parent - - Accessible.onPressAction: firePush(readerMethodSacMobile) - onClicked: firePush(readerMethodSacMobile) - } - Column { - id: methodSacMobileSection - padding: 10 - spacing: Constants.component_spacing - width: parent.width - - Rectangle { - anchors.horizontalCenter: parent.horizontalCenter - border.color: Style.color.tutorial_how - border.width: 3 - height: radius * 2 - radius: numberTwo.height - width: radius * 2 - - GText { - id: numberThree - anchors.centerIn: parent - horizontalAlignment: Text.AlignHCenter - text: "3" - textStyle: Style.text.tutorial_header_secondary_highlight - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - Item { - height: sacMobileImage.height - width: parent.width - - Rectangle { - anchors.horizontalCenter: parent.horizontalCenter - border.color: Style.color.tutorial_how - border.width: 3 - height: radius * 2 - radius: parent.width * 0.06 - width: radius * 2 - x: (parent.width * 0.5) - (width / 2) - y: (parent.height * 0.4) - (height / 2) - - TutorialImage { - centerX: 0.5 - centerY: 0.5 - source: "qrc:///images/tutorial/wifi.svg" - width: parent.width * 0.8 - } - } - TutorialImage { - id: sacMobileImage - centerX: 0.5 - centerY: 0.5 - source: "qrc:///images/tutorial/how_method_sac_mobile.svg" - width: parent.width - } - GText { - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("App on tablet or smartphone without NFC chip") - textStyle: Style.text.tutorial_content - width: parent.width * 0.4 - x: (parent.width * 0.25) - (width / 2) - y: (parent.height * 0.95) - (height / 2) - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - GText { - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("Smartphone with NFC chip as card reader") - textStyle: Style.text.tutorial_content - width: parent.width * 0.4 - x: (parent.width * 0.75) - (width / 2) - y: (parent.height * 0.95) - (height / 2) - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/arrow_blue.svg" - width: parent.width * 0.2 - } - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - } - Rectangle { - property alias text: textContent.text - - color: Style.color.tutorial_how - height: textContent.height + 2 * Constants.component_spacing - width: parent.width - - GText { - id: textContent - anchors.centerIn: parent - color: Constants.white - horizontalAlignment: Text.AlignHCenter - //: LABEL ANDROID IOS - text: qsTr("Another tip") - textStyle: Style.text.tutorial_header - width: parent.width * 0.8 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - Column { - spacing: Constants.component_spacing - width: parent.width - - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("For lengthy forms, e.g. a BAf\u00F6G application, we recommend you to use the AusweisApp2 on a computer...") - textStyle: Style.text.tutorial_header_secondary - width: parent.width * 0.9 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - Item { - height: formImage.height - width: parent.width - - TutorialImage { - id: formImage - centerX: 0.4 - centerY: 0.5 - source: "qrc:///images/tutorial/how_form_no_fun.svg" - width: parent.width * 0.6 - } - GText { - color: Style.color.accent - horizontalAlignment: Text.AlignLeft - rightPadding: Constants.component_spacing - - //: LABEL ANDROID IOS - text: qsTr("Filling long forms is no fun on a smartphone!") - textStyle: Style.text.tutorial_content - width: parent.width * 0.5 - x: parent.width * 0.5 - y: (parent.height * 0.5) - (height / 2) - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("... and to use a smartphone to communicate with your ID card. A USB reader is of course also an alternative.") - textStyle: Style.text.tutorial_header_secondary - width: parent.width * 0.9 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/how_desktop.svg" - width: parent.width - } -} diff --git a/resources/qml/Governikus/TutorialView/+mobile/TutorialImage.qml b/resources/qml/Governikus/TutorialView/+mobile/TutorialImage.qml deleted file mode 100644 index fecbcf120..000000000 --- a/resources/qml/Governikus/TutorialView/+mobile/TutorialImage.qml +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Global 1.0 - -Image { - property real centerX: 0.5 - property real centerY: 0.5 - - asynchronous: true - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - x: (parent.width * centerX) - (width / 2) - y: (parent.height * centerY) - (height / 2) -} diff --git a/resources/qml/Governikus/TutorialView/+mobile/TutorialImportant.qml b/resources/qml/Governikus/TutorialView/+mobile/TutorialImportant.qml deleted file mode 100644 index b362aee50..000000000 --- a/resources/qml/Governikus/TutorialView/+mobile/TutorialImportant.qml +++ /dev/null @@ -1,271 +0,0 @@ -/** - * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.PinResetInformationModel 1.0 -import Governikus.Type.SettingsModel 1.0 -import Governikus.Type.NumberModel 1.0 -import Governikus.Type.ChangePinModel 1.0 - -TutorialContent { - id: baseItem - signal letsGoClicked - signal showPinManagement - - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - text: (SettingsModel.language === "en" ? - //: LABEL ANDROID IOS - qsTr("Please exchange your") : - //: LABEL ANDROID IOS - qsTr("Before you use the online ID function please change the")) - textStyle: Style.text.tutorial_header - width: parent.width * 0.9 - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_important.svg" - } - Column { - spacing: Constants.component_spacing - width: parent.width - - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - //: LABEL ANDROID IOS - text: qsTr("five-digit") - textStyle: Style.text.tutorial_header - width: parent.width * 0.9 - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - //: LABEL ANDROID IOS - text: qsTr("Transport PIN") - textStyle: Style.text.tutorial_header_highlight - width: parent.width * 0.9 - } - TutorialImage { - source: "qrc:///images/tutorial/important_pin5.svg" - width: parent.width * 0.8 - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_important.svg" - } - Column { - spacing: Constants.component_spacing - width: parent.width - - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - //: LABEL ANDROID IOS - text: qsTr("with a") - textStyle: Style.text.tutorial_header - width: parent.width * 0.9 - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - //: LABEL ANDROID IOS - text: qsTr("six-digit PIN") - textStyle: Style.text.tutorial_header_highlight - width: parent.width * 0.9 - } - TutorialImage { - source: "qrc:///images/tutorial/important_pin6.svg" - width: parent.width * 0.8 - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - text: (SettingsModel.language === "en" ? - //: LABEL ANDROID IOS - qsTr("before you use the online ID function!") : - //: LABEL ANDROID IOS - qsTr("change!")) - textStyle: Style.text.tutorial_header - width: parent.width * 0.9 - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - //: LABEL ANDROID IOS - text: qsTr("The Transport PIN is sent to you by the Bundesdruckerei via mail.") - textStyle: Style.text.tutorial_header - width: parent.width * 0.9 - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_important.svg" - } - Column { - spacing: Constants.component_spacing - width: parent.width - - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - //: LABEL ANDROID IOS - text: qsTr("Select for this purpose the menu item \"Change my (Transport) PIN\" from the start page. Later you can also change your six-digit PIN here") - textStyle: Style.text.tutorial_header_secondary - width: parent.width * 0.9 - } - TutorialShowMenuPath { - backgroundIcon: "qrc:///images/tutorial/background_icon_important.svg" - newSectionImage: "qrc:///images/tutorial/screenshot_pin_management_menu_%1_%2.png".arg(Constants.layout).arg(SettingsModel.language) - newSectionPointerY: Constants.is_layout_android ? 0.47 : 0.5 - width: parent.width - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - //: LABEL ANDROID IOS - text: qsTr("... or click this button to change your PIN right now:") - textStyle: Style.text.tutorial_header_secondary - width: parent.width * 0.9 - } - GButton { - anchors.horizontalCenter: parent.horizontalCenter - anchors.margins: Constants.component_spacing - //: LABEL ANDROID IOS - text: qsTr("Change my (Transport) PIN") - - onClicked: showPinManagement() - } - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("Please note: The Transport PIN can only be used for your first PIN change. If you have already set your six-digit PIN (e.g. while picking up your ID card) only the set PIN is valid.") - textStyle: Style.text.tutorial_header_secondary - width: parent.width * 0.9 - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - //: LABEL ANDROID IOS - text: qsTr("If you cannot recall your six-digit PIN or cannot find your PIN letter, you may request a new PIN using the PIN Reset Service.") - textStyle: Style.text.tutorial_header_secondary - width: parent.width * 0.9 - } - GButton { - anchors.horizontalCenter: parent.horizontalCenter - text: PinResetInformationModel.pinResetActionText - visible: text !== "" - - onClicked: Qt.openUrlExternally(PinResetInformationModel.pinResetUrl) - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_important.svg" - } - Column { - spacing: Constants.component_spacing - width: parent.width - - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/play_movie.png" - width: parent.width * 0.7 - - MouseArea { - - //: LABEL ANDROID IOS - Accessible.name: qsTr("Open YouTube video") - Accessible.role: Accessible.Button - anchors.fill: parent - - Accessible.onPressAction: clicked(null) - onClicked: Qt.openUrlExternally("https://www.ausweisapp.bund.de/%1/aa2/video-passwords".arg(SettingsModel.language)) - } - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("Learn more about this in the YouTube video") - textStyle: Style.text.tutorial_header_secondary - width: parent.width * 0.9 - } - Item { - height: letsGoImage.height - width: parent.width - - MouseArea { - anchors.fill: parent - - onClicked: baseItem.letsGoClicked() - } - TutorialImage { - id: letsGoImage - centerX: 0.5 - centerY: 0.5 - source: "qrc:///images/tutorial/important_lets_go.svg" - width: parent.width - } - GText { - color: Constants.white - horizontalAlignment: Text.AlignHCenter - //: LABEL ANDROID IOS - text: qsTr("Let's go") - textStyle: Style.text.tutorial_header - width: parent.width - x: (parent.width * 0.5) - (width / 2) - y: (parent.height * 0.6) - (height / 2) - } - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - //: LABEL ANDROID IOS - text: qsTr("Do you still have questions?") - textStyle: Style.text.tutorial_header - width: parent.width * 0.9 - } - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width - source: "qrc:///images/tutorial/important_space_questionmark.svg" - width: parent.width * 0.4 - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - //: LABEL ANDROID IOS - text: qsTr("You can read our FAQs or write to us...") - textStyle: Style.text.tutorial_header - width: parent.width * 0.9 - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - text: "%1/%2
    %3
    %4".arg("www.ausweisapp.bund.de").arg(SettingsModel.language).arg( - //: LABEL ANDROID IOS - qsTr("or")).arg("www.personalausweisportal.de") - textStyle: Style.text.tutorial_header_secondary - width: parent.width * 0.9 - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_important.svg" - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - //: LABEL ANDROID IOS - text: qsTr("You can always access this tutorial again from the \"Help\" section in the menu bar.") - textStyle: Style.text.tutorial_header - width: parent.width * 0.9 - } -} diff --git a/resources/qml/Governikus/TutorialView/+mobile/TutorialReaderMethodFooter.qml b/resources/qml/Governikus/TutorialView/+mobile/TutorialReaderMethodFooter.qml deleted file mode 100644 index b5bdb3438..000000000 --- a/resources/qml/Governikus/TutorialView/+mobile/TutorialReaderMethodFooter.qml +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 - -TutorialFooter { - id: footer - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - backRotation: 180 - //: LABEL ANDROID IOS - backText: qsTr("Back") - color: Style.color.accent - state: "showBothOptions" - width: baseItem.width -} diff --git a/resources/qml/Governikus/TutorialView/+mobile/TutorialReaderMethodNfc.qml b/resources/qml/Governikus/TutorialView/+mobile/TutorialReaderMethodNfc.qml deleted file mode 100644 index 577bd2464..000000000 --- a/resources/qml/Governikus/TutorialView/+mobile/TutorialReaderMethodNfc.qml +++ /dev/null @@ -1,514 +0,0 @@ -/** - * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 -import Governikus.Type.SettingsModel 1.0 - -SectionPage { - id: baseItem - signal quitTutorialClicked - - automaticSafeAreaMarginHandling: false - //: LABEL ANDROID IOS - title: qsTr("Tutorial: NFC") - titleBarVisible: false - - content: Item { - height: content.contentHeight - width: baseItem.width - - TutorialContent { - id: content - anchors.horizontalCenter: parent.horizontalCenter - height: content.contentHeight - visible: true - width: Constants.is_tablet ? baseItem.width * 0.5 : baseItem.width - - GSpacer { - height: statusBar.height - width: parent.width - } - Column { - spacing: Constants.component_spacing - width: parent.width - - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("Direct connection via NFC chip") - textStyle: Style.text.tutorial_header_secondary_highlight - width: parent.width * 0.9 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - Rectangle { - anchors.horizontalCenter: parent.horizontalCenter - border.color: Style.color.tutorial_how - border.width: 3 - height: radius * 2 - radius: numberOne.height - width: radius * 2 - - GText { - id: numberOne - anchors.centerIn: parent - horizontalAlignment: Text.AlignHCenter - text: "1" - textStyle: Style.text.tutorial_header_secondary_highlight - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/how_method_nfc.svg" - width: parent.width * 0.8 - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL IOS - text: (Constants.is_layout_ios ? qsTr("App on iPhone with NFC chip as card reader") : - //: LABEL ANDROID - qsTr("App on Android smartphone with NFC chip as card reader")) - textStyle: Style.text.tutorial_content - width: parent.width * 0.6 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - rotation: 90 - source: "qrc:///images/tutorial/arrow_blue.svg" - width: parent.width * 0.2 - } - Item { - height: providerOnSmartphone.height - width: parent.width - - TutorialImage { - id: providerOnSmartphone - source: "qrc:///images/tutorial/reader_nfc_provider_on_smartphone.svg" - width: parent.width - } - GText { - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("Click link on the website of the provider.") - textStyle: Style.text.tutorial_header_secondary - width: parent.width * 0.6 - x: (parent.width * 0.5) - (width / 2) - y: (parent.height * 0.9) - (height / 2) - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - } - Item { - height: userdataExample.height + textAccessWhoWhat.height + textOpenAutomatic.height + 2 * Constants.component_spacing - width: parent.width - - TutorialImage { - centerX: 0.2 - centerY: (textAccessWhoWhat.y + textAccessWhoWhat.height) / (2 * parent.height) - source: "qrc:///images/tutorial/reader_nfc_npa_on_smartphone.svg" - width: parent.width * 0.3 - } - GText { - id: textOpenAutomatic - horizontalAlignment: Text.AlignHCenter - rightPadding: Constants.component_spacing - - //: LABEL ANDROID IOS - text: qsTr("The App opens automatically.") - textStyle: Style.text.tutorial_content - width: parent.width * 0.6 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - - anchors { - right: parent.right - top: parent.top - } - } - GText { - id: textAccessWhoWhat - horizontalAlignment: Text.AlignHCenter - rightPadding: Constants.component_spacing - - //: LABEL ANDROID IOS - text: qsTr("The AusweisApp2 will display who wants to access which data.") - textStyle: Style.text.tutorial_header_secondary - width: parent.width * 0.6 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - - anchors { - right: parent.right - top: textOpenAutomatic.bottom - topMargin: Constants.component_spacing - } - } - TutorialImage { - id: userdataExample - source: "qrc:///images/tutorial/reader_nfc_userdata_example_%1.svg".arg(SettingsModel.language) - width: parent.width * 0.8 - - anchors { - horizontalCenter: parent.horizontalCenter - top: textAccessWhoWhat.bottom - topMargin: Constants.component_spacing - } - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - } - Column { - spacing: Constants.component_spacing - width: parent.width - - GText { - id: startProcessText - anchors.horizontalCenter: parent.horizontalCenter - //: LABEL ANDROID IOS - text: qsTr("Start the process with a click on:") - textStyle: Style.text.tutorial_header_secondary - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - Row { - anchors.horizontalCenter: parent.horizontalCenter - height: authArrow.height - spacing: Constants.component_spacing - - Image { - id: authArrow - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/arrow_blue.svg" - width: parent.width * 0.2 - } - GButton { - animationsDisabled: true - icon.source: "qrc:///images/identify.svg" - - //: LABEL ANDROID IOS - text: qsTr("Proceed to PIN entry") - tintIcon: true - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - } - Column { - anchors.horizontalCenter: parent.horizontalCenter - spacing: Constants.component_spacing - width: parent.width - - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/where_lay_down_id.svg" - width: parent.width * 0.8 - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL IOS - text: (Constants.is_layout_ios ? qsTr("... and place the top of the iPhone onto the ID card.") : - //: LABEL ANDROID - qsTr("... and place the ID card flat onto the NFC interface.")) - textStyle: Style.text.tutorial_header_secondary - width: parent.width * 0.9 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - Item { - height: noticeImage.height - width: parent.width - - TutorialImage { - id: noticeImage - centerX: 0.2 - centerY: 0.5 - source: "qrc:///images/tutorial/hint.svg" - width: parent.width * 0.2 - } - GText { - horizontalAlignment: Text.AlignLeft - - //: LABEL ANDROID IOS - text: qsTr("Do not move device or ID card!") - textStyle: Style.text.tutorial_content_highlight - width: parent.width * 0.6 - x: (parent.width * 0.65) - (width / 2) - y: (parent.height * 0.5) - (height / 2) - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - visible: Constants.is_layout_android - } - Item { - height: Math.max(nfcPosition.height, nfcText.height) - visible: Constants.is_layout_android - width: parent.width * 0.9 - - TutorialImage { - id: nfcPosition - source: "qrc:///images/tutorial/reader_nfc_smartphone_nfc_position.svg" - width: parent.width * 0.75 - - anchors { - left: parent.left - verticalCenter: parent.verticalCenter - } - } - GText { - id: nfcText - horizontalAlignment: Text.AlignLeft - - //: LABEL ANDROID - text: qsTr("The correct position is specific for your device. If a position does not work try a different one. The AusweisApp2 shows different common positions.") - textStyle: Style.text.tutorial_content_highlight - width: parent.width * 0.55 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - - anchors { - right: parent.right - verticalCenter: parent.verticalCenter - } - } - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID - text: qsTr("If your device is unable to detect your ID card try to check the device capabilities by clicking on \"Check device and ID card\" on the start page.") - textStyle: Style.text.tutorial_content_highlight - visible: Constants.is_layout_android - width: parent.width * 0.9 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("You can find more information on compatible devices on our %1mobile device list%2.").arg("".arg(SettingsModel.language)).arg("") - textStyle: Style.text.tutorial_header_secondary - visible: Constants.is_layout_android - width: parent.width * 0.9 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - } - Column { - spacing: Constants.component_spacing - width: parent.width - - Item { - height: pin6Image.height + Constants.component_spacing * 2 - width: parent.width - - GText { - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS This is the first of three lines "Enter" "six-digit PIN" "now!" and should be translated accoording to the third line. - text: qsTr("Enter") - textStyle: Style.text.tutorial_header - width: parent.width * 0.8 - x: (parent.width * 0.5) - (width / 2) - y: (parent.height * 0.05) - (height / 2) - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - TutorialImage { - id: pin6Image - centerX: 0.5 - centerY: 0.5 - source: "qrc:///images/tutorial/reader_nfc_pin6.svg" - width: parent.width * 0.8 - z: 1 - } - GText { - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("six-digit PIN") - textStyle: Style.text.tutorial_header_highlight - width: parent.width - x: (parent.width * 0.5) - (width / 2) - y: (parent.height * 0.2) - (height / 2) - z: 2 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS This is the third of three lines "Enter" "six-digit PIN" "now!" and should be translated accoording to the first line. - text: qsTr("now!") - textStyle: Style.text.tutorial_header - width: parent.width * 0.8 - x: (parent.width * 0.5) - (width / 2) - y: (parent.height * 0.9) - (height / 2) - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - Item { - height: Math.max(noticeImage2.height, noticeText2.height) - width: parent.width - - TutorialImage { - id: noticeImage2 - centerX: 0.2 - centerY: 0.5 - source: "qrc:///images/tutorial/hint.svg" - width: parent.width * 0.2 - } - GText { - id: noticeText2 - horizontalAlignment: Text.AlignLeft - - //: LABEL ANDROID IOS - text: qsTr("This is only possible if you have exchanged the five-digit Transport PIN with a six-digit PIN beforehand.") - textStyle: Style.text.tutorial_content_highlight - width: parent.width * 0.6 - x: (parent.width * 0.65) - (width / 2) - y: (parent.height * 0.5) - (height / 2) - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - } - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/play_movie.png" - width: parent.width * 0.7 - - MouseArea { - - //: LABEL ANDROID IOS - Accessible.name: qsTr("Open YouTube video") - Accessible.role: Accessible.Button - anchors.fill: parent - - Accessible.onPressAction: clicked(null) - onClicked: Qt.openUrlExternally("https://www.ausweisapp.bund.de/%1/aa2/video-nfc-%2".arg(SettingsModel.language).arg(Constants.layout)) - } - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("You can also watch this YouTube video explaining the process.") - textStyle: Style.text.tutorial_header_secondary - width: parent.width * 0.9 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - } - MouseArea { - height: finishedButton.height - width: parent.width - - onClicked: pop() - - Image { - id: finishedButton - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/reader_nfc_finished.svg" - width: parent.width * 0.8 - } - } - GSpacer { - height: footer.height - width: parent.width - } - } - } - navigationAction: NavigationAction { - action: NavigationAction.Action.Back - - onClicked: pop() - } - - Rectangle { - anchors.fill: parent - color: Constants.white - z: -1 - } - TutorialStatusBar { - id: statusBar - } - TutorialReaderMethodFooter { - id: footer - width: baseItem.width - - onMenuClicked: pop() - onQuitTutorialClicked: { - pop(); - baseItem.quitTutorialClicked(); - } - } -} diff --git a/resources/qml/Governikus/TutorialView/+mobile/TutorialReaderMethodSacDesktop.qml b/resources/qml/Governikus/TutorialView/+mobile/TutorialReaderMethodSacDesktop.qml deleted file mode 100644 index 3012cf416..000000000 --- a/resources/qml/Governikus/TutorialView/+mobile/TutorialReaderMethodSacDesktop.qml +++ /dev/null @@ -1,834 +0,0 @@ -/** - * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 -import Governikus.Type.SettingsModel 1.0 - -SectionPage { - id: baseItem - signal quitTutorialClicked - - automaticSafeAreaMarginHandling: false - //: LABEL ANDROID IOS - title: qsTr("Tutorial: Smartphone as card reader") - titleBarVisible: false - - content: Item { - height: content.contentHeight - width: baseItem.width - - TutorialContent { - id: content - anchors.horizontalCenter: parent.horizontalCenter - height: content.contentHeight - visible: true - width: Constants.is_tablet ? baseItem.width * 0.5 : baseItem.width - - GSpacer { - height: statusBar.height - width: parent.width - } - Column { - spacing: Constants.component_spacing - width: parent.width - - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("Smartphone as card reader") - textStyle: Style.text.tutorial_header_secondary_highlight - width: parent.width * 0.9 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - Rectangle { - anchors.horizontalCenter: parent.horizontalCenter - border.color: Style.color.tutorial_how - border.width: 3 - height: radius * 2 - radius: numberTwo.height - width: radius * 2 - - GText { - id: numberTwo - anchors.centerIn: parent - horizontalAlignment: Text.AlignHCenter - text: "2" - textStyle: Style.text.tutorial_header_secondary_highlight - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - Item { - height: sacStationaryImage.height - width: parent.width - - Rectangle { - anchors.horizontalCenter: parent.horizontalCenter - border.color: Style.color.tutorial_how - border.width: 3 - height: radius * 2 - radius: parent.width * 0.06 - width: radius * 2 - x: (parent.width * 0.5) - (width / 2) - y: (parent.height * 0.4) - (height / 2) - - TutorialImage { - centerX: 0.5 - centerY: 0.5 - source: "qrc:///images/tutorial/wifi.svg" - width: parent.width * 0.8 - } - } - TutorialImage { - id: sacStationaryImage - centerX: 0.5 - centerY: 0.5 - source: "qrc:///images/tutorial/how_method_sac_desktop.svg" - width: parent.width - } - GText { - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("App on computer without NFC chip") - textStyle: Style.text.tutorial_content - width: parent.width * 0.4 - x: (parent.width * 0.25) - (width / 2) - y: (parent.height * 0.95) - (height / 2) - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - GText { - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("Smartphone with NFC chip as card reader") - textStyle: Style.text.tutorial_content - width: parent.width * 0.4 - x: (parent.width * 0.75) - (width / 2) - y: (parent.height * 0.95) - (height / 2) - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - } - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - rotation: 90 - source: "qrc:///images/tutorial/arrow_blue.svg" - width: parent.width * 0.2 - } - Column { - spacing: Constants.component_spacing - width: parent.width - - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("Install AusweisApp2 on both your computer and your smartphone with NFC capability.") - textStyle: Style.text.tutorial_header - width: parent.width * 0.9 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/reader_sac_aa2_ok.svg" - width: parent.width * 0.8 - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - } - Column { - spacing: Constants.component_spacing - width: parent.width - - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/hint.svg" - width: parent.width * 0.3 - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("Both devices have to be connected to the same WiFi network") - textStyle: Style.text.tutorial_header_highlight - width: parent.width * 0.9 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/wifi.svg" - width: parent.width * 0.3 - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - } - Column { - spacing: Constants.component_spacing - width: parent.width - - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("Now choose \"Card reader\" in the AusweisApp2 on your smartphone...") - textStyle: Style.text.tutorial_header - width: parent.width * 0.9 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/reader_sac_menu_%1_%2.svg".arg(Constants.layout).arg(SettingsModel.language) - width: parent.width * 0.9 - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - } - Column { - spacing: Constants.component_spacing - width: parent.width - - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignRight - - //: LABEL ANDROID IOS - text: qsTr("Now") - textStyle: Style.text.tutorial_header - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - GButton { - id: pairingButton - anchors.horizontalCenter: parent.horizontalCenter - animationsDisabled: true - - //: LABEL ANDROID IOS - text: qsTr("Pair device") - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - rotation: 180 - source: "qrc:///images/tutorial/up_icon.svg" - width: parent.width * 0.1 - } - Item { - anchors.horizontalCenter: parent.horizontalCenter - height: greyBackgroundRect.height - width: pairingCodeText.width - - Rectangle { - id: greyBackgroundRect - anchors.horizontalCenter: parent.horizontalCenter - color: Style.color.tutorial_box_background - height: width - width: pairingCodeText.width - 40 - } - GText { - id: pairingCodeText - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: greyBackgroundRect.top - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("Pairing code") - textStyle: Style.text.tutorial_header_highlight - topPadding: 30 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - GText { - id: appearingText - anchors.bottom: greyBackgroundRect.bottom - anchors.horizontalCenter: parent.horizontalCenter - bottomPadding: 30 - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("appears!") - textStyle: Style.text.tutorial_header - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - visible: Constants.is_layout_ios - } - Item { - height: Math.max(noticeImage4.height, noticeText4.height) - visible: Constants.is_layout_ios - width: parent.width - - TutorialImage { - id: noticeImage4 - centerX: 0.2 - centerY: 0.5 - source: "qrc:///images/tutorial/hint.svg" - width: parent.width * 0.2 - } - GText { - id: noticeText4 - horizontalAlignment: Text.AlignLeft - - //: LABEL IOS - text: qsTr("On the first use of the Smartphone as card reader (SaC), iOS will asks for your permission to access the local network. This permission is required in order find and connect to your SaC. After the first request you can always access the permission in the iOS settings for this app.") - textStyle: Style.text.tutorial_content_highlight - width: parent.width * 0.6 - x: (parent.width * 0.65) - (width / 2) - y: (parent.height * 0.5) - (height / 2) - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - } - Column { - spacing: Constants.component_spacing - width: parent.width - - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/reader_sac_npa_on_laptop.svg" - width: parent.width * 0.3 - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("Start the App now on your computer and enter the settings.") - textStyle: Style.text.tutorial_header - width: parent.width * 0.8 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("Select the Smartphone as card reader tab.") - textStyle: Style.text.tutorial_header - width: parent.width * 0.8 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - } - Column { - spacing: Constants.component_spacing - width: parent.width - - Item { - height: desktopPairing.height - width: parent.width - - TutorialImage { - id: desktopPairing - source: "qrc:///images/tutorial/screenshot_pairing_%1.png".arg(SettingsModel.language) - width: parent.width * 0.6 - } - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("Select smartphone from list") - textStyle: Style.text.tutorial_header - width: parent.width * 0.8 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - Item { - height: noticeImage3.height - width: parent.width - - TutorialImage { - id: noticeImage3 - centerX: 0.2 - centerY: 0.5 - source: "qrc:///images/tutorial/hint.svg" - width: parent.width * 0.2 - } - GText { - horizontalAlignment: Text.AlignLeft - - //: LABEL ANDROID IOS - text: qsTr("Enter pairing code next.") - textStyle: Style.text.tutorial_content_highlight - width: parent.width * 0.6 - x: (parent.width * 0.65) - (width / 2) - y: (parent.height * 0.5) - (height / 2) - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - } - Column { - width: parent.width - - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/reader_sac_provider_on_laptop.svg" - width: parent.width * 0.5 - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("Click link on the website of the provider.") - textStyle: Style.text.tutorial_header_secondary - width: parent.width * 0.6 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - } - Item { - height: userdataExample.height + textAccessWhoWhat.height + textOpenAutomatic.height + 2 * Constants.component_spacing - width: parent.width - - TutorialImage { - centerX: 0.2 - centerY: (textAccessWhoWhat.y + textAccessWhoWhat.height) / (2 * parent.height) - source: "qrc:///images/tutorial/reader_sac_npa_on_laptop.svg" - width: parent.width * 0.3 - } - GText { - id: textOpenAutomatic - horizontalAlignment: Text.AlignHCenter - rightPadding: Constants.component_spacing - - //: LABEL ANDROID IOS - text: qsTr("The App opens automatically.") - textStyle: Style.text.tutorial_content - width: parent.width * 0.6 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - - anchors { - right: parent.right - top: parent.top - } - } - GText { - id: textAccessWhoWhat - horizontalAlignment: Text.AlignHCenter - rightPadding: Constants.component_spacing - - //: LABEL ANDROID IOS - text: qsTr("The AusweisApp2 will display who wants to access which data.") - textStyle: Style.text.tutorial_header_secondary - width: parent.width * 0.6 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - - anchors { - right: parent.right - top: textOpenAutomatic.bottom - topMargin: Constants.component_spacing - } - } - TutorialImage { - id: userdataExample - source: "qrc:///images/tutorial/reader_nfc_userdata_example_%1.svg".arg(SettingsModel.language) - width: parent.width * 0.8 - - anchors { - horizontalCenter: parent.horizontalCenter - top: textAccessWhoWhat.bottom - topMargin: Constants.component_spacing - } - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - } - Column { - spacing: Constants.component_spacing - width: parent.width - - GText { - id: startProcessText - anchors.horizontalCenter: parent.horizontalCenter - //: LABEL ANDROID IOS - text: qsTr("Start the process with a click on:") - textStyle: Style.text.tutorial_header_secondary - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - Row { - anchors.horizontalCenter: parent.horizontalCenter - height: authArrow.height - spacing: Constants.component_spacing - - Image { - id: authArrow - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/arrow_blue.svg" - width: parent.width * 0.2 - } - GButton { - animationsDisabled: true - icon.source: "qrc:///images/identify.svg" - - //: LABEL ANDROID IOS - text: qsTr("Proceed to PIN entry") - tintIcon: true - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - } - Column { - spacing: Constants.component_spacing - width: parent.width - - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/where_lay_down_id.svg" - width: parent.width * 0.8 - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("... and place the ID card onto the NFC interface.") - textStyle: Style.text.tutorial_header_secondary - width: parent.width * 0.9 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - Item { - height: noticeImage.height - width: parent.width - - TutorialImage { - id: noticeImage - centerX: 0.2 - centerY: 0.5 - source: "qrc:///images/tutorial/hint.svg" - width: parent.width * 0.2 - } - GText { - horizontalAlignment: Text.AlignLeft - - //: LABEL ANDROID IOS - text: qsTr("Do not move device or ID card!") - textStyle: Style.text.tutorial_content_highlight - width: parent.width * 0.6 - x: (parent.width * 0.65) - (width / 2) - y: (parent.height * 0.5) - (height / 2) - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - } - Item { - height: Math.max(nfcPosition.height, nfcText.height) - width: parent.width * 0.9 - - TutorialImage { - id: nfcPosition - source: "qrc:///images/tutorial/reader_nfc_smartphone_nfc_position.svg" - width: parent.width * 0.75 - - anchors { - left: parent.left - verticalCenter: parent.verticalCenter - } - } - GText { - id: nfcText - horizontalAlignment: Text.AlignLeft - - //: LABEL ANDROID IOS - text: qsTr("The correct position is specific for your device. If a position does not work try a different one. The AusweisApp2 shows different common positions.") - textStyle: Style.text.tutorial_content_highlight - width: parent.width * 0.55 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - - anchors { - right: parent.right - verticalCenter: parent.verticalCenter - } - } - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("If your device is unable to detect your ID card try to check the device capabilities by clicking on \"Check device and ID card\" on the start page.") - textStyle: Style.text.tutorial_content_highlight - width: parent.width * 0.9 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("You can find more information on compatible devices on our %1mobile device list%2.").arg("".arg(SettingsModel.language)).arg("") - textStyle: Style.text.tutorial_header_secondary - visible: Constants.is_layout_android - width: parent.width * 0.9 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - } - Column { - spacing: Constants.component_spacing - width: parent.width - - Item { - height: pin6Image.height + Constants.component_spacing * 2 - width: parent.width - - GText { - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS This is the first of three lines "Enter" "six-digit PIN" "now!" and should be translated according to the third line. - text: qsTr("Enter") - textStyle: Style.text.tutorial_header - width: parent.width * 0.8 - x: (parent.width * 0.5) - (width / 2) - y: (parent.height * 0.05) - (height / 2) - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - TutorialImage { - id: pin6Image - centerX: 0.5 - centerY: 0.5 - source: "qrc:///images/tutorial/reader_nfc_pin6.svg" - width: parent.width * 0.8 - z: 1 - } - GText { - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("six-digit PIN") - textStyle: Style.text.tutorial_header_highlight - width: parent.width - x: (parent.width * 0.5) - (width / 2) - y: (parent.height * 0.2) - (height / 2) - z: 2 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS This is the third of three lines "Enter" "six-digit PIN" "now!" and should be translated according to the first line. - text: qsTr("now!") - textStyle: Style.text.tutorial_header - width: parent.width * 0.8 - x: (parent.width * 0.5) - (width / 2) - y: (parent.height * 0.9) - (height / 2) - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - Item { - height: Math.max(noticeImage2.height, noticeText2.height) - width: parent.width - - TutorialImage { - id: noticeImage2 - centerX: 0.2 - centerY: 0.5 - source: "qrc:///images/tutorial/hint.svg" - width: parent.width * 0.2 - } - GText { - id: noticeText2 - horizontalAlignment: Text.AlignLeft - - //: LABEL ANDROID IOS - text: qsTr("This is only possible if you have exchanged the five-digit Transport PIN with a six-digit PIN beforehand.") - textStyle: Style.text.tutorial_content_highlight - width: parent.width * 0.6 - x: (parent.width * 0.65) - (width / 2) - y: (parent.height * 0.5) - (height / 2) - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - } - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/play_movie.png" - width: parent.width * 0.7 - - MouseArea { - - //: LABEL ANDROID IOS - Accessible.name: qsTr("Open YouTube video") - Accessible.role: Accessible.Button - anchors.fill: parent - - Accessible.onPressAction: clicked(null) - onClicked: Qt.openUrlExternally("https://www.ausweisapp.bund.de/%1/aa2/video-sac-desktop".arg(SettingsModel.language)) - } - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("You can also watch this YouTube video explaining the process.") - textStyle: Style.text.tutorial_header_secondary - width: parent.width * 0.9 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - } - MouseArea { - height: finishedButton.height - width: parent.width - - onClicked: pop() - - Image { - id: finishedButton - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/reader_nfc_finished.svg" - width: parent.width * 0.8 - } - } - GSpacer { - height: footer.height - width: parent.width - } - } - } - navigationAction: NavigationAction { - action: NavigationAction.Action.Back - - onClicked: pop() - } - - Rectangle { - anchors.fill: parent - color: Constants.white - z: -1 - } - TutorialStatusBar { - id: statusBar - } - TutorialReaderMethodFooter { - id: footer - width: baseItem.width - - onMenuClicked: pop() - onQuitTutorialClicked: { - pop(); - baseItem.quitTutorialClicked(); - } - } -} diff --git a/resources/qml/Governikus/TutorialView/+mobile/TutorialReaderMethodSacMobile.qml b/resources/qml/Governikus/TutorialView/+mobile/TutorialReaderMethodSacMobile.qml deleted file mode 100644 index 2b7c1a517..000000000 --- a/resources/qml/Governikus/TutorialView/+mobile/TutorialReaderMethodSacMobile.qml +++ /dev/null @@ -1,842 +0,0 @@ -/** - * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 -import Governikus.Type.SettingsModel 1.0 - -SectionPage { - id: baseItem - signal quitTutorialClicked - - automaticSafeAreaMarginHandling: false - //: LABEL ANDROID IOS - title: qsTr("Tutorial: Smartphone as card reader") - titleBarVisible: false - - content: Item { - height: content.contentHeight - width: baseItem.width - - TutorialContent { - id: content - anchors.horizontalCenter: parent.horizontalCenter - height: content.contentHeight - visible: true - width: Constants.is_tablet ? baseItem.width * 0.5 : baseItem.width - - GSpacer { - height: statusBar.height - width: parent.width - } - Column { - spacing: Constants.component_spacing - width: parent.width - - Rectangle { - anchors.horizontalCenter: parent.horizontalCenter - border.color: Style.color.tutorial_how - border.width: 3 - height: radius * 2 - radius: numberTwo.height - width: radius * 2 - - GText { - id: numberThree - anchors.centerIn: parent - horizontalAlignment: Text.AlignHCenter - text: "3" - textStyle: Style.text.tutorial_header_secondary_highlight - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - Item { - height: sacMobileImage.height - width: parent.width - - Rectangle { - anchors.horizontalCenter: parent.horizontalCenter - border.color: Style.color.tutorial_how - border.width: 3 - height: radius * 2 - radius: parent.width * 0.06 - width: radius * 2 - x: (parent.width * 0.5) - (width / 2) - y: (parent.height * 0.4) - (height / 2) - - TutorialImage { - centerX: 0.5 - centerY: 0.5 - source: "qrc:///images/tutorial/wifi.svg" - width: parent.width * 0.8 - } - } - TutorialImage { - id: sacMobileImage - centerX: 0.5 - centerY: 0.5 - source: "qrc:///images/tutorial/how_method_sac_mobile.svg" - width: parent.width - } - GText { - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("App on tablet or smartphone without NFC chip") - textStyle: Style.text.tutorial_content - width: parent.width * 0.4 - x: (parent.width * 0.25) - (width / 2) - y: (parent.height * 0.95) - (height / 2) - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - GText { - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("Smartphone with NFC chip as card reader") - textStyle: Style.text.tutorial_content - width: parent.width * 0.4 - x: (parent.width * 0.75) - (width / 2) - y: (parent.height * 0.95) - (height / 2) - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - } - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - rotation: 90 - source: "qrc:///images/tutorial/arrow_blue.svg" - width: parent.width * 0.2 - } - Column { - spacing: Constants.component_spacing - width: parent.width - - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("Install AusweisApp2 on both your device without NFC and your smartphone with NFC capability.") - textStyle: Style.text.tutorial_header - width: parent.width * 0.9 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/reader_sac_aa2_ok.svg" - width: parent.width * 0.8 - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - } - Column { - spacing: Constants.component_spacing - width: parent.width - - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/hint.svg" - width: parent.width * 0.3 - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("Both devices have to be connected to the same WiFi network") - textStyle: Style.text.tutorial_header_highlight - width: parent.width * 0.9 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/wifi.svg" - width: parent.width * 0.3 - } - } - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - rotation: 90 - source: "qrc:///images/tutorial/arrow_blue.svg" - width: parent.width * 0.2 - } - Column { - spacing: Constants.component_spacing - width: parent.width - - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("Now choose \"Card reader\" in the AusweisApp2 on your smartphone...") - textStyle: Style.text.tutorial_header - width: parent.width * 0.9 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/reader_sac_menu_%1_%2.svg".arg(Constants.layout).arg(SettingsModel.language) - width: parent.width * 0.9 - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - } - Column { - spacing: Constants.component_spacing - width: parent.width - - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignRight - - //: LABEL ANDROID IOS - text: qsTr("Now") - textStyle: Style.text.tutorial_header - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - GButton { - id: pairingButton - anchors.horizontalCenter: parent.horizontalCenter - animationsDisabled: true - - //: LABEL ANDROID IOS - text: qsTr("Pair device") - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - rotation: 180 - source: "qrc:///images/tutorial/up_icon.svg" - width: parent.width * 0.1 - } - Item { - anchors.horizontalCenter: parent.horizontalCenter - height: greyBackgroundRect.height - width: pairingCodeText.width - - Rectangle { - id: greyBackgroundRect - anchors.horizontalCenter: parent.horizontalCenter - color: Style.color.tutorial_box_background - height: width - width: pairingCodeText.width - 40 - } - GText { - id: pairingCodeText - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: greyBackgroundRect.top - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("Pairing code") - textStyle: Style.text.tutorial_header_highlight - topPadding: 30 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - GText { - id: appearingText - anchors.bottom: greyBackgroundRect.bottom - anchors.horizontalCenter: parent.horizontalCenter - bottomPadding: 30 - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("appears!") - textStyle: Style.text.tutorial_header - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - visible: Constants.is_layout_ios - } - Item { - height: Math.max(noticeImage5.height, noticeText5.height) - visible: Constants.is_layout_ios - width: parent.width - - TutorialImage { - id: noticeImage5 - centerX: 0.2 - centerY: 0.5 - source: "qrc:///images/tutorial/hint.svg" - width: parent.width * 0.2 - } - GText { - id: noticeText5 - horizontalAlignment: Text.AlignLeft - - //: LABEL IOS - text: qsTr("On the first use of the Smartphone as card reader (SaC), iOS will asks for your permission to access the local network. This permission is required in order find and connect to your SaC. After the first request you can always access the permission in the iOS settings for this app.") - textStyle: Style.text.tutorial_content_highlight - width: parent.width * 0.6 - x: (parent.width * 0.65) - (width / 2) - y: (parent.height * 0.5) - (height / 2) - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - rotation: 90 - source: "qrc:///images/tutorial/arrow_blue.svg" - width: parent.width * 0.2 - } - Column { - spacing: Constants.component_spacing - width: parent.width - - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/reader_sac_no_nfc_devices.svg" - width: parent.width * 0.5 - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - text: (Constants.is_layout_ios ? - //: LABEL IOS - qsTr("Now open the AusweisApp2 on your device without NFC and select Manage pairings.") : - //: LABEL ANDROID - qsTr("Now open the AusweisApp2 on your device without NFC and select Smartphone as card reader.")) - textStyle: Style.text.tutorial_header - width: parent.width * 0.9 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("Now select Settings.") - textStyle: Style.text.tutorial_header - width: parent.width * 0.9 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - } - Column { - spacing: Constants.component_spacing - width: parent.width - - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/phone_list.svg" - width: parent.width * 0.5 - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("Choose smartphone from list") - textStyle: Style.text.tutorial_header - width: parent.width * 0.7 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - Item { - height: noticeImage4.height - width: parent.width - - TutorialImage { - id: noticeImage4 - centerX: 0.2 - centerY: 0.5 - source: "qrc:///images/tutorial/hint.svg" - width: parent.width * 0.2 - } - GText { - horizontalAlignment: Text.AlignLeft - - //: LABEL ANDROID IOS - text: qsTr("Enter pairing code next.") - textStyle: Style.text.tutorial_content_highlight - width: parent.width * 0.6 - x: (parent.width * 0.65) - (width / 2) - y: (parent.height * 0.5) - (height / 2) - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - } - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - rotation: 90 - source: "qrc:///images/tutorial/arrow_blue.svg" - width: parent.width * 0.2 - } - Column { - width: parent.width - - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/reader_sac_no_nfc_provider.svg" - width: parent.width * 0.5 - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("Click link on the website of the provider on the device without NFC.") - textStyle: Style.text.tutorial_header_secondary - width: parent.width * 0.6 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - } - Item { - height: userdataExample.height + textAccessWhoWhat.height + textOpenAutomatic.height + 2 * Constants.component_spacing - width: parent.width - - TutorialImage { - centerX: 0.2 - centerY: (textAccessWhoWhat.y + textAccessWhoWhat.height) / (2 * parent.height) - source: "qrc:///images/tutorial/tablet-no-nfc.svg" - width: parent.width * 0.15 - } - GText { - id: textOpenAutomatic - horizontalAlignment: Text.AlignHCenter - rightPadding: Constants.component_spacing - - //: LABEL ANDROID IOS - text: qsTr("The App opens automatically.") - textStyle: Style.text.tutorial_content - width: parent.width * 0.6 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - - anchors { - right: parent.right - top: parent.top - } - } - GText { - id: textAccessWhoWhat - horizontalAlignment: Text.AlignHCenter - rightPadding: Constants.component_spacing - - //: LABEL ANDROID IOS - text: qsTr("The AusweisApp2 will display who wants to access which data.") - textStyle: Style.text.tutorial_header_secondary - width: parent.width * 0.6 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - - anchors { - right: parent.right - top: textOpenAutomatic.bottom - topMargin: Constants.component_spacing - } - } - TutorialImage { - id: userdataExample - source: "qrc:///images/tutorial/reader_nfc_userdata_example_%1.svg".arg(SettingsModel.language) - width: parent.width * 0.8 - - anchors { - horizontalCenter: parent.horizontalCenter - top: textAccessWhoWhat.bottom - topMargin: Constants.component_spacing - } - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - } - Column { - spacing: Constants.component_spacing - width: parent.width - - GText { - id: startProcessText - anchors.horizontalCenter: parent.horizontalCenter - //: LABEL ANDROID IOS - text: qsTr("Start the process with a click on:") - textStyle: Style.text.tutorial_header_secondary - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - Row { - anchors.horizontalCenter: parent.horizontalCenter - height: authArrow.height - spacing: Constants.component_spacing - - Image { - id: authArrow - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/arrow_blue.svg" - width: parent.width * 0.2 - } - GButton { - animationsDisabled: true - icon.source: "qrc:///images/identify.svg" - - //: LABEL ANDROID IOS - text: qsTr("Proceed to PIN entry") - tintIcon: true - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - } - Column { - spacing: Constants.component_spacing - width: parent.width - - Item { - height: screenshotAuth.height - width: parent.width - - TutorialImage { - id: screenshotAuth - centerX: 0.5 - centerY: 0.4 - source: "qrc:///images/tutorial/screenshot_choose_reader_%1_%2.png".arg(Constants.layout).arg(SettingsModel.language) - width: parent.width * 0.5 - } - TutorialImage { - id: pointerImage - centerX: 0.52 - centerY: 0.89 - source: "qrc:///images/tutorial/hand.svg" - width: parent.width * 0.1 - } - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("Tap on WiFi") - textStyle: Style.text.tutorial_header - width: parent.width * 0.9 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - } - Column { - spacing: Constants.component_spacing - width: parent.width - - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/where_lay_down_id.svg" - width: parent.width * 0.8 - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("... and place the ID card onto the NFC interface.") - textStyle: Style.text.tutorial_header_secondary - width: parent.width * 0.9 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - Item { - height: noticeImage.height - width: parent.width - - TutorialImage { - id: noticeImage - centerX: 0.2 - centerY: 0.5 - source: "qrc:///images/tutorial/hint.svg" - width: parent.width * 0.2 - } - GText { - horizontalAlignment: Text.AlignLeft - - //: LABEL ANDROID IOS - text: qsTr("Do not move device or ID card!") - textStyle: Style.text.tutorial_content_highlight - width: parent.width * 0.6 - x: (parent.width * 0.65) - (width / 2) - y: (parent.height * 0.5) - (height / 2) - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - } - Item { - height: Math.max(nfcPosition.height, nfcText.height) - width: parent.width * 0.9 - - TutorialImage { - id: nfcPosition - source: "qrc:///images/tutorial/reader_nfc_smartphone_nfc_position.svg" - width: parent.width * 0.75 - - anchors { - left: parent.left - verticalCenter: parent.verticalCenter - } - } - GText { - id: nfcText - horizontalAlignment: Text.AlignLeft - - //: LABEL ANDROID IOS - text: qsTr("The correct position is specific for your device. If a position does not work try a different one. The AusweisApp2 shows different common positions.") - textStyle: Style.text.tutorial_content_highlight - width: parent.width * 0.55 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - - anchors { - right: parent.right - verticalCenter: parent.verticalCenter - } - } - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("If your device is unable to detect your ID card try to check the device capabilities by clicking on \"Check device and ID card\" on the start page.") - textStyle: Style.text.tutorial_content_highlight - width: parent.width * 0.9 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("You can find more information on compatible devices on our %1mobile device list%2.").arg("".arg(SettingsModel.language)).arg("") - textStyle: Style.text.tutorial_header_secondary - visible: Constants.is_layout_android - width: parent.width * 0.9 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - } - Column { - spacing: Constants.component_spacing - width: parent.width - - Item { - height: pin6Image.height + Constants.component_spacing * 2 - width: parent.width - - GText { - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS This is the first of three lines "Enter" "six-digit PIN" "now!" and should be translated according to the third line. - text: qsTr("Enter") - textStyle: Style.text.tutorial_header - width: parent.width * 0.8 - x: (parent.width * 0.5) - (width / 2) - y: (parent.height * 0.05) - (height / 2) - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - TutorialImage { - id: pin6Image - centerX: 0.5 - centerY: 0.5 - source: "qrc:///images/tutorial/reader_nfc_pin6.svg" - width: parent.width * 0.8 - z: 1 - } - GText { - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("six-digit PIN") - textStyle: Style.text.tutorial_header_highlight - width: parent.width - x: (parent.width * 0.5) - (width / 2) - y: (parent.height * 0.2) - (height / 2) - z: 2 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS This is the third of three lines "Enter" "six-digit PIN" "now!" and should be translated according to the first line. - text: qsTr("now!") - textStyle: Style.text.tutorial_header - width: parent.width * 0.8 - x: (parent.width * 0.5) - (width / 2) - y: (parent.height * 0.9) - (height / 2) - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - Item { - height: Math.max(noticeImage2.height, noticeText2.height) - width: parent.width - - TutorialImage { - id: noticeImage2 - centerX: 0.2 - centerY: 0.5 - source: "qrc:///images/tutorial/hint.svg" - width: parent.width * 0.2 - } - GText { - id: noticeText2 - horizontalAlignment: Text.AlignLeft - - //: LABEL ANDROID IOS - text: qsTr("This is only possible if you have exchanged the five-digit Transport PIN with a six-digit PIN beforehand.") - textStyle: Style.text.tutorial_content_highlight - width: parent.width * 0.6 - x: (parent.width * 0.65) - (width / 2) - y: (parent.height * 0.5) - (height / 2) - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_how.svg" - } - MouseArea { - height: finishedButton.height - width: parent.width - - onClicked: pop() - - Image { - id: finishedButton - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/reader_nfc_finished.svg" - width: parent.width * 0.8 - } - } - GSpacer { - height: footer.height - width: parent.width - } - } - } - navigationAction: NavigationAction { - action: NavigationAction.Action.Back - - onClicked: pop() - } - - Rectangle { - anchors.fill: parent - color: Constants.white - z: -1 - } - TutorialStatusBar { - id: statusBar - } - TutorialReaderMethodFooter { - id: footer - width: baseItem.width - - onMenuClicked: pop() - onQuitTutorialClicked: { - pop(); - baseItem.quitTutorialClicked(); - } - } -} diff --git a/resources/qml/Governikus/TutorialView/+mobile/TutorialSeperator.qml b/resources/qml/Governikus/TutorialView/+mobile/TutorialSeperator.qml deleted file mode 100644 index fb845a5f2..000000000 --- a/resources/qml/Governikus/TutorialView/+mobile/TutorialSeperator.qml +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Global 1.0 - -Column { - property alias source: image.source - - width: parent.width - - TutorialImage { - id: image - centerX: 0.5 - centerY: 0.5 - width: parent.width * 0.03 - } -} diff --git a/resources/qml/Governikus/TutorialView/+mobile/TutorialShowMenuPath.qml b/resources/qml/Governikus/TutorialView/+mobile/TutorialShowMenuPath.qml deleted file mode 100644 index 69aba71c6..000000000 --- a/resources/qml/Governikus/TutorialView/+mobile/TutorialShowMenuPath.qml +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Type.SettingsModel 1.0 - -Item { - id: root - - property alias backgroundIcon: icon.source - property alias newSectionImage: newSection.source - property double newSectionPointerX: 1 - property double newSectionPointerY: 0 - - height: width * 0.6 - - Image { - id: icon - height: 0.85 * parent.height - width: 0.54 * parent.width - x: 0.2167 * parent.width - y: 0 - z: -1 - } - TutorialZoomTriangle { - height: startMenu.height - opacity: 0.3 - width: 0.083 * parent.width - x: startMenu.x + startMenu.width - y: startMenu.y - z: 1 - } - TutorialImage { - id: startMenu - centerX: 0.483 + 0.1525 - centerY: 0.15 + 0.4 - source: "qrc:///images/tutorial/screenshot_start_%1_%2.png".arg(Constants.layout).arg(SettingsModel.language) - width: root.width * 0.3 - } - TutorialZoomTriangle { - height: newSection.height - opacity: 0.3 - pointerXRatio: root.newSectionPointerX - pointerYRatio: root.newSectionPointerY - width: 0.083 * parent.width - x: newSection.x + newSection.width - y: newSection.y - z: 1 - } - TutorialImage { - id: newSection - centerX: 0.125 + 0.1525 - centerY: 0.075 + 0.4 - width: root.width * 0.3 - } - TutorialImage { - centerX: 0.808 + 0.0667 - centerY: 0.4 + 0.155 - source: "qrc:///images/tutorial/phone.svg" - width: root.width / 7.5 - } -} diff --git a/resources/qml/Governikus/TutorialView/+mobile/TutorialSpacer.qml b/resources/qml/Governikus/TutorialView/+mobile/TutorialSpacer.qml deleted file mode 100644 index 7e9502025..000000000 --- a/resources/qml/Governikus/TutorialView/+mobile/TutorialSpacer.qml +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 - -Rectangle { - id: baseItem - - property alias text: textContent.text - - height: textContent.height + 2 * Constants.component_spacing - - GText { - id: textContent - anchors.centerIn: parent - color: Constants.white - horizontalAlignment: Text.AlignHCenter - textStyle: Style.text.tutorial_header - width: parent.width * 0.8 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } -} diff --git a/resources/qml/Governikus/TutorialView/+mobile/TutorialStatusBar.qml b/resources/qml/Governikus/TutorialView/+mobile/TutorialStatusBar.qml deleted file mode 100644 index 78d1c9adf..000000000 --- a/resources/qml/Governikus/TutorialView/+mobile/TutorialStatusBar.qml +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Global 1.0 - -Rectangle { - anchors.top: parent.top - color: footer.color - height: plugin.safeAreaMargins.top - width: parent.width - - Behavior on color { - ColorAnimation { - duration: Constants.animation_duration - } - } -} diff --git a/resources/qml/Governikus/TutorialView/+mobile/TutorialView.qml b/resources/qml/Governikus/TutorialView/+mobile/TutorialView.qml deleted file mode 100644 index ed419555b..000000000 --- a/resources/qml/Governikus/TutorialView/+mobile/TutorialView.qml +++ /dev/null @@ -1,466 +0,0 @@ -/** - * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import QtQml.Models 2.15 -import QtQml 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 -import Governikus.Type.SettingsModel 1.0 -import Governikus.Type.UiModule 1.0 - -SectionPage { - id: root - - property int contentWidth: Math.min(Style.dimens.max_text_width, root.width) - property var lastVisibleItem - property int lastYPosition: 0 - - signal leave - - function leaveView() { - flickable.contentY = 0; - state = ""; - collapseAllAnimation.start(); - root.leave(); - } - - automaticSafeAreaMarginHandling: false - //: LABEL ANDROID IOS - title: qsTr("Tutorial") - titleBarVisible: false - - navigationAction: NavigationAction { - onClicked: root.state !== "" ? root.state = "" // collapse sections - : leaveView() - } - states: [ - State { - name: "what" - }, - State { - name: "where" - }, - State { - name: "how" - }, - State { - name: "important" - } - ] - transitions: [ - Transition { - to: "what" - - TutorialExpandAnimation { - targetContent: whatContent - targetHeader: whatHeader - } - TutorialCollapseAnimation { - targetContent: whereContent - } - TutorialCollapseAnimation { - targetContent: howContent - } - TutorialCollapseAnimation { - targetContent: importantContent - } - }, - Transition { - to: "where" - - TutorialExpandAnimation { - targetContent: whereContent - targetHeader: whereHeader - } - TutorialCollapseAnimation { - targetContent: whatContent - } - TutorialCollapseAnimation { - targetContent: howContent - } - TutorialCollapseAnimation { - targetContent: importantContent - } - }, - Transition { - to: "how" - - TutorialExpandAnimation { - targetContent: howContent - targetHeader: howHeader - } - TutorialCollapseAnimation { - targetContent: whatContent - } - TutorialCollapseAnimation { - targetContent: whereContent - } - TutorialCollapseAnimation { - targetContent: importantContent - } - }, - Transition { - to: "important" - - TutorialExpandAnimation { - targetContent: importantContent - targetHeader: importantHeader - } - TutorialCollapseAnimation { - targetContent: whatContent - } - TutorialCollapseAnimation { - targetContent: whereContent - } - TutorialCollapseAnimation { - targetContent: howContent - } - }, - Transition { - to: "" - - NumberAnimation { - duration: 500 - easing.type: Easing.InOutQuad - property: "contentY" - target: flickable - to: 0 - } - TutorialCollapseAnimation { - targetContent: whatContent - } - TutorialCollapseAnimation { - targetContent: whereContent - } - TutorialCollapseAnimation { - targetContent: howContent - } - TutorialCollapseAnimation { - targetContent: importantContent - } - } - ] - - Component.onCompleted: { - if (visible) { - setLockedAndHidden(); - } - } - onVisibleChanged: { - if (visible) { - flickable.contentY = lastYPosition; - setLockedAndHidden(); - } else { - lastYPosition = flickable.contentY; - } - } - - SequentialAnimation { - id: collapseAllAnimation - NumberAnimation { - duration: 500 - easing.type: Easing.InOutQuad - property: "contentY" - target: flickable - to: 0 - } - PropertyAction { - property: "visible" - target: whatContent - value: false - } - PropertyAction { - property: "visible" - target: whereContent - value: false - } - PropertyAction { - property: "visible" - target: howContent - value: false - } - PropertyAction { - property: "visible" - target: importantContent - value: false - } - } - Rectangle { - anchors.fill: parent - color: Constants.white - } - GFlickable { - id: flickable - contentHeight: flickableContent.height - contentWidth: flickableContent.width - height: parent.height - scrollBarBottomPadding: footer.height - scrollBarTopPadding: plugin.safeAreaMargins.top - topMargin: statusBar.height - width: root.width - - Item { - width: root.width - - Column { - id: flickableContent - anchors.horizontalCenter: parent.horizontalCenter - width: root.width - - TutorialHeader { - id: whatHeader - categoryAbove: false - headerImageSource: "qrc:///images/tutorial/main_menu_what_caret.svg" - height: ((flickable.height - flickable.topMargin - footer.height) / 13.0) * 3.0 - initY: 0 - miniIconCoordinates: [{ - "x": 0.0625, - "y": 0.5 - }, { - "x": 0.1875, - "y": 0.15625 - }, { - "x": 0.2, - "y": 0.59375 - }, { - "x": 0.390625, - "y": 0.78125 - }, { - "x": 0.65625, - "y": 0.15625 - }, { - "x": 0.703125, - "y": 0.65625 - }, { - "x": 0.890625, - "y": 0.625 - }, { - "x": 0.90625, - "y": 0.3125 - }] - miniIconSource: "qrc:///images/tutorial/icon_circle.svg" - //: LABEL ANDROID IOS - titleText: qsTr("What?") - width: root.width - z: 40 - - Accessible.onScrollDownAction: flickable.scrollPageDown() - Accessible.onScrollUpAction: flickable.scrollPageUp() - onClicked: { - if (!whatContent.visible) { - root.state = "what"; - } else { - root.state = ""; - } - } - } - TutorialWhat { - id: whatContent - anchors.horizontalCenter: parent.horizontalCenter - width: root.contentWidth - - Accessible.onScrollDownAction: flickable.scrollPageDown() - Accessible.onScrollUpAction: flickable.scrollPageUp() - } - TutorialHeader { - id: whereHeader - headerImageSource: "qrc:///images/tutorial/main_menu_where_caret.svg" - height: ((flickable.height - flickable.topMargin - footer.height) / 13.0) * 3.0 - initY: whatHeader.height - miniIconCoordinates: [{ - "x": 0.046875, - "y": 0.34375 - }, { - "x": 0.1875, - "y": 0.09375 - }, { - "x": 0.21875, - "y": 0.65625 - }, { - "x": 0.4, - "y": 0.62 - }, { - "x": 0.55, - "y": 0.36 - }, { - "x": 0.65, - "y": 0.28125 - }, { - "x": 0.75, - "y": 0.5625 - }, { - "x": 0.890625, - "y": 0.5 - }] - miniIconSource: "qrc:///images/tutorial/icon_star.svg" - //: LABEL ANDROID IOS - titleText: qsTr("Where?") - width: root.width - z: 30 - - Accessible.onScrollDownAction: flickable.scrollPageDown() - Accessible.onScrollUpAction: flickable.scrollPageUp() - onClicked: { - if (!whereContent.visible) { - root.state = "where"; - } else { - root.state = ""; - } - } - } - TutorialWhere { - id: whereContent - anchors.horizontalCenter: parent.horizontalCenter - width: root.contentWidth - - Accessible.onScrollDownAction: flickable.scrollPageDown() - Accessible.onScrollUpAction: flickable.scrollPageUp() - } - TutorialHeader { - id: howHeader - headerImageSource: "qrc:///images/tutorial/main_menu_how_caret.svg" - height: ((flickable.height - flickable.topMargin - footer.height) / 13.0) * 3.0 - initY: whatHeader.height + whereHeader.height - miniIconCoordinates: [{ - "x": 0.03125, - "y": 0.125 - }, { - "x": 0.078125, - "y": 0.46875 - }, { - "x": 0.203125, - "y": 0.4375 - }, { - "x": 0.32, - "y": 0.68 - }, { - "x": 0.64, - "y": 0.21875 - }, { - "x": 0.78125, - "y": 0.5625 - }, { - "x": 0.875, - "y": 0.0625 - }, { - "x": 0.9, - "y": 0.6 - }] - miniIconSource: "qrc:///images/tutorial/icon_box.svg" - //: LABEL ANDROID IOS - titleText: qsTr("How?") - width: root.width - z: 20 - - Accessible.onScrollDownAction: flickable.scrollPageDown() - Accessible.onScrollUpAction: flickable.scrollPageUp() - onClicked: { - if (!howContent.visible) { - root.state = "how"; - } else { - root.state = ""; - } - } - } - TutorialHow { - id: howContent - anchors.horizontalCenter: parent.horizontalCenter - width: root.contentWidth - - Accessible.onScrollDownAction: flickable.scrollPageDown() - Accessible.onScrollUpAction: flickable.scrollPageUp() - onFirePush: pSectionPage => push(pSectionPage) - onQuitTutorialClicked: leaveView() - } - TutorialHeader { - id: importantHeader - headerImageSource: "qrc:///images/tutorial/main_menu_important_caret.svg" - height: ((flickable.height - flickable.topMargin - footer.height) / 13.0) * 4.0 - initY: whatHeader.height + whereHeader.height + howHeader.height - miniIconCoordinates: [{ - "x": 0.046875, - "y": 0.46875 - }, { - "x": 0.14, - "y": 0.22 - }, { - "x": 0.25, - "y": 0.71875 - }, { - "x": 0.62, - "y": 0.7 - }, { - "x": 0.67, - "y": 0.24 - }, { - "x": 0.78125, - "y": 0.4375 - }, { - "x": 0.796875, - "y": 0.65625 - }, { - "x": 0.9375, - "y": 0.1875 - }] - miniIconSource: "qrc:///images/tutorial/icon_diamond.svg" - overlapping: false - //: LABEL ANDROID IOS - titleText: qsTr("Important!") - width: root.width - z: 10 - - Accessible.onScrollDownAction: flickable.scrollPageDown() - Accessible.onScrollUpAction: flickable.scrollPageUp() - onClicked: { - if (!importantContent.visible) { - root.state = "important"; - } else { - root.state = ""; - } - } - } - TutorialImportant { - id: importantContent - anchors.horizontalCenter: parent.horizontalCenter - width: root.contentWidth - - Accessible.onScrollDownAction: flickable.scrollPageDown() - Accessible.onScrollUpAction: flickable.scrollPageUp() - onLetsGoClicked: leaveView() - onShowPinManagement: { - SettingsModel.transportPinReminder = false; - root.show(UiModule.PINMANAGEMENT); - } - } - - // We could use a bottom margin instead of this rectangle, but that would result in the content suddenly - // disappearing below the TutorialFooter at the end of the collapse animation (because the section's - // content is NOT clipped between its two surrounding TutorialHeaders). - Rectangle { - color: Constants.white - height: footer.height - width: root.width - } - } - } - } - TutorialStatusBar { - id: statusBar - } - TutorialFooter { - id: footer - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - backToMenuActive: root.state !== "" - color: importantContent.visible && flickable.contentY > importantHeader.y - 1 ? Style.color.tutorial_important : howContent.visible && flickable.contentY > howHeader.y - 1 ? Style.color.tutorial_how : whereContent.visible && flickable.contentY > whereHeader.y - 1 ? Style.color.tutorial_where : Style.color.tutorial_what - width: root.width - - onMenuClicked: root.state = "" - onQuitTutorialClicked: leaveView() - } -} diff --git a/resources/qml/Governikus/TutorialView/+mobile/TutorialWhat.qml b/resources/qml/Governikus/TutorialView/+mobile/TutorialWhat.qml deleted file mode 100644 index 153a37488..000000000 --- a/resources/qml/Governikus/TutorialView/+mobile/TutorialWhat.qml +++ /dev/null @@ -1,460 +0,0 @@ -/** - * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.SettingsModel 1.0 - -TutorialContent { - id: baseItem - Column { - anchors.horizontalCenter: parent.horizontalCenter - width: parent.width * 0.9 - - GText { - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("What is the online ID function?") - textStyle: Style.text.tutorial_header_accent - width: parent.width - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - GText { - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("You can use it to authenticate yourself in the internet") - textStyle: Style.text.tutorial_header - width: parent.width - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_what.svg" - } - Column { - spacing: Constants.component_spacing - width: parent.width - - Item { - height: parent.width * 0.6 - width: parent.width - - Rectangle { - id: circle - color: Style.color.tutorial_box_background - height: width - radius: width * 0.5 - width: parent.width * 0.6 - x: (parent.width * 0.5) - (width / 2) - } - TutorialImage { - id: stylisedEpa - centerX: 0.8 - centerY: 0.5 - rotation: 12 - source: "qrc:///images/ausweis.svg" - width: parent.height * 0.4 - z: 2 - } - TutorialImage { - id: smartPhone - centerX: 0.2 - centerY: 0.5 - source: "qrc:///images/tutorial/phone.svg" - width: parent.height * 0.4 - z: 3 - } - TutorialImage { - id: shield - centerX: 0.5 - centerY: 0.5 - source: "qrc:///images/tutorial/save.svg" - width: parent.height * 0.3 - z: 4 - } - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("and also to deal with administrative paperwork and business matters electronically!") - textStyle: Style.text.tutorial_content - width: parent.width * 0.9 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - TutorialSpacer { - color: Style.color.tutorial_what - - //: LABEL ANDROID IOS - text: qsTr("Alright, but is it secure?") - width: parent.width - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - Column { - anchors.horizontalCenter: parent.horizontalCenter - width: parent.width * 0.9 - - GText { - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("Of course, because we use a so called") - textStyle: Style.text.tutorial_content - width: parent.width - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - GText { - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("Mutual authentication") - textStyle: Style.text.tutorial_header_highlight - width: parent.width - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_what.svg" - } - Column { - spacing: Constants.component_spacing - width: parent.width - - Item { - height: parent.width * 0.6 - width: parent.width - - TutorialImage { - centerX: 0.25 - centerY: 0.5 - source: "qrc:///images/tutorial/user-tine@3x.png" - width: parent.height * 0.3 - z: 2 - } - TutorialImage { - centerX: 0.2 - centerY: 0.65 - source: "qrc:///images/npa.svg" - width: parent.height * 0.15 - z: 3 - } - TutorialImage { - centerX: 0.45 - centerY: 0.75 - source: "qrc:///images/tutorial/circle-lock.svg" - width: parent.height * 0.7 - z: 1 - } - TutorialImage { - centerX: 0.55 - centerY: 0.2 - source: "qrc:///images/tutorial/circle-lock-2.svg" - width: parent.height * 0.7 - z: 1 - } - TutorialImage { - centerX: 0.7 - centerY: 0.5 - source: "qrc:///images/tutorial/providericons.png" - width: parent.height * 0.8 - z: 2 - } - TutorialImage { - centerX: 0.7 - centerY: 0.48 - source: "qrc:///images/tutorial/provider_home.svg" - width: parent.height * 0.18 - z: 3 - } - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("... it establishes a secure connection between ID card and provider.") - textStyle: Style.text.tutorial_header_secondary - width: parent.width * 0.9 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_what.svg" - } - Column { - spacing: Constants.component_spacing * 2 - width: parent.width - - Item { - height: parent.width * 0.6 - width: parent.width - - GText { - horizontalAlignment: Text.AlignLeft - - //: LABEL ANDROID IOS - text: qsTr("On every authentication you get displayed who wants to access which data") - textStyle: Style.text.tutorial_content - width: parent.width * 0.35 - x: (parent.width * 0.2) - (width / 2) - y: (parent.height * 0.5) - (height / 2) - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - TutorialImage { - id: screenshot - - readonly property real rightX: x + width - - centerX: 0.6 - centerY: 0.5 - source: "qrc:///images/tutorial/screenshot_cert_%1_%2.png".arg(Constants.layout).arg(SettingsModel.language) - width: parent.height * 0.6 - z: 3 - } - TutorialZoomTriangle { - height: screenshot.height - opacity: 0.3 - width: small_smartphone.centerXValue - screenshot.rightX - x: screenshot.rightX - y: (parent.height * 0.5) - (height / 2) - z: 4 - } - TutorialImage { - id: small_smartphone - - readonly property real centerXValue: x + (width / 2) - - centerX: 0.9 - centerY: 0.5 - source: "qrc:///images/tutorial/phone.svg" - width: parent.height * 0.2 - z: 1 - } - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - //: LABEL ANDROID IOS - text: qsTr("and you consent to the request with your six-digit PIN.") - textStyle: Style.text.tutorial_content - width: parent.width * 0.95 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - Item { - height: parent.width * 0.3 - width: parent.width - z: 5 - - TutorialImage { - centerX: 0.6 - centerY: 0.5 - source: "qrc:///images/tutorial/pin-6@2x.png" - width: parent.height - } - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_what.svg" - } - Column { - spacing: Constants.component_spacing - width: parent.width - - Item { - height: width * 0.6 - width: parent.width - - Rectangle { - color: Style.color.tutorial_box_background - height: width - radius: width * 0.5 - width: parent.width * 0.6 - x: (parent.width * 0.5) - (width / 2) - z: 1 - } - GText { - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("... is the provider authorized for this?") - textStyle: Style.text.tutorial_header_highlight - width: parent.width - 2 * Constants.component_spacing - x: (parent.width * 0.5) - (width / 2) - y: (parent.height * 0.3) - (height / 2) - z: 2 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - GText { - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("The provider needs an authorization of the Federal Office of Administration.") - textStyle: Style.text.tutorial_content - width: parent.width - 2 * Constants.component_spacing - x: (parent.width * 0.5) - (width / 2) - y: (parent.height * 0.5) - z: 2 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - Item { - height: parent.width * 0.3 - width: parent.width - - GText { - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("Certificate") - textStyle: Style.text.tutorial_header_highlight - width: parent.width - x: (parent.width * 0.2) - (width / 2) - y: (parent.height * 0.5) - (height / 2) - z: 1 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - TutorialImage { - centerX: 0.5 - centerY: 0.5 - source: "qrc:///images/tutorial/provider_home.svg" - width: parent.height * 0.7 - z: 1 - } - TutorialImage { - centerX: 0.8 - centerY: 0.5 - source: "qrc:///images/tutorial/bva.svg" - width: parent.height - z: 1 - } - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_what.svg" - } - Column { - spacing: Constants.component_spacing - width: parent.width - - Item { - height: parent.width * 0.3 - width: parent.width - - TutorialImage { - centerX: 0.15 - centerY: 0.4 - source: "qrc:///images/tutorial/user-tine@3x.png" - width: parent.height * 0.5 - z: 1 - } - TutorialImage { - centerX: 0.25 - centerY: 0.5 - source: "qrc:///images/tutorial/pin-6@2x.png" - width: parent.height - z: 2 - } - TutorialImage { - centerX: 0.7 - centerY: 0.25 - source: "qrc:///images/tutorial/provider_home.svg" - width: parent.height * 0.6 - z: 1 - } - TutorialImage { - centerX: 0.8 - centerY: 0.5 - source: "qrc:///images/tutorial/bva.svg" - width: parent.height * 0.8 - z: 2 - } - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - //: LABEL ANDROID IOS - text: qsTr("Every time both participants authenticate each other...") - textStyle: Style.text.tutorial_header_highlight - width: parent.width * 0.9 - z: 1 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - TutorialSpacer { - color: Style.color.tutorial_what - - //: LABEL ANDROID IOS - text: qsTr("... and therefore your data is protected and securely transferred.") - width: parent.width - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - Column { - spacing: Constants.component_spacing - width: parent.width - - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("You can also watch a video on YouTube on this topic") - textStyle: Style.text.tutorial_header_secondary - width: parent.width * 0.8 - z: 2 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/play_movie.png" - width: parent.width * 0.7 - - MouseArea { - - //: LABEL ANDROID IOS - Accessible.name: qsTr("Open YouTube video") - Accessible.role: Accessible.Button - anchors.fill: parent - - Accessible.onPressAction: clicked(null) - onClicked: Qt.openUrlExternally("https://www.ausweisapp.bund.de/%1/aa2/video-authentication-example".arg(SettingsModel.language)) - } - } - } -} diff --git a/resources/qml/Governikus/TutorialView/+mobile/TutorialWhere.qml b/resources/qml/Governikus/TutorialView/+mobile/TutorialWhere.qml deleted file mode 100644 index c94bf6810..000000000 --- a/resources/qml/Governikus/TutorialView/+mobile/TutorialWhere.qml +++ /dev/null @@ -1,262 +0,0 @@ -/** - * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.SettingsModel 1.0 - -TutorialContent { - id: baseItem - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("Where can I use the online ID function?") - textStyle: Style.text.tutorial_header_accent - width: parent.width * 0.9 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_where.svg" - } - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/where_overview_question.svg" - width: parent.width * 0.75 - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_where.svg" - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("On every website of a provider where you see this icon:") - textStyle: Style.text.tutorial_header_secondary - width: parent.width * 0.9 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/npa.svg" - width: parent.width * 0.2 - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("By the way, you can find many services directly in the AusweisApp2 provider list.") - textStyle: Style.text.tutorial_content - width: parent.width * 0.8 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_where.svg" - } - TutorialShowMenuPath { - backgroundIcon: "qrc:///images/tutorial/background_icon_where.svg" - newSectionImage: "qrc:///images/tutorial/screenshot_providerlist_%1_%2.png".arg(Constants.layout).arg(SettingsModel.language) - newSectionPointerY: Constants.is_layout_android ? 0.85 : 0.87 - width: parent.width - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_where.svg" - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("The integrated self-authentication is a special service to view the data saved on your ID card.") - textStyle: Style.text.tutorial_header - width: parent.width * 0.9 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_where.svg" - } - TutorialShowMenuPath { - backgroundIcon: "qrc:///images/tutorial/background_icon_where.svg" - newSectionImage: "qrc:///images/tutorial/screenshot_selfauthentication_%1_%2.png".arg(Constants.layout).arg(SettingsModel.language) - newSectionPointerY: Constants.is_layout_android ? 0.66 : 0.67 - width: parent.width - } - TutorialSpacer { - color: Style.color.tutorial_where - - //: LABEL ANDROID IOS - text: qsTr("And this is how it works") - width: parent.width - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("The AusweisApp2 will always display who wants to access which of your data.") - textStyle: Style.text.tutorial_header - width: parent.width * 0.9 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/where_userdata_example_%1.svg".arg(SettingsModel.language) - width: parent.width * 0.8 - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_where.svg" - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("To allow the shown service access to the requested data click \"Proceed to PIN entry\"") - textStyle: Style.text.tutorial_header_secondary - width: parent.width * 0.8 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/where_identify_now_%1.svg".arg(SettingsModel.language) - width: parent.width - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_where.svg" - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - text: (Constants.is_layout_ios ? - //: LABEL IOS - qsTr("Now lay down your ID card and hold the top of your iPhone to the ID card.") : - //: LABEL ANDROID - qsTr("Now place your ID card on the NFC-interface of your smartphone.") + " " + - //: LABEL ANDROID - qsTr("The correct position is specific for your device. If a position does not work try a different one. The AusweisApp2 shows different common positions. If your device is unable to detect your ID card try to check the device capabilities by clicking on \"Check device and ID card\" on the start page.")) - textStyle: Style.text.tutorial_header_secondary - width: parent.width * 0.9 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - Image { - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - height: width * (sourceSize.height / sourceSize.width) - source: "qrc:///images/tutorial/where_lay_down_id.svg" - width: parent.width * 0.7 - } - Item { - height: noticeImage.height - width: parent.width - - TutorialImage { - id: noticeImage - centerX: 0.2 - centerY: 0.5 - source: "qrc:///images/tutorial/hint.svg" - width: parent.width * 0.2 - } - GText { - horizontalAlignment: Text.AlignLeft - rightPadding: Constants.component_spacing - text: (Constants.is_layout_ios ? - //: LABEL IOS - qsTr("Do not move your iPhone during the procedure!") : - //: LABEL ANDROID - qsTr("Do not move your device during the procedure!")) - textStyle: Style.text.tutorial_content - width: parent.width * 0.5 - x: (parent.width * 0.75) - (width / 2) - y: (parent.height * 0.5) - (height / 2) - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } - TutorialSeperator { - source: "qrc:///images/tutorial/section_seperator_where.svg" - } - Item { - height: pin6Image.height + Constants.component_spacing * 2 - width: parent.width - - GText { - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS This is the first of three lines "Enter" "six-digit PIN" "now!" and should be translated according to the third line. - text: qsTr("Enter") - textStyle: Style.text.tutorial_header - width: parent.width * 0.8 - x: (parent.width * 0.5) - (width / 2) - y: (parent.height * 0.05) - (height / 2) - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - TutorialImage { - id: pin6Image - centerX: 0.5 - centerY: 0.5 - source: "qrc:///images/tutorial/where_pin6.svg" - width: parent.width * 0.8 - z: 1 - } - GText { - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("six-digit PIN") - textStyle: Style.text.tutorial_header_highlight - width: parent.width - x: (parent.width * 0.5) - (width / 2) - y: (parent.height * 0.2) - (height / 2) - z: 2 - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - GText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS This is the third of three lines "Enter" "six-digit PIN" "now!" and should be translated according to the first line. - text: qsTr("now!") - textStyle: Style.text.tutorial_header - width: parent.width * 0.8 - x: (parent.width * 0.5) - (width / 2) - y: (parent.height * 0.9) - (height / 2) - - Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() - Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() - } - } -} diff --git a/resources/qml/Governikus/TutorialView/+mobile/TutorialZoomTriangle.qml b/resources/qml/Governikus/TutorialView/+mobile/TutorialZoomTriangle.qml deleted file mode 100644 index 728484030..000000000 --- a/resources/qml/Governikus/TutorialView/+mobile/TutorialZoomTriangle.qml +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Shapes 1.15 -import Governikus.Global 1.0 - -Shape { - property double pointerXRatio: 1.0 - property double pointerYRatio: 0.5 - - ShapePath { - fillColor: Constants.black - startX: 0 - startY: 0 - - PathLine { - x: 0 - y: height - } - PathLine { - x: pointerXRatio * width - y: pointerYRatio * height - } - PathLine { - x: 0 - y: 0 - } - } -} diff --git a/resources/qml/Governikus/TutorialView/qmldir b/resources/qml/Governikus/TutorialView/qmldir deleted file mode 100644 index 1b3e18f4b..000000000 --- a/resources/qml/Governikus/TutorialView/qmldir +++ /dev/null @@ -1,26 +0,0 @@ -module TutorialView - -internal TransportPinAssistantView TransportPinAssistantView.qml -internal TutorialCollapseAnimation TutorialCollapseAnimation.qml -internal TutorialContent TutorialContent.qml -internal TutorialExpandAnimation TutorialExpandAnimation.qml -internal TutorialFooter TutorialFooter.qml -internal TutorialFooterButton TutorialFooterButton.qml -internal TutorialHeader TutorialHeader.qml -internal TutorialHow TutorialHow.qml -internal TutorialImage TutorialImage.qml -internal TutorialImportant TutorialImportant.qml -internal TutorialReaderMethodFooter TutorialReaderMethodFooter.qml -internal TutorialReaderMethodNfc TutorialReaderMethodNfc.qml -internal TutorialReaderMethodSacDesktop TutorialReaderMethodSacDesktop.qml -internal TutorialReaderMethodSacMobile TutorialReaderMethodSacMobile.qml -internal TutorialSeperator TutorialSeperator.qml -internal TutorialShowMenuPath TutorialShowMenuPath.qml -internal TutorialSpacer TutorialSpacer.qml -internal TutorialStatusBar TutorialStatusBar.qml -internal TutorialWhat TutorialWhat.qml -internal TutorialWhere TutorialWhere.qml -internal TutorialZoomTriangle TutorialZoomTriangle.qml - -SetupAssistantView 1.0 SetupAssistantView.qml -TutorialView 1.0 TutorialView.qml diff --git a/resources/qml/Governikus/UpdateView/+desktop/UpdateView.qml b/resources/qml/Governikus/UpdateView/+desktop/UpdateView.qml index 3f9340f02..15a2fd123 100644 --- a/resources/qml/Governikus/UpdateView/+desktop/UpdateView.qml +++ b/resources/qml/Governikus/UpdateView/+desktop/UpdateView.qml @@ -1,20 +1,20 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQml 2.15 -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.InformationView 1.0 -import Governikus.ResultView 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.GlobalStatus 1.0 -import Governikus.Type.ReleaseInformationModel 1.0 -import Governikus.Type.SettingsModel 1.0 -import Governikus.View 1.0 +import QtQml +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.InformationView +import Governikus.ResultView +import Governikus.Style +import Governikus.TitleBar +import Governikus.Type.ApplicationModel +import Governikus.Type.GlobalStatus +import Governikus.Type.ReleaseInformationModel +import Governikus.Type.SettingsModel +import Governikus.View SectionPage { id: root @@ -25,14 +25,13 @@ SectionPage { signal leaveView titleBarAction: TitleBarAction { - helpTopic: "applicationUpdate" //: LABEL DESKTOP text: qsTr("Application update") } ResultView { buttonType: NavigationButton.Type.Back - resultType: ResultView.Type.IsError + icon: root.update.missingPlatform ? "qrc:///images/status_error_%1.svg".arg(Style.currentTheme.name) : "qrc:///images/workflow_error_network_%1.svg".arg(Style.currentTheme.name) text: root.update.missingPlatform ? //: LABEL DESKTOP Resulttext if no update information is available for the current platform. qsTr("An update information for your platform is not available.") : @@ -44,7 +43,7 @@ SectionPage { } ResultView { buttonType: NavigationButton.Type.Back - resultType: ResultView.Type.IsSuccess + icon: "qrc:///images/status_ok_%1.svg".arg(Style.currentTheme.name) //: LABEL DESKTOP The currently installed version is the most recent one, no action is required. text: qsTr("Your version %1 of %2 is up to date!").arg(Qt.application.version).arg(Qt.application.name) visible: !SettingsModel.appUpdateAvailable && root.update.valid @@ -53,6 +52,7 @@ SectionPage { } GPane { id: pane + activeFocusOnTab: true title: qsTr("An update is available (installed version %1)").arg(Qt.application.version) visible: root.update.valid && root.update.updateAvailable @@ -61,65 +61,63 @@ SectionPage { fill: parent margins: Constants.pane_padding } - ColumnLayout { - height: pane.availableContentHeight - width: parent.width + UpdateViewInformation { + id: updateInformation - UpdateViewInformation { - id: updateInformation - Layout.fillWidth: true - downloadSize: root.update.size - releaseDate: root.update.date - version: root.update.version - } - GSeparator { - Layout.bottomMargin: Layout.topMargin - Layout.fillWidth: true - Layout.topMargin: Constants.text_spacing - } - Item { - Layout.fillHeight: true - Layout.fillWidth: true - clip: true - - ReleaseNotesView { - model: releaseInformationModel.updateRelease - - anchors { - bottomMargin: Constants.pane_padding - fill: parent - leftMargin: Constants.pane_padding - topMargin: Constants.pane_padding - } - ReleaseInformationModel { - id: releaseInformationModel - } + Layout.fillWidth: true + downloadSize: root.update.size + releaseDate: root.update.date + version: root.update.version + } + GSeparator { + Layout.bottomMargin: Layout.topMargin + Layout.fillWidth: true + Layout.topMargin: Constants.text_spacing + } + Item { + Layout.fillHeight: true + Layout.fillWidth: true + clip: true + + ReleaseNotesView { + model: releaseInformationModel.updateRelease + + anchors { + bottomMargin: Constants.pane_padding + fill: parent + leftMargin: Constants.pane_padding + topMargin: Constants.pane_padding } - ScrollGradients { - anchors.fill: parent - color: Style.color.background_pane - leftMargin: 0 - rightMargin: 0 + ReleaseInformationModel { + id: releaseInformationModel + } } - GSeparator { - Layout.bottomMargin: Layout.topMargin - Layout.fillWidth: true - Layout.topMargin: Constants.text_spacing + ScrollGradients { + anchors.fill: parent + color: Style.color.pane + leftMargin: 0 + rightMargin: 0 } - UpdateViewButtonRow { - id: updateButtons - Layout.fillWidth: true - progressText: "%1 KiB / %2 KiB".arg(root.update.downloadProgress.toLocaleString(Qt.locale(SettingsModel.language), "f", 0)).arg(root.update.downloadTotal.toLocaleString(Qt.locale(SettingsModel.language), "f", 0)) - progressValue: root.update.downloadProgress * 100 / root.update.downloadTotal - - onRemindLater: root.leaveView() - onSkipUpdate: { - root.update.skipUpdate(); - root.leaveView(); - } - onToggleUpdate: root.downloadRunning ? root.update.abortDownload() : download.exec() + } + GSeparator { + Layout.bottomMargin: Layout.topMargin + Layout.fillWidth: true + Layout.topMargin: Constants.text_spacing + } + UpdateViewButtonRow { + id: updateButtons + + Layout.fillWidth: true + progressText: "%1 KiB / %2 KiB".arg(root.update.downloadProgress.toLocaleString(Qt.locale(SettingsModel.language), "f", 0)).arg(root.update.downloadTotal.toLocaleString(Qt.locale(SettingsModel.language), "f", 0)) + progressValue: root.update.downloadProgress * 100 / root.update.downloadTotal + + onRemindLater: root.leaveView() + onSkipUpdate: { + root.update.skipUpdate(); + root.leaveView(); } + onToggleUpdate: root.downloadRunning ? root.update.abortDownload() : download.exec() } } Connections { @@ -134,6 +132,7 @@ SectionPage { } ConfirmationPopup { id: download + function exec() { if (root.update.compatible || Qt.platform.os === "osx") load(); diff --git a/resources/qml/Governikus/UpdateView/+desktop/UpdateViewButtonRow.qml b/resources/qml/Governikus/UpdateView/+desktop/UpdateViewButtonRow.qml index e044467f7..769382ff4 100644 --- a/resources/qml/Governikus/UpdateView/+desktop/UpdateViewButtonRow.qml +++ b/resources/qml/Governikus/UpdateView/+desktop/UpdateViewButtonRow.qml @@ -1,12 +1,12 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.SettingsModel 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.Type.ApplicationModel +import Governikus.Type.SettingsModel RowLayout { id: root @@ -23,9 +23,10 @@ RowLayout { GProgressBar { id: bar + Layout.fillWidth: true activeFocusOnTab: true - backgroundColor: Style.color.background_pane_inactive + backgroundColor: Style.color.control visible: downloadInProgress } GButton { diff --git a/resources/qml/Governikus/UpdateView/+desktop/UpdateViewInformation.qml b/resources/qml/Governikus/UpdateView/+desktop/UpdateViewInformation.qml index 6fd3dceb4..179c76d24 100644 --- a/resources/qml/Governikus/UpdateView/+desktop/UpdateViewInformation.qml +++ b/resources/qml/Governikus/UpdateView/+desktop/UpdateViewInformation.qml @@ -1,12 +1,12 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.SettingsModel 1.0 -import Governikus.View 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.Type.SettingsModel +import Governikus.View ColumnLayout { id: root @@ -28,15 +28,14 @@ ColumnLayout { //: LABEL DESKTOP Information about the available, new version number. text: qsTr("New version:") - textStyle: Style.text.normal FocusFrame { } } GText { id: textVersion + activeFocusOnTab: true - textStyle: Style.text.normal FocusFrame { } @@ -46,7 +45,6 @@ ColumnLayout { //: LABEL DESKTOP Date when the available update was released. text: qsTr("Release date:") - textStyle: Style.text.normal FocusFrame { } @@ -54,7 +52,6 @@ ColumnLayout { GText { activeFocusOnTab: true text: releaseDate.toLocaleDateString(Qt.locale(SettingsModel.language)) - textStyle: Style.text.normal FocusFrame { } @@ -64,7 +61,6 @@ ColumnLayout { //: LABEL DESKTOP Download size of the available update in megabyte. text: qsTr("Download size:") - textStyle: Style.text.normal FocusFrame { } @@ -72,7 +68,6 @@ ColumnLayout { GText { activeFocusOnTab: true text: "%1 MiB".arg((downloadSize / 1024576).toLocaleString(Qt.locale(SettingsModel.language), "f", 1)) - textStyle: Style.text.normal FocusFrame { } @@ -82,7 +77,6 @@ ColumnLayout { //: LABEL DESKTOP Plaintext link to the update download. text: qsTr("Download link:") - textStyle: Style.text.normal visible: downloadUrl !== "" FocusFrame { @@ -91,7 +85,6 @@ ColumnLayout { GText { activeFocusOnTab: true text: "%1".arg(downloadUrl) - textStyle: Style.text.normal visible: downloadUrl !== "" FocusFrame { @@ -102,7 +95,6 @@ ColumnLayout { //: LABEL DESKTOP Link to download checksum to verify the downloaded update file. text: qsTr("Checksum link:") - textStyle: Style.text.normal visible: checksumUrl !== "" FocusFrame { @@ -111,7 +103,6 @@ ColumnLayout { GText { activeFocusOnTab: true text: "%1".arg(checksumUrl) - textStyle: Style.text.normal visible: checksumUrl !== "" FocusFrame { diff --git a/resources/qml/Governikus/View/+desktop/Controller.qml b/resources/qml/Governikus/View/+desktop/Controller.qml index b89a7e32b..14b987402 100644 --- a/resources/qml/Governikus/View/+desktop/Controller.qml +++ b/resources/qml/Governikus/View/+desktop/Controller.qml @@ -1,7 +1,7 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 +import QtQuick BaseController { signal nextView(int pName) diff --git a/resources/qml/Governikus/View/+desktop/FocusFrame.qml b/resources/qml/Governikus/View/+desktop/FocusFrame.qml index 51619f259..2174323d9 100644 --- a/resources/qml/Governikus/View/+desktop/FocusFrame.qml +++ b/resources/qml/Governikus/View/+desktop/FocusFrame.qml @@ -1,23 +1,22 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.ApplicationModel 1.0 +import QtQuick +import Governikus.Global +import Governikus.Style Rectangle { id: baseItem + property color borderColor: Style.color.focus_indicator property Item framee: parent - property bool isOnLightBackground: true property real marginFactor: 1 property Item scope: parent - readonly property real size: Math.max(ApplicationModel.scaleFactor * 4, 1) + readonly property real size: Math.max(plugin.scaleFactor * 4, 1) anchors.fill: framee anchors.margins: marginFactor * -size * 2 - border.color: isOnLightBackground ? Style.color.focus_indicator : Style.color.focus_indicator_inverse + border.color: baseItem.borderColor border.width: scope.activeFocus && plugin.showFocusIndicator ? size : 0 color: Style.color.transparent radius: size * 2 diff --git a/resources/qml/Governikus/View/+desktop/FocusPoint.qml b/resources/qml/Governikus/View/+desktop/FocusPoint.qml index 61d124c3c..c1d87a75c 100644 --- a/resources/qml/Governikus/View/+desktop/FocusPoint.qml +++ b/resources/qml/Governikus/View/+desktop/FocusPoint.qml @@ -1,21 +1,20 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.ApplicationModel 1.0 +import QtQuick +import Governikus.Global +import Governikus.Style +import Governikus.Type.ApplicationModel Text { id: border - property bool isOnLightBackground: true property Item scope: parent anchors.left: parent.left anchors.top: parent.top - color: isOnLightBackground ? Style.color.focus_indicator : Style.color.focus_indicator_inverse - font.pixelSize: Style.dimens.hint_font_size + color: Style.color.focus_indicator + font.pixelSize: Style.dimens.text horizontalAlignment: Text.AlignHCenter text: "✱" visible: scope.activeFocus && plugin.showFocusIndicator diff --git a/resources/qml/Governikus/View/+desktop/FramedImage.qml b/resources/qml/Governikus/View/+desktop/FramedImage.qml index 58e2fc6c2..3e373967c 100644 --- a/resources/qml/Governikus/View/+desktop/FramedImage.qml +++ b/resources/qml/Governikus/View/+desktop/FramedImage.qml @@ -1,9 +1,9 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import Governikus.Global +import Governikus.Style Item { id: baseItem @@ -14,6 +14,7 @@ Item { Rectangle { id: frame + anchors.centerIn: parent anchors.fill: parent border.color: baseItem.tintColor @@ -23,6 +24,7 @@ Item { } TintableIcon { id: image + anchors.fill: frame anchors.margins: frame.border.width * 2 sourceSize.height: frame.height diff --git a/resources/qml/Governikus/View/+desktop/SectionPage.qml b/resources/qml/Governikus/View/+desktop/SectionPage.qml index a26acdbe0..73abb600e 100644 --- a/resources/qml/Governikus/View/+desktop/SectionPage.qml +++ b/resources/qml/Governikus/View/+desktop/SectionPage.qml @@ -1,17 +1,17 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.TitleBar 1.0 -import Governikus.Style 1.0 -import Governikus.View 1.0 +import QtQuick +import QtQuick.Controls +import Governikus.TitleBar +import Governikus.Style +import Governikus.View Controller { id: controller + readonly property bool breadcrumpSearchPath: true property bool isAbstract: false - readonly property bool sectionPageTypeMarker: true property TitleBarAction titleBarAction: null function setActive() { diff --git a/resources/qml/Governikus/View/+mobile/ContentArea.qml b/resources/qml/Governikus/View/+mobile/ContentArea.qml index ba17e8aff..bddf8d980 100644 --- a/resources/qml/Governikus/View/+mobile/ContentArea.qml +++ b/resources/qml/Governikus/View/+mobile/ContentArea.qml @@ -1,23 +1,20 @@ /** * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.CheckIDCardView 1.0 -import Governikus.ChangePinView 1.0 -import Governikus.HistoryView 1.0 -import Governikus.MainView 1.0 -import Governikus.MoreView 1.0 -import Governikus.AuthView 1.0 -import Governikus.ProviderView 1.0 -import Governikus.SettingsView 1.0 -import Governikus.SelfAuthenticationView 1.0 -import Governikus.SmartView 1.0 -import Governikus.TutorialView 1.0 -import Governikus.RemoteServiceView 1.0 -import Governikus.View 1.0 -import Governikus.Type.SettingsModel 1.0 -import Governikus.Type.UiModule 1.0 +import QtQuick +import Governikus.Global +import Governikus.CheckIDCardView +import Governikus.ChangePinView +import Governikus.MainView +import Governikus.MoreView +import Governikus.AuthView +import Governikus.SettingsView +import Governikus.SelfAuthenticationView +import Governikus.SmartView +import Governikus.RemoteServiceView +import Governikus.View +import Governikus.Type.SettingsModel +import Governikus.Type.UiModule Item { id: baseItem @@ -29,14 +26,24 @@ Item { TabBarView { id: authView + anchors.fill: parent visible: baseItem.activeModule === UiModule.IDENTIFY initialItem: AuthView { + onShowChangePinView: { + show(UiModule.PINMANAGEMENT); + popAll(); + } + onWorkflowFinished: { + show(UiModule.DEFAULT); + popAll(); + } } } TabBarView { id: mainView + anchors.fill: parent visible: baseItem.activeModule === UiModule.DEFAULT @@ -45,14 +52,17 @@ Item { } TabBarView { id: selfAuthenticationView + anchors.fill: parent visible: baseItem.activeModule === UiModule.SELF_AUTHENTICATION initialItem: SelfAuthenticationView { + onBack: show(UiModule.DEFAULT) } } TabBarView { id: checkIDCardView + anchors.fill: parent visible: baseItem.activeModule === UiModule.CHECK_ID_CARD @@ -61,38 +71,27 @@ Item { } TabBarView { id: smartView - anchors.fill: parent - visible: baseItem.activeModule === UiModule.SMART - initialItem: SmartView { - } - } - TabBarView { - id: providerView anchors.fill: parent - visible: baseItem.activeModule === UiModule.PROVIDER + visible: baseItem.activeModule === UiModule.SMART_EID - initialItem: ProviderView { - } - } - TabBarView { - id: historyView - anchors.fill: parent - visible: baseItem.activeModule === UiModule.HISTORY - - initialItem: HistoryView { + initialItem: SmartView { } } TabBarView { id: changePinView + anchors.fill: parent visible: baseItem.activeModule === UiModule.PINMANAGEMENT initialItem: ChangePinView { + onClose: show(UiModule.DEFAULT) + onWorkflowFinished: popAll() } } TabBarView { id: remoteView + anchors.fill: parent visible: baseItem.activeModule === UiModule.REMOTE_SERVICE @@ -101,6 +100,7 @@ Item { } TabBarView { id: settingsView + anchors.fill: parent visible: baseItem.activeModule === UiModule.SETTINGS @@ -109,6 +109,7 @@ Item { } TabBarView { id: helpView + anchors.fill: parent visible: baseItem.activeModule === UiModule.HELP || baseItem.activeModule === UiModule.TUTORIAL diff --git a/resources/qml/Governikus/View/+mobile/Controller.qml b/resources/qml/Governikus/View/+mobile/Controller.qml index d725d518c..e2690774a 100644 --- a/resources/qml/Governikus/View/+mobile/Controller.qml +++ b/resources/qml/Governikus/View/+mobile/Controller.qml @@ -1,13 +1,13 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Workflow 1.0 +import QtQuick +import QtQuick.Controls +import Governikus.Workflow BaseController { readonly property var navBar: typeof (navigation) !== "undefined" ? navigation : parent ? parent.navBar : null - readonly property var stackView: StackView.view ? StackView.view : (parent && parent.stackView ? parent.stackView : parent) + property var stackView: StackView.view ? StackView.view : (parent && parent.stackView ? parent.stackView : parent) readonly property bool workflowActive: stackView ? (stackView.currentItem instanceof GeneralWorkflow) : false function getLockedAndHidden() { @@ -17,9 +17,9 @@ BaseController { console.log("Controller cannot find navBar"); return false; } - function pop() { + function pop(pItem) { if (stackView) { - stackView.pop(); + stackView.pop(pItem); } else { console.log("Controller not attached to StackView"); } diff --git a/resources/qml/Governikus/View/+mobile/FlickableSectionPage.qml b/resources/qml/Governikus/View/+mobile/FlickableSectionPage.qml new file mode 100644 index 000000000..48f621309 --- /dev/null +++ b/resources/qml/Governikus/View/+mobile/FlickableSectionPage.qml @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick +import Governikus.Global +import Governikus.Style + +SectionPage { + id: root + + default property alias data: flickable.data + property bool fillWidth: false + property real margins: Constants.pane_padding + property alias spacing: flickable.spacing + + function scrollPageDown() { + flickable.scrollPageDown(baseItem); + } + function scrollPageUp() { + flickable.scrollPageUp(baseItem); + } + + contentIsScrolled: !flickable.atYBeginning + + Connections { + function onActivate() { + flickable.highlightScrollbar(); + } + } + GFlickableColumnLayout { + id: flickable + + anchors.fill: parent + bottomMargin: root.margins + leftMargin: root.margins + maximumContentWidth: fillWidth ? -1 : Style.dimens.max_text_width + rightMargin: root.margins + spacing: 0 + topMargin: root.margins + } +} diff --git a/resources/qml/Governikus/View/+mobile/FocusFrame.qml b/resources/qml/Governikus/View/+mobile/FocusFrame.qml index 3d3c128ac..2880ef244 100644 --- a/resources/qml/Governikus/View/+mobile/FocusFrame.qml +++ b/resources/qml/Governikus/View/+mobile/FocusFrame.qml @@ -1,11 +1,11 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 +import QtQuick Item { + property color borderColor property Item framee - property bool isOnLightBackground property real marginFactor property real radius property Item scope diff --git a/resources/qml/Governikus/View/+mobile/FocusPoint.qml b/resources/qml/Governikus/View/+mobile/FocusPoint.qml index 8b7e02186..21784bafc 100644 --- a/resources/qml/Governikus/View/+mobile/FocusPoint.qml +++ b/resources/qml/Governikus/View/+mobile/FocusPoint.qml @@ -1,10 +1,9 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 +import QtQuick Text { - property bool isOnLightBackground property Item scope: parent visible: false diff --git a/resources/qml/Governikus/View/+mobile/SectionPage.qml b/resources/qml/Governikus/View/+mobile/SectionPage.qml index 3d558d389..b9aa42ce8 100644 --- a/resources/qml/Governikus/View/+mobile/SectionPage.qml +++ b/resources/qml/Governikus/View/+mobile/SectionPage.qml @@ -1,62 +1,33 @@ /** * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.Type.ApplicationModel 1.0 +import QtQuick +import QtQuick.Controls +import Governikus.Global +import Governikus.Style +import Governikus.TitleBar +import Governikus.Type.ApplicationModel Controller { id: root - // When enabled the section page will automatically add a safeAreaMargin to the bottom of the page - property bool automaticSafeAreaMarginHandling: true - property alias content: flickableContent.data - property bool contentBehindTitlebar: false + property bool contentIsScrolled: false property bool hiddenNavbarPadding: false property var navigationAction: null property var rightTitleBarAction: null - - // Main flickable of this view - property var sectionPageFlickable: flickable - property string title: "" - property color titleBarColor: Style.color.accent + property bool smartEidUsed: false + required property string title property real titleBarOpacity: 1 property bool titleBarVisible: true + signal activate signal reset - function activated() { - if (ApplicationModel.isScreenReaderRunning()) { - updateFocus(); - } - highlightScrollbar(); - } - function highlightScrollbar() { - sectionPageFlickable.highlightScrollbar(); - } - function scrollPageDown() { - sectionPageFlickable.scrollPageDown(); - } - function scrollPageUp() { - sectionPageFlickable.scrollPageUp(); - } - - GFlickable { - id: flickable - anchors.bottom: parent.bottom - contentHeight: flickableContent.height - contentWidth: flickableContent.width - height: contentBehindTitlebar ? (parent.height + Style.dimens.titlebar_height) : parent.height - scrollBarTopPadding: contentBehindTitlebar ? Style.dimens.titlebar_height : 0 - width: parent.width - - Item { - id: flickableContent - height: childrenRect.height - width: flickable.width + Connections { + function onActivate() { + if (ApplicationModel.isScreenReaderRunning()) { + updateFocus(); + } } } } diff --git a/resources/qml/Governikus/View/+mobile/TabBarView.qml b/resources/qml/Governikus/View/+mobile/TabBarView.qml index 34e31143c..d70facf68 100644 --- a/resources/qml/Governikus/View/+mobile/TabBarView.qml +++ b/resources/qml/Governikus/View/+mobile/TabBarView.qml @@ -1,10 +1,10 @@ /** * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Type.ApplicationModel 1.0 +import QtQuick +import QtQuick.Controls +import Governikus.Global +import Governikus.Type.ApplicationModel StackView { id: root @@ -12,8 +12,8 @@ StackView { readonly property bool animationEnabled: !ApplicationModel.isScreenReaderRunning() function doActivate() { - if (visible && currentItem && typeof currentItem.activated === "function") { - currentItem.activated(); + if (visible && currentItem && typeof currentItem.activate === "function") { + currentItem.activate(); } } @@ -33,6 +33,7 @@ StackView { Component { id: enterAnimation + Transition { readonly property bool reversed: false @@ -58,6 +59,7 @@ StackView { } Component { id: exitAnimation + Transition { enabled: animationEnabled diff --git a/resources/qml/Governikus/View/BaseController.qml b/resources/qml/Governikus/View/BaseController.qml index 9c146dd2b..5b0a52b4a 100644 --- a/resources/qml/Governikus/View/BaseController.qml +++ b/resources/qml/Governikus/View/BaseController.qml @@ -1,12 +1,13 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Type.ApplicationModel 1.0 +import QtQuick +import QtQuick.Controls +import Governikus.Type.ApplicationModel Item { id: root + function showRemoveCardFeedback(workflowModel, success) { if (workflowModel.showRemoveCardFeedback) { workflowModel.showRemoveCardFeedback = false; @@ -45,6 +46,7 @@ Item { QtObject { id: d + function forceFocusFirstA11yItem(view) { if (!view.visible) { return false; @@ -54,8 +56,8 @@ Item { view.forceActiveFocus(Qt.MouseFocusReason); return true; } - for (var i = 0; i < view.children.length; i++) { - var child = view.children[i]; + for (let i = 0; i < view.children.length; i++) { + let child = view.children[i]; if (forceFocusFirstA11yItem(child)) { return true; } diff --git a/resources/qml/Governikus/View/qmldir b/resources/qml/Governikus/View/qmldir index 81c18c5ef..65a39547b 100644 --- a/resources/qml/Governikus/View/qmldir +++ b/resources/qml/Governikus/View/qmldir @@ -4,6 +4,7 @@ internal BaseController BaseController.qml ContentArea 1.0 ContentArea.qml Controller 1.0 Controller.qml +FlickableSectionPage 1.0 FlickableSectionPage.qml SectionPage 1.0 SectionPage.qml TabBarView 1.0 TabBarView.qml FocusFrame 1.0 FocusFrame.qml diff --git a/resources/qml/Governikus/WhiteListClient/+mobile/WhiteListSurveyView.qml b/resources/qml/Governikus/WhiteListClient/+mobile/WhiteListSurveyView.qml index 1b400732c..af37b5d75 100644 --- a/resources/qml/Governikus/WhiteListClient/+mobile/WhiteListSurveyView.qml +++ b/resources/qml/Governikus/WhiteListClient/+mobile/WhiteListSurveyView.qml @@ -1,216 +1,115 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.AuthModel 1.0 -import Governikus.Type.SurveyModel 1.0 - -SectionPage { +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.TitleBar +import Governikus.View +import Governikus.Type.ApplicationModel +import Governikus.Type.AuthModel +import Governikus.Type.SurveyModel + +FlickableSectionPage { id: root + signal done(bool pUserAccepted) + spacing: Constants.pane_spacing //: LABEL ANDROID IOS title: qsTr("Feedback") - content: Column { - padding: Constants.pane_padding - spacing: Constants.pane_spacing - width: root.width - - GPane { - id: whitePane - - //: INFO ANDROID IOS Request to the user if the device information should be shared for statistics (Whitelist) - Header - title: qsTr("Send device data?") - - anchors { - left: parent.left - margins: Constants.pane_padding - right: parent.right - } - GText { - anchors.left: parent.left - anchors.right: parent.right - //: INFO ANDROID IOS Request to the user if the device information should be shared for statistics (Whitelist) - Part of content text - text: qsTr("Would you like to help us to improve the AusweisApp2?") - } - GText { - anchors.left: parent.left - anchors.right: parent.right - //: INFO ANDROID IOS Request to the user if the device information should be shared for statistics (Whitelist) - Part of content text - text: qsTr("Supplying your device characteristics helps us to gather reliable information about the compatibility of your device.") - } - GText { - anchors.left: parent.left - anchors.right: parent.right - //: INFO ANDROID IOS Request to the user if the device information should be shared for statistics (Whitelist) - Part of content text - text: qsTr("The transmission is anonymous. No personal data is collected or transmitted!") - } - Column { - anchors.left: parent.left - anchors.right: parent.right - spacing: 2 - - GSeparator { - anchors.left: parent.left - anchors.right: parent.right - } - Button { - id: collapsableCollectedData - anchors.left: parent.left - anchors.right: parent.right - height: showDataButton.height + Constants.pane_spacing - - background: Rectangle { - color: collapsableCollectedData.down ? Style.color.tutorial_box_background : Style.color.background_pane - } - contentItem: Item { - Item { - id: showDataButton - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - height: showDataText.height - - GText { - id: showDataTriangle - anchors.right: parent.right - anchors.top: parent.top - horizontalAlignment: Text.AlignRight - rightPadding: Constants.groupbox_spacing - text: d.dataHidden ? "\u25BC" : "\u25B2" - } - GText { - id: showDataText - anchors.bottom: showDataTriangle.bottom - anchors.bottomMargin: showDataText.height / 8 - anchors.right: showDataTriangle.left - rightPadding: Constants.groupbox_spacing - text: qsTr("Collected data") - } - } - Item { - id: collectedData - - property real openHeight: dataColumn.implicitHeight - - anchors.top: showDataButton.bottom - clip: true - height: openHeight - opacity: 0 - width: parent.width - - Column { - id: dataColumn - anchors.left: parent.left - topPadding: Constants.groupbox_spacing - width: parent.width - - Repeater { - id: repeater - model: SurveyModel - - delegate: LabeledText { - label: title - text: value - width: dataColumn.width - } - } - } - } - } - states: [ - State { - name: "open" - when: !d.dataHidden - - PropertyChanges { - height: collectedData.openHeight + showDataButton.height + Constants.pane_spacing - target: collapsableCollectedData - } - PropertyChanges { - height: collectedData.openHeight - target: collectedData - } - PropertyChanges { - opacity: 1.0 - target: collectedData - } - } - ] - transitions: [ - Transition { - PropertyAnimation { - duration: 500 - easing.type: Easing.InOutQuad - property: "height" - target: collectedData - } - PropertyAnimation { - duration: 500 - easing.type: Easing.InOutQuad - property: "opacity" - target: collectedData - } - PropertyAnimation { - duration: 500 - easing.type: Easing.InOutQuad - property: "height" - target: collapsableCollectedData - } - } - ] - - onClicked: { - d.dataHidden = !d.dataHidden; - } - } - GSeparator { - anchors.left: parent.left - anchors.right: parent.right - } - } - GText { - anchors.left: parent.left - anchors.right: parent.right - //: INFO ANDROID IOS Request to the user if the device information should be shared for statistics (Whitelist) - Thank you message - text: qsTr("Thank you for your assistance!") - } - } - Row { - anchors.horizontalCenter: parent.horizontalCenter - height: childrenRect.height - spacing: Constants.component_spacing - - GButton { - //: LABEL ANDROID IOS - text: qsTr("Do not send") - - onClicked: root.done(false) - } - GButton { - //: LABEL ANDROID IOS - text: qsTr("Send") - - onClicked: root.done(true) - } - } - } navigationAction: NavigationAction { action: NavigationAction.Action.Cancel onClicked: root.done(false) } - QtObject { - id: d + PaneTitle { + Layout.leftMargin: Constants.pane_padding + Layout.rightMargin: Constants.pane_padding + //: INFO ANDROID IOS Request to the user if the device information should be shared for statistics (Whitelist) - Header + text: qsTr("Send device data?") + } + GText { + Layout.alignment: Qt.AlignHCenter + Layout.leftMargin: Constants.pane_padding + Layout.rightMargin: Constants.pane_padding + horizontalAlignment: Text.AlignHCenter + //: INFO ANDROID IOS Request to the user if the device information should be shared for statistics (Whitelist) - Part of content text + text: qsTr("Would you like to help us to improve the %1?").arg(Qt.application.name) + } + GText { + Layout.alignment: Qt.AlignHCenter + Layout.leftMargin: Constants.pane_padding + Layout.rightMargin: Constants.pane_padding + horizontalAlignment: Text.AlignHCenter + //: INFO ANDROID IOS Request to the user if the device information should be shared for statistics (Whitelist) - Part of content text + text: qsTr("Supplying your device characteristics helps us to gather reliable information about the compatibility of your device.") + } + GText { + Layout.alignment: Qt.AlignHCenter + Layout.leftMargin: Constants.pane_padding + Layout.rightMargin: Constants.pane_padding + horizontalAlignment: Text.AlignHCenter + //: INFO ANDROID IOS Request to the user if the device information should be shared for statistics (Whitelist) - Part of content text + text: qsTr("The transmission is anonymous. No personal data is collected or transmitted!") + } + GSeparator { + Layout.fillWidth: true + } + GCollapsible { + Layout.fillWidth: true + Layout.leftMargin: -Constants.pane_padding * 2 + Layout.rightMargin: -Constants.pane_padding * 2 + horizontalMargin: Constants.pane_padding * 3 + title: qsTr("Collected data") + + Repeater { + model: SurveyModel + + delegate: LabeledText { + Layout.fillWidth: true + label: title + text: value + } + } + } + GSeparator { + Layout.fillWidth: true + } + GText { + Layout.alignment: Qt.AlignHCenter + Layout.leftMargin: Constants.pane_padding + Layout.rightMargin: Constants.pane_padding + horizontalAlignment: Text.AlignHCenter + //: INFO ANDROID IOS Request to the user if the device information should be shared for statistics (Whitelist) - Thank you message + text: qsTr("Thank you for your assistance!") + } + GSpacer { + Layout.fillHeight: true + } + Row { + Layout.alignment: Qt.AlignHCenter + Layout.leftMargin: Constants.pane_padding + Layout.rightMargin: Constants.pane_padding + Layout.topMargin: Constants.pane_padding + height: childrenRect.height + spacing: Constants.component_spacing + + GButton { + //: LABEL ANDROID IOS + text: qsTr("Do not send") + + onClicked: root.done(false) + } + GButton { + //: LABEL ANDROID IOS + text: qsTr("Send") - property bool dataHidden: true + onClicked: root.done(true) + } } } diff --git a/resources/qml/Governikus/Workflow/+desktop/GeneralWorkflow.qml b/resources/qml/Governikus/Workflow/+desktop/GeneralWorkflow.qml index 583982c7f..fbd8e89d7 100644 --- a/resources/qml/Governikus/Workflow/+desktop/GeneralWorkflow.qml +++ b/resources/qml/Governikus/Workflow/+desktop/GeneralWorkflow.qml @@ -1,17 +1,17 @@ /** * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.View 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.AuthModel 1.0 -import Governikus.Type.NumberModel 1.0 -import Governikus.Type.PasswordType 1.0 -import Governikus.Type.ReaderPlugIn 1.0 -import Governikus.Type.RemoteServiceModel 1.0 +import QtQuick +import QtQuick.Controls +import Governikus.Global +import Governikus.Style +import Governikus.View +import Governikus.Type.ApplicationModel +import Governikus.Type.AuthModel +import Governikus.Type.NumberModel +import Governikus.Type.PasswordType +import Governikus.Type.ReaderPlugIn +import Governikus.Type.RemoteServiceModel SectionPage { id: root @@ -44,38 +44,53 @@ SectionPage { anchors.bottom: retryCounter.top anchors.bottomMargin: Constants.component_spacing anchors.horizontalCenter: retryCounter.horizontalCenter + font.bold: true //: LABEL DESKTOP text: qsTr("Attempts") - textStyle: Style.text.normal_highlight visible: retryCounter.visible } - StatusIcon { + RetryCounter { id: retryCounter - Accessible.name: qsTr("Remaining ID card PIN attempts: %1").arg(NumberModel.retryCounter) - activeFocusOnTab: true + anchors.left: parent.left anchors.margins: height anchors.top: parent.top - contentBackgroundColor: Style.color.accent - height: Style.dimens.status_icon_small - text: NumberModel.retryCounter - textStyle: Style.text.title_inverse visible: NumberModel.retryCounter >= 0 && NumberModel.passwordType === PasswordType.PIN - - FocusFrame { + } + TintableAnimation { + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.top + anchors.verticalCenterOffset: parent.height / 4 + height: Style.dimens.header_icon_size + source: { + if (d.foundRemoteReader) { + return "qrc:///images/desktop/workflow_waitfor_idcard_sak.webp"; + } + if (d.foundPCSCReader) { + return "qrc:///images/desktop/workflow_waitfor_idcard_usb.webp"; + } + return "qrc:///images/desktop/workflow_waitfor_reader.webp"; } + tintColor: Style.color.control + visible: waitingFor === Workflow.WaitingFor.Reader } - StatusIcon { + TintableIcon { anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.top anchors.verticalCenterOffset: parent.height / 4 - borderEnabled: false - busy: true - height: Style.dimens.status_icon_large - source: AuthModel.readerImage + source: { + if (d.foundRemoteReader) { + return "qrc:///images/desktop/workflow_idcard_nfc.svg"; + } + return "qrc:///images/desktop/workflow_idcard_usb.svg"; + } + sourceSize.height: Style.dimens.header_icon_size + tintColor: Style.color.control + visible: waitingFor === Workflow.WaitingFor.Password } ProgressCircle { id: progressCircle + Accessible.focusable: true Accessible.name: qsTr("Step %1 of 3").arg(state) Accessible.role: Accessible.ProgressBar @@ -97,6 +112,7 @@ SectionPage { } GText { id: mainText + Accessible.name: mainText.text activeFocusOnTab: true anchors.horizontalCenter: parent.horizontalCenter @@ -106,6 +122,9 @@ SectionPage { text: { switch (waitingFor) { case Workflow.WaitingFor.Reader: + if (!!AuthModel.eidTypeMismatchError) { + return AuthModel.eidTypeMismatchError; + } if (ApplicationModel.extendedLengthApdusUnsupported) { //: ERROR DESKTOP return qsTr("The used card reader does not meet the technical requirements (Extended Length not supported)."); @@ -122,7 +141,7 @@ SectionPage { return ""; } } - textStyle: Style.text.header + textStyle: Style.text.headline visible: text !== "" width: Math.min(parent.width - (2 * Constants.pane_padding), Style.dimens.max_text_width) @@ -138,11 +157,11 @@ SectionPage { return qsTr("No ID card detected. Please ensure that your ID card is placed on the card reader."); } else if (!d.foundPCSCReader && d.foundRemoteReader) { //: INFO DESKTOP The AA2 is waiting for the smartphone to be placed on the id. - return qsTr("No ID card detected. Please make sure that the NFC interface of the smartphone (connected to %1) is correctly placed on your ID card.").arg(RemoteServiceModel.connectedServerDeviceNames); + return qsTr("No ID card detected. Please follow the instructions on your smartphone (connected to %1) to use it as card reader.").arg(RemoteServiceModel.connectedServerDeviceNames); } //: INFO DESKTOP The AA2 is waiting for an ID card to be inserted into the card reader (or smartphone for that matter). - return qsTr("Please place the smartphone (connected to %1) on your ID card or put the ID card on the card reader.").arg(RemoteServiceModel.connectedServerDeviceNames); + return qsTr("Please follow the instructions on your smartphone (connected to %1) or put the ID card on the card reader.").arg(RemoteServiceModel.connectedServerDeviceNames); } activeFocusOnTab: true @@ -150,7 +169,6 @@ SectionPage { anchors.top: mainText.bottom anchors.topMargin: Constants.text_spacing horizontalAlignment: Text.AlignHCenter - linkColor: Style.text.header.textColor text: { switch (waitingFor) { case Workflow.WaitingFor.Reader: @@ -164,35 +182,23 @@ SectionPage { } } textFormat: Text.StyledText - textStyle: Style.text.header_secondary - visible: text !== "" && !ApplicationModel.extendedLengthApdusUnsupported + visible: text !== "" && !ApplicationModel.extendedLengthApdusUnsupported && AuthModel.eidTypeMismatchError === "" width: Math.min(parent.width - (2 * Constants.pane_padding), Style.dimens.max_text_width) FocusFrame { } } - MoreInformationLink { + GButton { id: readerSettingsLink + anchors.horizontalCenter: parent.horizontalCenter anchors.top: subText.bottom anchors.topMargin: Constants.component_spacing - visible: false - - states: [ - State { - name: "readerSettings" - when: waitingFor === Workflow.WaitingFor.Reader && !d.foundSelectedReader - PropertyChanges { - iconVisible: false - target: readerSettingsLink - //: INFO DESKTOP - text: qsTr("Go to reader settings") - visible: true + //: INFO DESKTOP + text: qsTr("Go to reader settings") + visible: waitingFor === Workflow.WaitingFor.Reader && !d.foundSelectedReader - onClicked: root.settingsRequested() - } - } - ] + onClicked: root.settingsRequested() } } diff --git a/resources/qml/Governikus/Workflow/+desktop/ProgressCircle.qml b/resources/qml/Governikus/Workflow/+desktop/ProgressCircle.qml index 2375c5b63..ab620c455 100644 --- a/resources/qml/Governikus/Workflow/+desktop/ProgressCircle.qml +++ b/resources/qml/Governikus/Workflow/+desktop/ProgressCircle.qml @@ -1,15 +1,14 @@ /** * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.ApplicationModel 1.0 +import QtQuick +import Governikus.Global +import Governikus.Style Item { - height: selector.height + height: Math.max(circle1.maximumHeight, circle2.maximumHeight, circle3.maximumHeight) state: "1" - width: d.stepWidth * 4 + height + width: d.stepWidth * 2 + height states: [ State { @@ -27,10 +26,6 @@ Item { enabled: false target: circle3 } - PropertyChanges { - anchors.leftMargin: 0 - target: line - } }, State { name: "2" @@ -47,10 +42,6 @@ Item { enabled: false target: circle3 } - PropertyChanges { - anchors.leftMargin: -d.stepWidth - target: line - } }, State { name: "3" @@ -67,20 +58,10 @@ Item { enabled: true target: circle3 } - PropertyChanges { - anchors.leftMargin: 2 * -d.stepWidth - target: line - } } ] transitions: [ Transition { - PropertyAnimation { - duration: 500 - easing.type: Easing.InOutCubic - property: "anchors.leftMargin" - target: line - } SequentialAnimation { PauseAnimation { duration: 200 @@ -104,42 +85,51 @@ Item { QtObject { id: d - readonly property int stepWidth: ApplicationModel.scaleFactor * 250 + readonly property int stepWidth: plugin.scaleFactor * 250 } Rectangle { - id: line - anchors.left: parent.horizontalCenter + id: line1 + + anchors.left: circle1.horizontalCenter + anchors.leftMargin: Constants.component_spacing + circle1.maximumHeight / 2 + anchors.right: circle2.horizontalCenter + anchors.rightMargin: Constants.component_spacing + circle2.maximumHeight / 2 anchors.verticalCenter: parent.verticalCenter color: Style.color.border - height: ApplicationModel.scaleFactor * 8 - width: d.stepWidth * 2 + height: Style.dimens.border_width + width: d.stepWidth + } + Rectangle { + id: line2 + + anchors.left: circle2.horizontalCenter + anchors.leftMargin: Constants.component_spacing + circle2.maximumHeight / 2 + anchors.right: circle3.horizontalCenter + anchors.rightMargin: Constants.component_spacing + circle3.maximumHeight / 2 + anchors.verticalCenter: parent.verticalCenter + color: Style.color.border + height: Style.dimens.border_width + width: d.stepWidth } TextCircle { id: circle1 - anchors.horizontalCenter: line.left - anchors.verticalCenter: line.verticalCenter + + anchors.horizontalCenter: parent.left + anchors.verticalCenter: parent.verticalCenter text: "1" } TextCircle { id: circle2 - anchors.horizontalCenter: line.horizontalCenter - anchors.verticalCenter: line.verticalCenter + + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter text: "2" } TextCircle { id: circle3 - anchors.horizontalCenter: line.right - anchors.verticalCenter: line.verticalCenter + + anchors.horizontalCenter: parent.right + anchors.verticalCenter: parent.verticalCenter text: "3" } - Rectangle { - id: selector - anchors.centerIn: parent - border.color: Style.color.accent - border.width: ApplicationModel.scaleFactor * 6 - color: Style.color.transparent - height: circle1.height + ApplicationModel.scaleFactor * 40 - radius: height / 2 - width: height - } } diff --git a/resources/qml/Governikus/Workflow/+desktop/TextCircle.qml b/resources/qml/Governikus/Workflow/+desktop/TextCircle.qml index f4cfa150f..146a73e91 100644 --- a/resources/qml/Governikus/Workflow/+desktop/TextCircle.qml +++ b/resources/qml/Governikus/Workflow/+desktop/TextCircle.qml @@ -1,26 +1,48 @@ /** * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import QtQuick.Controls +import Governikus.Global +import Governikus.Style Rectangle { + id: root + + readonly property double maximumHeight: enabledFontMetrics.height * 2.5 property alias text: number.text - border.color: Style.color.high_contrast_item_border - border.width: Style.dimens.high_contrast_item_border - color: enabled ? Style.color.accent : Style.color.background_pane + border.color: Style.color.control_border + border.width: Style.dimens.border_width + color: Style.color.transparent enabled: false - height: number.height * 2 + height: maximumHeight * d.scaleFactor radius: width * 0.5 width: height + QtObject { + id: d + + property double scaleFactor: root.enabled ? 1.0 : 0.7 + + Behavior on scaleFactor { + PropertyAnimation { + duration: 500 + easing.type: Easing.InOutCubic + } + } + } GText { id: number + Accessible.ignored: true anchors.centerIn: parent - textStyle: parent.enabled ? Style.text.header_inverse_highlight : Style.text.header_accent_highlight + font.pixelSize: Style.dimens.text_headline * d.scaleFactor + textStyle: Style.text.headline + } + FontMetrics { + id: enabledFontMetrics + + font.pixelSize: Style.dimens.text_headline } } diff --git a/resources/qml/Governikus/Workflow/+mobile/CardReader.qml b/resources/qml/Governikus/Workflow/+mobile/CardReader.qml index 7c624e120..90fd106a4 100644 --- a/resources/qml/Governikus/Workflow/+mobile/CardReader.qml +++ b/resources/qml/Governikus/Workflow/+mobile/CardReader.qml @@ -1,10 +1,10 @@ /** * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.ApplicationModel 1.0 +import QtQuick +import Governikus.Global +import Governikus.Style +import Governikus.Type.ApplicationModel Item { id: baseItem @@ -37,6 +37,7 @@ Item { } Timer { id: offTimer + interval: 500 onTriggered: { @@ -49,6 +50,7 @@ Item { } Rectangle { id: reader + anchors.bottom: parent.bottom color: Style.color.card_reader height: parent.height * 5 / 7 @@ -57,6 +59,7 @@ Item { Rectangle { id: slot + anchors.left: parent.left anchors.leftMargin: parent.width * 0.2 anchors.right: parent.right @@ -69,8 +72,9 @@ Item { } Rectangle { id: card + anchors.horizontalCenter: parent.horizontalCenter - color: Style.color.accent + color: Style.color.control height: baseItem.height * 1.5 / 7 radius: height * 0.05 width: baseItem.width * 0.5 @@ -105,6 +109,7 @@ Item { Rectangle { id: cardStripe1 + anchors.left: parent.left anchors.leftMargin: parent.width * 0.1 anchors.right: parent.right @@ -117,6 +122,7 @@ Item { } Rectangle { id: cardStripe2 + anchors.left: parent.left anchors.leftMargin: parent.width * 0.1 anchors.right: parent.right @@ -148,6 +154,7 @@ Item { } Grid { id: pinGrid + anchors.bottom: reader.bottom anchors.left: parent.left anchors.margins: display.margin @@ -158,6 +165,7 @@ Item { Repeater { id: repeater + model: 9 Item { @@ -171,13 +179,14 @@ Item { Rectangle { id: pinButtonCircle + anchors.centerIn: parent height: width radius: width * 0.5 state: "off" width: pinButton._size - Behavior on color { + Behavior on color { ColorAnimation { duration: 250 } @@ -208,7 +217,7 @@ Item { } } ] - Behavior on width { + Behavior on width { NumberAnimation { duration: 1000 easing.type: Easing.OutElastic diff --git a/resources/qml/Governikus/Workflow/+mobile/GeneralWorkflow.qml b/resources/qml/Governikus/Workflow/+mobile/GeneralWorkflow.qml index 884b0c22a..7038a2752 100644 --- a/resources/qml/Governikus/Workflow/+mobile/GeneralWorkflow.qml +++ b/resources/qml/Governikus/Workflow/+mobile/GeneralWorkflow.qml @@ -1,21 +1,29 @@ /** * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.TechnologyInfo 1.0 -import Governikus.TitleBar 1.0 -import Governikus.Workflow 1.0 -import Governikus.ResultView 1.0 -import Governikus.View 1.0 -import Governikus.Type.ReaderPlugIn 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.TechnologyInfo +import Governikus.TitleBar +import Governikus.Workflow +import Governikus.ResultView +import Governikus.Style +import Governikus.View +import Governikus.Type.ReaderPlugIn SectionPage { id: baseItem - property var workflowModel + property alias autoInsertCard: technologyInfo.autoInsertCard + property bool hideSwitch: false + property var initialPlugIn: null + readonly property bool isLandscape: ApplicationWindow.window && ApplicationWindow.menuBar ? ApplicationWindow.window.height - ApplicationWindow.menuBar.height < ApplicationWindow.window.width : false + property alias workflowModel: technologyInfo.workflowModel property string workflowTitle + contentIsScrolled: technologyInfo.contentIsScrolled || isLandscape && !technologySwitch.atYBeginning title: workflowTitle navigationAction: NavigationAction { @@ -24,67 +32,45 @@ SectionPage { onClicked: workflowModel.cancelWorkflow() } - Item { - anchors { - bottom: technologySwitch.visible ? technologySwitch.top : parent.bottom - left: parent.left - right: parent.right - top: parent.top + Component.onCompleted: { + if (initialPlugIn != null) { + technologySwitch.requestPluginType(initialPlugIn); } - NfcWorkflow { - anchors.fill: parent - visible: workflowModel.readerPlugInType === ReaderPlugIn.NFC + } - onStartScanIfNecessary: workflowModel.startScanExplicitly() - } - SmartWorkflow { - anchors.fill: parent - visible: workflowModel.readerPlugInType === ReaderPlugIn.SMART - workflowModel: baseItem.workflowModel - } - RemoteWorkflow { - anchors.fill: parent - visible: workflowModel.readerPlugInType === ReaderPlugIn.REMOTE_IFD || workflowModel.readerPlugInType === ReaderPlugIn.PCSC + GridLayout { + anchors.fill: parent + columns: 3 + flow: isLandscape ? Flow.LeftToRight : Flow.TopToBottom + rows: 3 - onDeviceUnpaired: function (pDeviceName) { - push(deviceUnpairedView, { - "deviceName": pDeviceName - }); - } + WorkflowInfoList { + id: technologyInfo - Component { - id: deviceUnpairedView - ResultView { - property string deviceName + Layout.fillHeight: true + Layout.fillWidth: true + } + GSeparator { + id: separator - resultType: ResultView.Type.IsError - //: INFO ANDROID IOS The paired smartphone was removed since it did not respond to connection attempts. It needs to be paired again before using it. - text: qsTr("The device \"%1\" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader.").arg(deviceName) - title: workflowTitle + readonly property real shorteningFactor: 0.75 - onCancelClicked: pop() - onContinueClicked: pop() - } - } - } - SimulatorWorkflow { - anchors.fill: parent - visible: workflowModel.readerPlugInType === ReaderPlugIn.SIMULATOR - workflowModel: baseItem.workflowModel + Layout.alignment: Qt.AlignCenter + Layout.preferredHeight: isLandscape ? parent.height * shorteningFactor : Style.dimens.separator_size + Layout.preferredWidth: isLandscape ? Style.dimens.separator_size : parent.width * shorteningFactor + visible: technologySwitch.visible } - } - TechnologySwitch { - id: technologySwitch - selectedTechnology: workflowModel.readerPlugInType - supportedTechnologies: workflowModel.supportedPlugInTypes - visible: workflowModel.supportedPlugInTypes.length > 1 + TechnologySwitch { + id: technologySwitch - onRequestPluginType: pReaderPlugInType => workflowModel.readerPlugInType = pReaderPlugInType + Layout.fillHeight: isLandscape + Layout.fillWidth: !isLandscape + flowVertically: isLandscape + selectedTechnology: workflowModel.readerPlugInType + supportedTechnologies: workflowModel.supportedPlugInTypes + visible: !hideSwitch && workflowModel.supportedPlugInTypes.length > 1 - anchors { - bottom: parent.bottom - left: parent.left - right: parent.right + onRequestPluginType: pReaderPlugInType => workflowModel.readerPlugInType = pReaderPlugInType } } } diff --git a/resources/qml/Governikus/Workflow/+mobile/NfcProgressIndicator.qml b/resources/qml/Governikus/Workflow/+mobile/NfcProgressIndicator.qml index 602e6d085..16a670069 100644 --- a/resources/qml/Governikus/Workflow/+mobile/NfcProgressIndicator.qml +++ b/resources/qml/Governikus/Workflow/+mobile/NfcProgressIndicator.qml @@ -1,10 +1,10 @@ /** * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 -import Governikus.Type.CardPositionModel 1.0 +import QtQuick +import Governikus.Global +import Governikus.Style +import Governikus.Type.CardPositionModel Item { id: root @@ -14,15 +14,42 @@ Item { property var cardPosition: null property bool startPositionLeft: true - height: Style.dimens.workflow_progress_indicator_size + implicitHeight: Style.dimens.workflow_progress_indicator_size + implicitWidth: phone.implicitWidth states: [ + State { + name: "unavailable" + + PropertyChanges { + source: "qrc:///images/mobile/x.svg" + target: symbol + tintColor: Style.color.text_warning + visible: true + } + PropertyChanges { + opacity: 0 + restoreEntryValues: false + target: card + } + PropertyChanges { + running: false + target: modelActivationTimer + } + PropertyChanges { + restoreEntryValues: false + running: false + target: cardPositionModel + } + }, State { name: "off" PropertyChanges { - target: phone - tintEnabled: true + source: "qrc:///images/mobile/questionmark.svg" + target: symbol + tintColor: Style.color.control + visible: true } PropertyChanges { opacity: 0 @@ -43,8 +70,8 @@ Item { name: "on" PropertyChanges { - target: phone - tintEnabled: false + target: symbol + visible: false } PropertyChanges { running: true @@ -63,9 +90,11 @@ Item { } CardPositionModel { id: cardPositionModel + } Timer { id: modelActivationTimer + interval: 1000 onTriggered: cardPositionModel.running = true @@ -81,12 +110,12 @@ Item { PropertyAction { property: "anchors.horizontalCenterOffset" target: card - value: (startPositionLeft ? -phone.width : phone.width) * 0.75 + value: (startPositionLeft ? -fakephone.width : fakephone.width) * 0.75 } PropertyAction { property: "anchors.verticalCenterOffset" target: card - value: -phone.height * 0.5 + value: -fakephone.height * 0.5 } PropertyAction { property: "rotation" @@ -118,14 +147,14 @@ Item { easing.type: Easing.OutCubic property: "anchors.horizontalCenterOffset" target: card - to: phone.width * ((cardPosition ? cardPosition.x : 0) - 0.5) + to: fakephone.width * ((cardPosition ? cardPosition.x : 0) - 0.5) } NumberAnimation { duration: root.animateInDuration easing.type: Easing.OutCubic property: "anchors.verticalCenterOffset" target: card - to: phone.height * ((cardPosition ? cardPosition.y : 0) - 0.5) + to: fakephone.height * ((cardPosition ? cardPosition.y : 0) - 0.5) } } PauseAnimation { @@ -142,39 +171,61 @@ Item { duration: animation.pauseDuration * 0.1 } } - Image { - id: card - anchors.centerIn: phone - asynchronous: true - fillMode: Image.PreserveAspectFit - opacity: 0 - source: "qrc:///images/ausweis.svg" - sourceSize.height: phone.height * 0.5 - transformOrigin: Item.Center - visible: !phone.tintEnabled - } TintableIcon { id: phone + anchors.centerIn: parent - clip: true - desaturate: true - opacity: tintEnabled ? 0.7 : 1.0 - source: "qrc:///images/mobile/phone_nfc.svg" + source: symbol.visible ? "qrc:///images/mobile/phone_nfc_info.svg" : "qrc:///images/mobile/phone_nfc.svg" sourceSize.height: Style.dimens.header_icon_size + tintColor: Style.color.control z: 0 - Image { + TintableIcon { + id: card + + anchors.centerIn: fakephone + asynchronous: true + fillMode: Image.PreserveAspectFit + opacity: 0 + source: "qrc:///images/mobile/card.svg" + sourceSize.height: fakephone.height * 0.5 + tintColor: Style.color.control + visible: !symbol.visible + } + Item { + id: fakephone + + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + anchors.horizontalCenterOffset: -parent.width * 0.06 + anchors.top: parent.top + clip: true + width: parent.width * 0.43 + + TintableIcon { + asynchronous: true + fillMode: Image.PreserveAspectFit + opacity: card.z < 0 ? card.opacity : 0 + rotation: card.rotation + source: "qrc:///images/mobile/card.svg" + sourceSize.height: card.sourceSize.height + tintColor: Style.color.control_disabled + visible: card.visible + x: card.x - fakephone.x + y: card.y - fakephone.y + z: 1 + } + } + TintableIcon { + id: symbol + + anchors.horizontalCenter: phone.right + anchors.horizontalCenterOffset: -phone.width * 0.19 + anchors.verticalCenter: phone.bottom + anchors.verticalCenterOffset: -phone.height * 0.36 asynchronous: true fillMode: Image.PreserveAspectFit - opacity: card.z < 0 ? card.opacity : 0 - rotation: card.rotation - source: "qrc:///images/ausweis_outline.svg" - sourceSize.height: card.sourceSize.height - transformOrigin: Item.Center - visible: !phone.tintEnabled - x: card.x - phone.x - y: card.y - phone.y - z: 1 + sourceSize.height: phone.height * 0.2 } } } diff --git a/resources/qml/Governikus/Workflow/+mobile/NfcWorkflow.qml b/resources/qml/Governikus/Workflow/+mobile/NfcWorkflow.qml index bf22c67bb..55567753c 100644 --- a/resources/qml/Governikus/Workflow/+mobile/NfcWorkflow.qml +++ b/resources/qml/Governikus/Workflow/+mobile/NfcWorkflow.qml @@ -1,16 +1,18 @@ /** * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.TechnologyInfo 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.ReaderPlugIn 1.0 -import Governikus.Type.NumberModel 1.0 -import Governikus.Type.RemoteServiceModel 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.TechnologyInfo +import Governikus.Type.ApplicationModel +import Governikus.Type.AuthModel +import Governikus.Type.ReaderPlugIn +import Governikus.Type.NumberModel +import Governikus.Type.RemoteServiceModel -Item { +GFlickableColumnLayout { id: baseItem readonly property bool isRemoteWorkflow: ApplicationModel.currentWorkflow === ApplicationModel.WORKFLOW_REMOTE_SERVICE @@ -18,16 +20,31 @@ Item { signal startScanIfNecessary + clip: true + maximumContentWidth: Style.dimens.max_text_width + spacing: 0 + topMargin: 0 + NfcProgressIndicator { id: progressIndicator + Accessible.ignored: true - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - state: nfcState === ApplicationModel.NFC_READY ? "on" : "off" + Layout.alignment: Qt.AlignCenter + state: { + switch (nfcState) { + case ApplicationModel.NFC_READY: + return "on"; + case ApplicationModel.NFC_UNAVAILABLE: + return "unavailable"; + default: + return "off"; + } + } } TechnologyInfo { id: technologyInfo + + Layout.alignment: Qt.AlignHCenter enableButtonText: { switch (nfcState) { case ApplicationModel.NFC_DISABLED: @@ -65,6 +82,9 @@ Item { if (nfcState !== ApplicationModel.NFC_READY) { return ""; } + if (AuthModel.eidTypeMismatchError !== "") { + return AuthModel.eidTypeMismatchError; + } if (ApplicationModel.extendedLengthApdusUnsupported) { //: INFO ANDROID IOS The NFC interface does not meet the minimum requirements, using a different smartphone is suggested. return qsTr("Your device does not meet the technical requirements (Extended Length not supported). However you can use a separate smartphone as card reader to utilize the eID function."); @@ -98,14 +118,5 @@ Item { } onEnableClicked: nfcState === ApplicationModel.NFC_DISABLED ? ApplicationModel.showSettings(ApplicationModel.SETTING_NFC) : startScanIfNecessary() - - anchors { - bottom: parent.bottom - left: parent.left - leftMargin: Constants.component_spacing - right: parent.right - rightMargin: Constants.component_spacing - top: progressIndicator.bottom - } } } diff --git a/resources/qml/Governikus/Workflow/+mobile/ProgressCircle.qml b/resources/qml/Governikus/Workflow/+mobile/ProgressCircle.qml index a003661ec..19b3308e9 100644 --- a/resources/qml/Governikus/Workflow/+mobile/ProgressCircle.qml +++ b/resources/qml/Governikus/Workflow/+mobile/ProgressCircle.qml @@ -1,9 +1,9 @@ /** * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import Governikus.Global +import Governikus.Style Item { id: baseItem @@ -78,6 +78,7 @@ Item { Rectangle { id: rec1 + anchors.left: baseItem.horizontalCenter anchors.verticalCenter: parent.verticalCenter color: Constants.blue @@ -86,6 +87,7 @@ Item { } Rectangle { id: tCircle1 + anchors.horizontalCenter: rec1.left anchors.verticalCenter: rec1.verticalCenter border.color: Constants.white @@ -129,25 +131,27 @@ Item { Rectangle { id: innerDisc + anchors.centerIn: parent border.color: Constants.blue border.width: 1 - color: tCircle1.state === "active" ? Style.color.accent : Constants.white + color: tCircle1.state === "active" ? Style.color.control : Constants.white height: width radius: width / 2 GText { Accessible.ignored: true anchors.centerIn: parent - color: tCircle1.state === "active" ? Constants.white : Style.color.accent + color: tCircle1.state === "active" ? Constants.white : Style.color.control + font.bold: true font.pixelSize: parent.height / 3 text: "1" - textStyle: Style.text.normal_highlight } } } TextCircle { id: tCircle2 + anchors.horizontalCenter: rec1.right anchors.verticalCenter: rec1.verticalCenter text: "2" diff --git a/resources/qml/Governikus/Workflow/+mobile/RemoteProgressIndicator.qml b/resources/qml/Governikus/Workflow/+mobile/RemoteProgressIndicator.qml index 85c3ca2c1..4a400bf7b 100644 --- a/resources/qml/Governikus/Workflow/+mobile/RemoteProgressIndicator.qml +++ b/resources/qml/Governikus/Workflow/+mobile/RemoteProgressIndicator.qml @@ -1,28 +1,43 @@ /** * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import Governikus.Global +import Governikus.Style Item { id: baseItem property bool foundSelectedReader: false - height: Style.dimens.workflow_progress_indicator_size + implicitHeight: Style.dimens.workflow_progress_indicator_size + implicitWidth: phone.implicitWidth TintableIcon { id: phone + anchors.centerIn: parent - desaturate: true - opacity: tintEnabled ? 0.7 : 1.0 - source: "qrc:///images/mobile/phone_remote.svg" + source: "qrc:///images/mobile/phone_remote_info.svg" sourceSize.height: Style.dimens.header_icon_size + tintColor: Style.color.control visible: !baseItem.foundSelectedReader + + Image { + id: x + + anchors.horizontalCenter: phone.right + anchors.horizontalCenterOffset: -phone.width * 0.19 + anchors.verticalCenter: phone.bottom + anchors.verticalCenterOffset: -phone.height * 0.36 + asynchronous: true + fillMode: Image.PreserveAspectFit + source: "qrc:///images/mobile/x.svg" + sourceSize.height: phone.height * 0.2 + } } Item { id: currentAction + anchors.bottom: pCircle.top anchors.left: parent.left anchors.margins: Constants.component_spacing @@ -38,6 +53,7 @@ Item { } ProgressCircle { id: pCircle + anchors.bottom: parent.bottom anchors.left: parent.left anchors.right: parent.right diff --git a/resources/qml/Governikus/Workflow/+mobile/RemoteWorkflow.qml b/resources/qml/Governikus/Workflow/+mobile/RemoteWorkflow.qml index 0ecf8be70..90bd72c49 100644 --- a/resources/qml/Governikus/Workflow/+mobile/RemoteWorkflow.qml +++ b/resources/qml/Governikus/Workflow/+mobile/RemoteWorkflow.qml @@ -1,17 +1,19 @@ /** * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import Governikus.Global 1.0 -import Governikus.RemoteServiceView 1.0 -import Governikus.TechnologyInfo 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.RemoteServiceModel 1.0 -import Governikus.Type.ReaderPlugIn 1.0 -import Governikus.Type.NumberModel 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.RemoteServiceView +import Governikus.TechnologyInfo +import Governikus.Type.ApplicationModel +import Governikus.Type.AuthModel +import Governikus.Type.RemoteServiceModel +import Governikus.Type.ReaderPlugIn +import Governikus.Type.NumberModel -Item { +GFlickableColumnLayout { id: baseItem property bool foundSelectedReader: ApplicationModel.availableReader > 0 @@ -20,6 +22,11 @@ Item { signal deviceUnpaired(var pDeviceName) + clip: true + maximumContentWidth: Style.dimens.max_text_width + spacing: 0 + topMargin: 0 + onFoundSelectedReaderChanged: { if (baseItem.settingsPushed && foundSelectedReader) { remoteServiceSettings.pop(); @@ -35,14 +42,15 @@ Item { } RemoteProgressIndicator { id: progressIndicator + Accessible.ignored: true - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top + Layout.alignment: Qt.AlignCenter foundSelectedReader: baseItem.foundSelectedReader } TechnologyInfo { id: techInfo + + Layout.alignment: Qt.AlignHCenter enableButtonText: { if (!wifiEnabled) { //: LABEL ANDROID IOS @@ -71,12 +79,14 @@ Item { } if (!!NumberModel.inputError) { return NumberModel.inputError; + } else if (!!AuthModel.eidTypeMismatchError) { + return AuthModel.eidTypeMismatchError; } else if (ApplicationModel.extendedLengthApdusUnsupported) { //: INFO ANDROID IOS The device does not support Extended Length and can not be used as card reader. - qsTr("The connected smartphone as card reader (SaC) unfortunately does not meet the technical requirements (Extended Length not supported)."); + return qsTr("The connected smartphone as card reader (SaC) unfortunately does not meet the technical requirements (Extended Length not supported)."); } else { //: INFO ANDROID IOS The connection to the smartphone was established, the ID card may be inserted. - return qsTr("Connected to %1. Please place the NFC interface of the smartphone on your ID card.").arg(RemoteServiceModel.connectedServerDeviceNames); + return qsTr("Connected to %1. Please follow the instructions on the connected smartphone.").arg(RemoteServiceModel.connectedServerDeviceNames); } } titleText: { @@ -104,18 +114,10 @@ Item { push(remoteServiceSettings); } } - - anchors { - bottom: parent.bottom - left: parent.left - leftMargin: Constants.component_spacing - right: parent.right - rightMargin: Constants.component_spacing - top: progressIndicator.bottom - } } RemoteServiceSettings { id: remoteServiceSettings + visible: false } } diff --git a/resources/qml/Governikus/Workflow/+mobile/SimulatorWorkflow.qml b/resources/qml/Governikus/Workflow/+mobile/SimulatorWorkflow.qml index 16dac48e2..9b0aa8605 100644 --- a/resources/qml/Governikus/Workflow/+mobile/SimulatorWorkflow.qml +++ b/resources/qml/Governikus/Workflow/+mobile/SimulatorWorkflow.qml @@ -1,27 +1,32 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.TechnologyInfo 1.0 -import Governikus.Style 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.TechnologyInfo +import Governikus.Style -Item { +GFlickableColumnLayout { id: baseItem property var workflowModel + clip: true + maximumContentWidth: Style.dimens.max_text_width + spacing: 0 + topMargin: 0 + Item { id: progressIndicator - height: Style.dimens.workflow_progress_indicator_size - anchors { - left: parent.left - right: parent.right - top: parent.top - } + Layout.alignment: Qt.AlignCenter + implicitHeight: Style.dimens.workflow_progress_indicator_size + implicitWidth: icon.implicitWidth + TintableIcon { id: icon + anchors.centerIn: parent desaturate: true source: "qrc:///images/mobile/phone_simulator.svg" @@ -31,6 +36,8 @@ Item { } TechnologyInfo { id: technologyInfo + + Layout.alignment: Qt.AlignHCenter //: LABEL ANDROID IOS enableButtonText: qsTr("Continue") @@ -38,14 +45,5 @@ Item { titleText: qsTr("Simulator") onEnableClicked: workflowModel.insertSimulator() - - anchors { - bottom: parent.bottom - left: parent.left - leftMargin: Constants.component_spacing - right: parent.right - rightMargin: Constants.component_spacing - top: progressIndicator.bottom - } } } diff --git a/resources/qml/Governikus/Workflow/+mobile/SmartProgressIndicator.qml b/resources/qml/Governikus/Workflow/+mobile/SmartProgressIndicator.qml index d4e385531..b488dba7d 100644 --- a/resources/qml/Governikus/Workflow/+mobile/SmartProgressIndicator.qml +++ b/resources/qml/Governikus/Workflow/+mobile/SmartProgressIndicator.qml @@ -1,19 +1,21 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import Governikus.Global +import Governikus.Style Item { id: baseItem property alias disabled: icon.tintEnabled - height: Style.dimens.workflow_progress_indicator_size + implicitHeight: Style.dimens.workflow_progress_indicator_size + implicitWidth: icon.implicitWidth TintableIcon { id: icon + anchors.centerIn: parent desaturate: true opacity: tintEnabled ? 0.7 : 1.0 diff --git a/resources/qml/Governikus/Workflow/+mobile/SmartWorkflow.qml b/resources/qml/Governikus/Workflow/+mobile/SmartWorkflow.qml index 1c2a7b5c9..3e21c9351 100644 --- a/resources/qml/Governikus/Workflow/+mobile/SmartWorkflow.qml +++ b/resources/qml/Governikus/Workflow/+mobile/SmartWorkflow.qml @@ -1,38 +1,48 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.TechnologyInfo 1.0 -import Governikus.Type.ApplicationModel 1.0 -import Governikus.Type.SmartModel 1.0 -import Governikus.Type.NumberModel 1.0 -import Governikus.Type.PersonalizationModel 1.0 +import QtQuick +import QtQuick.Layouts +import Governikus.Global +import Governikus.Style +import Governikus.TechnologyInfo +import Governikus.Type.ApplicationModel +import Governikus.Type.SmartModel +import Governikus.Type.NumberModel +import Governikus.Type.PersonalizationModel +import Governikus.Type.RemoteServiceModel -Item { +GFlickableColumnLayout { id: baseItem + property bool autoInsertCard: false readonly property bool canUseSmart: smartState === SmartModel.SMART_READY && isSmartCardAllowed && SmartModel.isScanRunning readonly property bool isRemoteWorkflow: ApplicationModel.currentWorkflow === ApplicationModel.WORKFLOW_REMOTE_SERVICE - readonly property bool isSmartCardAllowed: workflowModel.isSmartCardAllowed + readonly property bool isSmartCardAllowed: workflowModel.isCurrentSmartCardAllowed readonly property int smartState: SmartModel.smartState property var workflowModel + clip: true + maximumContentWidth: Style.dimens.max_text_width + spacing: 0 + topMargin: 0 + + onCanUseSmartChanged: if (autoInsertCard) + technologyInfo.enableClicked() + SmartProgressIndicator { id: progressIndicator + Accessible.ignored: true + Layout.alignment: Qt.AlignCenter disabled: !canUseSmart - - anchors { - left: parent.left - right: parent.right - top: parent.top - } } TechnologyInfo { id: technologyInfo + + Layout.alignment: Qt.AlignHCenter enableButtonText: { - if (canUseSmart) { + if (canUseSmart && !autoInsertCard) { return qsTr("Continue"); } return ""; @@ -65,13 +75,17 @@ Item { } } subTitleText: { - if (canUseSmart) { + if (canUseSmart && !autoInsertCard) { //: LABEL ANDROID IOS return qsTr("Your Smart-eID is ready for use, press \"Continue\" to proceed."); } return ""; } titleText: { + if (isRemoteWorkflow && RemoteServiceModel.connectedClientName !== "") { + //: INFO ANDROID IOS %1 will be replaced with the name of the device. + return qsTr("The device \"%1\" wants to access your Smart-eID.").arg(RemoteServiceModel.connectedClientName); + } switch (smartState) { case SmartModel.SMART_UPDATING_STATUS: //: LABEL ANDROID IOS @@ -99,14 +113,5 @@ Item { onEnableClicked: if (canUseSmart) workflowModel.insertSmartCard() - - anchors { - bottom: parent.bottom - left: parent.left - leftMargin: Constants.component_spacing - right: parent.right - rightMargin: Constants.component_spacing - top: progressIndicator.bottom - } } } diff --git a/resources/qml/Governikus/Workflow/+mobile/TextCircle.qml b/resources/qml/Governikus/Workflow/+mobile/TextCircle.qml index 4dd022d98..28e727751 100644 --- a/resources/qml/Governikus/Workflow/+mobile/TextCircle.qml +++ b/resources/qml/Governikus/Workflow/+mobile/TextCircle.qml @@ -1,10 +1,10 @@ /** * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import QtQuick.Controls +import Governikus.Global +import Governikus.Style Item { property alias text: t.text @@ -66,6 +66,7 @@ Item { GBusyIndicator { id: busy + anchors.centerIn: parent height: rec.height * 1.1 running: false @@ -73,18 +74,20 @@ Item { } Rectangle { id: rec + anchors.centerIn: parent border.color: Constants.blue border.width: 1 - color: parent.state === "active" ? Style.color.accent : Constants.white + color: parent.state === "active" ? Style.color.control : Constants.white height: parent.state === "active" ? parent.height : parent.height / 2 radius: width * 0.5 width: height } GText { id: t + anchors.centerIn: rec - color: parent.state === "active" ? Constants.white : Style.color.accent - textStyle: parent.state === "active" ? Style.text.normal_highlight : Style.text.normal + color: parent.state === "active" ? Constants.white : Style.color.control + font.bold: parent.state === "active" } } diff --git a/resources/qml/Governikus/Workflow/+mobile/WorkflowInfoList.qml b/resources/qml/Governikus/Workflow/+mobile/WorkflowInfoList.qml new file mode 100644 index 000000000..a53f7d773 --- /dev/null +++ b/resources/qml/Governikus/Workflow/+mobile/WorkflowInfoList.qml @@ -0,0 +1,68 @@ +/** + * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick +import Governikus.Global +import Governikus.Workflow +import Governikus.ResultView +import Governikus.Style +import Governikus.Type.ReaderPlugIn + +Item { + id: baseItem + + property alias autoInsertCard: smartWorkflow.autoInsertCard + readonly property bool contentIsScrolled: nfcWorkflow.visible && !nfcWorkflow.atYBeginning || smartWorkflow.visible && !smartWorkflow.atYBeginning || remoteWorkflow.visible && !remoteWorkflow.atYBeginning || simulatorWorkflow.visible && !simulatorWorkflow.atYBeginning + required property var workflowModel + + NfcWorkflow { + id: nfcWorkflow + + anchors.fill: parent + visible: baseItem.workflowModel.readerPlugInType === ReaderPlugIn.NFC + + onStartScanIfNecessary: baseItem.workflowModel.startScanExplicitly() + } + SmartWorkflow { + id: smartWorkflow + + anchors.fill: parent + visible: baseItem.workflowModel.readerPlugInType === ReaderPlugIn.SMART + workflowModel: baseItem.workflowModel + } + RemoteWorkflow { + id: remoteWorkflow + + anchors.fill: parent + visible: baseItem.workflowModel.readerPlugInType === ReaderPlugIn.REMOTE_IFD || baseItem.workflowModel.readerPlugInType === ReaderPlugIn.PCSC + + onDeviceUnpaired: function (pDeviceName) { + push(deviceUnpairedView, { + "deviceName": pDeviceName + }); + } + + Component { + id: deviceUnpairedView + + ResultView { + property string deviceName + + icon: "qrc:///images/workflow_error_no_sak_%1.svg".arg(Style.currentTheme.name) + //: INFO ANDROID IOS The paired smartphone was removed since it did not respond to connection attempts. It needs to be paired again before using it. + text: qsTr("The device \"%1\" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader.").arg(deviceName) + title: workflowTitle + + onCancelClicked: pop() + onContinueClicked: pop() + } + } + } + SimulatorWorkflow { + id: simulatorWorkflow + + anchors.fill: parent + visible: baseItem.workflowModel.readerPlugInType === ReaderPlugIn.SIMULATOR + workflowModel: baseItem.workflowModel + } +} diff --git a/resources/qml/Governikus/Workflow/Workflow.qml b/resources/qml/Governikus/Workflow/Workflow.qml index 06ae95501..b5eb2f770 100644 --- a/resources/qml/Governikus/Workflow/Workflow.qml +++ b/resources/qml/Governikus/Workflow/Workflow.qml @@ -1,7 +1,7 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 +import QtQuick QtObject { enum WaitingFor { diff --git a/resources/qml/Governikus/Workflow/qmldir b/resources/qml/Governikus/Workflow/qmldir index dbdcf504f..94eb63bac 100644 --- a/resources/qml/Governikus/Workflow/qmldir +++ b/resources/qml/Governikus/Workflow/qmldir @@ -6,6 +6,7 @@ internal ProgressCircle ProgressCircle.qml internal RemoteProgressIndicator RemoteProgressIndicator.qml internal RemoteWorkflow RemoteWorkflow.qml internal SmartProgressIndicator SmartProgressIndicator.qml +internal WorkflowInfoList WorkflowInfoList.qml internal TextCircle TextCircle.qml GeneralWorkflow 1.0 GeneralWorkflow.qml diff --git a/resources/shader/OpacityMaskShader.frag b/resources/shader/OpacityMaskShader.frag deleted file mode 100644 index bdcf11355..000000000 --- a/resources/shader/OpacityMaskShader.frag +++ /dev/null @@ -1,8 +0,0 @@ -varying highp vec2 qt_TexCoord0; -uniform highp float qt_Opacity; -uniform lowp sampler2D source; -uniform lowp sampler2D maskSource; - -void main() { - gl_FragColor = texture2D(source, qt_TexCoord0.st) * texture2D(maskSource, qt_TexCoord0.st).a * qt_Opacity; -} \ No newline at end of file diff --git a/resources/shader/qt6/OpacityMaskShader.frag b/resources/shader/qt6/OpacityMaskShader.frag deleted file mode 100644 index 68ee16eda..000000000 --- a/resources/shader/qt6/OpacityMaskShader.frag +++ /dev/null @@ -1,13 +0,0 @@ -#version 440 -layout(location = 0) in vec2 qt_TexCoord0; -layout(location = 0) out vec4 fragColor; -layout(binding = 1) uniform sampler2D source; -layout(binding = 2) uniform sampler2D maskSource; -layout(std140, binding = 0) uniform buf { - mat4 qt_Matrix; - float qt_Opacity; -} ubuf; -void main() -{ - fragColor = texture(source, qt_TexCoord0.st) * texture(maskSource, qt_TexCoord0.st).a * ubuf.qt_Opacity; -} diff --git a/resources/statemachine.sh.in b/resources/statemachine.sh.in index 2f8de06ea..76c1d7be1 100755 --- a/resources/statemachine.sh.in +++ b/resources/statemachine.sh.in @@ -1,7 +1,7 @@ #!/bin/sh RULE=' -s/[[:alnum:]]+\.setInitialState\(s([[:alnum:]]+)\)\;/[*] --> \1/p +s/auto[[:space:]]s([[:alnum:]]+)[[:space:]]=[[:space:]]addInitialState<[[:alnum:]]+>\(\);/[*] --> \1/p s/setInitialState\(s([[:alnum:]]+)\)\;/[*] --> \1/p s/auto[[:space:]]sFinal[[:space:]]=[[:space:]]addState\(\)\;/state Final #DarkSeaGreen/p s/[[:alnum:]]+\-.addTransition\(s([[:alnum:]]+)\,[[:space:]]+\&[[:alnum:]]+\:\:fire([[:alnum:]]+)\,[[:space:]]+s([[:alnum:]]+)\)\;/\1 --> \3 : \2/p @@ -22,6 +22,7 @@ function createImage { createImage @PROJECT_SOURCE_DIR@/src/workflows/base/states/CompositeStatePace.cpp @PROJECT_BINARY_DIR@/uml_CompositeStatePace createImage @PROJECT_SOURCE_DIR@/src/workflows/base/states/CompositeStateProcessCvcsAndSetRights.cpp @PROJECT_BINARY_DIR@/uml_CompositeStateProcessCvcsAndSetRights createImage @PROJECT_SOURCE_DIR@/src/workflows/base/states/CompositeStateTrustedChannel.cpp @PROJECT_BINARY_DIR@/uml_CompositeStateTrustedChannel +createImage @PROJECT_SOURCE_DIR@/src/workflows/personalization/states/CompositeStatePrepareApplet.cpp @PROJECT_BINARY_DIR@/uml_CompositeStatePrepareApplet createImage @PROJECT_SOURCE_DIR@/src/workflows/base/controller/ChangePinController.cpp @PROJECT_BINARY_DIR@/uml_ChangePinController createImage @PROJECT_SOURCE_DIR@/src/workflows/selfauth/controller/SelfAuthController.cpp @PROJECT_BINARY_DIR@/uml_SelfAuthController createImage @PROJECT_SOURCE_DIR@/src/workflows/base/controller/AuthController.cpp @PROJECT_BINARY_DIR@/uml_AuthController diff --git a/resources/template.html b/resources/template.html index 629fa4135..bda4b93c3 100644 --- a/resources/template.html +++ b/resources/template.html @@ -80,8 +80,8 @@ diff --git a/resources/translations/ausweisapp2_de.ts b/resources/translations/ausweisapp2_de.ts index e40e18354..275298374 100644 --- a/resources/translations/ausweisapp2_de.ts +++ b/resources/translations/ausweisapp2_de.ts @@ -5,7 +5,7 @@ DvcsAttributes revision - b9ade3b30f3d + 56dc58807a8c @@ -27,34 +27,56 @@ - AdditionalResultsFooterItem + AuthController - Additional results in other categories: %1. Click here to remove filter. - Weitere Ergebnisse in anderen Kategorien: %1. Klicken Sie hier, um den Filter zu entfernen. + Identify + LABEL ANDROID IOS + Ausweisen + + + Cancel authentication process + LABEL ANDROID IOS + Beende Ausweisvorgang - Additional results in other categories: - LABEL DESKTOP IOS_TABLET ANDROID_TABLET - Weitere Ergebnisse in anderen Kategorien: + Acquiring provider certificate + INFO ANDROID IOS Header of the progress status message during the authentication process. + Berechtigungszertifikat wird heruntergeladen - Show - Anzeigen + Authentication in progress + INFO ANDROID IOS Header of the progress status message during the authentication process. + Ausweisvorgang wird durchgeführt + + + Please wait a moment. + INFO ANDROID IOS Generic status message during the authentication process. + Bitte warten Sie einen Moment. + + + Please do not move the ID card. + INFO ANDROID IOS Second line text if a basic card reader is used and background communication with the card/server is running. Is not actually visible since the basic reader password handling is done by EnterPasswordView. + Bitte den Ausweis nicht bewegen. + + + Please observe the display of your card reader. + INFO ANDROID IOS The card reader requests the user's attention. + Bitte beachten Sie die Anzeige Ihres Kartenlesers. - - - AdditionalResultsItem - %1 additional results in other categories - %1 Ergebnisse in anderen Kategorien + A wrong PIN has been entered twice on your ID card. For a third attempt, please first enter the six-digit Card Access Number (CAN). You can find your CAN in the bottom right on the front of your ID card. + INFO ANDROID IOS The PIN was entered wrongfully two times, the third attempts requires additional CAN verification, hint where the CAN is found. + Die PIN Ihres Ausweises wurde zweimal falsch eingegeben. Für einen dritten Versuch geben Sie bitte zunächst die sechsstellige Zugangsnummer (CAN) ein. Diese finden Sie rechts unten auf der Vorderseite Ihres Ausweises. - Click to remove category filter and show additional results. - Klicken Sie hier, um den Filter zu entfernen. + Send log + LABEL ANDROID IOS + Protokoll senden - Additional results: - Weitere Ergebnisse: + Authenticate with provider + LABEL ANDROID IOS A11y button to confirm the PIN and start the provider authentication + Bei Anbieter ausweisen @@ -107,9 +129,7 @@ LABEL ANDROID IOS ---------- INFO DESKTOP Generic progress status message while no card communication is active. ---------- -INFO DESKTOP Generic progress status message during authentication. ----------- -INFO ANDROID IOS Generic status message during the authentication process. +INFO DESKTOP Generic progress status message during authentication. Bitte warten Sie einen Moment. @@ -119,23 +139,17 @@ INFO ANDROID IOS Generic status message during the authentication process. Acquiring provider certificate - INFO DESKTOP Header of the progress information during the authentication process. ----------- -INFO ANDROID IOS Header of the progress status message during the authentication process. + INFO DESKTOP Header of the progress information during the authentication process. Berechtigungszertifikat wird heruntergeladen Authentication in progress - INFO DESKTOP Header of the progress information during the authentication process. ----------- -INFO ANDROID IOS Header of the progress status message during the authentication process. + INFO DESKTOP Header of the progress information during the authentication process. Ausweisvorgang wird durchgeführt Please do not move the ID card. - INFO DESKTOP Second line text if a basic card reader is used and data is exchanged with the card/server in the background. Is not actually visible since the basic reader password handling is done by EnterPasswordView. ----------- -INFO ANDROID IOS Second line text if a basic card reader is used and background communication with the card/server is running. Is not actually visible since the basic reader password handling is done by EnterPasswordView. + INFO DESKTOP Second line text if a basic card reader is used and data is exchanged with the card/server in the background. Is not actually visible since the basic reader password handling is done by EnterPasswordView. Bitte den Ausweis nicht bewegen. @@ -143,31 +157,9 @@ INFO ANDROID IOS Second line text if a basic card reader is used and background INFO DESKTOP Error code (string) of current GlobalStatus code, shown as header of popup. Fehlercode: %1 - - Cancel authentication process - LABEL ANDROID IOS - Beende Ausweisvorgang - - - Please observe the display of your card reader. - INFO ANDROID IOS The card reader requests the user's attention. - Bitte beachten Sie die Anzeige Ihres Kartenlesers. - - - A wrong PIN has been entered twice on your ID card. For a third attempt, please first enter the six-digit Card Access Number (CAN). You can find your CAN in the bottom right on the front of your ID card. - INFO ANDROID IOS The PIN was entered wrongfully two times, the third attempts requires additional CAN verification, hint where the CAN is found. - Die PIN Ihres Ausweises wurde zweimal falsch eingegeben. Für einen dritten Versuch geben Sie bitte zunächst die sechsstellige Zugangsnummer (CAN) ein. Diese finden Sie rechts unten auf der Vorderseite Ihres Ausweises. - - - Send log - LABEL ANDROID IOS - Protokoll senden - Authenticate with provider - LABEL DESKTOP A11y button to confirm the PIN and start the provider authentication ----------- -LABEL ANDROID IOS A11y button to confirm the PIN and start the provider authentication + LABEL DESKTOP A11y button to confirm the PIN and start the provider authentication Bei Anbieter ausweisen @@ -210,52 +202,6 @@ LABEL ANDROID IOS A11y button to confirm the PIN and start the provider authenti Sie können nun Ihren Ausweis vom Gerät entfernen. - - BaseHistoryView - - History - INFO ANDROID IOS - Verlauf - - - Currently there are no history entries. - INFO ANDROID IOS No authentication history, placeholder text. - Derzeit gibt es keine Einträge im Verlauf. - - - - BaseProviderView - - No results matching your search query found - LABEL IOS_PHONE ANDROID_PHONE The text entered into the provider search field results in no matches - Keine Ergebnisse zu Ihrer Suche gefunden - - - Provider - LABEL IOS_TABLET ANDROID_TABLET - Anbieter - - - Citizen services - LABEL IOS_TABLET ANDROID_TABLET - Bürgerdienste - - - Financials - LABEL IOS_TABLET ANDROID_TABLET - Finanzen - - - Insurances - LABEL IOS_TABLET ANDROID_TABLET - Versicherungen - - - Other services - LABEL IOS_TABLET ANDROID_TABLET - Weitere Dienste - - BuildHelper @@ -307,13 +253,6 @@ LABEL ANDROID IOS A11y button to confirm the PIN and start the provider authenti OpenSSL-Version - - CancelAction - - Cancel - Abbrechen - - CardPositionView @@ -344,6 +283,7 @@ LABEL ANDROID IOS A11y button to confirm the PIN and start the provider authenti CardReaderView Connected USB card readers + LABEL DESKTOP Verbundene USB-Kartenleser @@ -358,47 +298,77 @@ LABEL ANDROID IOS A11y button to confirm the PIN and start the provider authenti After connecting a new card reader it may take a few seconds to recognize the driver. It may be necessary to restart your system after installing the driver. Only connected card readers are shown here. %1 Nachdem ein neuer Kartenleser angeschlossen worden ist, kann es einige Sekunden dauern bis der Treiber erkannt wird. Unter Umständen kann ein Neustart Ihres Betriebssystems notwendig sein. Es werden hier nur angeschlossene Kartenleser angezeigt. %1 + + No connected card reader found. + Keine angeschlossenen Kartenleser gefunden. + - Category + CertificateDescriptionPage - Provider - Anbieter + Provider Information + LABEL DESKTOP +---------- +LABEL ANDROID IOS + Anbieterinformationen + + + ChangePinController - All - Alle + Your ID card PIN is unblocked. You now have three more attempts to change your PIN. + INFO ANDROID IOS The ID card has just been unblocked and the user can now continue with their PIN change. + Ihre Karten-PIN wurde entsperrt. Sie haben nun drei weitere Versuche, um Ihre PIN zu ändern. - Citizen services - Bürgerdienste + Setting new Smart-eID PIN + LABEL ANDROID IOS Processing screen label while the card communication is running after the new Smart-eID PIN has been entered during PIN change process. + Neue Smart-eID-PIN wird gesetzt - Insurances - Versicherungen + Change Smart-eID PIN + LABEL ANDROID IOS Processing screen label while the card communication is running before the new ID card PIN has been entered during PIN change process. + Smart-eID-PIN ändern - Financials - Finanzen + Setting new ID card PIN + LABEL ANDROID IOS Processing screen label while the card communication is running after the new ID card PIN has been entered during PIN change process. + Neue Karten-PIN wird gesetzt - Other services - Weitere Dienste + Change ID card PIN + LABEL ANDROID IOS Processing screen label while the card communication is running before the new ID card PIN has been entered during PIN change process. + Karten-PIN ändern - - - CertificateDescriptionPage - Provider Information - LABEL DESKTOP ----------- -LABEL ANDROID IOS - Anbieterinformationen + Please wait a moment. + INFO ANDROID IOS Generic progress message during PIN change process. + Bitte warten Sie einen Moment. - Close - LABEL DESKTOP - Schließen + Please do not move the ID card. + INFO ANDROID IOS Loading screen during PIN change process, data communication is currently ongoing. Message is usually not visible since the password handling with basic reader is handled by EnterPasswordView. + Bitte den Ausweis nicht bewegen. + + + Please observe the display of your card reader. + INFO ANDROID IOS Either an comfort card reader or smartphone-as-card-reader is used, the user needs to react to request on that device. + Bitte beachten Sie die Anzeige Ihres Kartenlesers. + + + A wrong ID card PIN has been entered twice on your ID card. For a third attempt, please first enter the six-digit Card Access Number (CAN). You can find your CAN in the bottom right on the front of your ID card. + INFO ANDROID IOS The wrong ID card PIN was entered twice, the next attempt requires additional verifcation via CAN. + Die Karten-PIN Ihres Ausweises wurde zweimal falsch eingegeben. Für einen dritten Versuch geben Sie bitte zunächst die sechsstellige Zugangsnummer (CAN) ein. Diese finden Sie rechts unten auf der Vorderseite Ihres Ausweises. + + + You have entered an incorrect, six-digit ID card PIN thrice, your ID card PIN is now blocked. To remove the block, the ten-digit PUK must be entered first. + INFO ANDROID IOS The ID card PIN (including the CAN) was entered wrongfully three times, the PUK is required to unlock the ID card. + Sie haben dreimal eine falsche, sechsstellige Karten-PIN eingegeben, Ihre Karten-PIN ist nun gesperrt. Um die Sperre aufzuheben, muss zunächst die zehnstellige PUK eingegeben werden. + + + Please note that you may use the five-digit Transport PIN only once to change to a six-digit ID card PIN. If you already set a six-digit ID card PIN, the five-digit Transport PIN is no longer valid. + INFO ANDROID IOS + Bitte beachten Sie, dass Sie die fünfstellige Transport-PIN nur einmalig zum Ändern in eine sechsstellige Karten-PIN verwenden können. Wenn Sie bereits eine sechsstellige Karten-PIN festgelegt haben, ist die fünfstellige Transport-PIN nicht mehr gültig. @@ -419,16 +389,12 @@ LABEL ANDROID IOS Please do not move the ID card. - INFO DESKTOP Processing screen text while the card communication is running after the PIN has been entered during PIN change process. ----------- -INFO ANDROID IOS Loading screen during PIN change process, data communication is currently ongoing. Message is usually not visible since the password handling with basic reader is handled by EnterPasswordView. + INFO DESKTOP Processing screen text while the card communication is running after the PIN has been entered during PIN change process. Bitte den Ausweis nicht bewegen. Your ID card PIN is unblocked. You now have three more attempts to change your PIN. - INFO DESKTOP The ID card has just been unblocked and the user can now continue with their ID card PIN change. ----------- -INFO ANDROID IOS The ID card has just been unblocked and the user can now continue with their PIN change. + INFO DESKTOP The ID card has just been unblocked and the user can now continue with their ID card PIN change. Ihre Karten-PIN wurde entsperrt. Sie haben nun drei weitere Versuche, um Ihre PIN zu ändern. @@ -451,61 +417,21 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin - stellen Sie sicher, dass der Ausweis korrekt auf dem Kartenleser positioniert ist - bewegen Sie den Ausweis nicht, während auf diesen zugegriffen wird - - Change my (Transport) PIN - LABEL ANDROID IOS - Meine (Transport-)​PIN ändern - Change Transport PIN LABEL ANDROID IOS Transport-PIN ändern - - Setting new Smart-eID PIN - LABEL ANDROID IOS Processing screen label while the card communication is running after the new Smart-eID PIN has been entered during PIN change process. - Neue Smart-eID-PIN wird gesetzt - - - Change Smart-eID PIN - LABEL ANDROID IOS Processing screen label while the card communication is running before the new ID card PIN has been entered during PIN change process. - Smart-eID-PIN ändern - - - Setting new ID card PIN - LABEL ANDROID IOS Processing screen label while the card communication is running after the new ID card PIN has been entered during PIN change process. - Neue Karten-PIN wird gesetzt - - - Change ID card PIN - LABEL ANDROID IOS Processing screen label while the card communication is running before the new ID card PIN has been entered during PIN change process. - Karten-PIN ändern - - - Please wait a moment. - INFO ANDROID IOS Generic progress message during PIN change process. - Bitte warten Sie einen Moment. - - - Please observe the display of your card reader. - INFO ANDROID IOS Either an comfort card reader or smartphone-as-card-reader is used, the user needs to react to request on that device. - Bitte beachten Sie die Anzeige Ihres Kartenlesers. - - - A wrong ID card PIN has been entered twice on your ID card. For a third attempt, please first enter the six-digit Card Access Number (CAN). You can find your CAN in the bottom right on the front of your ID card. - INFO ANDROID IOS The wrong ID card PIN was entered twice, the next attempt requires additional verification via CAN. - Die Karten-PIN Ihres Ausweises wurde zweimal falsch eingegeben. Für einen dritten Versuch geben Sie bitte zunächst die sechsstellige Zugangsnummer (CAN) ein. Diese finden Sie unten rechts auf der Vorderseite Ihres Ausweises. - - - You have entered an incorrect, six-digit ID card PIN thrice, your ID card PIN is now blocked. To remove the block, the ten-digit PUK must be entered first. - INFO ANDROID IOS The ID card PIN (including the CAN) was entered wrongfully three times, the PUK is required to unlock the ID card. - Sie haben dreimal eine falsche, sechsstellige Karten-PIN eingegeben, Ihre Karten-PIN ist nun gesperrt. Um die Sperre aufzuheben, muss zunächst die zehnstellige PUK eingegeben werden. - The device "%1" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. INFO DESKTOP The paired devices was removed since it did not respond to connection attempts. It needs to be paired again if it should be used as card reader. Das Gerät "%1" wurde entkoppelt, da es nicht auf Verbindungsversuche reagiert hat. Koppeln Sie das Gerät erneut, um es wieder als Kartenleser zu verwenden. + + Please note that you may use the five-digit Transport PIN only once to change to a six-digit ID card PIN. If you already set a six-digit ID card PIN, the five-digit Transport PIN is no longer valid. + INFO DESKTOP + Bitte beachten Sie, dass Sie die fünfstellige Transport-PIN nur einmalig zum Ändern in eine sechsstellige Karten-PIN verwenden können. Wenn Sie bereits eine sechsstellige Karten-PIN festgelegt haben, ist die fünfstellige Transport-PIN nicht mehr gültig. + ChangePinViewContent @@ -797,207 +723,145 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin CheckSmartResultView - Check Smart-eID + Unknown result code: %1 LABEL ANDROID IOS - Smart-eID prüfen + Unbekannter Ergebniscode: %1 - Result of Smart-eID check + Please wait a moment. LABEL ANDROID IOS - Ergebnis der Smart-eID-Prüfung + Bitte warten Sie einen Moment. - Continue + Updating Smart-eID status... LABEL ANDROID IOS - Fortsetzen + Status der Smart-eID wird aktualisiert... - What does that mean? + Check device and ID card LABEL ANDROID IOS - Was bedeutet das? - - - You may now try the function: "See my personal data". Press the Continue button to do so now. - Probieren Sie zum Abschluss der Prüfung die Funktion "Meine Daten einsehen". Drücken Sie Fortsetzen um fortzufahren. + Gerät und Ausweis prüfen - Supported + Your mobile device does not meet the technical requirements for Smart-eID.<br><br>You may check if your device and ID card are suitable to use the eID function. LABEL ANDROID IOS - Unterstützt + Ihr Gerät erfüllt leider nicht die technischen Voraussetzungen für die Smart-eID.<br><br>Sie können stattdessen prüfen, ob Ihr Gerät und Ihr Ausweis für die Online-Ausweisfunktion geeignet sind. - Not supported + Smart-eID not supported LABEL ANDROID IOS - Nicht unterstützt + Smart-eID nicht unterstützt - Prepared + Possible causes are: LABEL ANDROID IOS - Vorbereitet + Mögliche Ursachen hierfür sind: - Not prepared + The setup has not been completed. LABEL ANDROID IOS - Nicht vorbereitet + Die Einrichtung wurde nicht vollständig abgeschlossen. - Set up + The Smart-eID PIN has been entered incorrectly three times. LABEL ANDROID IOS - Eingerichtet + Die Smart-eID-PIN wurde drei mal falsch eingegeben. - Not set up + The %1 has been uninstalled temporarily. LABEL ANDROID IOS - Nicht eingerichtet + Die %1 wurde zwischenzeitlich deinstalliert. - Invalid + You may continue with the setup of the Smart-eID. LABEL ANDROID IOS - Ungültig + Sie können mit der Einrichtung der Smart-eID fortfahren. - Ready for use + Continue LABEL ANDROID IOS - Einsatzbereit + Fortsetzen - - - CheckSmartSuggestionView - Unknown result code: %1 + Your device meets the technical requirements for Smart-eID. You may now continue the setup process. LABEL ANDROID IOS - Unbekannter Ergebniscode: %1 + Ihr Gerät erfüllt die technischen Voraussetzung für die Smart-eID. Sie können mit der Einrichtung fortfahren. - Updating Smart-eID status... + Smart-eID supported LABEL ANDROID IOS - Status der Smart-eID wird aktualisiert... + Smart-eID unterstützt - Please wait a moment. - LABEL ANDROID IOS - Bitte warten Sie einen Moment. + Your device meets the technical requirements for Smart-eID, however, the Smart-eID that was set up is invalid. + LABEL ANDROID IOS LABEL ANDROID IOS + Ihr Gerät erfüllt die technischen Voraussetzungen für die Smart-eID, allerdings ist die eingerichtete Smart-eID ungültig. - Smart-eID not supported + Smart-eID invalid LABEL ANDROID IOS - Smart-eID nicht unterstützt + Smart-eID ungültig - Your mobile device does not meet the technical requirements for Smart-eID.<br><br>You may check if your device and ID card are suitable to use the eID function. + Smart-eID check failed LABEL ANDROID IOS - Ihr Gerät erfüllt leider nicht die technischen Voraussetzungen für die Smart-eID.<br><br>Sie können stattdessen prüfen, ob Ihr Gerät und Ihr Ausweis für die Online-Ausweisfunktion geeignet sind. + Smart-eID-Prüfung fehlgeschlagen - Check device and ID card + Back LABEL ANDROID IOS - Gerät und Ausweis prüfen + Zurück + + + ConnectSacView - Smart-eID invalid - LABEL ANDROID IOS - Smart-eID ungültig - - - Your device meets the technical requirements for Smart-eID, however, the Smart-eID that was set up is invalid. - LABEL ANDROID IOS LABEL ANDROID IOS - Ihr Gerät erfüllt die technischen Voraussetzungen für die Smart-eID, allerdings ist die eingerichtete Smart-eID ungültig. - - - Possible causes are: - LABEL ANDROID IOS - Mögliche Ursachen hierfür sind: - - - The setup has not been completed. - LABEL ANDROID IOS - Die Einrichtung wurde nicht vollständig abgeschlossen. - - - The preparation for the Smart-eID is defective. - LABEL ANDROID IOS - Die Vorbereitung für die Smart-eID ist defekt. - - - The Smart-eID PIN has been entered incorrectly three times. - LABEL ANDROID IOS - Die Smart-eID-PIN wurde drei mal falsch eingegeben. - - - The AusweisApp2 has been uninstalled temporarily. - LABEL ANDROID IOS - Die AusweisApp2 wurde zwischenzeitlich deinstalliert. - - - Please restart the setup of the Smart-eID. - LABEL ANDROID IOS - Bitte starten Sie die Einrichtung der Smart-eID erneut. - - - Set up Smart-eID - LABEL ANDROID IOS - Smart-eID einrichten - - - Smart-eID not prepared - LABEL ANDROID IOS - Smart-eID nicht vorbereitet - - - Your device meets the technical requirements for Smart-eID, but is not yet provisioned for setup. The provisioning is done automatically during the Smart-eID setup process. - LABEL ANDROID IOS - Ihr Gerät erfüllt die technischen Voraussetzungen für die Smart-eID, ist jedoch noch nicht für die Einrichtung vorbereitet. Die Vorbereitung erfolgt während der Smart-eID-Einrichtung automatisch. + Pairing + LABEL DESKTOP + Kopplung - Smart-eID not set up - LABEL ANDROID IOS - Smart-eID nicht eingerichtet + Pairing the device ... + LABEL DESKTOP + Das Gerät wird gekoppelt ... - Your device meets the technical requirements for Smart-eID and is already provisioned for setup. You can now start the Smart-eID setup. - LABEL ANDROID IOS - Ihr Gerät erfüllt die technischen Voraussetzungen für die Smart-eID und ist bereits für die Einrichtung vorbereitet. Sie können nun mit der Smart-eID-Einrichtung beginnen. + Pairing to "%1" failed: + ERROR DESKTOP An error occurred while pairing the device. + Die Kopplung mit "%1" ist fehlgeschlagen: - CheckSmartView - - Check Smart-eID - LABEL ANDROID IOS - Smart-eID prüfen - + DarkModeButtons - Your device needs to meet the technical requirements to use the Smart-eID function. - LABEL ANDROID IOS - Um die Smart-eID-Funktion nutzen zu können, muss Ihr Gerät die technischen Voraussetzungen erfüllen. + System + LABEL ALL_PLATFORMS + Systemeinstellungen - Check here if your device is suitable to set up a Smart-eID. - LABEL ANDROID IOS - Prüfen Sie hier, ob Ihr Gerät für die Einrichtung einer Smart-eID geeignet ist. + Dark + LABEL ALL_PLATFORMS + Dunkel - Start check - LABEL ANDROID IOS - Prüfung starten + Light + LABEL ALL_PLATFORMS + Hell - - - ConnectSacView - Pairing - LABEL DESKTOP - Kopplung + Set the app appearance to system mode + LABEL ALL_PLATFORMS + Setzt das Erscheinungsbild der Anwendung auf die Systemeinstellungen - Pairing the device ... - LABEL DESKTOP - Das Gerät wird gekoppelt ... + Set the app appearance to dark mode + LABEL ALL_PLATFORMS + Setzt das Erscheinungsbild der Anwendung auf dunkel - Pairing to "%1" failed: - ERROR DESKTOP An error occurred while pairing the device. - Die Kopplung mit "%1" ist fehlgeschlagen: + Set the app appearance to light mode + LABEL ALL_PLATFORMS + Setzt das Erscheinungsbild der Anwendung auf hell @@ -1023,11 +887,6 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin LABEL DESKTOP Protokolldatei - - History - LABEL DESKTOP - Verlauf - Show beta testing image LABEL DESKTOP @@ -1043,6 +902,16 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin LABEL DESKTOP Überspringe Berechtigungen-Seite im CAN-erlaubt-Modus + + Reset hideable dialogs + LABEL DESKTOP + Setze versteckbare Dialoge zurück + + + Show Transport PIN reminder, store feedback and close reminder dialogs. + LABEL DESKTOP + Zeige Transport-PIN Hinweis, Store Feedback und Fenster-Schließ Hinweis Dialoge. + DecisionView @@ -1051,11 +920,6 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin LABEL DESKTOP Nein - - Maybe - LABEL DESKTOP - Vielleicht - Yes LABEL DESKTOP @@ -1125,11 +989,6 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin LABEL DESKTOP Testmodus für die Selbstauskunft - - Enable internal card simulator - LABEL DESKTOP - Aktiviere den internen Kartensimulator - The internal card simulator allows to run an authentication in the test PKI without any ID card or card reader. Note that no other card reader can be used while the simulator is activated. LABEL DESKTOP @@ -1140,11 +999,6 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin LABEL DESKTOP Entwicklermodus - - The developer mode is aimed at integrators / developers for new service applications. For this reason, the developer mode works only in the test PKI. By activating the developer mode, some safety tests are deactivated. This means that the authentication process continues although the AusweisApp2 would usually abort the process with an error message when used in normal operation mode. Information on the disregarded error in the developer mode is displayed in the attached window below the AusweisApp2. - LABEL DESKTOP - Der Entwicklermodus richtet sich an Integratoren / Entwickler für neue Dienste. Aus diesem Grund funktioniert der Entwicklermodus lediglich in der Test-PKI. Durch Aktivierung des Entwicklermodus werden einige Sicherheitsprüfungen abgestellt. Die Authentisierung wird auch dann weitergeführt, wenn die AusweisApp2 im Normalbetrieb die Authentisierung mit einer Fehlermeldung abbrechen würde. Der übergangene Fehler im Entwicklermodus wird im angehängten Fenster unterhalb der AusweisApp2 angezeigt. - Custom config.json LABEL DESKTOP @@ -1170,6 +1024,21 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin LABEL DESKTOP JSON-Konfigurationsdatei (*.json) + + Allow test sample card usage + LABEL DESKTOP + Testmusterkarten erlauben + + + Internal card simulator + LABEL DESKTOP + Interner Kartensimulator + + + The developer mode deactivates some security checks and the authentication process will continue even if some errors occur. Skipped errors will be shown as notifications. The developer mode is only usable with the test PKI. + LABEL DESKTOP + Im Entwicklermodus werden einige Sicherheitsprüfungen abgestellt und die Authentisierung bei bestimmten Fehlern trotzdem fortgesetzt. Übergangene Fehler werden in den Benachrichtigungen angezeigt. Der Entwicklermodus funktioniert nur in der Test-PKI. + DevicesListDelegate @@ -1180,15 +1049,6 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin DiagnosisView - - Diagnosis - LABEL DESKTOP - Diagnose - - - Save diagnosis to textfile - Speichere Diagnose in Textdatei - Save to file LABEL DESKTOP @@ -1210,138 +1070,111 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin Textdateien (*.txt) - Save diagnosis + System data LABEL DESKTOP - Diagnose speichern + Systemdaten - - - EditRights - You are about to identify yourself towards the following provider - LABEL DESKTOP - Sie möchten sich bei folgendem Anbieter ausweisen + Save system data to textfile + Speichere Systemdaten in Textdatei - Show more information about the service provider - Zeige mehr Informationen über den Anbieter + SystemData + Systemdaten - Details about the provider - LABEL DESKTOP ----------- -LABEL ANDROID_TABLET IOS_TABLET - Details zum Anbieter + Save system data + LABEL DESKTOP + Systemdaten speichern + + + EditRights Proceed to %1 entry LABEL DESKTOP %1 can be "CAN" or "PIN" ---------- -LABEL IOS_PHONE ANDROID_PHONE %1 can be "CAN" or "PIN" ----------- -LABEL ANDROID_TABLET IOS_TABLET %1 can be "CAN" or "PIN" +LABEL IOS_PHONE ANDROID_PHONE %1 can be "CAN" or "PIN" Weiter zur %1-Eingabe CAN LABEL DESKTOP Inserted into "Proceed to %1 entry" ---------- -LABEL IOS_PHONE Inserted into "Proceed to %1 entry" ----------- -LABEL ANDROID_TABLET IOS_TABLET Inserted into "Proceed to %1 entry" +LABEL IOS_PHONE Inserted into "Proceed to %1 entry" CAN PIN LABEL DESKTOP Inserted into "Proceed to %1 entry" ---------- -LABEL IOS_PHONE Inserted into "Proceed to %1 entry" ----------- -LABEL ANDROID_TABLET IOS_TABLET Inserted into "Proceed to %1 entry" +LABEL IOS_PHONE Inserted into "Proceed to %1 entry" PIN By entering the CAN, access to the following data of the ID card will be allowed to the mentioned provider: LABEL DESKTOP ---------- -LABEL IOS_PHONE ANDROID_PHONE ----------- -LABEL ANDROID_TABLET IOS_TABLET +LABEL IOS_PHONE ANDROID_PHONE Mit Eingabe der CAN gewähren Sie dem oben genannten Anbieter folgende Datenzugriffe auf den Ausweis: By entering your PIN, access to the following data of your ID card will be allowed to the mentioned provider: LABEL DESKTOP ---------- -LABEL IOS_PHONE ANDROID_PHONE ----------- -LABEL ANDROID_TABLET IOS_TABLET +LABEL IOS_PHONE ANDROID_PHONE Mit Eingabe Ihrer PIN gewähren Sie dem oben genannten Anbieter folgende Datenzugriffe auf Ihren Ausweis: Transactional information LABEL DESKTOP ---------- -LABEL IOS_PHONE ANDROID_PHONE ----------- -LABEL ANDROID_TABLET IOS_TABLET +LABEL IOS_PHONE ANDROID_PHONE Transaktionsinformationen The provider mentioned above does not require any data stored on your ID card, only confirmation of you possessing a valid ID card. LABEL DESKTOP ---------- -LABEL IOS_PHONE ANDROID_PHONE ----------- -LABEL ANDROID_TABLET IOS_TABLET +LABEL IOS_PHONE ANDROID_PHONE Der oben genannte Anbieter benötigt keine Daten von Ihrem Ausweis. Dieser möchte lediglich sicherstellen, dass Sie im Besitz eines gültigen Ausweises sind. Write access (update) LABEL DESKTOP ---------- -LABEL IOS_PHONE ANDROID_PHONE ----------- -LABEL ANDROID_TABLET IOS_TABLET +LABEL IOS_PHONE ANDROID_PHONE Schreibzugriff (Aktualisierung) Read access LABEL DESKTOP ---------- -LABEL IOS_PHONE ANDROID_PHONE ----------- -LABEL ANDROID_TABLET IOS_TABLET +LABEL IOS_PHONE ANDROID_PHONE Lesezugriff Read access (optional) LABEL DESKTOP ---------- -LABEL IOS_PHONE ANDROID_PHONE ----------- -LABEL ANDROID_TABLET IOS_TABLET +LABEL IOS_PHONE ANDROID_PHONE Lesezugriff (optional) Identify - LABEL IOS_PHONE ANDROID_PHONE ----------- -LABEL ANDROID_TABLET IOS_TABLET + LABEL IOS_PHONE ANDROID_PHONE Ausweisen You are about to identify yourself towards the following provider: - LABEL IOS_PHONE ANDROID_PHONE + LABEL DESKTOP ---------- -LABEL ANDROID_TABLET IOS_TABLET +LABEL IOS_PHONE ANDROID_PHONE Sie möchten sich bei folgendem Anbieter ausweisen: Provider - LABEL IOS_PHONE ANDROID_PHONE ----------- -LABEL ANDROID_TABLET IOS_TABLET + LABEL IOS_PHONE ANDROID_PHONE Anbieter @@ -1357,11 +1190,6 @@ LABEL ANDROID_TABLET IOS_TABLET LABEL DESKTOP Versuche - - Remaining ID card PIN attempts: %1 - LABEL DESKTOP - Verbleibende Karten-PIN Versuche: %1 - Enter CAN LABEL DESKTOP @@ -1411,13 +1239,6 @@ LABEL ANDROID IOS LABEL ANDROID IOS Karten-PIN eingeben - - The new ID card PIN and the confirmation do not match. Please correct your input. - INFO DESKTOP The changed ID card PIN was entered wrongfully during the confirmation process. ----------- -INFO ANDROID IOS The changed ID card PIN was entered wrongfully during confirmation. - Die neue Karten-PIN und ihre Wiederholung stimmen nicht überein. Bitte korrigieren Sie Ihre Eingabe. - Please enter the five-digit Transport PIN. INFO DESKTOP The AA2 expects the Transport PIN with five digits. @@ -1505,18 +1326,9 @@ LABEL ANDROID IOS LABEL ANDROID IOS Neue Smart-eID-PIN bestätigen - - The new Smart-eID PIN and the confirmation do not match. Please correct your input. - INFO DESKTOP The changed Smart-eID PIN was entered wrongfully during the confirmation process. ----------- -INFO ANDROID IOS The changed Smart-eID PIN was entered wrongfully during confirmation. - Die neue Smart-eID-PIN und ihre Wiederholung stimmen nicht überein. Bitte korrigieren Sie Ihre Eingabe. - You have entered an incorrect, six-digit Smart-eID PIN twice. An incorrect third attempt will invalidate your Smart-eID and you will have to set it up again. - INFO DESKTOP The wrong Smart-eID PIN was entered twice on the Smart-eID ----------- -INFO ANDROID IOS The wrong Smart-eID PIN was entered twice on the Smart-eID + INFO DESKTOP The wrong Smart-eID PIN was entered twice on the Smart-eID Sie haben zweimal eine falsche, sechsstellige Smart-eID-PIN eingegeben. Ein dritter Fehlversuch wird Ihre Smart-eID ungültig machen und Sie müssen sie neu einrichten. @@ -1557,6 +1369,11 @@ INFO ANDROID IOS The AA2 expects a Smart-eID PIN with six digits in an authentic LABEL ANDROID IOS Button to switch to a six-digit ID card PIN. Haben Sie eine sechsstellige Karten-PIN? + + You have entered an incorrect, six-digit Smart-eID PIN twice. After the next failed attempt you will no longer be able to use your Smart-eID and will need to set it up again. + INFO ANDROID IOS The wrong Smart-eID PIN was entered twice on the Smart-eID + Sie haben zweimal eine falsche, sechsstellige Smart-eID-PIN eingegeben. Nach dem nächsten Fehlversuch können Sie Ihre Smart-eID nicht mehr einsetzen und müssen diese neu einrichten. + Send CAN LABEL DESKTOP @@ -1613,12 +1430,40 @@ LABEL ANDROID IOS LABEL ANDROID IOS Karten-PIN senden + + Send confirmation of new ID card PIN + LABEL ANDROID IOS + Bestätigung der neuen Karten-PIN senden + + + Send confirmation of new Smart-eID PIN + LABEL ANDROID IOS + Bestätigung der neuen Smart-eID-PIN senden + Enter the pairing code shown on your smartphone. INFO DESKTOP The pairing code needs to be supplied. Geben Sie den Kopplungscode ein, der auf Ihrem Smartphone angezeigt wird. + + GCollapsible + + collapse + LABEL ANDROID IOS + einklappen + + + expand + LABEL ANDROID IOS + ausklappen + + + Currently selected is %1 + LABEL ANDROID IOS + Aktuell ausgewählt ist %1 + + GProgressBar @@ -1659,34 +1504,49 @@ LABEL ANDROID IOS %1 automatisch beim Hochfahren starten und als Eintrag der Menüleiste hinzufügen - Auto-start %1 after boot - LABEL WINDOWS Text for auto-start option - %1 automatisch beim Hochfahren starten + Using the developer mode forces the notifications to be enabled. + LABEL DESKTOP Only visible when the user activates the developer mode in the settings. + Im Entwicklermodus werden die internen Benachrichtigungen erzwungen. - Close after authentication + Network LABEL DESKTOP - Nach Authentisierung schließen + Netzwerk - Use internal notifications + Use the proxy (%1) specified during the installation. LABEL DESKTOP - Interne Benachrichtigungen aktivieren + Benutze den bei der Installation angegebenen Proxy (%1). - Using the developer mode forces the notifications to be enabled. - LABEL DESKTOP Only visible when the user activates the developer mode in the settings. - Im Entwicklermodus werden die internen Benachrichtigungen erzwungen. + Appearance + LABEL DESKTOP + Erscheinungsbild - Network + Use the system font LABEL DESKTOP - Netzwerk + Systemschriftart verwenden - Use the proxy (%1) specified during the installation. + Toggling will restart the %1 LABEL DESKTOP - Benutze den bei der Installation angegebenen Proxy (%1). + Ein Umschalten startet die %1 neu + + + Close %1 after authentication + LABEL DESKTOP + %1 nach Authentisierung schließen + + + Show notifications inside of %1 + LABEL DESKTOP + Benachrichtigungen in der %1 anzeigen + + + Auto-start %1 after boot and add a tray icon + LABEL WINDOWS Text for auto-start option + %1 automatisch beim Hochfahren starten und im Benachrichtigungsfeld hinzufügen @@ -1696,10 +1556,6 @@ LABEL ANDROID IOS LABEL DESKTOP Versuche - - Remaining ID card PIN attempts: %1 - Verbleibende Karten-PIN Versuche: %1 - Step %1 of 3 Schritt %1 von 3 @@ -1729,16 +1585,6 @@ LABEL ANDROID IOS INFO DESKTOP The AA2 is waiting for an ID card to be inserted into the card reader. Es wurde kein Ausweis erkannt. Bitte stellen Sie sicher, dass Ihr Ausweis auf dem Kartenleser aufliegt. - - No ID card detected. Please make sure that the NFC interface of the smartphone (connected to %1) is correctly placed on your ID card. - INFO DESKTOP The AA2 is waiting for the smartphone to be placed on the id. - Es wurde kein Ausweis erkannt. Bitte stellen Sie sicher, dass die NFC-Schnittstelle des Smartphones (verbunden mit %1) korrekt auf Ihrem Ausweis platziert ist. - - - Please place the smartphone (connected to %1) on your ID card or put the ID card on the card reader. - INFO DESKTOP The AA2 is waiting for an ID card to be inserted into the card reader (or smartphone for that matter). - Bitte platzieren Sie das Smartphone (verbunden mit %1) auf Ihrem Ausweis oder legen Sie den Ausweis auf den Kartenleser. - No card reader detected. Please make sure that an USB card reader is connected or a smartphone as card reader is paired and available. Open the reader settings to configure readers and get more information about supported readers. INFO DESKTOP AA2 is waiting for the card reader or the ID card. @@ -1755,263 +1601,62 @@ LABEL ANDROID IOS Zu den Einstellungen - The device "%1" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. - INFO ANDROID IOS The paired smartphone was removed since it did not respond to connection attempts. It needs to be paired again before using it. - Das Gerät "%1" wurde entkoppelt, da es nicht auf Verbindungsversuche reagiert hat. Koppeln Sie das Gerät erneut, um es wieder als Kartenleser zu verwenden. + No ID card detected. Please follow the instructions on your smartphone (connected to %1) to use it as card reader. + INFO DESKTOP The AA2 is waiting for the smartphone to be placed on the id. + Es wurde kein Ausweis erkannt. Bitte folgen Sie den Anweisungen auf Ihrem Smartphone (verbunden mit %1), um es als Kartenleser zu verwenden. + + + Please follow the instructions on your smartphone (connected to %1) or put the ID card on the card reader. + INFO DESKTOP The AA2 is waiting for an ID card to be inserted into the card reader (or smartphone for that matter). + Bitte folgen Sie den Anweisungen auf Ihrem Smartphone (verbunden mit %1) oder legen Sie den Ausweis auf den Kartenleser. Hint Hint + LABEL DESKTOP +---------- +LABEL ANDROID IOS Tipp - HistoryListItem + LanguageButtonData - Click to view details of history entry. - LABEL ANDROID IOS - Zeige Details des Verlaufseintrags. + German + LABEL ALL_PLATFORMS + Deutsch - Tap for more details - LABEL ANDROID IOS - Berühren Sie hier für mehr Details + Set language to german + LABEL ALL_PLATFORMS + Verwende deutsche Sprache - - - HistoryListViewDelegate - Delete entry - LABEL ANDROID - Lösche Eintrag + English + LABEL ALL_PLATFORMS + Englisch - Delete history entry: %1 - INFO IOS Accessible name for the trash icon of a history entry. - Lösche Verlaufseintrag: %1 + Set language to english + LABEL ALL_PLATFORMS + Verwende englische Sprache - - - HistoryRemovalTimePeriodControl - Time period - LABEL DESKTOP - Zeitspanne + Ukrainian + LABEL ALL_PLATFORMS + Ukrainisch - Past hour - LABEL DESKTOP - Letzte Stunde + Set language to ukrainian + LABEL ALL_PLATFORMS + Verwende ukrainische Sprache - Past day - LABEL DESKTOP - Letzter Tag - - - Past week - LABEL DESKTOP - Letzte Woche - - - Last four weeks - LABEL DESKTOP - Letzte vier Wochen - - - All history - LABEL DESKTOP - Gesamter Zeitraum - - - - HistoryView - - Delete history? - INFO DESKTOP Header of the confirmation dialog to clear the entire authentication history. - Verlauf löschen? - - - All history entries will be deleted. - INFO DESKTOP Content of the confirmation dialog to clear the entire authentication history. - Alle im Verlauf gespeicherten Informationen werden gelöscht. - - - Deleted %1 entries from the history. - INFO DESKTOP Feedback how many history entries were removed. - Es wurden %1 Einträge aus dem Verlauf gelöscht. - - - History - LABEL DESKTOP - Verlauf - - - Search in history - LABEL DESKTOP - Im Verlauf suchen - - - Clear history - LABEL DESKTOP - Lösche Verlauf - - - Save as PDF... - LABEL DESKTOP - Als PDF speichern... - - - Portable Document Format (*.pdf) - LABEL DESKTOP - Portables Dokumentenformat (*.pdf) - - - Currently there are no history entries. - INFO DESKTOP No authentication history, placeholder text. - Derzeit gibt es keine Einträge im Verlauf. - - - No history entries match your search term. - INFO DESKTOP No authentication history entries match the search, placeholder text. - Es wurden keine Verlaufseinträge zu Ihrer Suche gefunden. - - - Delete all entries - LABEL IOS - Alle Einträge löschen - - - Save history - LABEL DESKTOP - Verlauf speichern - - - - HistoryViewConfirmationPopup - - Delete history - LABEL ANDROID IOS - Verlauf löschen - - - All history entries will be deleted. - LABEL ANDROID IOS Confirmaton popup to clear all history entries. - Alle im Verlauf gespeicherten Informationen werden gelöscht. - - - Delete - LABEL ANDROID IOS - Löschen - - - - HistoryViewDetails - - Details for history entry - Details des Verlaufseintrags - - - Provider Information - LABEL ANDROID IOS - Anbieterinformationen - - - Provider name - LABEL DESKTOP ----------- -LABEL ANDROID IOS - Anbieter - - - Purpose - LABEL DESKTOP ----------- -LABEL ANDROID IOS - Zweck - - - Date - LABEL DESKTOP ----------- -LABEL ANDROID IOS - Datum - - - dd.MM.yyyy - LABEL DESKTOP Date format according to https://doc.qt.io/qt/qdate.html#toString ----------- -LABEL ANDROID IOS Date format according to https://doc.qt.io/qt/qdate.html#toString - dd.MM.yyyy - - - Write access (update) - LABEL DESKTOP ----------- -LABEL ANDROID IOS - Schreibzugriff (Aktualisierung) - - - Read access - LABEL DESKTOP ----------- -LABEL ANDROID IOS - Lesezugriff - - - Terms of usage - LABEL DESKTOP ----------- -LABEL ANDROID IOS - Nutzungsbedingungen - - - - HistoryViewTitleBarControls - - Delete all entries - LABEL ANDROID - Lösche alle Einträge - - - - LanguageButtons - - German - LABEL ALL_PLATFORMS - Deutsch - - - Set language to german - LABEL ALL_PLATFORMS - Verwende deutsche Sprache - - - English - LABEL ALL_PLATFORMS - Englisch - - - Set language to english - LABEL ALL_PLATFORMS - Verwende englische Sprache - - - Ukrainian - LABEL ALL_PLATFORMS - Ukrainisch - - - Set language to ukrainian - LABEL ALL_PLATFORMS - Verwende ukrainische Sprache - - - Russian - LABEL ALL_PLATFORMS - Russisch + Russian + LABEL ALL_PLATFORMS + Russisch Set language to russian @@ -2019,14 +1664,6 @@ LABEL ANDROID IOS Verwende russische Sprache - - LanguageSelectionPopup - - Select language - LABEL ANDROID IOS - Sprache auswählen - - LicenseInformation @@ -2164,6 +1801,14 @@ INFO ANDROID IOS The current logfile is about to be removed, user confirmation r Derzeit gibt es keine Einträge im Log die zu Ihrem Filter passen. + + LogViewDelegate + + The log entry was copied to the clipboard. + INFO DESKTOP Toast message used to confirm the copy of a log entry. + Der Protokolleintrag wurde in die Zwischenablage kopiert. + + MainView @@ -2171,28 +1816,11 @@ INFO ANDROID IOS The current logfile is about to be removed, user confirmation r LABEL DESKTOP Meine Daten<br>einsehen - - Provider - LABEL DESKTOP ----------- -LABEL ANDROID IOS - Anbieter - - - History - LABEL DESKTOP - Verlauf - Settings LABEL DESKTOP Einstellungen - - Change my<br>(Transport) PIN - LABEL DESKTOP - Meine (Transport-)<br>PIN ändern - Help LABEL DESKTOP @@ -2208,11 +1836,6 @@ LABEL ANDROID IOS LABEL ANDROID IOS Gerät und Ausweis prüfen - - Change my (Transport) PIN - LABEL ANDROID IOS - Meine (Transport-)​PIN ändern - See my personal data LABEL ANDROID IOS @@ -2223,6 +1846,25 @@ LABEL ANDROID IOS LABEL ANDROID IOS Smart-eID + + Two finger swipe to scroll. + Mit zwei Fingern wischem zum Scrollen. + + + List of workflows with %1 items. + Liste mit %1 Vorgängen. + + + Item %1 of %2 + Element %1 von %2 + + + Change PIN + LABEL DESKTOP +---------- +LABEL ANDROID IOS + PIN ändern + MoreInformationLink @@ -2246,11 +1888,6 @@ LABEL ANDROID IOS LABEL DESKTOP Allgemein - - Diagnosis and logs - LABEL DESKTOP - Diagnose und Protokolle - Version information LABEL DESKTOP @@ -2260,9 +1897,7 @@ LABEL ANDROID IOS Software license - LABEL DESKTOP ----------- -LABEL ANDROID IOS + LABEL DESKTOP Softwarelizenz @@ -2277,255 +1912,137 @@ LABEL ANDROID IOS LABEL ANDROID IOS Hilfe & Feedback - - Tutorial - LABEL ANDROID IOS - Tutorial - - - Do you want to know how to use %1? - LABEL ANDROID IOS - Möchten Sie wissen, wie die %1 verwendet wird? - - - Video tutorials - LABEL ANDROID IOS - Videotutorials - - - Do you want to see the video tutorials? - LABEL ANDROID IOS - Möchten Sie die Videotutorials ansehen? - - - FAQ - LABEL ANDROID IOS - FAQ - - - Do you have further questions about %1? - LABEL ANDROID IOS - Haben Sie weitere Fragen zur %1? - - - Support - LABEL ANDROID IOS - Support - - - Do you need further support? - LABEL ANDROID IOS - Benötigen Sie weitergehende Unterstützung? - Privacy statement LABEL ANDROID IOS Datenschutzerklärung - - Do you want to read the privacy statement? - LABEL ANDROID IOS - Möchten Sie die Datenschutzerklärung einsehen? - Accessibility statement LABEL ANDROID IOS Barrierefreiheitserklärung - - Do you want to read the accessibility statement? - LABEL ANDROID IOS - Möchten Sie die Barrierefreiheitserklärung einsehen? - Rate %1 LABEL ANDROID IOS Bewerten Sie die %1 - - Do you want to rate us in the App Store? - LABEL ANDROID IOS - Möchten Sie uns im App Store bewerten? - - - Do you want to rate us in the Google Play Store? - Möchten Sie uns im Google Play Store bewerten? - - - Diagnosis - LABEL ANDROID IOS - Diagnose - Logs LABEL ANDROID IOS Protokolle - Do you want to view the logs of %1? + Information LABEL ANDROID IOS - Möchten Sie die Protokolle der %1 ansehen? + Information - Report error + List of Providers LABEL ANDROID IOS - Melden Sie einen Fehler + Anbieterliste - Did you find a bug? Please help us by sending us the log file together with a description of the error. + Data and logs + LABEL DESKTOP + Daten und Protokolle + + + FAQ - Frequently asked questions LABEL ANDROID IOS - Haben Sie einen Fehler entdeckt? Helfen Sie uns, indem Sie uns die Protokolldatei zusammen mit einer Fehlerbeschreibung zusenden. + FAQ – Häufig gestellte Fragen - Information + Contact LABEL ANDROID IOS - Information + Kontakt - Do you want to see detailed information about %1? + Show Logs LABEL ANDROID IOS - Möchten Sie detaillierte Informationen über die %1 ansehen? + Protokolle anzeigen - Do you want to read the software licenses? + Send log to the support LABEL ANDROID IOS - Möchten Sie die Software-Lizenzen lesen? + Protokoll an den Support senden - Do you want to view the release notes of %1? + Terms of use and software license LABEL ANDROID IOS - Möchten Sie die Release Notes der %1 ansehen? + Nutzungsbedingungen und Softwarelizenz MoreViewDiagnosis - Diagnosis + Logs LABEL DESKTOP - Diagnose + Protokolle - You can view and save the diagnosis information of the AusweisApp2 and your system here. + Show logs LABEL DESKTOP - Sie können die Diagnose-Informationen der AusweisApp2 und Ihres System hier einsehen und speichern. + Zeige Protokolle - Show diagnosis + Show system data LABEL DESKTOP - Zeige Diagnose + Zeige Systemdaten - Logs + System data LABEL DESKTOP - Protokolle + Systemdaten + + + MoreViewGeneral - Do you want to view the logs of %1? + Open website LABEL DESKTOP - Möchten Sie die Protokolle der %1 ansehen? + Öffne Webseite - Show logs + Privacy statement LABEL DESKTOP - Zeige Protokolle + Datenschutzerklärung - Report error + Accessibility statement LABEL DESKTOP - Melden Sie einen Fehler + Barrierefreiheitserklärung - Did you find a bug? Please help us by sending us the log file together with a description of the error. + Do you want to see a list of service providers? LABEL DESKTOP - Haben Sie einen Fehler entdeckt? Helfen Sie uns, indem Sie uns die Protokolldatei zusammen mit einer Fehlerbeschreibung zusenden. + Möchten Sie eine Liste mit Diensteanbietern sehen? - Open website - LABEL DESKTOP - Öffne Webseite - - - - MoreViewGeneral - - Online help - LABEL DESKTOP - Online-Hilfe - - - Do you have questions about %1? - LABEL DESKTOP - Haben Sie Fragen zur %1? - - - Open website - LABEL DESKTOP - Öffne Webseite - - - Video tutorials - LABEL DESKTOP - Videotutorials - - - Do you want to see the video tutorials? - LABEL DESKTOP - Möchten Sie die Videotutorials ansehen? - - - FAQ - LABEL DESKTOP - FAQ - - - Do you have further questions about %1? - LABEL DESKTOP - Haben Sie weitere Fragen zur %1? - - - Support - LABEL DESKTOP - Support - - - Do you need further support? - LABEL DESKTOP - Benötigen Sie weitergehende Unterstützung? - - - Privacy statement - LABEL DESKTOP - Datenschutzerklärung - - - Do you want to read the privacy statement? - LABEL DESKTOP - Möchten Sie die Datenschutzerklärung einsehen? - - - Accessibility statement + List of Providers LABEL DESKTOP - Barrierefreiheitserklärung + Anbieterliste - Do you want to read the accessibility statement? + FAQ - Frequently asked questions LABEL DESKTOP - Möchten Sie die Barrierefreiheitserklärung einsehen? + FAQ – Häufig gestellte Fragen - Setup assistant + Contact LABEL DESKTOP - Einrichtungsassistent + Kontakt + + + NavigationAction - Do you want to run the setup assistant again? - LABEL DESKTOP - Möchten Sie den Einrichtungsassistenten erneut durchführen? + Cancel + Abbrechen - Start setup assistant - LABEL DESKTOP - Starte Einrichtungsassistenten + Back + Zurück @@ -2549,18 +2066,10 @@ LABEL ANDROID IOS NavigationView - - History - Verlauf - Start Start - - Provider - Anbieter - Settings Einstellungen @@ -2702,6 +2211,7 @@ LABEL ANDROID IOS Delete last digit, disabled until input is present. + LABEL ANDROID IOS A11y text for the "delete" button text when the button is disabled. Lösche letzte Ziffer, deaktiviert da keine Eingabe vorliegt. @@ -2783,21 +2293,11 @@ LABEL ANDROID IOS LABEL ALL_PLATFORMS PIN-Information - - The card PIN is a six-digit PIN that you set yourself. You always need this PIN if you want to use the eID function. - INFO ALL_PLATFORMS Answer to the question 'what is the card pin?' - Die Karten-PIN ist eine sechsstellige PIN, die Sie selbst gesetzt haben. Diese PIN brauchen Sie immer, wenn Sie die Online-Ausweisfunktion nutzen möchten. - Where can I find the card PIN? LABEL ALL_PLATFORMS Wo finde ich die Karten-PIN? - - You set the card PIN either directly when you picked up your ID card at the citizens' office (Bürgeramt) or later in AusweisApp2 using the five-digit Transport PIN. Only when you have set a six-digit PIN of your own choice can you use the eID function. - INFO ALL_PLATFORMS Answer to the question 'Where can I find the card PIN?' - Sie haben die Karten-PIN entweder direkt bei der Abholung des Ausweises im Bürgeramt oder später in der AusweisApp2 mithilfe der fünfstelligen Transport-PIN gesetzt. Erst wenn Sie eine selbstgewählte, sechsstellige PIN gesetzt haben, können Sie die Online-Ausweisfunktion nutzen. - How do I choose a secure PIN? LABEL ALL_PLATFORMS @@ -2815,7 +2315,9 @@ LABEL ANDROID IOS Keep your PIN secret and change it if another person becomes aware of it. - INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure PIN?' paragraph 3/3 + INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure PIN?' paragraph 3/3 +---------- +INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure (Smart-eID) PIN?' paragraph 3/3 Halten Sie Ihre PIN geheim und ändern Sie diese, wenn eine andere Person hiervon Kenntnis erlangt. @@ -2843,21 +2345,6 @@ LABEL ANDROID IOS INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 3/3 Sobald Sie eine Karten-PIN gesetzt haben, verliert die Transport-PIN Ihre Gültigkeit. - - Smartphone as card reader information - LABEL ALL_PLATFORMS - Smartphone als Kartenleser-Information - - - You may use your smartphone as a card reader with AusweisApp2. The smartphone needs to feature a supported NFC chipset and both devices, your smartphone and this machine, need to be connected to the same WiFi network. - INFO ALL_PLATFORMS Description text of SaC pairing - Es besteht die Möglichkeit, Ihr Smartphone als Kartenleser mit der AusweisApp2 zu verwenden. Das Smartphone muss einen unterstützten NFC-Chip verwenden und beide Geräte, sowohl das Smartphone als auch Ihr Rechner, müssen mit dem selben WLAN-Netz verbunden sein. - - - To use your smartphone as a card reader you'll always need to activate the remote service in the AusweisApp2 on the smartphone. For the first time you'll also need to start the pairing mode on your smartphone, select the device from the list of available devices on this machine and then enter the pairing code shown on the phone. - INFO ALL_PLATFORMS Description text of SaC pairing - Um Ihr Smartphone als Kartenleser zu verwenden muss stets der Fernzugriff in der AusweisApp2 auf Ihrem Smartphone aktiviert sein. Für eine initiale Verbindung der Geräte muss zusätzlich der Kopplungsmodus auf dem Smartphone aktiviert werden, wählen Sie danach das Gerät aus der Liste der verfügbaren Geräte auf Ihrem Rechner und geben Sie den von Ihrem Smartphone dargestellten Kopplungscode ein. - Where do I find the PUK? LABEL ALL_PLATFORMS @@ -2987,7 +2474,7 @@ LABEL ALL_PLATFORMS Your ID card comes with a five-digit 'Transport PIN' which you need to replace with a six-digit PIN that you choose yourself. - INFO ALL_PLATFORMS Description text explaining the PINs 1/6 + INFO ALL_PLATFORMS Description text explaining the PINs 1/7 Ihr Ausweis wurde bei Erstellung mit einer fünfstelligen „Transport-PIN“ versehen, die Sie durch eine sechsstellige, selbstgewählte PIN ersetzen müssen. @@ -2996,49 +2483,114 @@ LABEL ALL_PLATFORMS Fünfstellige Transport-PIN - The five-digit Transport PIN was sent to you by post after you applied for your ID card. - INFO ALL_PLATFORMS Description text explaining the PINs 2/6 + Six-digit PIN + LABEL ALL_PLATFORMS + Sechsstellige PIN + + + You can use the PIN Reset Service to request a new card PIN free of charge. + LABEL ALL_PLATFORMS + Dann fordern Sie jetzt mithilfe des PIN-Rücksetzdienstes kostenlos eine neue Karten-PIN an. + + + If you do not know either your Transport PIN or your card PIN, you can request a new PIN free of charge using the PIN Reset Service. + LABEL ALL_PLATFORMS Hint text for requested Transport PIN but both, Transport PIN and PIN, are not known. + Wenn Ihnen weder Ihre Transport-PIN noch Ihre Karten-PIN bekannt ist, können Sie mit dem PIN-Rücksetzdienst kostenlos eine neue PIN anfordern. + + + If you have forgotten your card PIN, you can request a new PIN free of charge using the PIN Reset Service. + LABEL ALL_PLATFORMS Hint text for PIN but it is unknown. + Wenn Sie Ihre Karten-PIN vergessen haben, können Sie mit dem PIN-Rücksetzdienst kostenlos eine neue PIN anfordern. + + + The five-digit Transport PIN was sent to you by mail after you applied for your ID card. + INFO ALL_PLATFORMS Description text explaining the PINs 2/7 Die fünfstellige Transport-PIN wurde Ihnen per Post zugesandt, nachdem Sie Ihren Ausweis beantragt haben. - The PIN can only be used once. When you set up the eID function, you will replace this five-digit PIN with a six-digit PIN that you choose yourself. - INFO ALL_PLATFORMS Description text explaining the PINs 3/6 - Diese PIN kann nur einmal verwendet werden. Wenn Sie Ihren Online-Ausweis einrichten, ersetzen Sie diese fünfstellige Transport-PIN durch eine sechsstellige, selbstgewählte PIN. + What is the Smart-eID PIN? + LABEL ALL_PLATFORMS + Was ist die Smart-eID-PIN? - Six-digit PIN + Set up Smart-eID LABEL ALL_PLATFORMS - Sechsstellige PIN + Smart-eID einrichten - This is a number that you choose yourself when you set up the eID function for the first time. It replaces your five-digit Transport PIN. - INFO ALL_PLATFORMS Description text explaining the PINs 4/6 - Die sechsstellige PIN ist eine Zahlenkombination, die Sie selbst wählen, wenn Sie Ihren Online-Ausweis zum ersten Mal einrichten. Sie ersetzt Ihre fünfstellige Transport-PIN. + The Smart-eID PIN is a six-digit PIN that you set yourself. You always need this PIN if you want to use your Smart-eID. + INFO ALL_PLATFORMS Answer to the question 'what is the Smart-eID pin?' + Die Smart-eID-PIN ist eine sechsstellige PIN, die Sie selbst setzen. Diese PIN brauchen Sie immer, wenn Sie die Smart-eID nutzen möchten. - This PIN allows you to prove online that the ID card belongs to you. No one can use your ID card online without this PIN. - INFO ALL_PLATFORMS Description text explaining the PINs 5/6 - Mit der sechsstelligen, selbstgewählten PIN weisen Sie online nach, dass der Ausweis Ihnen gehört. Keiner kann Ihren Ausweis online benutzen ohne diese PIN. + For your six-digit Smart-eID PIN, choose a combination of numbers that cannot be guessed - i.e. neither "123456", nor your date of birth, nor any other numbers printed on your ID card. + INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure (Smart-eID) PIN?' paragraph 1/3 + Wählen Sie für Ihre sechsstellige Smart-eID-Pin eine Zahlenkombination, die nicht leicht zu erraten ist - also weder „123456“, noch Ihr Geburtsdatum oder andere Zahlen, die auf dem Ausweis aufgedruckt sind. - You can change your six-digit PIN at any time in AusweisApp2. - INFO ALL_PLATFORMS Description text explaining the PINs 6/6 - Sie können Ihre PIN jederzeit in der AusweisApp2 ändern. + You can change your six-digit Smart-eID PIN at any time and an unlimited number of times as long as you know your valid Smart-eID PIN. + INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure (Smart-eID) PIN?' paragraph 2/3 + Sie können Ihre sechsstellige Smart-eID-PIN jederzeit und unbegrenzt oft ändern, solange Ihnen Ihre gültige Smart-eID-PIN bekannt ist. - You can use the PIN Reset Service to request a new card PIN free of charge. - LABEL ALL_PLATFORMS - Dann fordern Sie jetzt mithilfe des PIN-Rücksetzdienstes kostenlos eine neue Karten-PIN an. + The PIN can only be used once. When you set up the eID function, you will replace this five-digit Transport PIN with a six-digit card PIN that you choose yourself. + INFO ALL_PLATFORMS Description text explaining the PINs 3/7 + Diese PIN kann nur einmal verwendet werden. Wenn Sie Ihren Online-Ausweis einrichten, ersetzen Sie diese fünfstellige Transport-PIN durch eine sechsstellige, selbstgewählte Karten-PIN. - If you do not know either your Transport PIN or your card PIN, you can request a new PIN free of charge using the PIN Reset Service. - LABEL ALL_PLATFORMS Hint text for requested Transport PIN but both, Transport PIN and PIN, are not known. - Wenn Ihnen weder Ihre Transport-PIN noch Ihre Karten-PIN bekannt ist, können Sie mit dem PIN-Rücksetzdienst kostenlos eine neue PIN anfordern. + The six-digit card PIN is a number that you choose yourself when you set up the eID function for the first time. It replaces your five-digit Transport PIN. + INFO ALL_PLATFORMS Description text explaining the PINs 4/7 + Die sechsstellige Karten-PIN ist eine Zahlenkombination, die Sie selbst vergeben, wenn Sie Ihren Online-Ausweis zum ersten Mal einrichten. Sie ersetzt Ihre fünfstellige Transport-PIN. - If you have forgotten your card PIN, you can request a new PIN free of charge using the PIN Reset Service. + The Smart-eID PIN also has six digits. You also choose that PIN yourself while setting up the Smart-eID for the first time. + INFO ALL_PLATFORMS Description text explaining the PINs 5/7 + Auch die Smart-eID-PIN ist sechsstellig. Sie vergeben auch diese PIN selbst, wenn Sie die Smart-eID zum ersten Mal einrichten. + + + You can change your card PIN and your Smart-eID PIN at any time in %1. + INFO ALL_PLATFORMS Description text explaining the PINs (%1 is replaced with the application name) 7/7 + Sie können die Karten-PIN und die Smart-eID-PIN jederzeit in der %1 ändern. + + + With this six-digit PIN you prove online that the ID card or Smart-eID belongs to you. No one can use the eID function without this PIN. + INFO ALL_PLATFORMS Description text explaining the PINs 6/7 + Mit der sechsstelligen PIN weisen Sie online nach, dass der Ausweis bzw. die Smart-eID Ihnen gehören. Keiner kann die Online-Ausweisfunktion benutzen ohne diese PIN. + + + The card PIN is a six-digit PIN that you set yourself. You always need this PIN if you want to use the eID function with your ID card. + INFO ALL_PLATFORMS Answer to the question 'what is the card pin?' + Die Karten-PIN ist eine sechsstellige PIN, die Sie selbst gesetzt haben. Diese PIN brauchen Sie immer, wenn Sie die Online-Ausweisfunktion mit Ihrer Ausweiskarte nutzen möchten. + + + You set the card PIN either directly when you picked up your ID card at the citizens' office (Bürgeramt) or later in %1 using the five-digit Transport PIN. Only when you have set a six-digit PIN of your own choice can you use the eID function and set up a Smart-eID. + INFO ALL_PLATFORMS Answer to the question 'Where can I find the card PIN?' (%1 is replaced with the application name) + Sie haben die Karten-PIN entweder direkt bei der Abholung des Ausweises im Bürgeramt oder später in der %1 mithilfe der fünfstelligen Transport-PIN gesetzt. Erst wenn Sie eine selbstgewählte, sechsstellige PIN gesetzt haben, können Sie die Online-Ausweisfunktion nutzen und eine Smart-eID einrichten. + + + If you have forgotten your Smart-eID PIN, you can renew your Smart-eID and thereby set a new PIN. LABEL ALL_PLATFORMS Hint text for PIN but it is unknown. - Wenn Sie Ihre Karten-PIN vergessen haben, können Sie mit dem PIN-Rücksetzdienst kostenlos eine neue PIN anfordern. + Wenn Sie Ihre Smart-eID-PIN vergessen haben, können Sie Ihre Smart-eID erneuern und hierbei eine neue PIN setzen. + + + Where can I find the Smart-eID PIN? + LABEL ALL_PLATFORMS + Wo finde ich die Smart-eID-PIN? + + + You have set the Smart-eID PIN while setting up the Smart-eID. + INFO ALL_PLATFORMS Answer to the question 'Where can I find the Smart-eID PIN?' + Sie haben die Smart-eID-PIN bei der Einrichtung der Smart-eID gesetzt. + + + With this six-digit PIN you prove online that the ID card belongs to you. No one can use the eID function without this PIN. + INFO ALL_PLATFORMS Description text explaining the PINs 6/7 + Mit der sechsstelligen PIN weisen Sie online nach, dass der Ausweis Ihnen gehört. Keiner kann die Online-Ausweisfunktion benutzen ohne diese PIN. + + + You can change your card PIN at any time in %1. + INFO ALL_PLATFORMS Description text explaining the PINs (%1 is replaced with the application name) 7/7 + Sie können die Karten-PIN jederzeit in der %1 ändern. @@ -3106,6 +2658,11 @@ LABEL ALL_PLATFORMS LABEL ANDROID IOS Löschen Sie Ihre Smart-eID, bevor Sie Ihr Smartphone verschenken oder verkaufen. + + If you uninstall the %1 or reset your smartphone, the Smart-eID must be set up again. + LABEL ANDROID IOS + Wenn Sie die %1 deinstallieren oder Ihr Smartphone zurücksetzen, muss die Smart-eID neu eingerichtet werden. + PersonalizationProgressView @@ -3164,6 +2721,11 @@ LABEL ALL_PLATFORMS LABEL ANDROID IOS Smart-eID + + Please wait a moment, the current process is being finished. + LABEL ANDROID IOS + Bitte warten Sie einen Moment, der laufende Vorgang wird noch abgeschlossen. + PersonalizationResultView @@ -3202,11 +2764,6 @@ LABEL ALL_PLATFORMS INFO ANDROID IOS Placeholder (error) text if the Smart-eID setup finished successfully but for some reason no blocking code was retrieved Die Smart-eID-Einrichtung wurde erfolgreich abgeschlossen, jedoch konnte kein Sperrkennwort abgerufen werden. Aus Sicherheitsgründen sollten Sie Ihre Smart-eID löschen und die Einrichtung neu starten. - - You have reached the allowed amount of Smart-eID setups for the current period. You may set up another Smart-eID with your ID card on %1. - LABEL ANDROID IOS - Sie haben die erlaubte Anzahl an Smart-eID-Einrichtungen für den aktuellen Zeitraum erreicht. Sie können ab dem %1 wieder eine Smart-eID mit Ihrem Ausweis einrichten. - Attention: you may only set up <b><u>one</u></b> more Smart-eID with your ID card. Further setups may be carried out on %1. LABEL ANDROID IOS @@ -3255,383 +2812,148 @@ LABEL ALL_PLATFORMS - ProviderContactInfo - - Provider contact information - Kontaktinformationen des Anbieters - + ProviderInfoSection - Contact information of the selected provider. - Kontaktinformationen des ausgewählten Anbieters. + See details under "more..." + LABEL DESKTOP + Weitere Details unter "mehr..." - Contact + Show more information about the service provider LABEL DESKTOP - Kontakt + Zeige mehr Informationen über den Anbieter - Unknown + Details about the provider LABEL DESKTOP - Unbekannt + Details zum Anbieter - ProviderDetailButtonBar + ProxyCredentialsPopup - To provider - LABEL DESKTOP + Sign in + LABEL DESKTOP Text of the button in the proxy credentials popup. ---------- -LABEL ANDROID_TABLET IOS_TABLET - Zum Anbieter +LABEL DESKTOP Title of the proxy credentials popup. + Anmelden - - - ProviderDetailDescription - Description - LABEL ANDROID_TABLET IOS_TABLET - Beschreibung + The proxy %1 requires username and password. + LABEL DESKTOP Text of the proxy credentials popup. An example for %1 is http://proxy.example.com:1337. + Für den Proxy %1 sind ein Nutzername und ein Passwort erforderlich. - The provider did not provide a description. - LABEL ANDROID_TABLET IOS_TABLET - Der Anbieter hat keine Beschreibung zur Verfügung gestellt. + Proxy credential username + LABEL DESKTOP Accessible name. + Benutzername für den Proxy - - - ProviderDetailHistory - List of your past interactions with this provider - Ihre vergangenen Interaktionen mit diesem Anbieter + Username + LABEL DESKTOP Label of the textfield for the username. + Nutzername - The list is empty, no recorded interaction with this provider. - Die Liste ist leer, keine Interaktion mit diesem Anbieter aufgezeichnet. + Proxy credential password + LABEL DESKTOP Accessible name. + Passwort für den Proxy - Currently there are no history entries. - INFO DESKTOP No authentication history, placeholder text. ----------- -INFO ANDROID_TABLET IOS_TABLET No authentication history, placeholder text. - Derzeit gibt es keine Einträge im Verlauf. + Password + LABEL DESKTOP Label of the textfield for the password. + Passwort + + + QObject - History - LABEL ANDROID_TABLET IOS_TABLET - Verlauf + An error occurred in log handling: %1 + LABEL ALL_PLATFORMS + Es ist ein Fehler bei der Protokollverwaltung aufgetreten: %1 - Purpose for reading out requested data - LABEL ANDROID_TABLET IOS_TABLET - Zweck des Auslesevorgangs + Please describe the error that occurred. + Bitte beschreiben Sie den aufgetretenen Fehler. - - - ProviderDetailHistoryInfo - Provider - LABEL ANDROID_TABLET IOS_TABLET - Anbieter + You may want to attach the logfile which can be saved from the error dialog. + Bitte fügen Sie der E-Mail das Protokoll als Anhang zu. - Purpose for reading out requested data - LABEL ANDROID_TABLET IOS_TABLET - Zweck des Auslesevorgangs + Error code + Fehlernummer - Read data - LABEL ANDROID_TABLET IOS_TABLET - Ausgelesene Daten + Service URL + Service URL - Terms of usage - LABEL ANDROID_TABLET IOS_TABLET - Nutzungsbedingungen + Parameter of occurred error: + Parameter des aufgetretenen Fehlers: - - - ProviderDetailHistoryItem - Service: - LABEL DESKTOP - Dienst: + Critical errors: + Kritische Fehler: + + + ReaderConfigurationInfo - Provider: - LABEL DESKTOP - Anbieter: + Unknown reader + LABEL ALL_PLATFORMS + Unbekannter Kartenleser + + + ReleaseNotes - Click to view details of history entry. - Zeige Details des Verlaufseintrags. + Retry + LABEL DESKTOP +---------- +LABEL ANDROID IOS + Erneut versuchen - Touch for more details + Release notes LABEL ANDROID IOS - Berühren Sie hier für mehr Details + Release Notes - ProviderDetailView + RemoteReaderDelegate - Description - LABEL DESKTOP - Beschreibung + Smartphone named "%1" + Smartphone namens "%1" - The provider did not provide a description. - LABEL DESKTOP - Der Anbieter hat keine Beschreibung zur Verfügung gestellt. + Press space to unpair the smartphone "%1". + Drücken Sie die Leertaste um das Smartphone "%1" zu entkoppeln. - History - LABEL DESKTOP - Verlauf + Press space to pair the smartphone "%1". + Drücken Sie die Leertaste um das Smartphone "%1" zu koppeln. - - - ProviderGridView - No results matching your search query found - LABEL DESKTOP IOS_TABLET ANDROID_TABLET The text entered into the provider search field results in no matches - Keine Ergebnisse zu Ihrer Suche gefunden + Remove remote device + Entferne das Gerät - ProviderHeader + RemoteReaderView - To provider - LABEL ANDROID IOS - Zum Anbieter + Paired devices + LABEL DESKTOP + Gekoppelte Geräte - - - ProviderInfoSection - See details under "more..." + Add pairing LABEL DESKTOP - Weitere Details unter "mehr..." + Kopplung hinzufügen - - - ProviderListItemDelegate - Open provider details for %1 - Öffne Details vom Anbieter %1 - - - Click to set category filter to %1 - Klicken Sie hier um den Kategoriefilter auf %1 zu setzen - - - - ProviderModelItem - - Click to open homepage. - INFO ALL_PLATFORMS A11y action text appended to provider homepage to be read read by screen reader. - Klicken, um die Homepage zu öffnen. - - - Click to send email. - INFO ALL_PLATFORMS A11y action text appended to provider mail to be read read by screen reader. - Klicken, um eine E-Mail zu senden. - - - Costs - LABEL DESKTOP - Kosten - - - Click to call. - INFO ALL_PLATFORMS A11y action text appended to provider phone number to be read read by screen reader. - Klicken, um anzurufen. - - - Click to open map. - INFO ALL_PLATFORMS A11y action text appended to provider address maps url to be read read by screen reader. - Klicken, um Karte zu öffnen. - - - Homepage - Homepage - - - E-Mail - E-Mail - - - Phone - Telefon - - - Address - Adresse - - - - ProviderOverview - - All provider - LABEL DESKTOP - Alle Anbieter - - - Citizen services - LABEL DESKTOP - Bürgerdienste - - - Financials - LABEL DESKTOP - Finanzen - - - Insurances - LABEL DESKTOP - Versicherungen - - - Other services - LABEL DESKTOP - Weitere Dienste - - - - ProviderView - - Provider - LABEL DESKTOP - Anbieter - - - Search providers - LABEL DESKTOP - Anbieter suchen - - - - ProxyCredentialsPopup - - Sign in - LABEL DESKTOP Text of the button in the proxy credentials popup. ----------- -LABEL DESKTOP Title of the proxy credentials popup. - Anmelden - - - The proxy %1 requires username and password. - LABEL DESKTOP Text of the proxy credentials popup. An example for %1 is http://proxy.example.com:1337. - Für den Proxy %1 sind ein Nutzername und ein Passwort erforderlich. - - - Proxy credential username - LABEL DESKTOP Accessible name. - Benutzername für den Proxy - - - Username - LABEL DESKTOP Label of the textfield for the username. - Nutzername - - - Proxy credential password - LABEL DESKTOP Accessible name. - Passwort für den Proxy - - - Password - LABEL DESKTOP Label of the textfield for the password. - Passwort - - - - QObject - - An error occurred in log handling: %1 - LABEL ALL_PLATFORMS - Es ist ein Fehler bei der Protokollverwaltung aufgetreten: %1 - - - Please describe the error that occurred. - Bitte beschreiben Sie den aufgetretenen Fehler. - - - You may want to attach the logfile which can be saved from the error dialog. - Bitte fügen Sie der E-Mail das Protokoll als Anhang zu. - - - Error code - Fehlernummer - - - Service URL - Service URL - - - Parameter of occurred error: - Parameter des aufgetretenen Fehlers: - - - Critical errors: - Kritische Fehler: - - - - ReaderConfigurationInfo - - Unknown reader - LABEL ALL_PLATFORMS - Unbekannter Kartenleser - - - - ReleaseNotes - - Retry - LABEL DESKTOP ----------- -LABEL ANDROID IOS - Erneut versuchen - - - Release notes - LABEL ANDROID IOS - Release Notes - - - - RemoteReaderDelegate - - Smartphone named "%1" - Smartphone namens "%1" - - - Press space to unpair the smartphone "%1". - Drücken Sie die Leertaste um das Smartphone "%1" zu entkoppeln. - - - Press space to pair the smartphone "%1". - Drücken Sie die Leertaste um das Smartphone "%1" zu koppeln. - - - Remove remote device - Entferne das Gerät - - - - RemoteReaderView - - Paired devices - Gekoppelte Geräte - - - Add pairing - Kopplung hinzufügen - - - Open the %1 on your Smartphone as card reader. - LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 4. %1 is a placeholder-tag for the app name. - Öffnen Sie die %1 auf Ihrem Smartphone als Kartenleser. + Open the %1 on your Smartphone as card reader. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 4. %1 is a placeholder-tag for the app name. + Öffnen Sie die %1 auf Ihrem Smartphone als Kartenleser. Both devices have to be connected to the same WiFi. @@ -3649,6 +2971,7 @@ LABEL ANDROID IOS Last connected + LABEL DESKTOP Zuletzt verbunden @@ -3659,6 +2982,11 @@ LABEL ANDROID IOS RemoteServiceController + + Remote service + LABEL ANDROID IOS + Fernzugriff + You are about to identify yourself towards the following provider using the device "%1": LABEL ANDROID IOS @@ -3669,11 +2997,6 @@ LABEL ANDROID IOS LABEL ANDROID IOS Kartenleser - - Remote service - LABEL ANDROID IOS - Fernzugriff - RemoteServiceSettings @@ -3761,7 +3084,7 @@ Hierfür müssen Sie zuvor das entsprechende Gerät mit diesem Smartphone koppel Paired Devices - INFO ANDROID IOS + LABEL ANDROID IOS Gekoppelte Geräte @@ -3807,6 +3130,11 @@ Hierfür müssen Sie zuvor das entsprechende Gerät mit diesem Smartphone koppel RemoteServiceViewRemote + + Click to remove device + LABEL ANDROID IOS + Klicken, um das Gerät zu entfernen + Remove pairing INFO ANDROID IOS @@ -3842,11 +3170,6 @@ Hierfür müssen Sie zuvor das entsprechende Gerät mit diesem Smartphone koppel LABEL ANDROID IOS Kopplung hinzufügen - - Click to remove device - LABEL ANDROID IOS - Klicken, um das Gerät zu entfernen - Last connected LABEL ANDROID IOS @@ -3904,9 +3227,9 @@ Hierfür müssen Sie zuvor das entsprechende Gerät mit diesem Smartphone koppel Das verbundene Smartphone als Kartenleser erfüllt leider nicht die technischen Voraussetzungen (Extended Length wird nicht unterstützt). - Connected to %1. Please place the NFC interface of the smartphone on your ID card. + Connected to %1. Please follow the instructions on the connected smartphone. INFO ANDROID IOS The connection to the smartphone was established, the ID card may be inserted. - Verbunden mit %1. Bitte platzieren Sie das Smartphone mit der NFC-Schnittstelle auf Ihrem Ausweis. + Verbunden mit %1. Bitte folgen Sie den Anweisungen auf dem verbundenen Smartphone. Manage pairings @@ -3926,10 +3249,6 @@ Hierfür müssen Sie zuvor das entsprechende Gerät mit diesem Smartphone koppel ResultErrorView - - Show error details - Fehlerdetails anzeigen - Details Details @@ -3969,183 +3288,79 @@ Hierfür müssen Sie zuvor das entsprechende Gerät mit diesem Smartphone koppel - ScreenOrientationSelectionPopup + RetryCounter - Select screen orientation - LABEL ANDROID - Bildschirmausrichtung wählen + Remaining ID card PIN attempts: %1 + LABEL DESKTOP + Verbleibende Karten-PIN Versuche: %1 + + + SecurityAndPrivacySettings - Set screen orientation to portrait - LABEL ANDROID - Bildschirmausrichtung auf Hochformat setzen + Onscreen keypad + LABEL DESKTOP + Bildschirmtastatur - Portrait - LABEL ANDROID - Hochformat + Use on screen keypad for PIN entry + LABEL DESKTOP + Bildschirmtastatur für die PIN-Eingabe verwenden - recommended - empfohlen + Software updates + LABEL DESKTOP + Software-Aktualisierungen - Set screen orientation to landscape - LABEL ANDROID - Bildschirmausrichtung auf Querformat setzen + Check at program start + LABEL DESKTOP + Automatisch bei Programmstart prüfen - Landscape - LABEL ANDROID - Querformat + Show update + LABEL DESKTOP + Aktualisierung anzeigen - Using a screen orientation unfit for your device may result in display errors. - LABEL ANDROID - Die Ver­wen­dung ei­ner, für Ihr Ge­rät nicht ge­eig­ne­ten Bild­schirm­aus­rich­tung kann zu An­zei­ge­feh­lern füh­ren. + Check now + LABEL DESKTOP + Jetzt überprüfen - - - SearchBar - Search - LABEL DESKTOP ----------- -LABEL ANDROID - Suchen + An update is available (version %1)! + LABEL DESKTOP An update is available, the new version is supplied to the user. + Eine Aktualisierung ist verfügbar (Version %1)! - Clear - Löschen + An update is available but retrieving the information failed. + LABEL DESKTOP The updater found an update but not all required update information are valid, this should be a very rare case. + Eine Aktualisierung ist verfügbar, das Herunterladen der Informationen ist jedoch fehlgeschlagen. - Type provider to search for - LABEL ANDROID - Tippen Sie den Namen des Anbieters ein, nach dem Sie suchen möchten + Your version %1 of %2 is up to date. + LABEL DESKTOP The current version is up to date, no user action is required. + Ihre Version %1 der %2 ist aktuell. - Abort search - LABEL ANDROID - Suche abbrechen + No update information available, please check for update manually. + LABEL DESKTOP The automatic update check is disabled (or no network connection was present during app start), a manual check for update is required. + Keine Aktualisierungsinformationen vorhanden, bitte prüfen Sie manuell auf verfügbare Aktualisierungen. - Search provider list - LABEL ANDROID - Durchsuchen der Anbieterliste + Shuffle digits of on screen keypad + LABEL DESKTOP + Ziffern der Bildschirmtastatur zufällig anordnen - Enter search string - Sucheingabe + Button animation + LABEL DESKTOP + Tasten-Animationen - Search providers - Anbieter suchen - - - Clear search string - Lösche Sucheingabe - - - Cancel - LABEL IOS - Abbrechen - - - - SecurityAndPrivacySettings - - History - LABEL DESKTOP - Verlauf - - - Save authentication history - LABEL DESKTOP - Verlauf der Ausweisvorgänge speichern - - - Clear entire history - LABEL DESKTOP - Lösche gesamten Verlauf - - - History is empty - Es gibt keine Einträge im Verlauf - - - Onscreen keypad - LABEL DESKTOP - Bildschirmtastatur - - - Use on screen keypad for PIN entry - LABEL DESKTOP - Bildschirmtastatur für die PIN-Eingabe verwenden - - - Shuffle keypad buttons - LABEL DESKTOP - Zufällige Anordnung der Ziffern - - - Visual feedback when pressing keypad buttons - LABEL DESKTOP - Animation der Tasten auf der Bildschirmtastatur - - - Software updates - LABEL DESKTOP - Software-Aktualisierungen - - - Check at program start - LABEL DESKTOP - Automatisch bei Programmstart prüfen - - - Show update - LABEL DESKTOP - Aktualisierung anzeigen - - - Check now - LABEL DESKTOP - Jetzt überprüfen - - - An update is available (version %1)! - LABEL DESKTOP An update is available, the new version is supplied to the user. - Eine Aktualisierung ist verfügbar (Version %1)! - - - An update is available but retrieving the information failed. - LABEL DESKTOP The updater found an update but not all required update information are valid, this should be a very rare case. - Eine Aktualisierung ist verfügbar, das Herunterladen der Informationen ist jedoch fehlgeschlagen. - - - Your version %1 of %2 is up to date. - LABEL DESKTOP The current version is up to date, no user action is required. - Ihre Version %1 der %2 ist aktuell. - - - No update information available, please check for update manually. - LABEL DESKTOP The automatic update check is disabled (or no network connection was present during app start), a manual check for update is required. - Keine Aktualisierungsinformationen vorhanden, bitte prüfen Sie manuell auf verfügbare Aktualisierungen. - - - Delete history + Visually highlight key presses on screen keypad LABEL DESKTOP - Verlauf löschen - - - All history entries will be deleted. - INFO DESKTOP The current history is about to be removed, user confirmation required. - Alle im Verlauf gespeicherten Informationen werden gelöscht. - - - Deleted %1 entries from the history. - INFO DESKTOP Feedback how many history entries were removed. - Es wurden %1 Einträge aus dem Verlauf gelöscht. + Eingaben auf der Bildschirmtastatur optisch hervorheben @@ -4165,23 +3380,11 @@ LABEL ANDROID LABEL DESKTOP Title of the self authentication result data view Ausgelesene Daten - - Save as PDF... - LABEL DESKTOP - Als PDF speichern... - - - Information - Information - - - Portable Document Format (*.pdf) - LABEL DESKTOP - Portables Dokumentenformat (*.pdf) - OK - LABEL DESKTOP + LABEL DESKTOP +---------- +LABEL ANDROID IOS OK @@ -4189,11 +3392,6 @@ LABEL ANDROID LABEL ANDROID IOS Ausweisen - - Save read self-authentication data - LABEL DESKTOP - Ausgelesene Daten der Selbstauskunft speichern - SelfAuthenticationView @@ -4232,6 +3430,16 @@ LABEL ANDROID IOS LABEL ANDROID IOS Meine Daten einsehen + + Self-authentication + LABEL ANDROID IOS + Selbstauskunft + + + Hint + LABEL ANDROID IOS + Tipp + SettingsView @@ -4287,63 +3495,16 @@ LABEL ANDROID IOS LABEL ANDROID IOS Sprache wechseln - - Screen orientation - LABEL ANDROID - Bildschirmausrichtung - - - Landscape - LABEL ANDROID - Querformat - - - Portrait - LABEL ANDROID - Hochformat - Device name LABEL ANDROID IOS Gerätename - - PIN pad mode - LABEL ANDROID IOS - Tastaturmodus - Enter PIN on this device LABEL ANDROID IOS PIN-Eingabe auf diesem Gerät - - Save history - LABEL ANDROID IOS - Verlauf speichern - - - Save authentication history - LABEL ANDROID IOS - Verlauf der Ausweisvorgänge speichern - - - History - LABEL ANDROID IOS ----------- -LABEL ALL_PLATFORMS - Verlauf - - - View authentication history - LABEL ANDROID IOS - Verlauf der Ausweisvorgänge anzeigen - - - Shuffle keypad buttons - LABEL ANDROID IOS - Zufällige Anordnung der Ziffern - Randomize the order of the on screen keypad buttons LABEL ANDROID IOS @@ -4354,56 +3515,21 @@ LABEL ALL_PLATFORMS LABEL ANDROID IOS Tasten-Animationen - - Visual feedback when pressing keypad buttons - LABEL ANDROID IOS - Animation der Tasten auf der Bildschirmtastatur - - - CAN allowed mode - LABEL ANDROID IOS - CAN-allowed-Modus - - - Support CAN allowed mode - LABEL ANDROID IOS - CAN-allowed-Modus unterstützen - - - Allow the id card to be used with only the CAN - LABEL ANDROID IOS - Unterstütze die Verwendung des Ausweis nur mit der CAN - Skip rights page LABEL ANDROID IOS Anzeige der Berechtigungen überspringen - - Do not show the rights page, when in can allowed mode - LABEL ANDROID IOS - Überspringe die Anzeige der Berechtigungen im CAN-allowed-Modus - Testmode for the self-authentication LABEL ANDROID IOS Testmodus für die Selbstauskunft - - Use the test environment during a self-authentication - LABEL ANDROID IOS - Benutze die Test-Umgebung während der Selbstauskunft - Internal card simulator LABEL ANDROID IOS Interner Kartensimulator - - Enable internal card simulator - LABEL ANDROID IOS - Aktiviere den internen Kartensimulator - Developer mode LABEL ANDROID IOS @@ -4435,97 +3561,112 @@ LABEL ALL_PLATFORMS 15 Tage alte Protokolldatei - Show requested rights on this device as well + Smart-eID LABEL ANDROID IOS - Angefragte Berechtigung auch auf diesem Gerät anzeigen + Smart-eID + + + Reset Smart-eID + LABEL ANDROID IOS + Smart-eID zurücksetzen - Show access rights + Reset Smart-eID data on your device LABEL ANDROID IOS - Berechtigungsanzeige + Smart-eID auf Ihrem Gerät zurücksetzen - Manage paired devices and add new devices + Show requested rights on this device as well LABEL ANDROID IOS - Gekoppelte Geräte verwalten und neue Geräte hinzufügen + Angefragte Berechtigung auch auf diesem Gerät anzeigen Manage pairings LABEL ANDROID IOS Kopplungen verwalten - - - SetupAssistantView - Setup Assistant - LABEL DESKTOP - Einrichtungsassistent + Show Transport PIN reminder, store feedback and close reminder dialogs. + LABEL ANDROID IOS + Zeige Transport-PIN Hinweis, Store Feedback und Fenster-Schließ Hinweis Dialoge. - Welcome to the AusweisApp2. Please take a few moments to set up the environment to your needs. Every decision you make can later be changed in the settings menu. - INFO DESKTOP Welcome message when starting the setup assistant. - Willkommen in der AusweisApp2. Bitte nehmen Sie sich einen Moment Zeit, um die App nach Ihren Wünschen anzupassen. Jede Einstellung kann später wieder im Einstellungsmenü geändert werden. + Reset hideable dialogs + LABEL ANDROID IOS + Setze versteckbare Dialoge zurück - Do you want to automatically start the %1 after boot? - INFO DESKTOP Question if the App shall be started automatically after boot - Wollen Sie die %1 automatisch nach dem Hochfahren starten? + Toggling will restart the %1 + LABEL ANDROID IOS + Ein Umschalten startet die %1 neu - In order to successfully use the eID function, %1 has to be running. It is therefore advisable to activate the auto-start after system startup. - INFO DESKTOP Information text why autostart of the App is advisable - Um die Online-Ausweisfunktion erfolgreich nutzen zu können, muss die %1 gestartet sein. Daher ist es ratsam, dies beim Systemstart zuzulassen. + Use system font + LABEL ANDROID IOS + Systemschriftart verwenden - The launch will add an icon to the menu bar. - INFO MACOS Additional information that macOS auto-start add a symbol to the menu bar - Der Start erfolgt hierbei als Eintrag in der Menüleiste. + Appearance + LABEL ANDROID IOS + Erscheinungsbild - Auto-start Setting - LABEL DESKTOP - Autostart-Einstellung + Add and remove devices + LABEL ANDROID IOS + Geräte hinzufügen oder entfernen - Do you want to save a history of performed authentications on your device? - INFO DESKTOP Question if the authentication history shall be stored. - Möchten Sie einen Verlauf durchgeführter Authentisierungen auf diesem Gerät speichern? + On-site reading + LABEL ANDROID IOS + Vor-Ort-Auslesen - The history is only saved locally. You can use it to see on what date you transmitted which data to which party. After enabling the history you can view and delete the entries anytime. - INFO DESKTOP Information text which data is stored in the history record. - Der Verlauf wird nur lokal angelegt. Dort können Sie jederzeit nachschauen, wann Sie wem welche Daten übermittelt haben. Sie können nach aktivieren der Funktion jederzeit Verlaufseinträge einsehen und löschen. + Support CAN allowed mode for on-site reading + LABEL ANDROID IOS + CAN-Allowed Modus für Vor-Ort-Auslesen unterstützen - History Setting - LABEL DESKTOP - Verlaufseinstellungen + Allow test sample card usage + LABEL ANDROID IOS + Testmusterkarten erlauben + + + Simulate a test sample card in authentications + LABEL ANDROID IOS + Bei der Authentisierung eine Testmusterkarte simulieren + + + Visually highlight key presses on screen keypad + LABEL ANDROID IOS + Eingaben auf der Bildschirmtastatur optisch hervorheben + + + SetupAutostartView - Do you want to set up a card reader <u>now</u>? - INFO DESKTOP Question if the the user wants to setup any card readers now. - Möchten Sie <u>jetzt</u> einen Kartenleser einrichten? + Do you want to automatically start the %1 after boot? + INFO DESKTOP Question if the App shall be started automatically after boot + Wollen Sie die %1 automatisch nach dem Hochfahren starten? - In order to use the online identification feature on the computer, you need to set up a suitable smartphone or card reader before the first authentication process. - INFO DESKTOP Information text why a card reader is required to use the online - Für die Nutzung der Online-Ausweisfunktion am Computer müssen Sie vor dem ersten Ausweisvorgang ein geeignetes Smartphone oder einen separaten Kartenleser einrichten. + In order to successfully use the eID function, %1 has to be running. It is therefore advisable to activate the auto-start after system startup. + INFO DESKTOP Information text why autostart of the App is advisable + Um die Online-Ausweisfunktion erfolgreich nutzen zu können, muss die %1 gestartet sein. Daher ist es ratsam, dies beim Systemstart zuzulassen. - Card Readers - LABEL DESKTOP - Kartenleser + The launch will add an icon to the menu bar. + INFO MACOS Additional information that macOS auto-start adds a symbol to the menu bar + Der Start erfolgt hierbei als Eintrag in der Menüleiste. - You have completed the setup of the AusweisApp2 successfully. - INFO DESKTOP Success message after completing the setup assistant. - Sie haben die Einrichtung der AusweisApp2 erfolgreich abgeschlossen. + Autostart Settings + LABEL DESKTOP + Autostart Einstellungen - Proceed to start page - INFO DESKTOP A11y button text to exit the setup assistant. - Weiter zur Startseite + The launch will add a tray icon to the notification area. + INFO WINDOWS Additional information that Windows auto-start adds a symbol to the notification area. + Der Start erfolgt hierbei als Tray-Icon im Infobereich. @@ -4542,26 +3683,21 @@ LABEL ALL_PLATFORMS - SmartDeleteStartView - - Delete Smart-eID - LABEL ANDROID IOS - Smart-eID löschen - + SmartDeleteBaseView - Are you sure you want to delete the Smart-eID? + Smart-eID LABEL ANDROID IOS - Sind Sie sicher, dass Sie die Smart-eID löschen wollen? + Smart-eID - Delete + Please wait a moment. LABEL ANDROID IOS - Löschen + Bitte warten Sie einen Moment. - Smart-eID + Send log LABEL ANDROID IOS - Smart-eID + Protokoll senden If you want to use that functionality again, you need to set up a new Smart-eID first. @@ -4575,84 +3711,135 @@ LABEL ALL_PLATFORMS - SmartMainView - - Updating Smart-eID status... - LABEL ANDROID IOS - Status der Smart-eID wird aktualisiert... - + SmartDeleteView - Smart-eID not supported + Delete Smart-eID LABEL ANDROID IOS - Smart-eID nicht unterstützt + Smart-eID löschen - Smart-eID invalid + You have successfuly deleted your Smart-eID. LABEL ANDROID IOS - Smart-eID ungültig + Sie haben Ihre Smart-eID erfolgreich gelöscht. - Smart-eID ready for use + The Smart-eID could not be successfully deleted from your device. LABEL ANDROID IOS - Smart-eID einsatzbereit + Die Smart-eID konnte nicht erfolgreich von Ihrem Gerät gelöscht werden. - Smart-eID supported + Back to start page LABEL ANDROID IOS - Smart-eID unterstützt + Zur Startseite - Please wait a moment. + You are about to delete the Smart-eID data that is currently stored on your device. LABEL ANDROID IOS - Bitte warten Sie einen Moment. + Sie sind dabei, die Daten der Smart-eID von Ihrem Gerät zu löschen. - Unfortunately, this functionality is not supported by your device. + Are you sure you want to delete the Smart-eID? LABEL ANDROID IOS - Leider wird diese Funktion von Ihrem Gerät nicht unterstützt. + Sind Sie sicher, dass Sie die Smart-eID löschen wollen? - Your Smart-eID is in an invalid state. You need to set it up again to perform online identifications without your ID card. + Delete LABEL ANDROID IOS - Ihre Smart-eID ist in einem ungültigen Zustand. Sie müssen sie erneut einrichten, um die Online-Ausweisfunktion auch ohne Ausweiskarte nutzen zu können. + Löschen - Your Smart-eID is set up and ready for use. You can now perform online identifications without your ID card if supported by the provider. + Deleting Smart-eID LABEL ANDROID IOS - Ihre Smart-eID ist eingerichtet und einsatzbereit. Sie können die Online-Ausweisfunktion jetzt auch ohne Ausweiskarte nutzen, wenn der jeweilige Diensteanbieter dies unterstützt. + Lösche Smart-eID - Set up a Smart-eID in order to perform online identifications without your ID card if supported by the provider. + Delete the Smart-eID LABEL ANDROID IOS - Richten Sie eine Smart-eID ein, um die Online-Ausweisfunktion auch ohne Ausweiskarte nutzen zu können, wenn der jeweilige Diensteanbieter dies unterstützt. + Löschen der Smart-eID - SmartSettingsView + SmartMainView - Smart-eID + Updating Smart-eID status... LABEL ANDROID IOS - Smart-eID + Status der Smart-eID wird aktualisiert... - Check Smart-eID status + Smart-eID ready for use LABEL ANDROID IOS - Smart-eID-Status prüfen + Smart-eID einsatzbereit - Check device compatibility and the current state of any present Smart-eID + Please wait a moment. LABEL ANDROID IOS - Unterstützung des Geräts sowie den aktuellen Zustand der Smart-eID prüfen + Bitte warten Sie einen Moment. - Set up Smart-eID + Your Smart-eID is set up and ready for use. You can now perform online identifications without your ID card if supported by the provider. LABEL ANDROID IOS - Smart-eID einrichten + Ihre Smart-eID ist eingerichtet und einsatzbereit. Sie können die Online-Ausweisfunktion jetzt auch ohne Ausweiskarte nutzen, wenn der jeweilige Diensteanbieter dies unterstützt. + + + Check here if your device is suitable to set up a Smart-eID. + LABEL ANDROID IOS + Prüfen Sie hier, ob Ihr Gerät für die Einrichtung einer Smart-eID geeignet ist. + + + Start check + LABEL ANDROID IOS + Prüfung starten + + + With the Smart-eID you may also use the online identification function without the ID card. + LABEL ANDROID IOS + Mit der Smart-eID können Sie die Online-Ausweisfunktion auch ohne Ausweiskarte nutzen. + + + + SmartResetView + + Reset Smart-eID + LABEL ANDROID IOS + Smart-eID zurücksetzen + + + You have successfully reset your Smart-eID. + LABEL ANDROID IOS + Sie haben Ihre Smart-eID erfolgreich zurückgesetzt. + + + You are about to reset your Smart-eID data. This can also be used for troubleshooting as well. + LABEL ANDROID IOS + Sie sind dabei, die Daten der Smart-eID auf Ihrem Gerät zurücksetzen. Dies kann auch zur Problembeseitigung verwendet werden. + + + Are you sure you want to reset the Smart-eID? + LABEL ANDROID IOS + Sind Sie sicher, dass Sie die Smart-eID zurücksetzen wollen? + + + Reset + LABEL ANDROID IOS + Zurücksetzen + + + Resetting Smart-eID + LABEL ANDROID IOS + Setze Smart-eID zurück + + + Reset the Smart-eID + LABEL ANDROID IOS + Zurücksetzen der Smart-eID + + + SmartSettingsView - Set up Smart-eID on this device + Smart-eID LABEL ANDROID IOS - Smart-eID auf diesem Gerät einrichten + Smart-eID Renew Smart-eID @@ -4670,19 +3857,29 @@ LABEL ALL_PLATFORMS Smart-eID löschen - Remove Smart-eID data from your device + Delete Smart-eID data from your device LABEL ANDROID IOS Smart-eID Daten von diesem Gerät löschen - Reset Smart-eID + Try Smart-eID LABEL ANDROID IOS - Smart-eID zurücksetzen + Smart-eID ausprobieren + + + Show Smart-eID data + LABEL ANDROID IOS + Smart-eID-Daten anzeigen - Remove Smart-eID data and provisioning from your device + Change Smart-eID PIN + LABEL ANDROID IOS + Smart-eID-PIN ändern + + + Change the chosen Smart-eID PIN LABEL ANDROID IOS - Smart-eID Daten und Vorbereitung entfernen + Selbstgewählte PIN der Smart-eID ändern @@ -4702,14 +3899,14 @@ LABEL ALL_PLATFORMS LABEL ANDROID IOS Smart-eID einrichten - - - SmartUpdateStartView - Smart-eID + Smart-eID setup LABEL ANDROID IOS - Smart-eID + Smart-eID-Einrichtung + + + SmartUpdateStartView You are about to renew your Smart-eID. In order to proceed, you need your ID card, your six-digit ID card PIN and an internet connection. LABEL ANDROID IOS @@ -4725,48 +3922,28 @@ LABEL ALL_PLATFORMS LABEL ANDROID IOS Smart-eID erneuern - - - SmartView - - Smart-eID - LABEL ANDROID IOS - Smart-eID - - - Please wait a moment. - LABEL ANDROID IOS - Bitte warten Sie einen Moment. - - - You are about to delete the Smart-eID data that is currently stored on your device. - LABEL ANDROID IOS - Sie sind dabei, die Daten der Smart-eID von Ihrem Gerät zu löschen. - - - Delete Smart-eID - LABEL ANDROID IOS - Smart-eID löschen - - Deleting Smart-eID + Renew the Smart-eID LABEL ANDROID IOS - Lösche Smart-eID + Erneuern der Smart-eID - You are about to delete the Smart-eID data from your device and also remove the Smart-eID provisioning. This can a be used for troubleshooting as well. + Smart-eID renewal LABEL ANDROID IOS - Sie sind dabei, die Daten der Smart-eID von Ihrem Gerät zu löschen und auch die Smart-eID Vorbereitung zu entfernen. Dies kann auch zur Fehlerbehebung genutzt werden. + Smart-eID-Erneuerung + + + SmartView - Reset Smart-eID + Smart-eID LABEL ANDROID IOS - Smart-eID zurücksetzen + Smart-eID - Resetting Smart-eID + Check Smart-eID LABEL ANDROID IOS - Setze Smart-eID zurück + Smart-eID prüfen @@ -4831,7 +4008,7 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& LABEL ANDROID IOS Sie haben noch keine Smart-eID eingerichtet oder diese ist nicht mehr nutzbar. -Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle auswählen, oder wählen Sie "WLAN", um sich mit einem anderen Smartphone als Kartenleser zu verbinden. Möchten Sie stattdessen eine Smart-eID einrichten, brechen Sie den aktuellen Vorgang bitte ab und starten Sie die Smart-eID Einrichtung vom Startbildschirm. +Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle auswählen, oder wählen Sie "WLAN", um sich mit einem anderen Smartphone als Kartenleser zu verbinden. Möchten Sie stattdessen eine Smart-eID einrichten, brechen Sie den aktuellen Vorgang bitte ab und starten Sie die Smart-eID-Einrichtung vom Startbildschirm. Continue @@ -4846,13 +4023,18 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle auswählen. Möchten Sie stattdessen eine Smart-eID einrichten, brechen Sie den aktuellen Vorgang bitte ab und starten Sie die Smart-eID-Einrichtung vom Startbildschirm. + + The device "%1" wants to access your Smart-eID. + INFO ANDROID IOS %1 will be replaced with the name of the device. + Das Gerät "%1" möchte auf Ihre Smart-eID zugreifen. + StoreFeedbackPopup - Are you satisfied with AusweisApp2? + Are you satisfied with %1? INFO ANDROID Header of the app rating popup. - Zufrieden mit der AusweisApp2? + Zufrieden mit der %1? We would be very grateful if you could leave a rating on the Google Play Store! @@ -4911,26 +4093,6 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au TitleBar - - Navigation bar - LABEL DESKTOP - Navigationsleiste - - - List - LABEL DESKTOP - Liste - - - %1 elements - LABEL DESKTOP - %1 Elemente - - - 1 element - LABEL DESKTOP - 1 Element - Start page LABEL DESKTOP @@ -4944,950 +4106,59 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au Open settings view of %1 Öffne die %1 Einstellungen - - Open online help in browser - Öffne die Online-Hilfe im Browser - - - Open online help of %1 in browser - Öffne die Online-Hilfe der %1 im Browser - Notifications - Benachrichtungen + Benachrichtigungen Show in-app notifications of %1 Zeige den interne Benachrichtigungsdialog der %1 - - - TitleBarAction - - Navigating to %1 in current context disabled - LABEL DESKTOP - Navigation zu %1 ist im aktuellen Kontext deaktiviert - - - element %1 of %2 - LABEL DESKTOP - Element %1 von %2 - - - Current context: %1 - LABEL DESKTOP - Aktueller Kontext: %1 - - Navigate to %1 + Title bar LABEL DESKTOP - Navigiere zu %1 + Titelleiste TitleBarNavigation - Cancel - LABEL ANDROID IOS - Abbrechen - - - Back - LABEL ANDROID IOS - Zurück - - - - TransportPinAssistantView - - Transport PIN - LABEL DESKTOP - Transport-PIN - - - Do you want to change your (Transport) PIN now? - INFO DESKTOP Inquiry message if the five-digit Transport PIN should be changed to an ordinary PIN (now). - Möchten Sie Ihre (Transport-)PIN jetzt ändern? - - - If you have not already done so you have to change your five-digit Transport PIN to a six-digit PIN before you can use the online-ID function. - INFO DESKTOP Hint that a six-digit PIN is required to use the online identification feature of the ID card. - Falls noch nicht geschehen, müssen Sie vor der erstmaligen Nutzung der Online-Ausweisfunktion die fünfstellige Transport-PIN in eine sechsstellige PIN ändern. - - - - TransportPinReminderView - - Do you know your six-digit ID card PIN? - LABEL ANDROID IOS - Kennen Sie Ihre sechsstellige Karten-PIN? - - - No - LABEL ANDROID IOS - Nein - - - Yes - LABEL ANDROID IOS - Ja - - - Online identification with Transport PIN is not possible. The self-selected, six-digit ID card PIN is mandatory to use the eID function. - LABEL ANDROID IOS - Die Benutzung der Online-Ausweisfunktion mit der Transport-PIN ist nicht möglich. Die selbstgewählte, sechsstellige Karten-PIN wird zur Nutzung der Online-Ausweisfunktion zwingend benötigt. - - - - TutorialFooter - - Fold in - LABEL ANDROID IOS - Einklappen - - - Quit tutorial - LABEL ANDROID IOS - Tutorial beenden - - - - TutorialHow - - How can I use the AusweisApp2 on my iPhone? - INFO ANDROID IOS - Wie kann ich die AusweisApp2 auf meinem iPhone nutzen? - - - How can I use the AusweisApp2 on my smartphone? - Wie kann ich die AusweisApp2 auf meinem Smartphone nutzen? - - - Many iPhones (iPhone 7 and newer) can access the ID card via the built-in NFC interface. - INFO ANDROID IOS - Viele iPhones (iPhone 7 und neuer) können direkt über die im Gerät verbaute NFC-Schnittstelle auf die Online-Ausweisfunktion des Ausweises zugreifen. - - - Many Android devices can access the ID card via the built-in NFC interface. - Viele Android-Geräte können direkt über die im Gerät verbaute NFC-Schnittstelle auf die Online-Ausweisfunktion des Ausweises zugreifen. - - - You can test the capabilities of your device and your card by choosing "Check device and ID card" on the start page: - LABEL ANDROID IOS - Indem Sie "Gerät und Ausweis prüfen" auf der Startseite auswählen, können die Funktionalität Ihres Geräts und Ihrer Karte testen: - - - You can also find a list of compatible NFC-capable smartphones here: - LABEL ANDROID IOS - Außerdem finden Sie hier eine Liste kompatibler NFC-fähiger Smartphones: - - - The AusweisApp2 offers the following options to access your ID card: - LABEL ANDROID IOS - Die AusweisApp2 bietet zum Auslesen die folgenden Möglichkeiten: - - - Direct connection via NFC chip tutorial - LABEL ANDROID IOS - Tutorial zum direkten Auslesen über NFC - - - Direct connection via NFC chip - LABEL ANDROID IOS - Direktes Auslesen über NFC-Chip - - - App on iPhone <b>with</b> NFC chip as card reader - LABEL ANDROID IOS - App auf iPhone <b>mit</b> NFC-Chip als Kartenleser - - - App on Android smartphone <b>with</b> NFC chip as card reader - App auf Android-Telefon <b>mit</b> NFC-Chip als Kartenleser - - - Smartphone as card reader tutorial - LABEL ANDROID IOS - Tutorial zum Smartphone als Kartenleser - - - Smartphone as card reader - LABEL ANDROID IOS - Smartphone als Kartenleser - - - App on computer <b>without</b> NFC chip - LABEL ANDROID IOS - App auf Computer <b>ohne</b> NFC-Chip - - - Smartphone <b>with</b> NFC chip as card reader - LABEL ANDROID IOS - Smartphone <b>mit</b> NFC-Chip als Kartenleser - - - Smartphone as card reader mobile tutorial - LABEL ANDROID IOS - Mobilgeräte-Tutorial zum Smartphone als Kartenleser - - - App on tablet or smartphone <b>without</b> NFC chip - LABEL ANDROID IOS - App auf Tablet oder Telefon <b>ohne</b> NFC-Chip - - - Another tip - LABEL ANDROID IOS - Noch ein Tipp - - - For lengthy forms, e.g. a BAföG application, we recommend you to use the AusweisApp2 on a computer... - LABEL ANDROID IOS - Für aufwändigere Formulare wie z.B. den BAföG-Antrag empfehlen wir Ihnen die AusweisApp2 am Computer zu verwenden... - - - Filling long forms is no fun on a smartphone! - LABEL ANDROID IOS - Längere Anträge ausfüllen macht am Mobiltelefon keinen Spaß! - - - ... and to use a smartphone to communicate with your ID card. A USB reader is of course also an alternative. - LABEL ANDROID IOS - ... und zum Lesen des Ausweises das Smartphone als Kartenleser zu nutzen. Alternativ geht natürlich auch ein USB-Lesegerät. - - - - TutorialImportant - - Please exchange your - LABEL ANDROID IOS - Bitte tauschen Sie Ihre - - - Before you use the online ID function please change the - LABEL ANDROID IOS - Vor der erstmaligen Nutzung der Online-Ausweisfunktion bitte die - - - five-digit - LABEL ANDROID IOS - fünfstellige - - - Transport PIN - LABEL ANDROID IOS - Transport-PIN - - - with a - LABEL ANDROID IOS - mit einer - - - six-digit PIN - LABEL ANDROID IOS - sechsstelligen PIN - - - before you use the online ID function! - LABEL ANDROID IOS - bevor Sie die Online-Ausweisfunktion verwenden! - - - change! - LABEL ANDROID IOS - ersetzen! - - - The Transport PIN is sent to you by the Bundesdruckerei via mail. - LABEL ANDROID IOS - Die Transport-PIN wird Ihnen von der Bundesdruckerei per Brief zugesandt. - - - Select for this purpose the menu item "Change my (Transport) PIN" from the start page. Later you can also change your six-digit PIN here - LABEL ANDROID IOS - Wählen Sie zu diesem Zweck den Menüeintrag "Meine (Transport-)PIN ändern" auf der Startseite. Später können Sie an dieser Stelle auch Ihre sechsstellige PIN ändern - - - ... or click this button to change your PIN right now: - LABEL ANDROID IOS - ... oder auf diesen Button klicken um die PIN jetzt zu ändern: - - - Change my (Transport) PIN - LABEL ANDROID IOS - Meine (Transport-)​PIN ändern - - - Please note: The Transport PIN can only be used for your first PIN change. If you have already set your six-digit PIN (e.g. while picking up your ID card) only the set PIN is valid. - LABEL ANDROID IOS - Hinweis: Die Transport-PIN kann nur für die erstmalige PIN-Änderung verwendet werden. Sollten Sie (z.B. bei der Abholung Ihres Ausweises) bereits eine sechsstellige PIN gesetzt haben, ist nur noch diese gültig. - - - Open YouTube video - LABEL ANDROID IOS - Öffne das YouTube-Video - - - Learn more about this in the YouTube video - LABEL ANDROID IOS - Sie können mehr dazu im YouTube-Video erfahren - - - Let's go - LABEL ANDROID IOS - Los geht's - - - Do you still have questions? - LABEL ANDROID IOS - Oder haben Sie noch Fragen? - - - You can read our <b>FAQs</b> or <b>write</b> to us... - LABEL ANDROID IOS - Dann können Sie in unsere <b>FAQs</b> schauen oder uns <b>schreiben</b>... - - - or - LABEL ANDROID IOS - oder - - - You can always access this tutorial again from the "Help" section in the menu bar. - LABEL ANDROID IOS - Sie können dieses Tutorial jederzeit wieder über den Bereich "Hilfe" aufrufen. - - - If you cannot recall your six-digit PIN or cannot find your PIN letter, you may request a new PIN using the PIN Reset Service. - LABEL ANDROID IOS - Falls Sie sich nicht an Ihre sechsstellige PIN erinnern oder den PIN-Brief nicht finden können, können Sie eine neue PIN mithilfe des PIN-Rücksetzdienstes beantragen. - - - - TutorialReaderMethodFooter - - Back - LABEL ANDROID IOS - Zurück - - - - TutorialReaderMethodNfc - - Tutorial: NFC - LABEL ANDROID IOS - Tutorial: NFC - - - Direct connection via NFC chip - LABEL ANDROID IOS - Direktes Auslesen über NFC Chip - - - App on iPhone <b>with</b> NFC chip as card reader - LABEL IOS - App auf iPhone <b>mit</b> NFC-Chip als Kartenleser - - - App on Android smartphone <b>with</b> NFC chip as card reader - LABEL ANDROID - App auf Android-Telefon <b>mit</b> NFC-Chip als Kartenleser - - - Click link on the website of the provider. - LABEL ANDROID IOS - Link auf Webseite des Anbieters klicken. - - - The App opens automatically. - LABEL ANDROID IOS - Die App öffnet sich automatisch. - - - The AusweisApp2 will display who wants to access which data. - LABEL ANDROID IOS - Ihnen wird angezeigt, wer welche Ihrer Daten abfragen will. - - - Start the process with a click on: - LABEL ANDROID IOS - Starten Sie den Vorgang mit: - - - Proceed to PIN entry - LABEL ANDROID IOS - Weiter zur PIN-Eingabe - - - ... and place the top of the iPhone onto the ID card. - LABEL IOS - ...und platzieren Sie die Oberkante des iPhones auf dem Ausweis. - - - ... and place the ID card flat onto the NFC interface. - LABEL ANDROID - ...und platzieren Sie den Ausweis flach an der NFC-Schnittstelle. - - - Do not move device or ID card! - LABEL ANDROID IOS - Gerät und Ausweis nicht bewegen! - - - The correct position is specific for your device. If a position does not work try a different one. The AusweisApp2 shows different common positions. - LABEL ANDROID - Die korrekte Position ist abhängig von Ihrem Gerät. Probieren Sie andere Positionen aus wenn eine nicht funktionieren sollte. Die AusweisApp2 zeigt verschiedene typische Positionen. - - - If your device is unable to detect your ID card try to check the device capabilities by clicking on "Check device and ID card" on the start page. - LABEL ANDROID - Wenn Ihr Gerät keinen Ausweis erkennen kann versuchen Sie die Gerätefähigkeiten zu testen indem Sie "Gerät und Ausweis prüfen" auf der Startseite auswählen. - - - You can find more information on compatible devices on our %1mobile device list%2. - LABEL ANDROID IOS - Mehr Informationen zu kompatiblen Geräten finden Sie auf unserer %1Mobilgeräteliste%2. - - - Enter - LABEL ANDROID IOS This is the first of three lines "Enter" "six-digit PIN" "now!" and should be translated accoording to the third line. - Jetzt - - - six-digit PIN - LABEL ANDROID IOS - sechsstellige PIN - - - now! - LABEL ANDROID IOS This is the third of three lines "Enter" "six-digit PIN" "now!" and should be translated accoording to the first line. - eingeben! - - - This is only possible if you have exchanged the five-digit Transport PIN with a six-digit PIN beforehand. - LABEL ANDROID IOS - Funktioniert nur, wenn Sie die fünfstellige Transport-PIN bereits in eine sechsstellige PIN geändert haben. - - - Open YouTube video - LABEL ANDROID IOS - Öffne das YouTube-Video - - - You can also watch this YouTube video explaining the process. - LABEL ANDROID IOS - Sie können sich auch dieses YouTube-Video ansehen das den Prozess erläutert. - - - - TutorialReaderMethodSacDesktop - - Tutorial: Smartphone as card reader - LABEL ANDROID IOS - Tutorial: Smartphone als Kartenleser - - - Smartphone as card reader - LABEL ANDROID IOS - Smartphone als Kartenleser - - - App on computer <b>without</b> NFC chip - LABEL ANDROID IOS - App auf Computer <b>ohne</b> NFC-Chip - - - Smartphone <b>with</b> NFC chip as card reader - LABEL ANDROID IOS - Smartphone <b>mit</b> NFC-Chip als Kartenleser - - - Install AusweisApp2 on both your computer <b>and</b> your smartphone with NFC capability. - LABEL ANDROID IOS - Installieren Sie die AusweisApp2 <b>sowohl</b> auf Ihrem Rechner <b>als auch</b> auf Ihrem NFC-fähigen Smartphone. - - - Both devices have to be connected to the same WiFi network - LABEL ANDROID IOS - Beide Geräte müssen im selben WLAN sein - - - Now choose "Card reader" in the AusweisApp2 on your smartphone... - LABEL ANDROID IOS - Öffnen Sie nun in der AusweisApp2 auf dem Smartphone die Ansicht "Kartenleser"... - - - Now - LABEL ANDROID IOS - Jetzt - - - Pair device - LABEL ANDROID IOS - Gerät koppeln - - - Pairing code - LABEL ANDROID IOS - Kopplungscode - - - appears! - LABEL ANDROID IOS - erscheint! - - - On the first use of the Smartphone as card reader (SaC), iOS will asks for your permission to access the local network. This permission is required in order find and connect to your SaC. After the first request you can always access the permission in the iOS settings for this app. - LABEL IOS - Bei der ersten Verwendung des Smartphones als Kartenleser (SaK) bittet iOS Sie um Ihre Erlaubnis um auf das lokale Netzwerk zugreifen zu dürfen. Diese Berechtigung ist erforderlich, um Ihr SaK zu finden und eine Verbindung zu ihm herzustellen. Nach der ersten Anfrage können Sie jederzeit auf die Berechtigung in den iOS-Einstellungen für diese App zugreifen. - - - Start the App now on your computer and enter the settings. - LABEL ANDROID IOS - Öffnen Sie nun die App auf dem Computer und gehen auf Einstellungen. - - - Select the <b>Smartphone as card reader</b> tab. - LABEL ANDROID IOS - Den Reiter <b>Smartphone als Kartenleser</b> auswählen. - - - Select smartphone from list - LABEL ANDROID IOS - Smartphone in der Liste auswählen - - - Enter pairing code next. - LABEL ANDROID IOS - Dann Kopplungscode eingeben. - - - Click link on the website of the provider. - LABEL ANDROID IOS - Link auf Webseite des Anbieters klicken. - - - The App opens automatically. - LABEL ANDROID IOS - Die App öffnet sich automatisch. - - - The AusweisApp2 will display who wants to access which data. - LABEL ANDROID IOS - Ihnen wird angezeigt, wer welche Ihrer Daten abfragen will. - - - Start the process with a click on: - LABEL ANDROID IOS - Starten Sie den Vorgang mit: - - - Proceed to PIN entry - LABEL ANDROID IOS - Weiter zur PIN-Eingabe - - - ... and place the ID card onto the NFC interface. - LABEL ANDROID IOS - ...und platzieren Sie den Ausweis auf die NFC-Schnittstelle. - - - Do not move device or ID card! - LABEL ANDROID IOS - Gerät und Ausweis nicht bewegen! - - - The correct position is specific for your device. If a position does not work try a different one. The AusweisApp2 shows different common positions. - LABEL ANDROID IOS - Die korrekte Position ist abhängig von Ihrem Gerät. Probieren Sie andere Positionen aus wenn eine nicht funktionieren sollte. Die AusweisApp2 zeigt verschiedene typische Positionen. - - - If your device is unable to detect your ID card try to check the device capabilities by clicking on "Check device and ID card" on the start page. - LABEL ANDROID IOS - Wenn Ihr Gerät keinen Ausweis erkennen kann versuchen Sie die Gerätefähigkeiten zu testen indem Sie "Gerät und Ausweis prüfen" auf der Startseite auswählen. - - - You can find more information on compatible devices on our %1mobile device list%2. - LABEL ANDROID IOS - Mehr Informationen zu kompatiblen Geräten finden Sie auf unserer %1Mobilgeräteliste%2. - - - Enter - LABEL ANDROID IOS This is the first of three lines "Enter" "six-digit PIN" "now!" and should be translated according to the third line. - Jetzt - - - six-digit PIN - LABEL ANDROID IOS - sechsstellige PIN - - - now! - LABEL ANDROID IOS This is the third of three lines "Enter" "six-digit PIN" "now!" and should be translated according to the first line. - eingeben! - - - This is only possible if you have exchanged the five-digit Transport PIN with a six-digit PIN beforehand. - LABEL ANDROID IOS - Funktioniert nur, wenn Sie die fünfstellige Transport-PIN bereits in eine sechsstellige PIN geändert haben. - - - Open YouTube video - LABEL ANDROID IOS - Öffne das YouTube-Video - - - You can also watch this YouTube video explaining the process. - LABEL ANDROID IOS - Sie können sich auch dieses YouTube-Video ansehen das den Prozess erläutert. - - - - TutorialReaderMethodSacMobile - - Tutorial: Smartphone as card reader - LABEL ANDROID IOS - Tutorial: Smartphone als Kartenleser - - - App on tablet or smartphone <b>without</b> NFC chip - LABEL ANDROID IOS - App auf Tablet oder Telefon <b>ohne</b> NFC-Chip - - - Smartphone <b>with</b> NFC chip as card reader - LABEL ANDROID IOS - Smartphone <b>mit</b> NFC-Chip als Kartenleser - - - Install AusweisApp2 on both your device without NFC <b>and</b> your smartphone with NFC capability. - LABEL ANDROID IOS - Installieren Sie die AusweisApp2 auf Ihrem Gerät ohne NFC <b>und</b> auf Ihrem NFC-fähigen Smartphone. - - - Both devices have to be connected to the same WiFi network - LABEL ANDROID IOS - Beide Geräte müssen im selben WLAN sein - - - Now choose "Card reader" in the AusweisApp2 on your smartphone... - LABEL ANDROID IOS - Öffnen Sie nun in der AusweisApp2 auf dem Smartphone den Bereich "Kartenleser"... - - - Now - LABEL ANDROID IOS - Jetzt - - - Pair device - LABEL ANDROID IOS - Gerät koppeln - - - Pairing code - LABEL ANDROID IOS - Kopplungscode - - - appears! - LABEL ANDROID IOS - erscheint! - - - On the first use of the Smartphone as card reader (SaC), iOS will asks for your permission to access the local network. This permission is required in order find and connect to your SaC. After the first request you can always access the permission in the iOS settings for this app. - LABEL IOS - Bei der ersten Verwendung des Smartphones als Kartenleser (SaK) bittet iOS Sie um Ihre Erlaubnis um auf das lokale Netzwerk zugreifen zu dürfen. Diese Berechtigung ist erforderlich, um Ihr SaK zu finden und eine Verbindung zu ihm herzustellen. Nach der ersten Anfrage können Sie jederzeit auf die Berechtigung in den iOS-Einstellungen für diese App zugreifen. - - - Now open the AusweisApp2 on your device <b>without</b> NFC and select <b>Manage pairings</b>. - LABEL IOS - Öffnen Sie nun die AusweisApp2 auf dem Gerät <b>ohne</b> NFC und wählen Sie <b>Kopplungen verwalten</b> aus. - - - Now open the AusweisApp2 on your device <b>without</b> NFC and select <b>Smartphone as card reader</b>. - LABEL ANDROID - Öffnen Sie nun die AusweisApp2 auf dem Gerät <b>ohne</b> NFC und wählen <b>Smartphone als Kartenleser</b> aus. - - - Now select <b>Settings</b>. - LABEL ANDROID IOS - Dort <b>Einstellungen</b> auswählen. - - - Choose smartphone from list - LABEL ANDROID IOS - Smartphone aus Liste wählen - - - Enter pairing code next. - LABEL ANDROID IOS - Dann Kopplungscode eingeben. - - - Click link on the website of the provider on the device <b>without</b> NFC. - LABEL ANDROID IOS - Auf dem Gerät <b>ohne</b> NFC Link auf Webseite des Anbieters klicken. - - - The App opens automatically. - LABEL ANDROID IOS - Die App öffnet sich automatisch. - - - The AusweisApp2 will display who wants to access which data. - LABEL ANDROID IOS - Ihnen wird angezeigt, wer welche Ihrer Daten abfragen will. - - - Start the process with a click on: - LABEL ANDROID IOS - Den Vorgang starten mit: - - - Proceed to PIN entry - LABEL ANDROID IOS - Weiter zur PIN-Eingabe - - - Tap on WiFi - LABEL ANDROID IOS - Tap auf WLAN - - - ... and place the ID card onto the NFC interface. - LABEL ANDROID IOS - ...und platzieren Sie den Ausweis auf die NFC-Schnittstelle. - - - Do not move device or ID card! - LABEL ANDROID IOS - Gerät und Ausweis nicht bewegen! - - - The correct position is specific for your device. If a position does not work try a different one. The AusweisApp2 shows different common positions. - LABEL ANDROID IOS - Die korrekte Position ist abhängig von Ihrem Gerät. Probieren Sie andere Positionen aus wenn eine nicht funktionieren sollte. Die AusweisApp2 zeigt verschiedene typische Positionen. - - - If your device is unable to detect your ID card try to check the device capabilities by clicking on "Check device and ID card" on the start page. - LABEL ANDROID IOS - Wenn Ihr Gerät keinen Ausweis erkennen kann versuchen Sie die Gerätefähigkeiten zu testen indem Sie "Gerät und Ausweis prüfen" auf der Startseite auswählen. - - - You can find more information on compatible devices on our %1mobile device list%2. - LABEL ANDROID IOS - Mehr Informationen zu kompatiblen Geräten finden Sie auf unserer %1Mobilgeräteliste%2. - - - Enter - LABEL ANDROID IOS This is the first of three lines "Enter" "six-digit PIN" "now!" and should be translated according to the third line. - Jetzt - - - six-digit PIN - LABEL ANDROID IOS - sechsstellige PIN - - - now! - LABEL ANDROID IOS This is the third of three lines "Enter" "six-digit PIN" "now!" and should be translated according to the first line. - eingeben! - - - This is only possible if you have exchanged the five-digit Transport PIN with a six-digit PIN beforehand. - LABEL ANDROID IOS - Funktioniert nur, wenn Sie die fünfstellige Transport-PIN bereits in eine sechsstellige PIN geändert haben. - - - - TutorialView - - Tutorial - LABEL ANDROID IOS - Tutorial - - - What? - LABEL ANDROID IOS - Was? - - - Where? - LABEL ANDROID IOS - Wo? - - - How? - LABEL ANDROID IOS - Wie? - - - Important! - LABEL ANDROID IOS - Wichtig! - - - - TutorialWhat - - What is the online ID function? - LABEL ANDROID IOS - Was ist die Online-Ausweisfunktion? - - - You can use it to authenticate yourself in the internet - LABEL ANDROID IOS - Mit ihr weisen Sie sich sicher im Internet aus - - - and also to deal with administrative paperwork and business matters electronically! - LABEL ANDROID IOS - und erledigen damit Behördengänge oder geschäftliche Angelegenheiten einfach elektronisch! - - - Alright, but is it secure? - LABEL ANDROID IOS - Alles klar, nur ist das auch sicher? - - - Of course, because we use a so called - LABEL ANDROID IOS - Natürlich, dafür haben wir die sogenannte - - - Mutual authentication - LABEL ANDROID IOS - gegenseitige Authentifizierung - - - ... it establishes a secure connection between ID card and provider. - LABEL ANDROID IOS - ...sie stellt eine sichere Verbindung zwischen Ausweis und Anbieter her. - - - On every authentication you get displayed <b>who</b> wants to access <b>which</b> data - LABEL ANDROID IOS - Ihnen wird immer zuerst angezeigt, <b>wer welche</b> Daten auslesen möchte - - - and you consent to the request with your six-digit PIN. - LABEL ANDROID IOS - und Sie stimmen der Abfrage mit Ihrer sechsstelligen PIN zu. - - - ... is the provider authorized for this? - LABEL ANDROID IOS - ... und darf der das? - - - The provider needs an authorization of the Federal Office of Administration. - LABEL ANDROID IOS - Der Anbieter benötigt eine Berechtigung vom Bundesverwaltungsamt. - - - Certificate - LABEL ANDROID IOS - Zertifikat - - - Every time both participants authenticate each other... - LABEL ANDROID IOS - Es weisen sich also immer beide Seiten eindeutig aus... - - - ... and therefore your data is protected and securely transferred. - LABEL ANDROID IOS - ... so werden Ihre Daten geschützt und sicher übermittelt. - - - You can also watch a video on YouTube on this topic - LABEL ANDROID IOS - Sie können sich hierzu auch ein Video auf YouTube anschauen - - - Open YouTube video - LABEL ANDROID IOS - Öffne das YouTube-Video - - - - TutorialWhere - - Where can I use the online ID function? - LABEL ANDROID IOS - Wo kann ich die Online-Ausweisfunktion nutzen? - - - On every website of a provider where you see this icon: + Cancel LABEL ANDROID IOS - Überall, wo Sie auf der Webseite eines Online-Dienstes folgendes Logo sehen: + Abbrechen - By the way, you can find many services directly in the AusweisApp2 <b>provider list</b>. + Back LABEL ANDROID IOS - Übrigens, viele Dienste finden Sie direkt in der <b>Anbieterliste</b> der AusweisApp2. + Zurück + + + TransportPinReminderView - The <b>integrated self-authentication</b> is a special service to view the data saved on your ID card. + Do you know your six-digit ID card PIN? LABEL ANDROID IOS - Die <b>integrierte Selbstauskunft</b> ist ein spezieller Dienst, um Daten einzusehen, die auf Ihrem Ausweis gespeichert sind. + Kennen Sie Ihre sechsstellige Karten-PIN? - And this is how it works + No LABEL ANDROID IOS - Und so funktioniert's + Nein - The AusweisApp2 will always display <b>who</b> wants to access <b>which</b> of your data. + Yes LABEL ANDROID IOS - Die AusweisApp2 zeigt Ihnen immer an, wer welche Ihrer Daten abfragen will. + Ja - To allow the shown service access to the requested data click "Proceed to PIN entry" + Online identification with Transport PIN is not possible. The self-selected, six-digit ID card PIN is mandatory to use the eID function. LABEL ANDROID IOS - Um dem angezeigten Dienst Zugriff auf die angefragten Daten zu gewähren drücken Sie auf "Weiter zur PIN-Eingabe" - - - Now lay down your ID card and hold the top of your iPhone to the ID card. - LABEL IOS - Legen Sie nun Ihren Ausweis vor sich hin und halten Sie die Oberkante des iPhones an den Ausweis. - - - Now place your ID card on the NFC-interface of your smartphone. - LABEL ANDROID - Platzieren Sie nun Ihren Ausweis auf die NFC-Schnittstelle Ihres Smartphones. - - - The correct position is specific for your device. If a position does not work try a different one. The AusweisApp2 shows different common positions. If your device is unable to detect your ID card try to check the device capabilities by clicking on "Check device and ID card" on the start page. - LABEL ANDROID - Die korrekte Position ist abhängig von Ihrem Gerät. Probieren Sie andere Positionen aus wenn eine nicht funktionieren sollte. Die AusweisApp2 zeigt verschiedene typische Positionen. Wenn Ihr Gerät keinen Ausweis erkennen kann versuchen Sie die Gerätefähigkeiten zu testen indem Sie "Gerät und Ausweis prüfen" auf der Startseite auswählen. - - - Do not move your iPhone during the procedure! - LABEL IOS - iPhone während des gesamten Vorgangs nicht bewegen! - - - Do not move your device during the procedure! - LABEL ANDROID - Gerät während des gesamten Vorgangs nicht bewegen! - - - Enter - LABEL ANDROID IOS This is the first of three lines "Enter" "six-digit PIN" "now!" and should be translated according to the third line. - Jetzt + Die Benutzung der Online-Ausweisfunktion mit der Transport-PIN ist nicht möglich. Die selbstgewählte, sechsstellige Karten-PIN wird zur Nutzung der Online-Ausweisfunktion zwingend benötigt. - six-digit PIN + To set up a Smart-eID you also need to have assigned a six-digit PIN beforehand. LABEL ANDROID IOS - sechsstellige PIN - - - now! - LABEL ANDROID IOS This is the third of three lines "Enter" "six-digit PIN" "now!" and should be translated according to the first line. - eingeben! + Auch für die Einrichtung der Smart-eID müssen Sie zuvor die sechsstellige Karten-PIN gesetzt haben. @@ -6013,24 +4284,6 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au Link zur Prüfsumme: - - Utils - - today - LABEL ALL_PLATFORMS - heute - - - yesterday - LABEL ALL_PLATFORMS - gestern - - - dd.MM.yyyy - LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString - dd.MM.yyyy - - VersionInformation @@ -6077,14 +4330,14 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au Gerätedaten senden? - Would you like to help us to improve the AusweisApp2? + Would you like to help us to improve the %1? INFO ANDROID IOS Request to the user if the device information should be shared for statistics (Whitelist) - Part of content text - Möchten Sie uns helfen, die AusweisApp2 zu verbessern? + Möchten Sie uns helfen, die %1 zu verbessern? Supplying your device characteristics helps us to gather reliable information about the compatibility of your device. INFO ANDROID IOS Request to the user if the device information should be shared for statistics (Whitelist) - Part of content text - Mit der Übermittlung Ihrer Gerätedaten helfen Sie uns, verlässliche Aussagen über die Kompatibilität Ihres Gerätes mit der AusweisApp2 zu treffen. + Mit der Übermittlung Ihrer Gerätedaten helfen Sie uns, verlässliche Aussagen über die Kompatibilität Ihres Gerätes zu treffen. The transmission is anonymous. No personal data is collected or transmitted! @@ -6111,6 +4364,14 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au Senden + + WorkflowInfoList + + The device "%1" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. + INFO ANDROID IOS The paired smartphone was removed since it did not respond to connection attempts. It needs to be paired again before using it. + Das Gerät "%1" wurde entkoppelt, da es nicht auf Verbindungsversuche reagiert hat. Koppeln Sie das Gerät erneut, um es wieder als Kartenleser zu verwenden. + + governikus::AccessRoleAndRightsUtil @@ -6563,9 +4824,9 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au Firewalls von Drittanbietern - Outgoing AusweisApp2 rule + Outgoing %1 rule LABEL DESKTOP - Ausgehende AusweisApp2-Regel + Ausgehende %1-Regel Exists: %1 @@ -6573,9 +4834,9 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au Existiert: %1 - Incoming AusweisApp2 rule + Incoming %1 rule LABEL DESKTOP - Eingehende AusweisApp2-Regel + Eingehende %1-Regel Windows firewall rules @@ -6929,7 +5190,7 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au Die Anwendung hat einen Fehler vom Server erhalten. - Hash of TLS certificate not in certificate description (issuer: %1). This indicates a misconfiguration or manipulation of the certificate. Please check that your antivirus-software and firewalls are not interfering with TLS traffic. + Hash of TLS certificate not in certificate description (issuer: %1). This indicates a misconfiguration or manipulation of the certificate. Please check that your antivirus software and firewall are not interfering with TLS traffic. ERROR ALL_PLATFORMS The TLS certificate was not folded with the Authorization Certificate, thus violating the security requirements. Might also be caused by a firewall and/or the antivirus software. Der Hashwert des TLS-Zertifikats ist nicht in der Zertifikatsbeschreibung vorhanden (Aussteller: %1). Dies deutet auf eine Fehlkonfiguration oder Manipulation des Zertifikats hin. Bitte überprüfen Sie, dass weder eine Antivirus-Software noch eine Firewall in den TLS-Verkehr eingreifen. @@ -6948,11 +5209,6 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au ERROR ALL_PLATFORMS The device does not support the Smart-eID function Dieses Gerät unterstützt keine Smart-eID. - - The preparation of the Smart-eID Applet failed. - ERROR ANDROID The preparation of the Smart-eID Applet failed - Die Vorbereitung des Smart-eID-Applet ist fehlgeschlagen. - Initialization of Personalization of Smart-eID failed. ERROR ALL_PLATFORMS Initialization of Personalization failed @@ -7069,9 +5325,9 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au Bei der Kommunikation mit dem Ausweis ist ein Fehler aufgetreten. Bitte überprüfen Sie, dass der Ausweis korrekt aufgelegt ist und versuchen Sie es erneut. - A protocol error occurred. Please make sure that your ID card is placed correctly on the card reader and try again. If the problem occurs again, please contact our support at %1AusweisApp2 Support%2. - ERROR ALL_PLATFORMS Communication with the card failed due to the specification of the TR (Technische Richtlinie). The protocol was faulty or invalid values were requested/received, - Ein Protokollfehler ist aufgetreten. Bitte überprüfen Sie, dass der Ausweis korrekt aufgelegt ist und versuchen Sie es erneut. Wenn das Problem wieder auftritt kontaktieren Sie bitte unseren Support unter %1AusweisApp2 Support%2. + A protocol error occurred. Please make sure that your ID card is placed correctly on the card reader and try again. If the problem occurs again, please contact our support at %1. + ERROR ALL_PLATFORMS Communication with the card failed due to the specification of the TR (Technische Richtlinie). The protocol was faulty or invalid values were requested/received. %1 is a html link to the support. + Ein Protokollfehler ist aufgetreten. Bitte überprüfen Sie, dass der Ausweis korrekt aufgelegt ist und versuchen Sie es erneut. Wenn das Problem wieder auftritt kontaktieren Sie bitte unseren Support unter %1. The given PIN is not correct. @@ -7118,11 +5374,6 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au ERROR ALL_PLATFORMS The validity verification of the card failed. Die Gültigkeitsprüfung der Karte ist fehlgeschlagen. - - The Smart-eID is invalid. This might have been caused by entering the wrong Smart-eID PIN three times. - ERROR ALL_PLATFORMS The existing Smart-eID was invalidated. - Die Smart-eID ist ungültig. Dies kann an der dreifachen, fehlerhaften Eingabe der Smart-eID-PIN liegen. - The smartphone as card reader (SaC) connection was aborted. ERROR ALL_PLATFORMS The connection to the smartphone card reader (SaK) was lost. @@ -7134,9 +5385,9 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au Die Verbindungsanforderung zum Smartphone als Kartenleser (SaK) war fehlerhaft. - Your smartphone as card reader (SaC) version is incompatible with the local version. Please install the latest AusweisApp2 version on both your smartphone and your computer. + Your smartphone as card reader (SaC) version is incompatible with the local version. Please install the latest %1 version on both your smartphone and your computer. ERROR ALL_PLATFORMS The requested connection to the smartphone card reader (SaK) was invalid (API mismatch). - Die Version Ihres Smartphones als Kartenleser (SaK) ist inkompatibel. Bitte aktualisieren Sie Ihre Installation. + Die Version Ihres Smartphones als Kartenleser (SaK) ist inkompatibel. Installieren Sie bitte auf Ihrem Smartphone und Ihrem Computer die aktuellste %1 Version. A timeout occurred while trying to establish a connection to the smartphone as card reader (SaC). @@ -7183,26 +5434,55 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au ERROR ALL_PLATFORMS Starting the update failed. Ein neuer Prozess zur Durchführung der Aktualisierung konnte nicht gestartet werden. + + You have reached the allowed amount of Smart-eID setups for the current period. You may set up another Smart-eID with your ID card on %1. + ERROR ALL_PLATFORMS Personalization of Smart-eID is not allowed, no remaining attempts are left. + Sie haben die erlaubte Anzahl an Smart-eID-Einrichtungen für den aktuellen Zeitraum erreicht. Sie können ab dem %1 wieder eine Smart-eID mit Ihrem Ausweis einrichten. + + + Failed to get the ServiceInformation of the Smart-eID. + ERROR ALL_PLATFORMS Failed to get the ServiceInformation of the Smart-eID + Die Service-Informationen zu Ihrer Smart-eID konnten nicht abgerufen werden. + + + The authentication to the personalization service failed. + ERROR ALL_PLATFORMS No sessionID, required for a personalization, was received + Die Authentisierung gegenüber dem Personalisierungsservice ist fehlgeschlagen. + + + The Smart-eID is no longer ready for use. This might have been caused by entering the wrong Smart-eID PIN three times. You may personalize a new Smart-eID to resolve the issue. + ERROR ALL_PLATFORMS The existing Smart-eID was invalidated. + Die Smart-eID ist nicht mehr einsatzbereit. Dies kann an einer dreifachen, fehlerhaften Eingabe der Smart-eID-PIN liegen. Um dieses Problem zu beheben, können Sie eine neue Smart-eID personalisieren. + + + The preparation of the Smart-eID failed. + ERROR ANDROID The preparation of the Smart-eID Applet failed + Die Vorbereitung der Smart-eID ist fehlgeschlagen. + The program did not receive a StartPaosResponse message from the server. ERROR_MASKED ALL_PLATFORMS The PAOS message StartPaosResponse was not received. Die Anwendung hat keine StartPaosResponse Nachricht vom Server erhalten. - - - governikus::HistoryModel - No data stored on your ID card was read, only confirmed whether you are in possession of a valid ID card. - LABEL ALL_PLATFORMS - Es wurden keine Daten von Ihrem Ausweis ausgelesen, sondern lediglich sichergestellt, dass Sie im Besitz eines gültigen Ausweises sind. + The server could not process the client request. + ERROR_MASKED ALL_PLATFORMS + Der Server konnte die Anfrage des Clients nicht verarbeiten. - - - governikus::HistoryModelSearchFilter - dd.MM.yyyy - LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString - dd.MM.yyyy + The service encountered an internal error while processing a request. + ERROR ALL_PLATFORMS A server has responded with an HTTP error code 5xx. + Bei der Bearbeitung der Anfrage ist beim Dienstanbieter ein Fehler aufgetreten. + + + The service reported an error while processing a client request. + ERROR ALL_PLATFORMS A server has responded with an HTTP error code 4xx. + Der Dienstanbieter hat bei der Verarbeitung der Anfrage Fehler festgestellt. + + + %1 Support + LABEL ALL_PLATFORMS Link text to the app support. %1 is the app name. + %1 Support @@ -7325,11 +5605,6 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au INFO ALL_PLATFORMS The wrong Transport PIN was entered on the first attempt. Sie haben eine falsche, fünfstellige Transport-PIN eingegeben. Sie haben zwei weitere Versuche, die korrekte Transport-PIN einzugeben. - - Please note that you may use the five-digit Transport PIN only once to change to a six-digit ID card PIN. If you already set a six-digit ID card PIN, the five-digit Transport PIN is no longer valid. - INFO ALL_PLATFORMS - Bitte beachten Sie, dass Sie die fünfstellige Transport-PIN nur einmalig zum Ändern in eine sechsstellige Karten-PIN verwenden können. Wenn Sie bereits eine sechsstellige Karten-PIN festgelegt haben, ist die fünfstellige Transport-PIN nicht mehr gültig. - You have entered an incorrect, six-digit Smart-eID PIN. You have two further attempts to enter the correct Smart-eID PIN. INFO ALL_PLATFORMS The wrong Smart-eID PIN was entered on the first attempt. @@ -7345,11 +5620,6 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au INFO ALL_PLATFORMS The wrong Transport PIN was entered twice, the next attempt requires the CAN for additional verification. Sie haben zweimal eine falsche, fünfstellige Transport-PIN eingegeben. Für den dritten Versuch muss zunächst die sechsstellige Zugangsnummer (CAN) eingegeben werden. Sie finden Ihre CAN unten rechts auf der Vorderseite Ihres Ausweises. - - You have entered an incorrect, six-digit Smart-eID PIN twice. An incorrect third attempt will invalidate your Smart-eID and you will have to set it up again. - INFO ANDROID IOS The wrong Smart-eID PIN was entered twice, a third wrong attempt could invalidate the Smart-eID. - Sie haben zweimal eine falsche, sechsstellige Smart-eID-PIN eingegeben. Ein dritter Fehlversuch wird Ihre Smart-eID ungültig machen und Sie müssen sie neu einrichten. - You have entered an incorrect, six-digit ID card PIN twice. For a third attempt, the six-digit Card Access Number (CAN) must be entered first. You can find your CAN in the bottom right on the front of your ID card. INFO ALL_PLATFORMS The wrong ID card PIN was entered twice, the next attempt requires the CAN for additional verification. @@ -7380,96 +5650,19 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au INFO ALL_PLATFORMS The PUK entered wrongfully and needs to be supplied again. Sie haben einen falschen, zehnstelligen PUK eingegeben. Bitte versuchen Sie es erneut. - - - governikus::PdfCreator - - AusweisApp2 is a product of Governikus GmbH & Co. KG - on behalf of the Federal Office for Information Security. - LABEL ALL_PLATFORMS - Die AusweisApp2 ist ein Produkt der Governikus GmbH & Co. KG - im Auftrag des Bundesamtes für Sicherheit in der Informationstechnik. - - - For further information, please see %1 - LABEL ALL_PLATFORMS Footer in a generated PDF document. %1 is an URL. - Mehr Information finden Sie auf %1 - - - - governikus::PdfExporter - - Date - LABEL ALL_PLATFORMS - Datum - - - Details - LABEL ALL_PLATFORMS - Details - - - dd.MM.yyyy hh:mm AP - LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString - dd.MM.yyyy HH:mm - - - Provider: - LABEL ALL_PLATFORMS - Anbieter: - - - Purpose: - LABEL ALL_PLATFORMS - Zweck: - - - Read access: - LABEL ALL_PLATFORMS - Lesezugriff: - - - Write access (update): - LABEL ALL_PLATFORMS - Schreibzugriff (Aktualisierung): - - - dd.MM.yyyy - LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString - dd.MM.yyyy - - - hh:mm AP - LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString - HH:mm - - - At %1 %2 the following data were saved: - LABEL ALL_PLATFORMS - Die folgenden Daten wurden hier %1 %2 gespeichert: - - - History - LABEL ALL_PLATFORMS - Verlauf - - - Entry - LABEL ALL_PLATFORMS - Eintrag - - Content - LABEL ALL_PLATFORMS - Inhalt + You have entered an incorrect, six-digit Smart-eID PIN twice. After the next failed attempt you will no longer be able to use your Smart-eID and will need to set it up again. + INFO ANDROID IOS The wrong Smart-eID PIN was entered twice, a third wrong attempt could invalidate the Smart-eID. + Sie haben zweimal eine falsche, sechsstellige Smart-eID-PIN eingegeben. Nach dem nächsten Fehlversuch können Sie Ihre Smart-eID nicht mehr einsetzen und müssen diese neu einrichten. - At %1 %2 the following data has been read out of your ID card: - LABEL ALL_PLATFORMS - Die folgenden Daten wurden hier %1 %2 aus Ihrem Ausweis ausgelesen: + The input does not match. Please choose a new Smart-eID PIN. + ALL_PLATFORMS Error message if the new pin confirmation mismatches. + Die Eingaben stimmen nicht überein. Bitte wählen Sie eine neue Smart-eID-PIN. - Information - LABEL ALL_PLATFORMS - Information + The input does not match. Please choose a new ID card PIN. + Die Eingaben stimmen nicht überein. Bitte wählen Sie eine neue Karten-PIN. @@ -7504,47 +5697,6 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au Fordern Sie kostenlos eine neue Karten-PIN an, um die Online-Ausweisfunktion wieder nutzen zu können. - - governikus::ProviderModel - - %1/min - INFO ALL_PLATFORMS Unit for expenses for calling the hotline (per minute). - %1/min - - - %1/call - INFO ALL_PLATFORMS Unit for expenses for calling the hotline (per call). - %1/Anruf - - - %1 EUR - INFO ALL_PLATFORMS Currency unit for expenses for calling the hotline (Euro/Cent). - %1 EUR - - - %1 ct - %1 ct - - - %1 seconds free, afterwards - INFO ALL_PLATFORMS Free of charge seconds when calling the hotline. - %1 Sekunde frei, danach - - - landline costs %1; - INFO ALL_PLATFORMS Land line charges when calling the hotline. - Festnetzpreis %1; - - - mobile costs may vary. - INFO ALL_PLATFORMS Cell phone charges when calling the hotline. - Mobilfunkpreise abweichen. - - - mobile costs %1 - Mobilfunkpreise max. %1 - - governikus::ReaderModel @@ -7572,16 +5724,6 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au INFO ALL_PLATFORMS Der Kartenleser wird nicht offiziell unterstützt und funktioniert möglicherweise nicht richtig. - - online help - Is embedded in a sentence. - Online-Hilfe - - - No connected card reader found. See %1 for installation of card readers. - INFO ALL_PLATFORMS No card reader was found, the message contains a link to the installation section of the manual. - Es wurde kein Kartenleser gefunden. Details zur Installation finden Sie in der %1. - hh:mm:ss AP LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString @@ -7596,14 +5738,14 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au governikus::RedirectRequest - Cannot reach local AusweisApp2 + Cannot reach local %1 ERROR ALL_PLATFORMS The local AusweisApp (access via reverse proxy) is not reachable, part of an HTML error page. - Die lokale AusweisApp2 ist nicht erreichbar + Die lokale %1 ist nicht erreichbar - Your local AusweisApp2 is not running. Please start your local AusweisApp2 and try again. + Your local %1 is not running. Please start your local %1 and try again. ERROR ALL_PLATFORMS The local AusweisApp (access via reverse proxy) is not reachable, part of an HTML error page. - Ihre lokale AusweisApp2 läuft nicht. Bitte starten Sie Ihre lokale AusweisApp2 und versuchen Sie es erneut. + Ihre lokale %1 läuft nicht. Bitte starten Sie Ihre lokale %1 und versuchen Sie es erneut. Would you like to try again? @@ -7655,16 +5797,6 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString dd.MM.yyyy HH:mm - - online help - Is embedded in a sentence. - Online-Hilfe - - - No smartphone as card reader (Sac) available. Please make sure to activate the "remote service" on your smartphone and to connect both devices to the same WiFi. See %1 for details of use. - INFO ALL_PLATFORMS No smartphone with enabled remote service was found on the same network. - Kein Smartphone als Kartenleser verfügbar. Bitte stellen Sie sicher, dass die Funktion "Fernzugriff" in der AusweisApp2 auf Ihrem Smartphone aktiviert ist und beide Geräte mit demselben WLAN verbunden sind. Informationen zur Verwendung finden Sie in der %1. - Unavailable LABEL ALL_PLATFORMS @@ -7811,24 +5943,74 @@ Bitte aktivieren Sie NFC, um Ihr Smartphone als Kartenleser (SaK) benutzen zu k governikus::SmartModel - Delete data was successful. - LABEL ANDROID IOS - Daten erfolgreich gelöscht. + The online check for the Smart-eID support on your device failed. Please note that this process requires an internet connection. + ERROR ANDROID IOS The check for Smart-eID support failed without any specific reason. + Die Online-Prüfung zur Unterstützung der Smart-eID auf Ihrem Gerät ist fehlgeschlagen. Bitte beachten Sie, dass für diesen Vorgang eine Internetverbindung erforderlich ist. - Delete data failed. - LABEL ANDROID IOS - Löschen der Daten ist fehlgeschlagen. + The online check for the Smart-eID support on your device failed because the server is currently facing too many requests. Please try again later. + ERROR ANDROID IOS The check for Smart-eID support failed because the server is overloaded. + Die Online-Prüfung zur Unterstützung der Smart-eID auf Ihrem Gerät ist fehlgeschlagen da der Server derzeit überlastet ist. Bitte versuchen Sie es später erneut. - Delete Smart-eID was successful. - LABEL ANDROID IOS - Smart-eID erfolgreich gelöscht. + The online check for the Smart-eID support on your device failed because the server is currently under maintenance. Please try again later. + ERROR ANDROID IOS The check for Smart-eID support failed because the server is being maintained. + Die Online-Prüfung zur Unterstützung der Smart-eID auf Ihrem Gerät ist fehlgeschlagen da der Server derzeit gewartet wird. Bitte versuchen Sie es später erneut. - Delete Smart-eID failed. - LABEL ANDROID IOS - Löschen der Smart-eID ist fehlgeschlagen. + The Smart-eID data and provisioning could not be successfully deleted from your device. Please note that this process requires an internet connection. + ERROR ANDROID IOS Deletion of the Smart-eID failed without a specific reason. + Die Smart-eID und Provisionierung konnte nicht erfolgreich von Ihrem Gerät gelöscht werden. Bitte beachten Sie, dass für diesen Vorgang eine Internetverbindung erforderlich ist. + + + The Smart-eID data and provisioning could not be successfully deleted from your device because the server is currently facing too many requests. Please try again later. + ERROR ANDROID IOS Deletion of the Smart-eID failed because the server is overloaded. + Die Smart-eID und Provisionierung konnte nicht erfolgreich von Ihrem Gerät gelöscht werden da der Server derzeit überlastet ist. Bitte versuchen Sie es später erneut. + + + The Smart-eID data and provisioning could not be successfully deleted from your device because the server is currently under maintenance. Please try again later. + ERROR ANDROID IOS Deletion of the Smart-eID failed because the server is being maintained. + Die Smart-eID und Provisionierung konnte nicht erfolgreich von Ihrem Gerät gelöscht werden da der Server derzeit gewartet wird. Bitte versuchen Sie es später erneut. + + + The Smart-eID data and provisioning could not be successfully deleted from your device. In order to access the necessary device storage, active NFC functionality is required. Please activate NFC and restart the process. + ERROR ANDROID IOS Deletion of the Smart-eID failed because NFC is not activated. + Die Smart-eID und Provisionierung konnte nicht erfolgreich von Ihrem Gerät gelöscht werden. Eine aktive NFC-Funktionalität ist erforderlich, um auf die notwendigen Gerätespeicher zuzugreifen. Bitte aktivieren Sie NFC und starten Sie den Löschvorgang erneut. + + + The online check for the Smart-eID support on your device failed. In order to access the necessary device storage, active NFC functionality is required. Please activate NFC and try again. + ERROR ANDROID IOS The check for Smart-eID support failed because the NFC functionality is not activated. + Die Online-Prüfung zur Unterstützung der Smart-eID auf Ihrem Gerät ist fehlgeschlagen. Eine aktive NFC-Funktionalität ist erforderlich, um auf die notwendigen Gerätespeicher zuzugreifen. Bitte aktivieren Sie NFC und versuchen Sie es erneut. + + + The online check for the Smart-eID support on your device failed. The Google Play Integrity Check failed. + ERROR ANDROID IOS The check for Smart-eID support failed because Google Play Integrity Check failed. + Die Online-Prüfung zur Unterstützung der Smart-eID auf Ihrem Gerät ist fehlgeschlagen. Die Google Play-Integritätsprüfung ist fehlgeschlagen. + + + The online check for the Smart-eID support on your device failed. An authentication issue occurred (e.g. a resource was accessed without authorization or an unauthorized app tried to access a security component). + ERROR ANDROID IOS The check for Smart-eID support failed because an authorization issue occurred. + Die Online-Prüfung zur Unterstützung der Smart-eID auf Ihrem Gerät ist fehlgeschlagen. Ein Authorisierungsproblem ist aufgetreten (z.B. erfolgte ein Resourcenzugriff ohne Authorisierung oder eine nicht autorisierte App versuchte auf eine Sicherheitskomponente zuzugreifen). + + + The Smart-eID data and provisioning could not be successfully deleted from your device. The Google Play Integrity Check failed. + ERROR ANDROID IOS Deletion of the Smart-eID failed because the Google Play Integrity Check failed. + Die Smart-eID und Provisionierung konnte nicht erfolgreich von Ihrem Gerät gelöscht werden. Die Google Play-Integritätsprüfung ist fehlgeschlagen. + + + The Smart-eID data and provisioning could not be successfully deleted from your device. An authentication issue occurred (e.g. a resource was accessed without authorization or an unauthorized app tried to access a security component). + ERROR ANDROID IOS Deletion of the Smart-eID failed because an authorization issue occurred. + Die Smart-eID und Provisionierung konnte nicht erfolgreich von Ihrem Gerät gelöscht werden. Ein Authorisierungsproblem ist aufgetreten (z.B. erfolgte ein Resourcenzugriff ohne Authorisierung oder eine nicht autorisierte App versuchte auf eine Sicherheitskomponente zuzugreifen). + + + The online check for the Smart-eID support on your device failed. Please ensure that you have an internet connection and your antivirus software and firewall are not blocking the connection. + ERROR ANDROID IOS The check for Smart-eID support failed because a network connection error occurred. + Die Online-Prüfung zur Unterstützung der Smart-eID auf Ihrem Gerät ist fehlgeschlagen. Bitte stellen Sie sicher, dass Sie mit dem Internet verbunden sind und weder eine Antivirus-Software noch eine Firewall die Verbindung blockiert. + + + The Smart-eID data and provisioning could not be successfully deleted from your device. Please ensure that you have an internet connection and your antivirus software and firewall are not blocking the connection. + ERROR ANDROID IOS Deletion of the Smart-eID failed because a network connection error occurred. + Die Smart-eID und Provisionierung konnte nicht erfolgreich von Ihrem Gerät gelöscht werden. Bitte stellen Sie sicher, dass Sie mit dem Internet verbunden sind und weder eine Antivirus-Software noch eine Firewall die Verbindung blockiert. @@ -7856,11 +6038,21 @@ Bitte aktivieren Sie NFC, um Ihr Smartphone als Kartenleser (SaK) benutzen zu k governikus::StateConnectCard The used card reader does not meet the technical requirements (Extended Length not supported). + INFO IOS Der verwendete Kartenleser erfüllt leider nicht die technischen Voraussetzungen (Extended Length wird nicht unterstützt). - The provider requires a physical ID card. - Der Anbieter verlangt einen physischen Ausweis. + The used ID card type is not accepted by the server. + INFO IOS + Der verwendete Ausweistyp wird vom Server nicht akzeptiert. + + + + governikus::StateDeleteApplet + + Cleaning up old Smart-eID + LABEL ANDROID IOS + Bereinige alte Smart-eID @@ -7943,22 +6135,12 @@ Bitte aktivieren Sie NFC, um Ihr Smartphone als Kartenleser (SaK) benutzen zu k - governikus::StatePrepareApplet - - Checking Smart-eID status - LABEL ANDROID IOS - Überprüfe Smart-eID-Status - + governikus::StateInstallApplet Installing Smart-eID LABEL ANDROID IOS Installiere Smart-eID - - Cleaning up old Smart-eID - LABEL ANDROID IOS - Bereinige alte Smart-eID - governikus::StateTransmit @@ -7983,18 +6165,11 @@ Bitte aktivieren Sie NFC, um Ihr Smartphone als Kartenleser (SaK) benutzen zu k - governikus::StateWriteHistory - - Validity: -%1 - %2 - LABEL ALL_PLATFORMS - Gültigkeit: -%1 - %2 - + governikus::StateUpdateSupportInfo - Preparing results - INFO ALL_PLATFORMS Status message after the authentication was completed, the results are prepared for the user and the process will be continued in the browser - Ergebnisse werden vorbereitet + Checking Smart-eID status + LABEL ANDROID IOS + Überprüfe Smart-eID-Status @@ -8028,8 +6203,8 @@ Bitte aktivieren Sie NFC, um Ihr Smartphone als Kartenleser (SaK) benutzen zu k Max. NFC Paketlänge - AusweisApp2 Version - AusweisApp2-Version + %1 Version + %1-Version NFC Tag Type @@ -8049,9 +6224,9 @@ Bitte aktivieren Sie NFC, um Ihr Smartphone als Kartenleser (SaK) benutzen zu k Öffnen - Quit AusweisApp2 + Quit %1 LABEL DESKTOP - AusweisApp2 beenden + %1 beenden @@ -8081,26 +6256,18 @@ Bitte aktivieren Sie NFC, um Ihr Smartphone als Kartenleser (SaK) benutzen zu k Die Anwendung "%1" verwendet den benötigten Port (%2) bereits. Bitte beenden Sie "%1" und versuchen Sie es anschließend erneut! - You tried to start a newer version (%1) of currently running AusweisApp2. Please stop the current version (%2) and start again! + You tried to start a newer version (%1) of currently running %2. Please stop the current version (%3) and start again! ERROR ALL_PLATFORMS The external request to show the UI requested a newer version than the one currently installed. - Sie versuchen eine neuere Version (%1) der aktuell laufenden AusweisApp2 zu starten. Bitte beenden Sie zuerst die andere Version (%2) und versuchen Sie es anschließend erneut! + Sie versuchen eine neuere Version (%1) der aktuell laufenden %2 zu starten. Bitte beenden Sie zuerst die andere Version (%3) und versuchen Sie es anschließend erneut! - You tried to start an older version (%1) of currently running AusweisApp2. Please open the currently running version (%2)! + You tried to start an older version (%1) of currently running %2. Please open the currently running version (%3)! ERROR ALL_PLATFORMS The external request to show the UI requested an older version than the one currently installed. - Sie versuchen eine ältere Version (%1) der aktuell laufenden AusweisApp2 zu starten. Bitte öffnen Sie die aktuell laufende Version (%2)! - - - Reverse-Proxy of AusweisApp2 is started and this instance cannot rebind port. Please ask your administrator! - Der Reverse-Proxy der AusweisApp2 ist gestartet und diese Instanz konnte nicht auf einen anderen Port wechseln. Bitte wenden Sie sich an Ihren Administrator! + Sie versuchen eine ältere Version (%1) der aktuell laufenden %2 zu starten. Bitte öffnen Sie die aktuell laufende Version (%3)! - - - governikus::WebserviceActivationContext - The browser connection was lost. - ERROR ALL_PLATFORMS No HTTP connection present. - Die Verbindung zum Browser ging verloren. + Reverse-Proxy of %1 is started and this instance cannot rebind port. Please ask your administrator! + Der Reverse-Proxy der %1 ist gestartet und diese Instanz konnte nicht auf einen anderen Port wechseln. Bitte wenden Sie sich an Ihren Administrator! Cannot start authentication @@ -8122,6 +6289,11 @@ Bitte aktivieren Sie NFC, um Ihr Smartphone als Kartenleser (SaK) benutzen zu k ERROR ALL_PLATFORMS A new authentication request was received while the previous one was still running. Part of an HTML error page. Erneut versuchen + + The browser connection was lost. + ERROR ALL_PLATFORMS No HTTP connection present. + Die Verbindung zum Browser ging verloren. + Invalid request (%1) ERROR ALL_PLATFORMS Invalid request by the browser, part of an HTML error page @@ -8156,13 +6328,38 @@ Bitte aktivieren Sie NFC, um Ihr Smartphone als Kartenleser (SaK) benutzen zu k governikus::WorkflowModel - AusweisApp2 error report - %1 - AusweisApp2 Fehlerbericht - %1 + %1 error report - %2 + %1 Fehlerbericht - %2 Contact your local citizens' office (Bürgeramt) to apply for a new ID card or to unblock the ID card. Bitte wenden Sie sich an das Bürgeramt, um ein neues Ausweisdokument zu beantragen oder die Sperrung des Ausweises aufzuheben. + + The used Smart-eID is not accepted by the server. Please restart the remote service on your connected smartphone and try again with a physical ID card. + INFO ALL_PLATFORMS + Die verwendete Smart-eID wird vom Server nicht akzeptiert. Bitte starten Sie den Fernzugriff auf Ihrem verbundenen Smartphone neu und versuchen Sie es erneut mit einem physischen Ausweis. + + + The used Smart-eID is not accepted by the server. Please stop the remote service and use another Smart-eID or contact the service provider. + INFO ALL_PLATFORMS + Die verwendete Smart-eID wird vom Server nicht akzeptiert. Bitte stoppen Sie den Fernzugriff und verwenden Sie eine andere Smart-eID oder kontaktieren Sie den Diensteanbieter. + + + The used ID card is not accepted by the server. Please remove the ID card from your device or card reader and use a Smart-eID or contact the service provider. + INFO ALL_PLATFORMS + Der verwendete Ausweistyp wird vom Server nicht akzeptiert. Bitte entfernen Sie den Ausweis vom Gerät oder Kartenleser und verwenden Sie eine Smart-eID oder kontaktieren Sie den Diensteanbieter. + + + Renew your Smart-eID and set a new PIN in the Smart-eID menu. + LABEL ANDROID IOS The hint text that is shwon right above the redirect button that appears when a user tried to usa an unusable Smart-eID + Erneuern Sie Ihre Smart-eID und vergeben Sie eine neue PIN im Smart-eID Menü. + + + Go to Smart-eID menu + LABEL ANDROID IOS The text on the redirect button that appears when the user tried to use an unusable Smart-eID + Zum Smart-eID Menü + main @@ -8230,5 +6427,20 @@ Bitte aktivieren Sie NFC, um Ihr Smartphone als Kartenleser (SaK) benutzen zu k INFO DESKTOP Content of the popup that is shown when the AA2 is closed and the close/minimize info was not disabled. macOS specific if autostart is enabled. Das Programm steht weiterhin in der Menüleiste zur Verfügung. Klicken Sie auf das Symbol der %1, um die Anwendung wieder zu öffnen. + + The %1 will be shut down and an authentication will no longer be possible. You will have to restart the %1 to identify yourself towards providers. + INFO DESKTOP Text of the popup that is shown when the AA2 is quit for the first time. + Die %1 wird beendet und steht nicht länger für eine Authentisierung zur Verfügung. Sie müssen die %1 erneut starten, um sich gegenüber Dienstanbietern auszuweisen. + + + The %1 is closed. + INFO DESKTOP Header of the popup that is shown when the AA2 is quit for the first time. + Die %1 wird beendet. + + + This will cancel the current operation and shut the %1 down. You will have to restart the %1 to restart the operation. + INFO DESKTOP Content of the popup that is shown when the AA2 is shut down and a workflow is still active. + Hierdurch wird der aktuelle Vorgang abgebrochen und die %1 beendet. Sie müssen die %1 erneut starten, um den Vorgang neuzustarten. + diff --git a/resources/translations/ausweisapp2_ru.ts b/resources/translations/ausweisapp2_ru.ts index 43dbdadcc..c57b7de54 100644 --- a/resources/translations/ausweisapp2_ru.ts +++ b/resources/translations/ausweisapp2_ru.ts @@ -5,7 +5,7 @@ DvcsAttributes revision - b9ade3b30f3d + 56dc58807a8c @@ -27,34 +27,56 @@ - AdditionalResultsFooterItem + AuthController - Additional results in other categories: %1. Click here to remove filter. - Дополнительные результаты в других категориях: %1. Нажмите здесь, чтобы сбросить фильтр. + Identify + LABEL ANDROID IOS + Идентифицировать + + + Cancel authentication process + LABEL ANDROID IOS + Отмена процесса аутентификации - Additional results in other categories: - LABEL DESKTOP IOS_TABLET ANDROID_TABLET - Дополнительные результаты в других категориях: + Acquiring provider certificate + INFO ANDROID IOS Header of the progress status message during the authentication process. + Получение сертификата провайдера - Show - Показать следующее число дополнительных результатов: + Authentication in progress + INFO ANDROID IOS Header of the progress status message during the authentication process. + Выполняется аутентификация + + + Please wait a moment. + INFO ANDROID IOS Generic status message during the authentication process. + Подождите. + + + Please do not move the ID card. + INFO ANDROID IOS Second line text if a basic card reader is used and background communication with the card/server is running. Is not actually visible since the basic reader password handling is done by EnterPasswordView. + Не перемещайте идентификационную карту. + + + Please observe the display of your card reader. + INFO ANDROID IOS The card reader requests the user's attention. + Учитывайте указания на дисплее устройства чтения карт. - - - AdditionalResultsItem - %1 additional results in other categories - %1 в других категориях + A wrong PIN has been entered twice on your ID card. For a third attempt, please first enter the six-digit Card Access Number (CAN). You can find your CAN in the bottom right on the front of your ID card. + INFO ANDROID IOS The PIN was entered wrongfully two times, the third attempts requires additional CAN verification, hint where the CAN is found. + Дважды введен неправильный PIN-код идентификационной карты. Для третьей попытки сначала введите 6-значный код доступа (CAN). Код CAN указан внизу справа на передней стороне идентификационной карты. - Click to remove category filter and show additional results. - Нажмите, чтобы сбросить фильтр категорий и показать дополнительные результаты. + Send log + LABEL ANDROID IOS + Отправить файл журнала - Additional results: - Дополнительные результаты: + Authenticate with provider + LABEL ANDROID IOS A11y button to confirm the PIN and start the provider authentication + Аутентификация с помощью провайдера @@ -107,9 +129,7 @@ LABEL ANDROID IOS ---------- INFO DESKTOP Generic progress status message while no card communication is active. ---------- -INFO DESKTOP Generic progress status message during authentication. ----------- -INFO ANDROID IOS Generic status message during the authentication process. +INFO DESKTOP Generic progress status message during authentication. Подождите. @@ -119,23 +139,17 @@ INFO ANDROID IOS Generic status message during the authentication process. Acquiring provider certificate - INFO DESKTOP Header of the progress information during the authentication process. ----------- -INFO ANDROID IOS Header of the progress status message during the authentication process. + INFO DESKTOP Header of the progress information during the authentication process. Получение сертификата провайдера Authentication in progress - INFO DESKTOP Header of the progress information during the authentication process. ----------- -INFO ANDROID IOS Header of the progress status message during the authentication process. + INFO DESKTOP Header of the progress information during the authentication process. Выполняется аутентификация Please do not move the ID card. - INFO DESKTOP Second line text if a basic card reader is used and data is exchanged with the card/server in the background. Is not actually visible since the basic reader password handling is done by EnterPasswordView. ----------- -INFO ANDROID IOS Second line text if a basic card reader is used and background communication with the card/server is running. Is not actually visible since the basic reader password handling is done by EnterPasswordView. + INFO DESKTOP Second line text if a basic card reader is used and data is exchanged with the card/server in the background. Is not actually visible since the basic reader password handling is done by EnterPasswordView. Не перемещайте идентификационную карту. @@ -143,31 +157,9 @@ INFO ANDROID IOS Second line text if a basic card reader is used and background INFO DESKTOP Error code (string) of current GlobalStatus code, shown as header of popup. Код ошибки: %1 - - Cancel authentication process - LABEL ANDROID IOS - Отмена процесса аутентификации - - - Please observe the display of your card reader. - INFO ANDROID IOS The card reader requests the user's attention. - Учитывайте указания на дисплее устройства чтения карт. - - - A wrong PIN has been entered twice on your ID card. For a third attempt, please first enter the six-digit Card Access Number (CAN). You can find your CAN in the bottom right on the front of your ID card. - INFO ANDROID IOS The PIN was entered wrongfully two times, the third attempts requires additional CAN verification, hint where the CAN is found. - Дважды введен неправильный PIN-код идентификационной карты. Для третьей попытки сначала введите 6-значный код доступа (CAN). Код CAN указан внизу справа на передней стороне идентификационной карты. - - - Send log - LABEL ANDROID IOS - Отправить файл журнала - Authenticate with provider - LABEL DESKTOP A11y button to confirm the PIN and start the provider authentication ----------- -LABEL ANDROID IOS A11y button to confirm the PIN and start the provider authentication + LABEL DESKTOP A11y button to confirm the PIN and start the provider authentication Аутентификация с помощью провайдера @@ -210,52 +202,6 @@ LABEL ANDROID IOS A11y button to confirm the PIN and start the provider authenti Можно извлечь идентификационную карту из устройства. - - BaseHistoryView - - History - INFO ANDROID IOS - Журнал - - - Currently there are no history entries. - INFO ANDROID IOS No authentication history, placeholder text. - В настоящее время в журнале нет записей. - - - - BaseProviderView - - No results matching your search query found - LABEL IOS_PHONE ANDROID_PHONE The text entered into the provider search field results in no matches - По вашему запросу результатов не найдено - - - Provider - LABEL IOS_TABLET ANDROID_TABLET - Провайдер - - - Citizen services - LABEL IOS_TABLET ANDROID_TABLET - Услуги для граждан - - - Financials - LABEL IOS_TABLET ANDROID_TABLET - Финансы - - - Insurances - LABEL IOS_TABLET ANDROID_TABLET - Страхование - - - Other services - LABEL IOS_TABLET ANDROID_TABLET - Другие услуги - - BuildHelper @@ -307,13 +253,6 @@ LABEL ANDROID IOS A11y button to confirm the PIN and start the provider authenti Версия OpenSSL - - CancelAction - - Cancel - Отмена - - CardPositionView @@ -344,6 +283,7 @@ LABEL ANDROID IOS A11y button to confirm the PIN and start the provider authenti CardReaderView Connected USB card readers + LABEL DESKTOP Подключенные USB-устройства чтения карт @@ -358,47 +298,77 @@ LABEL ANDROID IOS A11y button to confirm the PIN and start the provider authenti After connecting a new card reader it may take a few seconds to recognize the driver. It may be necessary to restart your system after installing the driver. Only connected card readers are shown here. %1 При подключении нового устройства чтения карт может потребоваться несколько секунд для распознавания драйвера. После установки драйвера может потребоваться перезагрузка системы. Здесь отображаются только подключенные устройства чтения карт. %1 + + No connected card reader found. + + - Category + CertificateDescriptionPage - Provider - Провайдер + Provider Information + LABEL DESKTOP +---------- +LABEL ANDROID IOS + Информация о провайдере + + + ChangePinController - All - Все + Your ID card PIN is unblocked. You now have three more attempts to change your PIN. + INFO ANDROID IOS The ID card has just been unblocked and the user can now continue with their PIN change. + PIN-код вашей карты разблокирован. У вас есть три попытки изменить PIN-код. - Citizen services - Услуги для граждан + Setting new Smart-eID PIN + LABEL ANDROID IOS Processing screen label while the card communication is running after the new Smart-eID PIN has been entered during PIN change process. + Установка нового PIN-кода для Smart-eID - Insurances - Страхование + Change Smart-eID PIN + LABEL ANDROID IOS Processing screen label while the card communication is running before the new ID card PIN has been entered during PIN change process. + Изменить PIN-код для Smart-eID - Financials - Финансы + Setting new ID card PIN + LABEL ANDROID IOS Processing screen label while the card communication is running after the new ID card PIN has been entered during PIN change process. + Установить новый PIN-код идентификационной карты - Other services - Другие услуги + Change ID card PIN + LABEL ANDROID IOS Processing screen label while the card communication is running before the new ID card PIN has been entered during PIN change process. + Изменить PIN-код идентификационной карты - - - CertificateDescriptionPage - Provider Information - LABEL DESKTOP ----------- -LABEL ANDROID IOS - Информация о провайдере + Please wait a moment. + INFO ANDROID IOS Generic progress message during PIN change process. + Подождите. - Close - LABEL DESKTOP - Закрыть + Please do not move the ID card. + INFO ANDROID IOS Loading screen during PIN change process, data communication is currently ongoing. Message is usually not visible since the password handling with basic reader is handled by EnterPasswordView. + Не перемещайте идентификационную карту. + + + Please observe the display of your card reader. + INFO ANDROID IOS Either an comfort card reader or smartphone-as-card-reader is used, the user needs to react to request on that device. + Учитывайте указания на дисплее устройства чтения карт. + + + A wrong ID card PIN has been entered twice on your ID card. For a third attempt, please first enter the six-digit Card Access Number (CAN). You can find your CAN in the bottom right on the front of your ID card. + INFO ANDROID IOS The wrong ID card PIN was entered twice, the next attempt requires additional verifcation via CAN. + Дважды введен неправильный PIN-код вашей идентификационной карты. Для третьей попытки сначала введите 6-значный код доступа (CAN). Код CAN указан внизу справа на передней стороне идентификационной карты. + + + You have entered an incorrect, six-digit ID card PIN thrice, your ID card PIN is now blocked. To remove the block, the ten-digit PUK must be entered first. + INFO ANDROID IOS The ID card PIN (including the CAN) was entered wrongfully three times, the PUK is required to unlock the ID card. + Вы трижды ввели неправильный 6-значный PIN-код идентификационной карты, PIN-код идентификационной карты заблокирован. Для разблокировки введите 10-значный PUK-код. + + + Please note that you may use the five-digit Transport PIN only once to change to a six-digit ID card PIN. If you already set a six-digit ID card PIN, the five-digit Transport PIN is no longer valid. + INFO ANDROID IOS + Внимание: вы можете использовать 5-значный временный PIN-код только один раз — для смены 6-значного PIN-кода. Если вы уже установили 6-значный PIN-код, 5-значный временный PIN-код больше не действует. @@ -419,16 +389,12 @@ LABEL ANDROID IOS Please do not move the ID card. - INFO DESKTOP Processing screen text while the card communication is running after the PIN has been entered during PIN change process. ----------- -INFO ANDROID IOS Loading screen during PIN change process, data communication is currently ongoing. Message is usually not visible since the password handling with basic reader is handled by EnterPasswordView. + INFO DESKTOP Processing screen text while the card communication is running after the PIN has been entered during PIN change process. Не перемещайте идентификационную карту. Your ID card PIN is unblocked. You now have three more attempts to change your PIN. - INFO DESKTOP The ID card has just been unblocked and the user can now continue with their ID card PIN change. ----------- -INFO ANDROID IOS The ID card has just been unblocked and the user can now continue with their PIN change. + INFO DESKTOP The ID card has just been unblocked and the user can now continue with their ID card PIN change. PIN-код вашей карты разблокирован. У вас есть три попытки изменить PIN-код. @@ -451,61 +417,21 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin — Убедитесь в том, что карта правильно вставлена в устройство чтения карт. — Не перемещайте карту, пока система получает к ней доступ. - - Change my (Transport) PIN - LABEL ANDROID IOS - Изменить (временный) PIN-код - Change Transport PIN LABEL ANDROID IOS Изменить временный PIN-код - - Setting new Smart-eID PIN - LABEL ANDROID IOS Processing screen label while the card communication is running after the new Smart-eID PIN has been entered during PIN change process. - Установка нового PIN-кода для Smart-eID - - - Change Smart-eID PIN - LABEL ANDROID IOS Processing screen label while the card communication is running before the new ID card PIN has been entered during PIN change process. - Изменить PIN-код для Smart-eID - - - Setting new ID card PIN - LABEL ANDROID IOS Processing screen label while the card communication is running after the new ID card PIN has been entered during PIN change process. - Установить новый PIN-код идентификационной карты - - - Change ID card PIN - LABEL ANDROID IOS Processing screen label while the card communication is running before the new ID card PIN has been entered during PIN change process. - Изменить PIN-код идентификационной карты - - - Please wait a moment. - INFO ANDROID IOS Generic progress message during PIN change process. - Подождите. - - - Please observe the display of your card reader. - INFO ANDROID IOS Either an comfort card reader or smartphone-as-card-reader is used, the user needs to react to request on that device. - Учитывайте указания на дисплее устройства чтения карт. - - - A wrong ID card PIN has been entered twice on your ID card. For a third attempt, please first enter the six-digit Card Access Number (CAN). You can find your CAN in the bottom right on the front of your ID card. - INFO ANDROID IOS The wrong ID card PIN was entered twice, the next attempt requires additional verification via CAN. - Дважды введен неправильный PIN-код вашей идентификационной карты. Для третьей попытки сначала введите 6-значный код доступа (CAN). Код CAN указан внизу справа на передней стороне идентификационной карты. - - - You have entered an incorrect, six-digit ID card PIN thrice, your ID card PIN is now blocked. To remove the block, the ten-digit PUK must be entered first. - INFO ANDROID IOS The ID card PIN (including the CAN) was entered wrongfully three times, the PUK is required to unlock the ID card. - Вы трижды ввели неправильный 6-значный PIN-код идентификационной карты, PIN-код идентификационной карты заблокирован. Для разблокировки введите 10-значный PUK-код. - The device "%1" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. INFO DESKTOP The paired devices was removed since it did not respond to connection attempts. It needs to be paired again if it should be used as card reader. Сопряжение устройства «%1» не было выполнено, поскольку оно не отвечало на попытки соединения. Снова выполните сопряжение устройства для его использования в качестве устройства чтения карт. + + Please note that you may use the five-digit Transport PIN only once to change to a six-digit ID card PIN. If you already set a six-digit ID card PIN, the five-digit Transport PIN is no longer valid. + INFO DESKTOP + Внимание: вы можете использовать 5-значный временный PIN-код только один раз — для смены 6-значного PIN-кода. Если вы уже установили 6-значный PIN-код, 5-значный временный PIN-код больше не действует. + ChangePinViewContent @@ -797,207 +723,145 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin CheckSmartResultView - Check Smart-eID + Unknown result code: %1 LABEL ANDROID IOS - Проверить Smart-eID + Неизвестный код результата: %1 - Result of Smart-eID check + Please wait a moment. LABEL ANDROID IOS - Результат проверки Smart-eID + Подождите. - Continue + Updating Smart-eID status... LABEL ANDROID IOS - Продолжить + Обновление статуса Smart-eID… - What does that mean? + Check device and ID card LABEL ANDROID IOS - Что это значит? + Проверить устройство и идентификационную карту - You may now try the function: "See my personal data". Press the Continue button to do so now. - Проверьте функцию: «Просмотреть персональные данные». Для продолжения нажмите кнопку «Продолжить». - - - Supported + Your mobile device does not meet the technical requirements for Smart-eID.<br><br>You may check if your device and ID card are suitable to use the eID function. LABEL ANDROID IOS - Поддерживается + Ваше мобильное устройство не соответствует техническим требованиям для Smart-eID.<br><br>Вы можете проверить пригодность вашего устройства и идентификационной карты для использования функции eID. - Not supported + Smart-eID not supported LABEL ANDROID IOS - Не поддерживается + Smart-eID не поддерживается - Prepared + Possible causes are: LABEL ANDROID IOS - Подготовлено + Возможные причины - Not prepared + The setup has not been completed. LABEL ANDROID IOS - Не подготовлено + Создание не завершено. - Set up + The Smart-eID PIN has been entered incorrectly three times. LABEL ANDROID IOS - Настроено + PIN-код для Smart-eID трижды введен неправильно. - Not set up + The %1 has been uninstalled temporarily. LABEL ANDROID IOS - Не настроено + Приложение %1 удалено. - Invalid + You may continue with the setup of the Smart-eID. LABEL ANDROID IOS - Недействительно + - Ready for use + Continue LABEL ANDROID IOS - Готово к использованию + Продолжить - - - CheckSmartSuggestionView - Unknown result code: %1 + Your device meets the technical requirements for Smart-eID. You may now continue the setup process. LABEL ANDROID IOS - Неизвестный код результата: %1 + - Updating Smart-eID status... + Smart-eID supported LABEL ANDROID IOS - Обновление статуса Smart-eID… + - Please wait a moment. - LABEL ANDROID IOS - Подождите. + Your device meets the technical requirements for Smart-eID, however, the Smart-eID that was set up is invalid. + LABEL ANDROID IOS LABEL ANDROID IOS + - Smart-eID not supported + Smart-eID invalid LABEL ANDROID IOS - Smart-eID не поддерживается + - Your mobile device does not meet the technical requirements for Smart-eID.<br><br>You may check if your device and ID card are suitable to use the eID function. + Smart-eID check failed LABEL ANDROID IOS - Ваше мобильное устройство не соответствует техническим требованиям для Smart-eID.<br><br>Вы можете проверить пригодность вашего устройства и идентификационной карты для использования функции eID. + - Check device and ID card + Back LABEL ANDROID IOS - Проверить устройство и идентификационную карту + Назад + + + ConnectSacView - Smart-eID invalid - LABEL ANDROID IOS - Электронная идентификационная карта Smart-eID недействительна + Pairing + LABEL DESKTOP + Сопряжение - Your device meets the technical requirements for Smart-eID, however, the Smart-eID that was set up is invalid. - LABEL ANDROID IOS LABEL ANDROID IOS - Ваше устройство соответствует техническим требованиям для Smart-eID, однако созданная электронная идентификационная карта Smart-eID недействительна. + Pairing the device ... + LABEL DESKTOP + Сопряжение устройства… - Possible causes are: - LABEL ANDROID IOS - Возможные причины - - - The setup has not been completed. - LABEL ANDROID IOS - Создание не завершено. - - - The preparation for the Smart-eID is defective. - LABEL ANDROID IOS - Подготовка для Smart-eID выполнена с ошибкой. - - - The Smart-eID PIN has been entered incorrectly three times. - LABEL ANDROID IOS - PIN-код для Smart-eID трижды введен неправильно. - - - The AusweisApp2 has been uninstalled temporarily. - LABEL ANDROID IOS - Приложение AusweisApp2 удалено. - - - Please restart the setup of the Smart-eID. - LABEL ANDROID IOS - Перезапустите создание Smart-eID. - - - Set up Smart-eID - LABEL ANDROID IOS - Создание Smart-eID - - - Smart-eID not prepared - LABEL ANDROID IOS - Подготовка для Smart-eID не выполнена - - - Your device meets the technical requirements for Smart-eID, but is not yet provisioned for setup. The provisioning is done automatically during the Smart-eID setup process. - LABEL ANDROID IOS - Ваше устройство соответствует техническим требованиям для Smart-eID, но еще не готово к созданию электронной идентификационной карты. Подготовка выполняется автоматически во время создания электронной идентификационной карты Smart-eID. - - - Smart-eID not set up - LABEL ANDROID IOS - Электронная идентификационная карта Smart-eID не создана - - - Your device meets the technical requirements for Smart-eID and is already provisioned for setup. You can now start the Smart-eID setup. - LABEL ANDROID IOS - Ваше устройство соответствует техническим требованиям для Smart-eID и уже готово к созданию электронной идентификационной карты. Теперь можно запустить создание Smart-eID. + Pairing to "%1" failed: + ERROR DESKTOP An error occurred while pairing the device. + Сбой сопряжения «%1»: - CheckSmartView - - Check Smart-eID - LABEL ANDROID IOS - Проверить Smart-eID - + DarkModeButtons - Your device needs to meet the technical requirements to use the Smart-eID function. - LABEL ANDROID IOS - Ваше устройство должно соответствовать техническим требованиям для использования функций Smart-eID. + System + LABEL ALL_PLATFORMS + Система - Check here if your device is suitable to set up a Smart-eID. - LABEL ANDROID IOS - Проверьте здесь, подходит ли ваше устройство для создания Smart-eID. + Dark + LABEL ALL_PLATFORMS + - Start check - LABEL ANDROID IOS - Запуск проверки + Light + LABEL ALL_PLATFORMS + - - - ConnectSacView - Pairing - LABEL DESKTOP - Сопряжение + Set the app appearance to system mode + LABEL ALL_PLATFORMS + - Pairing the device ... - LABEL DESKTOP - Сопряжение устройства… + Set the app appearance to dark mode + LABEL ALL_PLATFORMS + - Pairing to "%1" failed: - ERROR DESKTOP An error occurred while pairing the device. - Сбой сопряжения «%1»: + Set the app appearance to light mode + LABEL ALL_PLATFORMS + @@ -1023,11 +887,6 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin LABEL DESKTOP Файл журнала - - History - LABEL DESKTOP - Журнал - Show beta testing image LABEL DESKTOP @@ -1043,6 +902,16 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin LABEL DESKTOP Пропустить страницу с правами в режиме «Код CAN разрешен» + + Reset hideable dialogs + LABEL DESKTOP + + + + Show Transport PIN reminder, store feedback and close reminder dialogs. + LABEL DESKTOP + + DecisionView @@ -1051,11 +920,6 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin LABEL DESKTOP Нет - - Maybe - LABEL DESKTOP - Возможно - Yes LABEL DESKTOP @@ -1125,11 +989,6 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin LABEL DESKTOP Тестовый режим для самоаутентификации - - Enable internal card simulator - LABEL DESKTOP - Включить внутренний симулятор карт - The internal card simulator allows to run an authentication in the test PKI without any ID card or card reader. Note that no other card reader can be used while the simulator is activated. LABEL DESKTOP @@ -1140,11 +999,6 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin LABEL DESKTOP Режим разработчика - - The developer mode is aimed at integrators / developers for new service applications. For this reason, the developer mode works only in the test PKI. By activating the developer mode, some safety tests are deactivated. This means that the authentication process continues although the AusweisApp2 would usually abort the process with an error message when used in normal operation mode. Information on the disregarded error in the developer mode is displayed in the attached window below the AusweisApp2. - LABEL DESKTOP - Режим разработчика предназначен для интеграторов/разработчиков новых сервисных приложений. Поэтому режим разработчика функционирует только в тестовой ИОК. При активации режима разработчика некоторые проверки безопасности деактивируются. При этом процесс аутентификации продолжается, хотя при использовании в стандартном режиме AusweisApp2 обычно прерывает процесс с сообщением об ошибке. Проигнорированная ошибка в режиме разработчика отображается на дисплее в дополнительном окне под окном приложения AusweisApp2. - Custom config.json LABEL DESKTOP @@ -1170,6 +1024,21 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin LABEL DESKTOP Файл конфигурации JSON (*.json) + + Allow test sample card usage + LABEL DESKTOP + + + + Internal card simulator + LABEL DESKTOP + Внутренний симулятор карт + + + The developer mode deactivates some security checks and the authentication process will continue even if some errors occur. Skipped errors will be shown as notifications. The developer mode is only usable with the test PKI. + LABEL DESKTOP + Режим разработчика предназначен для интеграторов/разработчиков новых сервисных приложений. Поэтому режим разработчика функционирует только в тестовой ИОК. При активации режима разработчика некоторые проверки безопасности деактивируются. При этом процесс аутентификации продолжается, хотя при использовании в стандартном режиме %1 обычно прерывает процесс с сообщением об ошибке. Проигнорированная ошибка в режиме разработчика отображается на дисплее в дополнительном окне под окном приложения %1. + DevicesListDelegate @@ -1180,15 +1049,6 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin DiagnosisView - - Diagnosis - LABEL DESKTOP - Диагностика - - - Save diagnosis to textfile - Сохранить данные диагностики в текстовый файл - Save to file LABEL DESKTOP @@ -1210,138 +1070,111 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin Текстовые файлы (*.txt) - Save diagnosis + System data LABEL DESKTOP - Сохранить диагностику + Диагностика - - - EditRights - You are about to identify yourself towards the following provider - LABEL DESKTOP - Вы собираетесь пройти самоидентификацию для следующего провайдера + Save system data to textfile + Сохранить данные диагностики в текстовый файл - Show more information about the service provider - Показать больше информации о провайдере службы + SystemData + Диагностика - Details about the provider - LABEL DESKTOP ----------- -LABEL ANDROID_TABLET IOS_TABLET - Подробная информация о провайдере + Save system data + LABEL DESKTOP + Сохранить диагностику + + + EditRights Proceed to %1 entry LABEL DESKTOP %1 can be "CAN" or "PIN" ---------- -LABEL IOS_PHONE ANDROID_PHONE %1 can be "CAN" or "PIN" ----------- -LABEL ANDROID_TABLET IOS_TABLET %1 can be "CAN" or "PIN" +LABEL IOS_PHONE ANDROID_PHONE %1 can be "CAN" or "PIN" Далее к вводу %1 CAN LABEL DESKTOP Inserted into "Proceed to %1 entry" ---------- -LABEL IOS_PHONE Inserted into "Proceed to %1 entry" ----------- -LABEL ANDROID_TABLET IOS_TABLET Inserted into "Proceed to %1 entry" +LABEL IOS_PHONE Inserted into "Proceed to %1 entry" CAN PIN LABEL DESKTOP Inserted into "Proceed to %1 entry" ---------- -LABEL IOS_PHONE Inserted into "Proceed to %1 entry" ----------- -LABEL ANDROID_TABLET IOS_TABLET Inserted into "Proceed to %1 entry" +LABEL IOS_PHONE Inserted into "Proceed to %1 entry" PIN By entering the CAN, access to the following data of the ID card will be allowed to the mentioned provider: LABEL DESKTOP ---------- -LABEL IOS_PHONE ANDROID_PHONE ----------- -LABEL ANDROID_TABLET IOS_TABLET +LABEL IOS_PHONE ANDROID_PHONE При вводе CAN вы предоставляете указанному выше провайдеру доступ к следующим данным идентификационной карты. By entering your PIN, access to the following data of your ID card will be allowed to the mentioned provider: LABEL DESKTOP ---------- -LABEL IOS_PHONE ANDROID_PHONE ----------- -LABEL ANDROID_TABLET IOS_TABLET +LABEL IOS_PHONE ANDROID_PHONE При вводе PIN-кода вы предоставляете указанному выше провайдеру доступ к следующим данным идентификационной карты. Transactional information LABEL DESKTOP ---------- -LABEL IOS_PHONE ANDROID_PHONE ----------- -LABEL ANDROID_TABLET IOS_TABLET +LABEL IOS_PHONE ANDROID_PHONE Информация о транзакциях The provider mentioned above does not require any data stored on your ID card, only confirmation of you possessing a valid ID card. LABEL DESKTOP ---------- -LABEL IOS_PHONE ANDROID_PHONE ----------- -LABEL ANDROID_TABLET IOS_TABLET +LABEL IOS_PHONE ANDROID_PHONE Указанный выше провайдер не требует хранения каких-либо данных на вашей идентификационной карте, требуется только подтверждение наличия действующей идентификационной карты. Write access (update) LABEL DESKTOP ---------- -LABEL IOS_PHONE ANDROID_PHONE ----------- -LABEL ANDROID_TABLET IOS_TABLET +LABEL IOS_PHONE ANDROID_PHONE Доступ для записи (обновление) Read access LABEL DESKTOP ---------- -LABEL IOS_PHONE ANDROID_PHONE ----------- -LABEL ANDROID_TABLET IOS_TABLET +LABEL IOS_PHONE ANDROID_PHONE Доступ для чтения Read access (optional) LABEL DESKTOP ---------- -LABEL IOS_PHONE ANDROID_PHONE ----------- -LABEL ANDROID_TABLET IOS_TABLET +LABEL IOS_PHONE ANDROID_PHONE Доступ для чтения (опционально) Identify - LABEL IOS_PHONE ANDROID_PHONE ----------- -LABEL ANDROID_TABLET IOS_TABLET + LABEL IOS_PHONE ANDROID_PHONE Идентифицировать You are about to identify yourself towards the following provider: - LABEL IOS_PHONE ANDROID_PHONE + LABEL DESKTOP ---------- -LABEL ANDROID_TABLET IOS_TABLET +LABEL IOS_PHONE ANDROID_PHONE Вы собираетесь пройти самоидентификацию для следующего провайдера: Provider - LABEL IOS_PHONE ANDROID_PHONE ----------- -LABEL ANDROID_TABLET IOS_TABLET + LABEL IOS_PHONE ANDROID_PHONE Провайдер @@ -1357,11 +1190,6 @@ LABEL ANDROID_TABLET IOS_TABLET LABEL DESKTOP Попытки - - Remaining ID card PIN attempts: %1 - LABEL DESKTOP - Осталось попыток ввода PIN-кода идентификационной карты: %1 - Enter CAN LABEL DESKTOP @@ -1411,13 +1239,6 @@ LABEL ANDROID IOS LABEL ANDROID IOS Ввести PIN-код идентификационной карты - - The new ID card PIN and the confirmation do not match. Please correct your input. - INFO DESKTOP The changed ID card PIN was entered wrongfully during the confirmation process. ----------- -INFO ANDROID IOS The changed ID card PIN was entered wrongfully during confirmation. - Новый PIN-код идентификационной карты и его подтверждение не совпадают. Проверьте введенные данные. - Please enter the five-digit Transport PIN. INFO DESKTOP The AA2 expects the Transport PIN with five digits. @@ -1505,18 +1326,9 @@ LABEL ANDROID IOS LABEL ANDROID IOS Подтвердить новый PIN-код для Smart-eID - - The new Smart-eID PIN and the confirmation do not match. Please correct your input. - INFO DESKTOP The changed Smart-eID PIN was entered wrongfully during the confirmation process. ----------- -INFO ANDROID IOS The changed Smart-eID PIN was entered wrongfully during confirmation. - Новый PIN-код для Smart-eID и его подтверждение не совпадают. Проверьте введенные данные. - You have entered an incorrect, six-digit Smart-eID PIN twice. An incorrect third attempt will invalidate your Smart-eID and you will have to set it up again. - INFO DESKTOP The wrong Smart-eID PIN was entered twice on the Smart-eID ----------- -INFO ANDROID IOS The wrong Smart-eID PIN was entered twice on the Smart-eID + INFO DESKTOP The wrong Smart-eID PIN was entered twice on the Smart-eID Вы дважды ввели неправильный 6-значный PIN-код для Smart-eID. При третьем неправильном вводе электронная идентификационная карта Smart-eID становится недействительной, ее необходимо создать повторно. @@ -1557,6 +1369,11 @@ INFO ANDROID IOS The AA2 expects a Smart-eID PIN with six digits in an authentic LABEL ANDROID IOS Button to switch to a six-digit ID card PIN. У вас есть 6-значный PIN-код идентификационной карты? + + You have entered an incorrect, six-digit Smart-eID PIN twice. After the next failed attempt you will no longer be able to use your Smart-eID and will need to set it up again. + INFO ANDROID IOS The wrong Smart-eID PIN was entered twice on the Smart-eID + + Send CAN LABEL DESKTOP @@ -1613,12 +1430,40 @@ LABEL ANDROID IOS LABEL ANDROID IOS Отправить PIN-код идентификационной карты + + Send confirmation of new ID card PIN + LABEL ANDROID IOS + + + + Send confirmation of new Smart-eID PIN + LABEL ANDROID IOS + + Enter the pairing code shown on your smartphone. INFO DESKTOP The pairing code needs to be supplied. Введите указанный в смартфоне код сопряжения. + + GCollapsible + + collapse + LABEL ANDROID IOS + + + + expand + LABEL ANDROID IOS + + + + Currently selected is %1 + LABEL ANDROID IOS + + + GProgressBar @@ -1659,34 +1504,49 @@ LABEL ANDROID IOS Автозапуск %1 после загрузки и добавление в строку меню - Auto-start %1 after boot - LABEL WINDOWS Text for auto-start option - Автозапуск %1 после загрузки + Using the developer mode forces the notifications to be enabled. + LABEL DESKTOP Only visible when the user activates the developer mode in the settings. + В режиме разработчика оповещения включаются принудительно. + + + Network + LABEL DESKTOP + Сеть - Close after authentication + Use the proxy (%1) specified during the installation. LABEL DESKTOP - Закрытие после аутентификации + Используйте указанный при установке прокси-сервер (%1). - Use internal notifications + Appearance LABEL DESKTOP - Включение внутренних оповещений + - Using the developer mode forces the notifications to be enabled. - LABEL DESKTOP Only visible when the user activates the developer mode in the settings. - В режиме разработчика оповещения включаются принудительно. + Use the system font + LABEL DESKTOP + - Network + Toggling will restart the %1 LABEL DESKTOP - Сеть + - Use the proxy (%1) specified during the installation. + Close %1 after authentication LABEL DESKTOP - Используйте указанный при установке прокси-сервер (%1). + Закрытие после аутентификации + + + Show notifications inside of %1 + LABEL DESKTOP + Включение внутренних оповещений + + + Auto-start %1 after boot and add a tray icon + LABEL WINDOWS Text for auto-start option + Автозапуск %1 после загрузки @@ -1696,10 +1556,6 @@ LABEL ANDROID IOS LABEL DESKTOP Попытки - - Remaining ID card PIN attempts: %1 - Осталось попыток ввода PIN-кода идентификационной карты: %1 - Step %1 of 3 Шаг %1 из 3 @@ -1729,16 +1585,6 @@ LABEL ANDROID IOS INFO DESKTOP The AA2 is waiting for an ID card to be inserted into the card reader. Идентификационная карта не обнаружена. Убедитесь в том, что идентификационная карта размещена на устройстве чтения карт. - - No ID card detected. Please make sure that the NFC interface of the smartphone (connected to %1) is correctly placed on your ID card. - INFO DESKTOP The AA2 is waiting for the smartphone to be placed on the id. - Идентификационная карта не обнаружена. Убедитесь в том, что интерфейс NFC на вашем смартфоне (подключен к %1) правильно расположен относительно идентификационной карты. - - - Please place the smartphone (connected to %1) on your ID card or put the ID card on the card reader. - INFO DESKTOP The AA2 is waiting for an ID card to be inserted into the card reader (or smartphone for that matter). - Разместите смартфон (подключен к %1) на идентификационной карте или вставьте карту в устройство чтения карт. - No card reader detected. Please make sure that an USB card reader is connected or a smartphone as card reader is paired and available. Open the reader settings to configure readers and get more information about supported readers. INFO DESKTOP AA2 is waiting for the card reader or the ID card. @@ -1755,301 +1601,92 @@ LABEL ANDROID IOS Перейти к настройкам устройства чтения карт - The device "%1" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. - INFO ANDROID IOS The paired smartphone was removed since it did not respond to connection attempts. It needs to be paired again before using it. - Сопряжение устройства «%1» не было выполнено, поскольку оно не отвечало на попытки соединения. Снова выполните сопряжение устройства для его использования в качестве устройства чтения карт. + No ID card detected. Please follow the instructions on your smartphone (connected to %1) to use it as card reader. + INFO DESKTOP The AA2 is waiting for the smartphone to be placed on the id. + + + + Please follow the instructions on your smartphone (connected to %1) or put the ID card on the card reader. + INFO DESKTOP The AA2 is waiting for an ID card to be inserted into the card reader (or smartphone for that matter). + Hint Hint + LABEL DESKTOP +---------- +LABEL ANDROID IOS Совет - HistoryListItem - - Click to view details of history entry. - LABEL ANDROID IOS - Щелкните, чтобы просмотреть подробную информацию о записи журнала. - + LanguageButtonData - Tap for more details - LABEL ANDROID IOS - Нажмите для получения подробной информации + German + LABEL ALL_PLATFORMS + Немецкий - - - HistoryListViewDelegate - Delete entry - LABEL ANDROID - Удалить запись + Set language to german + LABEL ALL_PLATFORMS + Использовать немецкий язык - Delete history entry: %1 - INFO IOS Accessible name for the trash icon of a history entry. - Удалить запись журнала: %1 + English + LABEL ALL_PLATFORMS + Английский - - - HistoryRemovalTimePeriodControl - Time period - LABEL DESKTOP - Временной промежуток + Set language to english + LABEL ALL_PLATFORMS + Использовать английский язык - Past hour - LABEL DESKTOP - Последний час + Ukrainian + LABEL ALL_PLATFORMS + Украинский - Past day - LABEL DESKTOP - Последний день + Set language to ukrainian + LABEL ALL_PLATFORMS + Использовать украинский язык - Past week - LABEL DESKTOP - Последняя неделя + Russian + LABEL ALL_PLATFORMS + Русский - Last four weeks - LABEL DESKTOP - Последние четыре недели + Set language to russian + LABEL ALL_PLATFORMS + Использовать русский язык + + + LicenseInformation - All history - LABEL DESKTOP - Весь журнал + Software license + LABEL ANDROID IOS + Лицензия на программное обеспечение - HistoryView + LocalNetworkInfo - Delete history? - INFO DESKTOP Header of the confirmation dialog to clear the entire authentication history. - Удалить журнал? + Go to application settings + INFO IOS Link to application settings + Перейти к настройкам приложения - All history entries will be deleted. - INFO DESKTOP Content of the confirmation dialog to clear the entire authentication history. - Все записи журнала будут удалены. + Ensure that access to the local network is allowed in your settings. + INFO IOS Let user know to check the application settings for local network permission + Убедитесь в наличии доступа к локальной сети. - - Deleted %1 entries from the history. - INFO DESKTOP Feedback how many history entries were removed. - Удалено записей из журнала: %1. - - - History - LABEL DESKTOP - Журнал - - - Search in history - LABEL DESKTOP - Поиск в журнале - - - Clear history - LABEL DESKTOP - Очистить журнал - - - Save as PDF... - LABEL DESKTOP - Сохранить как PDF… - - - Portable Document Format (*.pdf) - LABEL DESKTOP - Portable Document Format (*.pdf) - - - Currently there are no history entries. - INFO DESKTOP No authentication history, placeholder text. - В настоящее время в журнале нет записей. - - - No history entries match your search term. - INFO DESKTOP No authentication history entries match the search, placeholder text. - По вашему запросу записей журнала не найдено. - - - Delete all entries - LABEL IOS - Удалить все записи - - - Save history - LABEL DESKTOP - Сохранить журнал - - - - HistoryViewConfirmationPopup - - Delete history - LABEL ANDROID IOS - Удалить журнал - - - All history entries will be deleted. - LABEL ANDROID IOS Confirmaton popup to clear all history entries. - Все записи журнала будут удалены. - - - Delete - LABEL ANDROID IOS - Удалить - - - - HistoryViewDetails - - Details for history entry - Подробные данные записи журнала - - - Provider Information - LABEL ANDROID IOS - Информация о провайдере - - - Provider name - LABEL DESKTOP ----------- -LABEL ANDROID IOS - Имя провайдера - - - Purpose - LABEL DESKTOP ----------- -LABEL ANDROID IOS - Цель - - - Date - LABEL DESKTOP ----------- -LABEL ANDROID IOS - Дата - - - dd.MM.yyyy - LABEL DESKTOP Date format according to https://doc.qt.io/qt/qdate.html#toString ----------- -LABEL ANDROID IOS Date format according to https://doc.qt.io/qt/qdate.html#toString - dd.MM.yyyy - - - Write access (update) - LABEL DESKTOP ----------- -LABEL ANDROID IOS - Доступ для записи (обновление) - - - Read access - LABEL DESKTOP ----------- -LABEL ANDROID IOS - Доступ для чтения - - - Terms of usage - LABEL DESKTOP ----------- -LABEL ANDROID IOS - Условия использования - - - - HistoryViewTitleBarControls - - Delete all entries - LABEL ANDROID - Удалить все записи - - - - LanguageButtons - - German - LABEL ALL_PLATFORMS - Немецкий - - - Set language to german - LABEL ALL_PLATFORMS - Использовать немецкий язык - - - English - LABEL ALL_PLATFORMS - Английский - - - Set language to english - LABEL ALL_PLATFORMS - Использовать английский язык - - - Ukrainian - LABEL ALL_PLATFORMS - Украинский - - - Set language to ukrainian - LABEL ALL_PLATFORMS - Использовать украинский язык - - - Russian - LABEL ALL_PLATFORMS - Русский - - - Set language to russian - LABEL ALL_PLATFORMS - Использовать русский язык - - - - LanguageSelectionPopup - - Select language - LABEL ANDROID IOS - Выбрать язык - - - - LicenseInformation - - Software license - LABEL ANDROID IOS - Лицензия на программное обеспечение - - - - LocalNetworkInfo - - Go to application settings - INFO IOS Link to application settings - Перейти к настройкам приложения - - - Ensure that access to the local network is allowed in your settings. - INFO IOS Let user know to check the application settings for local network permission - Убедитесь в наличии доступа к локальной сети. - - - - LogTitleBarControls + + + LogTitleBarControls Share log Поделиться файлом журнала @@ -2164,6 +1801,14 @@ INFO ANDROID IOS The current logfile is about to be removed, user confirmation r В настоящее время отсутствуют записи журнала, соответствующие вашему фильтру. + + LogViewDelegate + + The log entry was copied to the clipboard. + INFO DESKTOP Toast message used to confirm the copy of a log entry. + Запись журнала скопирована в буфер обмена. + + MainView @@ -2171,28 +1816,11 @@ INFO ANDROID IOS The current logfile is about to be removed, user confirmation r LABEL DESKTOP Просмотреть<br>персональные данные - - Provider - LABEL DESKTOP ----------- -LABEL ANDROID IOS - Провайдер - - - History - LABEL DESKTOP - Журнал - Settings LABEL DESKTOP Настройки - - Change my<br>(Transport) PIN - LABEL DESKTOP - Изменить<br>(временный) PIN-код - Help LABEL DESKTOP @@ -2208,11 +1836,6 @@ LABEL ANDROID IOS LABEL ANDROID IOS Проверить устройство и идентификационную карту - - Change my (Transport) PIN - LABEL ANDROID IOS - Изменить (временный) PIN-код - See my personal data LABEL ANDROID IOS @@ -2223,6 +1846,25 @@ LABEL ANDROID IOS LABEL ANDROID IOS Smart-eID + + Two finger swipe to scroll. + + + + List of workflows with %1 items. + + + + Item %1 of %2 + + + + Change PIN + LABEL DESKTOP +---------- +LABEL ANDROID IOS + Изменить PIN-код + MoreInformationLink @@ -2246,11 +1888,6 @@ LABEL ANDROID IOS LABEL DESKTOP Общая информация - - Diagnosis and logs - LABEL DESKTOP - Диагностика и файлы журнала - Version information LABEL DESKTOP @@ -2260,9 +1897,7 @@ LABEL ANDROID IOS Software license - LABEL DESKTOP ----------- -LABEL ANDROID IOS + LABEL DESKTOP Лицензия на программное обеспечение @@ -2277,255 +1912,137 @@ LABEL ANDROID IOS LABEL ANDROID IOS Помощь и обратная связь - - Tutorial - LABEL ANDROID IOS - Руководство - - - Do you want to know how to use %1? - LABEL ANDROID IOS - Хотите узнать, как пользоваться %1? - - - Video tutorials - LABEL ANDROID IOS - Видеоруководство - - - Do you want to see the video tutorials? - LABEL ANDROID IOS - Хотите посмотреть видеоруководство? - - - FAQ - LABEL ANDROID IOS - Часто задаваемые вопросы - - - Do you have further questions about %1? - LABEL ANDROID IOS - Остались вопросы о %1? - - - Support - LABEL ANDROID IOS - Поддержка - - - Do you need further support? - LABEL ANDROID IOS - Требуется дополнительная поддержка? - Privacy statement LABEL ANDROID IOS Положение о конфиденциальности - - Do you want to read the privacy statement? - LABEL ANDROID IOS - Хотите прочитать положение о конфиденциальности? - Accessibility statement LABEL ANDROID IOS Заявление о доступности - - Do you want to read the accessibility statement? - LABEL ANDROID IOS - Хотите прочитать заявление о доступности? - Rate %1 LABEL ANDROID IOS Оценить %1 - - Do you want to rate us in the App Store? - LABEL ANDROID IOS - Хотите оценить нас в App Store? - - - Do you want to rate us in the Google Play Store? - Хотите оценить нас в Google Play Store? - - - Diagnosis - LABEL ANDROID IOS - Диагностика - Logs LABEL ANDROID IOS Файлы журнала - Do you want to view the logs of %1? + Information LABEL ANDROID IOS - Просмотреть файлы журнала %1? + Информация - Report error + List of Providers LABEL ANDROID IOS - Сообщить об ошибке + + + + Data and logs + LABEL DESKTOP + Диагностика и файлы журнала - Did you find a bug? Please help us by sending us the log file together with a description of the error. + FAQ - Frequently asked questions LABEL ANDROID IOS - Нашли ошибку? Помогите нам устранить ее, отправив файл журнала с описанием этой ошибки. + Часто задаваемые вопросы - Information + Contact LABEL ANDROID IOS - Информация + Поддержка - Do you want to see detailed information about %1? + Show Logs LABEL ANDROID IOS - Хотите просмотреть подробную информацию о %1? + Файлы журнала - Do you want to read the software licenses? + Send log to the support LABEL ANDROID IOS - Хотите прочитать лицензии на программное обеспечение? + Сообщить об ошибке - Do you want to view the release notes of %1? + Terms of use and software license LABEL ANDROID IOS - Хотите просмотреть примечания к версии %1? + Лицензия на программное обеспечение MoreViewDiagnosis - Diagnosis + Logs LABEL DESKTOP - Диагностика + Файлы журнала - You can view and save the diagnosis information of the AusweisApp2 and your system here. + Show logs LABEL DESKTOP - Здесь можно просмотреть и сохранить информацию о диагностике AusweisApp2 и вашей системы. + Показать файлы журнала - Show diagnosis + Show system data LABEL DESKTOP - Показать диагностику + Показать диагностику - Logs + System data LABEL DESKTOP - Файлы журнала - - - Do you want to view the logs of %1? - LABEL DESKTOP - Просмотреть файлы журнала %1? - - - Show logs - LABEL DESKTOP - Показать файлы журнала - - - Report error - LABEL DESKTOP - Сообщить об ошибке - - - Did you find a bug? Please help us by sending us the log file together with a description of the error. - LABEL DESKTOP - Нашли ошибку? Помогите нам устранить ее, отправив файл журнала с описанием этой ошибки. - - - Open website - LABEL DESKTOP - Открыть сайт + Диагностика MoreViewGeneral - - Online help - LABEL DESKTOP - Онлайн-справка - - - Do you have questions about %1? - LABEL DESKTOP - Есть вопросы о %1? - Open website LABEL DESKTOP Открыть сайт - - Video tutorials - LABEL DESKTOP - Видеоруководство - - - Do you want to see the video tutorials? - LABEL DESKTOP - Хотите посмотреть видеоруководство? - - - FAQ - LABEL DESKTOP - Часто задаваемые вопросы - - - Do you have further questions about %1? - LABEL DESKTOP - Остались вопросы о %1? - - - Support - LABEL DESKTOP - Поддержка - - - Do you need further support? - LABEL DESKTOP - Требуется дополнительная поддержка? - Privacy statement LABEL DESKTOP Положение о конфиденциальности - - Do you want to read the privacy statement? - LABEL DESKTOP - Хотите прочитать положение о конфиденциальности? - Accessibility statement LABEL DESKTOP Заявление о доступности - Do you want to read the accessibility statement? + Do you want to see a list of service providers? LABEL DESKTOP - Хотите прочитать заявление о доступности? + - Setup assistant + List of Providers LABEL DESKTOP - Помощник по настройке + - Do you want to run the setup assistant again? + FAQ - Frequently asked questions LABEL DESKTOP - Запустить помощника по настройке снова? + Часто задаваемые вопросы - Start setup assistant + Contact LABEL DESKTOP - Запустить помощника по настройке + Поддержка + + + + NavigationAction + + Cancel + Отмена + + + Back + Назад @@ -2549,18 +2066,10 @@ LABEL ANDROID IOS NavigationView - - History - Журнал - Start Пуск - - Provider - Провайдер - Settings Настройки @@ -2702,6 +2211,7 @@ LABEL ANDROID IOS Delete last digit, disabled until input is present. + LABEL ANDROID IOS A11y text for the "delete" button text when the button is disabled. Удалить последнюю цифру, деактивировано до начала ввода данных. @@ -2783,21 +2293,11 @@ LABEL ANDROID IOS LABEL ALL_PLATFORMS Информация о PIN-коде - - The card PIN is a six-digit PIN that you set yourself. You always need this PIN if you want to use the eID function. - INFO ALL_PLATFORMS Answer to the question 'what is the card pin?' - PIN-код карты — это 6-значный PIN-код, который пользователь создает самостоятельно. Этот PIN-код необходим, если планируется использовать функцию eID. - Where can I find the card PIN? LABEL ALL_PLATFORMS Где найти PIN-код карты? - - You set the card PIN either directly when you picked up your ID card at the citizens' office (Bürgeramt) or later in AusweisApp2 using the five-digit Transport PIN. Only when you have set a six-digit PIN of your own choice can you use the eID function. - INFO ALL_PLATFORMS Answer to the question 'Where can I find the card PIN?' - Вы устанавливаете PIN-код карты либо непосредственно при получении идентификационной карты в ведомстве по делам граждан (Bürgeramt), либо позже в AusweisApp2, используя для этого 5-значный временный PIN-код. Только установив 6-значный PIN-код по своему выбору, вы можете использовать функцию eID. - How do I choose a secure PIN? LABEL ALL_PLATFORMS @@ -2815,7 +2315,9 @@ LABEL ANDROID IOS Keep your PIN secret and change it if another person becomes aware of it. - INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure PIN?' paragraph 3/3 + INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure PIN?' paragraph 3/3 +---------- +INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure (Smart-eID) PIN?' paragraph 3/3 Держите PIN-код в секрете и измените его, если о нем станет известно другому человеку. @@ -2843,21 +2345,6 @@ LABEL ANDROID IOS INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 3/3 После создания PIN-кода карты временный PIN-код перестает действовать. - - Smartphone as card reader information - LABEL ALL_PLATFORMS - Информация о смартфоне, используемом в качестве устройства чтения карт - - - You may use your smartphone as a card reader with AusweisApp2. The smartphone needs to feature a supported NFC chipset and both devices, your smartphone and this machine, need to be connected to the same WiFi network. - INFO ALL_PLATFORMS Description text of SaC pairing - Вы можете использовать смартфон в качестве устройства чтения карт с помощью AusweisApp2. Смартфон должен быть оснащен поддерживаемым чипсетом NFC, и оба устройства (ваш смартфон и этот компьютер) должны быть подключены к одной сети Wi-Fi. - - - To use your smartphone as a card reader you'll always need to activate the remote service in the AusweisApp2 on the smartphone. For the first time you'll also need to start the pairing mode on your smartphone, select the device from the list of available devices on this machine and then enter the pairing code shown on the phone. - INFO ALL_PLATFORMS Description text of SaC pairing - Чтобы можно было использовать смартфон в качестве устройства чтения карт, в AusweisApp2 на смартфоне должна быть постоянно активирована удаленная служба. Для первичного соединения необходимо запустить режим сопряжения на смартфоне, выбрать устройство из списка доступных устройств на компьютере и ввести код сопряжения, отображающийся на смартфоне. - Where do I find the PUK? LABEL ALL_PLATFORMS @@ -2987,7 +2474,7 @@ LABEL ALL_PLATFORMS Your ID card comes with a five-digit 'Transport PIN' which you need to replace with a six-digit PIN that you choose yourself. - INFO ALL_PLATFORMS Description text explaining the PINs 1/6 + INFO ALL_PLATFORMS Description text explaining the PINs 1/7 К вашей идентификационной карте прилагается 5-значный временный PIN-код, который необходимо заменить на 6-значным PIN-кодом (его вы выберете сами). @@ -2995,36 +2482,11 @@ LABEL ALL_PLATFORMS LABEL ALL_PLATFORMS 5-значный временный PIN-код - - The five-digit Transport PIN was sent to you by post after you applied for your ID card. - INFO ALL_PLATFORMS Description text explaining the PINs 2/6 - 5-значный временный PIN-код был отправлен вам по почте после того, как вы заказали идентификационную карту. - - - The PIN can only be used once. When you set up the eID function, you will replace this five-digit PIN with a six-digit PIN that you choose yourself. - INFO ALL_PLATFORMS Description text explaining the PINs 3/6 - Этот PIN-код можно использовать только один раз. Настроив функцию eID, вы замените этот 5-значный PIN-код 6-значным PIN-кодом, который выберете сами. - Six-digit PIN LABEL ALL_PLATFORMS 6-значный PIN-код - - This is a number that you choose yourself when you set up the eID function for the first time. It replaces your five-digit Transport PIN. - INFO ALL_PLATFORMS Description text explaining the PINs 4/6 - Это номер, который вы выбираете сами при настройке функции eID в первый раз. Он заменяет 5-значный временный PIN-код. - - - This PIN allows you to prove online that the ID card belongs to you. No one can use your ID card online without this PIN. - INFO ALL_PLATFORMS Description text explaining the PINs 5/6 - Этот PIN-код позволяет в режиме онлайн подтвердить то, что идентификационная карта принадлежит именно вам. Никто не сможет использовать вашу идентификационную карту в режиме онлайн без этого PIN-кода. - - - You can change your six-digit PIN at any time in AusweisApp2. - INFO ALL_PLATFORMS Description text explaining the PINs 6/6 - Вы можете изменить свой 6-значный PIN-код в любое время в AusweisApp2. - You can use the PIN Reset Service to request a new card PIN free of charge. LABEL ALL_PLATFORMS @@ -3040,6 +2502,96 @@ LABEL ALL_PLATFORMS LABEL ALL_PLATFORMS Hint text for PIN but it is unknown. Если вы забыли PIN-код карты, вы можете бесплатно запросить новый PIN-код, воспользовавшись службой сброса PIN-кода. + + The five-digit Transport PIN was sent to you by mail after you applied for your ID card. + INFO ALL_PLATFORMS Description text explaining the PINs 2/7 + 5-значный временный PIN-код был отправлен вам по почте после того, как вы заказали идентификационную карту. + + + What is the Smart-eID PIN? + LABEL ALL_PLATFORMS + + + + Set up Smart-eID + LABEL ALL_PLATFORMS + Создание Smart-eID + + + The Smart-eID PIN is a six-digit PIN that you set yourself. You always need this PIN if you want to use your Smart-eID. + INFO ALL_PLATFORMS Answer to the question 'what is the Smart-eID pin?' + + + + For your six-digit Smart-eID PIN, choose a combination of numbers that cannot be guessed - i.e. neither "123456", nor your date of birth, nor any other numbers printed on your ID card. + INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure (Smart-eID) PIN?' paragraph 1/3 + + + + You can change your six-digit Smart-eID PIN at any time and an unlimited number of times as long as you know your valid Smart-eID PIN. + INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure (Smart-eID) PIN?' paragraph 2/3 + + + + The PIN can only be used once. When you set up the eID function, you will replace this five-digit Transport PIN with a six-digit card PIN that you choose yourself. + INFO ALL_PLATFORMS Description text explaining the PINs 3/7 + + + + The six-digit card PIN is a number that you choose yourself when you set up the eID function for the first time. It replaces your five-digit Transport PIN. + INFO ALL_PLATFORMS Description text explaining the PINs 4/7 + + + + The Smart-eID PIN also has six digits. You also choose that PIN yourself while setting up the Smart-eID for the first time. + INFO ALL_PLATFORMS Description text explaining the PINs 5/7 + + + + You can change your card PIN and your Smart-eID PIN at any time in %1. + INFO ALL_PLATFORMS Description text explaining the PINs (%1 is replaced with the application name) 7/7 + + + + With this six-digit PIN you prove online that the ID card or Smart-eID belongs to you. No one can use the eID function without this PIN. + INFO ALL_PLATFORMS Description text explaining the PINs 6/7 + + + + The card PIN is a six-digit PIN that you set yourself. You always need this PIN if you want to use the eID function with your ID card. + INFO ALL_PLATFORMS Answer to the question 'what is the card pin?' + + + + You set the card PIN either directly when you picked up your ID card at the citizens' office (Bürgeramt) or later in %1 using the five-digit Transport PIN. Only when you have set a six-digit PIN of your own choice can you use the eID function and set up a Smart-eID. + INFO ALL_PLATFORMS Answer to the question 'Where can I find the card PIN?' (%1 is replaced with the application name) + + + + If you have forgotten your Smart-eID PIN, you can renew your Smart-eID and thereby set a new PIN. + LABEL ALL_PLATFORMS Hint text for PIN but it is unknown. + + + + Where can I find the Smart-eID PIN? + LABEL ALL_PLATFORMS + + + + You have set the Smart-eID PIN while setting up the Smart-eID. + INFO ALL_PLATFORMS Answer to the question 'Where can I find the Smart-eID PIN?' + + + + With this six-digit PIN you prove online that the ID card belongs to you. No one can use the eID function without this PIN. + INFO ALL_PLATFORMS Description text explaining the PINs 6/7 + + + + You can change your card PIN at any time in %1. + INFO ALL_PLATFORMS Description text explaining the PINs (%1 is replaced with the application name) 7/7 + + PersonalizationController @@ -3106,6 +2658,11 @@ LABEL ALL_PLATFORMS LABEL ANDROID IOS Если вы дарите или продаете смартфон, сначала удалите из него Smart-eID. + + If you uninstall the %1 or reset your smartphone, the Smart-eID must be set up again. + LABEL ANDROID IOS + + PersonalizationProgressView @@ -3164,6 +2721,11 @@ LABEL ALL_PLATFORMS LABEL ANDROID IOS Smart-eID + + Please wait a moment, the current process is being finished. + LABEL ANDROID IOS + + PersonalizationResultView @@ -3202,11 +2764,6 @@ LABEL ALL_PLATFORMS INFO ANDROID IOS Placeholder (error) text if the Smart-eID setup finished successfully but for some reason no blocking code was retrieved Создание Smart-eID успешно завершено, но получить код блокировки не удалось. В целях безопасности необходимо удалить Smart-eID и создать заново. - - You have reached the allowed amount of Smart-eID setups for the current period. You may set up another Smart-eID with your ID card on %1. - LABEL ANDROID IOS - Достигнуто максимально допустимое количество попыток создания Smart-eID для текущего периода. Вы можете создать другую электронную идентификационную карту Smart-eID на основе своей идентификационной карты (%1). - Attention: you may only set up <b><u>one</u></b> more Smart-eID with your ID card. Further setups may be carried out on %1. LABEL ANDROID IOS @@ -3255,378 +2812,143 @@ LABEL ALL_PLATFORMS - ProviderContactInfo - - Provider contact information - Контактная информация провайдера - + ProviderInfoSection - Contact information of the selected provider. - Контактная информация выбранного провайдера. + See details under "more..." + LABEL DESKTOP + Подробнее см. в пункте «Дополнительные сведения». - Contact + Show more information about the service provider LABEL DESKTOP - Контакты + Показать больше информации о провайдере службы - Unknown + Details about the provider LABEL DESKTOP - Неизвестно + Подробная информация о провайдере - ProviderDetailButtonBar + ProxyCredentialsPopup - To provider - LABEL DESKTOP + Sign in + LABEL DESKTOP Text of the button in the proxy credentials popup. ---------- -LABEL ANDROID_TABLET IOS_TABLET - К провайдеру - - - - ProviderDetailDescription - - Description - LABEL ANDROID_TABLET IOS_TABLET - Описание - - - The provider did not provide a description. - LABEL ANDROID_TABLET IOS_TABLET - Провайдер не предоставил описание. +LABEL DESKTOP Title of the proxy credentials popup. + Войти в систему - - - ProviderDetailHistory - List of your past interactions with this provider - Список случаев вашего взаимодействия с этим провайдером + The proxy %1 requires username and password. + LABEL DESKTOP Text of the proxy credentials popup. An example for %1 is http://proxy.example.com:1337. + Прокси-сервер %1 запрашивает имя пользователя и пароль. - The list is empty, no recorded interaction with this provider. - Список пуст, нет записанных случаев взаимодействия с этим провайдером. + Proxy credential username + LABEL DESKTOP Accessible name. + Имя пользователя для прокси-сервера - Currently there are no history entries. - INFO DESKTOP No authentication history, placeholder text. ----------- -INFO ANDROID_TABLET IOS_TABLET No authentication history, placeholder text. - В настоящее время в журнале нет записей. + Username + LABEL DESKTOP Label of the textfield for the username. + Имя пользователя - History - LABEL ANDROID_TABLET IOS_TABLET - Журнал + Proxy credential password + LABEL DESKTOP Accessible name. + Пароль для прокси-сервера - Purpose for reading out requested data - LABEL ANDROID_TABLET IOS_TABLET - Цель считывания запрошенных данных + Password + LABEL DESKTOP Label of the textfield for the password. + Пароль - ProviderDetailHistoryInfo - - Provider - LABEL ANDROID_TABLET IOS_TABLET - Провайдер - + QObject - Purpose for reading out requested data - LABEL ANDROID_TABLET IOS_TABLET - Цель считывания запрошенных данных + An error occurred in log handling: %1 + LABEL ALL_PLATFORMS + Произошла ошибка при управлении файлом журнала: %1 - Read data - LABEL ANDROID_TABLET IOS_TABLET - Считать данные + Please describe the error that occurred. + Опишите возникшую ошибку. - Terms of usage - LABEL ANDROID_TABLET IOS_TABLET - Условия использования + You may want to attach the logfile which can be saved from the error dialog. + Вы можете приложить файл журнала, сохраненный из диалогового окна ошибки. - - - ProviderDetailHistoryItem - Service: - LABEL DESKTOP - Служба: + Error code + Код ошибки - Provider: - LABEL DESKTOP - Провайдер: + Service URL + URL службы - Click to view details of history entry. - Щелкните, чтобы просмотреть подробную информацию о записи журнала. + Parameter of occurred error: + Параметры возникшей ошибки: - Touch for more details - LABEL ANDROID IOS - Нажмите для получения подробной информации + Critical errors: + Критические ошибки: - ProviderDetailView - - Description - LABEL DESKTOP - Описание - - - The provider did not provide a description. - LABEL DESKTOP - Провайдер не предоставил описание. - + ReaderConfigurationInfo - History - LABEL DESKTOP - Журнал + Unknown reader + LABEL ALL_PLATFORMS + Неизвестное устройство чтения карт - ProviderGridView + ReleaseNotes - No results matching your search query found - LABEL DESKTOP IOS_TABLET ANDROID_TABLET The text entered into the provider search field results in no matches - По вашему запросу результатов не найдено + Retry + LABEL DESKTOP +---------- +LABEL ANDROID IOS + Повторить попытку - - - ProviderHeader - To provider + Release notes LABEL ANDROID IOS - К провайдеру - - - - ProviderInfoSection - - See details under "more..." - LABEL DESKTOP - Подробнее см. в пункте «Дополнительные сведения». + Примечания к версии - ProviderListItemDelegate + RemoteReaderDelegate - Open provider details for %1 - Открыть подробную информацию провайдера %1 + Smartphone named "%1" + Имя смартфона «%1» - Click to set category filter to %1 - Нажмите здесь, чтобы настроить фильтр категорий %1 + Press space to unpair the smartphone "%1". + Нажмите пробел, чтобы отменить сопряжение смартфона «%1». - - - ProviderModelItem - Click to open homepage. - INFO ALL_PLATFORMS A11y action text appended to provider homepage to be read read by screen reader. - Нажмите, чтобы открыть домашнюю страницу. + Press space to pair the smartphone "%1". + Нажмите пробел для сопряжения смартфона «%1». - Click to send email. - INFO ALL_PLATFORMS A11y action text appended to provider mail to be read read by screen reader. - Нажмите, чтобы отправить сообщение электронной почты. + Remove remote device + Удалить дистанционное устройство + + + RemoteReaderView - Costs + Paired devices LABEL DESKTOP - Стоимость + Сопряженные устройства - Click to call. - INFO ALL_PLATFORMS A11y action text appended to provider phone number to be read read by screen reader. - Нажмите, чтобы позвонить. - - - Click to open map. - INFO ALL_PLATFORMS A11y action text appended to provider address maps url to be read read by screen reader. - Нажмите, чтобы открыть карту. - - - Homepage - Домашняя страница - - - E-Mail - Электронная почта - - - Phone - Телефон - - - Address - Адрес - - - - ProviderOverview - - All provider - LABEL DESKTOP - Все провайдеры - - - Citizen services - LABEL DESKTOP - Услуги для граждан - - - Financials - LABEL DESKTOP - Финансы - - - Insurances - LABEL DESKTOP - Страхование - - - Other services - LABEL DESKTOP - Другие услуги - - - - ProviderView - - Provider - LABEL DESKTOP - Провайдер - - - Search providers - LABEL DESKTOP - Поиск провайдеров - - - - ProxyCredentialsPopup - - Sign in - LABEL DESKTOP Text of the button in the proxy credentials popup. ----------- -LABEL DESKTOP Title of the proxy credentials popup. - Войти в систему - - - The proxy %1 requires username and password. - LABEL DESKTOP Text of the proxy credentials popup. An example for %1 is http://proxy.example.com:1337. - Прокси-сервер %1 запрашивает имя пользователя и пароль. - - - Proxy credential username - LABEL DESKTOP Accessible name. - Имя пользователя для прокси-сервера - - - Username - LABEL DESKTOP Label of the textfield for the username. - Имя пользователя - - - Proxy credential password - LABEL DESKTOP Accessible name. - Пароль для прокси-сервера - - - Password - LABEL DESKTOP Label of the textfield for the password. - Пароль - - - - QObject - - An error occurred in log handling: %1 - LABEL ALL_PLATFORMS - Произошла ошибка при управлении файлом журнала: %1 - - - Please describe the error that occurred. - Опишите возникшую ошибку. - - - You may want to attach the logfile which can be saved from the error dialog. - Вы можете приложить файл журнала, сохраненный из диалогового окна ошибки. - - - Error code - Код ошибки - - - Service URL - URL службы - - - Parameter of occurred error: - Параметры возникшей ошибки: - - - Critical errors: - Критические ошибки: - - - - ReaderConfigurationInfo - - Unknown reader - LABEL ALL_PLATFORMS - Неизвестное устройство чтения карт - - - - ReleaseNotes - - Retry - LABEL DESKTOP ----------- -LABEL ANDROID IOS - Повторить попытку - - - Release notes - LABEL ANDROID IOS - Примечания к версии - - - - RemoteReaderDelegate - - Smartphone named "%1" - Имя смартфона «%1» - - - Press space to unpair the smartphone "%1". - Нажмите пробел, чтобы отменить сопряжение смартфона «%1». - - - Press space to pair the smartphone "%1". - Нажмите пробел для сопряжения смартфона «%1». - - - Remove remote device - Удалить дистанционное устройство - - - - RemoteReaderView - - Paired devices - Сопряженные устройства - - - Add pairing - Добавить сопряжение + Add pairing + LABEL DESKTOP + Добавить сопряжение Open the %1 on your Smartphone as card reader. @@ -3649,6 +2971,7 @@ LABEL ANDROID IOS Last connected + LABEL DESKTOP Последние подключенные @@ -3659,6 +2982,11 @@ LABEL ANDROID IOS RemoteServiceController + + Remote service + LABEL ANDROID IOS + Удаленная служба + You are about to identify yourself towards the following provider using the device "%1": LABEL ANDROID IOS @@ -3669,11 +2997,6 @@ LABEL ANDROID IOS LABEL ANDROID IOS Устройство чтения карт - - Remote service - LABEL ANDROID IOS - Удаленная служба - RemoteServiceSettings @@ -3761,7 +3084,7 @@ To do this you first have to pair that device with this smartphone. Paired Devices - INFO ANDROID IOS + LABEL ANDROID IOS Сопряженные устройства @@ -3807,6 +3130,11 @@ To do this you first have to pair that device with this smartphone. RemoteServiceViewRemote + + Click to remove device + LABEL ANDROID IOS + Нажмите для удаления устройства + Remove pairing INFO ANDROID IOS @@ -3842,11 +3170,6 @@ To do this you first have to pair that device with this smartphone. LABEL ANDROID IOS Добавить сопряжение - - Click to remove device - LABEL ANDROID IOS - Нажмите для удаления устройства - Last connected LABEL ANDROID IOS @@ -3904,9 +3227,9 @@ To do this you first have to pair that device with this smartphone. К сожалению, подключенный в качестве устройства чтения карт (SaC) смартфон не соответствует техническим требованиям (не поддерживается расширенная длина). - Connected to %1. Please place the NFC interface of the smartphone on your ID card. + Connected to %1. Please follow the instructions on the connected smartphone. INFO ANDROID IOS The connection to the smartphone was established, the ID card may be inserted. - Подключено к %1. Разместите интерфейс NFC смартфона на идентификационной карте. + Manage pairings @@ -3926,10 +3249,6 @@ To do this you first have to pair that device with this smartphone. ResultErrorView - - Show error details - Показать подробную информацию об ошибке - Details Подробная информация @@ -3969,109 +3288,15 @@ To do this you first have to pair that device with this smartphone. - ScreenOrientationSelectionPopup - - Select screen orientation - LABEL ANDROID - Выбрать ориентацию экрана - - - Set screen orientation to portrait - LABEL ANDROID - Установить книжную ориентацию экрана - - - Portrait - LABEL ANDROID - Книжная ориентация - - - recommended - рекомендуется - - - Set screen orientation to landscape - LABEL ANDROID - Установить альбомную ориентацию экрана - - - Landscape - LABEL ANDROID - Альбомная ориентация - - - Using a screen orientation unfit for your device may result in display errors. - LABEL ANDROID - Использование ориентации экрана, не соответствующей вашему устройству, может привести к ошибкам индикации. - - - - SearchBar - - Search - LABEL DESKTOP ----------- -LABEL ANDROID - Поиск - - - Clear - Очистить - - - Type provider to search for - LABEL ANDROID - Введите имя провайдера для поиска - - - Abort search - LABEL ANDROID - Отменить поиск - - - Search provider list - LABEL ANDROID - Поиск в списке провайдеров - - - Enter search string - Введите поисковый запрос - - - Search providers - Поиск провайдеров - - - Clear search string - Удалить поисковый запрос - + RetryCounter - Cancel - LABEL IOS - Отмена + Remaining ID card PIN attempts: %1 + LABEL DESKTOP + Осталось попыток ввода PIN-кода идентификационной карты: %1 SecurityAndPrivacySettings - - History - LABEL DESKTOP - Журнал - - - Save authentication history - LABEL DESKTOP - Сохранить журнал процессов аутентификации - - - Clear entire history - LABEL DESKTOP - Удалить весь журнал - - - History is empty - Нет записей журнала - Onscreen keypad LABEL DESKTOP @@ -4082,16 +3307,6 @@ LABEL ANDROID LABEL DESKTOP Использовать экранную клавиатуру для ввода PIN-кода - - Shuffle keypad buttons - LABEL DESKTOP - Случайное расположение кнопок клавиатуры - - - Visual feedback when pressing keypad buttons - LABEL DESKTOP - Анимация кнопок экранной клавиатуры при нажатии - Software updates LABEL DESKTOP @@ -4133,19 +3348,19 @@ LABEL ANDROID Нет информации об обновлениях, проверьте наличие доступных обновлений вручную. - Delete history + Shuffle digits of on screen keypad LABEL DESKTOP - Удалить журнал + Случайное расположение кнопок клавиатуры - All history entries will be deleted. - INFO DESKTOP The current history is about to be removed, user confirmation required. - Все записи журнала будут удалены. + Button animation + LABEL DESKTOP + Анимация кнопок экранной клавиатуры при нажатии - Deleted %1 entries from the history. - INFO DESKTOP Feedback how many history entries were removed. - Удалено записей из журнала: %1. + Visually highlight key presses on screen keypad + LABEL DESKTOP + @@ -4166,34 +3381,17 @@ LABEL ANDROID Считать данные - Save as PDF... - LABEL DESKTOP - Сохранить как PDF… - - - Information - Информация - - - Portable Document Format (*.pdf) - LABEL DESKTOP - Portable Document Format (*.pdf) - - - OK - LABEL DESKTOP - OK + OK + LABEL DESKTOP +---------- +LABEL ANDROID IOS + OK Identify LABEL ANDROID IOS Идентифицировать - - Save read self-authentication data - LABEL DESKTOP - Сохранить считанные данные самоаутентификации - SelfAuthenticationView @@ -4232,6 +3430,16 @@ LABEL ANDROID IOS LABEL ANDROID IOS Просмотреть персональные данные + + Self-authentication + LABEL ANDROID IOS + + + + Hint + LABEL ANDROID IOS + Совет + SettingsView @@ -4287,63 +3495,16 @@ LABEL ANDROID IOS LABEL ANDROID IOS Изменить язык - - Screen orientation - LABEL ANDROID - Ориентация экрана - - - Landscape - LABEL ANDROID - Альбомная ориентация - - - Portrait - LABEL ANDROID - Книжная ориентация - Device name LABEL ANDROID IOS Имя устройства - - PIN pad mode - LABEL ANDROID IOS - Режим клавиатуры для ввода PIN-кода - Enter PIN on this device LABEL ANDROID IOS Ввести PIN-код на этом устройстве - - Save history - LABEL ANDROID IOS - Сохранить журнал - - - Save authentication history - LABEL ANDROID IOS - Сохранить журнал процессов аутентификации - - - History - LABEL ANDROID IOS ----------- -LABEL ALL_PLATFORMS - Журнал - - - View authentication history - LABEL ANDROID IOS - Показать журнал процессов аутентификации - - - Shuffle keypad buttons - LABEL ANDROID IOS - Случайное расположение кнопок клавиатуры - Randomize the order of the on screen keypad buttons LABEL ANDROID IOS @@ -4354,56 +3515,21 @@ LABEL ALL_PLATFORMS LABEL ANDROID IOS Анимация кнопок - - Visual feedback when pressing keypad buttons - LABEL ANDROID IOS - Анимация кнопок экранной клавиатуры при нажатии - - - CAN allowed mode - LABEL ANDROID IOS - Режим «Код CAN разрешен» - - - Support CAN allowed mode - LABEL ANDROID IOS - Поддержка режима «Код CAN разрешен» - - - Allow the id card to be used with only the CAN - LABEL ANDROID IOS - Поддержка использования идентификационной карты только с CAN - Skip rights page LABEL ANDROID IOS Пропустить страницу с разрешениями - - Do not show the rights page, when in can allowed mode - LABEL ANDROID IOS - Не показывать страницу с правами в режиме «Код CAN разрешен» - Testmode for the self-authentication LABEL ANDROID IOS Тестовый режим для самоаутентификации - - Use the test environment during a self-authentication - LABEL ANDROID IOS - Использование тестовой среды при самоаутентификации - Internal card simulator LABEL ANDROID IOS Внутренний симулятор карт - - Enable internal card simulator - LABEL ANDROID IOS - Включить внутренний симулятор карт - Developer mode LABEL ANDROID IOS @@ -4435,1459 +3561,604 @@ LABEL ALL_PLATFORMS Файл журнала, созданный 15 дней назад - Show requested rights on this device as well - LABEL ANDROID IOS - Показывать запрошенные права также и в этом устройстве - - - Show access rights - LABEL ANDROID IOS - Показывать права доступа - - - Manage paired devices and add new devices - LABEL ANDROID IOS - Управление сопряженными устройствами и добавление новых устройств - - - Manage pairings - LABEL ANDROID IOS - Управление сопряжениями - - - - SetupAssistantView - - Setup Assistant - LABEL DESKTOP - Помощник по настройке - - - Welcome to the AusweisApp2. Please take a few moments to set up the environment to your needs. Every decision you make can later be changed in the settings menu. - INFO DESKTOP Welcome message when starting the setup assistant. - Добро пожаловать в AusweisApp2. Уделите время для настройки среды приложения в соответствии с вашими требованиями. Любую настройку позднее можно изменить в меню настроек. - - - Do you want to automatically start the %1 after boot? - INFO DESKTOP Question if the App shall be started automatically after boot - Запустить %1 автоматически после запуска? - - - In order to successfully use the eID function, %1 has to be running. It is therefore advisable to activate the auto-start after system startup. - INFO DESKTOP Information text why autostart of the App is advisable - Для успешного использования функции идентификации необходимо запустить %1. Рекомендуется разрешить автозапуск при запуске системы. - - - The launch will add an icon to the menu bar. - INFO MACOS Additional information that macOS auto-start add a symbol to the menu bar - Запуск добавит значок в строку меню. - - - Auto-start Setting - LABEL DESKTOP - Настройка автозапуска - - - Do you want to save a history of performed authentications on your device? - INFO DESKTOP Question if the authentication history shall be stored. - Сохранить журнал выполненных процессов аутентификации на этом устройстве? - - - The history is only saved locally. You can use it to see on what date you transmitted which data to which party. After enabling the history you can view and delete the entries anytime. - INFO DESKTOP Information text which data is stored in the history record. - Журнал сохранен лишь локально. Вы в любое время можете просмотреть, какие данные когда и кому вы передавали. После активации этой функции вы в любое время можете просматривать и удалять записи. - - - History Setting - LABEL DESKTOP - Настройки журнала - - - Do you want to set up a card reader <u>now</u>? - INFO DESKTOP Question if the the user wants to setup any card readers now. - Создать устройство чтения карт <u>сейчас</u>? - - - In order to use the online identification feature on the computer, you need to set up a suitable smartphone or card reader before the first authentication process. - INFO DESKTOP Information text why a card reader is required to use the online - Чтобы использовать функцию онлайн-идентификации на компьютере, перед первым процессом аутентификации необходимо настроить подходящий смартфон или устройство чтения карт. - - - Card Readers - LABEL DESKTOP - Устройства чтения карт - - - You have completed the setup of the AusweisApp2 successfully. - INFO DESKTOP Success message after completing the setup assistant. - Вы успешно завершили настройку AusweisApp2. - - - Proceed to start page - INFO DESKTOP A11y button text to exit the setup assistant. - Далее к начальной странице - - - - SimulatorWorkflow - - Simulator - LABEL ANDROID IOS - Симулятор - - - Continue - LABEL ANDROID IOS - Продолжить - - - - SmartDeleteStartView - - Delete Smart-eID - LABEL ANDROID IOS - Удалить Smart-eID - - - Are you sure you want to delete the Smart-eID? - LABEL ANDROID IOS - Удалить Smart-eID? - - - Delete - LABEL ANDROID IOS - Удалить - - - Smart-eID - LABEL ANDROID IOS - Smart-eID - - - If you want to use that functionality again, you need to set up a new Smart-eID first. - LABEL ANDROID IOS - Если вы хотите в будущем снова использовать этот функционал, необходимо сначала создать новую Smart-eID. - - - Reset Smart-eID - LABEL ANDROID IOS - Сбросить Smart-eID - - - - SmartMainView - - Updating Smart-eID status... - LABEL ANDROID IOS - Обновление статуса Smart-eID… - - - Smart-eID not supported - LABEL ANDROID IOS - Smart-eID не поддерживается - - - Smart-eID invalid - LABEL ANDROID IOS - Электронная идентификационная карта Smart-eID недействительна - - - Smart-eID ready for use - LABEL ANDROID IOS - Электронная идентификационная карта Smart-eID готова к использованию - - - Smart-eID supported - LABEL ANDROID IOS - Электронная идентификационная карта Smart-eID не поддерживается - - - Please wait a moment. - LABEL ANDROID IOS - Подождите. - - - Unfortunately, this functionality is not supported by your device. - LABEL ANDROID IOS - К сожалению, данный функционал не поддерживается вашим устройством. - - - Your Smart-eID is in an invalid state. You need to set it up again to perform online identifications without your ID card. - LABEL ANDROID IOS - Ваша электронная идентификационная карта Smart-eID в недействительном состоянии. Необходимо создать ее заново, чтобы выполнять онлайн-идентификацию без идентификационной карты. - - - Your Smart-eID is set up and ready for use. You can now perform online identifications without your ID card if supported by the provider. - LABEL ANDROID IOS - Ваша электронная идентификационная карта Smart-eID создана и готова к использованию. Теперь вы можете выполнять онлайн-идентификацию без идентификационной карты, если эта функция поддерживается провайдером. - - - Set up a Smart-eID in order to perform online identifications without your ID card if supported by the provider. - LABEL ANDROID IOS - Создайте электронную идентификационную карту Smart-eID, чтобы выполнять онлайн-идентификацию без идентификационной карты, если эта функция поддерживается провайдером. - - - - SmartSettingsView - - Smart-eID - LABEL ANDROID IOS - Smart-eID - - - Check Smart-eID status - LABEL ANDROID IOS - Проверить статус Smart-eID - - - Check device compatibility and the current state of any present Smart-eID - LABEL ANDROID IOS - Проверить совместимость устройства и текущее состояние Smart-eID - - - Set up Smart-eID - LABEL ANDROID IOS - Создание Smart-eID - - - Set up Smart-eID on this device - LABEL ANDROID IOS - Создать Smart-eID на этом устройстве - - - Renew Smart-eID - LABEL ANDROID IOS - Обновить Smart-eID - - - Renew your Smart-eID with current data - LABEL ANDROID IOS - Обновить Smart-eID с актуальными данными - - - Delete Smart-eID - LABEL ANDROID IOS - Удалить Smart-eID - - - Remove Smart-eID data from your device - LABEL ANDROID IOS - Удалить данные Smart-eID с вашего устройства - - - Reset Smart-eID - LABEL ANDROID IOS - Сбросить Smart-eID - - - Remove Smart-eID data and provisioning from your device - LABEL ANDROID IOS - Удалить данные Smart-eID и подготовку с вашего устройства - - - - SmartSetupStartView - - Smart-eID - LABEL ANDROID IOS - Smart-eID - - - You are about to set up a Smart-eID on your device. In order to proceed, you need you ID card, your six-digit ID card PIN and an internet connection. - LABEL ANDROID IOS - Вы собираетесь создать Smart-eID на устройстве. Для этого требуется идентификационная карта, 6-значный PIN-код идентификационной карты и подключение к Интернету. - - - Set up Smart-eID - LABEL ANDROID IOS - Создание Smart-eID - - - - SmartUpdateStartView - - Smart-eID - LABEL ANDROID IOS - Smart-eID - - - You are about to renew your Smart-eID. In order to proceed, you need your ID card, your six-digit ID card PIN and an internet connection. - LABEL ANDROID IOS - Вы собираетесь обновить Smart-eID. Для этого требуется идентификационная карта, 6-значный PIN-код идентификационной карты и подключение к Интернету. - - - Please note that your current Smart-eID is invalidated during the process and will not be usable until the update process is completed. - LABEL ANDROID IOS - Внимание: во время этого процесса текущая электронная идентификационная карта Smart-eID становится недействительной, ее нельзя использовать до завершения процесса обновления. - - - Renew Smart-eID - LABEL ANDROID IOS - Обновить Smart-eID - - - - SmartView - - Smart-eID - LABEL ANDROID IOS - Smart-eID - - - Please wait a moment. - LABEL ANDROID IOS - Подождите. - - - You are about to delete the Smart-eID data that is currently stored on your device. - LABEL ANDROID IOS - Вы собираетесь удалить данные Smart-eID, сохраненные на вашем устройстве. - - - Delete Smart-eID - LABEL ANDROID IOS - Удалить Smart-eID - - - Deleting Smart-eID - LABEL ANDROID IOS - Удаление Smart-eID - - - You are about to delete the Smart-eID data from your device and also remove the Smart-eID provisioning. This can a be used for troubleshooting as well. - LABEL ANDROID IOS - Вы собираетесь удалить данные и подготовку для Smart-eID со своего устройства. Это также может потребоваться для устранения ошибок. - - - Reset Smart-eID - LABEL ANDROID IOS - Сбросить Smart-eID - - - Resetting Smart-eID - LABEL ANDROID IOS - Сброс Smart-eID - - - - SmartWorkflow - - Updating Smart-eID status... - LABEL ANDROID IOS - Обновление статуса Smart-eID… - - - Smart-eID unsupported - LABEL ANDROID IOS - Smart-eID не поддерживается - - - Smart-eID disallowed - LABEL ANDROID IOS - Электронная идентификационная карта Smart-eID не одобрена - - - Smart-eID - LABEL ANDROID IOS - Smart-eID - - - Smart-eID not ready - LABEL ANDROID IOS - Электронная идентификационная карта Smart-eID не готова - - - Your Smart-eID is ready for use, press "Continue" to proceed. - LABEL ANDROID IOS - Ваша электронная идентификационная карта Smart-eID готова к использованию, нажмите «Продолжить» для продолжения. - - - Please wait a moment. - LABEL ANDROID IOS - Подождите. - - - Unfortunately, Smart-eID is not supported by your device. - -To proceed use your ID card by selecting the NFC interface or choose "WiFi" to connect with another device as cardreader. - LABEL ANDROID IOS - К сожалению, ваше устройство не поддерживает Smart-eID. - -Для продолжения используйте вашу идентификационную карту, выберите интерфейс NFC или Wi-Fi, чтобы подключить другое устройство в качестве устройства чтения карт. - - - Unfortunately, using your Smart-eID for this authentication is not allowed by the provider. - -To proceed use your ID card by selecting the NFC interface or choose "WiFi" to connect with another device as cardreader. - LABEL ANDROID IOS - К сожалению, использование Smart-eID для данной аутентификации не разрешено провайдером. - -Для продолжения используйте вашу идентификационную карту, выберите интерфейс NFC или Wi-Fi, чтобы подключить другое устройство в качестве устройства чтения карт. - - - You have not yet set up a Smart-eID or it is no longer usable. - -To proceed use your ID card by selecting the NFC interface or choose "WiFi" to connect with another device as cardreader. If you want to set up a Smart-eID instead, please abort the current process and start the Smart-eID setup from the main screen. - LABEL ANDROID IOS - Вы еще не создали электронную идентификационную карту Smart-eID, или же она более не пригодна для использования. - -Для продолжения используйте вашу идентификационную карту, выберите интерфейс NFC или Wi-Fi, чтобы подключить другое устройство в качестве устройства чтения карт. Если вы хотите создать новую электронную идентификационную карту Smart-eID, отмените текущий процесс и запустите настройку Smart-eID на начальном экране. - - - Continue - Продолжить - - - You have not yet set up a Smart-eID or it is no longer usable. - -To proceed use your ID card by selecting the NFC interface. If you want to set up a Smart-eID instead, please abort the current process and start the Smart-eID setup from the main screen. - LABEL ANDROID IOS - Вы еще не создали электронную идентификационную карту Smart-eID, или же она более не пригодна для использования. - -Для продолжения используйте вашу идентификационную карту, выбрав интерфейс NFC. Если вы хотите создать новую электронную идентификационную карту Smart-eID, отмените текущий процесс и запустите настройку Smart-eID на начальном экране. - - - - StoreFeedbackPopup - - Are you satisfied with AusweisApp2? - INFO ANDROID Header of the app rating popup. - Вам нравится AusweisApp2? - - - We would be very grateful if you could leave a rating on the Google Play Store! - INFO ANDROID Content of the app rating popup. - Мы будем благодарны, если вы оцените приложение в Google Play Store! - - - Do not ask again - LABEL ANDROID - Не спрашивать снова - - - Rate app - LABEL ANDROID - Оценить приложение - - - - TabbedReaderView - - Card Readers - LABEL DESKTOP - Устройства чтения карт - - - Smartphone as card reader - Смартфон в качестве устройства чтения карт - - - USB card reader - USB-устройство чтения карт - - - - TechnologySwitch - - NFC - LABEL ANDROID IOS - NFC - - - SMART - LABEL ANDROID IOS - SMART - - - WiFi - LABEL ANDROID IOS - Wi-Fi - - - SIM - LABEL ANDROID IOS - SIM - - - - TitleBar - - Navigation bar - LABEL DESKTOP - Панель навигации - - - List - LABEL DESKTOP - Список - - - %1 elements - LABEL DESKTOP - %1 элемент (-а/-ов) - - - 1 element - LABEL DESKTOP - 1 элемент - - - Start page - LABEL DESKTOP - Начальная страница - - - Settings - Настройки - - - Open settings view of %1 - Открыть настройки %1 - - - Open online help in browser - Открыть онлайн-справку в браузере - - - Open online help of %1 in browser - Открыть онлайн-справку %1 в браузере - - - Notifications - Оповещения - - - Show in-app notifications of %1 - Показать внутренние оповещения в приложении %1 - - - - TitleBarAction - - Navigating to %1 in current context disabled - LABEL DESKTOP - Навигация (%1) в текущем контексте деактивирована - - - element %1 of %2 - LABEL DESKTOP - элемент %1 из %2 - - - Current context: %1 - LABEL DESKTOP - Текущий контекст: %1 - - - Navigate to %1 - LABEL DESKTOP - Перейти к %1 - - - - TitleBarNavigation - - Cancel - LABEL ANDROID IOS - Отмена - - - Back - LABEL ANDROID IOS - Назад - - - - TransportPinAssistantView - - Transport PIN - LABEL DESKTOP - Временный PIN-код - - - Do you want to change your (Transport) PIN now? - INFO DESKTOP Inquiry message if the five-digit Transport PIN should be changed to an ordinary PIN (now). - Изменить (временный) PIN-код сейчас? - - - If you have not already done so you have to change your five-digit Transport PIN to a six-digit PIN before you can use the online-ID function. - INFO DESKTOP Hint that a six-digit PIN is required to use the online identification feature of the ID card. - Если вы не сделали этого ранее, измените 5-значный временный PIN-код на 6-значный PIN-код перед использованием функции онлайн-идентификации. - - - - TransportPinReminderView - - Do you know your six-digit ID card PIN? - LABEL ANDROID IOS - Вы знаете 6-значный PIN-код идентификационной карты? - - - No - LABEL ANDROID IOS - Нет - - - Yes - LABEL ANDROID IOS - Да - - - Online identification with Transport PIN is not possible. The self-selected, six-digit ID card PIN is mandatory to use the eID function. - LABEL ANDROID IOS - Онлайн-идентификация с помощью временного PIN-кода невозможна. Для использования функции eID необходим 6-значный PIN-код идентификационной карты, который пользователь создает самостоятельно. - - - - TutorialFooter - - Fold in - LABEL ANDROID IOS - Свернуть - - - Quit tutorial - LABEL ANDROID IOS - Выход из руководства - - - - TutorialHow - - How can I use the AusweisApp2 on my iPhone? - INFO ANDROID IOS - Как использовать AusweisApp2 на iPhone? - - - How can I use the AusweisApp2 on my smartphone? - Как использовать AusweisApp2 на смартфоне? - - - Many iPhones (iPhone 7 and newer) can access the ID card via the built-in NFC interface. - INFO ANDROID IOS - Многие смартфоны iPhone (iPhone 7 и новее) предоставляют доступ к идентификационной карте через встроенный интерфейс NFC. - - - Many Android devices can access the ID card via the built-in NFC interface. - Многие устройства с ОС Android предоставляют доступ к идентификационной карте через встроенный интерфейс NFC. - - - You can test the capabilities of your device and your card by choosing "Check device and ID card" on the start page: - LABEL ANDROID IOS - В пункте меню «Проверить устройство и идентификационную карту» на начальной странице вы можете проверить функционал устройства и вашу карту: - - - You can also find a list of compatible NFC-capable smartphones here: - LABEL ANDROID IOS - Здесь можно также просмотреть список NFC-совместимых смартфонов. - - - The AusweisApp2 offers the following options to access your ID card: - LABEL ANDROID IOS - AusweisApp2 предоставляет следующие возможности доступа к идентификационной карте. - - - Direct connection via NFC chip tutorial - LABEL ANDROID IOS - Руководство по прямому подключению через NFC - - - Direct connection via NFC chip - LABEL ANDROID IOS - Прямое подключение через NFC - - - App on iPhone <b>with</b> NFC chip as card reader - LABEL ANDROID IOS - Приложение на iPhone <b>с</b> чипсетом NFC в качестве устройства чтения карт - - - App on Android smartphone <b>with</b> NFC chip as card reader - Приложение на смартфоне <b>с</b> ОС Android с чипсетом NFC в качестве устройства чтения карт - - - Smartphone as card reader tutorial - LABEL ANDROID IOS - Руководство для смартфона, используемого в качестве устройства чтения карт - - - Smartphone as card reader - LABEL ANDROID IOS - Смартфон в качестве устройства чтения карт - - - App on computer <b>without</b> NFC chip - LABEL ANDROID IOS - Приложение на компьютере <b>без</b> чипсета NFC - - - Smartphone <b>with</b> NFC chip as card reader - LABEL ANDROID IOS - Смартфон <b>с</b> чипсетом NFC в качестве устройства чтения карт - - - Smartphone as card reader mobile tutorial - LABEL ANDROID IOS - Мобильное руководство для смартфона, используемого в качестве устройства чтения карт - - - App on tablet or smartphone <b>without</b> NFC chip - LABEL ANDROID IOS - Приложение на планшете или смартфоне <b>без</b> чипсета NFC - - - Another tip - LABEL ANDROID IOS - Еще один совет - - - For lengthy forms, e.g. a BAföG application, we recommend you to use the AusweisApp2 on a computer... - LABEL ANDROID IOS - Для длинных форм, например заявок на ссуду для обучения от государства, рекомендуем использовать AusweisApp2 на компьютере… - - - Filling long forms is no fun on a smartphone! - LABEL ANDROID IOS - Заполнять длинные формы на смартфоне неудобно! - - - ... and to use a smartphone to communicate with your ID card. A USB reader is of course also an alternative. - LABEL ANDROID IOS - …и использовать смартфон в качестве устройства чтения карт для идентификационной карты. Альтернативой может быть USB-устройство чтения карт. - - - - TutorialImportant - - Please exchange your - LABEL ANDROID IOS - Замените ваш - - - Before you use the online ID function please change the - LABEL ANDROID IOS - Перед использованием функции онлайн-идентификации измените - - - five-digit - LABEL ANDROID IOS - 5-значный - - - Transport PIN - LABEL ANDROID IOS - временный PIN-код - - - with a - LABEL ANDROID IOS - на - - - six-digit PIN - LABEL ANDROID IOS - 6-значный PIN-код - - - before you use the online ID function! - LABEL ANDROID IOS - перед использованием функции онлайн-идентификации! - - - change! - LABEL ANDROID IOS - заменить! - - - The Transport PIN is sent to you by the Bundesdruckerei via mail. - LABEL ANDROID IOS - Временный PIN-код отправлен вам федеральной типографией по почте. - - - Select for this purpose the menu item "Change my (Transport) PIN" from the start page. Later you can also change your six-digit PIN here - LABEL ANDROID IOS - Для этого выберите пункт меню «Изменить (временный) PIN-код» на начальной странице. Позднее вы также сможете изменить здесь 6-значный PIN-код - - - ... or click this button to change your PIN right now: - LABEL ANDROID IOS - …или нажмите кнопку для изменения PIN-кода прямо сейчас. - - - Change my (Transport) PIN - LABEL ANDROID IOS - Изменить (временный) PIN-код - - - Please note: The Transport PIN can only be used for your first PIN change. If you have already set your six-digit PIN (e.g. while picking up your ID card) only the set PIN is valid. - LABEL ANDROID IOS - Указание. Временный PIN-код можно использовать только для первой замены PIN-кода. Если вы уже использовали 6-значный PIN-код (например, при получении идентификационной карты), действителен только он. - - - Open YouTube video - LABEL ANDROID IOS - Открыть видео на YouTube - - - Learn more about this in the YouTube video - LABEL ANDROID IOS - Узнайте больше в видео на YouTube - - - Let's go + Smart-eID LABEL ANDROID IOS - Вперед + Smart-eID - Do you still have questions? + Reset Smart-eID LABEL ANDROID IOS - Остались вопросы? + Сбросить Smart-eID - You can read our <b>FAQs</b> or <b>write</b> to us... + Reset Smart-eID data on your device LABEL ANDROID IOS - Прочитайте раздел «Часто задаваемые вопросы» или <b>напишите</b> нам… + - or + Show Transport PIN reminder, store feedback and close reminder dialogs. LABEL ANDROID IOS - или + - You can always access this tutorial again from the "Help" section in the menu bar. + Reset hideable dialogs LABEL ANDROID IOS - Вы всегда можете вызвать это руководство в разделе «Справка» в строке меню. + - If you cannot recall your six-digit PIN or cannot find your PIN letter, you may request a new PIN using the PIN Reset Service. + Show requested rights on this device as well LABEL ANDROID IOS - Если вы не можете вспомнить 6-значный PIN-код или найти письмо с PIN-кодом, запросите новый PIN-код через службу сброса PIN-кода. + Показывать запрошенные права также и в этом устройстве - - - TutorialReaderMethodFooter - Back + Manage pairings LABEL ANDROID IOS - Назад + Управление сопряжениями - - - TutorialReaderMethodNfc - Tutorial: NFC + Toggling will restart the %1 LABEL ANDROID IOS - Руководство: NFC + - Direct connection via NFC chip + Use system font LABEL ANDROID IOS - Прямое подключение через NFC + - App on iPhone <b>with</b> NFC chip as card reader - LABEL IOS - Приложение на iPhone <b>с</b> чипсетом NFC в качестве устройства чтения карт + Appearance + LABEL ANDROID IOS + - App on Android smartphone <b>with</b> NFC chip as card reader - LABEL ANDROID - Приложение на смартфоне <b>с</b> ОС Android с чипсетом NFC в качестве устройства чтения карт + Add and remove devices + LABEL ANDROID IOS + Управление сопряженными устройствами и добавление новых устройств - Click link on the website of the provider. + On-site reading LABEL ANDROID IOS - Нажмите ссылку на сайт провайдера. + Режим «Код CAN разрешен» - The App opens automatically. + Support CAN allowed mode for on-site reading LABEL ANDROID IOS - Приложение открывается автоматически. + Поддержка режима «Код CAN разрешен» - The AusweisApp2 will display who wants to access which data. + Allow test sample card usage LABEL ANDROID IOS - AusweisApp2 показывает, кто и какие данные запрашивает. + - Start the process with a click on: + Simulate a test sample card in authentications LABEL ANDROID IOS - Запустите процесс нажатием: + - Proceed to PIN entry + Visually highlight key presses on screen keypad LABEL ANDROID IOS - Далее к вводу PIN-кода + + + + SetupAutostartView - ... and place the top of the iPhone onto the ID card. - LABEL IOS - …и расположите верхнюю часть iPhone на идентификационной карте. + Do you want to automatically start the %1 after boot? + INFO DESKTOP Question if the App shall be started automatically after boot + Запустить %1 автоматически после запуска? - ... and place the ID card flat onto the NFC interface. - LABEL ANDROID - …и расположите идентификационную карту на интерфейсе NFC. + In order to successfully use the eID function, %1 has to be running. It is therefore advisable to activate the auto-start after system startup. + INFO DESKTOP Information text why autostart of the App is advisable + Для успешного использования функции идентификации необходимо запустить %1. Рекомендуется разрешить автозапуск при запуске системы. - Do not move device or ID card! - LABEL ANDROID IOS - Не смещайте устройство или идентификационную карту! + The launch will add an icon to the menu bar. + INFO MACOS Additional information that macOS auto-start adds a symbol to the menu bar + Запуск добавит значок в строку меню. - The correct position is specific for your device. If a position does not work try a different one. The AusweisApp2 shows different common positions. - LABEL ANDROID - Правильное положение зависит от вашего устройства. Если в текущем положении функция не работает, попробуйте изменить положение. AusweisApp2 показывает различные подходящие положения. + Autostart Settings + LABEL DESKTOP + - If your device is unable to detect your ID card try to check the device capabilities by clicking on "Check device and ID card" on the start page. - LABEL ANDROID - Если ваше устройство не обнаруживает идентификационную карту, проверьте возможности устройства, нажав «Проверить устройство и идентификационную карту» на начальной странице. + The launch will add a tray icon to the notification area. + INFO WINDOWS Additional information that Windows auto-start adds a symbol to the notification area. + + + + SimulatorWorkflow - You can find more information on compatible devices on our %1mobile device list%2. + Simulator LABEL ANDROID IOS - Подробную информацию о совместимых устройствах см. в нашем %1списке мобильных устройств%2. + Симулятор - Enter - LABEL ANDROID IOS This is the first of three lines "Enter" "six-digit PIN" "now!" and should be translated accoording to the third line. - Ввести + Continue + LABEL ANDROID IOS + Продолжить + + + SmartDeleteBaseView - six-digit PIN + Smart-eID LABEL ANDROID IOS - 6-значный PIN-код + Smart-eID - now! - LABEL ANDROID IOS This is the third of three lines "Enter" "six-digit PIN" "now!" and should be translated accoording to the first line. - сейчас! + Please wait a moment. + LABEL ANDROID IOS + Подождите. - This is only possible if you have exchanged the five-digit Transport PIN with a six-digit PIN beforehand. + Send log LABEL ANDROID IOS - Возможно, только если 5-значный временный PIN-код уже изменен на 6-значный PIN-код. + Отправить файл журнала - Open YouTube video + If you want to use that functionality again, you need to set up a new Smart-eID first. LABEL ANDROID IOS - Открыть видео на YouTube + Если вы хотите в будущем снова использовать этот функционал, необходимо сначала создать новую Smart-eID. - You can also watch this YouTube video explaining the process. + Reset Smart-eID LABEL ANDROID IOS - Вы также можете просмотреть видео с описанием процесса на YouTube. + Сбросить Smart-eID - TutorialReaderMethodSacDesktop + SmartDeleteView - Tutorial: Smartphone as card reader + Delete Smart-eID LABEL ANDROID IOS - Руководство: Смартфон в качестве устройства чтения карт + Удалить Smart-eID - Smartphone as card reader + You have successfuly deleted your Smart-eID. LABEL ANDROID IOS - Смартфон в качестве устройства чтения карт + - App on computer <b>without</b> NFC chip + The Smart-eID could not be successfully deleted from your device. LABEL ANDROID IOS - Приложение на компьютере <b>без</b> чипсета NFC + - Smartphone <b>with</b> NFC chip as card reader + Back to start page LABEL ANDROID IOS - Смартфон <b>с</b> чипсетом NFC в качестве устройства чтения карт + - Install AusweisApp2 on both your computer <b>and</b> your smartphone with NFC capability. + You are about to delete the Smart-eID data that is currently stored on your device. LABEL ANDROID IOS - Установите AusweisApp2 на компьютер <b>и</b> смартфон с поддержкой NFC. + Вы собираетесь удалить данные Smart-eID, сохраненные на вашем устройстве. - Both devices have to be connected to the same WiFi network + Are you sure you want to delete the Smart-eID? LABEL ANDROID IOS - Оба устройства должны быть подключены к одной сети Wi-Fi. + Удалить Smart-eID? - Now choose "Card reader" in the AusweisApp2 on your smartphone... + Delete LABEL ANDROID IOS - Далее выберите «Устройство чтения карт» в AusweisApp2 на смартфоне… + Удалить - Now + Deleting Smart-eID LABEL ANDROID IOS - сейчас + Удаление Smart-eID - Pair device + Delete the Smart-eID LABEL ANDROID IOS - Выполнить сопряжение устройства + + + + SmartMainView - Pairing code + Updating Smart-eID status... LABEL ANDROID IOS - Код сопряжения + Обновление статуса Smart-eID… - appears! + Smart-eID ready for use LABEL ANDROID IOS - отображается! - - - On the first use of the Smartphone as card reader (SaC), iOS will asks for your permission to access the local network. This permission is required in order find and connect to your SaC. After the first request you can always access the permission in the iOS settings for this app. - LABEL IOS - При первом использовании смартфона в качестве устройства чтения карт (SaC) iOS запрашивает разрешение на доступ к локальной сети. Разрешение необходимо, чтобы обнаружить ваш SaC и подключиться к нему. После первого запроса вы всегда можете отменить разрешение в настройках iOS для этого приложения. + Электронная идентификационная карта Smart-eID готова к использованию - Start the App now on your computer and enter the settings. + Please wait a moment. LABEL ANDROID IOS - Откройте приложение на компьютере и перейдите в раздел настроек. + Подождите. - Select the <b>Smartphone as card reader</b> tab. + Your Smart-eID is set up and ready for use. You can now perform online identifications without your ID card if supported by the provider. LABEL ANDROID IOS - Выберите вкладку «Смартфон в качестве устройства чтения карт». + Ваша электронная идентификационная карта Smart-eID создана и готова к использованию. Теперь вы можете выполнять онлайн-идентификацию без идентификационной карты, если эта функция поддерживается провайдером. - Select smartphone from list + Check here if your device is suitable to set up a Smart-eID. LABEL ANDROID IOS - Выбрать смартфон из списка + Проверьте здесь, подходит ли ваше устройство для создания Smart-eID. - Enter pairing code next. + Start check LABEL ANDROID IOS - Далее введите код сопряжения. + Запуск проверки - Click link on the website of the provider. + With the Smart-eID you may also use the online identification function without the ID card. LABEL ANDROID IOS - Нажмите ссылку на сайт провайдера. + + + + SmartResetView - The App opens automatically. + Reset Smart-eID LABEL ANDROID IOS - Приложение открывается автоматически. + Сбросить Smart-eID - The AusweisApp2 will display who wants to access which data. + You have successfully reset your Smart-eID. LABEL ANDROID IOS - AusweisApp2 показывает, кто и какие данные запрашивает. + - Start the process with a click on: + You are about to reset your Smart-eID data. This can also be used for troubleshooting as well. LABEL ANDROID IOS - Запустите процесс нажатием: + - Proceed to PIN entry + Are you sure you want to reset the Smart-eID? LABEL ANDROID IOS - Далее к вводу PIN-кода + - ... and place the ID card onto the NFC interface. + Reset LABEL ANDROID IOS - …и расположите идентификационную карту на интерфейсе NFC. + - Do not move device or ID card! + Resetting Smart-eID LABEL ANDROID IOS - Не смещайте устройство или идентификационную карту! + Сброс Smart-eID - The correct position is specific for your device. If a position does not work try a different one. The AusweisApp2 shows different common positions. + Reset the Smart-eID LABEL ANDROID IOS - Правильное положение зависит от вашего устройства. Если в текущем положении функция не работает, попробуйте изменить положение. AusweisApp2 показывает различные подходящие положения. + + + + SmartSettingsView - If your device is unable to detect your ID card try to check the device capabilities by clicking on "Check device and ID card" on the start page. + Smart-eID LABEL ANDROID IOS - Если ваше устройство не обнаруживает идентификационную карту, проверьте возможности устройства, нажав «Проверить устройство и идентификационную карту» на начальной странице. + Smart-eID - You can find more information on compatible devices on our %1mobile device list%2. + Renew Smart-eID LABEL ANDROID IOS - Подробную информацию о совместимых устройствах см. в нашем %1списке мобильных устройств%2. - - - Enter - LABEL ANDROID IOS This is the first of three lines "Enter" "six-digit PIN" "now!" and should be translated according to the third line. - Ввести + Обновить Smart-eID - six-digit PIN + Renew your Smart-eID with current data LABEL ANDROID IOS - 6-значный PIN-код - - - now! - LABEL ANDROID IOS This is the third of three lines "Enter" "six-digit PIN" "now!" and should be translated according to the first line. - сейчас! + Обновить Smart-eID с актуальными данными - This is only possible if you have exchanged the five-digit Transport PIN with a six-digit PIN beforehand. + Delete Smart-eID LABEL ANDROID IOS - Возможно, только если 5-значный временный PIN-код уже изменен на 6-значный PIN-код. + Удалить Smart-eID - Open YouTube video + Delete Smart-eID data from your device LABEL ANDROID IOS - Открыть видео на YouTube + - You can also watch this YouTube video explaining the process. + Try Smart-eID LABEL ANDROID IOS - Вы также можете просмотреть видео с описанием процесса на YouTube. + - - - TutorialReaderMethodSacMobile - Tutorial: Smartphone as card reader + Show Smart-eID data LABEL ANDROID IOS - Руководство: Смартфон в качестве устройства чтения карт + - App on tablet or smartphone <b>without</b> NFC chip + Change Smart-eID PIN LABEL ANDROID IOS - Приложение на планшете или смартфоне <b>без</b> чипсета NFC + Изменить PIN-код для Smart-eID - Smartphone <b>with</b> NFC chip as card reader + Change the chosen Smart-eID PIN LABEL ANDROID IOS - Смартфон <b>с</b> чипсетом NFC в качестве устройства чтения карт + + + + SmartSetupStartView - Install AusweisApp2 on both your device without NFC <b>and</b> your smartphone with NFC capability. + Smart-eID LABEL ANDROID IOS - Установите AusweisApp2 на устройство без NFC <b>и</b> смартфон с поддержкой NFC. + Smart-eID - Both devices have to be connected to the same WiFi network + You are about to set up a Smart-eID on your device. In order to proceed, you need you ID card, your six-digit ID card PIN and an internet connection. LABEL ANDROID IOS - Оба устройства должны быть подключены к одной сети Wi-Fi. + Вы собираетесь создать Smart-eID на устройстве. Для этого требуется идентификационная карта, 6-значный PIN-код идентификационной карты и подключение к Интернету. - Now choose "Card reader" in the AusweisApp2 on your smartphone... + Set up Smart-eID LABEL ANDROID IOS - Далее выберите «Устройство чтения карт» в AusweisApp2 на смартфоне… + Создание Smart-eID - Now + Smart-eID setup LABEL ANDROID IOS - сейчас + + + + SmartUpdateStartView - Pair device + You are about to renew your Smart-eID. In order to proceed, you need your ID card, your six-digit ID card PIN and an internet connection. LABEL ANDROID IOS - Выполнить сопряжение устройства + Вы собираетесь обновить Smart-eID. Для этого требуется идентификационная карта, 6-значный PIN-код идентификационной карты и подключение к Интернету. - Pairing code + Please note that your current Smart-eID is invalidated during the process and will not be usable until the update process is completed. LABEL ANDROID IOS - Код сопряжения + Внимание: во время этого процесса текущая электронная идентификационная карта Smart-eID становится недействительной, ее нельзя использовать до завершения процесса обновления. - appears! + Renew Smart-eID LABEL ANDROID IOS - отображается! - - - On the first use of the Smartphone as card reader (SaC), iOS will asks for your permission to access the local network. This permission is required in order find and connect to your SaC. After the first request you can always access the permission in the iOS settings for this app. - LABEL IOS - При первом использовании смартфона в качестве устройства чтения карт (SaC) iOS запрашивает разрешение на доступ к локальной сети. Разрешение необходимо, чтобы обнаружить ваш SaC и подключиться к нему. После первого запроса вы всегда можете отменить разрешение в настройках iOS для этого приложения. - - - Now open the AusweisApp2 on your device <b>without</b> NFC and select <b>Manage pairings</b>. - LABEL IOS - Теперь откройте приложение AusweisApp2 в своем устройстве <b>без</b> NFC и выберите меню «Управление сопряжениями». - - - Now open the AusweisApp2 on your device <b>without</b> NFC and select <b>Smartphone as card reader</b>. - LABEL ANDROID - Откройте AusweisApp2 на вашем устройстве <b>без</b> NFC и выберите «Смартфон в качестве устройства чтения карт». + Обновить Smart-eID - Now select <b>Settings</b>. + Renew the Smart-eID LABEL ANDROID IOS - Далее выберите «Настройки». + - Choose smartphone from list + Smart-eID renewal LABEL ANDROID IOS - Выбрать смартфон из списка + + + + SmartView - Enter pairing code next. + Smart-eID LABEL ANDROID IOS - Далее введите код сопряжения. + Smart-eID - Click link on the website of the provider on the device <b>without</b> NFC. + Check Smart-eID LABEL ANDROID IOS - Нажмите ссылку на сайт провайдера на устройстве <b>без</b> NFC. + Проверить Smart-eID + + + SmartWorkflow - The App opens automatically. + Updating Smart-eID status... LABEL ANDROID IOS - Приложение открывается автоматически. + Обновление статуса Smart-eID… - The AusweisApp2 will display who wants to access which data. + Smart-eID unsupported LABEL ANDROID IOS - AusweisApp2 показывает, кто и какие данные запрашивает. + Smart-eID не поддерживается - Start the process with a click on: + Smart-eID disallowed LABEL ANDROID IOS - Запустите процесс нажатием: + Электронная идентификационная карта Smart-eID не одобрена - Proceed to PIN entry + Smart-eID LABEL ANDROID IOS - Далее к вводу PIN-кода + Smart-eID - Tap on WiFi + Smart-eID not ready LABEL ANDROID IOS - Нажмите Wi-Fi + Электронная идентификационная карта Smart-eID не готова - ... and place the ID card onto the NFC interface. + Your Smart-eID is ready for use, press "Continue" to proceed. LABEL ANDROID IOS - …и расположите идентификационную карту на интерфейсе NFC. + Ваша электронная идентификационная карта Smart-eID готова к использованию, нажмите «Продолжить» для продолжения. - Do not move device or ID card! + Please wait a moment. LABEL ANDROID IOS - Не смещайте устройство или идентификационную карту! + Подождите. - The correct position is specific for your device. If a position does not work try a different one. The AusweisApp2 shows different common positions. + Unfortunately, Smart-eID is not supported by your device. + +To proceed use your ID card by selecting the NFC interface or choose "WiFi" to connect with another device as cardreader. LABEL ANDROID IOS - Правильное положение зависит от вашего устройства. Если в текущем положении функция не работает, попробуйте изменить положение. AusweisApp2 показывает различные подходящие положения. + К сожалению, ваше устройство не поддерживает Smart-eID. + +Для продолжения используйте вашу идентификационную карту, выберите интерфейс NFC или Wi-Fi, чтобы подключить другое устройство в качестве устройства чтения карт. - If your device is unable to detect your ID card try to check the device capabilities by clicking on "Check device and ID card" on the start page. + Unfortunately, using your Smart-eID for this authentication is not allowed by the provider. + +To proceed use your ID card by selecting the NFC interface or choose "WiFi" to connect with another device as cardreader. LABEL ANDROID IOS - Если ваше устройство не обнаруживает идентификационную карту, проверьте возможности устройства, нажав «Проверить устройство и идентификационную карту» на начальной странице. + К сожалению, использование Smart-eID для данной аутентификации не разрешено провайдером. + +Для продолжения используйте вашу идентификационную карту, выберите интерфейс NFC или Wi-Fi, чтобы подключить другое устройство в качестве устройства чтения карт. - You can find more information on compatible devices on our %1mobile device list%2. + You have not yet set up a Smart-eID or it is no longer usable. + +To proceed use your ID card by selecting the NFC interface or choose "WiFi" to connect with another device as cardreader. If you want to set up a Smart-eID instead, please abort the current process and start the Smart-eID setup from the main screen. LABEL ANDROID IOS - Подробную информацию о совместимых устройствах см. в нашем %1списке мобильных устройств%2. + Вы еще не создали электронную идентификационную карту Smart-eID, или же она более не пригодна для использования. + +Для продолжения используйте вашу идентификационную карту, выберите интерфейс NFC или Wi-Fi, чтобы подключить другое устройство в качестве устройства чтения карт. Если вы хотите создать новую электронную идентификационную карту Smart-eID, отмените текущий процесс и запустите настройку Smart-eID на начальном экране. - Enter - LABEL ANDROID IOS This is the first of three lines "Enter" "six-digit PIN" "now!" and should be translated according to the third line. - Ввести + Continue + Продолжить - six-digit PIN + You have not yet set up a Smart-eID or it is no longer usable. + +To proceed use your ID card by selecting the NFC interface. If you want to set up a Smart-eID instead, please abort the current process and start the Smart-eID setup from the main screen. LABEL ANDROID IOS - 6-значный PIN-код - - - now! - LABEL ANDROID IOS This is the third of three lines "Enter" "six-digit PIN" "now!" and should be translated according to the first line. - сейчас! + Вы еще не создали электронную идентификационную карту Smart-eID, или же она более не пригодна для использования. + +Для продолжения используйте вашу идентификационную карту, выбрав интерфейс NFC. Если вы хотите создать новую электронную идентификационную карту Smart-eID, отмените текущий процесс и запустите настройку Smart-eID на начальном экране. - This is only possible if you have exchanged the five-digit Transport PIN with a six-digit PIN beforehand. - LABEL ANDROID IOS - Возможно, только если 5-значный временный PIN-код уже изменен на 6-значный PIN-код. + The device "%1" wants to access your Smart-eID. + INFO ANDROID IOS %1 will be replaced with the name of the device. + - TutorialView - - Tutorial - LABEL ANDROID IOS - Руководство - + StoreFeedbackPopup - What? - LABEL ANDROID IOS - Что? + Are you satisfied with %1? + INFO ANDROID Header of the app rating popup. + Вам нравится %1? - Where? - LABEL ANDROID IOS - Где? + We would be very grateful if you could leave a rating on the Google Play Store! + INFO ANDROID Content of the app rating popup. + Мы будем благодарны, если вы оцените приложение в Google Play Store! - How? - LABEL ANDROID IOS - Как? + Do not ask again + LABEL ANDROID + Не спрашивать снова - Important! - LABEL ANDROID IOS - Важно! + Rate app + LABEL ANDROID + Оценить приложение - TutorialWhat - - What is the online ID function? - LABEL ANDROID IOS - Что такое функция онлайн-идентификации? - - - You can use it to authenticate yourself in the internet - LABEL ANDROID IOS - Вы можете использовать ее для самоаутентификации в сети Интернет - - - and also to deal with administrative paperwork and business matters electronically! - LABEL ANDROID IOS - и таким образом решать административные и деловые вопросы в электронном виде! - + TabbedReaderView - Alright, but is it secure? - LABEL ANDROID IOS - Хорошо, а это безопасно? + Card Readers + LABEL DESKTOP + Устройства чтения карт - Of course, because we use a so called - LABEL ANDROID IOS - Конечно, потому что мы используем так называемую + Smartphone as card reader + Смартфон в качестве устройства чтения карт - Mutual authentication - LABEL ANDROID IOS - обоюдную аутентификацию: + USB card reader + USB-устройство чтения карт + + + TechnologySwitch - ... it establishes a secure connection between ID card and provider. + NFC LABEL ANDROID IOS - … она обеспечивает безопасное соединение идентификационной карты и провайдера. + NFC - On every authentication you get displayed <b>who</b> wants to access <b>which</b> data + SMART LABEL ANDROID IOS - При каждой аутентификации отображается, <b>кто</b> и к <b>каким</b> данным запрашивает доступ. + SMART - and you consent to the request with your six-digit PIN. + WiFi LABEL ANDROID IOS - и вы подтверждаете запрос с помощью 6-значного PIN-кода. + Wi-Fi - ... is the provider authorized for this? + SIM LABEL ANDROID IOS - … и авторизован ли провайдер? + SIM + + + TitleBar - The provider needs an authorization of the Federal Office of Administration. - LABEL ANDROID IOS - Провайдеру требуется разрешение Федерального административного ведомства. + Start page + LABEL DESKTOP + Начальная страница - Certificate - LABEL ANDROID IOS - Сертификат + Settings + Настройки - Every time both participants authenticate each other... - LABEL ANDROID IOS - Каждый раз, когда оба участника идентифицируют друг друга… + Open settings view of %1 + Открыть настройки %1 - ... and therefore your data is protected and securely transferred. - LABEL ANDROID IOS - …и поэтому ваши данные защищены и передаются безопасным путем. + Notifications + Оповещения - You can also watch a video on YouTube on this topic - LABEL ANDROID IOS - Вы также можете просмотреть видео по этой теме на YouTube + Show in-app notifications of %1 + Показать внутренние оповещения в приложении %1 - Open YouTube video - LABEL ANDROID IOS - Открыть видео на YouTube + Title bar + LABEL DESKTOP + - TutorialWhere - - Where can I use the online ID function? - LABEL ANDROID IOS - Где можно использовать функцию онлайн-идентификации? - + TitleBarNavigation - On every website of a provider where you see this icon: + Cancel LABEL ANDROID IOS - На любом сайте провайдера, где есть такой символ: + Отмена - By the way, you can find many services directly in the AusweisApp2 <b>provider list</b>. + Back LABEL ANDROID IOS - Кстати, многие службы перечислены в <b>списке провайдеров</b> AusweisApp2. + Назад + + + TransportPinReminderView - The <b>integrated self-authentication</b> is a special service to view the data saved on your ID card. + Do you know your six-digit ID card PIN? LABEL ANDROID IOS - <b>Интегрированная самоаутентификация</b> — это специальная служба для просмотра данных, сохраненных на идентификационной карте. + Вы знаете 6-значный PIN-код идентификационной карты? - And this is how it works + No LABEL ANDROID IOS - Как это работает + Нет - The AusweisApp2 will always display <b>who</b> wants to access <b>which</b> of your data. + Yes LABEL ANDROID IOS - AusweisApp2 всегда показывает, <b>кто</b> и <b>какие</b> данные запрашивает. + Да - To allow the shown service access to the requested data click "Proceed to PIN entry" + Online identification with Transport PIN is not possible. The self-selected, six-digit ID card PIN is mandatory to use the eID function. LABEL ANDROID IOS - Чтобы разрешить отображаемой службе доступ к запрашиваемым данным, нажмите «Далее к вводу PIN-кода». - - - Now lay down your ID card and hold the top of your iPhone to the ID card. - LABEL IOS - Теперь положите идентификационную карту перед собой и удерживайте верхний край iPhone на идентификационной карте. - - - Now place your ID card on the NFC-interface of your smartphone. - LABEL ANDROID - Теперь расположите идентификационную карту на интерфейсе NFC вашего смартфона. - - - The correct position is specific for your device. If a position does not work try a different one. The AusweisApp2 shows different common positions. If your device is unable to detect your ID card try to check the device capabilities by clicking on "Check device and ID card" on the start page. - LABEL ANDROID - Правильное положение зависит от вашего устройства. Если в текущем положении функция не работает, попробуйте изменить положение. AusweisApp2 показывает различные подходящие положения. Если ваше устройство не обнаруживает идентификационную карту, проверьте возможности устройства, нажав «Проверить устройство и идентификационную карту» на начальной странице. - - - Do not move your iPhone during the procedure! - LABEL IOS - Не перемещайте iPhone во время процедуры! - - - Do not move your device during the procedure! - LABEL ANDROID - Не перемещайте устройство во время процедуры! - - - Enter - LABEL ANDROID IOS This is the first of three lines "Enter" "six-digit PIN" "now!" and should be translated according to the third line. - Ввести + Онлайн-идентификация с помощью временного PIN-кода невозможна. Для использования функции eID необходим 6-значный PIN-код идентификационной карты, который пользователь создает самостоятельно. - six-digit PIN + To set up a Smart-eID you also need to have assigned a six-digit PIN beforehand. LABEL ANDROID IOS - 6-значный PIN-код - - - now! - LABEL ANDROID IOS This is the third of three lines "Enter" "six-digit PIN" "now!" and should be translated according to the first line. - сейчас! + @@ -6013,24 +4284,6 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u Ссылка для контрольной суммы: - - Utils - - today - LABEL ALL_PLATFORMS - сегодня - - - yesterday - LABEL ALL_PLATFORMS - вчера - - - dd.MM.yyyy - LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString - dd.MM.yyyy - - VersionInformation @@ -6077,9 +4330,9 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u Отправить данные устройства? - Would you like to help us to improve the AusweisApp2? + Would you like to help us to improve the %1? INFO ANDROID IOS Request to the user if the device information should be shared for statistics (Whitelist) - Part of content text - Хотите помочь нам сделать AusweisApp2 лучше? + Хотите помочь нам сделать %1 лучше? Supplying your device characteristics helps us to gather reliable information about the compatibility of your device. @@ -6111,6 +4364,14 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u Отправить + + WorkflowInfoList + + The device "%1" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. + INFO ANDROID IOS The paired smartphone was removed since it did not respond to connection attempts. It needs to be paired again before using it. + Сопряжение устройства "%1" не было выполнено, поскольку оно не отвечало на попытки соединения. Снова выполните сопряжение устройства для его использования в качестве устройства чтения карт. + + governikus::AccessRoleAndRightsUtil @@ -6563,9 +4824,9 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u Брандмауэры сторонних провайдеров - Outgoing AusweisApp2 rule + Outgoing %1 rule LABEL DESKTOP - Исходящее правило AusweisApp2 + Исходящее правило %1 Exists: %1 @@ -6573,9 +4834,9 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u Существует: %1 - Incoming AusweisApp2 rule + Incoming %1 rule LABEL DESKTOP - Входящее правило AusweisApp2 + Входящее правило %1 Windows firewall rules @@ -6929,7 +5190,7 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u Программа получила ошибку с сервера. - Hash of TLS certificate not in certificate description (issuer: %1). This indicates a misconfiguration or manipulation of the certificate. Please check that your antivirus-software and firewalls are not interfering with TLS traffic. + Hash of TLS certificate not in certificate description (issuer: %1). This indicates a misconfiguration or manipulation of the certificate. Please check that your antivirus software and firewall are not interfering with TLS traffic. ERROR ALL_PLATFORMS The TLS certificate was not folded with the Authorization Certificate, thus violating the security requirements. Might also be caused by a firewall and/or the antivirus software. В описании сертификата отсутствует хэш сертификата TLS (издатель: %1). Это указывает на неправильную конфигурацию или манипуляции с сертификатом. Убедитесь в том, что антивирусное программное обеспечение и брандмауэр не препятствуют трафику TLS. @@ -6948,11 +5209,6 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u ERROR ALL_PLATFORMS The device does not support the Smart-eID function Устройство не поддерживает Smart-eID. - - The preparation of the Smart-eID Applet failed. - ERROR ANDROID The preparation of the Smart-eID Applet failed - Сбой подготовки приложения Smart-eID. - Initialization of Personalization of Smart-eID failed. ERROR ALL_PLATFORMS Initialization of Personalization failed @@ -7069,9 +5325,9 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u Произошла ошибка при обмене данными с идентификационной картой. Убедитесь в том, что идентификационная карта правильно расположена на устройстве чтения карт, и повторите попытку. - A protocol error occurred. Please make sure that your ID card is placed correctly on the card reader and try again. If the problem occurs again, please contact our support at %1AusweisApp2 Support%2. - ERROR ALL_PLATFORMS Communication with the card failed due to the specification of the TR (Technische Richtlinie). The protocol was faulty or invalid values were requested/received, - Произошла ошибка протокола. Убедитесь в том, что идентификационная карта правильно расположена на устройстве чтения карт, и повторите попытку. Если проблема сохраняется, свяжитесь со службой поддержки %1AusweisApp2 Support%2. + A protocol error occurred. Please make sure that your ID card is placed correctly on the card reader and try again. If the problem occurs again, please contact our support at %1. + ERROR ALL_PLATFORMS Communication with the card failed due to the specification of the TR (Technische Richtlinie). The protocol was faulty or invalid values were requested/received. %1 is a html link to the support. + Произошла ошибка протокола. Убедитесь в том, что идентификационная карта правильно расположена на устройстве чтения карт, и повторите попытку. Если проблема сохраняется, свяжитесь со службой поддержки %1. The given PIN is not correct. @@ -7118,11 +5374,6 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u ERROR ALL_PLATFORMS The validity verification of the card failed. Сбой проверки действия карты. - - The Smart-eID is invalid. This might have been caused by entering the wrong Smart-eID PIN three times. - ERROR ALL_PLATFORMS The existing Smart-eID was invalidated. - Электронная идентификационная карта Smart-eID недействительна. Причиной может быть неправильный ввод PIN-кода для Smart-eID трижды. - The smartphone as card reader (SaC) connection was aborted. ERROR ALL_PLATFORMS The connection to the smartphone card reader (SaK) was lost. @@ -7134,9 +5385,9 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u Ошибка запроса соединения со смартфоном, используемым в качестве устройства чтения карт (SaC). - Your smartphone as card reader (SaC) version is incompatible with the local version. Please install the latest AusweisApp2 version on both your smartphone and your computer. + Your smartphone as card reader (SaC) version is incompatible with the local version. Please install the latest %1 version on both your smartphone and your computer. ERROR ALL_PLATFORMS The requested connection to the smartphone card reader (SaK) was invalid (API mismatch). - Версия смартфона, используемого в качестве устройства чтения карт (SaC), несовместима с локальной версией. Установите последнюю версию AusweisApp2 на смартфон и компьютер. + Версия смартфона, используемого в качестве устройства чтения карт (SaC), несовместима с локальной версией. Установите последнюю версию %1 на смартфон и компьютер. A timeout occurred while trying to establish a connection to the smartphone as card reader (SaC). @@ -7183,26 +5434,55 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u ERROR ALL_PLATFORMS Starting the update failed. Не удалось запустить новый процесс обновления. + + You have reached the allowed amount of Smart-eID setups for the current period. You may set up another Smart-eID with your ID card on %1. + ERROR ALL_PLATFORMS Personalization of Smart-eID is not allowed, no remaining attempts are left. + Достигнуто максимально допустимое количество попыток создания Smart-eID для текущего периода. Вы можете создать другую электронную идентификационную карту Smart-eID на основе своей идентификационной карты (%1). + + + Failed to get the ServiceInformation of the Smart-eID. + ERROR ALL_PLATFORMS Failed to get the ServiceInformation of the Smart-eID + + + + The authentication to the personalization service failed. + ERROR ALL_PLATFORMS No sessionID, required for a personalization, was received + + + + The Smart-eID is no longer ready for use. This might have been caused by entering the wrong Smart-eID PIN three times. You may personalize a new Smart-eID to resolve the issue. + ERROR ALL_PLATFORMS The existing Smart-eID was invalidated. + + + + The preparation of the Smart-eID failed. + ERROR ANDROID The preparation of the Smart-eID Applet failed + + The program did not receive a StartPaosResponse message from the server. ERROR_MASKED ALL_PLATFORMS The PAOS message StartPaosResponse was not received. Программа не получила сообщение StartPaosResponse с сервера. - - - governikus::HistoryModel - No data stored on your ID card was read, only confirmed whether you are in possession of a valid ID card. - LABEL ALL_PLATFORMS - Данные, хранящиеся на вашей идентификационной карте, не были считаны; было только подтверждено, что у вас есть действительная идентификационная карта. + The server could not process the client request. + ERROR_MASKED ALL_PLATFORMS + - - - governikus::HistoryModelSearchFilter - dd.MM.yyyy - LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString - dd.MM.yyyy + The service encountered an internal error while processing a request. + ERROR ALL_PLATFORMS A server has responded with an HTTP error code 5xx. + + + + The service reported an error while processing a client request. + ERROR ALL_PLATFORMS A server has responded with an HTTP error code 4xx. + + + + %1 Support + LABEL ALL_PLATFORMS Link text to the app support. %1 is the app name. + %1 Support @@ -7325,11 +5605,6 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u INFO ALL_PLATFORMS The wrong Transport PIN was entered on the first attempt. Вы ввели неправильный 5-значный временный PIN-код. Осталось две попытки ввода временного PIN-кода. - - Please note that you may use the five-digit Transport PIN only once to change to a six-digit ID card PIN. If you already set a six-digit ID card PIN, the five-digit Transport PIN is no longer valid. - INFO ALL_PLATFORMS - Внимание: вы можете использовать 5-значный временный PIN-код только один раз — для смены 6-значного PIN-кода. Если вы уже установили 6-значный PIN-код, 5-значный временный PIN-код больше не действует. - You have entered an incorrect, six-digit Smart-eID PIN. You have two further attempts to enter the correct Smart-eID PIN. INFO ALL_PLATFORMS The wrong Smart-eID PIN was entered on the first attempt. @@ -7345,11 +5620,6 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u INFO ALL_PLATFORMS The wrong Transport PIN was entered twice, the next attempt requires the CAN for additional verification. Вы дважды ввели неправильный 5-значный временный PIN-код. Для третьей попытки сначала введите 6-значный код доступа (CAN). Код CAN указан внизу справа на передней стороне идентификационной карты. - - You have entered an incorrect, six-digit Smart-eID PIN twice. An incorrect third attempt will invalidate your Smart-eID and you will have to set it up again. - INFO ANDROID IOS The wrong Smart-eID PIN was entered twice, a third wrong attempt could invalidate the Smart-eID. - Вы дважды ввели неправильный 6-значный PIN-код для Smart-eID. При третьем неправильном вводе электронная идентификационная карта Smart-eID становится недействительной, ее необходимо создать повторно. - You have entered an incorrect, six-digit ID card PIN twice. For a third attempt, the six-digit Card Access Number (CAN) must be entered first. You can find your CAN in the bottom right on the front of your ID card. INFO ALL_PLATFORMS The wrong ID card PIN was entered twice, the next attempt requires the CAN for additional verification. @@ -7380,96 +5650,19 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u INFO ALL_PLATFORMS The PUK entered wrongfully and needs to be supplied again. Вы ввели неправильный 10-значный PUK-код. Повторите попытку. - - - governikus::PdfCreator - - AusweisApp2 is a product of Governikus GmbH & Co. KG - on behalf of the Federal Office for Information Security. - LABEL ALL_PLATFORMS - AusweisApp2 является продуктом компании Governikus GmbH Co. KG — по заказу Федерального управления по информационной безопасности. - - - For further information, please see %1 - LABEL ALL_PLATFORMS Footer in a generated PDF document. %1 is an URL. - Дополнительную информацию см. %1 - - - - governikus::PdfExporter - - Date - LABEL ALL_PLATFORMS - Дата - - - Details - LABEL ALL_PLATFORMS - Подробная информация - - - dd.MM.yyyy hh:mm AP - LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString - dd.MM.yyyy hh:mm - - - Provider: - LABEL ALL_PLATFORMS - Провайдер: - - - Purpose: - LABEL ALL_PLATFORMS - Цель: - - - Read access: - LABEL ALL_PLATFORMS - Доступ для чтения: - - - Write access (update): - LABEL ALL_PLATFORMS - Доступ для записи (обновление): - - - dd.MM.yyyy - LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString - dd.MM.yyyy - - - hh:mm AP - LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString - hh:mm - - - At %1 %2 the following data were saved: - LABEL ALL_PLATFORMS - %1 %2 сохранены следующие данные. - - - History - LABEL ALL_PLATFORMS - Журнал - - - Entry - LABEL ALL_PLATFORMS - Запись - - Content - LABEL ALL_PLATFORMS - Содержание + You have entered an incorrect, six-digit Smart-eID PIN twice. After the next failed attempt you will no longer be able to use your Smart-eID and will need to set it up again. + INFO ANDROID IOS The wrong Smart-eID PIN was entered twice, a third wrong attempt could invalidate the Smart-eID. + - At %1 %2 the following data has been read out of your ID card: - LABEL ALL_PLATFORMS - %1 %2 считаны следующие данные вашей идентификационной карты. + The input does not match. Please choose a new Smart-eID PIN. + ALL_PLATFORMS Error message if the new pin confirmation mismatches. + - Information - LABEL ALL_PLATFORMS - Информация + The input does not match. Please choose a new ID card PIN. + @@ -7504,47 +5697,6 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u Запросите новый PIN-код карты бесплатно, чтобы снова иметь возможность использовать функцию eID. - - governikus::ProviderModel - - %1/min - INFO ALL_PLATFORMS Unit for expenses for calling the hotline (per minute). - %1/мин - - - %1/call - INFO ALL_PLATFORMS Unit for expenses for calling the hotline (per call). - %1/вызов - - - %1 EUR - INFO ALL_PLATFORMS Currency unit for expenses for calling the hotline (Euro/Cent). - %1 евро - - - %1 ct - %1 евроцентов - - - %1 seconds free, afterwards - INFO ALL_PLATFORMS Free of charge seconds when calling the hotline. - %1 секунд бесплатно, далее - - - landline costs %1; - INFO ALL_PLATFORMS Land line charges when calling the hotline. - стоимость стационарной связи %1; - - - mobile costs may vary. - INFO ALL_PLATFORMS Cell phone charges when calling the hotline. - Стоимость мобильной связи может отличаться. - - - mobile costs %1 - Стоимость мобильной связи %1 - - governikus::ReaderModel @@ -7572,16 +5724,6 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u INFO ALL_PLATFORMS Это устройство чтения карт не поддерживается официально и может работать неправильно. - - online help - Is embedded in a sentence. - онлайн-справка - - - No connected card reader found. See %1 for installation of card readers. - INFO ALL_PLATFORMS No card reader was found, the message contains a link to the installation section of the manual. - Подключенные устройства чтения карт не найдены. Информацию об установке устройств чтения карт см. здесь: %1. - hh:mm:ss AP LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString @@ -7596,14 +5738,14 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u governikus::RedirectRequest - Cannot reach local AusweisApp2 + Cannot reach local %1 ERROR ALL_PLATFORMS The local AusweisApp (access via reverse proxy) is not reachable, part of an HTML error page. - Не удается связаться с локальным приложением AusweisApp2 + Не удается связаться с локальным приложением %1 - Your local AusweisApp2 is not running. Please start your local AusweisApp2 and try again. + Your local %1 is not running. Please start your local %1 and try again. ERROR ALL_PLATFORMS The local AusweisApp (access via reverse proxy) is not reachable, part of an HTML error page. - Ваше локальное приложение AusweisApp2 не запущено. Запустите локальное приложение AusweisApp2 и повторите попытку. + Ваше локальное приложение %1 не запущено. Запустите локальное приложение %1 и повторите попытку. Would you like to try again? @@ -7655,16 +5797,6 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString dd.MM.yyyy hh:mm - - online help - Is embedded in a sentence. - онлайн-справка - - - No smartphone as card reader (Sac) available. Please make sure to activate the "remote service" on your smartphone and to connect both devices to the same WiFi. See %1 for details of use. - INFO ALL_PLATFORMS No smartphone with enabled remote service was found on the same network. - Нет доступных смартфонов, используемых в качестве устройства чтения карт (SaC). Убедитесь в том, что удаленная служба активирована на вашем смартфоне и оба устройства подключены к одной сети Wi-Fi. Подробную информацию об использовании см. здесь: %1. - Unavailable LABEL ALL_PLATFORMS @@ -7811,24 +5943,74 @@ Please enable NFC to use your smartphone as a card reader (SaC). governikus::SmartModel - Delete data was successful. - LABEL ANDROID IOS - Данные успешно удалены. + The online check for the Smart-eID support on your device failed. Please note that this process requires an internet connection. + ERROR ANDROID IOS The check for Smart-eID support failed without any specific reason. + - Delete data failed. - LABEL ANDROID IOS - Сбой удаления данных. + The online check for the Smart-eID support on your device failed because the server is currently facing too many requests. Please try again later. + ERROR ANDROID IOS The check for Smart-eID support failed because the server is overloaded. + - Delete Smart-eID was successful. - LABEL ANDROID IOS - Электронная идентификационная карта Smart-eID успешно удалена. + The online check for the Smart-eID support on your device failed because the server is currently under maintenance. Please try again later. + ERROR ANDROID IOS The check for Smart-eID support failed because the server is being maintained. + - Delete Smart-eID failed. - LABEL ANDROID IOS - Сбой удаления электронной идентификационной карты Smart-eID. + The Smart-eID data and provisioning could not be successfully deleted from your device. Please note that this process requires an internet connection. + ERROR ANDROID IOS Deletion of the Smart-eID failed without a specific reason. + + + + The Smart-eID data and provisioning could not be successfully deleted from your device because the server is currently facing too many requests. Please try again later. + ERROR ANDROID IOS Deletion of the Smart-eID failed because the server is overloaded. + + + + The Smart-eID data and provisioning could not be successfully deleted from your device because the server is currently under maintenance. Please try again later. + ERROR ANDROID IOS Deletion of the Smart-eID failed because the server is being maintained. + + + + The Smart-eID data and provisioning could not be successfully deleted from your device. In order to access the necessary device storage, active NFC functionality is required. Please activate NFC and restart the process. + ERROR ANDROID IOS Deletion of the Smart-eID failed because NFC is not activated. + + + + The online check for the Smart-eID support on your device failed. In order to access the necessary device storage, active NFC functionality is required. Please activate NFC and try again. + ERROR ANDROID IOS The check for Smart-eID support failed because the NFC functionality is not activated. + + + + The online check for the Smart-eID support on your device failed. The Google Play Integrity Check failed. + ERROR ANDROID IOS The check for Smart-eID support failed because Google Play Integrity Check failed. + + + + The online check for the Smart-eID support on your device failed. An authentication issue occurred (e.g. a resource was accessed without authorization or an unauthorized app tried to access a security component). + ERROR ANDROID IOS The check for Smart-eID support failed because an authorization issue occurred. + + + + The Smart-eID data and provisioning could not be successfully deleted from your device. The Google Play Integrity Check failed. + ERROR ANDROID IOS Deletion of the Smart-eID failed because the Google Play Integrity Check failed. + + + + The Smart-eID data and provisioning could not be successfully deleted from your device. An authentication issue occurred (e.g. a resource was accessed without authorization or an unauthorized app tried to access a security component). + ERROR ANDROID IOS Deletion of the Smart-eID failed because an authorization issue occurred. + + + + The online check for the Smart-eID support on your device failed. Please ensure that you have an internet connection and your antivirus software and firewall are not blocking the connection. + ERROR ANDROID IOS The check for Smart-eID support failed because a network connection error occurred. + + + + The Smart-eID data and provisioning could not be successfully deleted from your device. Please ensure that you have an internet connection and your antivirus software and firewall are not blocking the connection. + ERROR ANDROID IOS Deletion of the Smart-eID failed because a network connection error occurred. + @@ -7856,11 +6038,21 @@ Please enable NFC to use your smartphone as a card reader (SaC). governikus::StateConnectCard The used card reader does not meet the technical requirements (Extended Length not supported). + INFO IOS Используемое устройство чтения карт не соответствует техническим требованиям (не поддерживается расширенная длина). - The provider requires a physical ID card. - Провайдер требует физическую идентификационную карту. + The used ID card type is not accepted by the server. + INFO IOS + + + + + governikus::StateDeleteApplet + + Cleaning up old Smart-eID + LABEL ANDROID IOS + Очистка старой Smart-eID @@ -7943,21 +6135,11 @@ Please enable NFC to use your smartphone as a card reader (SaC). - governikus::StatePrepareApplet - - Checking Smart-eID status - LABEL ANDROID IOS - Проверка статуса Smart-eID - + governikus::StateInstallApplet Installing Smart-eID LABEL ANDROID IOS - Установка Smart-eID - - - Cleaning up old Smart-eID - LABEL ANDROID IOS - Очистка старой Smart-eID + Установка Smart-eID @@ -7983,18 +6165,11 @@ Please enable NFC to use your smartphone as a card reader (SaC). - governikus::StateWriteHistory + governikus::StateUpdateSupportInfo - Validity: -%1 - %2 - LABEL ALL_PLATFORMS - Действие: -%1 — %2 - - - Preparing results - INFO ALL_PLATFORMS Status message after the authentication was completed, the results are prepared for the user and the process will be continued in the browser - Подготовка результатов + Checking Smart-eID status + LABEL ANDROID IOS + Проверка статуса Smart-eID @@ -8028,8 +6203,8 @@ Please enable NFC to use your smartphone as a card reader (SaC). Макс. длина пакета NFC - AusweisApp2 Version - Версия AusweisApp2 + %1 Version + Версия %1 NFC Tag Type @@ -8049,9 +6224,9 @@ Please enable NFC to use your smartphone as a card reader (SaC). Открыть - Quit AusweisApp2 + Quit %1 LABEL DESKTOP - Выйти из AusweisApp2 + Выйти из %1 @@ -8081,26 +6256,18 @@ Please enable NFC to use your smartphone as a card reader (SaC). Программа (%1) использует требуемый порт (%2). Закройте %1 и повторите попытку! - You tried to start a newer version (%1) of currently running AusweisApp2. Please stop the current version (%2) and start again! + You tried to start a newer version (%1) of currently running %2. Please stop the current version (%3) and start again! ERROR ALL_PLATFORMS The external request to show the UI requested a newer version than the one currently installed. - Вы попытались запустить более новую версию (%1) уже запущенного приложения AusweisApp2. Остановите текущую версию (%2) и повторите попытку! + Вы попытались запустить более новую версию (%1) уже запущенного приложения %2. Остановите текущую версию (%3) и повторите попытку! - You tried to start an older version (%1) of currently running AusweisApp2. Please open the currently running version (%2)! + You tried to start an older version (%1) of currently running %2. Please open the currently running version (%3)! ERROR ALL_PLATFORMS The external request to show the UI requested an older version than the one currently installed. - Вы попытались запустить более старую версию (%1) уже запущенного приложения AusweisApp2. Откройте текущую запущенную версию (%2)! - - - Reverse-Proxy of AusweisApp2 is started and this instance cannot rebind port. Please ask your administrator! - Запущен обратный прокси-сервер AusweisApp2, и этот экземпляр не может повторно привязать порт. Обратитесь к своему администратору! + Вы попытались запустить более старую версию (%1) уже запущенного приложения %2. Откройте текущую запущенную версию (%3)! - - - governikus::WebserviceActivationContext - The browser connection was lost. - ERROR ALL_PLATFORMS No HTTP connection present. - Соединение с браузером прервано. + Reverse-Proxy of %1 is started and this instance cannot rebind port. Please ask your administrator! + Запущен обратный прокси-сервер %1, и этот экземпляр не может повторно привязать порт. Обратитесь к своему администратору! Cannot start authentication @@ -8122,6 +6289,11 @@ Please enable NFC to use your smartphone as a card reader (SaC). ERROR ALL_PLATFORMS A new authentication request was received while the previous one was still running. Part of an HTML error page. Повторить попытку + + The browser connection was lost. + ERROR ALL_PLATFORMS No HTTP connection present. + Соединение с браузером прервано. + Invalid request (%1) ERROR ALL_PLATFORMS Invalid request by the browser, part of an HTML error page @@ -8156,13 +6328,38 @@ Please enable NFC to use your smartphone as a card reader (SaC). governikus::WorkflowModel - AusweisApp2 error report - %1 - Отчет об ошибках AusweisApp2 — %1 + %1 error report - %2 + Отчет об ошибках %1 — %2 Contact your local citizens' office (Bürgeramt) to apply for a new ID card or to unblock the ID card. Обратитесь в местное ведомство по делам граждан (Bürgeramt), чтобы разблокировать идентификационную карту или заказать новую. + + The used Smart-eID is not accepted by the server. Please restart the remote service on your connected smartphone and try again with a physical ID card. + INFO ALL_PLATFORMS + + + + The used Smart-eID is not accepted by the server. Please stop the remote service and use another Smart-eID or contact the service provider. + INFO ALL_PLATFORMS + + + + The used ID card is not accepted by the server. Please remove the ID card from your device or card reader and use a Smart-eID or contact the service provider. + INFO ALL_PLATFORMS + + + + Renew your Smart-eID and set a new PIN in the Smart-eID menu. + LABEL ANDROID IOS The hint text that is shwon right above the redirect button that appears when a user tried to usa an unusable Smart-eID + + + + Go to Smart-eID menu + LABEL ANDROID IOS The text on the redirect button that appears when the user tried to use an unusable Smart-eID + + main @@ -8230,5 +6427,20 @@ Please enable NFC to use your smartphone as a card reader (SaC). INFO DESKTOP Content of the popup that is shown when the AA2 is closed and the close/minimize info was not disabled. macOS specific if autostart is enabled. Программа по-прежнему доступна через значок в строке меню. Нажмите на символ %1, чтобы снова открыть пользовательский интерфейс. + + The %1 will be shut down and an authentication will no longer be possible. You will have to restart the %1 to identify yourself towards providers. + INFO DESKTOP Text of the popup that is shown when the AA2 is quit for the first time. + + + + The %1 is closed. + INFO DESKTOP Header of the popup that is shown when the AA2 is quit for the first time. + + + + This will cancel the current operation and shut the %1 down. You will have to restart the %1 to restart the operation. + INFO DESKTOP Content of the popup that is shown when the AA2 is shut down and a workflow is still active. + + diff --git a/resources/translations/ausweisapp2_uk.ts b/resources/translations/ausweisapp2_uk.ts index 4fdae1f4e..87240c9bc 100644 --- a/resources/translations/ausweisapp2_uk.ts +++ b/resources/translations/ausweisapp2_uk.ts @@ -5,7 +5,7 @@ DvcsAttributes revision - b9ade3b30f3d + 56dc58807a8c @@ -27,34 +27,56 @@ - AdditionalResultsFooterItem + AuthController - Additional results in other categories: %1. Click here to remove filter. - Додаткові результати в інших категоріях: %1. Натисніть тут, щоб видалити фільтр. + Identify + LABEL ANDROID IOS + Ідентифікувати + + + Cancel authentication process + LABEL ANDROID IOS + Скасувати процес автентифікації - Additional results in other categories: - LABEL DESKTOP IOS_TABLET ANDROID_TABLET - Додаткові результати в інших категоріях: + Acquiring provider certificate + INFO ANDROID IOS Header of the progress status message during the authentication process. + Отримання сертифіката постачальника - Show - Показати + Authentication in progress + INFO ANDROID IOS Header of the progress status message during the authentication process. + Виконується автентифікація + + + Please wait a moment. + INFO ANDROID IOS Generic status message during the authentication process. + Трохи зачекайте. + + + Please do not move the ID card. + INFO ANDROID IOS Second line text if a basic card reader is used and background communication with the card/server is running. Is not actually visible since the basic reader password handling is done by EnterPasswordView. + Не рухайте ID-картку. + + + Please observe the display of your card reader. + INFO ANDROID IOS The card reader requests the user's attention. + Зверніть увагу на дисплей свого пристрою читання карток. - - - AdditionalResultsItem - %1 additional results in other categories - %1 додаткові результати в інших категоріях + A wrong PIN has been entered twice on your ID card. For a third attempt, please first enter the six-digit Card Access Number (CAN). You can find your CAN in the bottom right on the front of your ID card. + INFO ANDROID IOS The PIN was entered wrongfully two times, the third attempts requires additional CAN verification, hint where the CAN is found. + На вашій ID-картці двічі введено неправильний PIN-код. Для третьої спроби спочатку введіть шестизначний номер доступу до картки (CAN). Ви можете знайти номер CAN у нижньому правому куті на лицьовому боці своєї ID-картки. - Click to remove category filter and show additional results. - Натисніть, щоб видалити фільтр категорії та показати додаткові результати. + Send log + LABEL ANDROID IOS + Надіслати журнал - Additional results: - Додаткові результати: + Authenticate with provider + LABEL ANDROID IOS A11y button to confirm the PIN and start the provider authentication + Виконайте автентифікацію у провайдера @@ -107,9 +129,7 @@ LABEL ANDROID IOS ---------- INFO DESKTOP Generic progress status message while no card communication is active. ---------- -INFO DESKTOP Generic progress status message during authentication. ----------- -INFO ANDROID IOS Generic status message during the authentication process. +INFO DESKTOP Generic progress status message during authentication. Трохи зачекайте. @@ -119,23 +139,17 @@ INFO ANDROID IOS Generic status message during the authentication process. Acquiring provider certificate - INFO DESKTOP Header of the progress information during the authentication process. ----------- -INFO ANDROID IOS Header of the progress status message during the authentication process. + INFO DESKTOP Header of the progress information during the authentication process. Отримання сертифіката постачальника Authentication in progress - INFO DESKTOP Header of the progress information during the authentication process. ----------- -INFO ANDROID IOS Header of the progress status message during the authentication process. + INFO DESKTOP Header of the progress information during the authentication process. Виконується автентифікація Please do not move the ID card. - INFO DESKTOP Second line text if a basic card reader is used and data is exchanged with the card/server in the background. Is not actually visible since the basic reader password handling is done by EnterPasswordView. ----------- -INFO ANDROID IOS Second line text if a basic card reader is used and background communication with the card/server is running. Is not actually visible since the basic reader password handling is done by EnterPasswordView. + INFO DESKTOP Second line text if a basic card reader is used and data is exchanged with the card/server in the background. Is not actually visible since the basic reader password handling is done by EnterPasswordView. Не рухайте ID-картку. @@ -143,31 +157,9 @@ INFO ANDROID IOS Second line text if a basic card reader is used and background INFO DESKTOP Error code (string) of current GlobalStatus code, shown as header of popup. Код помилки: %1 - - Cancel authentication process - LABEL ANDROID IOS - Скасувати процес автентифікації - - - Please observe the display of your card reader. - INFO ANDROID IOS The card reader requests the user's attention. - Зверніть увагу на дисплей свого пристрою читання карток. - - - A wrong PIN has been entered twice on your ID card. For a third attempt, please first enter the six-digit Card Access Number (CAN). You can find your CAN in the bottom right on the front of your ID card. - INFO ANDROID IOS The PIN was entered wrongfully two times, the third attempts requires additional CAN verification, hint where the CAN is found. - На вашій ID-картці двічі введено неправильний PIN-код. Для третьої спроби спочатку введіть шестизначний номер доступу до картки (CAN). Ви можете знайти номер CAN у нижньому правому куті на лицьовому боці своєї ID-картки. - - - Send log - LABEL ANDROID IOS - Надіслати журнал - Authenticate with provider - LABEL DESKTOP A11y button to confirm the PIN and start the provider authentication ----------- -LABEL ANDROID IOS A11y button to confirm the PIN and start the provider authentication + LABEL DESKTOP A11y button to confirm the PIN and start the provider authentication Виконайте автентифікацію у провайдера @@ -210,52 +202,6 @@ LABEL ANDROID IOS A11y button to confirm the PIN and start the provider authenti Тепер ви можете видалити свою ID-картку з пристрою. - - BaseHistoryView - - History - INFO ANDROID IOS - Історія - - - Currently there are no history entries. - INFO ANDROID IOS No authentication history, placeholder text. - Наразі записів в історії немає. - - - - BaseProviderView - - No results matching your search query found - LABEL IOS_PHONE ANDROID_PHONE The text entered into the provider search field results in no matches - Не знайдено збігів за вашим пошуковим запитом - - - Provider - LABEL IOS_TABLET ANDROID_TABLET - Постачальник - - - Citizen services - LABEL IOS_TABLET ANDROID_TABLET - Послуги для громадян - - - Financials - LABEL IOS_TABLET ANDROID_TABLET - Фінанси - - - Insurances - LABEL IOS_TABLET ANDROID_TABLET - Страхування - - - Other services - LABEL IOS_TABLET ANDROID_TABLET - Інші послуги - - BuildHelper @@ -307,13 +253,6 @@ LABEL ANDROID IOS A11y button to confirm the PIN and start the provider authenti Версія OpenSSL - - CancelAction - - Cancel - Скасувати - - CardPositionView @@ -344,6 +283,7 @@ LABEL ANDROID IOS A11y button to confirm the PIN and start the provider authenti CardReaderView Connected USB card readers + LABEL DESKTOP Підключені USB-пристрої читання карток @@ -358,47 +298,77 @@ LABEL ANDROID IOS A11y button to confirm the PIN and start the provider authenti After connecting a new card reader it may take a few seconds to recognize the driver. It may be necessary to restart your system after installing the driver. Only connected card readers are shown here. %1 Після підключення нового пристрою читання карток може знадобитися кілька секунд, щоб розпізнати драйвер. Після встановлення драйвера може бути потрібно перезавантажити систему. Тут показано лише підключені пристрої читання карток. %1 + + No connected card reader found. + + - Category + CertificateDescriptionPage - Provider - Постачальник + Provider Information + LABEL DESKTOP +---------- +LABEL ANDROID IOS + Інформація про постачальника + + + ChangePinController - All - Усі + Your ID card PIN is unblocked. You now have three more attempts to change your PIN. + INFO ANDROID IOS The ID card has just been unblocked and the user can now continue with their PIN change. + PIN-код вашої ID-картки розблоковано. Тепер у вас є ще три спроби змінити PIN-код. - Citizen services - Послуги для громадян + Setting new Smart-eID PIN + LABEL ANDROID IOS Processing screen label while the card communication is running after the new Smart-eID PIN has been entered during PIN change process. + Установлення нового PIN-коду Smart-eID - Insurances - Страхування + Change Smart-eID PIN + LABEL ANDROID IOS Processing screen label while the card communication is running before the new ID card PIN has been entered during PIN change process. + Змінити PIN-код Smart-eID - Financials - Фінанси + Setting new ID card PIN + LABEL ANDROID IOS Processing screen label while the card communication is running after the new ID card PIN has been entered during PIN change process. + Установлення нового PIN-коду ID-картки - Other services - Інші послуги + Change ID card PIN + LABEL ANDROID IOS Processing screen label while the card communication is running before the new ID card PIN has been entered during PIN change process. + Змінити PIN-код ID-картки - - - CertificateDescriptionPage - Provider Information - LABEL DESKTOP ----------- -LABEL ANDROID IOS - Інформація про постачальника + Please wait a moment. + INFO ANDROID IOS Generic progress message during PIN change process. + Трохи зачекайте. - Close - LABEL DESKTOP - Закрити + Please do not move the ID card. + INFO ANDROID IOS Loading screen during PIN change process, data communication is currently ongoing. Message is usually not visible since the password handling with basic reader is handled by EnterPasswordView. + Не рухайте ID-картку. + + + Please observe the display of your card reader. + INFO ANDROID IOS Either an comfort card reader or smartphone-as-card-reader is used, the user needs to react to request on that device. + Зверніть увагу на дисплей свого пристрою читання карток. + + + A wrong ID card PIN has been entered twice on your ID card. For a third attempt, please first enter the six-digit Card Access Number (CAN). You can find your CAN in the bottom right on the front of your ID card. + INFO ANDROID IOS The wrong ID card PIN was entered twice, the next attempt requires additional verifcation via CAN. + На вашій ID-картці було двічі введено неправильний PIN-код. Для третьої спроби спочатку введіть шестизначний номер доступу до картки (CAN). Ви можете знайти номер CAN у нижньому правому куті на лицьовому боці своєї ID-картки. + + + You have entered an incorrect, six-digit ID card PIN thrice, your ID card PIN is now blocked. To remove the block, the ten-digit PUK must be entered first. + INFO ANDROID IOS The ID card PIN (including the CAN) was entered wrongfully three times, the PUK is required to unlock the ID card. + Ви тричі ввели неправильний шестизначний PIN-код ID-картки. Тепер PIN-код вашої ID-картки заблоковано. Щоб видалити блокування, потрібно спочатку ввести десятизначний PUK-код. + + + Please note that you may use the five-digit Transport PIN only once to change to a six-digit ID card PIN. If you already set a six-digit ID card PIN, the five-digit Transport PIN is no longer valid. + INFO ANDROID IOS + Зверніть увагу, що ви можете використати п’ятизначний транспортний PIN-код лише один раз, щоб змінити його на шестизначний PIN-код ID-картки. Якщо ви вже встановили шестизначний PIN-код ID-картки, п’ятизначний транспортний PIN-код більше не дійсний. @@ -419,16 +389,12 @@ LABEL ANDROID IOS Please do not move the ID card. - INFO DESKTOP Processing screen text while the card communication is running after the PIN has been entered during PIN change process. ----------- -INFO ANDROID IOS Loading screen during PIN change process, data communication is currently ongoing. Message is usually not visible since the password handling with basic reader is handled by EnterPasswordView. + INFO DESKTOP Processing screen text while the card communication is running after the PIN has been entered during PIN change process. Не рухайте ID-картку. Your ID card PIN is unblocked. You now have three more attempts to change your PIN. - INFO DESKTOP The ID card has just been unblocked and the user can now continue with their ID card PIN change. ----------- -INFO ANDROID IOS The ID card has just been unblocked and the user can now continue with their PIN change. + INFO DESKTOP The ID card has just been unblocked and the user can now continue with their ID card PIN change. PIN-код вашої ID-картки розблоковано. Тепер у вас є ще три спроби змінити PIN-код. @@ -451,61 +417,21 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin - переконайтеся, що картку правильно розміщено на пристрої читання; - не переміщуйте картку, поки до неї здійснюється доступ - - Change my (Transport) PIN - LABEL ANDROID IOS - Змінити мій (транспортний) PIN-код - Change Transport PIN LABEL ANDROID IOS Змінити транспортний PIN-код - - Setting new Smart-eID PIN - LABEL ANDROID IOS Processing screen label while the card communication is running after the new Smart-eID PIN has been entered during PIN change process. - Установлення нового PIN-коду Smart-eID - - - Change Smart-eID PIN - LABEL ANDROID IOS Processing screen label while the card communication is running before the new ID card PIN has been entered during PIN change process. - Змінити PIN-код Smart-eID - - - Setting new ID card PIN - LABEL ANDROID IOS Processing screen label while the card communication is running after the new ID card PIN has been entered during PIN change process. - Установлення нового PIN-коду ID-картки - - - Change ID card PIN - LABEL ANDROID IOS Processing screen label while the card communication is running before the new ID card PIN has been entered during PIN change process. - Змінити PIN-код ID-картки - - - Please wait a moment. - INFO ANDROID IOS Generic progress message during PIN change process. - Трохи зачекайте. - - - Please observe the display of your card reader. - INFO ANDROID IOS Either an comfort card reader or smartphone-as-card-reader is used, the user needs to react to request on that device. - Зверніть увагу на дисплей свого пристрою читання карток. - - - A wrong ID card PIN has been entered twice on your ID card. For a third attempt, please first enter the six-digit Card Access Number (CAN). You can find your CAN in the bottom right on the front of your ID card. - INFO ANDROID IOS The wrong ID card PIN was entered twice, the next attempt requires additional verification via CAN. - На вашій ID-картці було двічі введено неправильний PIN-код. Для третьої спроби спочатку введіть шестизначний номер доступу до картки (CAN). Ви можете знайти номер CAN у нижньому правому куті на лицьовому боці своєї ID-картки. - - - You have entered an incorrect, six-digit ID card PIN thrice, your ID card PIN is now blocked. To remove the block, the ten-digit PUK must be entered first. - INFO ANDROID IOS The ID card PIN (including the CAN) was entered wrongfully three times, the PUK is required to unlock the ID card. - Ви тричі ввели неправильний шестизначний PIN-код ID-картки. Тепер PIN-код вашої ID-картки заблоковано. Щоб видалити блокування, потрібно спочатку ввести десятизначний PUK-код. - The device "%1" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. INFO DESKTOP The paired devices was removed since it did not respond to connection attempts. It needs to be paired again if it should be used as card reader. Пару з пристроєм «%1» було скасовано, оскільки він не реагував на спроби підключення. Створіть пару з пристроєм знову, щоб використовувати його як пристрій читання карток. + + Please note that you may use the five-digit Transport PIN only once to change to a six-digit ID card PIN. If you already set a six-digit ID card PIN, the five-digit Transport PIN is no longer valid. + INFO DESKTOP + Зверніть увагу, що ви можете використати п’ятизначний транспортний PIN-код лише один раз, щоб змінити його на шестизначний PIN-код ID-картки. Якщо ви вже встановили шестизначний PIN-код ID-картки, п’ятизначний транспортний PIN-код більше не дійсний. + ChangePinViewContent @@ -797,207 +723,145 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin CheckSmartResultView - Check Smart-eID + Unknown result code: %1 LABEL ANDROID IOS - Перевірте Smart-eID + Невідомий код результату: %1 - Result of Smart-eID check + Please wait a moment. LABEL ANDROID IOS - Результат перевірки Smart-eID + Трохи зачекайте. - Continue + Updating Smart-eID status... LABEL ANDROID IOS - Продовжити + Триває оновлення статусу Smart-eID… - What does that mean? + Check device and ID card LABEL ANDROID IOS - Що це означає? + Перевірити пристрій та ID-картку - You may now try the function: "See my personal data". Press the Continue button to do so now. - Тепер ви можете спробувати скористатися функцією: «Дивитися мої особисті дані». Для цього натисніть кнопку «Продовжити». - - - Supported + Your mobile device does not meet the technical requirements for Smart-eID.<br><br>You may check if your device and ID card are suitable to use the eID function. LABEL ANDROID IOS - Підтримується + Ваш мобільний пристрій не відповідає технічним вимогам щодо Smart-eID.<br><br>Ви можете перевірити, чи підходять ваш пристрій та ID-картка для використання функції eID. - Not supported + Smart-eID not supported LABEL ANDROID IOS - Не підтримується + Smart-eID не підтримується - Prepared + Possible causes are: LABEL ANDROID IOS - Підготовлено + Можливі причини: - Not prepared + The setup has not been completed. LABEL ANDROID IOS - Не підготовлено + Налаштування не завершено. - Set up + The Smart-eID PIN has been entered incorrectly three times. LABEL ANDROID IOS - Налаштовано + PIN-код Smart-eID було введено неправильно тричі. - Not set up + The %1 has been uninstalled temporarily. LABEL ANDROID IOS - Не налаштовано + Програму %1 тимчасово видалено. - Invalid + You may continue with the setup of the Smart-eID. LABEL ANDROID IOS - Недійсний + - Ready for use + Continue LABEL ANDROID IOS - Готово до використання + Продовжити - - - CheckSmartSuggestionView - Unknown result code: %1 + Your device meets the technical requirements for Smart-eID. You may now continue the setup process. LABEL ANDROID IOS - Невідомий код результату: %1 + - Updating Smart-eID status... + Smart-eID supported LABEL ANDROID IOS - Триває оновлення статусу Smart-eID… + - Please wait a moment. - LABEL ANDROID IOS - Трохи зачекайте. + Your device meets the technical requirements for Smart-eID, however, the Smart-eID that was set up is invalid. + LABEL ANDROID IOS LABEL ANDROID IOS + - Smart-eID not supported + Smart-eID invalid LABEL ANDROID IOS - Smart-eID не підтримується + - Your mobile device does not meet the technical requirements for Smart-eID.<br><br>You may check if your device and ID card are suitable to use the eID function. + Smart-eID check failed LABEL ANDROID IOS - Ваш мобільний пристрій не відповідає технічним вимогам щодо Smart-eID.<br><br>Ви можете перевірити, чи підходять ваш пристрій та ID-картка для використання функції eID. + - Check device and ID card + Back LABEL ANDROID IOS - Перевірити пристрій та ID-картку + Назад + + + ConnectSacView - Smart-eID invalid - LABEL ANDROID IOS - Smart-eID недійсний + Pairing + LABEL DESKTOP + Створення пари - Your device meets the technical requirements for Smart-eID, however, the Smart-eID that was set up is invalid. - LABEL ANDROID IOS LABEL ANDROID IOS - Ваш пристрій відповідає технічним вимогам щодо Smart-eID, але налаштований Smart-eID є недійсним. + Pairing the device ... + LABEL DESKTOP + Створення пари з пристроєм… - Possible causes are: - LABEL ANDROID IOS - Можливі причини: - - - The setup has not been completed. - LABEL ANDROID IOS - Налаштування не завершено. - - - The preparation for the Smart-eID is defective. - LABEL ANDROID IOS - Підготовка до Smart-eID має порушення. - - - The Smart-eID PIN has been entered incorrectly three times. - LABEL ANDROID IOS - PIN-код Smart-eID було введено неправильно тричі. - - - The AusweisApp2 has been uninstalled temporarily. - LABEL ANDROID IOS - Програму AusweisApp2 тимчасово видалено. - - - Please restart the setup of the Smart-eID. - LABEL ANDROID IOS - Перезапустіть налаштування Smart-eID. - - - Set up Smart-eID - LABEL ANDROID IOS - Налаштувати Smart-eID - - - Smart-eID not prepared - LABEL ANDROID IOS - Smart-eID не підготовлено - - - Your device meets the technical requirements for Smart-eID, but is not yet provisioned for setup. The provisioning is done automatically during the Smart-eID setup process. - LABEL ANDROID IOS - Ваш пристрій відповідає технічним вимогам щодо Smart-eID, але його ще не підготовлено для налаштування. Підготовка здійснюється автоматично під час процесу налаштування Smart-eID. - - - Smart-eID not set up - LABEL ANDROID IOS - Smart-eID не налаштовано - - - Your device meets the technical requirements for Smart-eID and is already provisioned for setup. You can now start the Smart-eID setup. - LABEL ANDROID IOS - Ваш пристрій відповідає технічним вимогам щодо Smart-eID, і його вже підготовлено для налаштування. Тепер ви можете почати налаштування Smart-eID. + Pairing to "%1" failed: + ERROR DESKTOP An error occurred while pairing the device. + Не вдалося створити пару з пристроєм «%1»: - CheckSmartView - - Check Smart-eID - LABEL ANDROID IOS - Перевірте Smart-eID - + DarkModeButtons - Your device needs to meet the technical requirements to use the Smart-eID function. - LABEL ANDROID IOS - Для використання функції Smart-eID ваш пристрій має відповідати технічним вимогам. + System + LABEL ALL_PLATFORMS + Система - Check here if your device is suitable to set up a Smart-eID. - LABEL ANDROID IOS - Перевірте тут, чи підходить ваш пристрій для налаштування Smart-eID. + Dark + LABEL ALL_PLATFORMS + - Start check - LABEL ANDROID IOS - Почати перевірку + Light + LABEL ALL_PLATFORMS + - - - ConnectSacView - Pairing - LABEL DESKTOP - Створення пари + Set the app appearance to system mode + LABEL ALL_PLATFORMS + - Pairing the device ... - LABEL DESKTOP - Створення пари з пристроєм… + Set the app appearance to dark mode + LABEL ALL_PLATFORMS + - Pairing to "%1" failed: - ERROR DESKTOP An error occurred while pairing the device. - Не вдалося створити пару з пристроєм «%1»: + Set the app appearance to light mode + LABEL ALL_PLATFORMS + @@ -1023,11 +887,6 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin LABEL DESKTOP Файл журналу - - History - LABEL DESKTOP - Історія - Show beta testing image LABEL DESKTOP @@ -1043,6 +902,16 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin LABEL DESKTOP Пропустити сторінку прав у дозволеному режимі CAN + + Reset hideable dialogs + LABEL DESKTOP + + + + Show Transport PIN reminder, store feedback and close reminder dialogs. + LABEL DESKTOP + + DecisionView @@ -1051,11 +920,6 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin LABEL DESKTOP Ні - - Maybe - LABEL DESKTOP - Можливо - Yes LABEL DESKTOP @@ -1125,11 +989,6 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin LABEL DESKTOP Тестовий режим для самоавтентифікації - - Enable internal card simulator - LABEL DESKTOP - Увімкнути внутрішній симулятор картки - The internal card simulator allows to run an authentication in the test PKI without any ID card or card reader. Note that no other card reader can be used while the simulator is activated. LABEL DESKTOP @@ -1140,11 +999,6 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin LABEL DESKTOP Режим розробника - - The developer mode is aimed at integrators / developers for new service applications. For this reason, the developer mode works only in the test PKI. By activating the developer mode, some safety tests are deactivated. This means that the authentication process continues although the AusweisApp2 would usually abort the process with an error message when used in normal operation mode. Information on the disregarded error in the developer mode is displayed in the attached window below the AusweisApp2. - LABEL DESKTOP - Режим розробника орієнтований на інтеграторів/розробників нових сервісних програм. Тому режим розробника працює лише в тестовій PKI. Після активації режиму розробника деякі тести безпеки деактивуються. Це означає, що процес автентифікації продовжується, хоча під час використання в нормальному режимі роботи програма AusweisApp2 зазвичай перериває процес із повідомленням про помилку. Інформація про проігноровану помилку в режимі розробника відображається в прикріпленому вікні під програмою AusweisApp2. - Custom config.json LABEL DESKTOP @@ -1170,6 +1024,21 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin LABEL DESKTOP Конфігурація JSON (*.json) + + Allow test sample card usage + LABEL DESKTOP + + + + Internal card simulator + LABEL DESKTOP + Внутрішній симулятор картки + + + The developer mode deactivates some security checks and the authentication process will continue even if some errors occur. Skipped errors will be shown as notifications. The developer mode is only usable with the test PKI. + LABEL DESKTOP + Режим розробника орієнтований на інтеграторів/розробників нових сервісних програм. Тому режим розробника працює лише в тестовій PKI. Після активації режиму розробника деякі тести безпеки деактивуються. Це означає, що процес автентифікації продовжується, хоча під час використання в нормальному режимі роботи програма %1 зазвичай перериває процес із повідомленням про помилку. Інформація про проігноровану помилку в режимі розробника відображається в прикріпленому вікні під програмою %1. + DevicesListDelegate @@ -1180,15 +1049,6 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin DiagnosisView - - Diagnosis - LABEL DESKTOP - Діагностика - - - Save diagnosis to textfile - Зберегти діагностику в текстовий файл - Save to file LABEL DESKTOP @@ -1210,138 +1070,111 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin Текстові файли (*.txt) - Save diagnosis + System data LABEL DESKTOP - Зберегти діагностику + Діагностика - - - EditRights - You are about to identify yourself towards the following provider - LABEL DESKTOP - Ви збираєтеся ідентифікувати себе для такого постачальника + Save system data to textfile + Зберегти діагностику в текстовий файл - Show more information about the service provider - Показати додаткову інформацію про постачальника послуг + SystemData + Діагностика - Details about the provider - LABEL DESKTOP ----------- -LABEL ANDROID_TABLET IOS_TABLET - Відомості про постачальника + Save system data + LABEL DESKTOP + Зберегти діагностику + + + EditRights Proceed to %1 entry LABEL DESKTOP %1 can be "CAN" or "PIN" ---------- -LABEL IOS_PHONE ANDROID_PHONE %1 can be "CAN" or "PIN" ----------- -LABEL ANDROID_TABLET IOS_TABLET %1 can be "CAN" or "PIN" +LABEL IOS_PHONE ANDROID_PHONE %1 can be "CAN" or "PIN" Перейти до введення %1 CAN LABEL DESKTOP Inserted into "Proceed to %1 entry" ---------- -LABEL IOS_PHONE Inserted into "Proceed to %1 entry" ----------- -LABEL ANDROID_TABLET IOS_TABLET Inserted into "Proceed to %1 entry" +LABEL IOS_PHONE Inserted into "Proceed to %1 entry" CAN PIN LABEL DESKTOP Inserted into "Proceed to %1 entry" ---------- -LABEL IOS_PHONE Inserted into "Proceed to %1 entry" ----------- -LABEL ANDROID_TABLET IOS_TABLET Inserted into "Proceed to %1 entry" +LABEL IOS_PHONE Inserted into "Proceed to %1 entry" PIN By entering the CAN, access to the following data of the ID card will be allowed to the mentioned provider: LABEL DESKTOP ---------- -LABEL IOS_PHONE ANDROID_PHONE ----------- -LABEL ANDROID_TABLET IOS_TABLET +LABEL IOS_PHONE ANDROID_PHONE Після введення CAN-коду зазначеному постачальнику буде надано доступ до таких даних ID-картки: By entering your PIN, access to the following data of your ID card will be allowed to the mentioned provider: LABEL DESKTOP ---------- -LABEL IOS_PHONE ANDROID_PHONE ----------- -LABEL ANDROID_TABLET IOS_TABLET +LABEL IOS_PHONE ANDROID_PHONE Після введення PIN-коду зазначеному постачальнику буде надано доступ до таких даних вашої ID-картки: Transactional information LABEL DESKTOP ---------- -LABEL IOS_PHONE ANDROID_PHONE ----------- -LABEL ANDROID_TABLET IOS_TABLET +LABEL IOS_PHONE ANDROID_PHONE Інформація про транзакції The provider mentioned above does not require any data stored on your ID card, only confirmation of you possessing a valid ID card. LABEL DESKTOP ---------- -LABEL IOS_PHONE ANDROID_PHONE ----------- -LABEL ANDROID_TABLET IOS_TABLET +LABEL IOS_PHONE ANDROID_PHONE Постачальник, зазначений вище, не вимагає жодних даних, збережених на вашій ID-картці, йому потрібне лише підтвердження наявності у вас дійсної ID-картки. Write access (update) LABEL DESKTOP ---------- -LABEL IOS_PHONE ANDROID_PHONE ----------- -LABEL ANDROID_TABLET IOS_TABLET +LABEL IOS_PHONE ANDROID_PHONE Доступ для записування (оновлення) Read access LABEL DESKTOP ---------- -LABEL IOS_PHONE ANDROID_PHONE ----------- -LABEL ANDROID_TABLET IOS_TABLET +LABEL IOS_PHONE ANDROID_PHONE Доступ для читання Read access (optional) LABEL DESKTOP ---------- -LABEL IOS_PHONE ANDROID_PHONE ----------- -LABEL ANDROID_TABLET IOS_TABLET +LABEL IOS_PHONE ANDROID_PHONE Доступ для читання (необов’язково) Identify - LABEL IOS_PHONE ANDROID_PHONE ----------- -LABEL ANDROID_TABLET IOS_TABLET + LABEL IOS_PHONE ANDROID_PHONE Ідентифікувати You are about to identify yourself towards the following provider: - LABEL IOS_PHONE ANDROID_PHONE + LABEL DESKTOP ---------- -LABEL ANDROID_TABLET IOS_TABLET +LABEL IOS_PHONE ANDROID_PHONE Ви збираєтеся ідентифікувати себе для такого постачальника: Provider - LABEL IOS_PHONE ANDROID_PHONE ----------- -LABEL ANDROID_TABLET IOS_TABLET + LABEL IOS_PHONE ANDROID_PHONE Постачальник @@ -1357,11 +1190,6 @@ LABEL ANDROID_TABLET IOS_TABLET LABEL DESKTOP Спроби - - Remaining ID card PIN attempts: %1 - LABEL DESKTOP - Залишилося стільки спроб введення PIN-коду ID-картки: %1 - Enter CAN LABEL DESKTOP @@ -1411,13 +1239,6 @@ LABEL ANDROID IOS LABEL ANDROID IOS Уведіть PIN-код ID-картки - - The new ID card PIN and the confirmation do not match. Please correct your input. - INFO DESKTOP The changed ID card PIN was entered wrongfully during the confirmation process. ----------- -INFO ANDROID IOS The changed ID card PIN was entered wrongfully during confirmation. - Новий PIN-код ID-картки та його підтвердження не збігаються. Виправте введені дані. - Please enter the five-digit Transport PIN. INFO DESKTOP The AA2 expects the Transport PIN with five digits. @@ -1505,18 +1326,9 @@ LABEL ANDROID IOS LABEL ANDROID IOS Підтвердьте новий PIN-код Smart-eID - - The new Smart-eID PIN and the confirmation do not match. Please correct your input. - INFO DESKTOP The changed Smart-eID PIN was entered wrongfully during the confirmation process. ----------- -INFO ANDROID IOS The changed Smart-eID PIN was entered wrongfully during confirmation. - Новий PIN-код Smart-eID та його підтвердження не збігаються. Виправте введені дані. - You have entered an incorrect, six-digit Smart-eID PIN twice. An incorrect third attempt will invalidate your Smart-eID and you will have to set it up again. - INFO DESKTOP The wrong Smart-eID PIN was entered twice on the Smart-eID ----------- -INFO ANDROID IOS The wrong Smart-eID PIN was entered twice on the Smart-eID + INFO DESKTOP The wrong Smart-eID PIN was entered twice on the Smart-eID Ви двічі ввели неправильний шестизначний PIN-код Smart-eID. Якщо його втретє буде введено неправильно, ваш Smart-eID стане недійсним і вам доведеться знову його налаштувати. @@ -1557,6 +1369,11 @@ INFO ANDROID IOS The AA2 expects a Smart-eID PIN with six digits in an authentic LABEL ANDROID IOS Button to switch to a six-digit ID card PIN. У вас є шестизначний PIN-код ID-картки? + + You have entered an incorrect, six-digit Smart-eID PIN twice. After the next failed attempt you will no longer be able to use your Smart-eID and will need to set it up again. + INFO ANDROID IOS The wrong Smart-eID PIN was entered twice on the Smart-eID + + Send CAN LABEL DESKTOP @@ -1613,12 +1430,40 @@ LABEL ANDROID IOS LABEL ANDROID IOS Надіслати PIN-код ID-картки + + Send confirmation of new ID card PIN + LABEL ANDROID IOS + + + + Send confirmation of new Smart-eID PIN + LABEL ANDROID IOS + + Enter the pairing code shown on your smartphone. INFO DESKTOP The pairing code needs to be supplied. Введіть код створення пари, який відображається на вашому смартфоні. + + GCollapsible + + collapse + LABEL ANDROID IOS + + + + expand + LABEL ANDROID IOS + + + + Currently selected is %1 + LABEL ANDROID IOS + + + GProgressBar @@ -1659,34 +1504,49 @@ LABEL ANDROID IOS Виконати автозапуск %1 після завантаження та додати до рядка меню - Auto-start %1 after boot - LABEL WINDOWS Text for auto-start option - Виконати автозапуск %1 після завантаження + Using the developer mode forces the notifications to be enabled. + LABEL DESKTOP Only visible when the user activates the developer mode in the settings. + Використання режиму розробника примусово вмикає сповіщення. + + + Network + LABEL DESKTOP + Мережа - Close after authentication + Use the proxy (%1) specified during the installation. LABEL DESKTOP - Закрити після автентифікації + Використовувати проксі-сервер (%1), зазначений під час інсталяції. - Use internal notifications + Appearance LABEL DESKTOP - Використовувати внутрішні сповіщення + - Using the developer mode forces the notifications to be enabled. - LABEL DESKTOP Only visible when the user activates the developer mode in the settings. - Використання режиму розробника примусово вмикає сповіщення. + Use the system font + LABEL DESKTOP + - Network + Toggling will restart the %1 LABEL DESKTOP - Мережа + - Use the proxy (%1) specified during the installation. + Close %1 after authentication LABEL DESKTOP - Використовувати проксі-сервер (%1), зазначений під час інсталяції. + Закрити після автентифікації + + + Show notifications inside of %1 + LABEL DESKTOP + Використовувати внутрішні сповіщення + + + Auto-start %1 after boot and add a tray icon + LABEL WINDOWS Text for auto-start option + Виконати автозапуск %1 після завантаження @@ -1696,10 +1556,6 @@ LABEL ANDROID IOS LABEL DESKTOP Спроби - - Remaining ID card PIN attempts: %1 - Залишилося стільки спроб введення PIN-коду ID-картки: %1 - Step %1 of 3 Крок %1 із 3 @@ -1729,16 +1585,6 @@ LABEL ANDROID IOS INFO DESKTOP The AA2 is waiting for an ID card to be inserted into the card reader. ID-картку не виявлено. Розташуйте ID-картку на пристрої читання карток. - - No ID card detected. Please make sure that the NFC interface of the smartphone (connected to %1) is correctly placed on your ID card. - INFO DESKTOP The AA2 is waiting for the smartphone to be placed on the id. - ID-картку не виявлено. Правильно розташуйте інтерфейс NFC смартфона (підключеного до %1) на ID-картці. - - - Please place the smartphone (connected to %1) on your ID card or put the ID card on the card reader. - INFO DESKTOP The AA2 is waiting for an ID card to be inserted into the card reader (or smartphone for that matter). - Розташуйте смартфон (підключений до %1) на ID-картці або покладіть ID-картку на пристрій читання карток. - No card reader detected. Please make sure that an USB card reader is connected or a smartphone as card reader is paired and available. Open the reader settings to configure readers and get more information about supported readers. INFO DESKTOP AA2 is waiting for the card reader or the ID card. @@ -1755,301 +1601,92 @@ LABEL ANDROID IOS Перейти до параметрів пристрою читання - The device "%1" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. - INFO ANDROID IOS The paired smartphone was removed since it did not respond to connection attempts. It needs to be paired again before using it. - Пару з пристроєм «%1» було скасовано, оскільки він не реагував на спроби підключення. Створіть пару з пристроєм знову, щоб використовувати його як пристрій читання карток. + No ID card detected. Please follow the instructions on your smartphone (connected to %1) to use it as card reader. + INFO DESKTOP The AA2 is waiting for the smartphone to be placed on the id. + + + + Please follow the instructions on your smartphone (connected to %1) or put the ID card on the card reader. + INFO DESKTOP The AA2 is waiting for an ID card to be inserted into the card reader (or smartphone for that matter). + Hint Hint + LABEL DESKTOP +---------- +LABEL ANDROID IOS Підказка - HistoryListItem - - Click to view details of history entry. - LABEL ANDROID IOS - Натисніть, щоб переглянути відомості про запис в історії. - + LanguageButtonData - Tap for more details - LABEL ANDROID IOS - Торкніться, щоб отримати докладніші відомості + German + LABEL ALL_PLATFORMS + Німецька - - - HistoryListViewDelegate - Delete entry - LABEL ANDROID - Видалити запис + Set language to german + LABEL ALL_PLATFORMS + Вибрати німецьку мову - Delete history entry: %1 - INFO IOS Accessible name for the trash icon of a history entry. - Видалити запис із історії: %1 + English + LABEL ALL_PLATFORMS + Англійська - - - HistoryRemovalTimePeriodControl - Time period - LABEL DESKTOP - Період часу + Set language to english + LABEL ALL_PLATFORMS + Вибрати англійську мову - Past hour - LABEL DESKTOP - Минула година + Ukrainian + LABEL ALL_PLATFORMS + Українська - Past day - LABEL DESKTOP - Минулий день + Set language to ukrainian + LABEL ALL_PLATFORMS + Вибрати українську мову - Past week - LABEL DESKTOP - Минулий тиждень + Russian + LABEL ALL_PLATFORMS + Російська - Last four weeks - LABEL DESKTOP - Останні чотири тижні + Set language to russian + LABEL ALL_PLATFORMS + Использовать русский язык + + + LicenseInformation - All history - LABEL DESKTOP - Уся історія + Software license + LABEL ANDROID IOS + Ліцензія на програмне забезпечення - HistoryView + LocalNetworkInfo - Delete history? - INFO DESKTOP Header of the confirmation dialog to clear the entire authentication history. - Видалити історію? + Go to application settings + INFO IOS Link to application settings + Перейти до параметрів програми - All history entries will be deleted. - INFO DESKTOP Content of the confirmation dialog to clear the entire authentication history. - Усі записи в історії буде видалено. + Ensure that access to the local network is allowed in your settings. + INFO IOS Let user know to check the application settings for local network permission + Переконайтеся, що доступ до локальної мережі дозволено. - - Deleted %1 entries from the history. - INFO DESKTOP Feedback how many history entries were removed. - Видалено записи з історії (%1). - - - History - LABEL DESKTOP - Історія - - - Search in history - LABEL DESKTOP - Пошук в історії - - - Clear history - LABEL DESKTOP - Очистити історію - - - Save as PDF... - LABEL DESKTOP - Зберегти як файл PDF… - - - Portable Document Format (*.pdf) - LABEL DESKTOP - Файл формату Adobe Portable Document Format (*.pdf) - - - Currently there are no history entries. - INFO DESKTOP No authentication history, placeholder text. - Наразі записів в історії немає. - - - No history entries match your search term. - INFO DESKTOP No authentication history entries match the search, placeholder text. - Жоден запис в історії не відповідає вашому пошуковому запиту. - - - Delete all entries - LABEL IOS - Видалити всі записи - - - Save history - LABEL DESKTOP - Зберегти історію - - - - HistoryViewConfirmationPopup - - Delete history - LABEL ANDROID IOS - Видалити історію - - - All history entries will be deleted. - LABEL ANDROID IOS Confirmaton popup to clear all history entries. - Усі записи в історії буде видалено. - - - Delete - LABEL ANDROID IOS - Видалити - - - - HistoryViewDetails - - Details for history entry - Відомості про запис в історії - - - Provider Information - LABEL ANDROID IOS - Інформація про постачальника - - - Provider name - LABEL DESKTOP ----------- -LABEL ANDROID IOS - Назва постачальника - - - Purpose - LABEL DESKTOP ----------- -LABEL ANDROID IOS - Мета - - - Date - LABEL DESKTOP ----------- -LABEL ANDROID IOS - Дата - - - dd.MM.yyyy - LABEL DESKTOP Date format according to https://doc.qt.io/qt/qdate.html#toString ----------- -LABEL ANDROID IOS Date format according to https://doc.qt.io/qt/qdate.html#toString - dd.MM.yyyy - - - Write access (update) - LABEL DESKTOP ----------- -LABEL ANDROID IOS - Доступ для записування (оновлення) - - - Read access - LABEL DESKTOP ----------- -LABEL ANDROID IOS - Доступ для читання - - - Terms of usage - LABEL DESKTOP ----------- -LABEL ANDROID IOS - Умови використання - - - - HistoryViewTitleBarControls - - Delete all entries - LABEL ANDROID - Видалити всі записи - - - - LanguageButtons - - German - LABEL ALL_PLATFORMS - Німецька - - - Set language to german - LABEL ALL_PLATFORMS - Вибрати німецьку мову - - - English - LABEL ALL_PLATFORMS - Англійська - - - Set language to english - LABEL ALL_PLATFORMS - Вибрати англійську мову - - - Ukrainian - LABEL ALL_PLATFORMS - Українська - - - Set language to ukrainian - LABEL ALL_PLATFORMS - Вибрати українську мову - - - Russian - LABEL ALL_PLATFORMS - Російська - - - Set language to russian - LABEL ALL_PLATFORMS - Использовать русский язык - - - - LanguageSelectionPopup - - Select language - LABEL ANDROID IOS - Вибрати мову - - - - LicenseInformation - - Software license - LABEL ANDROID IOS - Ліцензія на програмне забезпечення - - - - LocalNetworkInfo - - Go to application settings - INFO IOS Link to application settings - Перейти до параметрів програми - - - Ensure that access to the local network is allowed in your settings. - INFO IOS Let user know to check the application settings for local network permission - Переконайтеся, що доступ до локальної мережі дозволено. - - - - LogTitleBarControls + + + LogTitleBarControls Share log Надати спільний доступ до журналу @@ -2164,6 +1801,14 @@ INFO ANDROID IOS The current logfile is about to be removed, user confirmation r Наразі немає жодних записів журналу, що відповідають цьому фільтру. + + LogViewDelegate + + The log entry was copied to the clipboard. + INFO DESKTOP Toast message used to confirm the copy of a log entry. + Запис журналу скопійовано до буфера обміну. + + MainView @@ -2171,28 +1816,11 @@ INFO ANDROID IOS The current logfile is about to be removed, user confirmation r LABEL DESKTOP Дивитися мої<br>особисті дані - - Provider - LABEL DESKTOP ----------- -LABEL ANDROID IOS - Постачальник - - - History - LABEL DESKTOP - Історія - Settings LABEL DESKTOP Параметри - - Change my<br>(Transport) PIN - LABEL DESKTOP - Змінити мій<br>(транспортний) PIN-код - Help LABEL DESKTOP @@ -2208,11 +1836,6 @@ LABEL ANDROID IOS LABEL ANDROID IOS Перевірити пристрій та ID-картку - - Change my (Transport) PIN - LABEL ANDROID IOS - Змінити мій (транспортний) PIN-код - See my personal data LABEL ANDROID IOS @@ -2223,6 +1846,25 @@ LABEL ANDROID IOS LABEL ANDROID IOS Smart-eID + + Two finger swipe to scroll. + + + + List of workflows with %1 items. + + + + Item %1 of %2 + + + + Change PIN + LABEL DESKTOP +---------- +LABEL ANDROID IOS + Змінити PIN-код + MoreInformationLink @@ -2246,11 +1888,6 @@ LABEL ANDROID IOS LABEL DESKTOP Загальні - - Diagnosis and logs - LABEL DESKTOP - Діагностика й журнали - Version information LABEL DESKTOP @@ -2260,9 +1897,7 @@ LABEL ANDROID IOS Software license - LABEL DESKTOP ----------- -LABEL ANDROID IOS + LABEL DESKTOP Ліцензія на програмне забезпечення @@ -2277,255 +1912,137 @@ LABEL ANDROID IOS LABEL ANDROID IOS Довідка та зворотний зв’язок - - Tutorial - LABEL ANDROID IOS - Посібник - - - Do you want to know how to use %1? - LABEL ANDROID IOS - Хочете дізнатися, як використовувати %1? - - - Video tutorials - LABEL ANDROID IOS - Відеопосібники - - - Do you want to see the video tutorials? - LABEL ANDROID IOS - Бажаєте дивитися відеопосібники? - - - FAQ - LABEL ANDROID IOS - Запитання й відповіді - - - Do you have further questions about %1? - LABEL ANDROID IOS - Маєте додаткові запитання про %1? - - - Support - LABEL ANDROID IOS - Підтримка - - - Do you need further support? - LABEL ANDROID IOS - Потрібна додаткова підтримка? - Privacy statement LABEL ANDROID IOS Заява про конфіденційність - - Do you want to read the privacy statement? - LABEL ANDROID IOS - Бажаєте прочитати заяву про конфіденційність? - Accessibility statement LABEL ANDROID IOS Заява про спеціальні можливості - - Do you want to read the accessibility statement? - LABEL ANDROID IOS - Бажаєте прочитати заяву про спеціальні можливості? - Rate %1 LABEL ANDROID IOS Оцінити %1 - - Do you want to rate us in the App Store? - LABEL ANDROID IOS - Бажаєте оцінити нас у магазині App Store? - - - Do you want to rate us in the Google Play Store? - Бажаєте оцінити нас у магазині Google Play? - - - Diagnosis - LABEL ANDROID IOS - Діагностика - Logs LABEL ANDROID IOS Журнали - Do you want to view the logs of %1? + Information LABEL ANDROID IOS - Бажаєте переглянути журнали %1? + Інформація - Report error + List of Providers LABEL ANDROID IOS - Повідомити про помилку + + + + Data and logs + LABEL DESKTOP + Діагностика й журнали - Did you find a bug? Please help us by sending us the log file together with a description of the error. + FAQ - Frequently asked questions LABEL ANDROID IOS - Знайшли помилку? Допоможіть нам, надіславши нам файл журналу разом з описом помилки. + Запитання й відповіді - Information + Contact LABEL ANDROID IOS - Інформація + Підтримка - Do you want to see detailed information about %1? + Show Logs LABEL ANDROID IOS - Бажаєте дивитися докладну інформацію про %1? + Журнали - Do you want to read the software licenses? + Send log to the support LABEL ANDROID IOS - Бажаєте ознайомитися з ліцензіями на програмне забезпечення? + Повідомити про помилку - Do you want to view the release notes of %1? + Terms of use and software license LABEL ANDROID IOS - Бажаєте переглянути примітки до випуску %1? + Ліцензія на програмне забезпечення MoreViewDiagnosis - Diagnosis + Logs LABEL DESKTOP - Діагностика + Журнали - You can view and save the diagnosis information of the AusweisApp2 and your system here. + Show logs LABEL DESKTOP - Тут можна переглянути й зберегти інформацію про діагностику програми AusweisApp2 та вашої системи. + Показати журнали - Show diagnosis + Show system data LABEL DESKTOP - Показати діагностику + Показати діагностику - Logs + System data LABEL DESKTOP - Журнали - - - Do you want to view the logs of %1? - LABEL DESKTOP - Бажаєте переглянути журнали %1? - - - Show logs - LABEL DESKTOP - Показати журнали - - - Report error - LABEL DESKTOP - Повідомити про помилку - - - Did you find a bug? Please help us by sending us the log file together with a description of the error. - LABEL DESKTOP - Знайшли помилку? Допоможіть нам, надіславши нам файл журналу разом з описом помилки. - - - Open website - LABEL DESKTOP - Відкрити сайт + Діагностика MoreViewGeneral - - Online help - LABEL DESKTOP - Онлайн-довідка - - - Do you have questions about %1? - LABEL DESKTOP - Маєте запитання про %1? - Open website LABEL DESKTOP Відкрити сайт - - Video tutorials - LABEL DESKTOP - Відеопосібники - - - Do you want to see the video tutorials? - LABEL DESKTOP - Бажаєте дивитися відеопосібники? - - - FAQ - LABEL DESKTOP - Запитання й відповіді - - - Do you have further questions about %1? - LABEL DESKTOP - Маєте додаткові запитання про %1? - - - Support - LABEL DESKTOP - Підтримка - - - Do you need further support? - LABEL DESKTOP - Потрібна додаткова підтримка? - Privacy statement LABEL DESKTOP Заява про конфіденційність - - Do you want to read the privacy statement? - LABEL DESKTOP - Бажаєте прочитати заяву про конфіденційність? - Accessibility statement LABEL DESKTOP Заява про спеціальні можливості - Do you want to read the accessibility statement? + Do you want to see a list of service providers? LABEL DESKTOP - Бажаєте прочитати заяву про спеціальні можливості? + - Setup assistant + List of Providers LABEL DESKTOP - Помічник з налаштування + - Do you want to run the setup assistant again? + FAQ - Frequently asked questions LABEL DESKTOP - Бажаєте знову запустити помічник з налаштування? + Запитання й відповіді - Start setup assistant + Contact LABEL DESKTOP - Запустити помічник з налаштування + Підтримка + + + + NavigationAction + + Cancel + Скасувати + + + Back + Назад @@ -2549,18 +2066,10 @@ LABEL ANDROID IOS NavigationView - - History - Історія - Start Почати - - Provider - Постачальник - Settings Параметри @@ -2702,6 +2211,7 @@ LABEL ANDROID IOS Delete last digit, disabled until input is present. + LABEL ANDROID IOS A11y text for the "delete" button text when the button is disabled. Видалити останній знак, вимкнено до введення. @@ -2783,21 +2293,11 @@ LABEL ANDROID IOS LABEL ALL_PLATFORMS Інформація про PIN-код - - The card PIN is a six-digit PIN that you set yourself. You always need this PIN if you want to use the eID function. - INFO ALL_PLATFORMS Answer to the question 'what is the card pin?' - PIN-код картки – це шестизначний PIN-код, який ви встановлюєте самостійно. Цей PIN-код обов’язковий, якщо ви хочете використовувати функцію eID. - Where can I find the card PIN? LABEL ALL_PLATFORMS Де я можу дізнатися PIN-код картки? - - You set the card PIN either directly when you picked up your ID card at the citizens' office (Bürgeramt) or later in AusweisApp2 using the five-digit Transport PIN. Only when you have set a six-digit PIN of your own choice can you use the eID function. - INFO ALL_PLATFORMS Answer to the question 'Where can I find the card PIN?' - Ви встановлюєте PIN-код картки безпосередньо під час отримання ID-картки у відділі обслуговування громадян (Bürgeramt) або пізніше в додатку AusweisApp2 за допомогою п’ятизначного транспортного PIN-коду. Використовувати функцію eID можна лише після самостійного встановлення шестизначного PIN-коду. - How do I choose a secure PIN? LABEL ALL_PLATFORMS @@ -2815,7 +2315,9 @@ LABEL ANDROID IOS Keep your PIN secret and change it if another person becomes aware of it. - INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure PIN?' paragraph 3/3 + INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure PIN?' paragraph 3/3 +---------- +INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure (Smart-eID) PIN?' paragraph 3/3 Тримайте свій PIN-код у таємниці та змініть його, якщо він стане відомий іншій особі. @@ -2843,21 +2345,6 @@ LABEL ANDROID IOS INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 3/3 Після встановлення PIN-коду картки транспортний PIN-код втрачає чинність. - - Smartphone as card reader information - LABEL ALL_PLATFORMS - Інформація про смартфон як пристрій читання карток - - - You may use your smartphone as a card reader with AusweisApp2. The smartphone needs to feature a supported NFC chipset and both devices, your smartphone and this machine, need to be connected to the same WiFi network. - INFO ALL_PLATFORMS Description text of SaC pairing - Ви можете використовувати свій смартфон як пристрій читання карток у програмі AusweisApp2. Смартфон повинен мати підтримуваний чіпсет NFC, і обидва пристрої, ваш смартфон і цей пристрій, мають бути підключені до однієї мережі Wi-Fi. - - - To use your smartphone as a card reader you'll always need to activate the remote service in the AusweisApp2 on the smartphone. For the first time you'll also need to start the pairing mode on your smartphone, select the device from the list of available devices on this machine and then enter the pairing code shown on the phone. - INFO ALL_PLATFORMS Description text of SaC pairing - Щоб використовувати смартфон як зчитувач карток, потрібно щоразу активовувати віддалену службу в додатку AusweisApp2 на смартфоні. Уперше вам також потрібно буде запустити режим створення пари на своєму смартфоні, вибрати пристрій зі списку доступних пристроїв на цьому апараті, а потім ввести код створення пари, показаний на телефоні. - Where do I find the PUK? LABEL ALL_PLATFORMS @@ -2987,7 +2474,7 @@ LABEL ALL_PLATFORMS Your ID card comes with a five-digit 'Transport PIN' which you need to replace with a six-digit PIN that you choose yourself. - INFO ALL_PLATFORMS Description text explaining the PINs 1/6 + INFO ALL_PLATFORMS Description text explaining the PINs 1/7 До вашої ID-картки додається п’ятизначний « PIN-код», який вам потрібно змінити на шестизначний PIN-код, який ви обираєте самостійно. @@ -2995,36 +2482,11 @@ LABEL ALL_PLATFORMS LABEL ALL_PLATFORMS П’ятизначний транспортний PIN-код - - The five-digit Transport PIN was sent to you by post after you applied for your ID card. - INFO ALL_PLATFORMS Description text explaining the PINs 2/6 - П’ятизначний транспортний PIN-код був надісланий вам у листі поштою після того, як ви подали заяву на отримання ID-картки. - - - The PIN can only be used once. When you set up the eID function, you will replace this five-digit PIN with a six-digit PIN that you choose yourself. - INFO ALL_PLATFORMS Description text explaining the PINs 3/6 - Цей PIN-код можна використати лише один раз. Коли ви налаштуєте функцію eID, ви заміните цей п’ятизначний PIN-код на шестизначний PIN-код, який ви оберете самостійно. - Six-digit PIN LABEL ALL_PLATFORMS Шестизначний PIN-код - - This is a number that you choose yourself when you set up the eID function for the first time. It replaces your five-digit Transport PIN. - INFO ALL_PLATFORMS Description text explaining the PINs 4/6 - Це код, який ви обираєте самостійно, коли вперше налаштовуєте функцію eID. Він замінює ваш п’ятизначний транспортний PIN-код. - - - This PIN allows you to prove online that the ID card belongs to you. No one can use your ID card online without this PIN. - INFO ALL_PLATFORMS Description text explaining the PINs 5/6 - Цей PIN-код дозволяє вам підтверджувати онлайн, що ID-картка належить саме вам. Без цього PIN-коду ніхто не зможе скористатися вашою ID-карткою в Інтернеті. - - - You can change your six-digit PIN at any time in AusweisApp2. - INFO ALL_PLATFORMS Description text explaining the PINs 6/6 - Ви можете в будь-який момент змінити свій шестизначний PIN-код у додатку AusweisApp2. - You can use the PIN Reset Service to request a new card PIN free of charge. LABEL ALL_PLATFORMS @@ -3040,6 +2502,96 @@ LABEL ALL_PLATFORMS LABEL ALL_PLATFORMS Hint text for PIN but it is unknown. Якщо ви забули PIN-код картки, ви можете безкоштовно надіслати запит на новий PIN-код, скориставшись службою скидання PIN-коду. + + The five-digit Transport PIN was sent to you by mail after you applied for your ID card. + INFO ALL_PLATFORMS Description text explaining the PINs 2/7 + 5-значний транспортний PIN-код був надісланий вам у листі поштою після того, як ви подали заяву на отримання ID-картки. + + + What is the Smart-eID PIN? + LABEL ALL_PLATFORMS + + + + Set up Smart-eID + LABEL ALL_PLATFORMS + Налаштувати Smart-eID + + + The Smart-eID PIN is a six-digit PIN that you set yourself. You always need this PIN if you want to use your Smart-eID. + INFO ALL_PLATFORMS Answer to the question 'what is the Smart-eID pin?' + + + + For your six-digit Smart-eID PIN, choose a combination of numbers that cannot be guessed - i.e. neither "123456", nor your date of birth, nor any other numbers printed on your ID card. + INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure (Smart-eID) PIN?' paragraph 1/3 + + + + You can change your six-digit Smart-eID PIN at any time and an unlimited number of times as long as you know your valid Smart-eID PIN. + INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure (Smart-eID) PIN?' paragraph 2/3 + + + + The PIN can only be used once. When you set up the eID function, you will replace this five-digit Transport PIN with a six-digit card PIN that you choose yourself. + INFO ALL_PLATFORMS Description text explaining the PINs 3/7 + + + + The six-digit card PIN is a number that you choose yourself when you set up the eID function for the first time. It replaces your five-digit Transport PIN. + INFO ALL_PLATFORMS Description text explaining the PINs 4/7 + + + + The Smart-eID PIN also has six digits. You also choose that PIN yourself while setting up the Smart-eID for the first time. + INFO ALL_PLATFORMS Description text explaining the PINs 5/7 + + + + You can change your card PIN and your Smart-eID PIN at any time in %1. + INFO ALL_PLATFORMS Description text explaining the PINs (%1 is replaced with the application name) 7/7 + + + + With this six-digit PIN you prove online that the ID card or Smart-eID belongs to you. No one can use the eID function without this PIN. + INFO ALL_PLATFORMS Description text explaining the PINs 6/7 + + + + The card PIN is a six-digit PIN that you set yourself. You always need this PIN if you want to use the eID function with your ID card. + INFO ALL_PLATFORMS Answer to the question 'what is the card pin?' + + + + You set the card PIN either directly when you picked up your ID card at the citizens' office (Bürgeramt) or later in %1 using the five-digit Transport PIN. Only when you have set a six-digit PIN of your own choice can you use the eID function and set up a Smart-eID. + INFO ALL_PLATFORMS Answer to the question 'Where can I find the card PIN?' (%1 is replaced with the application name) + + + + If you have forgotten your Smart-eID PIN, you can renew your Smart-eID and thereby set a new PIN. + LABEL ALL_PLATFORMS Hint text for PIN but it is unknown. + + + + Where can I find the Smart-eID PIN? + LABEL ALL_PLATFORMS + + + + You have set the Smart-eID PIN while setting up the Smart-eID. + INFO ALL_PLATFORMS Answer to the question 'Where can I find the Smart-eID PIN?' + + + + With this six-digit PIN you prove online that the ID card belongs to you. No one can use the eID function without this PIN. + INFO ALL_PLATFORMS Description text explaining the PINs 6/7 + + + + You can change your card PIN at any time in %1. + INFO ALL_PLATFORMS Description text explaining the PINs (%1 is replaced with the application name) 7/7 + + PersonalizationController @@ -3106,6 +2658,11 @@ LABEL ALL_PLATFORMS LABEL ANDROID IOS Видаліть свій Smart-eID, перш ніж віддавати комусь або продавати свій смартфон. + + If you uninstall the %1 or reset your smartphone, the Smart-eID must be set up again. + LABEL ANDROID IOS + + PersonalizationProgressView @@ -3164,6 +2721,11 @@ LABEL ALL_PLATFORMS LABEL ANDROID IOS Smart-eID + + Please wait a moment, the current process is being finished. + LABEL ANDROID IOS + + PersonalizationResultView @@ -3202,11 +2764,6 @@ LABEL ALL_PLATFORMS INFO ANDROID IOS Placeholder (error) text if the Smart-eID setup finished successfully but for some reason no blocking code was retrieved Налаштування Smart-eID успішно завершено, але код блокування не отримано. З міркувань безпеки вам слід видалити свій Smart-eID та ще раз почати налаштування. - - You have reached the allowed amount of Smart-eID setups for the current period. You may set up another Smart-eID with your ID card on %1. - LABEL ANDROID IOS - Ви досягли дозволеної кількості налаштувань Smart-eID за поточний період. Ви можете налаштувати інший Smart-eID для своєї ID-картки %1. - Attention: you may only set up <b><u>one</u></b> more Smart-eID with your ID card. Further setups may be carried out on %1. LABEL ANDROID IOS @@ -3255,378 +2812,143 @@ LABEL ALL_PLATFORMS - ProviderContactInfo - - Provider contact information - Контактна інформація постачальника - + ProviderInfoSection - Contact information of the selected provider. - Контактна інформація вибраного постачальника. + See details under "more..." + LABEL DESKTOP + Див. відомості в розділі «Додаткова інформація» - Contact + Show more information about the service provider LABEL DESKTOP - Контакти + Показати додаткову інформацію про постачальника послуг - Unknown + Details about the provider LABEL DESKTOP - Невідомо + Відомості про постачальника - ProviderDetailButtonBar + ProxyCredentialsPopup - To provider - LABEL DESKTOP + Sign in + LABEL DESKTOP Text of the button in the proxy credentials popup. ---------- -LABEL ANDROID_TABLET IOS_TABLET - До постачальника - - - - ProviderDetailDescription - - Description - LABEL ANDROID_TABLET IOS_TABLET - Опис - - - The provider did not provide a description. - LABEL ANDROID_TABLET IOS_TABLET - Постачальник не надав опис. +LABEL DESKTOP Title of the proxy credentials popup. + Увійти - - - ProviderDetailHistory - List of your past interactions with this provider - Список ваших минулих взаємодій із цим постачальником + The proxy %1 requires username and password. + LABEL DESKTOP Text of the proxy credentials popup. An example for %1 is http://proxy.example.com:1337. + Для проксі-сервера %1 потрібні ім’я користувача та пароль. - The list is empty, no recorded interaction with this provider. - Список порожній, взаємодію з цим постачальником не зафіксовано. + Proxy credential username + LABEL DESKTOP Accessible name. + Ім’я користувача облікових даних проксі-сервера - Currently there are no history entries. - INFO DESKTOP No authentication history, placeholder text. ----------- -INFO ANDROID_TABLET IOS_TABLET No authentication history, placeholder text. - Наразі записів в історії немає. + Username + LABEL DESKTOP Label of the textfield for the username. + Ім’я користувача - History - LABEL ANDROID_TABLET IOS_TABLET - Історія + Proxy credential password + LABEL DESKTOP Accessible name. + Пароль облікових даних проксі-сервера - Purpose for reading out requested data - LABEL ANDROID_TABLET IOS_TABLET - Мета зчитування запитуваних даних + Password + LABEL DESKTOP Label of the textfield for the password. + Пароль - ProviderDetailHistoryInfo - - Provider - LABEL ANDROID_TABLET IOS_TABLET - Постачальник - + QObject - Purpose for reading out requested data - LABEL ANDROID_TABLET IOS_TABLET - Мета зчитування запитуваних даних + An error occurred in log handling: %1 + LABEL ALL_PLATFORMS + Під час обробки журналу сталася помилка: %1 - Read data - LABEL ANDROID_TABLET IOS_TABLET - Зчитати дані + Please describe the error that occurred. + Опишіть помилку, яка сталася. - Terms of usage - LABEL ANDROID_TABLET IOS_TABLET - Умови використання + You may want to attach the logfile which can be saved from the error dialog. + Ви можете прикріпити файл журналу, який можна зберегти з діалогового вікна помилки. - - - ProviderDetailHistoryItem - Service: - LABEL DESKTOP - Служба: + Error code + Код помилки - Provider: - LABEL DESKTOP - Постачальник: + Service URL + URL-адреса служби - Click to view details of history entry. - Натисніть, щоб переглянути відомості про запис в історії. + Parameter of occurred error: + Параметр помилки: - Touch for more details - LABEL ANDROID IOS - Торкніться, щоб отримати докладніші відомості + Critical errors: + Критичні помилки: - ProviderDetailView - - Description - LABEL DESKTOP - Опис - - - The provider did not provide a description. - LABEL DESKTOP - Постачальник не надав опис. - + ReaderConfigurationInfo - History - LABEL DESKTOP - Історія + Unknown reader + LABEL ALL_PLATFORMS + Невідомий пристрій читання - ProviderGridView + ReleaseNotes - No results matching your search query found - LABEL DESKTOP IOS_TABLET ANDROID_TABLET The text entered into the provider search field results in no matches - Не знайдено збігів за вашим пошуковим запитом + Retry + LABEL DESKTOP +---------- +LABEL ANDROID IOS + Повторити спробу - - - ProviderHeader - To provider + Release notes LABEL ANDROID IOS - До постачальника - - - - ProviderInfoSection - - See details under "more..." - LABEL DESKTOP - Див. відомості в розділі «Додаткова інформація» + Примітки до випуску - ProviderListItemDelegate + RemoteReaderDelegate - Open provider details for %1 - Відкрити відомості про постачальника для %1 + Smartphone named "%1" + Смартфон під іменем «%1» - Click to set category filter to %1 - Натисніть, щоб установити фільтр категорії %1 + Press space to unpair the smartphone "%1". + Натисніть пробіл, щоб скасувати пару зі смартфоном «%1». - - - ProviderModelItem - Click to open homepage. - INFO ALL_PLATFORMS A11y action text appended to provider homepage to be read read by screen reader. - Натисніть, щоб відкрити домашню сторінку. + Press space to pair the smartphone "%1". + Натисніть пробіл, щоб створити пару зі смартфоном «%1». - Click to send email. - INFO ALL_PLATFORMS A11y action text appended to provider mail to be read read by screen reader. - Натисніть, щоб надіслати електронний лист. + Remove remote device + Видаліть віддалений пристрій + + + RemoteReaderView - Costs + Paired devices LABEL DESKTOP - Вартість + З’єднані пристрої - Click to call. - INFO ALL_PLATFORMS A11y action text appended to provider phone number to be read read by screen reader. - Натисніть, щоб зателефонувати. - - - Click to open map. - INFO ALL_PLATFORMS A11y action text appended to provider address maps url to be read read by screen reader. - Натисніть, щоб відкрити мапу. - - - Homepage - Домашня сторінка - - - E-Mail - Електронна пошта - - - Phone - Телефон - - - Address - Адреса - - - - ProviderOverview - - All provider - LABEL DESKTOP - Усі постачальники - - - Citizen services - LABEL DESKTOP - Послуги для громадян - - - Financials - LABEL DESKTOP - Фінанси - - - Insurances - LABEL DESKTOP - Страхування - - - Other services - LABEL DESKTOP - Інші послуги - - - - ProviderView - - Provider - LABEL DESKTOP - Постачальник - - - Search providers - LABEL DESKTOP - Шукати постачальників - - - - ProxyCredentialsPopup - - Sign in - LABEL DESKTOP Text of the button in the proxy credentials popup. ----------- -LABEL DESKTOP Title of the proxy credentials popup. - Увійти - - - The proxy %1 requires username and password. - LABEL DESKTOP Text of the proxy credentials popup. An example for %1 is http://proxy.example.com:1337. - Для проксі-сервера %1 потрібні ім’я користувача та пароль. - - - Proxy credential username - LABEL DESKTOP Accessible name. - Ім’я користувача облікових даних проксі-сервера - - - Username - LABEL DESKTOP Label of the textfield for the username. - Ім’я користувача - - - Proxy credential password - LABEL DESKTOP Accessible name. - Пароль облікових даних проксі-сервера - - - Password - LABEL DESKTOP Label of the textfield for the password. - Пароль - - - - QObject - - An error occurred in log handling: %1 - LABEL ALL_PLATFORMS - Під час обробки журналу сталася помилка: %1 - - - Please describe the error that occurred. - Опишіть помилку, яка сталася. - - - You may want to attach the logfile which can be saved from the error dialog. - Ви можете прикріпити файл журналу, який можна зберегти з діалогового вікна помилки. - - - Error code - Код помилки - - - Service URL - URL-адреса служби - - - Parameter of occurred error: - Параметр помилки: - - - Critical errors: - Критичні помилки: - - - - ReaderConfigurationInfo - - Unknown reader - LABEL ALL_PLATFORMS - Невідомий пристрій читання - - - - ReleaseNotes - - Retry - LABEL DESKTOP ----------- -LABEL ANDROID IOS - Повторити спробу - - - Release notes - LABEL ANDROID IOS - Примітки до випуску - - - - RemoteReaderDelegate - - Smartphone named "%1" - Смартфон під іменем «%1» - - - Press space to unpair the smartphone "%1". - Натисніть пробіл, щоб скасувати пару зі смартфоном «%1». - - - Press space to pair the smartphone "%1". - Натисніть пробіл, щоб створити пару зі смартфоном «%1». - - - Remove remote device - Видаліть віддалений пристрій - - - - RemoteReaderView - - Paired devices - З’єднані пристрої - - - Add pairing - Додавання пари + Add pairing + LABEL DESKTOP + Додавання пари Open the %1 on your Smartphone as card reader. @@ -3649,6 +2971,7 @@ LABEL ANDROID IOS Last connected + LABEL DESKTOP Останнє з’єднання @@ -3659,6 +2982,11 @@ LABEL ANDROID IOS RemoteServiceController + + Remote service + LABEL ANDROID IOS + Віддалена служба + You are about to identify yourself towards the following provider using the device "%1": LABEL ANDROID IOS @@ -3669,11 +2997,6 @@ LABEL ANDROID IOS LABEL ANDROID IOS Пристрій читання карток - - Remote service - LABEL ANDROID IOS - Віддалена служба - RemoteServiceSettings @@ -3761,7 +3084,7 @@ To do this you first have to pair that device with this smartphone. Paired Devices - INFO ANDROID IOS + LABEL ANDROID IOS З’єднані пристрої @@ -3807,6 +3130,11 @@ To do this you first have to pair that device with this smartphone. RemoteServiceViewRemote + + Click to remove device + LABEL ANDROID IOS + Натисніть, щоб видалити пристрій + Remove pairing INFO ANDROID IOS @@ -3842,11 +3170,6 @@ To do this you first have to pair that device with this smartphone. LABEL ANDROID IOS Додавання пари - - Click to remove device - LABEL ANDROID IOS - Натисніть, щоб видалити пристрій - Last connected LABEL ANDROID IOS @@ -3904,9 +3227,9 @@ To do this you first have to pair that device with this smartphone. Підключений смартфон як пристрій читання карток (SaC) не відповідає технічним вимогам (Extended Length не підтримується). - Connected to %1. Please place the NFC interface of the smartphone on your ID card. + Connected to %1. Please follow the instructions on the connected smartphone. INFO ANDROID IOS The connection to the smartphone was established, the ID card may be inserted. - Підключено до %1. Розташуйте інтерфейс NFC смартфона на своїй ID-картці. + Manage pairings @@ -3926,10 +3249,6 @@ To do this you first have to pair that device with this smartphone. ResultErrorView - - Show error details - Показати відомості про помилку - Details Відомості @@ -3969,109 +3288,15 @@ To do this you first have to pair that device with this smartphone. - ScreenOrientationSelectionPopup - - Select screen orientation - LABEL ANDROID - Вибрати орієнтацію екрана - - - Set screen orientation to portrait - LABEL ANDROID - Установити книжкову орієнтацію екрана - - - Portrait - LABEL ANDROID - Книжкова - - - recommended - рекомендовано - - - Set screen orientation to landscape - LABEL ANDROID - Установити альбомну орієнтацію екрана - - - Landscape - LABEL ANDROID - Альбомна - - - Using a screen orientation unfit for your device may result in display errors. - LABEL ANDROID - Використання орієнтації екрана, непридатної для вашого пристрою, може призвести до помилок відображення. - - - - SearchBar - - Search - LABEL DESKTOP ----------- -LABEL ANDROID - Пошук - - - Clear - Очистити - - - Type provider to search for - LABEL ANDROID - Уведіть постачальника для пошуку - - - Abort search - LABEL ANDROID - Перервати пошук - - - Search provider list - LABEL ANDROID - Список постачальників для пошуку - - - Enter search string - Увести пошуковий запит - - - Search providers - Шукати постачальників - - - Clear search string - Очистити пошуковий запит - + RetryCounter - Cancel - LABEL IOS - Скасувати + Remaining ID card PIN attempts: %1 + LABEL DESKTOP + Залишилося стільки спроб введення PIN-коду ID-картки: %1 SecurityAndPrivacySettings - - History - LABEL DESKTOP - Історія - - - Save authentication history - LABEL DESKTOP - Зберегти історію автентифікації - - - Clear entire history - LABEL DESKTOP - Очистити всю історію - - - History is empty - Історія пуста - Onscreen keypad LABEL DESKTOP @@ -4082,16 +3307,6 @@ LABEL ANDROID LABEL DESKTOP Використовувати екранну клавіатуру для введення PIN-коду - - Shuffle keypad buttons - LABEL DESKTOP - Кнопки клавіатури в довільному порядку - - - Visual feedback when pressing keypad buttons - LABEL DESKTOP - Візуальний відгук під час натискання кнопок клавіатури - Software updates LABEL DESKTOP @@ -4133,19 +3348,19 @@ LABEL ANDROID Інформація про оновлення недоступна, перевірте наявність оновлення вручну. - Delete history + Shuffle digits of on screen keypad LABEL DESKTOP - Видалити історію + Кнопки клавіатури в довільному порядку - All history entries will be deleted. - INFO DESKTOP The current history is about to be removed, user confirmation required. - Усі записи в історії буде видалено. + Button animation + LABEL DESKTOP + Візуальний відгук під час натискання кнопок клавіатури - Deleted %1 entries from the history. - INFO DESKTOP Feedback how many history entries were removed. - Видалено записи з історії (%1). + Visually highlight key presses on screen keypad + LABEL DESKTOP + @@ -4166,34 +3381,17 @@ LABEL ANDROID Зчитати дані - Save as PDF... - LABEL DESKTOP - Зберегти як файл PDF… - - - Information - Інформація - - - Portable Document Format (*.pdf) - LABEL DESKTOP - Файл формату Adobe Portable Document Format (*.pdf) - - - OK - LABEL DESKTOP - OK + OK + LABEL DESKTOP +---------- +LABEL ANDROID IOS + OK Identify LABEL ANDROID IOS Ідентифікувати - - Save read self-authentication data - LABEL DESKTOP - Зберегти зчитані дані самоавтентифікації - SelfAuthenticationView @@ -4232,6 +3430,16 @@ LABEL ANDROID IOS LABEL ANDROID IOS Дивитися мої особисті дані + + Self-authentication + LABEL ANDROID IOS + + + + Hint + LABEL ANDROID IOS + Підказка + SettingsView @@ -4287,1607 +3495,670 @@ LABEL ANDROID IOS LABEL ANDROID IOS Змінити мову - - Screen orientation - LABEL ANDROID - Орієнтація екрана - - - Landscape - LABEL ANDROID - Альбомна - - - Portrait - LABEL ANDROID - Книжкова - Device name - LABEL ANDROID IOS - Назва пристрою - - - PIN pad mode - LABEL ANDROID IOS - Режим клавіатури для вводу PIN-коду - - - Enter PIN on this device - LABEL ANDROID IOS - Введіть PIN-код на цьому пристрої - - - Save history - LABEL ANDROID IOS - Зберегти історію - - - Save authentication history - LABEL ANDROID IOS - Зберегти історію автентифікації - - - History - LABEL ANDROID IOS ----------- -LABEL ALL_PLATFORMS - Історія - - - View authentication history - LABEL ANDROID IOS - Переглянути історію автентифікації - - - Shuffle keypad buttons - LABEL ANDROID IOS - Кнопки клавіатури в довільному порядку - - - Randomize the order of the on screen keypad buttons - LABEL ANDROID IOS - Налаштувати довільний порядок кнопок на екранній клавіатурі - - - Keypad animations - LABEL ANDROID IOS - Анімація клавіатури - - - Visual feedback when pressing keypad buttons - LABEL ANDROID IOS - Візуальний відгук під час натискання кнопок клавіатури - - - CAN allowed mode - LABEL ANDROID IOS - Дозволений режим CAN - - - Support CAN allowed mode - LABEL ANDROID IOS - Підтримувати дозволений режим CAN - - - Allow the id card to be used with only the CAN - LABEL ANDROID IOS - Дозволити використовувати ID-картку лише з CAN - - - Skip rights page - LABEL ANDROID IOS - Пропустити сторінку прав - - - Do not show the rights page, when in can allowed mode - LABEL ANDROID IOS - Не показувати сторінку прав у дозволеному режимі CAN - - - Testmode for the self-authentication - LABEL ANDROID IOS - Тестовий режим для самоавтентифікації - - - Use the test environment during a self-authentication - LABEL ANDROID IOS - Використовувати тестове середовище під час самоавтентифікації - - - Internal card simulator - LABEL ANDROID IOS - Внутрішній симулятор картки - - - Enable internal card simulator - LABEL ANDROID IOS - Увімкнути внутрішній симулятор картки - - - Developer mode - LABEL ANDROID IOS - Режим розробника - - - Use a more tolerant mode - LABEL ANDROID IOS - Використовувати стійкіший режим - - - Layout style - LABEL ANDROID IOS - Стиль макета - - - Create dummy entries - LABEL ANDROID IOS - Створити фіктивні записи - - - New Logfile - LABEL ALL_PLATFORMS - Новий файл журналу - - - 15 days old Logfile - LABEL ALL_PLATFORMS - Файл журналу строком 15 днів - - - Show requested rights on this device as well - LABEL ANDROID IOS - Показати запит на права також на цьому пристрої - - - Show access rights - LABEL ANDROID IOS - Показати права доступу - - - Manage paired devices and add new devices - LABEL ANDROID IOS - Керування з’єднаними пристроями й додавання нових пристроїв - - - Manage pairings - LABEL ANDROID IOS - Керування створенням пари - - - - SetupAssistantView - - Setup Assistant - LABEL DESKTOP - Помічник з налаштування - - - Welcome to the AusweisApp2. Please take a few moments to set up the environment to your needs. Every decision you make can later be changed in the settings menu. - INFO DESKTOP Welcome message when starting the setup assistant. - Вітаємо в програмі AusweisApp2! Приділіть кілька хвилин, щоб налаштувати середовище відповідно до своїх потреб. Кожне прийняте вами рішення пізніше можна буде змінити в меню параметрів. - - - Do you want to automatically start the %1 after boot? - INFO DESKTOP Question if the App shall be started automatically after boot - Автоматично запускати %1 після завантаження? - - - In order to successfully use the eID function, %1 has to be running. It is therefore advisable to activate the auto-start after system startup. - INFO DESKTOP Information text why autostart of the App is advisable - Для успішного використання функції онлайн-ідентифікації має бути запущено %1. Тому рекомендовано активувати автозапуск після запуску системи. - - - The launch will add an icon to the menu bar. - INFO MACOS Additional information that macOS auto-start add a symbol to the menu bar - Після запуску до рядка меню буде додано піктограму. - - - Auto-start Setting - LABEL DESKTOP - Налаштування автозапуску - - - Do you want to save a history of performed authentications on your device? - INFO DESKTOP Question if the authentication history shall be stored. - Зберегти історію виконаних автентифікацій на вашому пристрої? - - - The history is only saved locally. You can use it to see on what date you transmitted which data to which party. After enabling the history you can view and delete the entries anytime. - INFO DESKTOP Information text which data is stored in the history record. - Історія зберігається лише локально. Ви можете використовувати її, щоб бачити, в який день і які дані ви передали якій стороні. Після ввімкнення історії ви можете будь-коли переглядати й видаляти записи. - - - History Setting - LABEL DESKTOP - Налаштування історії - - - Do you want to set up a card reader <u>now</u>? - INFO DESKTOP Question if the the user wants to setup any card readers now. - Бажаєте налаштувати пристрій читання карток <u>зараз</u>? - - - In order to use the online identification feature on the computer, you need to set up a suitable smartphone or card reader before the first authentication process. - INFO DESKTOP Information text why a card reader is required to use the online - Щоб використовувати функцію онлайн-ідентифікації на комп’ютері, перед першим процесом автентифікації необхідно налаштувати відповідний смартфон або пристрій читання карток. - - - Card Readers - LABEL DESKTOP - Пристрої читання карток - - - You have completed the setup of the AusweisApp2 successfully. - INFO DESKTOP Success message after completing the setup assistant. - Ви успішно завершили налаштування AusweisApp2. - - - Proceed to start page - INFO DESKTOP A11y button text to exit the setup assistant. - Перейти до початкової сторінки - - - - SimulatorWorkflow - - Simulator - LABEL ANDROID IOS - Симулятор - - - Continue - LABEL ANDROID IOS - Продовжити - - - - SmartDeleteStartView - - Delete Smart-eID - LABEL ANDROID IOS - Видалити Smart-eID - - - Are you sure you want to delete the Smart-eID? - LABEL ANDROID IOS - Справді видалити Smart-eID? - - - Delete - LABEL ANDROID IOS - Видалити - - - Smart-eID - LABEL ANDROID IOS - Smart-eID - - - If you want to use that functionality again, you need to set up a new Smart-eID first. - LABEL ANDROID IOS - Якщо ви хочете знову використовувати цю функцію, вам спочатку потрібно налаштувати новий Smart-eID. - - - Reset Smart-eID - LABEL ANDROID IOS - Скинути Smart-eID - - - - SmartMainView - - Updating Smart-eID status... - LABEL ANDROID IOS - Триває оновлення статусу Smart-eID… - - - Smart-eID not supported - LABEL ANDROID IOS - Smart-eID не підтримується - - - Smart-eID invalid - LABEL ANDROID IOS - Smart-eID недійсний - - - Smart-eID ready for use - LABEL ANDROID IOS - Smart-eID готовий до використання - - - Smart-eID supported - LABEL ANDROID IOS - Smart-eID підтримується - - - Please wait a moment. - LABEL ANDROID IOS - Трохи зачекайте. - - - Unfortunately, this functionality is not supported by your device. - LABEL ANDROID IOS - На жаль, ця функція не підтримується на вашому пристрої. - - - Your Smart-eID is in an invalid state. You need to set it up again to perform online identifications without your ID card. - LABEL ANDROID IOS - Ваш Smart-eID має недійсний статус. Вам потрібно знову налаштувати його, щоб виконувати онлайн-ідентифікацію без своєї ID-картки. - - - Your Smart-eID is set up and ready for use. You can now perform online identifications without your ID card if supported by the provider. - LABEL ANDROID IOS - Ваш Smart-eID налаштований і готовий до використання. Тепер ви можете виконувати онлайн-ідентифікацію без своєї ID-картки, якщо це підтримується постачальником. - - - Set up a Smart-eID in order to perform online identifications without your ID card if supported by the provider. - LABEL ANDROID IOS - Налаштуйте Smart-eID, щоб виконувати онлайн-ідентифікацію без своєї ID-картки, якщо це підтримується постачальником. - - - - SmartSettingsView - - Smart-eID - LABEL ANDROID IOS - Smart-eID - - - Check Smart-eID status - LABEL ANDROID IOS - Перевірити статус Smart-eID - - - Check device compatibility and the current state of any present Smart-eID - LABEL ANDROID IOS - Перевірте сумісність пристрою та поточний стан будь-якого наявного Smart-eID - - - Set up Smart-eID - LABEL ANDROID IOS - Налаштувати Smart-eID - - - Set up Smart-eID on this device - LABEL ANDROID IOS - Налаштуйте Smart-eID на цьому пристрої - - - Renew Smart-eID - LABEL ANDROID IOS - Поновити Smart-eID - - - Renew your Smart-eID with current data - LABEL ANDROID IOS - Поновіть свій Smart-eID за допомогою поточних даних - - - Delete Smart-eID - LABEL ANDROID IOS - Видалити Smart-eID - - - Remove Smart-eID data from your device - LABEL ANDROID IOS - Видаліть дані Smart-eID зі свого пристрою - - - Reset Smart-eID - LABEL ANDROID IOS - Скинути Smart-eID - - - Remove Smart-eID data and provisioning from your device - LABEL ANDROID IOS - Видаліть дані Smart-eID і підготовку зі свого пристрою - - - - SmartSetupStartView - - Smart-eID - LABEL ANDROID IOS - Smart-eID - - - You are about to set up a Smart-eID on your device. In order to proceed, you need you ID card, your six-digit ID card PIN and an internet connection. - LABEL ANDROID IOS - Ви збираєтеся налаштувати Smart-eID на своєму пристрої. Щоб продовжити, вам потрібні ID-картка, шестизначний PIN-код ID-картки й підключення до Інтернету. - - - Set up Smart-eID - LABEL ANDROID IOS - Налаштувати Smart-eID - - - - SmartUpdateStartView - - Smart-eID - LABEL ANDROID IOS - Smart-eID - - - You are about to renew your Smart-eID. In order to proceed, you need your ID card, your six-digit ID card PIN and an internet connection. - LABEL ANDROID IOS - Ви збираєтеся поновити свій Smart-eID. Щоб продовжити, вам потрібні ID-картка, шестизначний PIN-код ID-картки й підключення до Інтернету. - - - Please note that your current Smart-eID is invalidated during the process and will not be usable until the update process is completed. - LABEL ANDROID IOS - Зауважте, що під час цього процесу ваш поточний Smart-eID стає недійсним і його не можна буде використовувати до завершення процесу оновлення. - - - Renew Smart-eID - LABEL ANDROID IOS - Поновити Smart-eID - - - - SmartView - - Smart-eID - LABEL ANDROID IOS - Smart-eID - - - Please wait a moment. - LABEL ANDROID IOS - Трохи зачекайте. - - - You are about to delete the Smart-eID data that is currently stored on your device. - LABEL ANDROID IOS - Ви збираєтеся видалити дані Smart-eID, які зараз зберігаються на вашому пристрої. - - - Delete Smart-eID - LABEL ANDROID IOS - Видалити Smart-eID - - - Deleting Smart-eID - LABEL ANDROID IOS - Видалення Smart-eID - - - You are about to delete the Smart-eID data from your device and also remove the Smart-eID provisioning. This can a be used for troubleshooting as well. - LABEL ANDROID IOS - Ви збираєтеся видалити дані Smart-eID зі свого пристрою, а також видалити підготовку Smart-eID. Це також можна використовувати для усунення несправностей. - - - Reset Smart-eID - LABEL ANDROID IOS - Скинути Smart-eID - - - Resetting Smart-eID - LABEL ANDROID IOS - Скидання Smart-eID - - - - SmartWorkflow - - Updating Smart-eID status... - LABEL ANDROID IOS - Триває оновлення статусу Smart-eID… - - - Smart-eID unsupported - LABEL ANDROID IOS - Smart-eID не підтримується - - - Smart-eID disallowed - LABEL ANDROID IOS - Smart-eID не дозволено - - - Smart-eID - LABEL ANDROID IOS - Smart-eID - - - Smart-eID not ready - LABEL ANDROID IOS - Smart-eID не готовий - - - Your Smart-eID is ready for use, press "Continue" to proceed. - LABEL ANDROID IOS - Ваш Smart-eID готовий до використання, натисніть «Продовжити». - - - Please wait a moment. - LABEL ANDROID IOS - Трохи зачекайте. - - - Unfortunately, Smart-eID is not supported by your device. - -To proceed use your ID card by selecting the NFC interface or choose "WiFi" to connect with another device as cardreader. - LABEL ANDROID IOS - На жаль, Smart-eID не підтримується вашим пристроєм. - -Щоб продовжити, скористайтеся своєю ID-карткою, вибравши інтерфейс NFC, або виберіть «Wi-Fi», щоб підключитися до іншого пристрою як пристрою читання карток. - - - Unfortunately, using your Smart-eID for this authentication is not allowed by the provider. - -To proceed use your ID card by selecting the NFC interface or choose "WiFi" to connect with another device as cardreader. - LABEL ANDROID IOS - На жаль, використання вашого Smart-eID для цієї автентифікації не дозволено постачальником. - -Щоб продовжити, скористайтеся своєю ID-карткою, вибравши інтерфейс NFC, або виберіть «Wi-Fi», щоб підключитися до іншого пристрою як пристрою читання карток. - - - You have not yet set up a Smart-eID or it is no longer usable. - -To proceed use your ID card by selecting the NFC interface or choose "WiFi" to connect with another device as cardreader. If you want to set up a Smart-eID instead, please abort the current process and start the Smart-eID setup from the main screen. - LABEL ANDROID IOS - Ви ще не налаштували Smart-eID або він більше не придатний для використання. - -Щоб продовжити, скористайтеся своєю ID-карткою, вибравши інтерфейс NFC, або виберіть «Wi-Fi», щоб підключитися до іншого пристрою як пристрою читання карток. Якщо ви хочете натомість налаштувати Smart-eID, перервіть поточний процес і почніть налаштування Smart-eID з головного екрана. - - - Continue - Продовжити - - - You have not yet set up a Smart-eID or it is no longer usable. - -To proceed use your ID card by selecting the NFC interface. If you want to set up a Smart-eID instead, please abort the current process and start the Smart-eID setup from the main screen. - LABEL ANDROID IOS - Ви ще не налаштували Smart-eID або він більше не придатний для використання. - -Щоб продовжити, скористайтеся своєю ID-карткою, вибравши інтерфейс NFC. Якщо ви хочете натомість налаштувати Smart-eID, перервіть поточний процес і почніть налаштування Smart-eID з головного екрана. - - - - StoreFeedbackPopup - - Are you satisfied with AusweisApp2? - INFO ANDROID Header of the app rating popup. - Ви задоволені програмою AusweisApp2? - - - We would be very grateful if you could leave a rating on the Google Play Store! - INFO ANDROID Content of the app rating popup. - Будемо дуже вдячні, якщо ви поставите оцінку в магазині Google Play! - - - Do not ask again - LABEL ANDROID - Більше не запитувати - - - Rate app - LABEL ANDROID - Оцінити програму - - - - TabbedReaderView - - Card Readers - LABEL DESKTOP - Пристрої читання карток - - - Smartphone as card reader - Смартфон як пристрій читання карток - - - USB card reader - USB-пристрій читання карток - - - - TechnologySwitch - - NFC - LABEL ANDROID IOS - NFC - - - SMART - LABEL ANDROID IOS - SMART - - - WiFi - LABEL ANDROID IOS - Wi-Fi - - - SIM - LABEL ANDROID IOS - SIM - - - - TitleBar - - Navigation bar - LABEL DESKTOP - Панель навігації - - - List - LABEL DESKTOP - Список - - - %1 elements - LABEL DESKTOP - %1 елементів - - - 1 element - LABEL DESKTOP - 1 елемент - - - Start page - LABEL DESKTOP - Початкова сторінка - - - Settings - Параметри - - - Open settings view of %1 - Відкрити вікно параметрів %1 - - - Open online help in browser - Відкрити онлайн-довідку в браузері - - - Open online help of %1 in browser - Відкрити онлайн-довідку щодо %1 у браузері - - - Notifications - Сповіщення - - - Show in-app notifications of %1 - Показувати сповіщення в програмі щодо %1 - - - - TitleBarAction - - Navigating to %1 in current context disabled - LABEL DESKTOP - Перехід до %1 в поточному контексті вимкнено - - - element %1 of %2 - LABEL DESKTOP - елемент %1 з %2 - - - Current context: %1 - LABEL DESKTOP - Поточний контекст: %1 - - - Navigate to %1 - LABEL DESKTOP - Перейти до %1 - - - - TitleBarNavigation - - Cancel - LABEL ANDROID IOS - Скасувати - - - Back - LABEL ANDROID IOS - Назад - - - - TransportPinAssistantView - - Transport PIN - LABEL DESKTOP - Транспортний PIN-код - - - Do you want to change your (Transport) PIN now? - INFO DESKTOP Inquiry message if the five-digit Transport PIN should be changed to an ordinary PIN (now). - Бажаєте змінити свій (транспортний) PIN-код зараз? - - - If you have not already done so you have to change your five-digit Transport PIN to a six-digit PIN before you can use the online-ID function. - INFO DESKTOP Hint that a six-digit PIN is required to use the online identification feature of the ID card. - Якщо ви ще цього не зробили, вам доведеться змінити свій п’ятизначний транспортний PIN-код на шестизначний PIN-код, перш ніж ви зможете використовувати функцію онлайн-ідентифікації. - - - - TransportPinReminderView - - Do you know your six-digit ID card PIN? - LABEL ANDROID IOS - Ви знаєте шестизначний PIN-код своєї ID-картки? - - - No - LABEL ANDROID IOS - Ні - - - Yes - LABEL ANDROID IOS - Так - - - Online identification with Transport PIN is not possible. The self-selected, six-digit ID card PIN is mandatory to use the eID function. - LABEL ANDROID IOS - Онлайн-ідентифікація за допомогою транспортного PIN-коду неможлива. Самостійно обраний шестизначний PIN-код ID-картки обов’язковий для використання функції eID. - - - - TutorialFooter - - Fold in - LABEL ANDROID IOS - Згорнути - - - Quit tutorial - LABEL ANDROID IOS - Вийти з посібника - - - - TutorialHow - - How can I use the AusweisApp2 on my iPhone? - INFO ANDROID IOS - Як використовувати AusweisApp2 на iPhone? - - - How can I use the AusweisApp2 on my smartphone? - Як використовувати AusweisApp2 на смартфоні? - - - Many iPhones (iPhone 7 and newer) can access the ID card via the built-in NFC interface. - INFO ANDROID IOS - Багато моделей iPhone (iPhone 7 і новіші) можуть здійснювати доступ до ID-картки через вбудований інтерфейс NFC. - - - Many Android devices can access the ID card via the built-in NFC interface. - Багато пристроїв Android можуть здійснювати доступ до ID-картки через вбудований інтерфейс NFC. - - - You can test the capabilities of your device and your card by choosing "Check device and ID card" on the start page: - LABEL ANDROID IOS - Ви можете перевірити можливості свого пристрою та своєї картки, вибравши «Перевірити пристрій та ID-картку» на початковій сторінці: - - - You can also find a list of compatible NFC-capable smartphones here: - LABEL ANDROID IOS - Ви також можете знайти список сумісних смартфонів з підтримкою NFC тут: - - - The AusweisApp2 offers the following options to access your ID card: - LABEL ANDROID IOS - Програма AusweisApp2 пропонує такі варіанти доступу до вашої ID-картки: - - - Direct connection via NFC chip tutorial - LABEL ANDROID IOS - Посібник «Пряме підключення через мікросхему NFC» - - - Direct connection via NFC chip - LABEL ANDROID IOS - Пряме підключення через мікросхему NFC - - - App on iPhone <b>with</b> NFC chip as card reader - LABEL ANDROID IOS - Програма на iPhone <b>з</b> мікросхемою NFC як пристрій читання карток - - - App on Android smartphone <b>with</b> NFC chip as card reader - Програма на смартфоні Android <b>з</b> мікросхемою NFC як пристрій читання карток - - - Smartphone as card reader tutorial - LABEL ANDROID IOS - Посібник «Смартфон як пристрій читання карток» - - - Smartphone as card reader - LABEL ANDROID IOS - Смартфон як пристрій читання карток - - - App on computer <b>without</b> NFC chip - LABEL ANDROID IOS - Програма на комп’ютері <b>без</b> мікросхеми NFC - - - Smartphone <b>with</b> NFC chip as card reader - LABEL ANDROID IOS - Смартфон <b>з</b> мікросхемою NFC як пристрій читання карток - - - Smartphone as card reader mobile tutorial - LABEL ANDROID IOS - Мобільний посібник «Смартфон як пристрій читання карток» - - - App on tablet or smartphone <b>without</b> NFC chip - LABEL ANDROID IOS - Програма на планшеті або смартфоні <b>без</b> мікросхеми NFC - - - Another tip - LABEL ANDROID IOS - Ще одна порада - - - For lengthy forms, e.g. a BAföG application, we recommend you to use the AusweisApp2 on a computer... - LABEL ANDROID IOS - У разі форм великого обсягу, наприклад заявок на BAföG, рекомендуємо використовувати AusweisApp2 на комп’ютері… - - - Filling long forms is no fun on a smartphone! - LABEL ANDROID IOS - Заповнювати великі форми на смартфоні – справжній клопіт! - - - ... and to use a smartphone to communicate with your ID card. A USB reader is of course also an alternative. - LABEL ANDROID IOS - … і використовувати смартфон для зв’язку зі своєю ID-карткою. Також можна використовувати USB-пристрій читання карток. - - - - TutorialImportant - - Please exchange your - LABEL ANDROID IOS - Замініть - - - Before you use the online ID function please change the - LABEL ANDROID IOS - Перш ніж використовувати функцію онлайн-ідентифікації, замініть - - - five-digit - LABEL ANDROID IOS - п’ятизначний - - - Transport PIN - LABEL ANDROID IOS - транспортний PIN-код - - - with a - LABEL ANDROID IOS - на - - - six-digit PIN - LABEL ANDROID IOS - шестизначний PIN-код - - - before you use the online ID function! - LABEL ANDROID IOS - перш ніж використовувати функцію онлайн-ідентифікації! - - - change! - LABEL ANDROID IOS - замініть! - - - The Transport PIN is sent to you by the Bundesdruckerei via mail. - LABEL ANDROID IOS - Транспортний PIN-код надходить вам поштою від компанії Bundesdruckerei. - - - Select for this purpose the menu item "Change my (Transport) PIN" from the start page. Later you can also change your six-digit PIN here - LABEL ANDROID IOS - Для цього на початковій сторінці виберіть пункт меню «Змінити мій (транспортний) PIN-код». Пізніше ви також можете змінити свій шестизначний PIN-код тут - - - ... or click this button to change your PIN right now: - LABEL ANDROID IOS - … або натисніть цю кнопку, щоб змінити свій PIN-код прямо зараз: - - - Change my (Transport) PIN - LABEL ANDROID IOS - Змінити мій (транспортний) PIN-код - - - Please note: The Transport PIN can only be used for your first PIN change. If you have already set your six-digit PIN (e.g. while picking up your ID card) only the set PIN is valid. - LABEL ANDROID IOS - Майте на увазі: Транспортний PIN-код можна використовувати лише для першої зміни PIN-коду. Якщо ви вже встановили шестизначний PIN-код (наприклад, під час отримання ID-картки), тільки встановлений PIN-код є дійсним. - - - Open YouTube video - LABEL ANDROID IOS - Відкрити відео на YouTube - - - Learn more about this in the YouTube video - LABEL ANDROID IOS - Дізнайтеся більше з відео на YouTube - - - Let's go - LABEL ANDROID IOS - Поїхали! - - - Do you still have questions? - LABEL ANDROID IOS - Є запитання? - - - You can read our <b>FAQs</b> or <b>write</b> to us... - LABEL ANDROID IOS - Ознайомтеся з розділом «Запитання й відповіді» або <b>напишіть</b> нам… - - - or - LABEL ANDROID IOS - або - - - You can always access this tutorial again from the "Help" section in the menu bar. - LABEL ANDROID IOS - Ви завжди можете знову отримати доступ до цього посібника з розділу «Довідка» на панелі меню. - - - If you cannot recall your six-digit PIN or cannot find your PIN letter, you may request a new PIN using the PIN Reset Service. - LABEL ANDROID IOS - Якщо ви не можете згадати свій шестизначний PIN-код або не можете знайти свій лист із PIN-кодом, ви можете надіслати запит на новий PIN-код за допомогою служби скидання PIN-коду. - - - - TutorialReaderMethodFooter - - Back - LABEL ANDROID IOS - Назад - - - - TutorialReaderMethodNfc - - Tutorial: NFC - LABEL ANDROID IOS - Посібник: NFC - - - Direct connection via NFC chip - LABEL ANDROID IOS - Пряме підключення через мікросхему NFC - - - App on iPhone <b>with</b> NFC chip as card reader - LABEL IOS - Програма на iPhone <b>з</b> мікросхемою NFC як пристрій читання карток - - - App on Android smartphone <b>with</b> NFC chip as card reader - LABEL ANDROID - Програма на смартфоні Android <b>з</b> мікросхемою NFC як пристрій читання карток + LABEL ANDROID IOS + Назва пристрою - Click link on the website of the provider. + Enter PIN on this device LABEL ANDROID IOS - Натисніть посилання на сайті постачальника. + Введіть PIN-код на цьому пристрої - The App opens automatically. + Randomize the order of the on screen keypad buttons LABEL ANDROID IOS - Програма відкриється автоматично. + Налаштувати довільний порядок кнопок на екранній клавіатурі - The AusweisApp2 will display who wants to access which data. + Keypad animations LABEL ANDROID IOS - Програма AusweisApp2 покаже, хто хоче отримати доступ і до яких даних. + Анімація клавіатури - Start the process with a click on: + Skip rights page LABEL ANDROID IOS - Почніть процес, натиснувши: + Пропустити сторінку прав - Proceed to PIN entry + Testmode for the self-authentication LABEL ANDROID IOS - Перейти до введення PIN-коду + Тестовий режим для самоавтентифікації - ... and place the top of the iPhone onto the ID card. - LABEL IOS - … і помістіть верхню частину iPhone на ID-картку. + Internal card simulator + LABEL ANDROID IOS + Внутрішній симулятор картки - ... and place the ID card flat onto the NFC interface. - LABEL ANDROID - … і прикладіть ID-картку до інтерфейсу NFC. + Developer mode + LABEL ANDROID IOS + Режим розробника - Do not move device or ID card! + Use a more tolerant mode LABEL ANDROID IOS - Не рухайте пристрій та ID-картку! + Використовувати стійкіший режим - The correct position is specific for your device. If a position does not work try a different one. The AusweisApp2 shows different common positions. - LABEL ANDROID - Правильне положення залежить від конкретного пристрою. Якщо якесь положення не дає бажаного результату, спробуйте інше. AusweisApp2 показує різні поширені положення. + Layout style + LABEL ANDROID IOS + Стиль макета - If your device is unable to detect your ID card try to check the device capabilities by clicking on "Check device and ID card" on the start page. - LABEL ANDROID - Якщо ваш пристрій не може виявити вашу ID-картку, спробуйте перевірити його можливості, натиснувши «Перевірити пристрій та ID-картку» на початковій сторінці. + Create dummy entries + LABEL ANDROID IOS + Створити фіктивні записи - You can find more information on compatible devices on our %1mobile device list%2. - LABEL ANDROID IOS - Ви можете знайти докладнішу інформацію про сумісні пристрої в нашому списку %1мобільних пристроїв%2. + New Logfile + LABEL ALL_PLATFORMS + Новий файл журналу - Enter - LABEL ANDROID IOS This is the first of three lines "Enter" "six-digit PIN" "now!" and should be translated accoording to the third line. - Уведіть + 15 days old Logfile + LABEL ALL_PLATFORMS + Файл журналу строком 15 днів - six-digit PIN + Smart-eID LABEL ANDROID IOS - шестизначний PIN-код + Smart-eID - now! - LABEL ANDROID IOS This is the third of three lines "Enter" "six-digit PIN" "now!" and should be translated accoording to the first line. - зараз! + Reset Smart-eID + LABEL ANDROID IOS + Скинути Smart-eID - This is only possible if you have exchanged the five-digit Transport PIN with a six-digit PIN beforehand. + Reset Smart-eID data on your device LABEL ANDROID IOS - Це можливо, лише якщо ви перед цим замінили п’ятизначний транспортний PIN-код на шестизначний PIN-код. + - Open YouTube video + Show Transport PIN reminder, store feedback and close reminder dialogs. LABEL ANDROID IOS - Відкрити відео на YouTube + - You can also watch this YouTube video explaining the process. + Reset hideable dialogs LABEL ANDROID IOS - Ви також можете переглянути це відео на YouTube, у якому пояснюється цей процес. + - - - TutorialReaderMethodSacDesktop - Tutorial: Smartphone as card reader + Show requested rights on this device as well LABEL ANDROID IOS - Посібник: Смартфон як пристрій читання карток + Показати запит на права також на цьому пристрої - Smartphone as card reader + Manage pairings LABEL ANDROID IOS - Смартфон як пристрій читання карток + Керування створенням пари - App on computer <b>without</b> NFC chip + Toggling will restart the %1 LABEL ANDROID IOS - Програма на комп’ютері <b>без</b> мікросхеми NFC + - Smartphone <b>with</b> NFC chip as card reader + Use system font LABEL ANDROID IOS - Смартфон <b>з</b> мікросхемою NFC як пристрій читання карток + - Install AusweisApp2 on both your computer <b>and</b> your smartphone with NFC capability. + Appearance LABEL ANDROID IOS - Установіть програму AusweisApp2 на комп’ютері <b>та</b> смартфоні з функцією NFC. + - Both devices have to be connected to the same WiFi network + Add and remove devices LABEL ANDROID IOS - Обидва пристрої має бути підключено до однієї мережі Wi-Fi + Керування з’єднаними пристроями й додавання нових пристроїв - Now choose "Card reader" in the AusweisApp2 on your smartphone... + On-site reading LABEL ANDROID IOS - Тепер виберіть «Пристрій читання карток» у програмі AusweisApp2 на смартфоні… + Дозволений режим CAN - Now + Support CAN allowed mode for on-site reading LABEL ANDROID IOS - Зараз + Підтримувати дозволений режим CAN - Pair device + Allow test sample card usage LABEL ANDROID IOS - Створити пару з пристроєм + - Pairing code + Simulate a test sample card in authentications LABEL ANDROID IOS - Код створення пари + - appears! + Visually highlight key presses on screen keypad LABEL ANDROID IOS - з’являється! + + + + SetupAutostartView - On the first use of the Smartphone as card reader (SaC), iOS will asks for your permission to access the local network. This permission is required in order find and connect to your SaC. After the first request you can always access the permission in the iOS settings for this app. - LABEL IOS - Під час першого використання смартфона як пристрою читання карток (SaC) iOS запитає вашого дозволу на доступ до локальної мережі. Цей дозвіл потрібен для пошуку вашого SaC та підключення до нього. Після першого запиту ви завжди можете отримати доступ до дозволу в параметрах iOS для цієї програми. + Do you want to automatically start the %1 after boot? + INFO DESKTOP Question if the App shall be started automatically after boot + Автоматично запускати %1 після завантаження? - Start the App now on your computer and enter the settings. - LABEL ANDROID IOS - Запустіть програму на комп’ютері та введіть параметри. + In order to successfully use the eID function, %1 has to be running. It is therefore advisable to activate the auto-start after system startup. + INFO DESKTOP Information text why autostart of the App is advisable + Для успішного використання функції онлайн-ідентифікації має бути запущено %1. Тому рекомендовано активувати автозапуск після запуску системи. - Select the <b>Smartphone as card reader</b> tab. - LABEL ANDROID IOS - Виберіть вкладку «Смартфон як пристрій читання карток». + The launch will add an icon to the menu bar. + INFO MACOS Additional information that macOS auto-start adds a symbol to the menu bar + Після запуску до рядка меню буде додано піктограму. - Select smartphone from list - LABEL ANDROID IOS - Виберіть смартфон зі списку + Autostart Settings + LABEL DESKTOP + - Enter pairing code next. - LABEL ANDROID IOS - Далі введіть код створення пари. + The launch will add a tray icon to the notification area. + INFO WINDOWS Additional information that Windows auto-start adds a symbol to the notification area. + + + + SimulatorWorkflow - Click link on the website of the provider. + Simulator LABEL ANDROID IOS - Натисніть посилання на сайті постачальника. + Симулятор - The App opens automatically. + Continue LABEL ANDROID IOS - Програма відкриється автоматично. + Продовжити + + + SmartDeleteBaseView - The AusweisApp2 will display who wants to access which data. + Smart-eID LABEL ANDROID IOS - Програма AusweisApp2 покаже, хто хоче отримати доступ і до яких даних. + Smart-eID - Start the process with a click on: + Please wait a moment. LABEL ANDROID IOS - Почніть процес, натиснувши: + Трохи зачекайте. - Proceed to PIN entry + Send log LABEL ANDROID IOS - Перейти до введення PIN-коду + Надіслати журнал - ... and place the ID card onto the NFC interface. + If you want to use that functionality again, you need to set up a new Smart-eID first. LABEL ANDROID IOS - … і помістіть ID-картку на інтерфейс NFC. + Якщо ви хочете знову використовувати цю функцію, вам спочатку потрібно налаштувати новий Smart-eID. - Do not move device or ID card! + Reset Smart-eID LABEL ANDROID IOS - Не рухайте пристрій та ID-картку! + Скинути Smart-eID + + + SmartDeleteView - The correct position is specific for your device. If a position does not work try a different one. The AusweisApp2 shows different common positions. + Delete Smart-eID LABEL ANDROID IOS - Правильне положення залежить від конкретного пристрою. Якщо якесь положення не дає бажаного результату, спробуйте інше. AusweisApp2 показує різні поширені положення. + Видалити Smart-eID - If your device is unable to detect your ID card try to check the device capabilities by clicking on "Check device and ID card" on the start page. + You have successfuly deleted your Smart-eID. LABEL ANDROID IOS - Якщо ваш пристрій не може виявити вашу ID-картку, спробуйте перевірити його можливості, натиснувши «Перевірити пристрій та ID-картку» на початковій сторінці. + - You can find more information on compatible devices on our %1mobile device list%2. + The Smart-eID could not be successfully deleted from your device. LABEL ANDROID IOS - Ви можете знайти докладнішу інформацію про сумісні пристрої в нашому списку %1мобільних пристроїв%2. + - Enter - LABEL ANDROID IOS This is the first of three lines "Enter" "six-digit PIN" "now!" and should be translated according to the third line. - Уведіть + Back to start page + LABEL ANDROID IOS + - six-digit PIN + You are about to delete the Smart-eID data that is currently stored on your device. LABEL ANDROID IOS - шестизначний PIN-код + Ви збираєтеся видалити дані Smart-eID, які зараз зберігаються на вашому пристрої. - now! - LABEL ANDROID IOS This is the third of three lines "Enter" "six-digit PIN" "now!" and should be translated according to the first line. - зараз! + Are you sure you want to delete the Smart-eID? + LABEL ANDROID IOS + Справді видалити Smart-eID? - This is only possible if you have exchanged the five-digit Transport PIN with a six-digit PIN beforehand. + Delete LABEL ANDROID IOS - Це можливо, лише якщо ви перед цим замінили п’ятизначний транспортний PIN-код на шестизначний PIN-код. + Видалити - Open YouTube video + Deleting Smart-eID LABEL ANDROID IOS - Відкрити відео на YouTube + Видалення Smart-eID - You can also watch this YouTube video explaining the process. + Delete the Smart-eID LABEL ANDROID IOS - Ви також можете переглянути це відео на YouTube, у якому пояснюється цей процес. + - TutorialReaderMethodSacMobile + SmartMainView + + Updating Smart-eID status... + LABEL ANDROID IOS + Триває оновлення статусу Smart-eID… + - Tutorial: Smartphone as card reader + Smart-eID ready for use LABEL ANDROID IOS - Посібник: Смартфон як пристрій читання карток + Smart-eID готовий до використання - App on tablet or smartphone <b>without</b> NFC chip + Please wait a moment. LABEL ANDROID IOS - Програма на планшеті або смартфоні <b>без</b> мікросхеми NFC + Трохи зачекайте. - Smartphone <b>with</b> NFC chip as card reader + Your Smart-eID is set up and ready for use. You can now perform online identifications without your ID card if supported by the provider. LABEL ANDROID IOS - Смартфон <b>з</b> мікросхемою NFC як пристрій читання карток + Ваш Smart-eID налаштований і готовий до використання. Тепер ви можете виконувати онлайн-ідентифікацію без своєї ID-картки, якщо це підтримується постачальником. - Install AusweisApp2 on both your device without NFC <b>and</b> your smartphone with NFC capability. + Check here if your device is suitable to set up a Smart-eID. LABEL ANDROID IOS - Установіть програму AusweisApp2 на пристрої <b>без</b> NFC та смартфоні з функцією NFC. + Перевірте тут, чи підходить ваш пристрій для налаштування Smart-eID. - Both devices have to be connected to the same WiFi network + Start check LABEL ANDROID IOS - Обидва пристрої має бути підключено до однієї мережі Wi-Fi + Почати перевірку - Now choose "Card reader" in the AusweisApp2 on your smartphone... + With the Smart-eID you may also use the online identification function without the ID card. LABEL ANDROID IOS - Тепер виберіть «Пристрій читання карток» у програмі AusweisApp2 на смартфоні… + + + + SmartResetView - Now + Reset Smart-eID LABEL ANDROID IOS - Зараз + Скинути Smart-eID - Pair device + You have successfully reset your Smart-eID. LABEL ANDROID IOS - Створити пару з пристроєм + - Pairing code + You are about to reset your Smart-eID data. This can also be used for troubleshooting as well. LABEL ANDROID IOS - Код створення пари + - appears! + Are you sure you want to reset the Smart-eID? LABEL ANDROID IOS - з’являється! + - On the first use of the Smartphone as card reader (SaC), iOS will asks for your permission to access the local network. This permission is required in order find and connect to your SaC. After the first request you can always access the permission in the iOS settings for this app. - LABEL IOS - Під час першого використання смартфона як пристрою читання карток (SaC) iOS запитає вашого дозволу на доступ до локальної мережі. Цей дозвіл потрібен для пошуку вашого SaC та підключення до нього. Після першого запиту ви завжди можете отримати доступ до дозволу в параметрах iOS для цієї програми. + Reset + LABEL ANDROID IOS + - Now open the AusweisApp2 on your device <b>without</b> NFC and select <b>Manage pairings</b>. - LABEL IOS - Тепер відкрийте програму AusweisApp2 на пристрої <b>без</b> NFC і виберіть «Керування створенням пари». + Resetting Smart-eID + LABEL ANDROID IOS + Скидання Smart-eID - Now open the AusweisApp2 on your device <b>without</b> NFC and select <b>Smartphone as card reader</b>. - LABEL ANDROID - Тепер відкрийте програму AusweisApp2 на пристрої <b>без</b> NFC і виберіть «Смартфон як пристрій читання карток». + Reset the Smart-eID + LABEL ANDROID IOS + + + + SmartSettingsView - Now select <b>Settings</b>. + Smart-eID LABEL ANDROID IOS - Тепер виберіть «Параметри». + Smart-eID - Choose smartphone from list + Renew Smart-eID LABEL ANDROID IOS - Виберіть смартфон зі списку + Поновити Smart-eID - Enter pairing code next. + Renew your Smart-eID with current data LABEL ANDROID IOS - Далі введіть код створення пари. + Поновіть свій Smart-eID за допомогою поточних даних - Click link on the website of the provider on the device <b>without</b> NFC. + Delete Smart-eID LABEL ANDROID IOS - Натисніть посилання на сайті постачальника на пристрої <b>без</b> NFC. + Видалити Smart-eID - The App opens automatically. + Delete Smart-eID data from your device LABEL ANDROID IOS - Програма відкриється автоматично. + - The AusweisApp2 will display who wants to access which data. + Try Smart-eID LABEL ANDROID IOS - Програма AusweisApp2 покаже, хто хоче отримати доступ і до яких даних. + - Start the process with a click on: + Show Smart-eID data LABEL ANDROID IOS - Почніть процес, натиснувши: + - Proceed to PIN entry + Change Smart-eID PIN LABEL ANDROID IOS - Перейти до введення PIN-коду + Змінити PIN-код Smart-eID - Tap on WiFi + Change the chosen Smart-eID PIN LABEL ANDROID IOS - Торкніться Wi-Fi + + + + SmartSetupStartView - ... and place the ID card onto the NFC interface. + Smart-eID LABEL ANDROID IOS - … і помістіть ID-картку на інтерфейс NFC. + Smart-eID - Do not move device or ID card! + You are about to set up a Smart-eID on your device. In order to proceed, you need you ID card, your six-digit ID card PIN and an internet connection. LABEL ANDROID IOS - Не рухайте пристрій та ID-картку! + Ви збираєтеся налаштувати Smart-eID на своєму пристрої. Щоб продовжити, вам потрібні ID-картка, шестизначний PIN-код ID-картки й підключення до Інтернету. - The correct position is specific for your device. If a position does not work try a different one. The AusweisApp2 shows different common positions. + Set up Smart-eID LABEL ANDROID IOS - Правильне положення залежить від конкретного пристрою. Якщо якесь положення не дає бажаного результату, спробуйте інше. AusweisApp2 показує різні поширені положення. + Налаштувати Smart-eID - If your device is unable to detect your ID card try to check the device capabilities by clicking on "Check device and ID card" on the start page. + Smart-eID setup LABEL ANDROID IOS - Якщо ваш пристрій не може виявити вашу ID-картку, спробуйте перевірити його можливості, натиснувши «Перевірити пристрій та ID-картку» на початковій сторінці. + + + + SmartUpdateStartView - You can find more information on compatible devices on our %1mobile device list%2. + You are about to renew your Smart-eID. In order to proceed, you need your ID card, your six-digit ID card PIN and an internet connection. LABEL ANDROID IOS - Ви можете знайти докладнішу інформацію про сумісні пристрої в нашому списку %1мобільних пристроїв%2. + Ви збираєтеся поновити свій Smart-eID. Щоб продовжити, вам потрібні ID-картка, шестизначний PIN-код ID-картки й підключення до Інтернету. - Enter - LABEL ANDROID IOS This is the first of three lines "Enter" "six-digit PIN" "now!" and should be translated according to the third line. - Уведіть + Please note that your current Smart-eID is invalidated during the process and will not be usable until the update process is completed. + LABEL ANDROID IOS + Зауважте, що під час цього процесу ваш поточний Smart-eID стає недійсним і його не можна буде використовувати до завершення процесу оновлення. - six-digit PIN + Renew Smart-eID LABEL ANDROID IOS - шестизначний PIN-код + Поновити Smart-eID - now! - LABEL ANDROID IOS This is the third of three lines "Enter" "six-digit PIN" "now!" and should be translated according to the first line. - зараз! + Renew the Smart-eID + LABEL ANDROID IOS + - This is only possible if you have exchanged the five-digit Transport PIN with a six-digit PIN beforehand. + Smart-eID renewal LABEL ANDROID IOS - Це можливо, лише якщо ви перед цим замінили п’ятизначний транспортний PIN-код на шестизначний PIN-код. + - TutorialView + SmartView - Tutorial + Smart-eID LABEL ANDROID IOS - Посібник + Smart-eID - What? + Check Smart-eID LABEL ANDROID IOS - Що? + Перевірте Smart-eID + + + SmartWorkflow - Where? + Updating Smart-eID status... LABEL ANDROID IOS - Де? + Триває оновлення статусу Smart-eID… - How? + Smart-eID unsupported LABEL ANDROID IOS - Як? + Smart-eID не підтримується - Important! + Smart-eID disallowed LABEL ANDROID IOS - Важливо! + Smart-eID не дозволено - - - TutorialWhat - What is the online ID function? + Smart-eID LABEL ANDROID IOS - Що таке функція онлайн-ідентифікації? + Smart-eID - You can use it to authenticate yourself in the internet + Smart-eID not ready LABEL ANDROID IOS - Ви можете використовувати її для автентифікації в Інтернеті, + Smart-eID не готовий - and also to deal with administrative paperwork and business matters electronically! + Your Smart-eID is ready for use, press "Continue" to proceed. LABEL ANDROID IOS - а також щоб вирішувати адміністративні та ділові питання в електронному вигляді! + Ваш Smart-eID готовий до використання, натисніть «Продовжити». - Alright, but is it secure? + Please wait a moment. LABEL ANDROID IOS - Чудово, але чи безпечно це? + Трохи зачекайте. - Of course, because we use a so called + Unfortunately, Smart-eID is not supported by your device. + +To proceed use your ID card by selecting the NFC interface or choose "WiFi" to connect with another device as cardreader. LABEL ANDROID IOS - Звичайно, тому що ми використовуємо так звану + На жаль, Smart-eID не підтримується вашим пристроєм. + +Щоб продовжити, скористайтеся своєю ID-карткою, вибравши інтерфейс NFC, або виберіть «Wi-Fi», щоб підключитися до іншого пристрою як пристрою читання карток. - Mutual authentication + Unfortunately, using your Smart-eID for this authentication is not allowed by the provider. + +To proceed use your ID card by selecting the NFC interface or choose "WiFi" to connect with another device as cardreader. LABEL ANDROID IOS - взаємну автентифікацію + На жаль, використання вашого Smart-eID для цієї автентифікації не дозволено постачальником. + +Щоб продовжити, скористайтеся своєю ID-карткою, вибравши інтерфейс NFC, або виберіть «Wi-Fi», щоб підключитися до іншого пристрою як пристрою читання карток. - ... it establishes a secure connection between ID card and provider. + You have not yet set up a Smart-eID or it is no longer usable. + +To proceed use your ID card by selecting the NFC interface or choose "WiFi" to connect with another device as cardreader. If you want to set up a Smart-eID instead, please abort the current process and start the Smart-eID setup from the main screen. LABEL ANDROID IOS - … вона встановлює безпечне з’єднання між ID-карткою та постачальником. + Ви ще не налаштували Smart-eID або він більше не придатний для використання. + +Щоб продовжити, скористайтеся своєю ID-карткою, вибравши інтерфейс NFC, або виберіть «Wi-Fi», щоб підключитися до іншого пристрою як пристрою читання карток. Якщо ви хочете натомість налаштувати Smart-eID, перервіть поточний процес і почніть налаштування Smart-eID з головного екрана. - On every authentication you get displayed <b>who</b> wants to access <b>which</b> data - LABEL ANDROID IOS - Під час кожної автентифікації відображаються відомості, <b>хто</b> хоче отримати доступ та до <b>яких</b> даних. + Continue + Продовжити - and you consent to the request with your six-digit PIN. + You have not yet set up a Smart-eID or it is no longer usable. + +To proceed use your ID card by selecting the NFC interface. If you want to set up a Smart-eID instead, please abort the current process and start the Smart-eID setup from the main screen. LABEL ANDROID IOS - а ви даєте згоду на запит за допомогою шестизначного PIN-коду. + Ви ще не налаштували Smart-eID або він більше не придатний для використання. + +Щоб продовжити, скористайтеся своєю ID-карткою, вибравши інтерфейс NFC. Якщо ви хочете натомість налаштувати Smart-eID, перервіть поточний процес і почніть налаштування Smart-eID з головного екрана. - ... is the provider authorized for this? - LABEL ANDROID IOS - … чи має право постачальник робити це? + The device "%1" wants to access your Smart-eID. + INFO ANDROID IOS %1 will be replaced with the name of the device. + + + + StoreFeedbackPopup - The provider needs an authorization of the Federal Office of Administration. - LABEL ANDROID IOS - Постачальнику потрібен дозвіл Федерального управління. + Are you satisfied with %1? + INFO ANDROID Header of the app rating popup. + Ви задоволені програмою %1? - Certificate - LABEL ANDROID IOS - Сертифікат + We would be very grateful if you could leave a rating on the Google Play Store! + INFO ANDROID Content of the app rating popup. + Будемо дуже вдячні, якщо ви поставите оцінку в магазині Google Play! - Every time both participants authenticate each other... - LABEL ANDROID IOS - Щоразу обидва учасники автентифікують один одного… + Do not ask again + LABEL ANDROID + Більше не запитувати - ... and therefore your data is protected and securely transferred. - LABEL ANDROID IOS - …і тому ваші дані захищені та передаються безпечним чином. + Rate app + LABEL ANDROID + Оцінити програму + + + + TabbedReaderView + + Card Readers + LABEL DESKTOP + Пристрої читання карток - You can also watch a video on YouTube on this topic - LABEL ANDROID IOS - Ви також можете подивитися відео на YouTube на цю тему + Smartphone as card reader + Смартфон як пристрій читання карток - Open YouTube video - LABEL ANDROID IOS - Відкрити відео на YouTube + USB card reader + USB-пристрій читання карток - TutorialWhere + TechnologySwitch - Where can I use the online ID function? + NFC LABEL ANDROID IOS - Де я можу використовувати функцію онлайн-ідентифікації? + NFC - On every website of a provider where you see this icon: + SMART LABEL ANDROID IOS - На кожному сайті постачальника, де побачите цю піктограму: + SMART - By the way, you can find many services directly in the AusweisApp2 <b>provider list</b>. + WiFi LABEL ANDROID IOS - До речі, багато служб можна знайти безпосередньо в <b>списку постачальників</b> програми AusweisApp2. + Wi-Fi - The <b>integrated self-authentication</b> is a special service to view the data saved on your ID card. + SIM LABEL ANDROID IOS - <b>Служба вбудованої самоавтентифікації</b> – це спеціальна служба для перегляду даних, збережених на ID-картці. + SIM + + + + TitleBar + + Start page + LABEL DESKTOP + Початкова сторінка + + + Settings + Параметри - And this is how it works - LABEL ANDROID IOS - Ось як це працює + Open settings view of %1 + Відкрити вікно параметрів %1 - The AusweisApp2 will always display <b>who</b> wants to access <b>which</b> of your data. - LABEL ANDROID IOS - Програма AusweisApp2 завжди відображає, <b>хто</b> хоче отримати доступ і до <b>яких</b> ваших даних. + Notifications + Сповіщення - To allow the shown service access to the requested data click "Proceed to PIN entry" - LABEL ANDROID IOS - Щоб надати цій службі доступ до запитуваних даних, натисніть «Перейти до введення PIN-коду». + Show in-app notifications of %1 + Показувати сповіщення в програмі щодо %1 - Now lay down your ID card and hold the top of your iPhone to the ID card. - LABEL IOS - Тепер покладіть свою ID-картку і прикладіть до неї верхню частину свого iPhone. + Title bar + LABEL DESKTOP + + + + TitleBarNavigation - Now place your ID card on the NFC-interface of your smartphone. - LABEL ANDROID - Тепер помістіть свою ID-картку на інтерфейс NFC свого смартфона. + Cancel + LABEL ANDROID IOS + Скасувати - The correct position is specific for your device. If a position does not work try a different one. The AusweisApp2 shows different common positions. If your device is unable to detect your ID card try to check the device capabilities by clicking on "Check device and ID card" on the start page. - LABEL ANDROID - Правильне положення залежить від конкретного пристрою. Якщо якесь положення не дає бажаного результату, спробуйте інше. AusweisApp2 показує різні поширені положення. Якщо ваш пристрій не може виявити вашу ID-картку, спробуйте перевірити його можливості, натиснувши «Перевірити пристрій та ID-картку» на початковій сторінці. + Back + LABEL ANDROID IOS + Назад + + + TransportPinReminderView - Do not move your iPhone during the procedure! - LABEL IOS - Не рухайте iPhone під час виконання цієї процедури! + Do you know your six-digit ID card PIN? + LABEL ANDROID IOS + Ви знаєте шестизначний PIN-код своєї ID-картки? - Do not move your device during the procedure! - LABEL ANDROID - Не рухайте пристрій під час виконання цієї процедури! + No + LABEL ANDROID IOS + Ні - Enter - LABEL ANDROID IOS This is the first of three lines "Enter" "six-digit PIN" "now!" and should be translated according to the third line. - Уведіть + Yes + LABEL ANDROID IOS + Так - six-digit PIN + Online identification with Transport PIN is not possible. The self-selected, six-digit ID card PIN is mandatory to use the eID function. LABEL ANDROID IOS - шестизначний PIN-код + Онлайн-ідентифікація за допомогою транспортного PIN-коду неможлива. Самостійно обраний шестизначний PIN-код ID-картки обов’язковий для використання функції eID. - now! - LABEL ANDROID IOS This is the third of three lines "Enter" "six-digit PIN" "now!" and should be translated according to the first line. - зараз! + To set up a Smart-eID you also need to have assigned a six-digit PIN beforehand. + LABEL ANDROID IOS + @@ -6013,24 +4284,6 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u Посилання на контрольну суму: - - Utils - - today - LABEL ALL_PLATFORMS - сьогодні - - - yesterday - LABEL ALL_PLATFORMS - вчора - - - dd.MM.yyyy - LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString - dd.MM.yyyy - - VersionInformation @@ -6077,9 +4330,9 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u Надіслати дані пристрою? - Would you like to help us to improve the AusweisApp2? + Would you like to help us to improve the %1? INFO ANDROID IOS Request to the user if the device information should be shared for statistics (Whitelist) - Part of content text - Хочете допомогти нам покращити програму AusweisApp2? + Хочете допомогти нам покращити програму %1? Supplying your device characteristics helps us to gather reliable information about the compatibility of your device. @@ -6111,6 +4364,14 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u Надіслати + + WorkflowInfoList + + The device "%1" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. + INFO ANDROID IOS The paired smartphone was removed since it did not respond to connection attempts. It needs to be paired again before using it. + Пару з пристроєм "%1" було скасовано, оскільки він не реагував на спроби підключення. Створіть пару з пристроєм знову, щоб використовувати його як пристрій читання карток. + + governikus::AccessRoleAndRightsUtil @@ -6563,9 +4824,9 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u Брандмауери від сторонніх постачальників - Outgoing AusweisApp2 rule + Outgoing %1 rule LABEL DESKTOP - Вихідне правило AusweisApp2 + Вихідне правило %1 Exists: %1 @@ -6573,9 +4834,9 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u Існує: %1 - Incoming AusweisApp2 rule + Incoming %1 rule LABEL DESKTOP - Вхідне правило AusweisApp2 + Вхідне правило %1 Windows firewall rules @@ -6929,7 +5190,7 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u Програма отримала помилку від сервера. - Hash of TLS certificate not in certificate description (issuer: %1). This indicates a misconfiguration or manipulation of the certificate. Please check that your antivirus-software and firewalls are not interfering with TLS traffic. + Hash of TLS certificate not in certificate description (issuer: %1). This indicates a misconfiguration or manipulation of the certificate. Please check that your antivirus software and firewall are not interfering with TLS traffic. ERROR ALL_PLATFORMS The TLS certificate was not folded with the Authorization Certificate, thus violating the security requirements. Might also be caused by a firewall and/or the antivirus software. Хеш сертифіката TLS не вказано в описі сертифіката (емітент: %1). Це вказує на неправильну конфігурацію або маніпуляції з сертифікатом. Переконайтеся, що ваше антивірусне програмне забезпечення та брандмауери не взаємодіють із трафіком TLS. @@ -6948,11 +5209,6 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u ERROR ALL_PLATFORMS The device does not support the Smart-eID function Пристрій не підтримує Smart-eID. - - The preparation of the Smart-eID Applet failed. - ERROR ANDROID The preparation of the Smart-eID Applet failed - Не вдалося підготувати аплет Smart-eID. - Initialization of Personalization of Smart-eID failed. ERROR ALL_PLATFORMS Initialization of Personalization failed @@ -7069,9 +5325,9 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u Під час зв’язку з ID-карткою сталася помилка. Правильно розташуйте ID-картку на пристрої читання карток і повторіть спробу. - A protocol error occurred. Please make sure that your ID card is placed correctly on the card reader and try again. If the problem occurs again, please contact our support at %1AusweisApp2 Support%2. - ERROR ALL_PLATFORMS Communication with the card failed due to the specification of the TR (Technische Richtlinie). The protocol was faulty or invalid values were requested/received, - Сталася помилка протоколу. Правильно розташуйте ID-картку на пристрої читання карток і повторіть спробу. Якщо проблема виникає знову, зверніться до нашої служби підтримки за посиланням: %1служба підтримки AusweisApp2%2. + A protocol error occurred. Please make sure that your ID card is placed correctly on the card reader and try again. If the problem occurs again, please contact our support at %1. + ERROR ALL_PLATFORMS Communication with the card failed due to the specification of the TR (Technische Richtlinie). The protocol was faulty or invalid values were requested/received. %1 is a html link to the support. + Сталася помилка протоколу. Правильно розташуйте ID-картку на пристрої читання карток і повторіть спробу. Якщо проблема виникає знову, зверніться до нашої служби підтримки за посиланням: %1. The given PIN is not correct. @@ -7118,11 +5374,6 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u ERROR ALL_PLATFORMS The validity verification of the card failed. Не вдалося перевірити дійсність картки. - - The Smart-eID is invalid. This might have been caused by entering the wrong Smart-eID PIN three times. - ERROR ALL_PLATFORMS The existing Smart-eID was invalidated. - Smart-eID недійсний. Це могло статися через те, що неправильний PIN-код Smart-eID було введено тричі. - The smartphone as card reader (SaC) connection was aborted. ERROR ALL_PLATFORMS The connection to the smartphone card reader (SaK) was lost. @@ -7134,9 +5385,9 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u Запит на підключення смартфона як пристрою читання карток (SaC) недійсний. - Your smartphone as card reader (SaC) version is incompatible with the local version. Please install the latest AusweisApp2 version on both your smartphone and your computer. + Your smartphone as card reader (SaC) version is incompatible with the local version. Please install the latest %1 version on both your smartphone and your computer. ERROR ALL_PLATFORMS The requested connection to the smartphone card reader (SaK) was invalid (API mismatch). - Версія вашого смартфона як пристрою читання карток (SaC) є несумісною з локальною версією. Установіть останню версію AusweisApp2 як на свій смартфон, так і на комп’ютер. + Версія вашого смартфона як пристрою читання карток (SaC) є несумісною з локальною версією. Установіть останню версію %1 як на свій смартфон, так і на комп’ютер. A timeout occurred while trying to establish a connection to the smartphone as card reader (SaC). @@ -7183,26 +5434,55 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u ERROR ALL_PLATFORMS Starting the update failed. Не вдалося почати новий процес для запуску оновлення. + + You have reached the allowed amount of Smart-eID setups for the current period. You may set up another Smart-eID with your ID card on %1. + ERROR ALL_PLATFORMS Personalization of Smart-eID is not allowed, no remaining attempts are left. + Ви досягли дозволеної кількості налаштувань Smart-eID за поточний період. Ви можете налаштувати інший Smart-eID для своєї ID-картки %1. + + + Failed to get the ServiceInformation of the Smart-eID. + ERROR ALL_PLATFORMS Failed to get the ServiceInformation of the Smart-eID + + + + The authentication to the personalization service failed. + ERROR ALL_PLATFORMS No sessionID, required for a personalization, was received + + + + The Smart-eID is no longer ready for use. This might have been caused by entering the wrong Smart-eID PIN three times. You may personalize a new Smart-eID to resolve the issue. + ERROR ALL_PLATFORMS The existing Smart-eID was invalidated. + + + + The preparation of the Smart-eID failed. + ERROR ANDROID The preparation of the Smart-eID Applet failed + + The program did not receive a StartPaosResponse message from the server. ERROR_MASKED ALL_PLATFORMS The PAOS message StartPaosResponse was not received. Програма не отримала повідомлення StartPaosResponse від сервера. - - - governikus::HistoryModel - No data stored on your ID card was read, only confirmed whether you are in possession of a valid ID card. - LABEL ALL_PLATFORMS - Жодні дані, що зберігаються на вашій ID-картці, не зчитувалися, лише підтверджено, чи є у вас дійсна ID-картка. + The server could not process the client request. + ERROR_MASKED ALL_PLATFORMS + - - - governikus::HistoryModelSearchFilter - dd.MM.yyyy - LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString - dd.MM.yyyy + The service encountered an internal error while processing a request. + ERROR ALL_PLATFORMS A server has responded with an HTTP error code 5xx. + + + + The service reported an error while processing a client request. + ERROR ALL_PLATFORMS A server has responded with an HTTP error code 4xx. + + + + %1 Support + LABEL ALL_PLATFORMS Link text to the app support. %1 is the app name. + служба підтримки %1 @@ -7325,11 +5605,6 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u INFO ALL_PLATFORMS The wrong Transport PIN was entered on the first attempt. Ви ввели неправильний п’ятизначний транспортний PIN-код. Залишилося ще дві спроби введення транспортного PIN-коду. - - Please note that you may use the five-digit Transport PIN only once to change to a six-digit ID card PIN. If you already set a six-digit ID card PIN, the five-digit Transport PIN is no longer valid. - INFO ALL_PLATFORMS - Зверніть увагу, що ви можете використати п’ятизначний транспортний PIN-код лише один раз, щоб змінити його на шестизначний PIN-код ID-картки. Якщо ви вже встановили шестизначний PIN-код ID-картки, п’ятизначний транспортний PIN-код більше не дійсний. - You have entered an incorrect, six-digit Smart-eID PIN. You have two further attempts to enter the correct Smart-eID PIN. INFO ALL_PLATFORMS The wrong Smart-eID PIN was entered on the first attempt. @@ -7345,11 +5620,6 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u INFO ALL_PLATFORMS The wrong Transport PIN was entered twice, the next attempt requires the CAN for additional verification. Ви двічі ввели неправильний п’ятизначний транспортний PIN-код. Для третьої спроби спочатку потрібно ввести шестизначний номер доступу до картки (CAN). Ви можете знайти номер CAN у нижньому правому куті на лицьовому боці своєї ID-картки. - - You have entered an incorrect, six-digit Smart-eID PIN twice. An incorrect third attempt will invalidate your Smart-eID and you will have to set it up again. - INFO ANDROID IOS The wrong Smart-eID PIN was entered twice, a third wrong attempt could invalidate the Smart-eID. - Ви двічі ввели неправильний шестизначний PIN-код Smart-eID. Якщо його втретє буде введено неправильно, ваш Smart-eID стане недійсним і вам доведеться знову його налаштувати. - You have entered an incorrect, six-digit ID card PIN twice. For a third attempt, the six-digit Card Access Number (CAN) must be entered first. You can find your CAN in the bottom right on the front of your ID card. INFO ALL_PLATFORMS The wrong ID card PIN was entered twice, the next attempt requires the CAN for additional verification. @@ -7380,96 +5650,19 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u INFO ALL_PLATFORMS The PUK entered wrongfully and needs to be supplied again. Ви ввели неправильний десятизначний PUK-код. Повторіть спробу. - - - governikus::PdfCreator - - AusweisApp2 is a product of Governikus GmbH & Co. KG - on behalf of the Federal Office for Information Security. - LABEL ALL_PLATFORMS - AusweisApp2 є продуктом компанії Governikus GmbH & Co. KG – від імені Федерального управління з інформаційної безпеки. - - - For further information, please see %1 - LABEL ALL_PLATFORMS Footer in a generated PDF document. %1 is an URL. - Для отримання додаткової інформації див. %1 - - - - governikus::PdfExporter - - Date - LABEL ALL_PLATFORMS - Дата - - - Details - LABEL ALL_PLATFORMS - Відомості - - - dd.MM.yyyy hh:mm AP - LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString - dd.MM.yyyy hh:mm - - - Provider: - LABEL ALL_PLATFORMS - Постачальник: - - - Purpose: - LABEL ALL_PLATFORMS - Мета: - - - Read access: - LABEL ALL_PLATFORMS - Доступ для читання: - - - Write access (update): - LABEL ALL_PLATFORMS - Доступ для записування (оновлення): - - - dd.MM.yyyy - LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString - dd.MM.yyyy - - - hh:mm AP - LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString - hh:mm - - - At %1 %2 the following data were saved: - LABEL ALL_PLATFORMS - У %1 %2 було збережено такі дані: - - - History - LABEL ALL_PLATFORMS - Історія - - - Entry - LABEL ALL_PLATFORMS - Уведення - - Content - LABEL ALL_PLATFORMS - Вміст + You have entered an incorrect, six-digit Smart-eID PIN twice. After the next failed attempt you will no longer be able to use your Smart-eID and will need to set it up again. + INFO ANDROID IOS The wrong Smart-eID PIN was entered twice, a third wrong attempt could invalidate the Smart-eID. + - At %1 %2 the following data has been read out of your ID card: - LABEL ALL_PLATFORMS - У %1 %2 з вашої ID-картки було зчитано такі дані: + The input does not match. Please choose a new Smart-eID PIN. + ALL_PLATFORMS Error message if the new pin confirmation mismatches. + - Information - LABEL ALL_PLATFORMS - Інформація + The input does not match. Please choose a new ID card PIN. + @@ -7504,47 +5697,6 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u Надішліть безкоштовно запит на новий PIN-код картки, щоб знову мати змогу користуватися функцією eID. - - governikus::ProviderModel - - %1/min - INFO ALL_PLATFORMS Unit for expenses for calling the hotline (per minute). - %1/хв - - - %1/call - INFO ALL_PLATFORMS Unit for expenses for calling the hotline (per call). - %1/виклик - - - %1 EUR - INFO ALL_PLATFORMS Currency unit for expenses for calling the hotline (Euro/Cent). - %1 євро - - - %1 ct - %1 євроцент - - - %1 seconds free, afterwards - INFO ALL_PLATFORMS Free of charge seconds when calling the hotline. - %1 секунд безкоштовно, а потім - - - landline costs %1; - INFO ALL_PLATFORMS Land line charges when calling the hotline. - вартість стаціонарного телефонного зв’язку %1; - - - mobile costs may vary. - INFO ALL_PLATFORMS Cell phone charges when calling the hotline. - вартість мобільного зв’язку може відрізнятися. - - - mobile costs %1 - вартість мобільного зв’язку %1 - - governikus::ReaderModel @@ -7572,16 +5724,6 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u INFO ALL_PLATFORMS Цей пристрій читання карток офіційно не підтримується і може не працювати належним чином. - - online help - Is embedded in a sentence. - онлайн-довідка - - - No connected card reader found. See %1 for installation of card readers. - INFO ALL_PLATFORMS No card reader was found, the message contains a link to the installation section of the manual. - Не знайдено підключеного пристрою читання карток. Див. %1 щодо встановлення пристроїв читання карток. - hh:mm:ss AP LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString @@ -7596,14 +5738,14 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u governikus::RedirectRequest - Cannot reach local AusweisApp2 + Cannot reach local %1 ERROR ALL_PLATFORMS The local AusweisApp (access via reverse proxy) is not reachable, part of an HTML error page. - Немає доступу до локальної версії додатка AusweisApp2 + Немає доступу до локальної версії додатка %1 - Your local AusweisApp2 is not running. Please start your local AusweisApp2 and try again. + Your local %1 is not running. Please start your local %1 and try again. ERROR ALL_PLATFORMS The local AusweisApp (access via reverse proxy) is not reachable, part of an HTML error page. - Локальна версія додатка AusweisApp2 не запущена. Запустіть локальну версію додатка AusweisApp2 і спробуйте ще раз. + Локальна версія додатка %1 не запущена. Запустіть локальну версію додатка %1 і спробуйте ще раз. Would you like to try again? @@ -7655,16 +5797,6 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString dd.MM.yyyy hh:mm - - online help - Is embedded in a sentence. - онлайн-довідка - - - No smartphone as card reader (Sac) available. Please make sure to activate the "remote service" on your smartphone and to connect both devices to the same WiFi. See %1 for details of use. - INFO ALL_PLATFORMS No smartphone with enabled remote service was found on the same network. - Немає жодного смартфона як пристрою читання карток (SaC). Переконайтеся, що ви активували «віддалену службу» на своєму смартфоні та підключили обидва пристрої до однієї мережі Wi-Fi. Відомості про використання див. в розділі %1. - Unavailable LABEL ALL_PLATFORMS @@ -7811,24 +5943,74 @@ Please enable NFC to use your smartphone as a card reader (SaC). governikus::SmartModel - Delete data was successful. - LABEL ANDROID IOS - Дані видалено успішно. + The online check for the Smart-eID support on your device failed. Please note that this process requires an internet connection. + ERROR ANDROID IOS The check for Smart-eID support failed without any specific reason. + - Delete data failed. - LABEL ANDROID IOS - Не вдалося видалити дані. + The online check for the Smart-eID support on your device failed because the server is currently facing too many requests. Please try again later. + ERROR ANDROID IOS The check for Smart-eID support failed because the server is overloaded. + - Delete Smart-eID was successful. - LABEL ANDROID IOS - Smart-eID видалено успішно. + The online check for the Smart-eID support on your device failed because the server is currently under maintenance. Please try again later. + ERROR ANDROID IOS The check for Smart-eID support failed because the server is being maintained. + - Delete Smart-eID failed. - LABEL ANDROID IOS - Не вдалося видалити Smart-eID. + The Smart-eID data and provisioning could not be successfully deleted from your device. Please note that this process requires an internet connection. + ERROR ANDROID IOS Deletion of the Smart-eID failed without a specific reason. + + + + The Smart-eID data and provisioning could not be successfully deleted from your device because the server is currently facing too many requests. Please try again later. + ERROR ANDROID IOS Deletion of the Smart-eID failed because the server is overloaded. + + + + The Smart-eID data and provisioning could not be successfully deleted from your device because the server is currently under maintenance. Please try again later. + ERROR ANDROID IOS Deletion of the Smart-eID failed because the server is being maintained. + + + + The Smart-eID data and provisioning could not be successfully deleted from your device. In order to access the necessary device storage, active NFC functionality is required. Please activate NFC and restart the process. + ERROR ANDROID IOS Deletion of the Smart-eID failed because NFC is not activated. + + + + The online check for the Smart-eID support on your device failed. In order to access the necessary device storage, active NFC functionality is required. Please activate NFC and try again. + ERROR ANDROID IOS The check for Smart-eID support failed because the NFC functionality is not activated. + + + + The online check for the Smart-eID support on your device failed. The Google Play Integrity Check failed. + ERROR ANDROID IOS The check for Smart-eID support failed because Google Play Integrity Check failed. + + + + The online check for the Smart-eID support on your device failed. An authentication issue occurred (e.g. a resource was accessed without authorization or an unauthorized app tried to access a security component). + ERROR ANDROID IOS The check for Smart-eID support failed because an authorization issue occurred. + + + + The Smart-eID data and provisioning could not be successfully deleted from your device. The Google Play Integrity Check failed. + ERROR ANDROID IOS Deletion of the Smart-eID failed because the Google Play Integrity Check failed. + + + + The Smart-eID data and provisioning could not be successfully deleted from your device. An authentication issue occurred (e.g. a resource was accessed without authorization or an unauthorized app tried to access a security component). + ERROR ANDROID IOS Deletion of the Smart-eID failed because an authorization issue occurred. + + + + The online check for the Smart-eID support on your device failed. Please ensure that you have an internet connection and your antivirus software and firewall are not blocking the connection. + ERROR ANDROID IOS The check for Smart-eID support failed because a network connection error occurred. + + + + The Smart-eID data and provisioning could not be successfully deleted from your device. Please ensure that you have an internet connection and your antivirus software and firewall are not blocking the connection. + ERROR ANDROID IOS Deletion of the Smart-eID failed because a network connection error occurred. + @@ -7856,11 +6038,21 @@ Please enable NFC to use your smartphone as a card reader (SaC). governikus::StateConnectCard The used card reader does not meet the technical requirements (Extended Length not supported). + INFO IOS Використовуваний пристрій читання карток не відповідає технічним вимогам (Extended Length не підтримується). - The provider requires a physical ID card. - Постачальник вимагає фізичну ID-картку. + The used ID card type is not accepted by the server. + INFO IOS + + + + + governikus::StateDeleteApplet + + Cleaning up old Smart-eID + LABEL ANDROID IOS + Очищення старого Smart-eID @@ -7943,21 +6135,11 @@ Please enable NFC to use your smartphone as a card reader (SaC). - governikus::StatePrepareApplet - - Checking Smart-eID status - LABEL ANDROID IOS - Перевірка статусу Smart-eID - + governikus::StateInstallApplet Installing Smart-eID LABEL ANDROID IOS - Установлення Smart-eID - - - Cleaning up old Smart-eID - LABEL ANDROID IOS - Очищення старого Smart-eID + Установлення Smart-eID @@ -7983,18 +6165,11 @@ Please enable NFC to use your smartphone as a card reader (SaC). - governikus::StateWriteHistory + governikus::StateUpdateSupportInfo - Validity: -%1 - %2 - LABEL ALL_PLATFORMS - Термін дії: -%1 – %2 - - - Preparing results - INFO ALL_PLATFORMS Status message after the authentication was completed, the results are prepared for the user and the process will be continued in the browser - Підготовка результатів + Checking Smart-eID status + LABEL ANDROID IOS + Перевірка статусу Smart-eID @@ -8028,8 +6203,8 @@ Please enable NFC to use your smartphone as a card reader (SaC). Макс. довжина пакета NFC - AusweisApp2 Version - Версія AusweisApp2 + %1 Version + Версія %1 NFC Tag Type @@ -8049,9 +6224,9 @@ Please enable NFC to use your smartphone as a card reader (SaC). Відкрити - Quit AusweisApp2 + Quit %1 LABEL DESKTOP - Завершити роботу AusweisApp2 + Завершити роботу %1 @@ -8081,26 +6256,18 @@ Please enable NFC to use your smartphone as a card reader (SaC). Програма (%1) використовує потрібний порт (%2). Закрийте %1 і повторіть спробу! - You tried to start a newer version (%1) of currently running AusweisApp2. Please stop the current version (%2) and start again! + You tried to start a newer version (%1) of currently running %2. Please stop the current version (%3) and start again! ERROR ALL_PLATFORMS The external request to show the UI requested a newer version than the one currently installed. - Ви намагалися запустити новішу версію (%1) запущеної наразі програми AusweisApp2. Закрийте поточну версію (%2) і запустіть знову! + Ви намагалися запустити новішу версію (%1) запущеної наразі програми %2. Закрийте поточну версію (%3) і запустіть знову! - You tried to start an older version (%1) of currently running AusweisApp2. Please open the currently running version (%2)! + You tried to start an older version (%1) of currently running %2. Please open the currently running version (%3)! ERROR ALL_PLATFORMS The external request to show the UI requested an older version than the one currently installed. - Ви намагалися запустити старішу версію (%1) запущеної наразі програми AusweisApp2. Відкрийте запущену наразі версію (%2)! - - - Reverse-Proxy of AusweisApp2 is started and this instance cannot rebind port. Please ask your administrator! - Запущено зворотний проксі додатка AusweisApp2, і цей екземпляр не може перепризначити порт. Зверніться до свого адміністратора! + Ви намагалися запустити старішу версію (%1) запущеної наразі програми %2. Відкрийте запущену наразі версію (%3)! - - - governikus::WebserviceActivationContext - The browser connection was lost. - ERROR ALL_PLATFORMS No HTTP connection present. - З’єднання з браузером було втрачено. + Reverse-Proxy of %1 is started and this instance cannot rebind port. Please ask your administrator! + Запущено зворотний проксі додатка %1, і цей екземпляр не може перепризначити порт. Зверніться до свого адміністратора! Cannot start authentication @@ -8122,6 +6289,11 @@ Please enable NFC to use your smartphone as a card reader (SaC). ERROR ALL_PLATFORMS A new authentication request was received while the previous one was still running. Part of an HTML error page. Повторіть спробу + + The browser connection was lost. + ERROR ALL_PLATFORMS No HTTP connection present. + З’єднання з браузером було втрачено. + Invalid request (%1) ERROR ALL_PLATFORMS Invalid request by the browser, part of an HTML error page @@ -8156,13 +6328,38 @@ Please enable NFC to use your smartphone as a card reader (SaC). governikus::WorkflowModel - AusweisApp2 error report - %1 - Звіт про помилку програми AusweisApp2 – %1 + %1 error report - %2 + Звіт про помилку програми %1 – %2 Contact your local citizens' office (Bürgeramt) to apply for a new ID card or to unblock the ID card. Зверніться до місцевого відділу обслуговування громадян (Bürgeramt), щоб подати заяву на отримання нової ID-картки або розблокувати ID-картку. + + The used Smart-eID is not accepted by the server. Please restart the remote service on your connected smartphone and try again with a physical ID card. + INFO ALL_PLATFORMS + + + + The used Smart-eID is not accepted by the server. Please stop the remote service and use another Smart-eID or contact the service provider. + INFO ALL_PLATFORMS + + + + The used ID card is not accepted by the server. Please remove the ID card from your device or card reader and use a Smart-eID or contact the service provider. + INFO ALL_PLATFORMS + + + + Renew your Smart-eID and set a new PIN in the Smart-eID menu. + LABEL ANDROID IOS The hint text that is shwon right above the redirect button that appears when a user tried to usa an unusable Smart-eID + + + + Go to Smart-eID menu + LABEL ANDROID IOS The text on the redirect button that appears when the user tried to use an unusable Smart-eID + + main @@ -8230,5 +6427,20 @@ Please enable NFC to use your smartphone as a card reader (SaC). INFO DESKTOP Content of the popup that is shown when the AA2 is closed and the close/minimize info was not disabled. macOS specific if autostart is enabled. Програма залишається доступною через піктограму на панелі меню. Натисніть піктограму %1, щоб знову відкрити інтерфейс користувача. + + The %1 will be shut down and an authentication will no longer be possible. You will have to restart the %1 to identify yourself towards providers. + INFO DESKTOP Text of the popup that is shown when the AA2 is quit for the first time. + + + + The %1 is closed. + INFO DESKTOP Header of the popup that is shown when the AA2 is quit for the first time. + + + + This will cancel the current operation and shut the %1 down. You will have to restart the %1 to restart the operation. + INFO DESKTOP Content of the popup that is shown when the AA2 is shut down and a workflow is still active. + + diff --git a/resources/updatable-files/supported-providers.json b/resources/updatable-files/supported-providers.json index 5ed26ee79..4a1a59b1c 100644 --- a/resources/updatable-files/supported-providers.json +++ b/resources/updatable-files/supported-providers.json @@ -1,5 +1,4 @@ { - "$schema": "../json-schemas/supported-providers.json", "callcosts": [ { "prefixes": [ @@ -476,33 +475,18 @@ "category": "citizen", "subjectUrlInfo": "Using service from Servicekonto Nordrhein-Westfalen (https://servicekonto.nrw)." }, - { - "shortName": { - "": "Bürgerservice-Portal Krz" - }, - "longName": { - "": "Bürgerservice-Portal Kommunales Rechenzentrum Minden-Ravensberg/Lippe" - }, - "address": "https://www.buergerserviceportal.nrw/krz", - "homepage": "https://www.buergerserviceportal.nrw", - "email": "bsp@support.krz.de", - "category": "citizen", - "subjectUrls": [ - "https://www.buergerserviceportal.nrw" - ] - }, { "eidSupport": false, "shortName": { - "": "Bürgerservice-Portal Kreis Herford" + "": "Kreis Herford - Internetbasierte Fahrzeugzulassung" }, "longName": { - "": "Bürgerservice-Portal Kreis Herford" + "": "Kreis Herford - Internetbasierte Fahrzeugzulassung" }, "longDescription": { "": "In unserem Bürgerservice-Portal können Sie Anträge an die Kreisverwaltung Herford online erfassen und direkt zur weiteren Bearbeitung an die zuständigen Stellen übermitteln." }, - "address": "https://www.buergerserviceportal.nrw/krz/lkrherford", + "address": "https://www.kreis-herford.de/i-KFZ-Stufe 4", "homepage": "https://www.kreis-herford.de", "phone": "+49 5223 988 500", "email": "portal@kreis-herford.de", @@ -515,15 +499,15 @@ { "eidSupport": false, "shortName": { - "": "Bürgerservice-Portal Kreis Minden-Lübbecke" + "": "Kreis Minden-Lübbecke - Internetbasierte Fahrzeugzulassung" }, "longName": { - "": "Bürgerservice-Portal Kreis Minden-Lübbecke" + "": "Kreis Minden-Lübbecke - Internetbasierte Fahrzeugzulassung" }, "longDescription": { "": "In unserem Portal können Sie Ihren Antrag an den Kreis Minden-Lübbecke direkt online erfassen und elektronisch übermitteln." }, - "address": "https://www.buergerserviceportal.nrw/krz/mindenluebbecke", + "address": "https://www.minden-luebbecke.de/online-zulassung", "homepage": "https://www.minden-luebbecke.de", "phone": "+49 571 807 0", "email": "info@minden-luebbecke.de", @@ -682,20 +666,19 @@ "": "Deutsche Rentenversicherung" }, "longName": { - "": "Deutsche Rentenversicherung" + "": "Kundenportal der Deutschen Rentenversicherung" }, "longDescription": { - "": "Mit der Online-Ausweisfunktion im neuen Personalausweis können Sie ...
    • auf Informationen Ihres Rentenkontos im Kundenbereich ,eService' sicher zugreifen (z. B. Versicherungsverlauf und Beitragsrechnung),
    • Ihre Rentenauskunft online abrufen,
    • schnell und einfach Ihre persönlichen Daten ändern (z. B. Ihre Adresse und Bankverbindung).
    " + "": "Im Kundenportal konsolidiert die Deutsche Rentenversicherung verschiedene Online-Services übersichtlich an einem Ort und bietet Ihnen über eine sichere Authentifizierung den Zugriff auf Ihren persönlichen Bereich. Dort können Sie ihre Daten und Dokumente jederzeit selbständig, einfach und flexibel verwalten sowie mittels dem ePostfach elektronisch mit der Deutschen Rentenversicherung kommunizieren." }, - "address": "https://www.eservice-drv.de/OnlineDiensteWeb/init.do?npa=true&src=ausweisapp", + "address": "https://kundenportal.deutsche-rentenversicherung.de", "homepage": "https://www.deutsche-rentenversicherung.de", "phone": "+49 800 100 048070", "email": "Online-Dienste@deutsche-rentenversicherung.de", - "postalAddress": "Ruhrstraße 2
    10709 Berlin", + "postalAddress": "Deutsche Rentenversicherung Bund
    Hohenzollerndamm 45 - 47
    10713 Berlin", + "icon": "DRV_icon.png", "category": "citizen", - "subjectUrls": [ - "https://www.eservice-drv.de" - ] + "subjectUrlInfo": "Using service from Digitale Rentenübersicht (https://login.deutsche-rentenversicherung.de)." }, { "eidSupport": false, @@ -909,6 +892,26 @@ "category": "citizen", "subjectUrlInfo": "Using service from Servicekonto Sachsen (https://eidconnect.egov.sachsen.de)." }, + { + "shortName": { + "": "Landeshauptstadt Potsdam - iKFZ" + }, + "longName": { + "": "Landeshauptstadt Potsdam - Internetbasierte Fahrzeugzulassung" + }, + "longDescription": { + "": "Mit der internetbasierten Fahrzeugzulassung (iKFZ) kann der gesamte Lebenszyklus Ihres Fahrzeuges aus zulassungsrechtlicher Sicht online abgewickelt werden, von der Neuzulassung bis zur Außerbetriebsetzung. Ohne Wartezeit oder Gang zur Kfz-Zulassungsbehörde.

    Das Land Brandenburg hat dafür ein zentrales Portal geschaffen. Dort finden Sie alle teilnehmenden Zulassungsbehörden. Außerdem finden Sie dort weiterführende Erklärungen und Videos sowie die Voraussetzungen zur Nutzung des Services." + }, + "address": "https://ikfz.brandenburg.de/ikfz/de/kfz-zulassungsbehoerden/p-potsdam", + "homepage": "https://ikfz.brandenburg.de/ikfz/de", + "phone": "+49 331 289 3297", + "email": "zulassungsstelle@rathaus.potsdam.de", + "postalAddress": "Landeshauptstadt Potsdam
    Bereich Bürgerservice

    Kfz-Zulassungsbehörde
    Friedrich-Ebert-Str. 79/81
    14469 Potsdam", + "image": "Potsdam_image.png", + "icon": "Potsdam_icon.png", + "category": "citizen", + "subjectUrlInfo": "Using service from Landesportal Brandenburg (https://e-ident.brandenburg.de)." + }, { "shortName": { "": "Digitaler Bürgerservice Stadt Leipzig" @@ -1011,6 +1014,26 @@ "category": "citizen", "subjectUrlInfo": "Using service from Servicekonto Nordrhein-Westfalen (https://servicekonto.nrw)." }, + { + "shortName": { + "": "Online-Dienste Kreis Steinfurt" + }, + "longName": { + "": "Online-Dienste des Kreis Steinfurt" + }, + "longDescription": { + "": "Einige Leistungen können beim Kreis Steinfurt direkt online beantragt werden. Ein schriftlicher Antrag oder ein Behördengang kann damit entfallen." + }, + "address": "https://www.kreis-steinfurt.de/kv_steinfurt/live/Kreisverwaltung/Online-Dienste", + "homepage": "https://www.kreis-steinfurt.de", + "phone": "+49 2551 69 0", + "email": "post@kreis-steinfurt.de", + "postalAddress": "Kreis Steinfurt
    Tecklenburger Straße 10
    48565 Steinfurt", + "image": "KreisSteinfurt_image.jpg", + "icon": "KreisSteinfurt_icon.png", + "category": "citizen", + "subjectUrlInfo": "Using service from Bürgerservice-Portal Krz (https://www.buergerserviceportal.nrw)." + }, { "shortName": { "": "Serviceportal Solingen" @@ -1030,25 +1053,6 @@ "category": "citizen", "subjectUrlInfo": "Using service from Servicekonto Nordrhein-Westfalen (https://servicekonto.nrw)." }, - { - "shortName": { - "": "Online-Portal Kreis Lippe" - }, - "longName": { - "": "Online-Portal des Kreis Lippe" - }, - "longDescription": { - "": "Mit der Online-Ausweisfunktion können Sie sich am Bürgerportal des Kreises Lippe registrieren, anmelden und den Online-Service 'Elternbeiträge' nutzen. Als Eltern können Sie nach der einmaligen Registrierung
    • Ihre Selbsteinschätzung für den Elternbeitrag online einreichen,
    • den Bearbeitungsstand nachverfolgen,
    • Bescheide elektronisch im Dokumentenbereich empfangen.
    " - }, - "address": "https://portal.kreis-lippe.de", - "homepage": "https://portal.kreis-lippe.de", - "phone": "+49 5231 62 0", - "postalAddress": "Kreis Lippe
    Felix-Fechenbach-Str. 5
    32756 Detmold", - "category": "citizen", - "subjectUrls": [ - "https://egov-services.krz.de" - ] - }, { "shortName": { "": "Serviceportal Kreis Paderborn" @@ -1087,9 +1091,7 @@ "category": "citizen", "image": "Hameln-Pyrmont_image.png", "icon": "Hameln-Pyrmont_icon.png", - "subjectUrls": [ - "https://idp.servicekonto.niedersachsen.de" - ] + "subjectUrlInfo": "Using service from Servicekonto Niedersachsen (https://idp.servicekonto.niedersachsen.de)." }, { "shortName": { @@ -1178,8 +1180,8 @@ "longDescription": { "": "In diesem Portal haben Sie die Möglichkeit, Dienstleistungen Ihrer Zulassungsbehörde online zu beantragen und abzuwickeln. Kernbestandteil des Portals ist die internetbasierte Fahrzeugzulassung (i-Kfz)." }, - "address": "https://buergerportal.merzig-wadern.de/kfz", - "homepage": "https://buergerportal.merzig-wadern.de", + "address": "https://www.buergerservice-portal.de/saarland/lkrmerzigwadern", + "homepage": "https://www.merzig-wadern.de", "phone": "+49 6861 80 101", "email": "info@merzig-wadern.de", "postalAddress": "Landkreis Merzig-Wadern
    Bahnhofstraße 44
    66663 Merzig", @@ -1506,7 +1508,7 @@ "": "Selbstauskunft/ 'Meine Daten einsehen'" }, "longDescription": { - "": "Die AusweisApp2 verfügt über die Funktion 'Meine Daten einsehen'. Mit dieser Funktion können Sie eine Test-Authentisierung durchführen und die auf dem Personalausweis, elektronischen Aufenthaltstitel oder der eID-Karte gespeicherten Daten auslesen. Sie können also eine Selbstauskunft durchführen.

    Der App-Hersteller, die Governikus GmbH & Co. KG, bietet diesen Dienst an und erscheint daher als Anbieter, bei dem Sie sich ausweisen möchten. Nach Eingabe Ihrer PIN und erfolgreicher Datenübertragung werden Ihnen Ihre persönlichen Ausweis-Daten in der AusweisApp2 angezeigt. Hierbei handelt es sich um einen reinen Demonstrationsdienst, d.h. die ausgelesenen Daten werden lediglich zur Anzeige gebracht und weder gespeichert noch weitergegeben." + "": "Die AusweisApp verfügt über die Funktion 'Meine Daten einsehen'. Mit dieser Funktion können Sie eine Test-Authentisierung durchführen und die auf dem Personalausweis, elektronischen Aufenthaltstitel oder der eID-Karte gespeicherten Daten auslesen. Sie können also eine Selbstauskunft durchführen.

    Der App-Hersteller, die Governikus GmbH & Co. KG, bietet diesen Dienst an und erscheint daher als Anbieter, bei dem Sie sich ausweisen möchten. Nach Eingabe Ihrer PIN und erfolgreicher Datenübertragung werden Ihnen Ihre persönlichen Ausweis-Daten in der AusweisApp angezeigt. Hierbei handelt es sich um einen reinen Demonstrationsdienst, d.h. die ausgelesenen Daten werden lediglich zur Anzeige gebracht und weder gespeichert noch weitergegeben." }, "address": "https://www.ausweisapp.bund.de/aa2/download", "homepage": "https://www.ausweisapp.bund.de", @@ -1531,7 +1533,7 @@ "longDescription": { "": "Das Service-Portal bietet Online-Dienste rund um die KFZ-Zulassung. Sie können Ihr Auto z.B. online abmelden. Weitere Angebote wie die komplette online KFZ-Wiederzulassung und -Zulassung sind im Aufbau." }, - "address": "https://www.buergerserviceportal.nrw/krz/lkrlippe", + "address": "https://www.kreis-lippe.de/kreis-lippe/verwaltung-und-service/buergerservice/kreisverwaltung/ikfz-service.php", "homepage": "https://www.kreis-lippe.de", "phone": "+49 5231 62 0", "email": "stva@kreis-lippe.de", @@ -1993,12 +1995,12 @@ "": "Mit sign-me, dem digitalen Service für Ihre sichere Online-Unterschrift, wickeln Sie Ihre papierbasierten Unterschriftsprozesse durchgängig elektronisch ab. Ob Sie europaweit Dokumente austauschen, Transaktionen absichern oder Verträge unterschreiben wollen - mit dem digitalen Signaturservice ist dies möglich: online, komfortabel und rechtsverbindlich. Mit sign-me senken Sie Kosten, optimieren Workflows, verringern Abbruchraten bei Vertragsabschlüssen und verbessern die Kundenzufriedenheit. sign-me ermöglicht die Nutzung aller Signaturniveaus der eIDAS-Verordnung - von der einfachen über die fortgeschrittene bis hin zur qualifizierten Online-Unterschrift. Letztere erfüllt das Schriftformerfordernis und ist in der Rechtswirkung der handschriftlichen Unterschrift gleichgestellt." }, "address": "https://cloud.sign-me.de/signature/start", - "homepage": "https://www.bundesdruckerei.de/de/loesungen/sign-me", + "homepage": "https://www.d-trust.net/de/loesungen/sign-me", "image": "SignMe_image.jpg", "icon": "SignMe_icon.png", "phone": "+49 30 25980", "email": "vertrieb@d-trust.net", - "postalAddress": "Bundesdruckerei GmbH
    Kommandantenstraße 18
    10969 Berlin", + "postalAddress": "D-Trust GmbH
    Kommandantenstraße 15
    10969 Berlin", "category": "other", "subjectUrlInfo": "Using service from AusweisIDent (https://ausweisident.eid-service.de)." }, @@ -2084,6 +2086,26 @@ "category": "citizen", "subjectUrlInfo": "Using service from Niedersächsisches Ministerium für Inneres und Sport (https://e-id.niedersachsen.de)." }, + { + "shortName": { + "": "Service-Portal der Stadt Herborn" + }, + "longName": { + "": "Service-Portal der Stadt Herborn" + }, + "longDescription": { + "": "Die Stadt Herborn bietet eine Vielzahl von Dienstleistungen an, die online abgewickelt werden können. Dieses Portal bietet einen jederzeit aktuellen Überblick über die zur Verfügung stehenden Dienste." + }, + "address": "https://www.herborn.de/rathaus-politik/dienstleistungen-von-a-z/?online_only", + "homepage": "https://www.herborn.de", + "phone": "+49 2772 708 0", + "email": "info@herborn.de", + "postalAddress": "Magistrat der Stadt Herborn
    Hauptstraße 39
    35745 Herborn", + "image": "StadtHerborn_image.png", + "icon": "StadtHerborn_icon.png", + "category": "citizen", + "subjectUrlInfo": "Using service from Führungszeugnis und Auskunft aus dem Gewerbezentralregister (https://www.fuehrungszeugnis.bund.de)." + }, { "shortName": { "": "Stadt Oberursel - Online Dienste" @@ -2197,9 +2219,8 @@ "longDescription": { "": "Der Unterhaltsvorschuss ist eine staatliche Leistung für Kinder von Alleinerziehenden. Er hilft, die finanzielle Lebensgrundlage Ihres Kindes zu sichern, wenn der andere Elternteil nicht oder nur teilweise oder nicht regelmäßig Unterhalt in Höhe des Unterhaltsvorschusses zahlt. Sie können Unterhaltsvorschuss mit diesem Online-Dienst oder mit dem Papierantrag in Ihrer zuständigen Unterhaltsvorschuss-Stelle beantragen. Bitte beachten Sie, dass der Onlineantrag Unterhaltsvorschuss Online noch nicht in allen deutschen UV-Stellen verfügbar ist." }, - "address": "https://serviceportal.gemeinsamonline.de/Onlinedienste/Service/Entry/UVORSCHUSS", - "homepage": "https://www.finanzen.bremen.de/digitalisierung/nachnutzbare-ozg-services/uvo-108593", - "email": "betrieb-onlinedienste@finanzen.bremen.de", + "address": "https://www.unterhaltsvorschuss-online.de", + "homepage": "https://www.unterhaltsvorschuss-online.de", "postalAddress": "Der Senator für Finanzen
    Projektteam Unterhaltsvorschuss
    Rudolf-Hilferding-Platz 1
    28195 Bremen", "category": "citizen", "icon": "UVO_icon.svg", @@ -2207,24 +2228,6 @@ "https://idp.serviceportal.gemeinsamonline.de" ] }, - { - "shortName": { - "": "UVOJahr" - }, - "longName": { - "": "Unterhaltsvorschuss - Jährliche Überprüfung" - }, - "longDescription": { - "": "Viele Kinder Alleinerziehender erhalten Unterhaltsvorschuss. Die Unterhaltsvorschuss-Stelle muss jährlich prüfen, ob dem Kind der Unterhaltsvorschuss noch zusteht. Hier können Bürgerinnen und Bürger die notwendigen Angaben machen. Bitte beachten Sie, dass der Onlineantrag Unterhaltsvorschuss Online noch nicht in allen deutschen UV-Stellen verfügbar ist." - }, - "address": "https://serviceportal.gemeinsamonline.de/Onlinedienste/Service/Entry/UVOJAHR", - "homepage": "https://www.finanzen.bremen.de/digitalisierung/nachnutzbare-ozg-services/uvo-108593", - "email": "betrieb-onlinedienste@finanzen.bremen.de", - "postalAddress": "Der Senator für Finanzen
    Projektteam Unterhaltsvorschuss
    Rudolf-Hilferding-Platz 1
    28195 Bremen", - "category": "citizen", - "icon": "UVOJahr_icon.svg", - "subjectUrlInfo": "Using service from Unterhaltsvorschuss Online (https://idp.serviceportal.gemeinsamonline.de)." - }, { "eidSupport": false, "shortName": { @@ -2413,7 +2416,7 @@ "homepage": "https://www.oberhausen.de", "email": "info@oberhausen.de", "longDescription": { - "": "Im Serviceportal der Stadt Oberhausen finden Sie alle Online-Leistungen der Stadtverwaltung, von der Beantragung einer Personenstandsurkunde über die Anmeldung eines Autos bis zur Beantragung eines Bewohnerparkausweises. Einzelne Leistungen erfordern hierbei auch die Authentifizierung mit dem elektronischen Personalausweis und der AusweisApp2." + "": "Im Serviceportal der Stadt Oberhausen finden Sie alle Online-Leistungen der Stadtverwaltung, von der Beantragung einer Personenstandsurkunde über die Anmeldung eines Autos bis zur Beantragung eines Bewohnerparkausweises. Einzelne Leistungen erfordern hierbei auch die Authentifizierung mit dem elektronischen Personalausweis und der AusweisApp." }, "postalAddress": "Stadt Oberhausen
    Schwartzstraße 72
    46042 Oberhausen", "icon": "StadtOberhausen_icon.png", @@ -2473,12 +2476,49 @@ "homepage": "https://www.augsburg.de", "email": "augsburg@augsburg.de", "longDescription": { - "": "Für viele Leistungen ist der Weg ins Amt nicht nötig: Sie können zahlreiche Leistungen online beantragen und falls nötig bequem von zu Hause aus bezahlen. Eine Liste der Online-Services finden Sie auf der Webseite der Stadt Augsburg.

    Voraussetzung für einige Online-Services ist die BayernID. Zur Registrierung können Sie Ihren Online-Ausweis mit dazugehöriger PIN, einem geeigneten Smartphone oder Tablet und der installierten AusweisApp2 nutzen.

    Informationen zur Registrierung in der BayernID können Sie nachlesen (https://id.bayernportal.de/).

    Ein Beispiel ist die internetbasierte Fahrzeugzulassung und Fahrzeugabmeldung, die von der Kfz-Zulassungsbehörde in Augsburg angeboten wird. Weitere Informationen finden Sie auf der Internetseite der Online-Zulassungsbehörde." + "": "Für viele Leistungen ist der Weg ins Amt nicht nötig: Sie können zahlreiche Leistungen online beantragen und falls nötig bequem von zu Hause aus bezahlen. Eine Liste der Online-Services finden Sie auf der Webseite der Stadt Augsburg.

    Voraussetzung für einige Online-Services ist die BayernID. Zur Registrierung können Sie Ihren Online-Ausweis mit dazugehöriger PIN, einem geeigneten Smartphone oder Tablet und der installierten AusweisApp nutzen.

    Informationen zur Registrierung in der BayernID können Sie nachlesen (https://id.bayernportal.de/).

    Ein Beispiel ist die internetbasierte Fahrzeugzulassung und Fahrzeugabmeldung, die von der Kfz-Zulassungsbehörde in Augsburg angeboten wird. Weitere Informationen finden Sie auf der Internetseite der Online-Zulassungsbehörde." }, "postalAddress": "Stadt Augsburg
    Rathausplatz 1
    86150 Augsburg", "icon": "StadtAugsburg_icon.png", "category": "citizen", "subjectUrlInfo": "Using service from Bürgerservice-Portale der bayerischen Kommunen (https://bayernid.freistaat.bayern)." + }, + { + "shortName": { + "": "Servicekonto Niedersachsen" + }, + "longName": { + "": "Servicekonto Niedersachsen" + }, + "address": "https://servicekonto.niedersachsen.de", + "homepage": "https://servicekonto.niedersachsen.de", + "longDescription": { + "": "Das Servicekonto ist Ihr persönlicher Online-Zugang zu den Leistungen der Behörden. Damit können Sie in Zukunft eine Vielzahl von Verwaltungsleistungen von zu Hause digital erledigen. Dies gilt insbesondere für Niedersachsen, das Konto können Sie aber auch deutschlandweit nutzen.

    Egal welche Verwaltungsleistung Sie gerade benötigen, Sie werden sich dazu mit Ihrem Servicekonto anmelden und den zugehörigen Antrag rechtssicher bei der Behörde einreichen können. Außerdem werden Ihnen auf Wunsch Informationen und Bescheide zu Ihren Anträgen in Zukunft schnell und digital in Ihr Servicekonto-Postfach zugestellt.

    Das Servicekonto ist ein Angebot der niedersächsischen Landesverwaltung an alle Nutzerinnen und Nutzer niedersächsischer Verwaltungsleistungen." + }, + "category": "citizen", + "subjectUrls": [ + "https://idp.servicekonto.niedersachsen.de" + ] + }, + { + "shortName": { + "": "Serviceportal Schaumburg" + }, + "longName": { + "": "Regionales Serviceportal Schaumburg" + }, + "phone": "+49 5721 703 0", + "address": "https://www.serviceportal-schaumburg.de", + "homepage": "https://www.serviceportal-schaumburg.de", + "email": "info@schaumburg.de", + "longDescription": { + "": "Das gemeinsame Online-Serviceportal des Landkreises Schaumburg und der kreisangehörigen Kommunen ermöglicht es den Bürgerinnen und Bürgern, Anträge wie beispielsweise zum eigenen Gewerbe oder zum Bürger- und Wohngeld sicher und unkompliziert online einzureichen sowie Bescheide und Mitteilungen im persönlichen Postfach digital empfangen zu können. Der Landkreis Schaumburg bietet außerdem die Möglichkeit zur online Fahrzeugzulassung (i-KFZ).

    Bürgerinnen und Bürger können über das Online-Serviceportalaber nicht nur auf die Dienstleistungen der Kreisverwaltung zugreifen, sondern auch die Dienstleistungen der einzelnen kreisangehörigen Städte, Samtgemeinden und Gemeinden aufrufen. Das Serviceportal dient somit als zentrale Anlaufstelle für alle kommunalen Verwaltungsangelegenheiten." + }, + "postalAddress": "Landkreis Schaumburg
    Jahnstraße 20
    31655 Stadthagen", + "icon": "Schaumburg_icon.svg", + "image": "Schaumburg_image.svg", + "category": "citizen", + "subjectUrlInfo": "Using service from Servicekonto Niedersachsen (https://idp.servicekonto.niedersachsen.de)." } ] } diff --git a/resources/updatable-files/supported-readers.json b/resources/updatable-files/supported-readers.json index 98e4e5a39..b0ca340c5 100644 --- a/resources/updatable-files/supported-readers.json +++ b/resources/updatable-files/supported-readers.json @@ -3,6 +3,9 @@ { "VendorId": "0x0000", "ProductId": "0x0000", + "ProductIds": [ + "0x0000" + ], "Name": "Smartphone als Kartenleser", "Pattern": "^NFC.*", "Icon": "img_RemoteReader.png", @@ -27,13 +30,14 @@ { "Platforms": [ { + "DE": "Windows", + "EN": "Windows", "os": "win" }, { + "DE": "macOS", + "EN": "macOS", "os": "mac" - }, - { - "os": "unknown" } ], "DE": "Erfordert ein Smartphone mit aktiviertem Fernzugriff.", @@ -44,6 +48,9 @@ { "VendorId": "0x0000", "ProductId": "0x0001", + "ProductIds": [ + "0x0001" + ], "Name": "PersoSim", "Pattern": "^PersoSim.*", "Icon": "img_PersoSim.png", @@ -68,6 +75,9 @@ { "VendorId": "0x0000", "ProductId": "0x0002", + "ProductIds": [ + "0x0002" + ], "Name": "Simulator", "Pattern": "^Simulator$", "Icon": "img_Simulator.png", @@ -92,6 +102,9 @@ { "VendorId": "0x0C4B", "ProductId": "0x0501", + "ProductIds": [ + "0x0501" + ], "Name": "REINER SCT cyberJack RFID komfort", "Pattern": "REINER SCT cyberJack RFID komfort", "Icon": "img_Reiner_SCT_cyberjack_RFID_komfort.png", @@ -126,13 +139,14 @@ { "Platforms": [ { + "DE": "Windows", + "EN": "Windows", "os": "win" }, { + "DE": "macOS", + "EN": "macOS", "os": "mac" - }, - { - "os": "unknown" } ], "DE": "Es ist notwendig, die Treiber vom Hersteller zu installieren. Dazu folgen Sie bitte dem jeweiligen Link für Ihr Betriebssystem zur Herstellerseite.", @@ -143,6 +157,9 @@ { "VendorId": "0x0C4B", "ProductId": "0x2007", + "ProductIds": [ + "0x2007" + ], "Name": "REINER SCT cyberJack RFID komfort FON", "Pattern": "^REINER SCT cyberJack RFID komfort FON", "Icon": "img_Reiner_SCT_cyberjack_RFID_komfort.png", @@ -169,9 +186,13 @@ { "Platforms": [ { + "DE": "Windows", + "EN": "Windows", "os": "win" }, { + "DE": "macOS", + "EN": "macOS", "os": "mac" } ], @@ -183,6 +204,9 @@ { "VendorId": "0x0C4B", "ProductId": "0x0500", + "ProductIds": [ + "0x0500" + ], "Name": "REINER SCT cyberJack RFID standard", "Pattern": "REINER SCT cyberJack RFID standard", "Icon": "img_Reiner_SCT_cyberjack_RFID_standard.png", @@ -217,13 +241,14 @@ { "Platforms": [ { + "DE": "Windows", + "EN": "Windows", "os": "win" }, { + "DE": "macOS", + "EN": "macOS", "os": "mac" - }, - { - "os": "unknown" } ], "DE": "Es ist notwendig, die Treiber vom Hersteller zu installieren. Dazu folgen Sie bitte dem jeweiligen Link für Ihr Betriebssystem zur Herstellerseite.", @@ -234,6 +259,9 @@ { "VendorId": "0x0C4B", "ProductId": "0x9102", + "ProductIds": [ + "0x9102" + ], "Name": "REINER SCT cyberJack RFID basis", "Pattern": "REINER SCT cyberJack RFID basis", "Icon": "img_Reiner_SCT_cyberjack_RFID_basis.png", @@ -268,9 +296,13 @@ { "Platforms": [ { + "DE": "macOS", + "EN": "macOS", "os": "mac" }, { + "DE": "bis Windows 8.1", + "EN": "up to Windows 8.1", "os": "win", "max": "6.3" } @@ -281,8 +313,10 @@ { "Platforms": [ { + "DE": "ab Windows 10", + "EN": "from Windows 10", "os": "win", - "min": "10.0" + "min": "10" } ], "DE": "Es ist notwendig, die Treiber vom Hersteller zu installieren. Dazu folgen Sie bitte dem jeweiligen Link für Ihr Betriebssystem zur Herstellerseite.", @@ -293,8 +327,11 @@ { "VendorId": "0x0C4B", "ProductId": "0x0505", + "ProductIds": [ + "0x0505" + ], "Name": "REINER SCT cyberJack wave", - "Pattern": "REINER SCT cyberJack wave( USB 1)?$", + "Pattern": "REINER SCT cyberJack wave( USB)?( \\d{1,1})?$", "Icon": "img_cyberjack_wave.png", "IconWithNPA": "img_cyberjack_wave_mit_ausweis.png", "Drivers": [ @@ -304,7 +341,7 @@ "os": "win" } ], - "URL": "https://www.reiner-sct.com/support/support-anfrage/?os=Windows&productGroup=77304735&product=77304828&q=driver#choice5" + "URL": "https://help.reiner-sct.com/de/support/solutions/articles/101000475765" }, { "Platforms": [ @@ -327,20 +364,27 @@ { "Platforms": [ { + "DE": "Windows", + "EN": "Windows", "os": "win" }, { + "DE": "macOS", + "EN": "macOS", "os": "mac" } ], - "DE": "Es ist notwendig, die Treiber vom Hersteller zu installieren. Dazu folgen Sie bitte dem jeweiligen Link für Ihr Betriebssystem zur Herstellerseite.", - "EN": "It is necessary to install the drivers from the manufacturer. Please follow the relevant link for your operating system." + "DE": "Es ist notwendig, die Treiber vom Hersteller zu installieren. Dazu folgen Sie bitte dem jeweiligen Link für Ihr Betriebssystem zur Herstellerseite. Nach der Installation ist ein Neustart erforderlich.", + "EN": "It is necessary to install the drivers from the manufacturer. Please follow the relevant link for your operating system. A reboot is required after the installation of the driver." } ] }, { "VendorId": "0x0D46", "ProductId": "0x301D", + "ProductIds": [ + "0x301D" + ], "Name": "KOBIL IDToken", "Pattern": "^KOBIL (Systems )?IDToken( \\d{1,1})?$", "Icon": "img_KOBIL_ID_Token.png", @@ -357,7 +401,7 @@ }, { "os": "mac", - "min": "11.0" + "min": "11" }, { "os": "unknown" @@ -370,6 +414,8 @@ { "Platforms": [ { + "DE": "Windows", + "EN": "Windows", "os": "win" } ], @@ -379,12 +425,16 @@ { "Platforms": [ { + "DE": "bis macOS 10.14 (Mojave)", + "EN": "up to macOS 10.14 (Mojave)", "os": "mac", "max": "10.14" }, { + "DE": "ab macOS 11 (Big Sur)", + "EN": "from macOS 11 (Big Sur)", "os": "mac", - "min": "11.0" + "min": "11" } ], "DE": "Der Kartenleser funktioniert mit dem systemseitig installierten Treiber.", @@ -396,6 +446,9 @@ { "VendorId": "0x04E6", "ProductId": "0x512B", + "ProductIds": [ + "0x512B" + ], "Name": "Identiv SDI011 Dual Interface Smart Card Reader", "Pattern": "^(SCM Microsystems Inc. )?SDI011G? ((Contactless Reader( 0)?)|((USB Smart Card|Contactless) Reader\\([12]\\)))$", "Icon": "img_Identive_SDI011.png", @@ -413,17 +466,15 @@ "os": "unknown" } ], - "URL": "https://support.identiv.com/sdi010-011/" + "URL": "https://support.identiv.com/sdi010-011" } ], "Information": [ { "Platforms": [ { - "os": "win", - "max": "6.3" - }, - { + "DE": "macOS", + "EN": "macOS", "os": "mac" } ], @@ -433,18 +484,35 @@ { "Platforms": [ { + "DE": "bis Windows 10", + "EN": "up to Windows 10", "os": "win", - "min": "10.0" + "max": "10.0.19999" } ], - "DE": "Der Kartenleser funktioniert mit dem systemseitig installierten Treiber. Falls Sie jedoch den Treiber von der Webseite des Herstellers installieren möchten, ist anschließend ein Neustart erforderlich.", - "EN": "The card reader operates with the driver automatically installed by the system. In case you prefer to install the driver from the manufacturer's webseite, a reboot is required." + "DE": "Es ist notwendig, die Treiber vom Hersteller zu installieren. Dazu folgen Sie bitte dem jeweiligen Link für Ihr Betriebssystem zur Herstellerseite.", + "EN": "It is necessary to install the drivers from the manufacturer. Please follow the relevant link for your operating system." + }, + { + "Platforms": [ + { + "DE": "ab Windows 11", + "EN": "from Windows 11", + "os": "win", + "min": "10.0.20000" + } + ], + "DE": "Es ist notwendig, die Treiber vom Hersteller zu installieren. Dazu folgen Sie bitte dem jeweiligen Link für Ihr Betriebssystem zur Herstellerseite. Bitte beachten Sie nach der Treiberinstallation die Windows-Informationen zur Einstellung der Gerätesicherheit.", + "EN": "It is necessary to install the drivers from the manufacturer. Please follow the relevant link for your operating system. After the driver installation, please observe the Windows information notification regarding your device security settings." } ] }, { "VendorId": "0x04E6", "ProductId": "0x5292", + "ProductIds": [ + "0x5292" + ], "Name": "Identiv SCL01x Contactless Smart Card Reader", "Pattern": "^(SCM Microsystems Inc. )?SCL011G? Contactless Reader( 0)?$", "Icon": "img_Identive_SCL011.png", @@ -459,35 +527,27 @@ "os": "unknown" } ], - "URL": "https://support.identiv.com/scl010-scl011/" + "URL": "https://support.identiv.com/scl010-scl011" } ], "Information": [ { "Platforms": [ { - "os": "win", - "max": "6.3" - } - ], - "DE": "Der Kartenleser funktioniert mit dem systemseitig installierten Treiber", - "EN": "The card reader operates with the driver automatically installed by the system." - }, - { - "Platforms": [ - { - "os": "win", - "min": "10.0" + "DE": "Windows", + "EN": "Windows", + "os": "win" } ], - "DE": "Es ist notwendig, die Treiber vom Hersteller zu installieren. Dazu folgen Sie bitte dem jeweiligen Link für Ihr Betriebssystem zur Herstellerseite.", - "EN": "It is necessary to install the drivers from the manufacturer. Please follow the relevant link for your operating system." + "DE": "Es ist notwendig, die Treiber vom Hersteller zu installieren. Dazu folgen Sie bitte dem jeweiligen Link für Ihr Betriebssystem zur Herstellerseite. Bitte beachten Sie bei der Auswahl, dass nur der \"Windows 10 Drivers (SCL011 nPA)\" empfohlen wird.", + "EN": "It is necessary to install the drivers from the manufacturer. Please follow the relevant link for your operating system. Please note that only the driver named \"Windows 10 Drivers (SCL011 nPA)\" is advised for this card reader." }, { "Platforms": [ { - "os": "mac", - "min": "10.15" + "DE": "MacOS", + "EN": "MacOS", + "os": "mac" } ], "DE": "Der Kartenleser wird nicht mehr unterstützt, leider bietet der Hersteller keine aktuellen Treiber an.", @@ -499,6 +559,9 @@ { "VendorId": "0x04E6", "ProductId": "0x5790", + "ProductIds": [ + "0x5790" + ], "Name": "Identiv 3700 F", "Pattern": "^Identiv (uTrust|cloud|CLOUD) 3700 F (Contactless|CL) Reader( 0)?$", "Icon": "img_Identive_XXXX_F.png", @@ -523,20 +586,27 @@ { "Platforms": [ { + "DE": "Windows", + "EN": "Windows", "os": "win" }, { + "DE": "macOS", + "EN": "macOS", "os": "mac" } ], - "DE": "Der Kartenleser funktioniert mit dem systemseitig installierten Treiber.", - "EN": "The card reader operates with the driver automatically installed by the system." + "DE": "Der Kartenleser funktioniert mit dem systemseitig installierten Treiber. Alternativ können Sie den Treiber von der Webseite des Herstellers verwenden.", + "EN": "The card reader operates with the driver automatically installed by the system. Alternatively you have the option to install a driver from the manufacturer's website." } ] }, { "VendorId": "0x04E6", "ProductId": "0x5612", + "ProductIds": [ + "0x5612" + ], "Name": "Identiv 3720 F", "Pattern": "^Identiv (uTrust|cloud|CLOUD) 3720 (Contactless|CL) Reader( 0|\\(1\\))$", "Icon": "img_Identive_XXXX_F.png", @@ -554,38 +624,40 @@ "os": "unknown" } ], - "URL": "https://support.identiv.com/utrust-3720-f-multi-technology-multi-frequency-smart-card-reader/" + "URL": "https://support.identiv.com/utrust-3720-f-multi-technology-multi-frequency-smart-card-reader" } ], "Information": [ { "Platforms": [ { - "os": "win", - "max": "6.3" - }, - { - "os": "mac" + "DE": "Windows", + "EN": "Windows", + "os": "win" } ], - "DE": "Der Kartenleser funktioniert mit dem systemseitig installierten Treiber.", - "EN": "The card reader operates with the driver automatically installed by the system." + "DE": "Es ist notwendig, die Treiber vom Hersteller zu installieren. Dazu folgen Sie bitte dem jeweiligen Link für Ihr Betriebssystem zur Herstellerseite.", + "EN": "It is necessary to install the drivers from the manufacturer. Please follow the relevant link for your operating system." }, { "Platforms": [ { - "os": "win", - "min": "10.0" + "DE": "macOS", + "EN": "macOS", + "os": "mac" } ], - "DE": "Es ist notwendig, die Treiber vom Hersteller zu installieren. Dazu folgen Sie bitte dem jeweiligen Link für Ihr Betriebssystem zur Herstellerseite.", - "EN": "It is necessary to install the drivers from the manufacturer. Please follow the relevant link for your operating system." + "DE": "Es ist notwendig, die Treiber vom Hersteller zu installieren. Dazu folgen Sie bitte dem jeweiligen Link für Ihr Betriebssystem zur Herstellerseite. Nach der Installation ist ein Neustart erforderlich.", + "EN": "It is necessary to install the drivers from the manufacturer. Please follow the relevant link for your operating system. A reboot is required after the installation of the driver." } ] }, { "VendorId": "0x04E6", "ProductId": "0x5613", + "ProductIds": [ + "0x5613" + ], "Name": "Identiv 3721 F", "Pattern": "^Identiv (uTrust|cloud|CLOUD) 3721 (Contactless|CL) Reader( 0|\\(1\\))$", "Icon": "img_Identive_XXXX_F.png", @@ -603,38 +675,40 @@ "os": "unknown" } ], - "URL": "https://support.identiv.com/utrust-3721-f-multi-technology-multi-frequency-smart-card-reader-with-keyboard-emulation/" + "URL": "https://support.identiv.com/utrust-3721-f-multi-technology-multi-frequency-smart-card-reader-with-keyboard-emulation" } ], "Information": [ { "Platforms": [ { - "os": "win", - "max": "6.3" - }, - { - "os": "mac" + "DE": "Windows", + "EN": "Windows", + "os": "win" } ], - "DE": "Der Kartenleser funktioniert mit dem systemseitig installierten Treiber.", - "EN": "The card reader operates with the driver automatically installed by the system." + "DE": "Es ist notwendig, die Treiber vom Hersteller zu installieren. Dazu folgen Sie bitte dem jeweiligen Link für Ihr Betriebssystem zur Herstellerseite.", + "EN": "It is necessary to install the drivers from the manufacturer. Please follow the relevant link for your operating system." }, { "Platforms": [ { - "os": "win", - "min": "10.0" + "DE": "macOS", + "EN": "macOS", + "os": "mac" } ], - "DE": "Es ist notwendig, die Treiber vom Hersteller zu installieren. Dazu folgen Sie bitte dem jeweiligen Link für Ihr Betriebssystem zur Herstellerseite.", - "EN": "It is necessary to install the drivers from the manufacturer. Please follow the relevant link for your operating system." + "DE": "Es ist notwendig, die Treiber vom Hersteller zu installieren. Dazu folgen Sie bitte dem jeweiligen Link für Ihr Betriebssystem zur Herstellerseite. Nach der Installation ist ein Neustart erforderlich.", + "EN": "It is necessary to install the drivers from the manufacturer. Please follow the relevant link for your operating system. A reboot is required after the installation of the driver." } ] }, { "VendorId": "0x04E6", "ProductId": "0x5591", + "ProductIds": [ + "0x5591" + ], "Name": "Identiv SCL3711", "Pattern": "(SCM Microsystems SCL3711 reader & NFC device 0|SCL3711 Reader and NFC device)", "Icon": "img_Identive_SCL3711.png", @@ -645,9 +719,6 @@ { "os": "win" }, - { - "os": "mac" - }, { "os": "unknown" } @@ -659,6 +730,8 @@ { "Platforms": [ { + "DE": "Windows", + "EN": "Windows", "os": "win" } ], @@ -668,22 +741,22 @@ { "Platforms": [ { - "os": "mac", - "max": "10.12" - }, - { - "os": "mac", - "min": "10.14" + "DE": "macOS", + "EN": "macOS", + "os": "mac" } ], - "DE": "Der Kartenleser funktioniert mit dem systemseitig installierten Treiber. Falls Sie jedoch den Treiber von der Webseite des Herstellers installieren möchten, ist anschließend ein Neustart erforderlich.", - "EN": "The card reader operates with the driver automatically installed by the system. In case you prefer to install the driver from the manufacturer's webseite, a reboot is required." + "DE": "Der Kartenleser wird nicht mehr unterstützt, leider ist der vom Hersteller angebotene Treiber veraltert und funktioniert nicht.", + "EN": "The card reader is no longer supported, the driver offered by the manufacturer is unfortunately outdated and does not work." } ] }, { "VendorId": "0x04E6", "ProductId": "0x5720", + "ProductIds": [ + "0x5720" + ], "Name": "Identiv Cloud 4700 F", "Pattern": "(Identive CLOUD 4700 F Contactless Reader( 0| 1)|Identiv uTrust 4700 F Dual Interface Reader\\(2\\))", "Icon": "img_Identive_Cloud_4700_F.png", @@ -701,33 +774,40 @@ "os": "unknown" } ], - "URL": "https://www.scm-pc-card.de/index.php?lang=en&page=download&function=show_downloads&product_id=832" + "URL": "https://support.identiv.com/4701f" } ], "Information": [ { "Platforms": [ { + "DE": "Windows", + "EN": "Windows", "os": "win" } ], - "DE": "Der Kartenleser funktioniert mit dem systemseitig installierten Treiber. Falls Sie jedoch den Treiber von der Webseite des Herstellers installieren möchten, ist anschließend ein Neustart erforderlich.", - "EN": "The card reader operates with the driver automatically installed by the system. In case you prefer to install the driver from the manufacturer's webseite, a reboot is required." + "DE": "Der Kartenleser funktioniert mit dem systemseitig installierten Treiber. Alternativ können Sie den Treiber von der Webseite des Herstellers verwenden. Bitte beachten Sie dabei, dass nur ein Treiber für Modell 4701 F angeboten wird, dieser sich aber für Modell 4700 F eignet.", + "EN": "The card reader operates with the driver automatically installed by the system. Alternatively you have the option to install a driver from the manufacturer's website. Please note that a driver is provided for the 4701 F model only, but it is suitable for the 4700 F model." }, { "Platforms": [ { + "DE": "macOS", + "EN": "macOS", "os": "mac" } ], - "DE": "Es ist notwendig, die Treiber vom Hersteller zu installieren. Dazu folgen Sie bitte dem jeweiligen Link für Ihr Betriebssystem zur Herstellerseite.", - "EN": "It is necessary to install the drivers from the manufacturer. Please follow the relevant link for your operating system." + "DE": "Es ist notwendig, die Treiber vom Hersteller zu installieren. Dazu folgen Sie bitte dem jeweiligen Link für Ihr Betriebssystem zur Herstellerseite. Nach der Installation ist ein Neustart erforderlich.", + "EN": "It is necessary to install the drivers from the manufacturer. Please follow the relevant link for your operating system. A reboot is required after the installation of the driver." } ] }, { "VendorId": "0x04E6", "ProductId": "0x5724", + "ProductIds": [ + "0x5724" + ], "Name": "Identiv 4701 F", "Pattern": "^Identiv (uTrust|cloud|CLOUD) 4701 F (Contactless|CL|Dual Interface) Reader( 0| 1|\\(1\\)|\\(2\\))?$", "Icon": "img_Identive_4701_F.png", @@ -745,22 +825,26 @@ "os": "unknown" } ], - "URL": "https://www.scm-pc-card.de/index.php?page=download&function=show_downloads&lang=de&product_id=921" + "URL": "https://support.identiv.com/4701f" } ], "Information": [ { "Platforms": [ { + "DE": "Windows", + "EN": "Windows", "os": "win" } ], - "DE": "Der Kartenleser funktioniert mit dem systemseitig installierten Treiber. Falls Sie jedoch den Treiber von der Webseite des Herstellers installieren möchten, ist anschließend ein Neustart erforderlich.", - "EN": "The card reader operates with the driver automatically installed by the system. In case you prefer to install the driver from the manufacturer's webseite, a reboot is required." + "DE": "Der Kartenleser funktioniert mit dem systemseitig installierten Treiber. Alternativ können Sie den Treiber von der Webseite des Herstellers verwenden.", + "EN": "The card reader operates with the driver automatically installed by the system. Alternatively you have the option to install a driver from the manufacturer's website." }, { "Platforms": [ { + "DE": "macOS", + "EN": "macOS", "os": "mac" } ], @@ -772,6 +856,9 @@ { "VendorId": "0x072F", "ProductId": "0x0901", + "ProductIds": [ + "0x0901" + ], "Name": "ACS ACR1281U", "Pattern": "ACS ACR1281 PICC Reader( 0)?", "Icon": "img_ACS_ACR1281U.png", @@ -793,6 +880,8 @@ { "Platforms": [ { + "DE": "Windows", + "EN": "Windows", "os": "win" } ], @@ -802,6 +891,8 @@ { "Platforms": [ { + "DE": "macOS", + "EN": "macOS", "os": "mac" } ], @@ -813,6 +904,9 @@ { "VendorId": "0x076B", "ProductId": "0x5340", + "ProductIds": [ + "0x5340" + ], "Name": "HID OMNIKEY 5021-CL", "Pattern": "OMNIKEY CardMan 5x21-CL 0|OMNIKEY CardMan \\(076B:5340\\) 5021 CL", "Icon": "img_HID_Omnikey_Mobile_Reader_502X_CL.png", @@ -837,7 +931,10 @@ { "Platforms": [ { - "os": "win" + "DE": "bis Windows 10", + "EN": "up to Windows 10", + "os": "win", + "max": "10.0.19999" } ], "DE": "Es ist notwendig, die Treiber vom Hersteller zu installieren. Beachten Sie bei der Auswahl, dass nur der \"X-CHIP WINDOWS BU & RU driver\" funktioniert.", @@ -846,6 +943,20 @@ { "Platforms": [ { + "DE": "ab Windows 11", + "EN": "from Windows 11", + "os": "win", + "min": "10.0.20000" + } + ], + "DE": "Der Kartenleser funktioniert mit dem systemseitig installierten Treiber.", + "EN": "The card reader is compatible with the installed system driver." + }, + { + "Platforms": [ + { + "DE": "macOS", + "EN": "macOS", "os": "mac" } ], @@ -857,6 +968,9 @@ { "VendorId": "0x076B", "ProductId": "0x5022", + "ProductIds": [ + "0x5022" + ], "Name": "HID OMNIKEY 5022-CL", "Pattern": "HID Global OMNIKEY 5022 Smart Card Reader( 0)?$", "Icon": "img_HID_Omnikey_Mobile_Reader_502X_CL.png", @@ -866,9 +980,17 @@ "Platforms": [ { "os": "win" - }, + } + ], + "URL": "https://www3.hidglobal.com/drivers/39910" + }, + { + "Platforms": [ { "os": "mac" + }, + { + "os": "unknown" } ], "URL": "https://www.hidglobal.de/drivers" @@ -878,16 +1000,27 @@ { "Platforms": [ { - "os": "win" + "DE": "bis Windows 10", + "EN": "up to Windows 10", + "os": "win", + "max": "10.0.19999" } ], - "DE": "Der Kartenleser funktioniert mit dem systemseitig installierten Treiber. Falls Sie jedoch den Treiber von der Webseite des Herstellers installieren möchten, ist anschließend ein Neustart erforderlich.", - "EN": "The card reader operates with the driver automatically installed by the system. In case you prefer to install the driver from the manufacturer's webseite, a reboot is required." + "DE": "Der Kartenleser funktioniert mit dem systemseitig installierten Treiber. Alternativ können Sie den Treiber von der Webseite des Herstellers verwenden.", + "EN": "The card reader operates with the driver automatically installed by the system. Alternatively you have the option to install a driver from the manufacturer's website." }, { "Platforms": [ { + "DE": "macOS", + "EN": "macOS", "os": "mac" + }, + { + "DE": "ab Windows 11", + "EN": "from Windows 11", + "os": "win", + "min": "10.0.20000" } ], "DE": "Der Kartenleser funktioniert mit dem systemseitig installierten Treiber.", @@ -898,6 +1031,9 @@ { "VendorId": "0x076B", "ProductId": "0x5321", + "ProductIds": [ + "0x5321" + ], "Name": "HID OMNIKEY 5321 v2", "Pattern": "OMNIKEY CardMan 5x21-CL 0|OMNIKEY CardMan \\(076B:5321\\) 5321(\\(1\\)|\\(2\\))", "Icon": "img_HID_Global_OMNIKEY_5321_V2.png", @@ -907,32 +1043,71 @@ "Platforms": [ { "os": "win" - }, + } + ], + "URL": "https://www3.hidglobal.com/drivers/29765" + }, + { + "Platforms": [ { "os": "mac" } ], - "URL": "https://www.hidglobal.de/drivers" + "URL": "https://www3.hidglobal.com/drivers/29885" + }, + { + "Platforms": [ + { + "os": "unknown" + } + ], + "URL": "https://www3.hidglobal.com/drivers" } ], "Information": [ { "Platforms": [ { - "os": "win" - }, - { - "os": "mac" + "DE": "bis Windows 10", + "EN": "up to Windows 10", + "os": "win", + "max": "10.0.19999" } ], "DE": "Es ist notwendig, die Treiber vom Hersteller zu installieren. Dazu folgen Sie bitte dem jeweiligen Link für Ihr Betriebssystem zur Herstellerseite.", "EN": "It is necessary to install the drivers from the manufacturer. Please follow the relevant link for your operating system." + }, + { + "Platforms": [ + { + "DE": "ab Windows 11", + "EN": "from Windows 11", + "os": "win", + "min": "10.0.20000" + } + ], + "DE": "Der Kartenleser funktioniert mit dem systemseitig installierten Treiber.", + "EN": "The card reader is compatible with the installed system driver." + }, + { + "Platforms": [ + { + "DE": "macOS", + "EN": "macOS", + "os": "mac" + } + ], + "DE": "Es ist notwendig, die Treiber vom Hersteller zu installieren. Dazu folgen Sie bitte dem jeweiligen Link für Ihr Betriebssystem zur Herstellerseite. Nach der Installation ist ein Neustart erforderlich.", + "EN": "It is necessary to install the drivers from the manufacturer. Please follow the relevant link for your operating system. A reboot is required after the installation of the driver." } ] }, { "VendorId": "0x076B", "ProductId": "0x5421", + "ProductIds": [ + "0x5421" + ], "Name": "HID OMNIKEY 5421", "Pattern": "OMNIKEY CardMan 5x21-CL 0|OMNIKEY Smart Card Reader USB 0|OMNIKEY CardMan \\(076B:5421\\) 5421(\\(1\\)|\\(2\\))", "Icon": "img_HID_Omnikey_542x.png", @@ -942,43 +1117,73 @@ "Platforms": [ { "os": "win" - }, + } + ], + "URL": "https://www3.hidglobal.com/drivers/29765" + }, + { + "Platforms": [ { "os": "mac" - }, + } + ], + "URL": "https://www3.hidglobal.com/drivers/29885" + }, + { + "Platforms": [ { "os": "unknown" } ], - "URL": "https://www.hidglobal.com/drivers" + "URL": "https://www3.hidglobal.com/drivers" } ], "Information": [ { "Platforms": [ { - "os": "win" + "DE": "bis Windows 10", + "EN": "up to Windows 10", + "os": "win", + "max": "10.0.19999" + } + ], + "DE": "Es ist notwendig, die Treiber vom Hersteller zu installieren. Dazu folgen Sie bitte dem jeweiligen Link für Ihr Betriebssystem zur Herstellerseite.", + "EN": "It is necessary to install the drivers from the manufacturer. Please follow the relevant link for your operating system." + }, + { + "Platforms": [ + { + "DE": "ab Windows 11", + "EN": "from Windows 11", + "os": "win", + "min": "10.0.20000" } ], - "DE": "Es ist notwendig, die Treiber vom Hersteller zu installieren. Dazu folgen Sie bitte dem jeweiligen Link für Ihr Betriebssystem zur Herstellerseite. Beachten Sie bei der Auswahl, dass nur der \"X-CHIP WINDOWS BU & RU driver\" funktioniert.", - "EN": "It is necessary to install the drivers from the manufacturer. Please follow the relevant link for your operating system. Please note that only the driver named \"X-CHIP WINDOWS BU & RU driver\" works with this card reader." + "DE": "Der Kartenleser funktioniert mit dem systemseitig installierten Treiber.", + "EN": "The card reader is compatible with the installed system driver." }, { "Platforms": [ { + "DE": "macOS", + "EN": "macOS", "os": "mac" } ], - "DE": "Es ist notwendig, die Treiber vom Hersteller zu installieren. Dazu folgen Sie bitte dem jeweiligen Link für Ihr Betriebssystem zur Herstellerseite.", - "EN": "It is necessary to install the drivers from the manufacturer. Please follow the relevant link for your operating system." + "DE": "Es ist notwendig, die Treiber vom Hersteller zu installieren. Dazu folgen Sie bitte dem jeweiligen Link für Ihr Betriebssystem zur Herstellerseite. Nach der Installation ist ein Neustart erforderlich.", + "EN": "It is necessary to install the drivers from the manufacturer. Please follow the relevant link for your operating system. A reboot is required after the installation of the driver." } ] }, { "VendorId": "0x076B", "ProductId": "0x5422", + "ProductIds": [ + "0x5422" + ], "Name": "HID OMNIKEY 5422", - "Pattern": "HID Global OMNIKEY 5422CL Smartcard Reader 0|HID Global OMNIKEY Smartcard Reader (\\(1\\)|\\(2\\))", + "Pattern": "HID Global OMNIKEY 5422CL Smartcard Reader 0|HID Global OMNIKEY Smartcard Reader ?(\\(1\\)|\\(2\\))", "Icon": "img_HID_Omnikey_542x.png", "IconWithNPA": "img_HID_Omnikey_542x_mit_ausweis.png", "Drivers": [ @@ -998,7 +1203,10 @@ { "Platforms": [ { - "os": "win" + "DE": "bis Windows 10", + "EN": "up to Windows 10", + "os": "win", + "max": "10.0.19999" } ], "DE": "Der Kartenleser funktioniert mit dem systemseitig installierten Treiber. Falls Sie jedoch den Treiber von der Webseite des Herstellers installieren möchten, ist anschließend ein Neustart erforderlich.", @@ -1007,8 +1215,21 @@ { "Platforms": [ { - "os": "mac", - "min": "10.13" + "DE": "ab Windows 11", + "EN": "from Windows 11", + "os": "win", + "min": "10.0.20000" + } + ], + "DE": "Der Kartenleser funktioniert mit dem systemseitig installierten Treiber. Es ist kein Treiber vom Hersteller vorhanden.", + "EN": "The card reader is compatible with the installed system driver. There is no driver from the manufacturer." + }, + { + "Platforms": [ + { + "DE": "macOS", + "EN": "macOS", + "os": "mac" } ], "DE": "Der Kartenleser funktioniert mit dem systemseitig installierten Treiber. Es ist kein Treiber vom Hersteller vorhanden.", @@ -1019,6 +1240,9 @@ { "VendorId": "0x0AB1", "ProductId": "0x0003", + "ProductIds": [ + "0x0003" + ], "Name": "OBID RFID-Reader", "Pattern": "FEIG ELECTRONIC GmbH OBID myAXXESS basic Slot:CL 358334430", "Icon": "img_FEIG_myAXXES_basic.png", @@ -1037,6 +1261,8 @@ { "Platforms": [ { + "DE": "Windows", + "EN": "Windows", "os": "win" } ], @@ -1046,6 +1272,8 @@ { "Platforms": [ { + "DE": "macOS", + "EN": "macOS", "os": "mac" } ], @@ -1057,6 +1285,9 @@ { "VendorId": "0x08E6", "ProductId": "0x5504", + "ProductIds": [ + "0x5504" + ], "Name": "Gemalto Prox-SU Contactless", "Pattern": "Gemalto Prox( |-)SU( Contactless_| USB PC LinkReader(\\(1\\)|\\(2\\)))", "Icon": "img_Gemalto_Prox_SU.png", @@ -1081,9 +1312,13 @@ { "Platforms": [ { + "DE": "Windows", + "EN": "Windows", "os": "win" }, { + "DE": "bis macOS 10.15 (Catalina)", + "EN": "up to macOS 10.15 (Catalina)", "os": "mac", "max": "10.15" } @@ -1094,8 +1329,10 @@ { "Platforms": [ { + "DE": "ab macOS 11 (Big Sur)", + "EN": "from macOS 11 (Big Sur)", "os": "mac", - "min": "11.0" + "min": "11" } ], "DE": "Der Kartenleser funktioniert mit dem systemseitig installierten Treiber, ein Neustart ist erforderlich. Es ist kein Treiber vom Hersteller vorhanden.", @@ -1106,6 +1343,9 @@ { "VendorId": "0x08E6", "ProductId": "0x5503", + "ProductIds": [ + "0x5503" + ], "Name": "Gemalto Prox-DU HID", "Pattern": "Gemalto .*Prox(-DU| Dual)( Contactless_| USB PC Link(Reader| Reader)(\\(2\\)|\\(1\\)))", "Icon": "img_Gemalto_Prox_DU.png", @@ -1140,9 +1380,13 @@ { "Platforms": [ { + "DE": "Windows", + "EN": "Windows", "os": "win" }, { + "DE": "bis macOS 10.15 (Catalina)", + "EN": "up to macOS 10.15 (Catalina)", "os": "mac", "max": "10.15" } @@ -1153,8 +1397,10 @@ { "Platforms": [ { + "DE": "ab macOS 11 (Big Sur)", + "EN": "from macOS 11 (Big Sur)", "os": "mac", - "min": "11.0" + "min": "11" } ], "DE": "Der Kartenleser funktioniert mit dem systemseitig installierten Treiber, ein Neustart ist erforderlich. Es ist kein Treiber vom Hersteller vorhanden.", @@ -1165,6 +1411,9 @@ { "VendorId": "0x046A", "ProductId": "0x0091", + "ProductIds": [ + "0x0091" + ], "Name": "Cherry TC-1200", "Pattern": "(Cherry TC 1200($|[^-])|TC 12xx-CL 0|Cherry SC Reader \\(046A:0091\\))", "Icon": "img_Cherry_TC_1200.png", @@ -1189,9 +1438,13 @@ { "Platforms": [ { + "DE": "Windows", + "EN": "Windows", "os": "win" }, { + "DE": "macOS", + "EN": "macOS", "os": "mac" } ], @@ -1203,6 +1456,9 @@ { "VendorId": "0x046A", "ProductId": "0x0092", + "ProductIds": [ + "0x0092" + ], "Name": "Cherry TC-1300", "Pattern": "(Cherry TC 1300|Cherry Smartcard Terminal TC 13xx-CL 0|Cherry SC Reader \\(046A:0092\\))", "Icon": "img_Cherry_TC_1300.png", @@ -1227,9 +1483,13 @@ { "Platforms": [ { + "DE": "Windows", + "EN": "Windows", "os": "win" }, { + "DE": "macOS", + "EN": "macOS", "os": "mac" } ], @@ -1241,6 +1501,9 @@ { "VendorId": "0x046A", "ProductId": "0x0072", + "ProductIds": [ + "0x0072" + ], "Name": "Cherry ST-1275", "Pattern": "(Cherry ST-1275|Cherry SmartTerminal XX7X-RF 0)", "Icon": "img_Cherry_ST_1275.png", @@ -1265,6 +1528,8 @@ { "Platforms": [ { + "DE": "Windows", + "EN": "Windows", "os": "win" } ], @@ -1274,6 +1539,8 @@ { "Platforms": [ { + "DE": "macOS", + "EN": "macOS", "os": "mac" } ], @@ -1286,6 +1553,9 @@ { "VendorId": "0x046A", "ProductId": "0x01A2", + "ProductIds": [ + "0x01A2" + ], "Name": "Cherry Secure Board 1.0", "Pattern": "Cherry GmbH CHERRY SECURE BOARD 1.0( 0)?$", "Icon": "img_Cherry_secure_board.png", @@ -1310,9 +1580,13 @@ { "Platforms": [ { + "DE": "Windows", + "EN": "Windows", "os": "win" }, { + "DE": "macOS", + "EN": "macOS", "os": "mac" } ], @@ -1324,6 +1598,9 @@ { "VendorId": "0x2133", "ProductId": "0x010B", + "ProductIds": [ + "0x010B" + ], "Name": "Signotec Omega Pad", "Pattern": "NXP PR533( 0)?", "Icon": "img_Signotec_Omega_Pad.png", @@ -1348,9 +1625,13 @@ { "Platforms": [ { + "DE": "Windows", + "EN": "Windows", "os": "win" }, { + "DE": "macOS", + "EN": "macOS", "os": "mac" } ], diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f9589fe38..7230d6507 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,6 @@ ##################################################################### # The main component that will link all necessary modules and plugins -# into AusweisApp2 executable for the specific platform. +# into AusweisApp executable for the specific platform. # # This component includes a main entry point and command line # parser only. Everything else will be included from sub-modules. @@ -15,7 +15,6 @@ add_subdirectory(file_provider) add_subdirectory(configuration) add_subdirectory(network) -add_subdirectory(export) add_subdirectory(card) add_subdirectory(services) @@ -37,7 +36,7 @@ if(IOS) # Attention: the file names correspond to values in the Info.plist if(BUILD_PREVIEW) message(FATAL_ERROR "iOS preview not implemented") - elseif(IS_DEVELOPER_VERSION) + elseif(IS_BETA_VERSION) set(IOS_APPICON_PATH "beta/") else() set(IOS_APPICON_PATH "") @@ -49,13 +48,13 @@ if(IOS) set_source_files_properties(${RCC} PROPERTIES GENERATED TRUE) endif() elseif(MAC) - if(IS_DEVELOPER_VERSION) + if(IS_BETA_VERSION) set(MACOS_APPICON_PATH "beta/") else() set(MACOS_APPICON_PATH "") endif() - list(APPEND MAC_RESOURCES ${RESOURCES_DIR}/images/macos/${MACOS_APPICON_PATH}AusweisApp2.icns) + list(APPEND MAC_RESOURCES ${RESOURCES_DIR}/images/macos/${MACOS_APPICON_PATH}AusweisApp.icns) list(APPEND MAC_RESOURCES ${PACKAGING_DIR}/macos/container-migration.plist) list(APPEND MAC_RESOURCES ${RCC}) set_source_files_properties(${RCC} PROPERTIES GENERATED TRUE) @@ -73,34 +72,36 @@ endif() set(MAIN_FILE main.cpp) if(IOS) if(INTEGRATED_SDK) - add_library(AusweisApp SHARED ${MAIN_FILE} ${IOS_RESOURCES}) + add_library(AusweisAppBinary SHARED ${MAIN_FILE} ${IOS_RESOURCES}) else() - add_executable(AusweisApp MACOSX_BUNDLE ${MAIN_FILE} ${IOS_RESOURCES}) + add_executable(AusweisAppBinary MACOSX_BUNDLE ${MAIN_FILE} ${IOS_RESOURCES}) endif() elseif(ANDROID OR (INTEGRATED_SDK AND NOT CONTAINER_SDK)) - add_library(AusweisApp SHARED ${MAIN_FILE}) + add_library(AusweisAppBinary SHARED ${MAIN_FILE}) elseif(MAC) - add_executable(AusweisApp MACOSX_BUNDLE ${MAIN_FILE} ${MAC_RESOURCES}) + add_executable(AusweisAppBinary MACOSX_BUNDLE ${MAIN_FILE} ${MAC_RESOURCES}) else() - add_executable(AusweisApp WIN32 ${MAIN_FILE} windows.rc) + add_executable(AusweisAppBinary WIN32 ${MAIN_FILE} windows.rc) endif() if(TARGET AusweisAppRcc) - add_dependencies(AusweisApp AusweisAppRcc) + add_dependencies(AusweisAppBinary AusweisAppRcc) endif() -target_link_libraries(AusweisApp PRIVATE AusweisAppInit) +target_link_libraries(AusweisAppBinary PRIVATE AusweisAppInit) if(ANDROID) - set_target_properties(AusweisApp PROPERTIES OUTPUT_NAME "${PROJECT_NAME}_${CMAKE_ANDROID_ARCH_ABI}") + set_target_properties(AusweisAppBinary PROPERTIES OUTPUT_NAME "${PROJECT_NAME}_${CMAKE_ANDROID_ARCH_ABI}") +elseif(IOS AND INTEGRATED_SDK) + set_target_properties(AusweisAppBinary PROPERTIES OUTPUT_NAME "${PROJECT_NAME}2") else() - set_target_properties(AusweisApp PROPERTIES OUTPUT_NAME "${PROJECT_NAME}") + set_target_properties(AusweisAppBinary PROPERTIES OUTPUT_NAME "${PROJECT_NAME}") endif() if(TARGET AusweisAppConfig) - target_link_libraries(AusweisApp PRIVATE AusweisAppConfig) + target_link_libraries(AusweisAppBinary PRIVATE AusweisAppConfig) endif() -ADD_SHADERS_TO_TARGET(AusweisApp) +ADD_SHADERS_TO_TARGET(AusweisAppBinary) if(APPLE) set(MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}) @@ -113,16 +114,16 @@ if(APPLE) if(IOS AND INTEGRATED_SDK) set(MACOSX_FRAMEWORK_BUNDLE_VERSION ${PROJECT_VERSION}) set(MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${PROJECT_VERSION}) - set_target_properties(AusweisApp PROPERTIES MACOSX_FRAMEWORK_NAME ${PROJECT_NAME}) - set_target_properties(AusweisApp PROPERTIES MACOSX_FRAMEWORK_IDENTIFIER "${BUNDLE_IDENTIFIER}") - set_target_properties(AusweisApp PROPERTIES MACOSX_FRAMEWORK_INFO_PLIST "${PACKAGING_DIR}/ios/Info.framework.plist.in") + set_target_properties(AusweisAppBinary PROPERTIES MACOSX_FRAMEWORK_NAME ${PROJECT_NAME}) + set_target_properties(AusweisAppBinary PROPERTIES MACOSX_FRAMEWORK_IDENTIFIER "${BUNDLE_IDENTIFIER}") + set_target_properties(AusweisAppBinary PROPERTIES MACOSX_FRAMEWORK_INFO_PLIST "${PACKAGING_DIR}/ios/Info.framework.plist.in") elseif(IOS) - set_target_properties(AusweisApp PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${PACKAGING_DIR}/ios/Info.plist.in") + set_target_properties(AusweisAppBinary PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${PACKAGING_DIR}/ios/Info.plist.in") elseif(MAC AND NOT INTEGRATED_SDK) - set_target_properties(AusweisApp PROPERTIES RESOURCE "${MAC_RESOURCES}") - set_target_properties(AusweisApp PROPERTIES MACOSX_BUNDLE_ICON_FILE "${PROJECT_NAME}.icns") - set_target_properties(AusweisApp PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${PACKAGING_DIR}/macos/Info.plist.in") - set_target_properties(AusweisApp PROPERTIES XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT "dwarf-with-dsym") + set_target_properties(AusweisAppBinary PROPERTIES RESOURCE "${MAC_RESOURCES}") + set_target_properties(AusweisAppBinary PROPERTIES MACOSX_BUNDLE_ICON_FILE "${PROJECT_NAME}.icns") + set_target_properties(AusweisAppBinary PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${PACKAGING_DIR}/macos/Info.plist.in") + set_target_properties(AusweisAppBinary PROPERTIES XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT "dwarf-with-dsym") endif() endif() @@ -133,35 +134,35 @@ if(IOS) set(qt_suffix "_debug") endif() - target_link_libraries(AusweisApp PRIVATE OpenSSL::Crypto OpenSSL::SSL) # remove this if iOS uses shared libraries - target_link_libraries(AusweisApp PRIVATE -L${QT_INSTALL_ARCHDATA}/plugins/platforms) - target_link_libraries(AusweisApp PRIVATE -L${QT_INSTALL_ARCHDATA}/plugins/imageformats) - target_link_libraries(AusweisApp PRIVATE -L${QT_INSTALL_ARCHDATA}/lib) - target_link_libraries(AusweisApp PRIVATE ${Qt}::Core ${Qt}::Network) - target_link_libraries(AusweisApp PRIVATE -lqios${qt_suffix}) + target_link_libraries(AusweisAppBinary PRIVATE OpenSSL::Crypto OpenSSL::SSL) # remove this if iOS uses shared libraries + target_link_libraries(AusweisAppBinary PRIVATE -L${QT_INSTALL_ARCHDATA}/plugins/platforms) + target_link_libraries(AusweisAppBinary PRIVATE -L${QT_INSTALL_ARCHDATA}/plugins/imageformats) + target_link_libraries(AusweisAppBinary PRIVATE -L${QT_INSTALL_ARCHDATA}/lib) + target_link_libraries(AusweisAppBinary PRIVATE ${Qt}::Core ${Qt}::Network) + target_link_libraries(AusweisAppBinary PRIVATE -lqios${qt_suffix}) - target_link_libraries(AusweisApp PRIVATE "-lc++ -lz -lm") - target_link_libraries(AusweisApp PRIVATE ${IOS_ASSETSLIBRARY} ${IOS_UIKIT} ${IOS_COREFOUNDATION} ${IOS_OPENGLES} ${IOS_FOUNDATION} ${IOS_QUARTZCORE} ${IOS_CORETEXT} ${IOS_COREGRAPHICS} ${IOS_SECURITY} ${IOS_NETWORK} ${IOS_MOBILECORESERVICES} ${IOS_AUDIOTOOLBOX} ${IOS_IMAGEIO} ${IOS_CORENFC} ${IOS_MESSAGEUI} ${IOS_STOREKIT}) - target_link_libraries(AusweisApp PRIVATE -Wl,-e,_qt_main_wrapper) + target_link_libraries(AusweisAppBinary PRIVATE "-lc++ -lz -lm") + target_link_libraries(AusweisAppBinary PRIVATE ${IOS_ASSETSLIBRARY} ${IOS_UIKIT} ${IOS_COREFOUNDATION} ${IOS_OPENGLES} ${IOS_FOUNDATION} ${IOS_QUARTZCORE} ${IOS_CORETEXT} ${IOS_COREGRAPHICS} ${IOS_SECURITY} ${IOS_NETWORK} ${IOS_MOBILECORESERVICES} ${IOS_AUDIOTOOLBOX} ${IOS_IMAGEIO} ${IOS_CORENFC} ${IOS_MESSAGEUI} ${IOS_STOREKIT}) + target_link_libraries(AusweisAppBinary PRIVATE -Wl,-e,_qt_main_wrapper) if(TARGET ${Qt}::Qml) - target_link_libraries(AusweisApp PRIVATE ${Qt}::Gui ${Qt}::Svg ${Qt}::Qml ${Qt}::Quick ${Qt}::QuickControls2 ${Qt}::QuickTemplates2) - target_link_libraries(AusweisApp PRIVATE -lqsvg${qt_suffix} -lqjpeg${qt_suffix}) - target_link_libraries(AusweisApp PRIVATE AusweisAppQmlPlugins) + target_link_libraries(AusweisAppBinary PRIVATE ${Qt}::Gui ${Qt}::Svg ${Qt}::Qml ${Qt}::Quick ${Qt}::QuickControls2 ${Qt}::QuickTemplates2) + target_link_libraries(AusweisAppBinary PRIVATE -lqsvg${qt_suffix} -lqjpeg${qt_suffix}) + target_link_libraries(AusweisAppBinary PRIVATE AusweisAppQmlPlugins) endif() - set_target_properties(AusweisApp PROPERTIES RESOURCE "${IOS_RESOURCES}") - set_target_properties(AusweisApp PROPERTIES XCODE_ATTRIBUTE_SKIP_INSTALL "NO") - set_target_properties(AusweisApp PROPERTIES XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME "AppIcon") - set_target_properties(AusweisApp PROPERTIES XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "1,2") - set_target_properties(AusweisApp PROPERTIES XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${PACKAGING_DIR}/ios/AusweisApp2.entitlements") + set_target_properties(AusweisAppBinary PROPERTIES RESOURCE "${IOS_RESOURCES}") + set_target_properties(AusweisAppBinary PROPERTIES XCODE_ATTRIBUTE_SKIP_INSTALL "NO") + set_target_properties(AusweisAppBinary PROPERTIES XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME "AppIcon") + set_target_properties(AusweisAppBinary PROPERTIES XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "1,2") + set_target_properties(AusweisAppBinary PROPERTIES XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${PACKAGING_DIR}/ios/AusweisApp.entitlements") if(INTEGRATED_SDK) GET_PUBLIC_HEADER(AusweisAppUiFunctional PUBLIC_HEADER) - target_sources(AusweisApp PUBLIC ${PUBLIC_HEADER}) - set_target_properties(AusweisApp PROPERTIES FRAMEWORK TRUE FRAMEWORK_VERSION C MACOSX_FRAMEWORK_IDENTIFIER ${BUNDLE_IDENTIFIER}) - set_target_properties(AusweisApp PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION} PUBLIC_HEADER ${PUBLIC_HEADER}) - set_target_properties(AusweisApp PROPERTIES XCODE_ATTRIBUTE_INSTALL_PATH "@rpath") + target_sources(AusweisAppBinary PUBLIC ${PUBLIC_HEADER}) + set_target_properties(AusweisAppBinary PROPERTIES FRAMEWORK TRUE FRAMEWORK_VERSION C MACOSX_FRAMEWORK_IDENTIFIER ${BUNDLE_IDENTIFIER}) + set_target_properties(AusweisAppBinary PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION} PUBLIC_HEADER ${PUBLIC_HEADER}) + set_target_properties(AusweisAppBinary PROPERTIES XCODE_ATTRIBUTE_INSTALL_PATH "@rpath") else() if(USE_DISTRIBUTION_PROFILE) set(PROVISIONING_PROFILE_SPECIFIER "iOS Release (Distribution)") @@ -172,19 +173,19 @@ if(IOS) set(EXPORT_METHOD development) set(XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "iPhone Developer: Marco von der Puetten (46ZK7WV8QR)") endif() - set_target_properties(AusweisApp PROPERTIES XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER ${PROVISIONING_PROFILE_SPECIFIER}) - set_target_properties(AusweisApp PROPERTIES XCODE_ATTRIBUTE_INSTALL_PATH "$(LOCAL_APPS_DIR)") - set_target_properties(AusweisApp PROPERTIES XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY ${XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY}) + set_target_properties(AusweisAppBinary PROPERTIES XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER ${PROVISIONING_PROFILE_SPECIFIER}) + set_target_properties(AusweisAppBinary PROPERTIES XCODE_ATTRIBUTE_INSTALL_PATH "$(LOCAL_APPS_DIR)") + set_target_properties(AusweisAppBinary PROPERTIES XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY ${XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY}) endif() # prevent xcode to convert multiple png files to tiff - set_target_properties(AusweisApp PROPERTIES XCODE_ATTRIBUTE_COMBINE_HIDPI_IMAGES "NO") + set_target_properties(AusweisAppBinary PROPERTIES XCODE_ATTRIBUTE_COMBINE_HIDPI_IMAGES "NO") configure_file(${PACKAGING_DIR}/ios/exportOptions.plist.in ${CMAKE_BINARY_DIR}/exportOptions.plist @ONLY) endif() if(MAC) - target_link_libraries(AusweisApp PRIVATE ${OSX_APPKIT}) + target_link_libraries(AusweisAppBinary PRIVATE ${OSX_APPKIT}) set(AUTOSTART_HELPER_NAME AutostartHelper) set(AUTOSTART_HELPER_FULL_NAME ${PROJECT_NAME}${AUTOSTART_HELPER_NAME}) @@ -196,7 +197,7 @@ if(MAC) endif() if(WIN32) - target_link_libraries(AusweisApp PRIVATE ${WIN_DEFAULT_LIBS}) + target_link_libraries(AusweisAppBinary PRIVATE ${WIN_DEFAULT_LIBS}) endif() ##################################################################### @@ -204,37 +205,37 @@ endif() ##################################################################### if(ANDROID) - target_link_libraries(AusweisApp PRIVATE AusweisAppUiAidl) - if(NOT INTEGRATED_SDK) - target_link_libraries(AusweisApp PRIVATE AusweisAppUiLocalIfd) + target_link_libraries(AusweisAppBinary PRIVATE AusweisAppUiAidl) + if(NOT INTEGRATED_SDK AND USE_SMARTEID) + target_link_libraries(AusweisAppBinary PRIVATE AusweisAppUiLocalIfd) endif() else() - target_link_libraries(AusweisApp PRIVATE debug AusweisAppUiAidl) + target_link_libraries(AusweisAppBinary PRIVATE debug AusweisAppUiAidl) endif() if(TARGET ${Qt}::Qml) - target_link_libraries(AusweisApp PRIVATE AusweisAppUiQml) + target_link_libraries(AusweisAppBinary PRIVATE AusweisAppUiQml) endif() if(INTEGRATED_SDK AND NOT ANDROID AND NOT CONTAINER_SDK) - target_link_libraries(AusweisApp PRIVATE AusweisAppUiFunctional) + target_link_libraries(AusweisAppBinary PRIVATE AusweisAppUiFunctional) endif() if((NOT ANDROID AND NOT IOS AND NOT INTEGRATED_SDK) OR CONTAINER_SDK) - target_link_libraries(AusweisApp PRIVATE AusweisAppUiWebsocket) + target_link_libraries(AusweisAppBinary PRIVATE AusweisAppUiWebsocket) endif() if(CONTAINER_SDK OR DESKTOP) - target_link_libraries(AusweisApp PRIVATE AusweisAppUiAutomatic) + target_link_libraries(AusweisAppBinary PRIVATE AusweisAppUiAutomatic) endif() if(DESKTOP) - target_link_libraries(AusweisApp PRIVATE AusweisAppUiWebservice) - target_link_libraries(AusweisApp PRIVATE AusweisAppUiProxy) + target_link_libraries(AusweisAppBinary PRIVATE AusweisAppUiWebservice) + target_link_libraries(AusweisAppBinary PRIVATE AusweisAppUiProxy) endif() if((ANDROID OR IOS) AND NOT INTEGRATED_SDK) - target_link_libraries(AusweisApp PRIVATE AusweisAppUiScheme) + target_link_libraries(AusweisAppBinary PRIVATE AusweisAppUiScheme) endif() ##################################################################### @@ -242,29 +243,29 @@ endif() ##################################################################### if(ANDROID) - target_link_libraries(AusweisApp PRIVATE AusweisAppCardNfc) - if(INTEGRATED_SDK) - target_link_libraries(AusweisApp PRIVATE AusweisAppIfdLocal) + target_link_libraries(AusweisAppBinary PRIVATE AusweisAppCardNfc) + if(INTEGRATED_SDK AND USE_SMARTEID) + target_link_libraries(AusweisAppBinary PRIVATE AusweisAppIfdLocal) endif() endif() if(IOS) - target_link_libraries(AusweisApp PRIVATE AusweisAppCardNfc) + target_link_libraries(AusweisAppBinary PRIVATE AusweisAppCardNfc) endif() if(TARGET AusweisAppCardSmart) if(((ANDROID OR IOS) AND NOT INTEGRATED_SDK) OR CONTAINER_SDK) - target_link_libraries(AusweisApp PRIVATE AusweisAppCardSmart) + target_link_libraries(AusweisAppBinary PRIVATE AusweisAppCardSmart) else() - target_link_libraries(AusweisApp PRIVATE debug AusweisAppCardSmart) + target_link_libraries(AusweisAppBinary PRIVATE debug AusweisAppCardSmart) endif() endif() if(DESKTOP) - target_link_libraries(AusweisApp PRIVATE AusweisAppCardPcsc AusweisAppCardDrivers) + target_link_libraries(AusweisAppBinary PRIVATE AusweisAppCardPcsc AusweisAppCardDrivers) endif() -target_link_libraries(AusweisApp PRIVATE AusweisAppCardSimulator) +target_link_libraries(AusweisAppBinary PRIVATE AusweisAppCardSimulator) ##################################################################### diff --git a/src/android/AusweisApp2LocalIfdService.java b/src/android/AusweisApp2LocalIfdService.java index e63d45533..9243f22ae 100644 --- a/src/android/AusweisApp2LocalIfdService.java +++ b/src/android/AusweisApp2LocalIfdService.java @@ -19,7 +19,7 @@ public final class AusweisApp2LocalIfdService extends QtService { private static final String ACTION_ABORT_WORKFLOW = AusweisApp2LocalIfdService.class.getCanonicalName() + ".abort"; - public static final String PARAM_TLS_WEBSOCKET_PSK = "TLS_WEBSOCKET_PSK"; + public static final String PARAM_TLS_WEBSOCKET_PSK = "PSK"; public static final String PARAM_SERVICE_TOKEN = "SERVICE_TOKEN"; private final IBinder mBinder = new AusweisApp2LocalIfdServiceBinder(); @@ -175,13 +175,8 @@ public void onCreate() public void onDestroy() { LogHandler.getLogger().info("LocalIfdService destroyed"); + BootstrapHelper.triggerShutdown(); super.onDestroy(); - - // Workaround. When bound & unbound the QtService is in a funny state causing - // "WARNING: QApplication was not created in the main() thread." and a crash on - // first rebind. - // This workaround is inspired by https://bugreports.qt.io/browse/QTBUG-54012 . - System.exit(0); // NOPMD see comment above } diff --git a/src/android/AusweisApp2Service.java b/src/android/AusweisApp2Service.java index 8402097df..122b6a95f 100644 --- a/src/android/AusweisApp2Service.java +++ b/src/android/AusweisApp2Service.java @@ -48,14 +48,8 @@ public void onCreate() public void onDestroy() { LogHandler.getLogger().info("Android service destroyed."); - + BootstrapHelper.triggerShutdown(); super.onDestroy(); - - // Workaround. When bound & unbound the QtService is in a funny state causing - // "WARNING: QApplication was not created in the main() thread." and a crash on - // first rebind. - // This workaround is inspired by https://bugreports.qt.io/browse/QTBUG-54012 . - System.exit(0); // NOPMD see comment above } diff --git a/src/android/BootstrapHelper.java b/src/android/BootstrapHelper.java new file mode 100644 index 000000000..0b1f64580 --- /dev/null +++ b/src/android/BootstrapHelper.java @@ -0,0 +1,17 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ + +package com.governikus.ausweisapp2; + +public final class BootstrapHelper +{ + public static native void triggerShutdown(); + + private BootstrapHelper() + { + throw new IllegalStateException(); + } + + +} diff --git a/src/android/MainActivity.java b/src/android/MainActivity.java index 96051aaae..8091bfff3 100644 --- a/src/android/MainActivity.java +++ b/src/android/MainActivity.java @@ -15,6 +15,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.res.Configuration; import android.graphics.Color; import android.net.Uri; import android.nfc.NfcAdapter; @@ -44,11 +45,11 @@ public class MainActivity extends QtActivity private NfcForegroundDispatcher mNfcForegroundDispatcher; private NfcReaderMode mNfcReaderMode; - private boolean mReaderModeRequested; private boolean mIsResumed; - // Native method provided by UIPlugInQml + // Native methods provided by UIPlugInQml public static native void notifySafeAreaMarginsChanged(); + public static native void notifyConfigurationChanged(); private class NfcForegroundDispatcher { @@ -68,14 +69,7 @@ private class NfcForegroundDispatcher } }; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) - { - mPendingIntent = PendingIntent.getActivity(MainActivity.this, 0, new Intent(), PendingIntent.FLAG_MUTABLE); - } - else - { - mPendingIntent = PendingIntent.getActivity(MainActivity.this, 0, new Intent(), 0); - } + mPendingIntent = PendingIntent.getActivity(MainActivity.this, 0, new Intent(), PendingIntent.FLAG_IMMUTABLE); } @@ -160,14 +154,7 @@ void disable() void vibrate() { Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) // API 26, Android 8.0 - { - v.vibrate(VibrationEffect.createOneShot(250, VibrationEffect.DEFAULT_AMPLITUDE)); - return; - } - - v.vibrate(250); + v.vibrate(VibrationEffect.createOneShot(250, VibrationEffect.DEFAULT_AMPLITUDE)); } @@ -275,6 +262,9 @@ protected void onNewIntent(Intent newIntent) } + private native void setReaderModeNative(boolean pEnabled); + + @Override public void onResume() { @@ -282,18 +272,16 @@ public void onResume() mIsResumed = true; mNfcForegroundDispatcher.enable(); - if (mReaderModeRequested) - { - mNfcReaderMode.enable(); - } + setReaderModeNative(true); } @Override public void onPause() { - mNfcReaderMode.disable(); + setReaderModeNative(false); mNfcForegroundDispatcher.disable(); + mIsResumed = false; super.onPause(); } @@ -307,22 +295,17 @@ protected void onDestroy() } - // used by NfcReader - public void enableNfcReaderMode() + // used by NfcReaderManagerPlugIn + public void setReaderMode(boolean pEnabled) { - mReaderModeRequested = true; - if (mIsResumed) + if (pEnabled) { mNfcReaderMode.enable(); } - } - - - // used by NfcReader - public void disableNfcReaderMode() - { - mReaderModeRequested = false; - mNfcReaderMode.disable(); + else + { + mNfcReaderMode.disable(); + } } @@ -394,4 +377,12 @@ public boolean openUrl(String pUrl, String pReferrer) } + @Override + public void onConfigurationChanged(Configuration newConfig) + { + super.onConfigurationChanged(newConfig); + notifyConfigurationChanged(); + } + + } diff --git a/src/autostart_helper/main.mm b/src/autostart_helper/main.mm index 1a0e5fcf5..d03ab13af 100644 --- a/src/autostart_helper/main.mm +++ b/src/autostart_helper/main.mm @@ -34,7 +34,10 @@ - (void) applicationWillFinishLaunching: (NSNotification*) pNotification NSArray* mainBundleComponents = [helperBundlePathComponents subarrayWithRange:NSMakeRange(0, [helperBundlePathComponents count] - 4)]; NSString* mainBundlePath = [NSString pathWithComponents:mainBundleComponents]; NSLog(@"Launching application at: %@", mainBundlePath); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" BOOL result = [[NSWorkspace sharedWorkspace] launchApplication:mainBundlePath]; +#pragma clang diagnostic pop if (!result) { NSLog(@"Launching failed"); diff --git a/src/card/base/CardConnection.h b/src/card/base/CardConnection.h index 41849e4e1..4f7f4c632 100644 --- a/src/card/base/CardConnection.h +++ b/src/card/base/CardConnection.h @@ -12,9 +12,7 @@ #include "InputAPDUInfo.h" #include "ReaderInfo.h" #include "SmartCardDefinitions.h" -#include "asn1/CVCertificate.h" #include "asn1/CVCertificateChain.h" -#include "asn1/Chat.h" #include "command/BaseCardCommand.h" #include "command/DestroyPaceChannelCommand.h" diff --git a/src/card/base/CardConnectionWorker.cpp b/src/card/base/CardConnectionWorker.cpp index 37aaa89db..8f7a6ecd0 100644 --- a/src/card/base/CardConnectionWorker.cpp +++ b/src/card/base/CardConnectionWorker.cpp @@ -9,7 +9,7 @@ #include "pace/PaceHandler.h" #include - +#include using namespace governikus; @@ -46,7 +46,18 @@ CardConnectionWorker::~CardConnectionWorker() QSharedPointer CardConnectionWorker::create(Reader* pReader) { - return QSharedPointer(new CardConnectionWorker(pReader), &QObject::deleteLater); + const auto& customDeleter = [](CardConnectionWorker* pWorker){ + if (QThread::currentThread() == pWorker->thread()) + { + delete pWorker; + } + else + { + pWorker->deleteLater(); + } + }; + + return QSharedPointer(new CardConnectionWorker(pReader), customDeleter); } diff --git a/src/card/base/CardConnectionWorker.h b/src/card/base/CardConnectionWorker.h index a5aec83c6..2e9fe7c47 100644 --- a/src/card/base/CardConnectionWorker.h +++ b/src/card/base/CardConnectionWorker.h @@ -17,7 +17,7 @@ #include "asn1/CVCertificateChain.h" #include "asn1/SecurityInfos.h" #include "pace/SecureMessaging.h" -#include "pinpad/EstablishPaceChannel.h" +#include "pinpad/EstablishPaceChannelOutput.h" #include #include diff --git a/src/card/base/CardInfo.cpp b/src/card/base/CardInfo.cpp index 04cf34c85..e58dfd258 100644 --- a/src/card/base/CardInfo.cpp +++ b/src/card/base/CardInfo.cpp @@ -8,10 +8,6 @@ #include "CardInfo.h" -#include "CardConnectionWorker.h" -#include "apdu/FileCommand.h" -#include "asn1/ApplicationTemplates.h" -#include "asn1/PaceInfo.h" #include "asn1/SecurityInfos.h" #include @@ -156,156 +152,6 @@ MobileEidType CardInfo::getMobileEidType() const } -CardInfo CardInfoFactory::create(const QSharedPointer& pCardConnectionWorker) -{ - if (pCardConnectionWorker == nullptr) - { - qCWarning(card) << "No connection to smart card"; - return CardInfo(CardType::UNKNOWN); - } - - if (!CardInfoFactory::detectCard(pCardConnectionWorker)) - { - qCWarning(card) << "Not a German EID card"; - return CardInfo(CardType::UNKNOWN); - } - - const auto& efCardAccess = readEfCardAccess(pCardConnectionWorker); - if (!checkEfCardAccess(efCardAccess)) - { - qCWarning(card) << "EFCardAccess not found or is invalid"; - return CardInfo(CardType::UNKNOWN); - } - - const CardInfo cardInfo(efCardAccess->getMobileEIDTypeInfo() ? CardType::SMART_EID : CardType::EID_CARD, efCardAccess); - qCDebug(card) << "Card detected:" << cardInfo; - return cardInfo; -} - - -bool CardInfoFactory::selectApplication(const QSharedPointer& pCardConnectionWorker, const FileRef& pFileRef) -{ - qCDebug(card) << "Try to select application:" << pFileRef; - - FileCommand command(pFileRef); - ResponseApduResult select = pCardConnectionWorker->transmit(command); - if (select.mResponseApdu.getStatusCode() != StatusCode::SUCCESS) - { - qCWarning(card) << "Cannot select application identifier:" << select.mResponseApdu.getStatusCode(); - return false; - } - - return true; -} - - -bool CardInfoFactory::detectEid(const QSharedPointer& pCardConnectionWorker, const FileRef& pRef) -{ - // 1. Select the application id - selectApplication(pCardConnectionWorker, pRef); - - // 2. Select the master file - FileCommand command(FileRef::masterFile()); - ResponseApduResult result = pCardConnectionWorker->transmit(command); - if (result.mResponseApdu.getStatusCode() != StatusCode::SUCCESS) - { - qCWarning(card) << "Cannot select MF:" << result.mResponseApdu.getStatusCode(); - return false; - } - - // 3. Read EF.DIR - QByteArray rawEfDir; - if (pCardConnectionWorker->readFile(FileRef::efDir(), rawEfDir) != CardReturnCode::OK) - { - qCWarning(card) << "Cannot read EF.DIR"; - return false; - } - - const auto efDir = ApplicationTemplates::decode(rawEfDir); - if (efDir.isNull()) - { - qCWarning(card) << "Cannot parse EF.DIR"; - return false; - } - - if (!efDir->contains(FileRef::appEId().getIdentifier())) - { - qCWarning(card) << "EF.DIR does not match:" << rawEfDir.toHex(); - return false; - } - - return true; -} - - -bool CardInfoFactory::detectCard(const QSharedPointer& pCardConnectionWorker) -{ - for (const auto& appId : {FileRef::appEId(), FileRef::appPersosim()}) - { - const auto eidAvailable = detectEid(pCardConnectionWorker, appId); - if (eidAvailable) - { - return true; - } - } - - if (selectApplication(pCardConnectionWorker, FileRef::appPassport())) - { - qCDebug(card) << "Passport found"; - } - - return false; -} - - -QSharedPointer CardInfoFactory::readEfCardAccess(const QSharedPointer& pCardConnectionWorker) -{ - QByteArray efCardAccessBytes; - if (pCardConnectionWorker->readFile(FileRef::efCardAccess(), efCardAccessBytes) != CardReturnCode::OK) - { - qCCritical(card) << "Error while reading EF.CardAccess: Cannot read EF.CardAccess"; - return QSharedPointer(); - } - - auto efCardAccess = EFCardAccess::decode(efCardAccessBytes); - if (efCardAccess == nullptr) - { - qCCritical(card) << "Error while reading EF.CardAccess: Cannot parse EFCardAccess"; - } - return efCardAccess; -} - - -bool CardInfoFactory::checkEfCardAccess(const QSharedPointer& pEfCardAccess) -{ - if (!pEfCardAccess) - { - return false; - } - - /* - * At least one PACEInfo must have standardized domain parameters - */ - bool containsStandardizedDomainParameters = false; - const auto& infos = pEfCardAccess->getPaceInfos(); - for (const auto& paceInfo : infos) - { - if (paceInfo->isStandardizedDomainParameters()) - { - containsStandardizedDomainParameters = true; - break; - } - } - if (!containsStandardizedDomainParameters) - { - qCCritical(card) << "Error while reading EF.CardAccess: No PACEInfo with standardized domain parameters found"; - return false; - } - - return true; -} - - namespace governikus { diff --git a/src/card/base/CardInfo.h b/src/card/base/CardInfo.h index 219f68fc2..da8eceee5 100644 --- a/src/card/base/CardInfo.h +++ b/src/card/base/CardInfo.h @@ -8,22 +8,14 @@ #pragma once -#include "FileRef.h" #include "SmartCardDefinitions.h" #include "asn1/SecurityInfos.h" -#include #include -class test_CardInfo; - namespace governikus { -class CardConnectionWorker; -class Reader; -class ReaderInfo; - /*! * Holds smart card information. * An instance of CardInfo is created using the CardInfoFactory. @@ -84,43 +76,6 @@ class CardInfo [[nodiscard]] bool isPinInitial() const; }; - -/*! - * Factory for creation of CardInfo instances. - */ -class CardInfoFactory -{ - friend class ::test_CardInfo; - - public: - /*! - * In order to create a CardInfo instance a connection is established to the smart card - * and data is read. - */ - static CardInfo create(const QSharedPointer& pCardConnectionWorker); - - private: - static bool selectApplication(const QSharedPointer& pCardConnectionWorker, const FileRef& pFileRef); - - /*! - * Checks, if the smart card is a german eID card (i.e. a NPA or an EAT) or a passport. - */ - static bool detectCard(const QSharedPointer& pCardConnectionWorker); - static bool detectEid(const QSharedPointer& pCardConnectionWorker, const FileRef& pRef); - - /*! - * Reads the EF.CardAccess - */ - static QSharedPointer readEfCardAccess(const QSharedPointer& pCardConnectionWorker); - - /*! - * According to TR-03105 we have to perform some checks on EF.CardAccess the first time we read it. - * Therefore we read it just once and handle malformed EF.CardAccess structures here in card recognition process. - */ - static bool checkEfCardAccess(const QSharedPointer& pEfCardAccess); -}; - - QDebug operator<<(QDebug pDbg, const CardInfo& pCardInfo); diff --git a/src/card/base/CardInfoFactory.cpp b/src/card/base/CardInfoFactory.cpp new file mode 100644 index 000000000..c8e45a359 --- /dev/null +++ b/src/card/base/CardInfoFactory.cpp @@ -0,0 +1,169 @@ +/** + * Copyright (c) 2014-2023 Governikus GmbH & Co. KG, Germany + */ + +#include "CardInfoFactory.h" + +#include "apdu/FileCommand.h" +#include "asn1/ApplicationTemplates.h" +#include "asn1/PaceInfo.h" + +#include +#include +#include + + +Q_DECLARE_LOGGING_CATEGORY(card) + + +using namespace governikus; + + +CardInfo CardInfoFactory::create(const QSharedPointer& pCardConnectionWorker) +{ + if (pCardConnectionWorker == nullptr) + { + qCWarning(card) << "No connection to smart card"; + return CardInfo(CardType::UNKNOWN); + } + + if (!CardInfoFactory::detectCard(pCardConnectionWorker)) + { + qCWarning(card) << "Not a German EID card"; + return CardInfo(CardType::UNKNOWN); + } + + const auto& efCardAccess = readEfCardAccess(pCardConnectionWorker); + if (!checkEfCardAccess(efCardAccess)) + { + qCWarning(card) << "EFCardAccess not found or is invalid"; + return CardInfo(CardType::UNKNOWN); + } + + const CardInfo cardInfo(efCardAccess->getMobileEIDTypeInfo() ? CardType::SMART_EID : CardType::EID_CARD, efCardAccess); + qCDebug(card) << "Card detected:" << cardInfo; + return cardInfo; +} + + +bool CardInfoFactory::selectApplication(const QSharedPointer& pCardConnectionWorker, const FileRef& pFileRef) +{ + qCDebug(card) << "Try to select application:" << pFileRef; + + FileCommand command(pFileRef); + ResponseApduResult select = pCardConnectionWorker->transmit(command); + if (select.mResponseApdu.getStatusCode() != StatusCode::SUCCESS) + { + qCWarning(card) << "Cannot select application identifier:" << select.mResponseApdu.getStatusCode(); + return false; + } + + return true; +} + + +bool CardInfoFactory::detectEid(const QSharedPointer& pCardConnectionWorker, const FileRef& pRef) +{ + // 1. Select the application id + selectApplication(pCardConnectionWorker, pRef); + + // 2. Select the master file + FileCommand command(FileRef::masterFile()); + ResponseApduResult result = pCardConnectionWorker->transmit(command); + if (result.mResponseApdu.getStatusCode() != StatusCode::SUCCESS) + { + qCWarning(card) << "Cannot select MF:" << result.mResponseApdu.getStatusCode(); + return false; + } + + // 3. Read EF.DIR + QByteArray rawEfDir; + if (pCardConnectionWorker->readFile(FileRef::efDir(), rawEfDir) != CardReturnCode::OK) + { + qCWarning(card) << "Cannot read EF.DIR"; + return false; + } + + const auto efDir = ApplicationTemplates::decode(rawEfDir); + if (efDir.isNull()) + { + qCWarning(card) << "Cannot parse EF.DIR"; + return false; + } + + if (!efDir->contains(FileRef::appEId().getIdentifier())) + { + qCWarning(card) << "EF.DIR does not match:" << rawEfDir.toHex(); + return false; + } + + return true; +} + + +bool CardInfoFactory::detectCard(const QSharedPointer& pCardConnectionWorker) +{ + for (const auto& appId : {FileRef::appEId(), FileRef::appPersosim()}) + { + const auto eidAvailable = detectEid(pCardConnectionWorker, appId); + if (eidAvailable) + { + return true; + } + } + + if (selectApplication(pCardConnectionWorker, FileRef::appPassport())) + { + qCDebug(card) << "Passport found"; + } + + return false; +} + + +QSharedPointer CardInfoFactory::readEfCardAccess(const QSharedPointer& pCardConnectionWorker) +{ + QByteArray efCardAccessBytes; + if (pCardConnectionWorker->readFile(FileRef::efCardAccess(), efCardAccessBytes) != CardReturnCode::OK) + { + qCCritical(card) << "Error while reading EF.CardAccess: Cannot read EF.CardAccess"; + return QSharedPointer(); + } + + auto efCardAccess = EFCardAccess::decode(efCardAccessBytes); + if (efCardAccess == nullptr) + { + qCCritical(card) << "Error while reading EF.CardAccess: Cannot parse EFCardAccess"; + } + return efCardAccess; +} + + +bool CardInfoFactory::checkEfCardAccess(const QSharedPointer& pEfCardAccess) +{ + if (!pEfCardAccess) + { + return false; + } + + /* + * At least one PACEInfo must have standardized domain parameters + */ + bool containsStandardizedDomainParameters = false; + const auto& infos = pEfCardAccess->getPaceInfos(); + for (const auto& paceInfo : infos) + { + if (paceInfo->isStandardizedDomainParameters()) + { + containsStandardizedDomainParameters = true; + break; + } + } + if (!containsStandardizedDomainParameters) + { + qCCritical(card) << "Error while reading EF.CardAccess: No PACEInfo with standardized domain parameters found"; + return false; + } + + return true; +} diff --git a/src/card/base/CardInfoFactory.h b/src/card/base/CardInfoFactory.h new file mode 100644 index 000000000..338763f27 --- /dev/null +++ b/src/card/base/CardInfoFactory.h @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2014-2023 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "CardConnectionWorker.h" +#include "CardInfo.h" +#include "FileRef.h" + +#include + +class test_CardInfoFactory; + +namespace governikus +{ + +/*! + * Factory for creation of CardInfo instances. + */ +class CardInfoFactory final +{ + friend class ::test_CardInfoFactory; + + public: + /*! + * In order to create a CardInfo instance a connection is established to the smart card + * and data is read. + */ + static CardInfo create(const QSharedPointer& pCardConnectionWorker); + + private: + static bool selectApplication(const QSharedPointer& pCardConnectionWorker, const FileRef& pFileRef); + + /*! + * Checks, if the smart card is a german eID card (i.e. a NPA or an EAT) or a passport. + */ + static bool detectCard(const QSharedPointer& pCardConnectionWorker); + static bool detectEid(const QSharedPointer& pCardConnectionWorker, const FileRef& pRef); + + /*! + * Reads the EF.CardAccess + */ + static QSharedPointer readEfCardAccess(const QSharedPointer& pCardConnectionWorker); + + /*! + * According to TR-03105 we have to perform some checks on EF.CardAccess the first time we read it. + * Therefore we read it just once and handle malformed EF.CardAccess structures here in card recognition process. + */ + static bool checkEfCardAccess(const QSharedPointer& pEfCardAccess); +}; + + +} // namespace governikus diff --git a/src/card/base/Reader.cpp b/src/card/base/Reader.cpp index f2a63b6b1..46029e7db 100644 --- a/src/card/base/Reader.cpp +++ b/src/card/base/Reader.cpp @@ -5,6 +5,7 @@ #include "Reader.h" #include "CardConnectionWorker.h" +#include "CardInfoFactory.h" #include "apdu/CommandApdu.h" #include "apdu/CommandData.h" #include "apdu/PacePinStatus.h" @@ -59,11 +60,13 @@ void Reader::removeCardInfo() } -void Reader::fetchCardInfo(QSharedPointer pCardConnection) +void Reader::fetchCardInfo() { - setInfoCardInfo(CardInfoFactory::create(pCardConnection)); + const auto& cardConnection = createCardConnectionWorker(); - if (pCardConnection && pCardConnection->updateRetryCounter() != CardReturnCode::OK) + setInfoCardInfo(CardInfoFactory::create(cardConnection)); + + if (cardConnection && cardConnection->updateRetryCounter() != CardReturnCode::OK) { qCWarning(card) << "Update of the retry counter failed"; setInfoCardInfo(CardInfo(CardType::UNKNOWN)); @@ -71,7 +74,7 @@ void Reader::fetchCardInfo(QSharedPointer pCardConnection) } -int Reader::getTimerId() +int Reader::getTimerId() const { return mTimerId; } @@ -85,11 +88,7 @@ void Reader::setTimerId(int pTimerId) void Reader::insertCard(const QVariant& pData) { -#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) - const bool skipCheck = pData.type() == QVariant::Bool && pData.toBool(); -#else const bool skipCheck = pData.typeId() == QMetaType::Bool && pData.toBool(); -#endif if (!skipCheck && !mReaderInfo.isInsertable()) { qCDebug(card) << "Skipping insert because at least the personalization is missing"; diff --git a/src/card/base/Reader.h b/src/card/base/Reader.h index 9e4fe781f..5d85ff23f 100644 --- a/src/card/base/Reader.h +++ b/src/card/base/Reader.h @@ -13,6 +13,7 @@ namespace governikus { +class CardConnectionWorker; class Reader : public QObject @@ -26,9 +27,9 @@ class Reader void setInfoCardInfo(const CardInfo& pCardInfo); void setCardInfoTagType(CardInfo::TagType pTagType); void removeCardInfo(); - void fetchCardInfo(QSharedPointer pCardConnection); + void fetchCardInfo(); - [[nodiscard]] int getTimerId(); + [[nodiscard]] int getTimerId() const; void setTimerId(int pTimerId); void timerEvent(QTimerEvent* pEvent) override; diff --git a/src/card/base/ReaderFilter.cpp b/src/card/base/ReaderFilter.cpp index 16ba4980f..ecfe5f69c 100644 --- a/src/card/base/ReaderFilter.cpp +++ b/src/card/base/ReaderFilter.cpp @@ -4,14 +4,9 @@ #include "ReaderFilter.h" -#include "ReaderConfiguration.h" -#include "ReaderManagerPlugIn.h" +#include "ReaderConfigurationInfo.h" -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) - #include -#else - #include -#endif +#include using namespace governikus; diff --git a/src/card/base/ReaderFilter.h b/src/card/base/ReaderFilter.h index f953111b8..53ad3e972 100644 --- a/src/card/base/ReaderFilter.h +++ b/src/card/base/ReaderFilter.h @@ -17,8 +17,6 @@ namespace governikus { -class ReaderManagerPlugIn; - class ReaderFilter { public: diff --git a/src/card/base/ReaderInfo.h b/src/card/base/ReaderInfo.h index aa64eed98..aec197870 100644 --- a/src/card/base/ReaderInfo.h +++ b/src/card/base/ReaderInfo.h @@ -113,13 +113,6 @@ class ReaderInfo } - [[nodiscard]] bool isPhysicalCard() const - { - const auto& cardType = mCardInfo.getCardType(); - return cardType == CardType::EID_CARD; - } - - [[nodiscard]] bool isSoftwareSmartEid() const { return mCardInfo.getMobileEidType() == MobileEidType::HW_KEYSTORE; diff --git a/src/card/base/ReaderManager.cpp b/src/card/base/ReaderManager.cpp index 90ec06528..250cd8de1 100644 --- a/src/card/base/ReaderManager.cpp +++ b/src/card/base/ReaderManager.cpp @@ -225,34 +225,6 @@ void ReaderManager::stopScanAll(const QString& pError) } -bool ReaderManager::isScanRunning() const -{ - const QMutexLocker mutexLocker(&mMutex); - - bool running = false; - if (mWorker) - { - QMetaObject::invokeMethod(mWorker.data(), qOverload<>(&ReaderManagerWorker::isScanRunning), Qt::BlockingQueuedConnection, &running); - } - return running; -} - - -bool ReaderManager::isScanRunning(ReaderManagerPlugInType pType) const -{ - const QMutexLocker mutexLocker(&mMutex); - - bool running = false; - if (mWorker) - { - QMetaObject::invokeMethod(mWorker.data(), [this, pType] { - return mWorker->isScanRunning(pType); - }, Qt::BlockingQueuedConnection, &running); - } - return running; -} - - ReaderManagerPlugInInfo ReaderManager::getPlugInInfo(ReaderManagerPlugInType pType) const { const QMutexLocker mutexLocker(&mMutex); @@ -265,7 +237,7 @@ void ReaderManager::doUpdateCacheEntry(const ReaderInfo& pInfo) { const QMutexLocker mutexLocker(&mMutex); - qCDebug(card) << "Update cache entry:" << pInfo.getName(); + qCDebug(card).noquote() << "Update cache entry:" << pInfo.getName(); mReaderInfoCache.insert(pInfo.getName(), pInfo); } @@ -274,7 +246,7 @@ void ReaderManager::doRemoveCacheEntry(const ReaderInfo& pInfo) { const QMutexLocker mutexLocker(&mMutex); - qCDebug(card) << "Remove cache entry:" << pInfo.getName(); + qCDebug(card).noquote() << "Remove cache entry:" << pInfo.getName(); mReaderInfoCache.remove(pInfo.getName()); } @@ -283,7 +255,7 @@ void ReaderManager::doUpdatePluginCache(const ReaderManagerPlugInInfo& pInfo) { const QMutexLocker mutexLocker(&mMutex); - qCDebug(card) << "Update cache entry:" << pInfo.getPlugInType(); + qCDebug(card).noquote() << "Update cache entry:" << pInfo.getPlugInType(); mPlugInInfoCache.insert(pInfo.getPlugInType(), pInfo); } @@ -292,14 +264,7 @@ QVector ReaderManager::getReaderInfos(const ReaderFilter& pFilter) c { Q_ASSERT(mThread.isRunning() || mThread.isFinished()); const QMutexLocker mutexLocker(&mMutex); - -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) - const auto& list = mReaderInfoCache.values(); -#else - const auto& list = mReaderInfoCache.values().toVector(); // clazy:exclude=container-anti-pattern -#endif - - return pFilter.apply(list); + return pFilter.apply(mReaderInfoCache.values()); } @@ -320,12 +285,3 @@ void ReaderManager::updateReaderInfo(const QString& pReaderName) mWorker->updateReaderInfo(pReaderName); }, Qt::BlockingQueuedConnection); // needed to force the ReaderInfo update, else StateMachine loops based on stale state can occur } - - -void ReaderManager::updateRetryCounters() -{ - Q_ASSERT(mWorker); - const QMutexLocker mutexLocker(&mMutex); - - QMetaObject::invokeMethod(mWorker.data(), &ReaderManagerWorker::updateRetryCounters, Qt::QueuedConnection); -} diff --git a/src/card/base/ReaderManager.h b/src/card/base/ReaderManager.h index 88dc21c0c..ff41a4fa5 100644 --- a/src/card/base/ReaderManager.h +++ b/src/card/base/ReaderManager.h @@ -79,16 +79,6 @@ class ReaderManager */ void stopScanAll(const QString& pError = QString()); - /*! - * Queries if any plugin is currently scanning - */ - bool isScanRunning() const; - - /*! - * Queries if a plugin with the requested type is currently scanning - */ - bool isScanRunning(ReaderManagerPlugInType pType) const; - /*! * Stops started scan for devices. * Be aware that some plugins don't finish the whole scan if you @@ -107,6 +97,13 @@ class ReaderManager } + template + static bool isResultType(const QVariant& pResult) + { + return pResult.metaType() == QMetaType::fromType(); + } + + /*! * Executes a function on ReaderManager-Thread. * \param pFunc Function that will be executed. @@ -195,9 +192,6 @@ class ReaderManager return connection; } - - void updateRetryCounters(); - Q_SIGNALS: void firePluginAdded(const ReaderManagerPlugInInfo& pInfo); void fireStatusChanged(const ReaderManagerPlugInInfo& pInfo); diff --git a/src/card/base/ReaderManagerPlugIn.cpp b/src/card/base/ReaderManagerPlugIn.cpp index 0d174d68d..8b77773ba 100644 --- a/src/card/base/ReaderManagerPlugIn.cpp +++ b/src/card/base/ReaderManagerPlugIn.cpp @@ -12,12 +12,11 @@ ReaderManagerPlugIn::ReaderManagerPlugIn(ReaderManagerPlugInType pPlugInType, bool pAvailable, bool pPlugInEnabled) : mInfo(pPlugInType, pPlugInEnabled, pAvailable) - , mScanRunning(false) { } -void ReaderManagerPlugIn::shelve() +void ReaderManagerPlugIn::shelve() const { const auto& readers = getReaders(); for (const auto& reader : readers) @@ -32,9 +31,9 @@ void ReaderManagerPlugIn::shelve() void ReaderManagerPlugIn::startScan(bool /*pAutoConnect*/) { - if (!mScanRunning) + if (!mInfo.isScanRunning()) { - mScanRunning = true; + mInfo.setScanRunning(true); Q_EMIT fireStatusChanged(mInfo); } } @@ -44,9 +43,9 @@ void ReaderManagerPlugIn::stopScan(const QString& pError) { Q_UNUSED(pError) - if (mScanRunning) + if (mInfo.isScanRunning()) { - mScanRunning = false; + mInfo.setScanRunning(false); Q_EMIT fireStatusChanged(mInfo); } } diff --git a/src/card/base/ReaderManagerPlugIn.h b/src/card/base/ReaderManagerPlugIn.h index a023f5f73..966a2ee4f 100644 --- a/src/card/base/ReaderManagerPlugIn.h +++ b/src/card/base/ReaderManagerPlugIn.h @@ -9,7 +9,6 @@ #pragma once -#include "GlobalStatus.h" #include "Reader.h" #include "ReaderInfo.h" #include "ReaderManagerPlugInInfo.h" @@ -28,7 +27,6 @@ class ReaderManagerPlugIn private: ReaderManagerPlugInInfo mInfo; - bool mScanRunning; protected: void setPlugInEnabled(bool pEnabled) @@ -65,12 +63,6 @@ class ReaderManagerPlugIn } - [[nodiscard]] bool isScanRunning() const - { - return mScanRunning; - } - - [[nodiscard]] virtual QList getReaders() const = 0; @@ -99,7 +91,7 @@ class ReaderManagerPlugIn } - void shelve(); + void shelve() const; virtual void startScan(bool pAutoConnect); diff --git a/src/card/base/ReaderManagerPlugInInfo.cpp b/src/card/base/ReaderManagerPlugInInfo.cpp index 897abcfea..f8884cf8c 100644 --- a/src/card/base/ReaderManagerPlugInInfo.cpp +++ b/src/card/base/ReaderManagerPlugInInfo.cpp @@ -18,6 +18,7 @@ ReaderManagerPlugInInfo::ReaderManagerPlugInInfo(ReaderManagerPlugInType pType, , mValues() , mEnabled(pEnabled) , mAvailable(pAvailable) + , mScanRunning(false) { } diff --git a/src/card/base/ReaderManagerPlugInInfo.h b/src/card/base/ReaderManagerPlugInInfo.h index 805735c79..54cebc3a1 100644 --- a/src/card/base/ReaderManagerPlugInInfo.h +++ b/src/card/base/ReaderManagerPlugInInfo.h @@ -95,11 +95,26 @@ class ReaderManagerPlugInInfo mAvailable = pAvailable; } + + [[nodiscard]] bool isScanRunning() const + { + return mScanRunning; + } + + + void setScanRunning(bool pScanRunning) + { + mScanRunning = pScanRunning; + } + private: ReaderManagerPlugInType mType; QMap mValues; bool mEnabled; bool mAvailable; + bool mScanRunning; + + }; } // namespace governikus diff --git a/src/card/base/ReaderManagerWorker.cpp b/src/card/base/ReaderManagerWorker.cpp index ddef92760..285f31b6a 100644 --- a/src/card/base/ReaderManagerWorker.cpp +++ b/src/card/base/ReaderManagerWorker.cpp @@ -173,7 +173,7 @@ void ReaderManagerWorker::startScan(ReaderManagerPlugInType pType, bool pAutoCon Q_ASSERT(QObject::thread() == QThread::currentThread()); callOnPlugIn(pType, [pAutoConnect](ReaderManagerPlugIn* pPlugIn){ - if (!pPlugIn->isScanRunning()) + if (!pPlugIn->getInfo().isScanRunning()) { pPlugIn->startScan(pAutoConnect); } @@ -186,7 +186,7 @@ void ReaderManagerWorker::stopScan(ReaderManagerPlugInType pType, const QString& Q_ASSERT(QObject::thread() == QThread::currentThread()); callOnPlugIn(pType, [pError](ReaderManagerPlugIn* pPlugIn){ - if (pPlugIn->isScanRunning()) + if (pPlugIn->getInfo().isScanRunning()) { pPlugIn->stopScan(pError); } @@ -194,28 +194,6 @@ void ReaderManagerWorker::stopScan(ReaderManagerPlugInType pType, const QString& } -bool ReaderManagerWorker::isScanRunning() const -{ - Q_ASSERT(QObject::thread() == QThread::currentThread()); - - return std::any_of(mPlugIns.constBegin(), mPlugIns.constEnd(), [](const auto* plugin) - { - return plugin->isScanRunning(); - }); -} - - -bool ReaderManagerWorker::isScanRunning(ReaderManagerPlugInType pType) const -{ - Q_ASSERT(QObject::thread() == QThread::currentThread()); - - return std::any_of(mPlugIns.constBegin(), mPlugIns.constEnd(), [pType](const auto* plugin) - { - return plugin->getInfo().getPlugInType() == pType && plugin->isScanRunning(); - }); -} - - QVector ReaderManagerWorker::getReaderInfos() const { Q_ASSERT(QObject::thread() == QThread::currentThread()); @@ -279,23 +257,3 @@ void ReaderManagerWorker::createCardConnectionWorker(const QString& pReaderName) } Q_EMIT fireCardConnectionWorkerCreated(worker); } - - -void ReaderManagerWorker::updateRetryCounters() -{ - Q_ASSERT(QObject::thread() == QThread::currentThread()); - - const auto& readerInfos = getReaderInfos(); - for (const auto& readerInfo : readerInfos) - { - QSharedPointer worker; - if (const auto& reader = getReader(readerInfo.getName())) - { - worker = reader->createCardConnectionWorker(); - if (worker) - { - worker->updateRetryCounter(); - } - } - } -} diff --git a/src/card/base/ReaderManagerWorker.h b/src/card/base/ReaderManagerWorker.h index 470edd34a..9bedc08a0 100644 --- a/src/card/base/ReaderManagerWorker.h +++ b/src/card/base/ReaderManagerWorker.h @@ -42,13 +42,10 @@ class ReaderManagerWorker Q_INVOKABLE void shelve(); Q_INVOKABLE void startScan(ReaderManagerPlugInType pType, bool pAutoConnect); Q_INVOKABLE void stopScan(ReaderManagerPlugInType pType, const QString& pError); - Q_INVOKABLE [[nodiscard]] bool isScanRunning() const; - Q_INVOKABLE [[nodiscard]] bool isScanRunning(ReaderManagerPlugInType pType) const; - Q_INVOKABLE [[nodiscard]] QVector getReaderInfos() const; + [[nodiscard]] Q_INVOKABLE QVector getReaderInfos() const; Q_INVOKABLE void updateReaderInfo(const QString& pReaderName); Q_INVOKABLE void createCardConnectionWorker(const QString& pReaderName); - Q_INVOKABLE void updateRetryCounters(); Q_SIGNALS: void firePluginAdded(const ReaderManagerPlugInInfo& pInfo); diff --git a/src/card/base/apdu/CommandData.cpp b/src/card/base/apdu/CommandData.cpp index 3f456e399..9e02d755d 100644 --- a/src/card/base/apdu/CommandData.cpp +++ b/src/card/base/apdu/CommandData.cpp @@ -38,7 +38,7 @@ CommandData::CommandData(const QByteArray& pData) long size = -1; int tagNumber = -1; int tagClass = -1; - const auto result = ASN1_get_object(&p, &size, &tagNumber, &tagClass, data.length()); + const auto result = ASN1_get_object(&p, &size, &tagNumber, &tagClass, static_cast(data.length())); if (result & 0x80) { qCritical() << "Could not parse CommandData:" << getOpenSslError(); diff --git a/src/card/base/apdu/FileCommand.cpp b/src/card/base/apdu/FileCommand.cpp index 28da923ae..9f7c80ce3 100644 --- a/src/card/base/apdu/FileCommand.cpp +++ b/src/card/base/apdu/FileCommand.cpp @@ -48,7 +48,7 @@ FileCommand::FileCommand(const CommandApdu& pCommandApdu) } -FileCommand::FileCommand(const FileRef& pFileRef, int pOffset, int pLe) +FileCommand::FileCommand(const FileRef& pFileRef, qsizetype pOffset, int pLe) : mFileRef(pFileRef) , mOffset(pOffset) , mLe(pLe) @@ -62,7 +62,7 @@ const FileRef& FileCommand::getFileRef() const } -int FileCommand::getOffset() const +qsizetype FileCommand::getOffset() const { return mOffset; } diff --git a/src/card/base/apdu/FileCommand.h b/src/card/base/apdu/FileCommand.h index 39b49a6ca..98f7381e2 100644 --- a/src/card/base/apdu/FileCommand.h +++ b/src/card/base/apdu/FileCommand.h @@ -16,15 +16,15 @@ class FileCommand { private: FileRef mFileRef; - int mOffset; + qsizetype mOffset; int mLe; public: explicit FileCommand(const CommandApdu& pCommandApdu); - explicit FileCommand(const FileRef& pFileRef, int pOffset = 0, int pLe = CommandApdu::NO_LE); + explicit FileCommand(const FileRef& pFileRef, qsizetype pOffset = 0, int pLe = CommandApdu::NO_LE); [[nodiscard]] const FileRef& getFileRef() const; - [[nodiscard]] int getOffset() const; + [[nodiscard]] qsizetype getOffset() const; [[nodiscard]] int getLe() const; operator CommandApdu() const; diff --git a/src/card/base/apdu/SecureMessagingTypes.cpp b/src/card/base/apdu/SecureMessagingTypes.cpp index 017d360c7..a7ffdbadd 100644 --- a/src/card/base/apdu/SecureMessagingTypes.cpp +++ b/src/card/base/apdu/SecureMessagingTypes.cpp @@ -4,9 +4,6 @@ #include "SecureMessagingTypes.h" -#include "asn1/ASN1Util.h" - - using namespace governikus; diff --git a/src/card/base/asn1/ASN1TemplateUtil.h b/src/card/base/asn1/ASN1TemplateUtil.h index 1bcc31c94..eba6f3f8e 100644 --- a/src/card/base/asn1/ASN1TemplateUtil.h +++ b/src/card/base/asn1/ASN1TemplateUtil.h @@ -118,7 +118,7 @@ QSharedPointer decodeObject(const QByteArray& pData, bool pLogging = true) const auto** dataPointer = reinterpret_cast(&tmp); T* object = nullptr; - if (!decodeAsn1Object(&object, dataPointer, pData.length()) && pLogging) + if (!decodeAsn1Object(&object, dataPointer, static_cast(pData.length())) && pLogging) { qCWarning(card) << "Cannot decode ASN.1 object:" << getOpenSslError(); } diff --git a/src/card/base/asn1/ASN1Util.cpp b/src/card/base/asn1/ASN1Util.cpp index 1cca7cf73..bf2fc676a 100644 --- a/src/card/base/asn1/ASN1Util.cpp +++ b/src/card/base/asn1/ASN1Util.cpp @@ -4,8 +4,6 @@ #include "asn1/ASN1Util.h" -#include "apdu/SecureMessagingResponse.h" - #include #include #include @@ -19,7 +17,7 @@ using namespace governikus; void Asn1OctetStringUtil::setValue(const QByteArray& pValue, ASN1_OCTET_STRING* pAsn1OctetString) { - ASN1_OCTET_STRING_set(pAsn1OctetString, reinterpret_cast(pValue.data()), pValue.length()); + ASN1_OCTET_STRING_set(pAsn1OctetString, reinterpret_cast(pValue.data()), static_cast(pValue.length())); } @@ -37,7 +35,7 @@ QByteArray Asn1OctetStringUtil::getValue(ASN1_OCTET_STRING* pAsn1OctetString) void Asn1StringUtil::setValue(const QString& pString, ASN1_STRING* pOut) { QByteArray bytes = pString.toUtf8(); - ASN1_STRING_set(pOut, bytes.data(), bytes.length()); + ASN1_STRING_set(pOut, bytes.data(), static_cast(bytes.length())); } @@ -151,11 +149,11 @@ QDate Asn1BCDDateUtil::convertFromUnpackedBCDToQDate(const ASN1_OCTET_STRING* pD QByteArray Asn1Util::encode(int pClass, int pTag, const QByteArray& pData, bool pConstructed) { const int constructed = pConstructed ? V_ASN1_CONSTRUCTED : 0; - const int size = ASN1_object_size(constructed, pData.length(), pTag); + const int size = ASN1_object_size(constructed, static_cast(pData.length()), pTag); QByteArray result(size, 0); auto* p = reinterpret_cast(result.data()); - ASN1_put_object(&p, constructed, pData.length(), pTag, pClass); + ASN1_put_object(&p, constructed, static_cast(pData.length()), pTag, pClass); Q_ASSERT(reinterpret_cast(result.data()) + result.length() == p + pData.length()); memcpy(p, pData.data(), static_cast(pData.length())); diff --git a/src/card/base/asn1/ASN1Util.h b/src/card/base/asn1/ASN1Util.h index c7ee7ae7e..bb8225c22 100644 --- a/src/card/base/asn1/ASN1Util.h +++ b/src/card/base/asn1/ASN1Util.h @@ -14,15 +14,7 @@ #include #include - -/*! - * OpenSSL type declarations - */ -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) -DECLARE_STACK_OF(ASN1_OCTET_STRING) -#else DEFINE_STACK_OF(ASN1_OCTET_STRING) -#endif namespace governikus { diff --git a/src/card/base/asn1/ApplicationTemplate.h b/src/card/base/asn1/ApplicationTemplate.h index 85ec5b03d..853a78a3e 100644 --- a/src/card/base/asn1/ApplicationTemplate.h +++ b/src/card/base/asn1/ApplicationTemplate.h @@ -10,7 +10,6 @@ #include "ASN1TemplateUtil.h" #include "FileRef.h" -#include "SecurityProtocol.h" #include #include @@ -65,12 +64,7 @@ inline QDebug operator<<(QDebug pDbg, const QSharedPointer& } -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) -DECLARE_STACK_OF(ApplicationTemplate) -#else DEFINE_STACK_OF(ApplicationTemplate) -#endif - DECLARE_ASN1_FUNCTIONS(ApplicationTemplate) DECLARE_ASN1_OBJECT(ApplicationTemplate) diff --git a/src/card/base/asn1/ApplicationTemplates.cpp b/src/card/base/asn1/ApplicationTemplates.cpp index acc043f78..e2cd3231b 100644 --- a/src/card/base/asn1/ApplicationTemplates.cpp +++ b/src/card/base/asn1/ApplicationTemplates.cpp @@ -6,7 +6,6 @@ #include "ASN1TemplateUtil.h" #include "ASN1Util.h" -#include "FileRef.h" #include #include @@ -24,16 +23,8 @@ ASN1_ITEM_TEMPLATE(ApplicationTemplatesInternal) = ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SET_OF, 0x00, ApplicationTemplatesInternal, ApplicationTemplate) ASN1_ITEM_TEMPLATE_END(ApplicationTemplatesInternal) - IMPLEMENT_ASN1_FUNCTIONS(ApplicationTemplatesInternal) - IMPLEMENT_ASN1_OBJECT(ApplicationTemplatesInternal) - -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) - #define sk_ApplicationTemplate_num(data) SKM_sk_num(ApplicationTemplate, data) - #define sk_ApplicationTemplate_value(data, i) SKM_sk_value(ApplicationTemplate, data, i) -#endif - } // namespace governikus @@ -100,7 +91,7 @@ bool ApplicationTemplates::contains(const QByteArray& pIdentifier) } -int ApplicationTemplates::count() const +qsizetype ApplicationTemplates::count() const { return mApplicationTemplates.size(); } diff --git a/src/card/base/asn1/ApplicationTemplates.h b/src/card/base/asn1/ApplicationTemplates.h index 1d0a8db5a..17238e969 100644 --- a/src/card/base/asn1/ApplicationTemplates.h +++ b/src/card/base/asn1/ApplicationTemplates.h @@ -10,8 +10,6 @@ #pragma once #include "ApplicationTemplate.h" -#include "ChipAuthenticationInfo.h" -#include "PaceInfo.h" #include #include @@ -27,12 +25,7 @@ namespace governikus * defined in ISO 7816-4:2005 8.2.1.1 */ -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) -using ApplicationTemplatesInternal = stack_st_ApplicationTemplate; -#else using ApplicationTemplatesInternal = STACK_OF(ApplicationTemplate); -#endif - DECLARE_ASN1_FUNCTIONS(ApplicationTemplatesInternal) DECLARE_ASN1_OBJECT(ApplicationTemplatesInternal) @@ -57,7 +50,7 @@ class ApplicationTemplates [[nodiscard]] const QByteArray& getContentBytes() const; [[nodiscard]] const QVector>& getApplicationTemplates() const; - [[nodiscard]] int count() const; + [[nodiscard]] qsizetype count() const; }; diff --git a/src/card/base/asn1/AuthenticatedAuxiliaryData.cpp b/src/card/base/asn1/AuthenticatedAuxiliaryData.cpp index 3d509ca77..c31fb53c4 100644 --- a/src/card/base/asn1/AuthenticatedAuxiliaryData.cpp +++ b/src/card/base/asn1/AuthenticatedAuxiliaryData.cpp @@ -92,18 +92,10 @@ ASN1_ITEM_TEMPLATE(AgeVerificationDate) = ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_IMPTAG | ASN1_TFLG_APPLICATION, 0x13, AgeVerificationDate, ASN1_OCTET_STRING) ASN1_ITEM_TEMPLATE_END(AgeVerificationDate) - IMPLEMENT_ASN1_FUNCTIONS(AgeVerificationDate) DECLARE_ASN1_FUNCTIONS(AuthenticatedAuxiliaryDataInternal) DECLARE_ASN1_OBJECT(AuthenticatedAuxiliaryDataInternal) - - -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) - #define sk_AuxDataTemplate_num(data) SKM_sk_num(AuxDataTemplate, data) - #define sk_AuxDataTemplate_value(data, i) SKM_sk_value(AuxDataTemplate, data, i) -#endif - } // namespace governikus diff --git a/src/card/base/asn1/AuthenticatedAuxiliaryData.h b/src/card/base/asn1/AuthenticatedAuxiliaryData.h index 6a47d5e41..3939d2e53 100644 --- a/src/card/base/asn1/AuthenticatedAuxiliaryData.h +++ b/src/card/base/asn1/AuthenticatedAuxiliaryData.h @@ -50,13 +50,8 @@ using AuxDataTemplate = struct auxdatatemplate_st ASN1_TYPE* mExtInfo; }; -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) -DECLARE_STACK_OF(AuxDataTemplate) -using AuthenticatedAuxiliaryDataInternal = stack_st_AuxDataTemplate; -#else DEFINE_STACK_OF(AuxDataTemplate) using AuthenticatedAuxiliaryDataInternal = STACK_OF(AuxDataTemplate); -#endif class AuthenticatedAuxiliaryData { diff --git a/src/card/base/asn1/CVCertificate.cpp b/src/card/base/asn1/CVCertificate.cpp index 59e87ab1d..ee88e504d 100644 --- a/src/card/base/asn1/CVCertificate.cpp +++ b/src/card/base/asn1/CVCertificate.cpp @@ -6,7 +6,6 @@ #include "ASN1TemplateUtil.h" #include "ASN1Util.h" -#include "pace/ec/EcUtil.h" #include @@ -60,17 +59,11 @@ int CVCertificate::decodeCallback(int pOperation, ASN1_VALUE** pVal, const ASN1_ QByteArray sigValue = Asn1OctetStringUtil::getValue(cvc->mSignature); const auto* const sig = reinterpret_cast(sigValue.data()); - int siglen = sigValue.size(); + const auto siglen = static_cast(sigValue.size()); BIGNUM* r = BN_bin2bn(sig, siglen / 2, nullptr); BIGNUM* s = BN_bin2bn(sig + (siglen / 2), siglen / 2, nullptr); - -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) - cvc->mEcdsaSignature->r = r; - cvc->mEcdsaSignature->s = s; -#else ECDSA_SIG_set0(cvc->mEcdsaSignature, r, s); -#endif } } else if (pOperation == ASN1_OP_FREE_POST) diff --git a/src/card/base/asn1/CVCertificate.h b/src/card/base/asn1/CVCertificate.h index b5134ee4d..6aee6d877 100644 --- a/src/card/base/asn1/CVCertificate.h +++ b/src/card/base/asn1/CVCertificate.h @@ -8,10 +8,8 @@ #pragma once - #include "CVCertificateBody.h" - #include #include diff --git a/src/card/base/asn1/CVCertificateBody.cpp b/src/card/base/asn1/CVCertificateBody.cpp index e606e5023..8807642da 100644 --- a/src/card/base/asn1/CVCertificateBody.cpp +++ b/src/card/base/asn1/CVCertificateBody.cpp @@ -94,13 +94,6 @@ ASN1_ITEM_TEMPLATE_END(CVCertificateBody) IMPLEMENT_ASN1_FUNCTIONS(CVCertificateBody) IMPLEMENT_ASN1_OBJECT(CVCertificateBody) - - -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) - #define sk_CERTIFICATEEXTENSION_num(data) SKM_sk_num(CERTIFICATEEXTENSION, data) - #define sk_CERTIFICATEEXTENSION_value(data, i) SKM_sk_value(CERTIFICATEEXTENSION, data, i) -#endif - } // namespace governikus diff --git a/src/card/base/asn1/CVCertificateBody.h b/src/card/base/asn1/CVCertificateBody.h index 3324f829d..6f64feb34 100644 --- a/src/card/base/asn1/CVCertificateBody.h +++ b/src/card/base/asn1/CVCertificateBody.h @@ -34,12 +34,7 @@ using CERTIFICATEEXTENSION = struct CERTIFICATEEXTENSION_st ASN1_OCTET_STRING* mObject8; }; DECLARE_ASN1_FUNCTIONS(CERTIFICATEEXTENSION) - -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) -DECLARE_STACK_OF(CERTIFICATEEXTENSION) -#else DEFINE_STACK_OF(CERTIFICATEEXTENSION) -#endif using CVCertificateBody = struct certificateprofilebody_st { diff --git a/src/card/base/asn1/CVCertificateChainBuilder.cpp b/src/card/base/asn1/CVCertificateChainBuilder.cpp index baf058d1e..3c6548701 100644 --- a/src/card/base/asn1/CVCertificateChainBuilder.cpp +++ b/src/card/base/asn1/CVCertificateChainBuilder.cpp @@ -20,7 +20,8 @@ bool CVCertificateChainBuilder::isChild(const QSharedPointer>(), pProductive) + : ChainBuilder(QVector>(), &CVCertificateChainBuilder::isChild) + , mProductive(pProductive) { } diff --git a/src/card/base/asn1/CertificateDescription.h b/src/card/base/asn1/CertificateDescription.h index 302e48fb4..7beb93c96 100644 --- a/src/card/base/asn1/CertificateDescription.h +++ b/src/card/base/asn1/CertificateDescription.h @@ -93,10 +93,4 @@ struct CertificateDescription DECLARE_ASN1_FUNCTIONS(CertificateDescription) DECLARE_ASN1_OBJECT(CertificateDescription) - -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) - #define sk_ASN1_OCTET_STRING_num(data) data->stack.num - #define sk_ASN1_OCTET_STRING_value(data, i) SKM_sk_value(ASN1_OCTET_STRING, data, i) -#endif - } // namespace governikus diff --git a/src/card/base/asn1/ChainBuilder.h b/src/card/base/asn1/ChainBuilder.h index c35ae5178..240120068 100644 --- a/src/card/base/asn1/ChainBuilder.h +++ b/src/card/base/asn1/ChainBuilder.h @@ -12,7 +12,6 @@ #pragma once - #include #include #include diff --git a/src/card/base/asn1/EFCardSecurity.cpp b/src/card/base/asn1/EFCardSecurity.cpp index 0bb6be897..43e7c1967 100644 --- a/src/card/base/asn1/EFCardSecurity.cpp +++ b/src/card/base/asn1/EFCardSecurity.cpp @@ -36,12 +36,6 @@ QSharedPointer EFCardSecurity::fromHex(const QByteArray& pHexStr QSharedPointer EFCardSecurity::decode(const QByteArray& pBytes) { -#ifdef OPENSSL_NO_CMS - #error Cryptographic Message Syntax (CMS) is required. Do you use LibreSSL? - Q_UNUSED(pBytes) - return QSharedPointer(); - -#else const auto contentInfo = decodeObject(pBytes); if (contentInfo == nullptr) { @@ -77,8 +71,6 @@ QSharedPointer EFCardSecurity::decode(const QByteArray& pBytes) } return QSharedPointer::create(securityInfos); - -#endif } diff --git a/src/card/base/asn1/EFCardSecurity.h b/src/card/base/asn1/EFCardSecurity.h index a27df3717..b4c4a0a1b 100644 --- a/src/card/base/asn1/EFCardSecurity.h +++ b/src/card/base/asn1/EFCardSecurity.h @@ -6,10 +6,8 @@ * \brief Implementation of EFCardSecurity */ - #pragma once - #include "SecurityInfos.h" #ifndef OPENSSL_NO_CMS diff --git a/src/card/base/asn1/EcdsaPublicKey.cpp b/src/card/base/asn1/EcdsaPublicKey.cpp index 64cd2d9ed..7d3d5d241 100644 --- a/src/card/base/asn1/EcdsaPublicKey.cpp +++ b/src/card/base/asn1/EcdsaPublicKey.cpp @@ -213,7 +213,7 @@ QSharedPointer EcdsaPublicKey::createGroup(const CurveData& pData) con QSharedPointer EcdsaPublicKey::createKey(const QByteArray& pPublicPoint) const { - return createKey(reinterpret_cast(pPublicPoint.constData()), pPublicPoint.size()); + return createKey(reinterpret_cast(pPublicPoint.constData()), static_cast(pPublicPoint.size())); } diff --git a/src/card/base/asn1/MobileEIDTypeInfo.cpp b/src/card/base/asn1/MobileEIDTypeInfo.cpp index d67ebf307..45e808680 100644 --- a/src/card/base/asn1/MobileEIDTypeInfo.cpp +++ b/src/card/base/asn1/MobileEIDTypeInfo.cpp @@ -5,8 +5,6 @@ #include "MobileEIDTypeInfo.h" #include "ASN1TemplateUtil.h" -#include "ASN1Util.h" -#include "SecurityProtocol.h" using namespace governikus; diff --git a/src/card/base/asn1/Oid.cpp b/src/card/base/asn1/Oid.cpp index 9980e1e25..a18f7114b 100644 --- a/src/card/base/asn1/Oid.cpp +++ b/src/card/base/asn1/Oid.cpp @@ -246,15 +246,9 @@ QByteArray Oid::getData() const return QByteArray(); } -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) - return QByteArray(reinterpret_cast(mObject->data), mObject->length); - -#else const size_t len = OBJ_length(mObject); const uchar* const data = OBJ_get0_data(mObject); return QByteArray(reinterpret_cast(data), static_cast(len)); - -#endif } @@ -272,7 +266,7 @@ Oid::operator QByteArray() const } QByteArray description(oidSize + 1, '\0'); // +1 = null termination - OBJ_obj2txt(description.data(), description.size(), mObject, 1); + OBJ_obj2txt(description.data(), static_cast(description.size()), mObject, 1); description.resize(oidSize); // remove null termination if (const int nid = OBJ_obj2nid(mObject); nid != NID_undef) diff --git a/src/card/base/asn1/PaceInfo.h b/src/card/base/asn1/PaceInfo.h index 741be8de5..859c8b3a4 100644 --- a/src/card/base/asn1/PaceInfo.h +++ b/src/card/base/asn1/PaceInfo.h @@ -8,7 +8,6 @@ #pragma once -#include "EnumHelper.h" #include "SecurityInfo.h" class test_PaceInfo; diff --git a/src/card/base/asn1/SecurityInfo.cpp b/src/card/base/asn1/SecurityInfo.cpp index ddd4220ba..bd1ba10fb 100644 --- a/src/card/base/asn1/SecurityInfo.cpp +++ b/src/card/base/asn1/SecurityInfo.cpp @@ -4,10 +4,6 @@ #include "SecurityInfo.h" -#include "ASN1Util.h" -#include "ChipAuthenticationInfo.h" -#include "PaceInfo.h" - #include diff --git a/src/card/base/asn1/SecurityInfo.h b/src/card/base/asn1/SecurityInfo.h index 20ca0ec07..ab4c6eb37 100644 --- a/src/card/base/asn1/SecurityInfo.h +++ b/src/card/base/asn1/SecurityInfo.h @@ -35,11 +35,7 @@ struct securityinfo_st }; DECLARE_ASN1_FUNCTIONS(securityinfo_st) -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) -DECLARE_STACK_OF(securityinfo_st) -#else DEFINE_STACK_OF(securityinfo_st) -#endif DECLARE_ASN1_OBJECT(securityinfo_st) /* diff --git a/src/card/base/asn1/SecurityInfos.cpp b/src/card/base/asn1/SecurityInfos.cpp index 4195fcc8c..4da68e6b1 100644 --- a/src/card/base/asn1/SecurityInfos.cpp +++ b/src/card/base/asn1/SecurityInfos.cpp @@ -21,16 +21,8 @@ ASN1_ITEM_TEMPLATE(securityinfos_st) = ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SET_OF, 0x00, securityinfos_st, securityinfo_st) ASN1_ITEM_TEMPLATE_END(securityinfos_st) - IMPLEMENT_ASN1_FUNCTIONS(securityinfos_st) - IMPLEMENT_ASN1_OBJECT(securityinfos_st) - -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) - #define sk_securityinfo_st_num(data) SKM_sk_num(securityinfo_st, data) - #define sk_securityinfo_st_value(data, i) SKM_sk_value(securityinfo_st, data, i) -#endif - } // namespace governikus diff --git a/src/card/base/asn1/SignatureChecker.h b/src/card/base/asn1/SignatureChecker.h index 884e0cf95..d0cf83906 100644 --- a/src/card/base/asn1/SignatureChecker.h +++ b/src/card/base/asn1/SignatureChecker.h @@ -4,10 +4,9 @@ #pragma once -#include - #include "asn1/CVCertificate.h" +#include namespace governikus { diff --git a/src/card/base/command/BaseCardCommand.cpp b/src/card/base/command/BaseCardCommand.cpp index 895b14a3c..823e6028a 100644 --- a/src/card/base/command/BaseCardCommand.cpp +++ b/src/card/base/command/BaseCardCommand.cpp @@ -4,9 +4,7 @@ #include "BaseCardCommand.h" -#include "CardConnection.h" #include "Initializer.h" -#include "asn1/SecurityInfos.h" #include #include diff --git a/src/card/base/command/DestroyPaceChannelCommand.cpp b/src/card/base/command/DestroyPaceChannelCommand.cpp index e28902b38..8364f0628 100644 --- a/src/card/base/command/DestroyPaceChannelCommand.cpp +++ b/src/card/base/command/DestroyPaceChannelCommand.cpp @@ -4,8 +4,6 @@ #include "DestroyPaceChannelCommand.h" -#include "CardConnection.h" - using namespace governikus; diff --git a/src/card/base/command/DestroyPaceChannelCommand.h b/src/card/base/command/DestroyPaceChannelCommand.h index 9162d0e7a..0e934cb15 100644 --- a/src/card/base/command/DestroyPaceChannelCommand.h +++ b/src/card/base/command/DestroyPaceChannelCommand.h @@ -9,6 +9,7 @@ #pragma once #include "BaseCardCommand.h" +#include "CardConnectionWorker.h" class test_DestroyPaceChannelCommand; diff --git a/src/card/base/command/DidAuthenticateEAC1Command.cpp b/src/card/base/command/DidAuthenticateEAC1Command.cpp index b201edbd8..eb74080f0 100644 --- a/src/card/base/command/DidAuthenticateEAC1Command.cpp +++ b/src/card/base/command/DidAuthenticateEAC1Command.cpp @@ -4,8 +4,6 @@ #include "DidAuthenticateEAC1Command.h" -#include "BaseCardCommand.h" -#include "CardConnection.h" #include "apdu/CommandApdu.h" #include diff --git a/src/card/base/command/DidAuthenticateEAC1Command.h b/src/card/base/command/DidAuthenticateEAC1Command.h index 5118ce2c5..73b464781 100644 --- a/src/card/base/command/DidAuthenticateEAC1Command.h +++ b/src/card/base/command/DidAuthenticateEAC1Command.h @@ -9,7 +9,7 @@ #pragma once #include "BaseCardCommand.h" -#include "asn1/Chat.h" +#include "CardConnectionWorker.h" class test_DidAuthenticateEAC1Command; class test_StateDidAuthenticateEac1; diff --git a/src/card/base/command/EstablishPaceChannelCommand.cpp b/src/card/base/command/EstablishPaceChannelCommand.cpp index 493a0990e..1b6dd7be3 100644 --- a/src/card/base/command/EstablishPaceChannelCommand.cpp +++ b/src/card/base/command/EstablishPaceChannelCommand.cpp @@ -38,14 +38,13 @@ void EstablishPaceChannelCommand::internalExecute() return; } - if (mPacePasswordId == PacePasswordId::PACE_PUK) + if (mPacePasswordId == PacePasswordId::PACE_PUK + && (getCardConnectionWorker()->getReaderInfo().getRetryCounter() > 0 + || getCardConnectionWorker()->getReaderInfo().isPinDeactivated())) { - if (getCardConnectionWorker()->getReaderInfo().getRetryCounter() > 0 || getCardConnectionWorker()->getReaderInfo().isPinDeactivated()) - { - mPaceOutput.setPaceReturnCode(CardReturnCode::PIN_NOT_BLOCKED); - setReturnCode(mPaceOutput.getPaceReturnCode()); - return; - } + mPaceOutput.setPaceReturnCode(CardReturnCode::PIN_NOT_BLOCKED); + setReturnCode(mPaceOutput.getPaceReturnCode()); + return; } if (getCardConnectionWorker()->getReaderInfo().isSoftwareSmartEid()) diff --git a/src/card/base/command/TransmitCommand.cpp b/src/card/base/command/TransmitCommand.cpp index 13219cb6a..5d86739ca 100644 --- a/src/card/base/command/TransmitCommand.cpp +++ b/src/card/base/command/TransmitCommand.cpp @@ -4,7 +4,6 @@ #include "TransmitCommand.h" -#include "CardConnection.h" #include "CardReturnCode.h" #include "GlobalStatus.h" #include "InputAPDUInfo.h" diff --git a/src/card/base/command/TransmitCommand.h b/src/card/base/command/TransmitCommand.h index 26be31cd0..64084180e 100644 --- a/src/card/base/command/TransmitCommand.h +++ b/src/card/base/command/TransmitCommand.h @@ -9,6 +9,7 @@ #pragma once #include "BaseCardCommand.h" +#include "CardConnectionWorker.h" #include "InputAPDUInfo.h" class test_TransmitCommand; diff --git a/src/card/base/pace/CipherMac.cpp b/src/card/base/pace/CipherMac.cpp index 5ee07d43f..ba5a262b3 100644 --- a/src/card/base/pace/CipherMac.cpp +++ b/src/card/base/pace/CipherMac.cpp @@ -4,8 +4,6 @@ #include "pace/CipherMac.h" -#include "ec/EcUtil.h" - #include #include @@ -39,34 +37,7 @@ CipherMac::CipherMac(const SecurityProtocol& pSecurityProtocol, const QByteArray qCCritical(card) << "Key has wrong size (expected/got):" << EVP_CIPHER_key_length(cipher) << '/' << pKeyBytes.size(); return; } -#endif - -#if OPENSSL_VERSION_NUMBER < 0x10101000L || defined(LIBRESSL_VERSION_NUMBER) - const auto ctx = EcUtil::create(EVP_PKEY_CTX_new_id(EVP_PKEY_CMAC, nullptr)); - if (ctx.isNull() || !EVP_PKEY_keygen_init(ctx.data())) - { - qCCritical(card) << "Cannot init ctx"; - return; - } - - if (EVP_PKEY_CTX_ctrl(ctx.data(), -1, EVP_PKEY_OP_KEYGEN, EVP_PKEY_CTRL_CIPHER, 0, const_cast(cipher)) <= 0) - { - qCCritical(card) << "Cannot set cipher"; - return; - } - - if (EVP_PKEY_CTX_ctrl(ctx.data(), -1, EVP_PKEY_OP_KEYGEN, EVP_PKEY_CTRL_SET_MAC_KEY, pKeyBytes.size(), const_cast(pKeyBytes.data())) <= 0) - { - qCCritical(card) << "Cannot set key"; - return; - } - - if (!EVP_PKEY_keygen(ctx.data(), &mKey)) - { - qCCritical(card) << "Cannot generate EVP pkey"; - } -#elif OPENSSL_VERSION_NUMBER < 0x30000000L mKey = EVP_PKEY_new_CMAC_key(nullptr, reinterpret_cast(pKeyBytes.constData()), static_cast(pKeyBytes.size()), cipher); #else diff --git a/src/card/base/pace/SecureMessaging.h b/src/card/base/pace/SecureMessaging.h index 042a46adc..bca230301 100644 --- a/src/card/base/pace/SecureMessaging.h +++ b/src/card/base/pace/SecureMessaging.h @@ -11,7 +11,6 @@ #include "SecurityProtocol.h" #include "apdu/CommandApdu.h" #include "apdu/ResponseApdu.h" -#include "asn1/ASN1TemplateUtil.h" #include "pace/CipherMac.h" #include "pace/SymmetricCipher.h" diff --git a/src/card/base/pace/SymmetricCipher.cpp b/src/card/base/pace/SymmetricCipher.cpp index 91346d2e4..98cf9b2e3 100644 --- a/src/card/base/pace/SymmetricCipher.cpp +++ b/src/card/base/pace/SymmetricCipher.cpp @@ -35,22 +35,13 @@ SymmetricCipher::SymmetricCipher(const SecurityProtocol& pSecurityProtocol, cons } mCtx = EVP_CIPHER_CTX_new(); -#if OPENSSL_VERSION_NUMBER < 0x10100000L - EVP_CIPHER_CTX_init(mCtx); -#else EVP_CIPHER_CTX_reset(mCtx); -#endif } SymmetricCipher::~SymmetricCipher() { -#if OPENSSL_VERSION_NUMBER < 0x10100000L - EVP_CIPHER_CTX_cleanup(mCtx); -#else EVP_CIPHER_CTX_reset(mCtx); -#endif - EVP_CIPHER_CTX_free(mCtx); } @@ -76,7 +67,10 @@ QByteArray SymmetricCipher::encrypt(const QByteArray& pPlainData) } EVP_CIPHER_CTX_set_padding(mCtx, 0); - if (pPlainData.size() % EVP_CIPHER_block_size(EVP_CIPHER_CTX_cipher(mCtx)) != 0) +#if OPENSSL_VERSION_NUMBER < 0x30000000L + #define EVP_CIPHER_CTX_get0_cipher(x) EVP_CIPHER_CTX_cipher(x) +#endif + if (pPlainData.size() % EVP_CIPHER_block_size(EVP_CIPHER_CTX_get0_cipher(mCtx)) != 0) { qCCritical(card) << "Plain data length is not a multiple of the block size"; return QByteArray(); @@ -84,7 +78,7 @@ QByteArray SymmetricCipher::encrypt(const QByteArray& pPlainData) QVector cryptogram(pPlainData.size()); int update_len = 0; - if (!EVP_EncryptUpdate(mCtx, cryptogram.data(), &update_len, reinterpret_cast(pPlainData.constData()), pPlainData.size())) + if (!EVP_EncryptUpdate(mCtx, cryptogram.data(), &update_len, reinterpret_cast(pPlainData.constData()), static_cast(pPlainData.size()))) { qCCritical(card) << "Error on EVP_EncryptUpdate"; return QByteArray(); @@ -138,7 +132,10 @@ QByteArray SymmetricCipher::decrypt(const QByteArray& pEncryptedData) } EVP_CIPHER_CTX_set_padding(mCtx, 0); - if (pEncryptedData.size() % EVP_CIPHER_block_size(EVP_CIPHER_CTX_cipher(mCtx)) != 0) +#if OPENSSL_VERSION_NUMBER < 0x30000000L + #define EVP_CIPHER_CTX_get0_cipher(x) EVP_CIPHER_CTX_cipher(x) +#endif + if (pEncryptedData.size() % EVP_CIPHER_block_size(EVP_CIPHER_CTX_get0_cipher(mCtx)) != 0) { qCCritical(card) << "Encrypted data length is not a multiple of the block size"; return QByteArray(); @@ -146,7 +143,7 @@ QByteArray SymmetricCipher::decrypt(const QByteArray& pEncryptedData) QVector plaintext(pEncryptedData.size()); int update_len = 0; - if (!EVP_DecryptUpdate(mCtx, plaintext.data(), &update_len, reinterpret_cast(pEncryptedData.constData()), pEncryptedData.size())) + if (!EVP_DecryptUpdate(mCtx, plaintext.data(), &update_len, reinterpret_cast(pEncryptedData.constData()), static_cast(pEncryptedData.size()))) { qCCritical(card) << "Error on EVP_DecryptUpdate"; return QByteArray(); diff --git a/src/card/base/pace/ec/EcdhGenericMapping.cpp b/src/card/base/pace/ec/EcdhGenericMapping.cpp index 6aff2bc0a..cdee20f4c 100644 --- a/src/card/base/pace/ec/EcdhGenericMapping.cpp +++ b/src/card/base/pace/ec/EcdhGenericMapping.cpp @@ -2,9 +2,9 @@ * Copyright (c) 2014-2023 Governikus GmbH & Co. KG, Germany */ -#include "pace/ec/EcdhGenericMapping.h" +#include "EcdhGenericMapping.h" -#include "pace/ec/EcUtil.h" +#include "EcUtil.h" #include #include @@ -69,7 +69,7 @@ bool EcdhGenericMapping::generateEphemeralDomainParameters(const QByteArray& pCa } QSharedPointer s = EcUtil::create(BN_new()); - if (!BN_bin2bn(reinterpret_cast(pNonce.constData()), pNonce.size(), s.data())) + if (!BN_bin2bn(reinterpret_cast(pNonce.constData()), static_cast(pNonce.size()), s.data())) { qCCritical(card) << "Cannot convert nonce to BIGNUM"; return false; @@ -111,7 +111,7 @@ QSharedPointer EcdhGenericMapping::createNewGenerator(const QSharedPoi } -bool EcdhGenericMapping::setGenerator(const QSharedPointer& pNewGenerator) +bool EcdhGenericMapping::setGenerator(const QSharedPointer& pNewGenerator) const { QSharedPointer curveOrder = EcUtil::create(BN_new()); if (!EC_GROUP_get_order(mCurve.data(), curveOrder.data(), nullptr)) diff --git a/src/card/base/pace/ec/EcdhGenericMapping.h b/src/card/base/pace/ec/EcdhGenericMapping.h index e8b5f2c05..3a06cd1b1 100644 --- a/src/card/base/pace/ec/EcdhGenericMapping.h +++ b/src/card/base/pace/ec/EcdhGenericMapping.h @@ -30,7 +30,7 @@ class EcdhGenericMapping QSharedPointer createNewGenerator(const QSharedPointer& pCardPubKey, const QSharedPointer& pS); - bool setGenerator(const QSharedPointer& pNewGenerator); + bool setGenerator(const QSharedPointer& pNewGenerator) const; public: explicit EcdhGenericMapping(const QSharedPointer& pCurve); diff --git a/src/card/base/pace/ec/EcdhKeyAgreement.cpp b/src/card/base/pace/ec/EcdhKeyAgreement.cpp index 48899e84a..065cf388e 100644 --- a/src/card/base/pace/ec/EcdhKeyAgreement.cpp +++ b/src/card/base/pace/ec/EcdhKeyAgreement.cpp @@ -2,10 +2,11 @@ * Copyright (c) 2014-2023 Governikus GmbH & Co. KG, Germany */ -#include "pace/ec/EcdhKeyAgreement.h" +#include "EcdhKeyAgreement.h" +#include "EcUtil.h" +#include "asn1/ASN1Util.h" #include "asn1/PaceInfo.h" -#include "pace/ec/EcUtil.h" #include diff --git a/src/card/base/pace/ec/EcdhKeyAgreement.h b/src/card/base/pace/ec/EcdhKeyAgreement.h index af7b9d9f4..e8a480721 100644 --- a/src/card/base/pace/ec/EcdhKeyAgreement.h +++ b/src/card/base/pace/ec/EcdhKeyAgreement.h @@ -5,9 +5,8 @@ #pragma once #include "CardConnectionWorker.h" -#include "asn1/SecurityInfo.h" +#include "EcdhGenericMapping.h" #include "pace/KeyAgreement.h" -#include "pace/ec/EcdhGenericMapping.h" #include #include diff --git a/src/card/base/pinpad/EstablishPaceChannel.cpp b/src/card/base/pinpad/EstablishPaceChannel.cpp index 8850e0326..e01c37ec8 100644 --- a/src/card/base/pinpad/EstablishPaceChannel.cpp +++ b/src/card/base/pinpad/EstablishPaceChannel.cpp @@ -6,7 +6,6 @@ #include "LengthValue.h" #include "apdu/CommandApdu.h" -#include "apdu/ResponseApdu.h" #include "asn1/ASN1Util.h" #include @@ -97,26 +96,14 @@ bool EstablishPaceChannel::fromCcid(const QByteArray& pInput) return false; } - Q_ASSERT(channelInput->mPasswordID); - if (channelInput->mPasswordID) + const auto asn1_char = static_cast(ASN1_INTEGER_get(channelInput->mPasswordID)); + if (!Enum::isValue(asn1_char)) { - const auto asn1_char = static_cast(ASN1_INTEGER_get(channelInput->mPasswordID)); - if (Enum::isValue(asn1_char)) - { - mPasswordId = PacePasswordId(asn1_char); - } - else - { - qCDebug(card) << "Decapsulation: Bad PIN ID!"; - Q_ASSERT(false); - } - } - else - { - qCDebug(card) << "Decapsulation: No PIN ID!"; - Q_ASSERT(false); + qCDebug(card) << "Decapsulation: Bad PIN ID!"; + return false; } + mPasswordId = PacePasswordId(asn1_char); // Chat and certificate description are only available in authentications via PIN mode or CAN allowed mode if (mPasswordId == PacePasswordId::PACE_PIN || mPasswordId == PacePasswordId::PACE_CAN) { @@ -288,7 +275,7 @@ QByteArray EstablishPaceChannel::createCommandDataCcid() const if (!mCertificateDescription.isEmpty()) { const auto* unsignedCharPointer = reinterpret_cast(mCertificateDescription.constData()); - decodeAsn1Object(&channelInput->mCertificateDescription, &unsignedCharPointer, mCertificateDescription.size()); + decodeAsn1Object(&channelInput->mCertificateDescription, &unsignedCharPointer, static_cast(mCertificateDescription.size())); } QByteArray data = encodeObject(channelInput.data()); diff --git a/src/card/base/pinpad/EstablishPaceChannelOutput.cpp b/src/card/base/pinpad/EstablishPaceChannelOutput.cpp index 57f66e209..deac1de59 100644 --- a/src/card/base/pinpad/EstablishPaceChannelOutput.cpp +++ b/src/card/base/pinpad/EstablishPaceChannelOutput.cpp @@ -6,6 +6,7 @@ #include "LengthValue.h" #include "apdu/ResponseApdu.h" +#include "asn1/ASN1Util.h" #include #include @@ -47,6 +48,7 @@ CardReturnCode EstablishPaceChannelOutput::parseReturnCode(quint32 pPaceReturnCo // no error return CardReturnCode::OK; + case EstablishPaceChannelErrorCode::NoActivePinSet: case EstablishPaceChannelErrorCode::InconsistentLengthsInInput: case EstablishPaceChannelErrorCode::UnexpectedDataInInput: case EstablishPaceChannelErrorCode::UnexpectedCombinationOfDataInInput: @@ -69,9 +71,6 @@ CardReturnCode EstablishPaceChannelOutput::parseReturnCode(quint32 pPaceReturnCo case EstablishPaceChannelErrorCode::Timeout: return CardReturnCode::INPUT_TIME_OUT; - case EstablishPaceChannelErrorCode::NoActivePinSet: - return CardReturnCode::NO_ACTIVE_PIN_SET; - default: break; } @@ -142,9 +141,6 @@ EstablishPaceChannelErrorCode EstablishPaceChannelOutput::generateReturnCode(Car case CardReturnCode::CANCELLATION_BY_USER: return EstablishPaceChannelErrorCode::Abort; - - case CardReturnCode::NO_ACTIVE_PIN_SET: - return EstablishPaceChannelErrorCode::NoActivePinSet; } Q_UNREACHABLE(); @@ -163,6 +159,27 @@ void EstablishPaceChannelOutput::initEfCardAccess() } +bool EstablishPaceChannelOutput::findErrorCode(const QString& pOutputData) +{ + // Try to parse the value of EstablishPaceChannelOutput.errorCode + // the regular expression is determined by the ASN.1 structure of EstablishPaceChannelOutput + + QRegularExpression regExp(QStringLiteral("(.*)a1060404(?([[:xdigit:]]){8})a2040402")); + auto match = regExp.match(pOutputData); + if (!match.hasMatch()) + { + return false; + } + + qCWarning(card) << "Determine at least PACE return code by regular expression"; + const QByteArray paceReturnCodeBytes = QByteArray::fromHex(match.captured(QStringLiteral("a1")).toUtf8()); + mPaceReturnCode = parseReturnCode(qFromBigEndian(paceReturnCodeBytes.data())); + qCDebug(card) << "mPaceReturnCode:" << paceReturnCodeBytes.toHex() << mPaceReturnCode; + + return true; +} + + EstablishPaceChannelOutput::EstablishPaceChannelOutput(CardReturnCode pPaceReturnCode) : mPaceReturnCode(pPaceReturnCode) , mStatusMseSetAt() @@ -261,9 +278,12 @@ bool EstablishPaceChannelOutput::parseOutputData(const QByteArray& pOutput) return true; } + auto debugGuard = qScopeGuard([] { + qCDebug(card) << "Decapsulation of command failed. Wrong size."; + }); + if (it > pOutput.size()) { - qCDebug(card) << "Decapsulation of command failed. Wrong size."; return false; } @@ -271,7 +291,6 @@ bool EstablishPaceChannelOutput::parseOutputData(const QByteArray& pOutput) qCDebug(card) << "mCarCurr:" << mCarCurr; if (it > pOutput.size()) { - qCDebug(card) << "Decapsulation of command failed. Wrong size."; return false; } @@ -279,7 +298,6 @@ bool EstablishPaceChannelOutput::parseOutputData(const QByteArray& pOutput) qCDebug(card) << "mCarPrev:" << mCarPrev; if (it > pOutput.size()) { - qCDebug(card) << "Decapsulation of command failed. Wrong size."; return false; } @@ -287,10 +305,10 @@ bool EstablishPaceChannelOutput::parseOutputData(const QByteArray& pOutput) qCDebug(card) << "mIdIcc:" << mIdIcc.toHex(); if (it != pOutput.size()) { - qCDebug(card) << "Decapsulation of command failed. Wrong size."; return false; } + debugGuard.dismiss(); return true; } @@ -315,25 +333,9 @@ bool EstablishPaceChannelOutput::parseFromCcid(const QByteArray& pOutput) const auto channelOutput = decodeObject(outputData); if (channelOutput == nullptr) { - auto outputDataHex = QString::fromLatin1(outputData.toHex()); + const auto& outputDataHex = QString::fromLatin1(outputData.toHex()); qCCritical(card) << "Parsing EstablishPaceChannelOutput failed" << outputDataHex; - - // Try to parse the value of EstablishPaceChannelOutput.errorCode - // the regular expression is determined by the ASN.1 structure of EstablishPaceChannelOutput - - QRegularExpression regExp(QStringLiteral("(.*)a1060404(?([[:xdigit:]]){8})a2040402")); - auto match = regExp.match(outputDataHex); - if (match.hasMatch()) - { - qCWarning(card) << "Determine at least PACE return code by regular expression"; - const QByteArray paceReturnCodeBytes = QByteArray::fromHex(match.captured(QStringLiteral("a1")).toUtf8()); - mPaceReturnCode = parseReturnCode(qFromBigEndian(paceReturnCodeBytes.data())); - qCDebug(card) << "mPaceReturnCode:" << paceReturnCodeBytes.toHex() << mPaceReturnCode; - - return true; - } - - return false; + return findErrorCode(outputDataHex); } const QByteArray paceReturnCodeBytes = Asn1OctetStringUtil::getValue(channelOutput->mErrorCode); @@ -505,7 +507,7 @@ QByteArray EstablishPaceChannelOutput::toCcid() const Asn1OctetStringUtil::setValue(mStatusMseSetAt, establishPaceChannelOutput->mStatusMSESetAt); const auto* unsignedCharPointer = reinterpret_cast(mEfCardAccess.constData()); - decodeAsn1Object(&establishPaceChannelOutput->mEfCardAccess, &unsignedCharPointer, mEfCardAccess.size()); + decodeAsn1Object(&establishPaceChannelOutput->mEfCardAccess, &unsignedCharPointer, static_cast(mEfCardAccess.size())); if (!mIdIcc.isEmpty()) { diff --git a/src/card/base/pinpad/EstablishPaceChannelOutput.h b/src/card/base/pinpad/EstablishPaceChannelOutput.h index bd25d51be..07389e300 100644 --- a/src/card/base/pinpad/EstablishPaceChannelOutput.h +++ b/src/card/base/pinpad/EstablishPaceChannelOutput.h @@ -9,8 +9,6 @@ #pragma once #include "CardReturnCode.h" -#include "SmartCardDefinitions.h" -#include "asn1/CertificateDescription.h" #include "asn1/SecurityInfos.h" #include "pace/EstablishPaceChannelCode.h" @@ -61,6 +59,7 @@ class EstablishPaceChannelOutput void initMseStatusSetAt(); void initEfCardAccess(); + bool findErrorCode(const QString& pOutputData); public: explicit EstablishPaceChannelOutput(CardReturnCode pPaceReturnCode = CardReturnCode::COMMAND_FAILED); diff --git a/src/card/base/pinpad/LengthValue.h b/src/card/base/pinpad/LengthValue.h index bfab53abf..47190bcde 100644 --- a/src/card/base/pinpad/LengthValue.h +++ b/src/card/base/pinpad/LengthValue.h @@ -48,11 +48,7 @@ class LengthValue Q_ASSERT(sizeof(T) < INT_MAX); const int maxSize = std::numeric_limits::max(); -#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) - const int size = std::min(maxSize, pValue.size()); -#else const int size = std::min(maxSize, static_cast(pValue.size())); -#endif const auto it = pOutput.size(); pOutput.resize(it + static_cast(sizeof(T))); diff --git a/src/card/base/pinpad/PinModify.h b/src/card/base/pinpad/PinModify.h index fb3d1959a..b9f0112b9 100644 --- a/src/card/base/pinpad/PinModify.h +++ b/src/card/base/pinpad/PinModify.h @@ -4,8 +4,6 @@ #pragma once -#include "apdu/CommandApdu.h" - #include diff --git a/src/card/base/pinpad/PinModifyOutput.h b/src/card/base/pinpad/PinModifyOutput.h index 0e21ed008..2cdd15248 100644 --- a/src/card/base/pinpad/PinModifyOutput.h +++ b/src/card/base/pinpad/PinModifyOutput.h @@ -4,7 +4,6 @@ #pragma once -#include "CardReturnCode.h" #include "apdu/ResponseApdu.h" #include diff --git a/src/card/drivers/ReaderDetector.h b/src/card/drivers/ReaderDetector.h index af1d13390..35ab24cb8 100644 --- a/src/card/drivers/ReaderDetector.h +++ b/src/card/drivers/ReaderDetector.h @@ -10,7 +10,7 @@ #pragma once #include "Env.h" -#include "ReaderConfiguration.h" +#include "ReaderConfigurationInfo.h" #include "UsbId.h" #ifdef Q_OS_LINUX @@ -22,11 +22,6 @@ #endif #ifdef Q_OS_WIN - #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) -using EventFilterResultType = long; - #else -using EventFilterResultType = qintptr; - #endif #include #endif @@ -67,7 +62,7 @@ class ReaderDetector [[nodiscard]] virtual QVector attachedDevIds() const; #ifdef Q_OS_WIN - bool nativeEventFilter(const QByteArray& pEventType, void* pMessage, EventFilterResultType* pResult) override; + bool nativeEventFilter(const QByteArray& pEventType, void* pMessage, qintptr* pResult) override; #endif /*! diff --git a/src/card/drivers/ReaderDetector_win.cpp b/src/card/drivers/ReaderDetector_win.cpp index 5733565a5..81323d7e8 100644 --- a/src/card/drivers/ReaderDetector_win.cpp +++ b/src/card/drivers/ReaderDetector_win.cpp @@ -80,7 +80,7 @@ static QStringList attachedDevStringIds() static uint getId(const QString& pDevId, const QString& pPrefix) { static const int ID_LENGTH = 4; - const int prefixPosition = pDevId.indexOf(pPrefix, 0, Qt::CaseInsensitive); + const auto prefixPosition = pDevId.indexOf(pPrefix, 0, Qt::CaseInsensitive); if (prefixPosition == -1 || pDevId.size() < prefixPosition + pPrefix.size() + ID_LENGTH) { return 0; @@ -127,7 +127,7 @@ QVector ReaderDetector::attachedDevIds() const } -bool ReaderDetector::nativeEventFilter(const QByteArray& pEventType, void* pMessage, EventFilterResultType* pResult) +bool ReaderDetector::nativeEventFilter(const QByteArray& pEventType, void* pMessage, qintptr* pResult) { Q_UNUSED(pResult) diff --git a/src/card/nfc/NfcReader.cpp b/src/card/nfc/NfcReader.cpp index 10853f8fd..1c552f5fc 100644 --- a/src/card/nfc/NfcReader.cpp +++ b/src/card/nfc/NfcReader.cpp @@ -4,14 +4,10 @@ #include "NfcReader.h" -#include "CardConnectionWorker.h" #include "VolatileSettings.h" #include -#if defined(Q_OS_ANDROID) - #include -#endif using namespace governikus; @@ -49,8 +45,7 @@ void NfcReader::targetDetected(QNearFieldTarget* pTarget) mCard.reset(new NfcCard(pTarget)); connect(mCard.data(), &NfcCard::fireSetProgressMessage, this, &NfcReader::setProgressMessage); - QSharedPointer cardConnection = createCardConnectionWorker(); - fetchCardInfo(cardConnection); + fetchCardInfo(); if (!getCard()) { @@ -115,14 +110,6 @@ NfcReader::NfcReader() #if defined(Q_OS_ANDROID) mNfManager.startTargetDetection(QNearFieldTarget::TagTypeSpecificAccess); - - if (QNativeInterface::QAndroidApplication::isActivityContext()) - { - if (QJniObject activity = QNativeInterface::QAndroidApplication::context(); activity.isValid()) - { - activity.callMethod("enableNfcReaderMode"); - } - } #endif } @@ -130,13 +117,6 @@ NfcReader::NfcReader() #if defined(Q_OS_ANDROID) NfcReader::~NfcReader() { - if (QNativeInterface::QAndroidApplication::isActivityContext()) - { - if (QJniObject activity = QNativeInterface::QAndroidApplication::context(); activity.isValid()) - { - activity.callMethod("disableNfcReaderMode"); - } - } mNfManager.stopTargetDetection(); } diff --git a/src/card/nfc/NfcReaderManagerPlugIn.cpp b/src/card/nfc/NfcReaderManagerPlugIn.cpp index f874a1d0f..841c9845f 100644 --- a/src/card/nfc/NfcReaderManagerPlugIn.cpp +++ b/src/card/nfc/NfcReaderManagerPlugIn.cpp @@ -17,9 +17,12 @@ using namespace governikus; Q_DECLARE_LOGGING_CATEGORY(card_nfc) +QAtomicPointer NfcReaderManagerPlugIn::instance = nullptr; + + void NfcReaderManagerPlugIn::onNfcAdapterStateChanged(bool pEnabled) { - if (getInfo().isEnabled() == pEnabled) + if (getInfo().isEnabled() == pEnabled || !mNfcReader) { return; } @@ -52,18 +55,73 @@ void NfcReaderManagerPlugIn::onReaderDisconnected() } +void NfcReaderManagerPlugIn::setReaderMode(bool pEnabled) +{ +#ifdef Q_OS_ANDROID + if (QNativeInterface::QAndroidApplication::isActivityContext()) + { + if (QJniObject activity = QNativeInterface::QAndroidApplication::context(); activity.isValid()) + { + activity.callMethod("setReaderMode", "(Z)V", pEnabled); + } + } +#else + Q_UNUSED(pEnabled) +#endif +} + + +void NfcReaderManagerPlugIn::enqueueReaderMode(bool pEnabled) +{ + if (auto* plugin = NfcReaderManagerPlugIn::instance.loadRelaxed()) + { + QMetaObject::invokeMethod(plugin, [plugin, pEnabled] { + if (plugin->mNfcReader) + { + setReaderMode(pEnabled); + } + }, Qt::QueuedConnection); + } +} + + +#ifdef Q_OS_ANDROID +extern "C" +{ + +// These functions need to be explicitly exported so that the JVM can bind to them. +JNIEXPORT void JNICALL Java_com_governikus_ausweisapp2_MainActivity_setReaderModeNative(JNIEnv* pEnv, jobject pObj, jboolean pEnabled) +{ + Q_UNUSED(pEnv) + Q_UNUSED(pObj) + + NfcReaderManagerPlugIn::enqueueReaderMode(pEnabled); +} + + +} +#endif + + NfcReaderManagerPlugIn::NfcReaderManagerPlugIn() : ReaderManagerPlugIn(ReaderManagerPlugInType::NFC, QNearFieldManager().isSupported(QNearFieldTarget::TagTypeSpecificAccess) ) , mNfcReader(nullptr) { + instance = this; +} + + +NfcReaderManagerPlugIn::~NfcReaderManagerPlugIn() +{ + instance = nullptr; } QList NfcReaderManagerPlugIn::getReaders() const { - if (getInfo().isEnabled()) + if (getInfo().isEnabled() && mNfcReader) { return QList({mNfcReader.data()}); } @@ -76,7 +134,7 @@ void NfcReaderManagerPlugIn::init() { ReaderManagerPlugIn::init(); - if (mNfcReader) + if (!getInfo().isAvailable() || mNfcReader) { return; } @@ -90,26 +148,37 @@ void NfcReaderManagerPlugIn::init() connect(mNfcReader.data(), &NfcReader::fireReaderDisconnected, this, &NfcReaderManagerPlugIn::onReaderDisconnected); qCDebug(card_nfc) << "Add reader" << mNfcReader->getName(); - onNfcAdapterStateChanged(mNfcReader->isEnabled() && getInfo().isAvailable()); + setReaderMode(true); + onNfcAdapterStateChanged(mNfcReader->isEnabled()); } void NfcReaderManagerPlugIn::shutdown() { - onNfcAdapterStateChanged(false); - mNfcReader.reset(); + if (mNfcReader) + { + onNfcAdapterStateChanged(false); + setReaderMode(false); + mNfcReader.reset(); + } } void NfcReaderManagerPlugIn::startScan(bool pAutoConnect) { - mNfcReader->connectReader(); - ReaderManagerPlugIn::startScan(pAutoConnect); + if (mNfcReader) + { + mNfcReader->connectReader(); + ReaderManagerPlugIn::startScan(pAutoConnect); + } } void NfcReaderManagerPlugIn::stopScan(const QString& pError) { - mNfcReader->disconnectReader(pError); - ReaderManagerPlugIn::stopScan(pError); + if (mNfcReader) + { + mNfcReader->disconnectReader(pError); + ReaderManagerPlugIn::stopScan(pError); + } } diff --git a/src/card/nfc/NfcReaderManagerPlugIn.h b/src/card/nfc/NfcReaderManagerPlugIn.h index 51198847a..3fc53f2cf 100644 --- a/src/card/nfc/NfcReaderManagerPlugIn.h +++ b/src/card/nfc/NfcReaderManagerPlugIn.h @@ -11,6 +11,7 @@ #include "NfcReader.h" #include "ReaderManagerPlugIn.h" +#include #include @@ -25,6 +26,8 @@ class NfcReaderManagerPlugIn Q_INTERFACES(governikus::ReaderManagerPlugIn) private: + static QAtomicPointer instance; + QScopedPointer mNfcReader; private Q_SLOTS: @@ -32,8 +35,11 @@ class NfcReaderManagerPlugIn void onReaderDisconnected(); public: + static void setReaderMode(bool pEnabled); + static void enqueueReaderMode(bool pEnabled); + NfcReaderManagerPlugIn(); - ~NfcReaderManagerPlugIn() override = default; + ~NfcReaderManagerPlugIn() override; [[nodiscard]] QList getReaders() const override; diff --git a/src/card/pcsc/PcscCard.cpp b/src/card/pcsc/PcscCard.cpp index 9eb45dd7b..57ba32458 100644 --- a/src/card/pcsc/PcscCard.cpp +++ b/src/card/pcsc/PcscCard.cpp @@ -59,7 +59,7 @@ PcscCard::PcscCard(PcscReader* pPcscReader) , mTimer() { PCSC_RETURNCODE returnCode = SCardEstablishContext(SCARD_SCOPE_USER, nullptr, nullptr, &mContextHandle); - qCDebug(card_pcsc) << "SCardEstablishContext for" << mReader->getName() << ':' << PcscUtils::toString(returnCode); + qCDebug(card_pcsc) << "SCardEstablishContext for" << mReader->getName() << ':' << pcsc::toString(returnCode); mTimer.setInterval(4000); connect(&mTimer, &QTimer::timeout, this, &PcscCard::sendSCardStatus); @@ -75,7 +75,7 @@ PcscCard::~PcscCard() } PCSC_RETURNCODE returnCode = SCardReleaseContext(mContextHandle); - qCDebug(card_pcsc) << "SCardReleaseContext for" << mReader->getName() << ':' << PcscUtils::toString(returnCode); + qCDebug(card_pcsc) << "SCardReleaseContext for" << mReader->getName() << ':' << pcsc::toString(returnCode); mContextHandle = 0; } @@ -111,15 +111,15 @@ CardReturnCode PcscCard::establishConnection() PCSC_INT preferredProtocols = SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1; PCSC_RETURNCODE returnCode = SCardConnect(mContextHandle, mReader->getState().szReader, shareMode, preferredProtocols, &mCardHandle, &mProtocol); - qCDebug(card_pcsc) << "SCardConnect for" << mReader->getName() << ':' << PcscUtils::toString(returnCode) << "| cardHandle:" << mCardHandle << "| protocol:" << protocolToString(mProtocol); - if (returnCode != PcscUtils::Scard_S_Success) + qCDebug(card_pcsc) << "SCardConnect for" << mReader->getName() << ':' << pcsc::toString(returnCode) << "| cardHandle:" << mCardHandle << "| protocol:" << protocolToString(mProtocol); + if (returnCode != pcsc::Scard_S_Success) { return CardReturnCode::COMMAND_FAILED; } returnCode = SCardBeginTransaction(mCardHandle); - qCDebug(card_pcsc) << "SCardBeginTransaction for" << mReader->getName() << ':' << PcscUtils::toString(returnCode); - if (returnCode != PcscUtils::Scard_S_Success) + qCDebug(card_pcsc) << "SCardBeginTransaction for" << mReader->getName() << ':' << pcsc::toString(returnCode); + if (returnCode != pcsc::Scard_S_Success) { SCardDisconnect(mCardHandle, SCARD_LEAVE_CARD); return CardReturnCode::COMMAND_FAILED; @@ -143,14 +143,14 @@ CardReturnCode PcscCard::releaseConnection() mTimer.stop(); PCSC_RETURNCODE returnCode = SCardEndTransaction(mCardHandle, SCARD_LEAVE_CARD); - qCDebug(card_pcsc) << "SCardEndTransaction for" << mReader->getName() << ':' << PcscUtils::toString(returnCode); + qCDebug(card_pcsc) << "SCardEndTransaction for" << mReader->getName() << ':' << pcsc::toString(returnCode); returnCode = SCardDisconnect(mCardHandle, SCARD_RESET_CARD); mCardHandle = 0; mProtocol = SCARD_PROTOCOL_UNDEFINED; - qCDebug(card_pcsc) << "SCardDisconnect for" << mReader->getName() << ':' << PcscUtils::toString(returnCode); + qCDebug(card_pcsc) << "SCardDisconnect for" << mReader->getName() << ':' << pcsc::toString(returnCode); - return returnCode == PcscUtils::Scard_S_Success ? CardReturnCode::OK : CardReturnCode::COMMAND_FAILED; + return returnCode == pcsc::Scard_S_Success ? CardReturnCode::OK : CardReturnCode::COMMAND_FAILED; } @@ -169,7 +169,7 @@ ResponseApduResult PcscCard::transmit(const CommandApdu& pCmd) } CardResult data = transmit(QByteArray(pCmd)); - if (data.mReturnCode != PcscUtils::Scard_S_Success) + if (data.mReturnCode != pcsc::Scard_S_Success) { return {CardReturnCode::COMMAND_FAILED}; } @@ -181,7 +181,7 @@ ResponseApduResult PcscCard::transmit(const CommandApdu& pCmd) qCDebug(card_pcsc) << "got SW1 == 0x6C, retransmitting with new Le:" << tempResponse.getSW2(); CommandApdu retransmitCommand(pCmd.getHeaderBytes(), pCmd.getData(), tempResponse.getSW2()); data = transmit(QByteArray(retransmitCommand)); - if (data.mReturnCode != PcscUtils::Scard_S_Success) + if (data.mReturnCode != pcsc::Scard_S_Success) { return {CardReturnCode::COMMAND_FAILED}; } @@ -192,7 +192,7 @@ ResponseApduResult PcscCard::transmit(const CommandApdu& pCmd) qCDebug(card_pcsc) << "got SW1 == 0x61, getting response with Le:" << tempResponse.getSW2(); CommandApdu getResponseCommand(Ins::GET_RESPONSE, 0, 0, QByteArray(), tempResponse.getSW2()); CardResult tmpData = transmit(QByteArray(getResponseCommand)); - if (data.mReturnCode != PcscUtils::Scard_S_Success) + if (data.mReturnCode != pcsc::Scard_S_Success) { return {CardReturnCode::COMMAND_FAILED}; } @@ -226,7 +226,7 @@ PcscCard::CardResult PcscCard::transmit(const QByteArray& pSendBuffer) default: qCDebug(card_pcsc) << "unsupported protocol"; - return {PcscUtils::Scard_E_Proto_Mismatch}; + return {pcsc::Scard_E_Proto_Mismatch}; } auto [returnCode, buffer] = transmit(pSendBuffer, sendPci); @@ -235,19 +235,19 @@ PcscCard::CardResult PcscCard::transmit(const QByteArray& pSendBuffer) * Reconnecting makes only sense, when no secure messaging channel is active. * Otherwise the secure messaging channel is destroyed and the transmit will fail anyway. */ - if (returnCode == PcscUtils::Scard_W_Reset_Card && !CommandApdu(pSendBuffer).isSecureMessaging()) + if (returnCode == pcsc::Scard_W_Reset_Card && !CommandApdu(pSendBuffer).isSecureMessaging()) { returnCode = SCardReconnect(mCardHandle, SCARD_SHARE_SHARED, mProtocol, SCARD_RESET_CARD, nullptr); qCDebug(card_pcsc) << "Reconnect to Card"; - if (returnCode == PcscUtils::Scard_S_Success) + if (returnCode == pcsc::Scard_S_Success) { returnCode = SCardBeginTransaction(mCardHandle); - qCDebug(card_pcsc) << "SCardBeginTransaction:" << PcscUtils::toString(returnCode); + qCDebug(card_pcsc) << "SCardBeginTransaction:" << pcsc::toString(returnCode); return transmit(pSendBuffer, sendPci); } - qCCritical(card_pcsc) << "SCardReconnect failed:" << PcscUtils::toString(returnCode); + qCCritical(card_pcsc) << "SCardReconnect failed:" << pcsc::toString(returnCode); } return {returnCode, buffer}; @@ -273,42 +273,42 @@ PcscCard::CardResult PcscCard::transmit(const QByteArray& pSendBuffer, reinterpret_cast(data.data()), &dataReceived); - qCDebug(card_pcsc) << "SCardTransmit for" << mReader->getName() << ':' << PcscUtils::toString(returnCode); + qCDebug(card_pcsc) << "SCardTransmit for" << mReader->getName() << ':' << pcsc::toString(returnCode); switch (returnCode) { - case PcscUtils::Scard_S_Success: + case pcsc::Scard_S_Success: data.resize(static_cast(dataReceived)); qCDebug(card_pcsc) << "SCardTransmit resBuffer:" << data.toHex(); if (data.size() < 2) { qCCritical(card_pcsc) << "Response buffer smaller than 2"; - return {PcscUtils::Scard_F_Unknown_Error}; + return {pcsc::Scard_F_Unknown_Error}; } return {returnCode, data}; - case PcscUtils::Scard_E_Insufficient_Buffer: + case pcsc::Scard_E_Insufficient_Buffer: qCCritical(card_pcsc) << "Max allowed receive buffer size of" << data.size() << "exceeded. Expected size is" << dataReceived; Q_ASSERT(false); return {returnCode}; - case PcscUtils::Scard_E_Invalid_Handle: - case PcscUtils::Scard_E_Invalid_Parameter: - case PcscUtils::Scard_E_Invalid_Value: - case PcscUtils::Scard_E_No_Service: - case PcscUtils::Scard_E_No_Smartcard: - case PcscUtils::Scard_E_Not_Transacted: - case PcscUtils::Scard_E_Proto_Mismatch: - case PcscUtils::Scard_E_Reader_Unavailable: - case PcscUtils::Scard_F_Comm_Error: - case PcscUtils::Scard_W_Reset_Card: - case PcscUtils::Scard_W_Removed_Card: + case pcsc::Scard_E_Invalid_Handle: + case pcsc::Scard_E_Invalid_Parameter: + case pcsc::Scard_E_Invalid_Value: + case pcsc::Scard_E_No_Service: + case pcsc::Scard_E_No_Smartcard: + case pcsc::Scard_E_Not_Transacted: + case pcsc::Scard_E_Proto_Mismatch: + case pcsc::Scard_E_Reader_Unavailable: + case pcsc::Scard_F_Comm_Error: + case pcsc::Scard_W_Reset_Card: + case pcsc::Scard_W_Removed_Card: return {returnCode}; default: - qCCritical(card_pcsc) << "Unexpected returnCode:" << PcscUtils::toString(returnCode); + qCCritical(card_pcsc) << "Unexpected returnCode:" << pcsc::toString(returnCode); Q_ASSERT(false); return {returnCode}; } @@ -333,7 +333,7 @@ EstablishPaceChannelOutput PcscCard::establishPaceChannel(PacePasswordId pPasswo EstablishPaceChannel builder(pPasswordId, pChat, pCertificateDescription); auto [returnCode, controlRes] = control(cmdID, builder.createCommandData()); - if (returnCode != PcscUtils::Scard_S_Success) + if (returnCode != pcsc::Scard_S_Success) { qCWarning(card_pcsc) << "Control to establish PACE channel failed"; return EstablishPaceChannelOutput(CardReturnCode::COMMAND_FAILED); @@ -358,7 +358,7 @@ CardReturnCode PcscCard::destroyPaceChannel() DestroyPaceChannelBuilder builder; auto [returnCode, controlRes] = control(cmdID, builder.createCommandData()); - if (returnCode != PcscUtils::Scard_S_Success) + if (returnCode != pcsc::Scard_S_Success) { qCWarning(card_pcsc) << "Control to destroy PACE channel failed"; return CardReturnCode::COMMAND_FAILED; @@ -380,7 +380,7 @@ PcscCard::CardResult PcscCard::control(PCSC_INT pCntrCode, const QByteArray& pCn static_cast(buffer.size()), &len); - if (returnCode != PcscUtils::Scard_S_Success) + if (returnCode != pcsc::Scard_S_Success) { len = 0; } @@ -389,11 +389,11 @@ PcscCard::CardResult PcscCard::control(PCSC_INT pCntrCode, const QByteArray& pCn { qCCritical(card_pcsc) << "Buffer size smaller than read length"; Q_ASSERT(buffer.size() >= static_cast(len)); - return {PcscUtils::Scard_F_Unknown_Error}; + return {pcsc::Scard_F_Unknown_Error}; } buffer.resize(static_cast(len)); - qCDebug(card_pcsc) << "SCardControl for" << mReader->getName() << ':' << PcscUtils::toString(returnCode) << buffer.toHex(); + qCDebug(card_pcsc) << "SCardControl for" << mReader->getName() << ':' << pcsc::toString(returnCode) << buffer.toHex(); return {returnCode, buffer}; } @@ -408,7 +408,7 @@ ResponseApduResult PcscCard::setEidPin(quint8 pTimeoutSeconds) PinModify pinModify(pTimeoutSeconds); auto [returnCode, controlRes] = control(cmdID, pinModify.createCcid()); - if (returnCode != PcscUtils::Scard_S_Success) + if (returnCode != pcsc::Scard_S_Success) { qCWarning(card_pcsc) << "Modify PIN failed"; return {CardReturnCode::COMMAND_FAILED}; diff --git a/src/card/pcsc/PcscReader.cpp b/src/card/pcsc/PcscReader.cpp index 1b218fba7..72485a177 100644 --- a/src/card/pcsc/PcscReader.cpp +++ b/src/card/pcsc/PcscReader.cpp @@ -39,15 +39,15 @@ PcscReader::PcscReader(const QString& pReaderName) PCSC_RETURNCODE PcscReader::init() { PCSC_RETURNCODE returnCode = SCardEstablishContext(SCARD_SCOPE_USER, nullptr, nullptr, &mContextHandle); - qCDebug(card_pcsc) << "SCardEstablishContext:" << PcscUtils::toString(returnCode); - if (returnCode != PcscUtils::Scard_S_Success) + qCDebug(card_pcsc) << "SCardEstablishContext:" << pcsc::toString(returnCode); + if (returnCode != pcsc::Scard_S_Success) { qCWarning(card_pcsc) << "Cannot establish context"; return returnCode; } returnCode = readReaderFeatures(); - if (returnCode != PcscUtils::Scard_S_Success) + if (returnCode != pcsc::Scard_S_Success) { qCWarning(card_pcsc) << "Features / Capabilities not successful:" << returnCode; return returnCode; @@ -57,7 +57,7 @@ PCSC_RETURNCODE PcscReader::init() PcscReader::updateCard(); setTimerId(startTimer(500)); - return PcscUtils::Scard_S_Success; + return pcsc::Scard_S_Success; } @@ -67,8 +67,8 @@ PcscReader::~PcscReader() if (mContextHandle != 0) { - qCDebug(card_pcsc) << "SCardCancel: " << PcscUtils::toString(SCardCancel(mContextHandle)); - qCDebug(card_pcsc) << "SCardReleaseContext:" << PcscUtils::toString(SCardReleaseContext(mContextHandle)); + qCDebug(card_pcsc) << "SCardCancel: " << pcsc::toString(SCardCancel(mContextHandle)); + qCDebug(card_pcsc) << "SCardReleaseContext:" << pcsc::toString(SCardReleaseContext(mContextHandle)); mContextHandle = 0; } @@ -157,13 +157,13 @@ static QString SCARD_STATE_toString(DWORD i) void PcscReader::updateCard() { PCSC_RETURNCODE returnCode = SCardGetStatusChange(mContextHandle, 0, &mReaderState, 1); - if (returnCode == PcscUtils::Scard_E_Timeout) + if (returnCode == pcsc::Scard_E_Timeout) { return; } - else if (returnCode == PcscUtils::Scard_E_Unknown_Reader) + else if (returnCode == pcsc::Scard_E_Unknown_Reader) { - qCWarning(card_pcsc) << "SCardGetStatusChange:" << PcscUtils::toString(returnCode); + qCWarning(card_pcsc) << "SCardGetStatusChange:" << pcsc::toString(returnCode); qCWarning(card_pcsc) << "Reader unknown, stop updating reader information"; if (getTimerId() != 0) { @@ -172,9 +172,9 @@ void PcscReader::updateCard() } return; } - else if (returnCode != PcscUtils::Scard_S_Success) + else if (returnCode != pcsc::Scard_S_Success) { - qCWarning(card_pcsc) << "SCardGetStatusChange:" << PcscUtils::toString(returnCode); + qCWarning(card_pcsc) << "SCardGetStatusChange:" << pcsc::toString(returnCode); qCWarning(card_pcsc) << "Cannot update reader"; return; } @@ -219,8 +219,7 @@ void PcscReader::updateCard() for (int tryCount = 0; tryCount < MAX_TRY_COUNT; ++tryCount) { mPcscCard.reset(new PcscCard(this)); - QSharedPointer cardConnection = createCardConnectionWorker(); - fetchCardInfo(cardConnection); + fetchCardInfo(); if (getReaderInfo().hasEid()) { @@ -279,21 +278,20 @@ PCSC_RETURNCODE PcscReader::readReaderFeatures() SCARDHANDLE cardHandle = 0; PCSC_INT protocol = 0; const auto& readerName = getReaderInfo().getName(); - QString str = - QStringLiteral("SCardConnect(%1, %2, %3, %4, %5, %6)").arg(mContextHandle, 0, 16).arg(readerName).arg(SCARD_SHARE_DIRECT) - .arg(PROTOCOL).arg(cardHandle, 0, 16).arg(protocol); - qCDebug(card_pcsc) << str; + qCDebug(card_pcsc) << QStringLiteral("SCardConnect(%1, %2, %3, %4, %5, %6)").arg(mContextHandle, 0, 16).arg(readerName).arg(SCARD_SHARE_DIRECT) + .arg(PROTOCOL).arg(cardHandle, 0, 16).arg(protocol); + PCSC_RETURNCODE returnCode = SCardConnect(mContextHandle, mReaderState.szReader, SCARD_SHARE_DIRECT, PROTOCOL, &cardHandle, &protocol); - qCDebug(card_pcsc) << "SCardConnect for" << readerName << ':' << PcscUtils::toString(returnCode); - if (returnCode != PcscUtils::Scard_S_Success) + qCDebug(card_pcsc) << "SCardConnect for" << readerName << ':' << pcsc::toString(returnCode); + if (returnCode != pcsc::Scard_S_Success) { return returnCode; } const auto guard = qScopeGuard([cardHandle, readerName] { PCSC_RETURNCODE disconnectCode = SCardDisconnect(cardHandle, SCARD_LEAVE_CARD); - qCDebug(card_pcsc) << "SCardDisconnect for" << readerName << ':' << PcscUtils::toString(disconnectCode); + qCDebug(card_pcsc) << "SCardDisconnect for" << readerName << ':' << pcsc::toString(disconnectCode); }); // control (get features) @@ -313,18 +311,18 @@ PCSC_RETURNCODE PcscReader::readReaderFeatures() &clen); buffer.resize(static_cast(clen)); - qCDebug(card_pcsc) << "SCardControl for" << readerName << ':' << PcscUtils::toString(returnCode); - if (returnCode != PcscUtils::Scard_S_Success) + qCDebug(card_pcsc) << "SCardControl for" << readerName << ':' << pcsc::toString(returnCode); + if (returnCode != pcsc::Scard_S_Success) { qCCritical(card_pcsc) << "Determining the reader features failed. Assuming this is a basic reader"; - return PcscUtils::Scard_S_Success; + return pcsc::Scard_S_Success; } qCDebug(card_pcsc) << "FEATURES:" << buffer.toHex(); mReaderFeatures = PcscReaderFeature(buffer); qCDebug(card_pcsc) << "FEATURES:" << mReaderFeatures; - return PcscUtils::Scard_S_Success; + return pcsc::Scard_S_Success; } diff --git a/src/card/pcsc/PcscReaderManagerPlugIn.cpp b/src/card/pcsc/PcscReaderManagerPlugIn.cpp index dd98e4289..69fb1a106 100644 --- a/src/card/pcsc/PcscReaderManagerPlugIn.cpp +++ b/src/card/pcsc/PcscReaderManagerPlugIn.cpp @@ -51,8 +51,8 @@ QList PcscReaderManagerPlugIn::getReaders() const void PcscReaderManagerPlugIn::startScan(bool pAutoConnect) { PCSC_RETURNCODE returnCode = SCardEstablishContext(SCARD_SCOPE_USER, nullptr, nullptr, &mContextHandle); - setPlugInEnabled(returnCode == PcscUtils::Scard_S_Success); - qCDebug(card_pcsc) << "SCardEstablishContext:" << PcscUtils::toString(returnCode); + setPlugInEnabled(returnCode == pcsc::Scard_S_Success); + qCDebug(card_pcsc) << "SCardEstablishContext:" << pcsc::toString(returnCode); if (!getInfo().isEnabled()) { qCWarning(card_pcsc) << "Not started: Cannot establish context"; @@ -71,9 +71,9 @@ void PcscReaderManagerPlugIn::stopScan(const QString& pError) if (mContextHandle) { PCSC_RETURNCODE returnCode = SCardReleaseContext(mContextHandle); - qCDebug(card_pcsc) << "SCardReleaseContext:" << PcscUtils::toString(returnCode); + qCDebug(card_pcsc) << "SCardReleaseContext:" << pcsc::toString(returnCode); mContextHandle = 0; - if (returnCode != PcscUtils::Scard_S_Success) + if (returnCode != pcsc::Scard_S_Success) { qCWarning(card_pcsc) << "Error releasing context"; } @@ -87,11 +87,11 @@ void PcscReaderManagerPlugIn::updateReaders() { QStringList readersToAdd; PCSC_RETURNCODE returnCode = readReaderNames(readersToAdd); - if (returnCode != PcscUtils::Scard_S_Success && returnCode != PcscUtils::Scard_E_No_Readers_Available) + if (returnCode != pcsc::Scard_S_Success && returnCode != pcsc::Scard_E_No_Readers_Available) { qCWarning(card_pcsc) << "Cannot update readers, returnCode:" << returnCode; - if (returnCode == PcscUtils::Scard_E_No_Service && mTimer.isActive()) + if (returnCode == pcsc::Scard_E_No_Service && mTimer.isActive()) { // Work around for an issue on Linux: Sometimes when unplugging a reader // the library seems to get confused and any further calls with existing @@ -101,7 +101,7 @@ void PcscReaderManagerPlugIn::updateReaders() stopScan(); startScan(true); } - else if (returnCode == PcscUtils::Scard_E_Service_Stopped && mTimer.isActive()) + else if (returnCode == pcsc::Scard_E_Service_Stopped && mTimer.isActive()) { // Work around for an issue on Windows 8.1: Sometimes when unplugging a reader // the library seems to get confused and any further calls with existing @@ -111,7 +111,7 @@ void PcscReaderManagerPlugIn::updateReaders() stopScan(); startScan(true); } - else if (returnCode == PcscUtils::Scard_E_Invalid_Handle && mTimer.isActive()) + else if (returnCode == pcsc::Scard_E_Invalid_Handle && mTimer.isActive()) { // If the pc/sc daemon terminates on Linux, the handle is invalidated. We try // to restart the manager in this case. @@ -122,7 +122,7 @@ void PcscReaderManagerPlugIn::updateReaders() } QStringList readersToRemove(mReaders.keys()); - for (QMutableListIterator it(readersToAdd); it.hasNext();) + for (QMutableListIterator it(readersToAdd); it.hasNext();) { QString readerName = it.next(); if (readersToRemove.contains(readerName)) @@ -154,7 +154,7 @@ void PcscReaderManagerPlugIn::addReaders(const QStringList& pReaderNames) for (const auto& readerName : pReaderNames) { auto pcscReader = std::make_unique(readerName); - if (pcscReader->init() != PcscUtils::Scard_S_Success) + if (pcscReader->init() != pcsc::Scard_S_Success) { qCDebug(card_pcsc) << "Initialization of" << readerName << "failed"; continue; @@ -198,21 +198,21 @@ void PcscReaderManagerPlugIn::removeReaders(const QStringList& pReaderNames) } -PCSC_RETURNCODE PcscReaderManagerPlugIn::readReaderNames(QStringList& pReaderNames) +PCSC_RETURNCODE PcscReaderManagerPlugIn::readReaderNames(QStringList& pReaderNames) const { if (mContextHandle == 0) { - return PcscUtils::Scard_E_Invalid_Handle; + return pcsc::Scard_E_Invalid_Handle; } QVarLengthArray readers; auto maxReadersSize = static_cast(readers.capacity()); PCSC_RETURNCODE returnCode = SCardListReaders(mContextHandle, nullptr, readers.data(), &maxReadersSize); - if (returnCode != PcscUtils::Scard_S_Success) + if (returnCode != pcsc::Scard_S_Success) { - if (returnCode != PcscUtils::Scard_E_No_Readers_Available) + if (returnCode != pcsc::Scard_E_No_Readers_Available) { - qCWarning(card_pcsc) << "SCardListReaders:" << PcscUtils::toString(returnCode); + qCWarning(card_pcsc) << "SCardListReaders:" << pcsc::toString(returnCode); qCWarning(card_pcsc) << "Cannot read reader names"; } return returnCode; diff --git a/src/card/pcsc/PcscReaderManagerPlugIn.h b/src/card/pcsc/PcscReaderManagerPlugIn.h index 6b4b79f1c..a36f844b5 100644 --- a/src/card/pcsc/PcscReaderManagerPlugIn.h +++ b/src/card/pcsc/PcscReaderManagerPlugIn.h @@ -37,7 +37,7 @@ class PcscReaderManagerPlugIn QMap mReaders; private: - PCSC_RETURNCODE readReaderNames(QStringList& pReaderNames); + PCSC_RETURNCODE readReaderNames(QStringList& pReaderNames) const; void updateReaders(); inline QString extractReaderName(const PCSC_CHAR_PTR pReaderPointer) const; void addReaders(const QStringList& pReaderNames); diff --git a/src/card/pcsc/PcscUtils.cpp b/src/card/pcsc/PcscUtils.cpp index ab06abe17..98d4b879c 100644 --- a/src/card/pcsc/PcscUtils.cpp +++ b/src/card/pcsc/PcscUtils.cpp @@ -7,7 +7,7 @@ using namespace governikus; -QString PcscUtils::toString(PCSC_RETURNCODE pCode) +QString pcsc::toString(PCSC_RETURNCODE pCode) { const auto& metaEnum = QMetaEnum::fromType(); const char* const name = metaEnum.valueToKey(static_cast(pCode)); @@ -18,3 +18,18 @@ QString PcscUtils::toString(PCSC_RETURNCODE pCode) return QString::fromLatin1(name); } + + +QDataStream& pcsc::operator<<(QDataStream& pStream, const PcscReturnCode& pCode) +{ + return pStream << static_cast(pCode); +} + + +QDataStream& pcsc::operator>>(QDataStream& pStream, PcscReturnCode& pCode) +{ + qint64 tmp; + pStream >> tmp; + pCode = static_cast(tmp); + return pStream; +} diff --git a/src/card/pcsc/PcscUtils.h b/src/card/pcsc/PcscUtils.h index 992156aca..68f279300 100644 --- a/src/card/pcsc/PcscUtils.h +++ b/src/card/pcsc/PcscUtils.h @@ -54,92 +54,89 @@ using PCSC_UCHAR_PTR = uchar*; #endif -namespace governikus +namespace governikus::pcsc { -class PcscUtils + +Q_NAMESPACE + +/** + * Error codes from http://msdn.microsoft.com/en-us/library/aa924526.aspx + */ +enum PcscReturnCode : PCSC_RETURNCODE { - Q_GADGET - - private: - PcscUtils() = delete; - ~PcscUtils() = delete; - - public: - /** - * Error codes from http://msdn.microsoft.com/en-us/library/aa924526.aspx - */ - enum PcscReturnCode : PCSC_RETURNCODE - { - Scard_S_Success = returnCode(SCARD_S_SUCCESS), /**< No error was encountered. */ - Scard_F_Internal_Error = returnCode(SCARD_F_INTERNAL_ERROR), /**< An internal consistency check failed. */ - Scard_E_Cancelled = returnCode(SCARD_E_CANCELLED), /**< The action was cancelled by an SCardCancel request. */ - Scard_E_Invalid_Handle = returnCode(SCARD_E_INVALID_HANDLE), /**< The supplied handle was invalid. */ - Scard_E_Invalid_Parameter = returnCode(SCARD_E_INVALID_PARAMETER), /**< One or more of the supplied parameters could not be properly interpreted. */ - Scard_E_Invalid_Target = returnCode(SCARD_E_INVALID_TARGET), /**< Registry startup information is missing or invalid. */ - Scard_E_No_Memory = returnCode(SCARD_E_NO_MEMORY), /**< Not enough memory available to complete this command. */ - Scard_F_Waited_Too_Long = returnCode(SCARD_F_WAITED_TOO_LONG), /**< An internal consistency timer has expired. */ - Scard_E_Insufficient_Buffer = returnCode(SCARD_E_INSUFFICIENT_BUFFER), /**< The data buffer to receive returned data is too small for the returned data. */ - Scard_E_Unknown_Reader = returnCode(SCARD_E_UNKNOWN_READER), /**< The specified reader name is not recognized. */ - Scard_E_Timeout = returnCode(SCARD_E_TIMEOUT), /**< The user-specified timeout value has expired. */ - Scard_E_Sharing_Violation = returnCode(SCARD_E_SHARING_VIOLATION), /**< The smart card cannot be accessed because of other connections outstanding. */ - Scard_E_No_Smartcard = returnCode(SCARD_E_NO_SMARTCARD), /**< The operation requires a Smart Card, but no Smart Card is currently in the device. */ - Scard_E_Unknown_Card = returnCode(SCARD_E_UNKNOWN_CARD), /**< The specified smart card name is not recognized. */ - Scard_E_Cant_Dispose = returnCode(SCARD_E_CANT_DISPOSE), /**< The system could not dispose of the media in the requested manner. */ - Scard_E_Proto_Mismatch = returnCode(SCARD_E_PROTO_MISMATCH), /**< The requested protocols are incompatible with the protocol currently in use with the smart card. */ - Scard_E_Not_Ready = returnCode(SCARD_E_NOT_READY), /**< The reader or smart card is not ready to accept commands. */ - Scard_E_Invalid_Value = returnCode(SCARD_E_INVALID_VALUE), /**< One or more of the supplied parameters values could not be properly interpreted. */ - Scard_E_System_Cancelled = returnCode(SCARD_E_SYSTEM_CANCELLED), /**< The action was cancelled by the system, presumably to log off or shut down. */ - Scard_F_Comm_Error = returnCode(SCARD_F_COMM_ERROR), /**< An internal communications error has been detected. */ - Scard_F_Unknown_Error = returnCode(SCARD_F_UNKNOWN_ERROR), /**< An internal error has been detected, but the source is unknown. */ - Scard_E_Invalid_Atr = returnCode(SCARD_E_INVALID_ATR), /**< An ATR obtained from the registry is not a valid ATR string. */ - Scard_E_Not_Transacted = returnCode(SCARD_E_NOT_TRANSACTED), /**< An attempt was made to end a non-existent transaction. */ - Scard_E_Reader_Unavailable = returnCode(SCARD_E_READER_UNAVAILABLE), /**< The specified reader is not currently available for use. */ - Scard_P_Shutdown = returnCode(SCARD_P_SHUTDOWN), /**< The operation has been aborted to allow the server application to exit. */ - Scard_E_Pci_Too_Small = returnCode(SCARD_E_PCI_TOO_SMALL), /**< The PCI Receive buffer was too small. */ - Scard_E_Reader_Unsupported = returnCode(SCARD_E_READER_UNSUPPORTED), /**< The reader driver does not meet minimal requirements for support. */ - Scard_E_Duplicate_Reader = returnCode(SCARD_E_DUPLICATE_READER), /**< The reader driver did not produce a unique reader name. */ - Scard_E_Card_Unsupported = returnCode(SCARD_E_CARD_UNSUPPORTED), /**< The smart card does not meet minimal requirements for support. */ - Scard_E_No_Service = returnCode(SCARD_E_NO_SERVICE), /**< The Smart card resource manager is not running. */ - Scard_E_Service_Stopped = returnCode(SCARD_E_SERVICE_STOPPED), /**< The Smart card resource manager has shut down. */ - Scard_E_Unsupported_Feature = returnCode(SCARD_E_UNSUPPORTED_FEATURE), /**< This smart card does not support the requested feature. */ - Scard_E_Unexpected = returnCode(SCARD_E_UNEXPECTED), /**< An unexpected card error has occurred. */ - Scard_E_Icc_Installation = returnCode(SCARD_E_ICC_INSTALLATION), /**< No primary provider can be found for the smart card. */ - Scard_E_Icc_Createorder = returnCode(SCARD_E_ICC_CREATEORDER), /**< The requested order of object creation is not supported. */ - - Scard_E_Dir_Not_Found = returnCode(SCARD_E_DIR_NOT_FOUND), /**< The identified directory does not exist in the smart card. */ - Scard_E_File_Not_Found = returnCode(SCARD_E_FILE_NOT_FOUND), /**< The identified file does not exist in the smart card. */ - Scard_E_No_Dir = returnCode(SCARD_E_NO_DIR), /**< The supplied path does not represent a smart card directory. */ - Scard_E_No_File = returnCode(SCARD_E_NO_FILE), /**< The supplied path does not represent a smart card file. */ - Scard_E_No_Access = returnCode(SCARD_E_NO_ACCESS), /**< Access is denied to this file. */ - Scard_E_Write_Too_Many = returnCode(SCARD_E_WRITE_TOO_MANY), /**< The smart card does not have enough memory to store the information. */ - Scard_E_Bad_Seek = returnCode(SCARD_E_BAD_SEEK), /**< There was an error trying to set the smart card file object pointer. */ - Scard_E_Invalid_Chv = returnCode(SCARD_E_INVALID_CHV), /**< The supplied PIN is incorrect. */ - Scard_E_Unknown_Res_Mng = returnCode(SCARD_E_UNKNOWN_RES_MNG), /**< An unrecognized error code was returned from a layered component. */ - Scard_E_No_Such_Certificate = returnCode(SCARD_E_NO_SUCH_CERTIFICATE), /**< The requested certificate does not exist. */ - Scard_E_Certificate_Unavailable = returnCode(SCARD_E_CERTIFICATE_UNAVAILABLE), /**< The requested certificate could not be obtained. */ - Scard_E_No_Readers_Available = returnCode(SCARD_E_NO_READERS_AVAILABLE), /**< Cannot find a smart card reader. */ - Scard_E_Comm_Data_Lost = returnCode(SCARD_E_COMM_DATA_LOST), /**< A communications error with the smart card has been detected. Retry the operation. */ - Scard_E_No_Key_Container = returnCode(SCARD_E_NO_KEY_CONTAINER), /**< The requested key container does not exist on the smart card. */ - Scard_E_Server_Too_Busy = returnCode(SCARD_E_SERVER_TOO_BUSY), /**< The Smart Card Resource Manager is too busy to complete this operation. */ - - Scard_W_Unsupported_Card = returnCode(SCARD_W_UNSUPPORTED_CARD), /**< The reader cannot communicate with the card, due to ATR string configuration conflicts. */ - Scard_W_Unresponsive_Card = returnCode(SCARD_W_UNRESPONSIVE_CARD), /**< The smart card is not responding to a reset. */ - Scard_W_Unpowered_Card = returnCode(SCARD_W_UNPOWERED_CARD), /**< Power has been removed from the smart card, so that further communication is not possible. */ - Scard_W_Reset_Card = returnCode(SCARD_W_RESET_CARD), /**< The smart card has been reset, so any shared state information is invalid. */ - Scard_W_Removed_Card = returnCode(SCARD_W_REMOVED_CARD), /**< The smart card has been removed, so further communication is not possible. */ - - Scard_W_Security_Violation = returnCode(SCARD_W_SECURITY_VIOLATION), /**< Access was denied because of a security violation. */ - Scard_W_Wrong_Chv = returnCode(SCARD_W_WRONG_CHV), /**< The card cannot be accessed because the wrong PIN was presented. */ - Scard_W_Chv_Blocked = returnCode(SCARD_W_CHV_BLOCKED), /**< The card cannot be accessed because the maximum number of PIN entry attempts has been reached. */ - Scard_W_Eof = returnCode(SCARD_W_EOF), /**< The end of the smart card file has been reached. */ - Scard_W_Cancelled_By_User = returnCode(SCARD_W_CANCELLED_BY_USER), /**< The user pressed "Cancel" on a Smart Card Selection Dialog. */ - Scard_W_Card_Not_Authenticated = returnCode(SCARD_W_CARD_NOT_AUTHENTICATED) /**< No PIN was presented to the smart card. */ - }; - Q_ENUM(PcscReturnCode) - - static QString toString(PCSC_RETURNCODE pCode); + Scard_S_Success = returnCode(SCARD_S_SUCCESS), /**< No error was encountered. */ + Scard_F_Internal_Error = returnCode(SCARD_F_INTERNAL_ERROR), /**< An internal consistency check failed. */ + Scard_E_Cancelled = returnCode(SCARD_E_CANCELLED), /**< The action was cancelled by an SCardCancel request. */ + Scard_E_Invalid_Handle = returnCode(SCARD_E_INVALID_HANDLE), /**< The supplied handle was invalid. */ + Scard_E_Invalid_Parameter = returnCode(SCARD_E_INVALID_PARAMETER), /**< One or more of the supplied parameters could not be properly interpreted. */ + Scard_E_Invalid_Target = returnCode(SCARD_E_INVALID_TARGET), /**< Registry startup information is missing or invalid. */ + Scard_E_No_Memory = returnCode(SCARD_E_NO_MEMORY), /**< Not enough memory available to complete this command. */ + Scard_F_Waited_Too_Long = returnCode(SCARD_F_WAITED_TOO_LONG), /**< An internal consistency timer has expired. */ + Scard_E_Insufficient_Buffer = returnCode(SCARD_E_INSUFFICIENT_BUFFER), /**< The data buffer to receive returned data is too small for the returned data. */ + Scard_E_Unknown_Reader = returnCode(SCARD_E_UNKNOWN_READER), /**< The specified reader name is not recognized. */ + Scard_E_Timeout = returnCode(SCARD_E_TIMEOUT), /**< The user-specified timeout value has expired. */ + Scard_E_Sharing_Violation = returnCode(SCARD_E_SHARING_VIOLATION), /**< The smart card cannot be accessed because of other connections outstanding. */ + Scard_E_No_Smartcard = returnCode(SCARD_E_NO_SMARTCARD), /**< The operation requires a Smart Card, but no Smart Card is currently in the device. */ + Scard_E_Unknown_Card = returnCode(SCARD_E_UNKNOWN_CARD), /**< The specified smart card name is not recognized. */ + Scard_E_Cant_Dispose = returnCode(SCARD_E_CANT_DISPOSE), /**< The system could not dispose of the media in the requested manner. */ + Scard_E_Proto_Mismatch = returnCode(SCARD_E_PROTO_MISMATCH), /**< The requested protocols are incompatible with the protocol currently in use with the smart card. */ + Scard_E_Not_Ready = returnCode(SCARD_E_NOT_READY), /**< The reader or smart card is not ready to accept commands. */ + Scard_E_Invalid_Value = returnCode(SCARD_E_INVALID_VALUE), /**< One or more of the supplied parameters values could not be properly interpreted. */ + Scard_E_System_Cancelled = returnCode(SCARD_E_SYSTEM_CANCELLED), /**< The action was cancelled by the system, presumably to log off or shut down. */ + Scard_F_Comm_Error = returnCode(SCARD_F_COMM_ERROR), /**< An internal communications error has been detected. */ + Scard_F_Unknown_Error = returnCode(SCARD_F_UNKNOWN_ERROR), /**< An internal error has been detected, but the source is unknown. */ + Scard_E_Invalid_Atr = returnCode(SCARD_E_INVALID_ATR), /**< An ATR obtained from the registry is not a valid ATR string. */ + Scard_E_Not_Transacted = returnCode(SCARD_E_NOT_TRANSACTED), /**< An attempt was made to end a non-existent transaction. */ + Scard_E_Reader_Unavailable = returnCode(SCARD_E_READER_UNAVAILABLE), /**< The specified reader is not currently available for use. */ + Scard_P_Shutdown = returnCode(SCARD_P_SHUTDOWN), /**< The operation has been aborted to allow the server application to exit. */ + Scard_E_Pci_Too_Small = returnCode(SCARD_E_PCI_TOO_SMALL), /**< The PCI Receive buffer was too small. */ + Scard_E_Reader_Unsupported = returnCode(SCARD_E_READER_UNSUPPORTED), /**< The reader driver does not meet minimal requirements for support. */ + Scard_E_Duplicate_Reader = returnCode(SCARD_E_DUPLICATE_READER), /**< The reader driver did not produce a unique reader name. */ + Scard_E_Card_Unsupported = returnCode(SCARD_E_CARD_UNSUPPORTED), /**< The smart card does not meet minimal requirements for support. */ + Scard_E_No_Service = returnCode(SCARD_E_NO_SERVICE), /**< The Smart card resource manager is not running. */ + Scard_E_Service_Stopped = returnCode(SCARD_E_SERVICE_STOPPED), /**< The Smart card resource manager has shut down. */ + Scard_E_Unsupported_Feature = returnCode(SCARD_E_UNSUPPORTED_FEATURE), /**< This smart card does not support the requested feature. */ + Scard_E_Unexpected = returnCode(SCARD_E_UNEXPECTED), /**< An unexpected card error has occurred. */ + Scard_E_Icc_Installation = returnCode(SCARD_E_ICC_INSTALLATION), /**< No primary provider can be found for the smart card. */ + Scard_E_Icc_Createorder = returnCode(SCARD_E_ICC_CREATEORDER), /**< The requested order of object creation is not supported. */ + + Scard_E_Dir_Not_Found = returnCode(SCARD_E_DIR_NOT_FOUND), /**< The identified directory does not exist in the smart card. */ + Scard_E_File_Not_Found = returnCode(SCARD_E_FILE_NOT_FOUND), /**< The identified file does not exist in the smart card. */ + Scard_E_No_Dir = returnCode(SCARD_E_NO_DIR), /**< The supplied path does not represent a smart card directory. */ + Scard_E_No_File = returnCode(SCARD_E_NO_FILE), /**< The supplied path does not represent a smart card file. */ + Scard_E_No_Access = returnCode(SCARD_E_NO_ACCESS), /**< Access is denied to this file. */ + Scard_E_Write_Too_Many = returnCode(SCARD_E_WRITE_TOO_MANY), /**< The smart card does not have enough memory to store the information. */ + Scard_E_Bad_Seek = returnCode(SCARD_E_BAD_SEEK), /**< There was an error trying to set the smart card file object pointer. */ + Scard_E_Invalid_Chv = returnCode(SCARD_E_INVALID_CHV), /**< The supplied PIN is incorrect. */ + Scard_E_Unknown_Res_Mng = returnCode(SCARD_E_UNKNOWN_RES_MNG), /**< An unrecognized error code was returned from a layered component. */ + Scard_E_No_Such_Certificate = returnCode(SCARD_E_NO_SUCH_CERTIFICATE), /**< The requested certificate does not exist. */ + Scard_E_Certificate_Unavailable = returnCode(SCARD_E_CERTIFICATE_UNAVAILABLE), /**< The requested certificate could not be obtained. */ + Scard_E_No_Readers_Available = returnCode(SCARD_E_NO_READERS_AVAILABLE), /**< Cannot find a smart card reader. */ + Scard_E_Comm_Data_Lost = returnCode(SCARD_E_COMM_DATA_LOST), /**< A communications error with the smart card has been detected. Retry the operation. */ + Scard_E_No_Key_Container = returnCode(SCARD_E_NO_KEY_CONTAINER), /**< The requested key container does not exist on the smart card. */ + Scard_E_Server_Too_Busy = returnCode(SCARD_E_SERVER_TOO_BUSY), /**< The Smart Card Resource Manager is too busy to complete this operation. */ + + Scard_W_Unsupported_Card = returnCode(SCARD_W_UNSUPPORTED_CARD), /**< The reader cannot communicate with the card, due to ATR string configuration conflicts. */ + Scard_W_Unresponsive_Card = returnCode(SCARD_W_UNRESPONSIVE_CARD), /**< The smart card is not responding to a reset. */ + Scard_W_Unpowered_Card = returnCode(SCARD_W_UNPOWERED_CARD), /**< Power has been removed from the smart card, so that further communication is not possible. */ + Scard_W_Reset_Card = returnCode(SCARD_W_RESET_CARD), /**< The smart card has been reset, so any shared state information is invalid. */ + Scard_W_Removed_Card = returnCode(SCARD_W_REMOVED_CARD), /**< The smart card has been removed, so further communication is not possible. */ + + Scard_W_Security_Violation = returnCode(SCARD_W_SECURITY_VIOLATION), /**< Access was denied because of a security violation. */ + Scard_W_Wrong_Chv = returnCode(SCARD_W_WRONG_CHV), /**< The card cannot be accessed because the wrong PIN was presented. */ + Scard_W_Chv_Blocked = returnCode(SCARD_W_CHV_BLOCKED), /**< The card cannot be accessed because the maximum number of PIN entry attempts has been reached. */ + Scard_W_Eof = returnCode(SCARD_W_EOF), /**< The end of the smart card file has been reached. */ + Scard_W_Cancelled_By_User = returnCode(SCARD_W_CANCELLED_BY_USER), /**< The user pressed "Cancel" on a Smart Card Selection Dialog. */ + Scard_W_Card_Not_Authenticated = returnCode(SCARD_W_CARD_NOT_AUTHENTICATED) /**< No PIN was presented to the smart card. */ }; +Q_ENUM_NS(PcscReturnCode) + +QString toString(PCSC_RETURNCODE pCode); + +QDataStream& operator<<(QDataStream& pStream, const PcscReturnCode& pCode); +QDataStream& operator>>(QDataStream& pStream, PcscReturnCode& pCode); +} // namespace governikus::pcsc /** @@ -213,5 +210,3 @@ class PcscUtils #undef SCARD_W_CANCELLED_BY_USER #undef SCARD_W_CARD_NOT_AUTHENTICATED #endif - -} // namespace governikus diff --git a/src/card/simulator/SimulatorCard.cpp b/src/card/simulator/SimulatorCard.cpp index 69b1abf5d..afddf9b01 100644 --- a/src/card/simulator/SimulatorCard.cpp +++ b/src/card/simulator/SimulatorCard.cpp @@ -7,6 +7,7 @@ #include "FileRef.h" #include "VolatileSettings.h" #include "apdu/CommandData.h" +#include "apdu/FileCommand.h" #include "apdu/GeneralAuthenticateResponse.h" #include "asn1/ASN1TemplateUtil.h" #include "asn1/ASN1Util.h" @@ -180,7 +181,7 @@ ResponseApduResult SimulatorCard::setEidPin(quint8 pTimeoutSeconds) ResponseApduResult SimulatorCard::executeFileCommand(const CommandApdu& pCmd) { const FileCommand fileCommand(pCmd); - const int offset = fileCommand.getOffset(); + const auto offset = fileCommand.getOffset(); const auto fileRef = fileCommand.getFileRef(); ResponseApduResult result = {CardReturnCode::OK, ResponseApdu(StatusCode::SUCCESS)}; @@ -306,7 +307,7 @@ QByteArray SimulatorCard::brainpoolP256r1Multiplication(const QByteArray& pPoint } QSharedPointer scalar = EcUtil::create(BN_new()); - if (!BN_bin2bn(reinterpret_cast(pScalar.data()), pScalar.size(), scalar.data())) + if (!BN_bin2bn(reinterpret_cast(pScalar.data()), static_cast(pScalar.size()), scalar.data())) { qCCritical(card) << "Interpreting the scalar failed"; } @@ -346,7 +347,7 @@ QByteArray SimulatorCard::generateAuthenticationToken(const QByteArray& pPublicK } -QByteArray SimulatorCard::generateRestrictedId(const QByteArray& pPublicKey) +QByteArray SimulatorCard::generateRestrictedId(const QByteArray& pPublicKey) const { // const Oid oid(KnownOid::ID_RI_ECDH_SHA_256); @@ -359,7 +360,7 @@ QByteArray SimulatorCard::generateRestrictedId(const QByteArray& pPublicKey) StatusCode SimulatorCard::verifyAuxiliaryData(const QByteArray& pCommandData) { const auto* unsignedCharPointer = reinterpret_cast(pCommandData.constData()); - ASN1_OBJECT* obj = d2i_ASN1_OBJECT(nullptr, &unsignedCharPointer, pCommandData.size()); + ASN1_OBJECT* obj = d2i_ASN1_OBJECT(nullptr, &unsignedCharPointer, static_cast(pCommandData.size())); const auto guard = qScopeGuard([obj] {ASN1_OBJECT_free(obj);}); return mFileSystem.verify(Oid(obj), mAuxiliaryData); } diff --git a/src/card/simulator/SimulatorCard.h b/src/card/simulator/SimulatorCard.h index 8d4c87bb8..d1afd0d40 100644 --- a/src/card/simulator/SimulatorCard.h +++ b/src/card/simulator/SimulatorCard.h @@ -10,7 +10,6 @@ #include "Card.h" #include "SimulatorFileSystem.h" -#include "apdu/FileCommand.h" #include "asn1/AuthenticatedAuxiliaryData.h" #include "pace/SecureMessaging.h" @@ -55,7 +54,7 @@ class SimulatorCard ResponseApduResult executeGeneralAuthenticate(const CommandApdu& pCmd); QByteArray brainpoolP256r1Multiplication(const QByteArray& pPoint, const QByteArray& pScalar) const; QByteArray generateAuthenticationToken(const QByteArray& pPublicKey, const QByteArray& pNonce); - QByteArray generateRestrictedId(const QByteArray& pPublicKey); + QByteArray generateRestrictedId(const QByteArray& pPublicKey) const; StatusCode verifyAuxiliaryData(const QByteArray& pCommandData); }; diff --git a/src/card/simulator/SimulatorFileSystem.cpp b/src/card/simulator/SimulatorFileSystem.cpp index 1846b0ae0..2c95e7526 100644 --- a/src/card/simulator/SimulatorFileSystem.cpp +++ b/src/card/simulator/SimulatorFileSystem.cpp @@ -5,7 +5,6 @@ #include "SimulatorFileSystem.h" #include "FileRef.h" -#include "JsonValueRef.h" #include "apdu/CommandApdu.h" #include "apdu/ResponseApdu.h" #include "asn1/ASN1TemplateUtil.h" @@ -154,7 +153,7 @@ SimulatorFileSystem::SimulatorFileSystem(const QJsonObject& pData) initMandatoryData(); const auto& files = pData[QLatin1String("files")].toArray(); - for (JsonValueRef value : files) + for (const QJsonValueConstRef value : files) { if (!value.isObject()) { @@ -178,7 +177,7 @@ SimulatorFileSystem::SimulatorFileSystem(const QJsonObject& pData) } const auto& keys = pData[QLatin1String("keys")].toArray(); - for (JsonValueRef value : keys) + for (const QJsonValueConstRef value : keys) { if (!value.isObject()) { @@ -222,7 +221,7 @@ StatusCode SimulatorFileSystem::select(const QByteArray& pFileId) } -QByteArray SimulatorFileSystem::read(int pOffset, int pLength, bool pExtendedLen) +QByteArray SimulatorFileSystem::read(qsizetype pOffset, int pLength, bool pExtendedLen) const { if (pLength <= CommandApdu::NO_LE || pLength > CommandApdu::EXTENDED_MAX_LE) { @@ -256,7 +255,7 @@ QByteArray SimulatorFileSystem::read(int pOffset, int pLength, bool pExtendedLen } -StatusCode SimulatorFileSystem::write(int pOffset, const QByteArray& pData) +StatusCode SimulatorFileSystem::write(qsizetype pOffset, const QByteArray& pData) { if (!mFiles.contains(mSelectedFile)) { @@ -285,7 +284,7 @@ QByteArray SimulatorFileSystem::getPrivateKey(int pKeyId) const } -StatusCode SimulatorFileSystem::verify(const Oid& pOid, const QSharedPointer& pAuxiliaryData) +StatusCode SimulatorFileSystem::verify(const Oid& pOid, const QSharedPointer& pAuxiliaryData) const { if (!pAuxiliaryData) { diff --git a/src/card/simulator/SimulatorFileSystem.h b/src/card/simulator/SimulatorFileSystem.h index ef627ff99..48cc8f967 100644 --- a/src/card/simulator/SimulatorFileSystem.h +++ b/src/card/simulator/SimulatorFileSystem.h @@ -36,13 +36,13 @@ class SimulatorFileSystem explicit SimulatorFileSystem(const QJsonObject& pData); [[nodiscard]] StatusCode select(const QByteArray& pFileId); - [[nodiscard]] QByteArray read(int pOffset, int pLength, bool pExtendedLen); - [[nodiscard]] StatusCode write(int pOffset, const QByteArray& pData); + [[nodiscard]] QByteArray read(qsizetype pOffset, int pLength, bool pExtendedLen) const; + [[nodiscard]] StatusCode write(qsizetype pOffset, const QByteArray& pData); [[nodiscard]] QByteArray getEfCardAccess() const; [[nodiscard]] QByteArray getPrivateKey(int pKeyId) const; - [[nodiscard]] StatusCode verify(const Oid& pOid, const QSharedPointer& pAuxiliaryData); + [[nodiscard]] StatusCode verify(const Oid& pOid, const QSharedPointer& pAuxiliaryData) const; private: void createFile(const QByteArray& pFileId, const QByteArray& pShortFileId, const QByteArray& pContent); diff --git a/src/card/simulator/SimulatorReader.cpp b/src/card/simulator/SimulatorReader.cpp index 3d4889f7f..95fc8a343 100644 --- a/src/card/simulator/SimulatorReader.cpp +++ b/src/card/simulator/SimulatorReader.cpp @@ -35,8 +35,7 @@ void SimulatorReader::insertCard(const QVariant& pData) const auto& filesystem = data.isEmpty() ? SimulatorFileSystem() : SimulatorFileSystem(data); mCard.reset(new SimulatorCard(filesystem)); - QSharedPointer cardConnection = createCardConnectionWorker(); - fetchCardInfo(cardConnection); + fetchCardInfo(); Q_EMIT fireCardInserted(getReaderInfo()); } diff --git a/src/card/simulator/SimulatorReaderManagerPlugIn.cpp b/src/card/simulator/SimulatorReaderManagerPlugIn.cpp index 38f0cc2ee..dfaf3eb79 100644 --- a/src/card/simulator/SimulatorReaderManagerPlugIn.cpp +++ b/src/card/simulator/SimulatorReaderManagerPlugIn.cpp @@ -23,6 +23,7 @@ SimulatorReaderManagerPlugIn::SimulatorReaderManagerPlugIn() void SimulatorReaderManagerPlugIn::init() { ReaderManagerPlugIn::init(); + onSettingsChanged(); } @@ -73,7 +74,7 @@ void SimulatorReaderManagerPlugIn::insert(const QString& pReaderName, const QVar { Q_UNUSED(pReaderName) - if (!isScanRunning()) + if (!getInfo().isScanRunning()) { return; } diff --git a/src/card/smart/SmartManager.cpp b/src/card/smart/SmartManager.cpp index 62edfb1ab..4a077bd66 100644 --- a/src/card/smart/SmartManager.cpp +++ b/src/card/smart/SmartManager.cpp @@ -6,8 +6,11 @@ #include "AppSettings.h" #include "ReaderManager.h" -#include "SecureStorage.h" +#include "VolatileSettings.h" #include "command/TransmitCommand.h" +#ifdef Q_OS_ANDROID + #include "SecureStorage.h" +#endif #include #include @@ -16,7 +19,6 @@ #include #include #endif - #include @@ -89,8 +91,10 @@ SmartManager::SmartManager() const auto& storage = Env::getSingleton(); const auto [result, msg] = initializeService(env.jniEnv(), context.object(), storage->getSmartServiceId().toStdString(), - storage->getSmartVersionTag().toStdString(), storage->getSmartSsdAid().toStdString()); +#else + const auto [result, msg] = initializeService(); +#endif if (result != EidServiceResult::SUCCESS) { @@ -98,8 +102,6 @@ SmartManager::SmartManager() return; } -#endif - mInitialized = true; qCDebug(card_smart) << "SmartManager created"; } @@ -119,23 +121,48 @@ bool SmartManager::isValid() const SmartManager::~SmartManager() { -#ifdef Q_OS_ANDROID const auto [result, msg] = shutdownService(); if (result != EidServiceResult::SUCCESS) { qCDebug(card_smart) << "Failed to shutdown the service:" << QString::fromStdString(msg); } -#endif qCDebug(card_smart) << "SmartManager destroyed"; } +bool SmartManager::smartAvailable() const +{ + if (!isValid()) + { + return false; + } + + const auto& eidStatus = status(); + if (eidStatus != EidStatus::INTERNAL_ERROR && eidStatus != EidStatus::NO_PROVISIONING) + { + return true; + } + + const auto& settings = Env::getSingleton()->getGeneralSettings(); + if (!Env::getSingleton()->isUsedAsSDK() && settings.doSmartUpdate()) + { + const auto& [result, status] = updateSupportInfo(); + if (result != EidServiceResult::SUCCESS || status == EidSupportStatus::INTERNAL_ERROR) + { + qCDebug(card_smart) << "updateSupportInfo() failed - Cache could not be initialized"; + } + } + + return settings.isSmartAvailable(); +} + + EidStatus SmartManager::status() const { if (!isValid()) { - return EidStatus::UNAVAILABLE; + return EidStatus::INTERNAL_ERROR; } const auto& status = getSmartEidStatus(); @@ -144,29 +171,68 @@ EidStatus SmartManager::status() const } -EidUpdateInfo SmartManager::updateInfo() +EidSupportStatusResult SmartManager::updateSupportInfo() const +{ + if (!isValid()) + { + return {EidServiceResult::ERROR, EidSupportStatus::UNAVAILABLE}; + } + + const auto supportInfo = getSmartEidSupportInfo(); + qCDebug(card_smart) << "getSmartEidSupportInfo() finished with result" << supportInfo.mResult << "and status" << supportInfo.mStatus; + + if (supportInfo.mResult == EidServiceResult::SUCCESS) + { + auto& settings = Env::getSingleton()->getGeneralSettings(); + switch (supportInfo.mStatus) + { + case EidSupportStatus::AVAILABLE: + case EidSupportStatus::UP_TO_DATE: + case EidSupportStatus::UPDATE_AVAILABLE: + settings.setSmartAvailable(true); + break; + + case EidSupportStatus::UNAVAILABLE: + settings.setSmartAvailable(false); + break; + + case EidSupportStatus::INTERNAL_ERROR: + qCWarning(card_smart) << "Internal error of getSmartEidSupportInfo() - Cache update skipped"; + break; + } + } + else + { + qCWarning(card_smart) << "getSmartEidSupportInfo() was not successful - Cache update skipped"; + } + + return supportInfo; +} + + +ServiceInformationResult SmartManager::serviceInformation() const { if (!isValid()) { - return EidUpdateInfo::UNAVAILABLE; + return {EidServiceResult::UNDEFINED}; } - const auto& updateInfo = getUpdateInfo(); - qCDebug(card_smart) << "getUpdateInfo() finished with" << updateInfo; - return updateInfo; + const auto& serviceInformation = getServiceInformation(); + qCDebug(card_smart) << "getServiceInformation() finished with" << serviceInformation; + return serviceInformation; } -bool SmartManager::deleteSmart(const ProgressHandler& pHandler) const +EidServiceResult SmartManager::deleteSmart(const ProgressHandler& pHandler) const { if (!isValid()) { - return false; + return EidServiceResult::ERROR; } const auto& deleteResult = deleteSmartEid(pHandler); qCDebug(card_smart) << "deleteSmartEid() finished with" << deleteResult; - return deleteResult == EidServiceResult::SUCCESS; + return deleteResult; } @@ -183,16 +249,16 @@ bool SmartManager::deletePersonalization() const } -bool SmartManager::installSmart(const ProgressHandler& pHandler) const +EidServiceResult SmartManager::installSmart(const ProgressHandler& pHandler) const { if (!isValid()) { - return false; + return EidServiceResult::ERROR; } const auto& installResult = installSmartEid(pHandler); qCDebug(card_smart) << "installSmartEid() finished with" << installResult; - return installResult == EidServiceResult::SUCCESS; + return installResult; } @@ -239,20 +305,14 @@ QByteArrayList SmartManager::performPersonalization(const QVector } -PersonalizationResult SmartManager::finalizePersonalization() const +PersonalizationResult SmartManager::finalizePersonalization(int pStatus) const { if (!isValid()) { return PersonalizationResult(); } -#ifdef Q_OS_ANDROID - return ::finalizePersonalization(); - -#else - return {EidServiceResult::SUCCESS}; - -#endif + return ::finalizePersonalization(pStatus); } @@ -263,7 +323,6 @@ EstablishPaceChannelOutput SmartManager::prepareIdentification(const QByteArray& return EstablishPaceChannelOutput(CardReturnCode::COMMAND_FAILED); } -#ifdef Q_OS_IOS const auto& result = ::prepareIdentification(pChat.toHex().toStdString()); EstablishPaceChannelOutput establishPaceChannelOutput; @@ -273,12 +332,6 @@ EstablishPaceChannelOutput SmartManager::prepareIdentification(const QByteArray& establishPaceChannelOutput.setIdIcc(fromHex(result.mIdIcc)); return establishPaceChannelOutput; - -#else - Q_UNUSED(pChat) - return EstablishPaceChannelOutput(CardReturnCode::COMMAND_FAILED); - -#endif } @@ -289,7 +342,6 @@ ResponseApduResult SmartManager::challenge() const return {CardReturnCode::COMMAND_FAILED}; } -#ifdef Q_OS_IOS const auto& result = getChallenge(); ResponseApduResult responseApduResult; @@ -297,11 +349,6 @@ ResponseApduResult SmartManager::challenge() const responseApduResult.mResponseApdu = ResponseApdu(fromHex(result.mData)); return responseApduResult; - -#else - return {CardReturnCode::COMMAND_FAILED}; - -#endif } @@ -312,7 +359,6 @@ TerminalAndChipAuthenticationResult SmartManager::performTAandCA(const CVCertifi return {CardReturnCode::COMMAND_FAILED}; } -#ifdef Q_OS_IOS std::list terminalCvcChain; for (const auto& certificate : pTerminalCvcChain) { @@ -333,16 +379,6 @@ TerminalAndChipAuthenticationResult SmartManager::performTAandCA(const CVCertifi tAandCAResult.mNonce = fromHex(result.mNonce); return tAandCAResult; - -#else - Q_UNUSED(pTerminalCvcChain) - Q_UNUSED(pAuxiliaryData) - Q_UNUSED(pSignature) - Q_UNUSED(pPin) - Q_UNUSED(pEphemeralPublicKey) - return {CardReturnCode::COMMAND_FAILED}; - -#endif } @@ -397,95 +433,160 @@ void SmartManager::abortSDKWorkflow() const QDebug operator<<(QDebug pDbg, const EidStatus& pStatus) { - const auto& toString = [](const EidStatus& status){ - switch (status) - { - case EidStatus::UNAVAILABLE: - return QLatin1String("UNAVAILABLE"); - - case EidStatus::NO_PROVISIONING: - return QLatin1String("NO_PROVISIONING"); + QLatin1String status; + switch (pStatus) + { + case EidStatus::NO_PROVISIONING: + status = QLatin1String("NO_PROVISIONING"); + break; - case EidStatus::NO_PERSONALIZATION: - return QLatin1String("NO_PERSONALIZATION"); + case EidStatus::NO_PERSONALIZATION: + status = QLatin1String("NO_PERSONALIZATION"); + break; - case EidStatus::APPLET_UNUSABLE: - return QLatin1String("APPLET_UNUSABLE"); + case EidStatus::UNUSABLE: + status = QLatin1String("UNUSABLE"); + break; - case EidStatus::PERSONALIZED: - return QLatin1String("PERSONALIZED"); + case EidStatus::PERSONALIZED: + status = QLatin1String("PERSONALIZED"); + break; - case EidStatus::INTERNAL_ERROR: - return QLatin1String("INTERNAL_ERROR"); - } + case EidStatus::INTERNAL_ERROR: + status = QLatin1String("INTERNAL_ERROR"); + break; - Q_UNREACHABLE(); - }; + case EidStatus::CERT_EXPIRED: + status = QLatin1String("CERT_EXPIRED"); + break; + } QDebugStateSaver saver(pDbg); - pDbg.nospace() << toString(pStatus) << " 0x" << Qt::hex << static_cast(pStatus); + pDbg.nospace() << status << " 0x" << Qt::hex << static_cast(pStatus); return pDbg; } -QDebug operator<<(QDebug pDbg, const EidUpdateInfo& pInfo) +QDebug operator<<(QDebug pDbg, const EidSupportStatus& pInfo) { - const auto& toString = [](const EidUpdateInfo& info){ - switch (info) - { - case EidUpdateInfo::UNAVAILABLE: - return QLatin1String("UNAVAILABLE"); - - case EidUpdateInfo::NO_PROVISIONING: - return QLatin1String("NO_PROVISIONING"); + QLatin1String info; + switch (pInfo) + { + case EidSupportStatus::UNAVAILABLE: + info = QLatin1String("UNAVAILABLE"); + break; - case EidUpdateInfo::UPDATE_AVAILABLE: - return QLatin1String("UPDATE_AVAILABLE"); + case EidSupportStatus::UPDATE_AVAILABLE: + info = QLatin1String("UPDATE_AVAILABLE"); + break; - case EidUpdateInfo::UP_TO_DATE: - return QLatin1String("UP_TO_DATE"); + case EidSupportStatus::UP_TO_DATE: + info = QLatin1String("UP_TO_DATE"); + break; - case EidUpdateInfo::INTERNAL_ERROR: - return QLatin1String("INTERNAL_ERROR"); - } + case EidSupportStatus::INTERNAL_ERROR: + info = QLatin1String("INTERNAL_ERROR"); + break; - Q_UNREACHABLE(); - }; + case EidSupportStatus::AVAILABLE: + info = QLatin1String("AVAILABLE"); + break; + } QDebugStateSaver saver(pDbg); - pDbg.nospace() << toString(pInfo) << " 0x" << Qt::hex << static_cast(pInfo); + pDbg.nospace() << info << " 0x" << Qt::hex << static_cast(pInfo); return pDbg; } QDebug operator<<(QDebug pDbg, const EidServiceResult& pResult) { - const auto& toString = [](const EidServiceResult& result){ - switch (result) - { - case EidServiceResult::SUCCESS: - return QLatin1String("SUCCESS"); + QLatin1String result; + switch (pResult) + { + case EidServiceResult::SUCCESS: + result = QLatin1String("SUCCESS"); + break; + + case EidServiceResult::UNDEFINED: + result = QLatin1String("UNDEFINED"); + break; + + case EidServiceResult::INFO: + result = QLatin1String("INFO"); + break; + + case EidServiceResult::WARN: + result = QLatin1String("WARN"); + break; + + case EidServiceResult::ERROR: + result = QLatin1String("ERROR"); + break; - case EidServiceResult::UNDEFINED: - return QLatin1String("UNDEFINED"); + case EidServiceResult::UNSUPPORTED: + result = QLatin1String("UNSUPPORTED"); + break; + + case EidServiceResult::OVERLOAD_PROTECTION: + result = QLatin1String("OVERLOAD_PROTECTION"); + break; + + case EidServiceResult::UNDER_MAINTENANCE: + result = QLatin1String("UNDER_MAINTENANCE"); + break; + + case EidServiceResult::NFC_NOT_ACTIVATED: + result = QLatin1String("NFC_NOT_ACTIVATED"); + break; + + case EidServiceResult::INTEGRITY_CHECK_FAILED: + result = QLatin1String("INTEGRITY_CHECK_FAILED"); + break; + + case EidServiceResult::NOT_AUTHENTICATED: + result = QLatin1String("NOT_AUTHENTICATED"); + break; + + case EidServiceResult::NETWORK_CONNECTION_ERROR: + result = QLatin1String("NETWORK_CONNECTION_ERROR"); + break; + } + + QDebugStateSaver saver(pDbg); + pDbg.nospace() << result << " 0x" << Qt::hex << static_cast(pResult); + return pDbg; +} - case EidServiceResult::INFO: - return QLatin1String("INFO"); - case EidServiceResult::WARN: - return QLatin1String("WARN"); +QDebug operator<<(QDebug pDbg, const SmartEidType& pType) +{ + QLatin1String type; + switch (pType) + { + case SmartEidType::UNKNOWN: + type = QLatin1String("UNKNOWN"); + break; - case EidServiceResult::ERROR: - return QLatin1String("ERROR"); + case SmartEidType::APPLET: + type = QLatin1String("APPLET"); + break; - case EidServiceResult::UNSUPPORTED: - return QLatin1String("UNSUPPORTED"); - } + case SmartEidType::NON_APPLET: + type = QLatin1String("NON_APPLET"); + break; + } - Q_UNREACHABLE(); - }; + QDebugStateSaver saver(pDbg); + pDbg.nospace() << type << " 0x" << Qt::hex << static_cast(pType); + return pDbg; +} + +QDebug operator<<(QDebug pDbg, const ServiceInformationResult& pResult) +{ QDebugStateSaver saver(pDbg); - pDbg.nospace() << toString(pResult) << " 0x" << Qt::hex << static_cast(pResult); + pDbg << "{" << pResult.mResult << "|" << pResult.mType << "|" << QString::fromStdString(pResult.mChallengeType) << "}"; + return pDbg; } diff --git a/src/card/smart/SmartManager.h b/src/card/smart/SmartManager.h index 0fecde10a..1a917e2a4 100644 --- a/src/card/smart/SmartManager.h +++ b/src/card/smart/SmartManager.h @@ -25,8 +25,11 @@ Q_DECLARE_METATYPE(EidStatus) -Q_DECLARE_METATYPE(EidUpdateInfo) +Q_DECLARE_METATYPE(EidSupportStatus) +Q_DECLARE_METATYPE(EidSupportStatusResult) Q_DECLARE_METATYPE(EidServiceResult) +Q_DECLARE_METATYPE(SmartEidType) +Q_DECLARE_METATYPE(ServiceInformationResult) Q_DECLARE_METATYPE(GenericDataResult) Q_DECLARE_METATYPE(InitializeResult) Q_DECLARE_METATYPE(PersonalizationResult) @@ -58,14 +61,16 @@ class SmartManager using ProgressHandler = std::function; ~SmartManager() override; + [[nodiscard]] bool smartAvailable() const; EidStatus status() const; - EidUpdateInfo updateInfo(); - bool deleteSmart(const ProgressHandler& pHandler = ProgressHandler()) const; + [[nodiscard]] EidSupportStatusResult updateSupportInfo() const; + ServiceInformationResult serviceInformation() const; + [[nodiscard]] EidServiceResult deleteSmart(const ProgressHandler& pHandler = ProgressHandler()) const; bool deletePersonalization() const; - bool installSmart(const ProgressHandler& pHandler = ProgressHandler()) const; + [[nodiscard]] EidServiceResult installSmart(const ProgressHandler& pHandler = ProgressHandler()) const; InitializeResult initializePersonalization(const QString& pChallenge, const QString& pPin) const; QByteArrayList performPersonalization(const QVector& pInputApdus) const; - [[nodiscard]] PersonalizationResult finalizePersonalization() const; + [[nodiscard]] PersonalizationResult finalizePersonalization(int pStatus) const; EstablishPaceChannelOutput prepareIdentification(const QByteArray& pChat) const; [[nodiscard]] ResponseApduResult challenge() const; [[nodiscard]] TerminalAndChipAuthenticationResult performTAandCA( @@ -82,5 +87,7 @@ class SmartManager } // namespace governikus QDebug operator<<(QDebug pDbg, const EidStatus& pStatus); -QDebug operator<<(QDebug pDbg, const EidUpdateInfo& pInfo); +QDebug operator<<(QDebug pDbg, const EidSupportStatus& pInfo); QDebug operator<<(QDebug pDbg, const EidServiceResult& pResult); +QDebug operator<<(QDebug pDbg, const SmartEidType& pType); +QDebug operator<<(QDebug pDbg, const ServiceInformationResult& pResult); diff --git a/src/card/smart/SmartReader.cpp b/src/card/smart/SmartReader.cpp index 6808550f2..663ffb504 100644 --- a/src/card/smart/SmartReader.cpp +++ b/src/card/smart/SmartReader.cpp @@ -15,8 +15,8 @@ using namespace governikus; Q_DECLARE_LOGGING_CATEGORY(card_smart) -SmartReader::SmartReader() - : ConnectableReader(ReaderManagerPlugInType::SMART, QStringLiteral("Smart")) +SmartReader::SmartReader(const QString& pName) + : ConnectableReader(ReaderManagerPlugInType::SMART, pName) , mCard() { } @@ -30,22 +30,17 @@ Card* SmartReader::getCard() const void SmartReader::connectReader() { - switch (const auto& status = SmartManager::get()->status()) + const auto& smartManager = SmartManager::get(); + if (const auto& status = smartManager->status(); status != EidStatus::PERSONALIZED) { - case EidStatus::PERSONALIZED: - { - qCDebug(card_smart) << "targetDetected, type: Smart"; - - mCard.reset(new SmartCard()); - QSharedPointer cardConnection = createCardConnectionWorker(); - fetchCardInfo(cardConnection); - shelveCard(); - break; - } - - default: - qCDebug(card_smart) << "Skipped to connect the reader because the Smart-eID is not personalized:" << status; + qCDebug(card_smart) << "Skipped to connect the reader because the Smart-eID is not personalized:" << status; + return; } + + qCDebug(card_smart) << "targetDetected, type: Smart"; + mCard.reset(new SmartCard()); + fetchCardInfo(); + shelveCard(); } diff --git a/src/card/smart/SmartReader.h b/src/card/smart/SmartReader.h index 7cfc42ff4..1966ebaee 100644 --- a/src/card/smart/SmartReader.h +++ b/src/card/smart/SmartReader.h @@ -28,7 +28,7 @@ class SmartReader QScopedPointer mCard; public: - SmartReader(); + explicit SmartReader(const QString& pName); [[nodiscard]] Card* getCard() const override; void connectReader() override; diff --git a/src/card/smart/SmartReaderManagerPlugIn.cpp b/src/card/smart/SmartReaderManagerPlugIn.cpp index 1d375a765..7799fddba 100644 --- a/src/card/smart/SmartReaderManagerPlugIn.cpp +++ b/src/card/smart/SmartReaderManagerPlugIn.cpp @@ -4,7 +4,7 @@ #include "SmartReaderManagerPlugIn.h" -#include "Env.h" +#include "AppSettings.h" #include "SmartManager.h" #include "VolatileSettings.h" @@ -17,32 +17,43 @@ using namespace governikus; Q_DECLARE_LOGGING_CATEGORY(card_smart) -bool SmartReaderManagerPlugIn::initializeSmart(const QSharedPointer& pSmartManager) const +static QString READER_NAME() { - const auto& smartAvailable = isSmartAvailable(pSmartManager); - if (Env::getSingleton()->isUsedAsSDK() || smartAvailable) + return QStringLiteral("Smart"); +} + + +void SmartReaderManagerPlugIn::publishReader(const ReaderInfo& pInfo) +{ + if (mReaderAdded) { - return smartAvailable; + Q_EMIT fireReaderPropertiesUpdated(pInfo); + return; } - qCDebug(card_smart) << "Updating Smart-eID info"; - pSmartManager->updateInfo(); - - return isSmartAvailable(pSmartManager); + Q_EMIT fireReaderAdded(pInfo); + mReaderAdded = true; } -bool SmartReaderManagerPlugIn::isSmartAvailable(const QSharedPointer& pSmartManager) const +void SmartReaderManagerPlugIn::onSmartAvailableChanged(bool pSmartAvailable) { - const auto& eidStatus = pSmartManager->status(); - return eidStatus != EidStatus::INTERNAL_ERROR && eidStatus != EidStatus::UNAVAILABLE; + if (pSmartAvailable) + { + init(); + return; + } + + shutdown(); } SmartReaderManagerPlugIn::SmartReaderManagerPlugIn() : ReaderManagerPlugIn(ReaderManagerPlugInType::SMART) + , mReaderAdded(false) , mSmartReader(nullptr) { + connect(&Env::getSingleton()->getGeneralSettings(), &GeneralSettings::fireSmartAvailableChanged, this, &SmartReaderManagerPlugIn::onSmartAvailableChanged); } @@ -59,11 +70,6 @@ QList SmartReaderManagerPlugIn::getReaders() const void SmartReaderManagerPlugIn::init() { - if (getInfo().isAvailable()) - { - return; - } - ReaderManagerPlugIn::init(); const auto& smartManager = SmartManager::get(); @@ -72,20 +78,26 @@ void SmartReaderManagerPlugIn::init() smartManager->abortSDKWorkflow(); } - if (!initializeSmart(smartManager)) + if (!smartManager->smartAvailable()) + { + qCWarning(card_smart) << "Smart-eID is not available"; + publishReader(ReaderInfo(READER_NAME())); + return; + } + + if (getInfo().isAvailable()) { - qCWarning(card_smart) << "Smart-eID was not initialized"; return; } setPlugInAvailable(true); - mSmartReader.reset(new SmartReader()); + mSmartReader.reset(new SmartReader(READER_NAME())); connect(mSmartReader.data(), &SmartReader::fireReaderPropertiesUpdated, this, &SmartReaderManagerPlugIn::fireReaderPropertiesUpdated); connect(mSmartReader.data(), &SmartReader::fireCardInfoChanged, this, &SmartReaderManagerPlugIn::fireCardInfoChanged); connect(mSmartReader.data(), &SmartReader::fireCardInserted, this, &SmartReaderManagerPlugIn::fireCardInserted); connect(mSmartReader.data(), &SmartReader::fireCardRemoved, this, &SmartReaderManagerPlugIn::fireCardRemoved); qCDebug(card_smart) << "Add reader" << mSmartReader->getName(); - Q_EMIT fireReaderAdded(mSmartReader->getReaderInfo()); + publishReader(mSmartReader->getReaderInfo()); } @@ -96,8 +108,9 @@ void SmartReaderManagerPlugIn::shutdown() return; } - setPlugInAvailable(false); mSmartReader.reset(); + Q_EMIT fireReaderPropertiesUpdated(ReaderInfo(READER_NAME())); + setPlugInAvailable(false); } @@ -109,7 +122,7 @@ void SmartReaderManagerPlugIn::insert(const QString& pReaderName, const QVariant return; } - if (!isScanRunning()) + if (!getInfo().isScanRunning()) { qCDebug(card_smart) << "Skipping insert because the scan is not running"; return; diff --git a/src/card/smart/SmartReaderManagerPlugIn.h b/src/card/smart/SmartReaderManagerPlugIn.h index 273a4d89c..450195fa2 100644 --- a/src/card/smart/SmartReaderManagerPlugIn.h +++ b/src/card/smart/SmartReaderManagerPlugIn.h @@ -25,9 +25,13 @@ class SmartReaderManagerPlugIn Q_INTERFACES(governikus::ReaderManagerPlugIn) private: + bool mReaderAdded; QScopedPointer mSmartReader; - bool initializeSmart(const QSharedPointer& pSmartManager) const; - bool isSmartAvailable(const QSharedPointer& pSmartManager) const; + + void publishReader(const ReaderInfo& pInfo); + + private Q_SLOTS: + void onSmartAvailableChanged(bool pSmartAvailable); public: SmartReaderManagerPlugIn(); diff --git a/src/configuration/ProviderConfiguration.h b/src/configuration/ProviderConfiguration.h index 227302ac2..195359c2c 100644 --- a/src/configuration/ProviderConfiguration.h +++ b/src/configuration/ProviderConfiguration.h @@ -18,8 +18,6 @@ #include #include -class test_HistoryModel; - namespace governikus { @@ -28,7 +26,6 @@ class ProviderConfiguration { Q_OBJECT friend class Env; - friend class ::test_HistoryModel; private: const QSharedPointer mUpdatableFile; diff --git a/src/configuration/ProviderConfigurationParser.cpp b/src/configuration/ProviderConfigurationParser.cpp index 647b20878..3c0a20b7c 100644 --- a/src/configuration/ProviderConfigurationParser.cpp +++ b/src/configuration/ProviderConfigurationParser.cpp @@ -4,7 +4,6 @@ #include "ProviderConfigurationParser.h" -#include "JsonValueRef.h" #include "LanguageString.h" #include @@ -36,7 +35,7 @@ QVector ProviderConfigurationParser::parseProvider(co const QJsonArray& array = doc[QLatin1String("provider")].toArray(); QVector providers; providers.reserve(array.size()); - for (JsonValueRef entry : array) + for (const QJsonValueConstRef entry : array) { const QJsonObject prov = entry.toObject(); @@ -79,11 +78,11 @@ QMap ProviderConfigurationParser::parseCallCosts(const QByteA QMap callCosts; const auto& callCostArray = doc[QLatin1String("callcosts")].toArray(); - for (JsonValueRef callCostElem : callCostArray) + for (const QJsonValueConstRef callCostElem : callCostArray) { const auto cost = CallCost(callCostElem); const auto& prefixArray = callCostElem.toObject()[QLatin1String("prefixes")].toArray(); - for (JsonValueRef prefixElem : prefixArray) + for (const QJsonValueConstRef prefixElem : prefixArray) { const auto& prefix = prefixElem.toString(); callCosts.insert(prefix, cost); diff --git a/src/configuration/ReaderConfiguration.cpp b/src/configuration/ReaderConfiguration.cpp index 01e44302d..63ccabfcc 100644 --- a/src/configuration/ReaderConfiguration.cpp +++ b/src/configuration/ReaderConfiguration.cpp @@ -111,7 +111,7 @@ ReaderConfigurationInfo ReaderConfiguration::getReaderConfigurationInfoById(cons { for (const auto& info : std::as_const(mReaderConfigurationInfos)) { - if (pId.getVendorId() == info.getVendorId() && pId.getProductId() == info.getProductId()) + if (pId.getVendorId() == info.getVendorId() && info.getProductIds().contains(pId.getProductId())) { return info; } diff --git a/src/configuration/ReaderConfiguration.h b/src/configuration/ReaderConfiguration.h index 274db1d85..bb7cdeee8 100644 --- a/src/configuration/ReaderConfiguration.h +++ b/src/configuration/ReaderConfiguration.h @@ -43,8 +43,8 @@ class ReaderConfiguration void onFileUpdated(); public: - static QString getNoReaderFoundIconPath(); - static QString getMultipleReaderIconPath(); + [[nodiscard]] static QString getNoReaderFoundIconPath(); + [[nodiscard]] static QString getMultipleReaderIconPath(); void update(); [[nodiscard]] const QVector& getReaderConfigurationInfos() const; diff --git a/src/configuration/ReaderConfigurationInfo.cpp b/src/configuration/ReaderConfigurationInfo.cpp index 51471f4f9..b049483b8 100644 --- a/src/configuration/ReaderConfigurationInfo.cpp +++ b/src/configuration/ReaderConfigurationInfo.cpp @@ -17,14 +17,14 @@ ReaderConfigurationInfo::ReaderConfigurationInfo() ReaderConfigurationInfo::ReaderConfigurationInfo(const QString& pReaderName) - : d(new InternalInfo(false, 0, 0, pReaderName, QString(), QString(), QStringLiteral("default_reader.png"), QStringLiteral("default_reader_mit_ausweis.png"))) + : d(new InternalInfo(false, 0, {}, pReaderName, QString(), QString(), QStringLiteral("default_reader.png"), QStringLiteral("default_reader_mit_ausweis.png"))) { } -ReaderConfigurationInfo::ReaderConfigurationInfo(uint pVendorId, uint pProductId, +ReaderConfigurationInfo::ReaderConfigurationInfo(uint pVendorId, const QSet& pProductIds, const QString& pName, const QString& pUrl, const QString& pPattern, const QString& pIcon, const QString& pIconWithNPA) - : d(new InternalInfo(true, pVendorId, pProductId, pName, pUrl, pPattern, pIcon, pIconWithNPA)) + : d(new InternalInfo(true, pVendorId, pProductIds, pName, pUrl, pPattern, pIcon, pIconWithNPA)) { } @@ -50,9 +50,9 @@ uint ReaderConfigurationInfo::getVendorId() const } -uint ReaderConfigurationInfo::getProductId() const +QSet ReaderConfigurationInfo::getProductIds() const { - return d->mProductId; + return d->mProductIds; } diff --git a/src/configuration/ReaderConfigurationInfo.h b/src/configuration/ReaderConfigurationInfo.h index 4887f016e..28de934cf 100644 --- a/src/configuration/ReaderConfigurationInfo.h +++ b/src/configuration/ReaderConfigurationInfo.h @@ -28,7 +28,7 @@ class ReaderConfigurationInfo public: const bool mKnown; const uint mVendorId; - const uint mProductId; + const QSet mProductIds; const QString mName; const QString mUrl; const QString mPattern; @@ -36,11 +36,11 @@ class ReaderConfigurationInfo const QString mIconWithNPA; - InternalInfo(bool pKnown, uint pVendorId, uint pProductId, const QString& pName, const QString& pUrl, + InternalInfo(bool pKnown, uint pVendorId, const QSet& pProductIds, const QString& pName, const QString& pUrl, const QString& pPattern, const QString& pIcon, const QString& pIconWithNPA) : mKnown(pKnown) , mVendorId(pVendorId) - , mProductId(pProductId) + , mProductIds(pProductIds) , mName(pName) , mUrl(pUrl) , mPattern(pPattern) @@ -54,7 +54,7 @@ class ReaderConfigurationInfo { return !(mKnown != pOther.mKnown || mVendorId != pOther.mVendorId || - mProductId != pOther.mProductId || + mProductIds != pOther.mProductIds || mName != pOther.mName || mUrl != pOther.mUrl || mPattern != pOther.mPattern || @@ -70,7 +70,7 @@ class ReaderConfigurationInfo public: ReaderConfigurationInfo(); explicit ReaderConfigurationInfo(const QString& pReaderName); - ReaderConfigurationInfo(uint pVendorId, uint pProductId, + ReaderConfigurationInfo(uint pVendorId, const QSet& pProductIds, const QString& pName, const QString& pUrl, const QString& pPattern, const QString& pIcon, const QString& pIconWithNPA); @@ -80,7 +80,7 @@ class ReaderConfigurationInfo [[nodiscard]] bool isKnownReader() const; [[nodiscard]] uint getVendorId() const; - [[nodiscard]] uint getProductId() const; + [[nodiscard]] QSet getProductIds() const; [[nodiscard]] const QString& getName() const; [[nodiscard]] const QString& getUrl() const; [[nodiscard]] const QString& getPattern() const; diff --git a/src/configuration/ReaderConfigurationParser.cpp b/src/configuration/ReaderConfigurationParser.cpp index e81f9be64..3eadf9e6d 100644 --- a/src/configuration/ReaderConfigurationParser.cpp +++ b/src/configuration/ReaderConfigurationParser.cpp @@ -4,8 +4,6 @@ #include "ReaderConfigurationParser.h" -#include "JsonValueRef.h" - #include #include #include @@ -36,7 +34,7 @@ QString ReaderConfigurationParser::EntryParser::getDriverUrl(const QJsonObject& } const QJsonArray& driversArray = driversValue.toArray(); - for (JsonValueRef entry : driversArray) + for (const QJsonValueConstRef entry : driversArray) { const QJsonObject& obj = entry.toObject(); if (obj.isEmpty()) @@ -100,7 +98,7 @@ bool ReaderConfigurationParser::EntryParser::matchPlatform(const QJsonArray& pPl return QOperatingSystemVersion(pCurrentVersion.type(), number.majorVersion(), minor, micro); }; - for (JsonValueRef entry : pPlatforms) + for (const QJsonValueConstRef entry : pPlatforms) { const auto& obj = entry.toObject(); if (obj.value(QLatin1String("os")).toString() == currentOS) @@ -119,6 +117,46 @@ bool ReaderConfigurationParser::EntryParser::matchPlatform(const QJsonArray& pPl } +QSet ReaderConfigurationParser::EntryParser::getProductIds(const QJsonObject& object, bool* parseOk) const +{ + static const auto productIdsKey = QLatin1String("ProductIds"); + if (object.contains(productIdsKey) && object[productIdsKey].isArray()) + { + QSet productIds; + const QJsonArray productIdsArray = object[productIdsKey].toArray(); + for (const QJsonValueConstRef value : productIdsArray) + { + if (!value.isString()) + { + *parseOk = false; + return {}; + } + const uint parsedUInt = value.toString().toUInt(parseOk, 16); + if (!*parseOk) + { + return {}; + } + productIds.insert(parsedUInt); + } + return productIds; + } + + static const auto productIdKey = QLatin1String("ProductId"); + if (object.contains(productIdKey) && object.value(productIdKey).isString()) + { + const uint parsedUInt = object.value(productIdKey).toString().toUInt(parseOk, 16); + if (!*parseOk) + { + return {}; + } + return {parsedUInt}; + } + + *parseOk = false; + return {}; +} + + ReaderConfigurationInfo ReaderConfigurationParser::EntryParser::parse() const { if (!mJsonValue.isObject()) @@ -135,10 +173,10 @@ ReaderConfigurationInfo ReaderConfigurationParser::EntryParser::parse() const return fail(QStringLiteral("Invalid or missing vendor id")); } - const uint productId = object.value(QLatin1String("ProductId")).toString().toUInt(&parseOk, 16); - if (!parseOk) + const QSet productIds = getProductIds(object, &parseOk); + if (!parseOk || productIds.isEmpty()) { - return fail(QStringLiteral("Invalid or missing product id")); + return fail(QStringLiteral("Invalid or missing product ids")); } const QString& name = object.value(QLatin1String("Name")).toString(); @@ -159,7 +197,7 @@ ReaderConfigurationInfo ReaderConfigurationParser::EntryParser::parse() const const QString& icon = object.value(QLatin1String("Icon")).toString(); const QString& iconWithNPA = object.value(QLatin1String("IconWithNPA")).toString(); - return ReaderConfigurationInfo(vendorId, productId, name, url, pattern, icon, iconWithNPA); + return ReaderConfigurationInfo(vendorId, productIds, name, url, pattern, icon, iconWithNPA); } @@ -200,7 +238,7 @@ QVector ReaderConfigurationParser::parse(const QByteArr const QJsonArray& devicesArray = devicesValue.toArray(); QVector infos; - for (JsonValueRef entry : devicesArray) + for (const QJsonValueConstRef entry : devicesArray) { auto info = EntryParser(entry).parse(); if (info.isKnownReader()) @@ -235,13 +273,13 @@ QVector ReaderConfigurationParser::fail(const QString& bool ReaderConfigurationParser::hasUniqueId(const ReaderConfigurationInfo& pInfo, const QVector& pInfos) { const uint vendorId = pInfo.getVendorId(); - const uint productId = pInfo.getProductId(); + const QSet productIds = pInfo.getProductIds(); const QString& name = pInfo.getName(); const QString& pattern = pInfo.getPattern(); for (const ReaderConfigurationInfo& info : pInfos) { - if (vendorId > 0 && productId > 0 && vendorId == info.getVendorId() && productId == info.getProductId()) + if (vendorId > 0 && !productIds.isEmpty() && vendorId == info.getVendorId() && productIds.intersects(info.getProductIds())) { return false; } diff --git a/src/configuration/ReaderConfigurationParser.h b/src/configuration/ReaderConfigurationParser.h index 9cb73b581..373df836c 100644 --- a/src/configuration/ReaderConfigurationParser.h +++ b/src/configuration/ReaderConfigurationParser.h @@ -8,7 +8,7 @@ #pragma once -#include "ReaderConfiguration.h" +#include "ReaderConfigurationInfo.h" #include #include @@ -35,6 +35,7 @@ class ReaderConfigurationParser [[nodiscard]] QString getDriverUrl(const QJsonObject& pObject) const; [[nodiscard]] bool matchPlatform(const QJsonArray& pPlatforms, const QOperatingSystemVersion& pCurrentVersion = QOperatingSystemVersion::current()) const; [[nodiscard]] ReaderConfigurationInfo fail(const QString& logMessage) const; + [[nodiscard]] QSet getProductIds(const QJsonObject& object, bool* parseOk) const; public: explicit EntryParser(const QJsonValue& pJsonValue); diff --git a/src/core/controller/AppController.cpp b/src/core/controller/AppController.cpp index aabb35b93..dac5b1329 100644 --- a/src/core/controller/AppController.cpp +++ b/src/core/controller/AppController.cpp @@ -15,7 +15,6 @@ #include "UILoader.h" #include "UIPlugIn.h" #include "VolatileSettings.h" -#include "controller/AuthController.h" #include "controller/ChangePinController.h" #include @@ -119,9 +118,9 @@ void AppController::start() }, Qt::QueuedConnection); }); - if (!Env::getSingleton()->isLoaded()) + if (!Env::getSingleton()->isValid()) { - qCCritical(init) << "SecureStorage not loaded"; + qCCritical(init) << "SecureStorage not valid"; return; } @@ -191,23 +190,7 @@ void AppController::onWorkflowFinished() qDebug() << controller->metaObject()->className() << "done"; disconnect(controller.data(), &WorkflowController::fireComplete, this, &AppController::onWorkflowFinished); - if (mActiveWorkflow->getContext()->getLastPaceResult() == CardReturnCode::NO_ACTIVE_PIN_SET) - { - switch (mActiveWorkflow->getAction()) - { - case Action::AUTH: - case Action::SELF: - case Action::PERSONALIZATION: - onWorkflowRequested(ChangePinController::createWorkflowRequest(true)); - break; - - case Action::PIN: - case Action::REMOTE_SERVICE: - break; - } - } - - Q_EMIT fireWorkflowFinished(mActiveWorkflow->getContext()); + Q_EMIT fireWorkflowFinished(mActiveWorkflow); qCInfo(support) << "Finish workflow" << mActiveWorkflow->getAction(); mActiveWorkflow.reset(); @@ -241,6 +224,7 @@ void AppController::onWorkflowRequested(const QSharedPointer& p { case WorkflowControl::UNHANDLED: qWarning() << "Cannot start or enqueue workflow:" << pRequest->getAction(); + Q_EMIT fireWorkflowUnhandled(pRequest); break; case WorkflowControl::SKIP: @@ -249,6 +233,7 @@ void AppController::onWorkflowRequested(const QSharedPointer& p { qDebug() << "Waiting workflow:" << mWaitingRequest->getAction(); } + Q_EMIT fireWorkflowUnhandled(pRequest); break; case WorkflowControl::ENQUEUE: @@ -342,10 +327,9 @@ void AppController::completeShutdown() qCDebug(init) << "Emit fire shutdown"; Q_EMIT fireShutdown(); - ResourceLoader::getInstance().shutdown(); - const auto& uiShutdown = [this] { const auto& exitApp = [this] { + ResourceLoader::getInstance().shutdown(); qCDebug(init) << "Quit event loop of QCoreApplication"; QCoreApplication::exit(mExitCode); }; @@ -438,6 +422,7 @@ void AppController::onUiPlugin(const UIPlugIn* pPlugin) connect(this, &AppController::fireShutdown, pPlugin, &UIPlugIn::doShutdown, Qt::QueuedConnection); connect(this, &AppController::fireWorkflowStarted, pPlugin, &UIPlugIn::onWorkflowStarted); connect(this, &AppController::fireWorkflowFinished, pPlugin, &UIPlugIn::onWorkflowFinished); + connect(this, &AppController::fireWorkflowUnhandled, pPlugin, &UIPlugIn::onWorkflowUnhandled); connect(this, &AppController::fireInitialized, pPlugin, &UIPlugIn::onApplicationInitialized); connect(this, &AppController::fireStarted, pPlugin, &UIPlugIn::onApplicationStarted); connect(this, &AppController::fireShowUi, pPlugin, &UIPlugIn::onShowUi); @@ -482,7 +467,7 @@ bool AppController::startNewWorkflow(const QSharedPointer& pReq controller->run(); //second: activate ui - Q_EMIT fireWorkflowStarted(mActiveWorkflow->getContext()); + Q_EMIT fireWorkflowStarted(mActiveWorkflow); if (!mActiveWorkflow->getContext()->wasClaimed()) { @@ -495,11 +480,7 @@ bool AppController::startNewWorkflow(const QSharedPointer& pReq } -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) bool AppController::nativeEventFilter(const QByteArray& pEventType, void* pMessage, qintptr* pResult) -#else -bool AppController::nativeEventFilter(const QByteArray& pEventType, void* pMessage, long* pResult) -#endif { Q_UNUSED(pResult) #if !defined(Q_OS_WIN) @@ -527,8 +508,9 @@ void AppController::clearCacheFolders() qDebug() << "Try to find and clear cache folder"; const QStringList cachePaths = QStandardPaths::standardLocations(QStandardPaths::CacheLocation); - for (const QString& cachePath : cachePaths) + for (QString cachePath : cachePaths) { + cachePath.replace(QStringLiteral("AusweisApp"), QStringLiteral("AusweisApp2")); auto cacheDir = QDir(cachePath); if (!cacheDir.exists()) diff --git a/src/core/controller/AppController.h b/src/core/controller/AppController.h index a54552a67..6c5a6f561 100644 --- a/src/core/controller/AppController.h +++ b/src/core/controller/AppController.h @@ -51,12 +51,7 @@ class AppController final AppController(); bool eventFilter(QObject* pObj, QEvent* pEvent) override; - -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) bool nativeEventFilter(const QByteArray& pEventType, void* pMessage, qintptr* pResult) override; -#else - bool nativeEventFilter(const QByteArray& pEventType, void* pMessage, long* pResult) override; -#endif void start(); @@ -66,8 +61,9 @@ class AppController final void fireInitialized(); void fireStarted(); void fireShutdown(); - void fireWorkflowStarted(QSharedPointer pContext); - void fireWorkflowFinished(QSharedPointer pContext); + void fireWorkflowStarted(const QSharedPointer& pRequest); + void fireWorkflowFinished(const QSharedPointer& pRequest); + void fireWorkflowUnhandled(const QSharedPointer& pRequest); void fireShowUi(UiModule pModule); void fireHideUi(); void fireShowUserInformation(const QString& pInformationMessage); diff --git a/src/diagnosis/DiagnosisFirewallDetection.cpp b/src/diagnosis/DiagnosisFirewallDetection.cpp index 7436515e7..2da408ee3 100644 --- a/src/diagnosis/DiagnosisFirewallDetection.cpp +++ b/src/diagnosis/DiagnosisFirewallDetection.cpp @@ -54,11 +54,11 @@ void DiagnosisFirewallDetection::parseFirewallFirstRuleInfos(const QString& pFir } if (lineparts[0].startsWith(QLatin1String("Name"))) { - if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8 && lineparts[1].startsWith(QLatin1String("AusweisApp2"))) + if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8 && lineparts[1].startsWith(QLatin1String("AusweisApp"))) { mFirstFirewallRuleExists = true; } - else if (lineparts[1].startsWith(QLatin1String("AusweisApp2-Firewall-Rule"))) + else if (lineparts[1].startsWith(QLatin1String("AusweisApp-Firewall-Rule"))) { mFirstFirewallRuleExists = true; } @@ -111,7 +111,7 @@ void DiagnosisFirewallDetection::parseFirewallSecondRuleInfos(const QString& pFi } if (lineparts[0].startsWith(QLatin1String("Name")) || lineparts[0].startsWith(QLatin1String("DisplayName"))) { - if (lineparts[1].startsWith(QLatin1String("AusweisApp2-SaC"))) + if (lineparts[1].startsWith(QLatin1String("AusweisApp-SaC"))) { mSecondFirewallRuleExists = true; } @@ -328,11 +328,11 @@ void DiagnosisFirewallDetection::startDetection() firstRuleParameters << QStringLiteral("-Command"); if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8) { - firstRuleParameters << QStringLiteral("(New-object -comObject HNetCfg.FwPolicy2).rules | where-object {$_.name -like \"AusweisApp2\"}"); + firstRuleParameters << QStringLiteral("(New-object -comObject HNetCfg.FwPolicy2).rules | where-object {$_.name -like \"AusweisApp\"}"); } else { - firstRuleParameters << QStringLiteral("Get-NetFirewallRule -Name \"AusweisApp2-Firewall-Rule\""); + firstRuleParameters << QStringLiteral("Get-NetFirewallRule -Name \"AusweisApp-Firewall-Rule\""); } connect(&mFirewallFirstRuleProcess, QOverload::of(&QProcess::finished), this, &DiagnosisFirewallDetection::onFirstRuleDone); @@ -346,11 +346,11 @@ void DiagnosisFirewallDetection::startDetection() secondRuleParameters << QStringLiteral("-Command"); if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8) { - secondRuleParameters << QStringLiteral("(New-object -comObject HNetCfg.FwPolicy2).rules | where-object {$_.name -like \"AusweisApp2-SaC\"}"); + secondRuleParameters << QStringLiteral("(New-object -comObject HNetCfg.FwPolicy2).rules | where-object {$_.name -like \"AusweisApp-SaC\"}"); } else { - secondRuleParameters << QStringLiteral("Get-NetFirewallRule -DisplayName \"AusweisApp2-SaC\""); + secondRuleParameters << QStringLiteral("Get-NetFirewallRule -DisplayName \"AusweisApp-SaC\""); } connect(&mFirewallSecondRuleProcess, QOverload::of(&QProcess::finished), this, &DiagnosisFirewallDetection::onSecondRuleDone); diff --git a/src/diagnosis/DiagnosisModel.cpp b/src/diagnosis/DiagnosisModel.cpp index d6f4315b7..802b242b8 100644 --- a/src/diagnosis/DiagnosisModel.cpp +++ b/src/diagnosis/DiagnosisModel.cpp @@ -11,17 +11,24 @@ #include "LanguageLoader.h" #include "RemoteServiceSettings.h" -#include +#include +#include +#include +#if defined(Q_OS_WIN) + #include +#endif #include +#include using namespace governikus; -DiagnosisModel::DiagnosisModel(const QSharedPointer& pContext) +DiagnosisModel::DiagnosisModel() : mSections() - , mContext(pContext) - , mAusweisApp2Section() + , mContext(new DiagnosisContext()) + , mDiagnosisController(mContext) + , mAusweisAppSection() , mTimestampSection() , mRemoteDeviceSectionRunning(false) , mRemoteDeviceSection() @@ -50,6 +57,10 @@ DiagnosisModel::DiagnosisModel(const QSharedPointer& pContext) mSections[Section::SECURITY].reset(new SectionModel()); QQmlEngine::setObjectOwnership(mSections[Section::SECURITY].data(), QQmlEngine::CppOwnership); + + + initContent(); + mDiagnosisController.run(); } @@ -85,9 +96,9 @@ QString DiagnosisModel::getSectionName(Section pSection) const void DiagnosisModel::initGeneralSections() { - mAusweisApp2Section.clear(); + mAusweisAppSection.clear(); BuildHelper::processInformationHeader([this](const QString& pKey, const QString& pValue){ - mAusweisApp2Section << ContentItem(pKey, pValue); + mAusweisAppSection << ContentItem(pKey, pValue); }); //: LABEL DESKTOP @@ -101,7 +112,7 @@ void DiagnosisModel::initGeneralSections() void DiagnosisModel::updateGeneralSection() { mSections[Section::GENERAL]->removeAllItems(); - mSections[Section::GENERAL]->addContent(mAusweisApp2Section); + mSections[Section::GENERAL]->addContent(mAusweisAppSection); mSections[Section::GENERAL]->addContent(mTimestampSection); } @@ -258,6 +269,63 @@ QString DiagnosisModel::boolToString(bool pBoolean) const } +QString DiagnosisModel::getAsPlaintext() const +{ + +#ifdef Q_OS_WIN + static const QString endl = QStringLiteral("\r\n"); +#else + static const QString endl(QLatin1Char('\n')); +#endif + + QStringList modelPlaintext; + + const auto& sections = mSections.keys(); + for (const auto& section : sections) + { + modelPlaintext << getSectionName(section); + modelPlaintext << mSections[section]->getAsPlaintext(); + modelPlaintext << endl; + } + + return modelPlaintext.join(endl); +} + + +void DiagnosisModel::initContent() +{ + disconnectSignals(); + + beginResetModel(); + + initGeneralSections(); + updateGeneralSection(); + + initCardReaderSections(); + updateCardReaderSection(false); + + initNetworkSections(); + updateNetworkSection(false); + + initAntiVirusAndFirewallSection(); + updateAntiVirusAndFirewallSection(false); + + onRemoteInfosChanged(); + + endResetModel(); + + connectSignals(); + + mConnectionTest.startConnectionTest(); + +#ifdef Q_OS_WIN + mAntivirusDetection.startInformationProcess(); + mFirewallDetection.startDetection(); +#endif + +} + + QVariant DiagnosisModel::data(const QModelIndex& pIndex, int pRole) const { const auto section = static_cast
    (pIndex.row()); @@ -284,7 +352,7 @@ QVariant DiagnosisModel::data(const QModelIndex& pIndex, int pRole) const int DiagnosisModel::rowCount(const QModelIndex& pParent) const { Q_UNUSED(pParent) - return mSections.size(); + return static_cast(mSections.size()); } @@ -303,26 +371,14 @@ QString DiagnosisModel::getCreationTime() const } -QString DiagnosisModel::getAsPlaintext() const +void DiagnosisModel::saveToFile(const QUrl& pFilename) const { - -#ifdef Q_OS_WIN - static const QString endl = QStringLiteral("\r\n"); -#else - static const QString endl(QLatin1Char('\n')); -#endif - - QStringList modelPlaintext; - - const auto& sections = mSections.keys(); - for (const auto& section : sections) + QFile file(pFilename.toLocalFile()); + if (file.open(QIODevice::WriteOnly)) { - modelPlaintext << getSectionName(section); - modelPlaintext << mSections[section]->getAsPlaintext(); - modelPlaintext << endl; + QString diagnosisLog = getAsPlaintext(); + file.write(diagnosisLog.toUtf8()); } - - return modelPlaintext.join(endl); } @@ -576,7 +632,7 @@ void DiagnosisModel::onFirewallInformationReady() QString firstRuleExists = boolToString(mFirewallDetection.getFirstRuleExists()); QString firstRuleEnabled = boolToString(mFirewallDetection.getFirstRuleEnabled()); //: LABEL DESKTOP - windowsFirewallSettings << tr("Outgoing AusweisApp2 rule"); + windowsFirewallSettings << tr("Outgoing %1 rule").arg(QCoreApplication::applicationName()); //: LABEL DESKTOP windowsFirewallSettings << tr("Exists: %1").arg(firstRuleExists); //: LABEL DESKTOP @@ -585,7 +641,7 @@ void DiagnosisModel::onFirewallInformationReady() QString secondRuleExists = boolToString(mFirewallDetection.getSecondRuleExists()); QString secondRuleEnabled = boolToString(mFirewallDetection.getSecondRuleEnabled()); //: LABEL DESKTOP - windowsFirewallSettings << tr("Incoming AusweisApp2 rule"); + windowsFirewallSettings << tr("Incoming %1 rule").arg(QCoreApplication::applicationName()); //: LABEL DESKTOP windowsFirewallSettings << tr("Exists: %1").arg(secondRuleExists); //: LABEL DESKTOP @@ -771,35 +827,3 @@ void DiagnosisModel::onReaderInfosChanged() updateCardReaderSection(); Q_EMIT fireRunningChanged(); } - - -void DiagnosisModel::reloadContent() -{ - disconnectSignals(); - - beginResetModel(); - - initGeneralSections(); - updateGeneralSection(); - - initCardReaderSections(); - updateCardReaderSection(false); - - initNetworkSections(); - updateNetworkSection(false); - - initAntiVirusAndFirewallSection(); - updateAntiVirusAndFirewallSection(false); - - onRemoteInfosChanged(); - mConnectionTest.startConnectionTest(); - -#ifdef Q_OS_WIN - mAntivirusDetection.startInformationProcess(); - mFirewallDetection.startDetection(); -#endif - - connectSignals(); - - endResetModel(); -} diff --git a/src/diagnosis/DiagnosisModel.h b/src/diagnosis/DiagnosisModel.h index 76e824e7c..9a0752dd6 100644 --- a/src/diagnosis/DiagnosisModel.h +++ b/src/diagnosis/DiagnosisModel.h @@ -10,15 +10,20 @@ #include "DiagnosisFirewallDetection.h" #include "SectionModel.h" #include "context/DiagnosisContext.h" +#include "controller/DiagnosisController.h" #include #include -#include +#include #include +#include +#include #include + class test_DiagnosisModel; + namespace governikus { @@ -29,6 +34,8 @@ class DiagnosisModel friend class ::test_DiagnosisModel; + Q_PROPERTY(bool running READ isRunning NOTIFY fireRunningChanged) + private: enum ContentRoles { @@ -45,8 +52,9 @@ class DiagnosisModel QMap> mSections; QSharedPointer mContext; + DiagnosisController mDiagnosisController; - QVector mAusweisApp2Section; + QVector mAusweisAppSection; QVector mTimestampSection; bool mRemoteDeviceSectionRunning; @@ -80,19 +88,21 @@ class DiagnosisModel void disconnectSignals(); [[nodiscard]] QString boolToString(bool pBoolean) const; + [[nodiscard]] QString getAsPlaintext() const; + + void initContent(); public: - explicit DiagnosisModel(const QSharedPointer& pContext); + explicit DiagnosisModel(); ~DiagnosisModel() override; [[nodiscard]] QVariant data(const QModelIndex& pIndex, int pRole = Qt::DisplayRole) const override; [[nodiscard]] int rowCount(const QModelIndex& pParent = QModelIndex()) const override; [[nodiscard]] QHash roleNames() const override; - [[nodiscard]] QString getCreationTime() const; - [[nodiscard]] QString getAsPlaintext() const; + [[nodiscard]] Q_INVOKABLE QString getCreationTime() const; + Q_INVOKABLE void saveToFile(const QUrl& pFilename) const; [[nodiscard]] bool isRunning() const; - void reloadContent(); Q_SIGNALS: void fireRunningChanged(); diff --git a/src/diagnosis/SectionModel.cpp b/src/diagnosis/SectionModel.cpp index 224f84d05..0fc67249f 100644 --- a/src/diagnosis/SectionModel.cpp +++ b/src/diagnosis/SectionModel.cpp @@ -53,7 +53,7 @@ QVariant SectionModel::data(const QModelIndex& pIndex, int pRole) const int SectionModel::rowCount(const QModelIndex& pParent) const { Q_UNUSED(pParent) - return mContentItems.size(); + return static_cast(mContentItems.size()); } @@ -87,7 +87,8 @@ void SectionModel::addContent(const QVector& pContent) return; } - beginInsertRows(index(mContentItems.size()), mContentItems.size(), mContentItems.size() + pContent.size() - 1); + const auto contentItemSize = static_cast(mContentItems.size()); + beginInsertRows(index(contentItemSize), contentItemSize, contentItemSize + static_cast(pContent.size()) - 1); mContentItems << pContent; endInsertRows(); } diff --git a/src/diagnosis/SelfDiagnosisModel.cpp b/src/diagnosis/SelfDiagnosisModel.cpp deleted file mode 100644 index b36ee70c1..000000000 --- a/src/diagnosis/SelfDiagnosisModel.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/** - * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany - */ - -#include "SelfDiagnosisModel.h" - -#include -#include -#include - - -using namespace governikus; - - -SelfDiagnosisModel::SelfDiagnosisModel() - : QObject() - , mDiagnosisContext(new DiagnosisContext()) - , mDiagnosisModel(mDiagnosisContext) -{ - QQmlEngine::setObjectOwnership(&mDiagnosisModel, QQmlEngine::CppOwnership); - - connect(&mDiagnosisModel, &DiagnosisModel::fireRunningChanged, this, &SelfDiagnosisModel::fireRunningChanged); -} - - -bool SelfDiagnosisModel::isRunning() const -{ - return mDiagnosisModel.isRunning(); -} - - -void SelfDiagnosisModel::saveToFile(const QUrl& pFilename) const -{ - QFile file(pFilename.toLocalFile()); - if (file.open(QIODevice::WriteOnly)) - { - QString diagnosisLog = mDiagnosisModel.getAsPlaintext(); - file.write(diagnosisLog.toUtf8()); - } -} - - -QString SelfDiagnosisModel::getCreationTime() const -{ - return mDiagnosisModel.getCreationTime(); -} - - -void SelfDiagnosisModel::onTranslationChanged() -{ - mDiagnosisModel.reloadContent(); -} - - -QAbstractListModel* SelfDiagnosisModel::getSectionsModel() -{ - return &mDiagnosisModel; -} - - -void SelfDiagnosisModel::startController() -{ - if (mDiagnosisController.isNull()) - { - mDiagnosisController.reset(new DiagnosisController(mDiagnosisContext)); - mDiagnosisController->run(); - } - mDiagnosisModel.reloadContent(); -} - - -void SelfDiagnosisModel::stopController() -{ - mDiagnosisController.reset(); -} diff --git a/src/diagnosis/SelfDiagnosisModel.h b/src/diagnosis/SelfDiagnosisModel.h deleted file mode 100644 index 935f51f35..000000000 --- a/src/diagnosis/SelfDiagnosisModel.h +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany - */ - -#pragma once - -#include "DiagnosisModel.h" -#include "Env.h" -#include "context/DiagnosisContext.h" -#include "controller/DiagnosisController.h" - -#include -#include -#include -#include - - -namespace governikus -{ - -class SelfDiagnosisModel - : public QObject -{ - Q_OBJECT - friend class Env; - - Q_PROPERTY(QAbstractListModel * sectionsModel READ getSectionsModel CONSTANT) - Q_PROPERTY(bool running READ isRunning NOTIFY fireRunningChanged) - - private: - QSharedPointer mDiagnosisContext; - DiagnosisModel mDiagnosisModel; - QScopedPointer mDiagnosisController; - - SelfDiagnosisModel(); - ~SelfDiagnosisModel() override = default; - - bool isRunning() const; - - public: - [[nodiscard]] QAbstractListModel* getSectionsModel(); - Q_INVOKABLE void startController(); - Q_INVOKABLE void stopController(); - Q_INVOKABLE void saveToFile(const QUrl& pFilename) const; - [[nodiscard]] Q_INVOKABLE QString getCreationTime() const; - - public Q_SLOTS: - void onTranslationChanged(); - - Q_SIGNALS: - void fireSectionContentModelChanged(); - void fireCurrentSectionChanged(); - void fireRunningChanged(); -}; - -} // namespace governikus diff --git a/src/diagnosis/controller/DiagnosisController.cpp b/src/diagnosis/controller/DiagnosisController.cpp index 3957fc022..03e2afede 100644 --- a/src/diagnosis/controller/DiagnosisController.cpp +++ b/src/diagnosis/controller/DiagnosisController.cpp @@ -20,7 +20,6 @@ DiagnosisController::DiagnosisController(const QSharedPointer& : QObject(pParent) , mContext(pContext) , mWatcherPcscInfo() - , mScanHasToBeStopped(false) { connect(&mWatcherPcscInfo, &QFutureWatcher::finished, this, &DiagnosisController::onPcscInfoRetrieved); @@ -37,28 +36,15 @@ DiagnosisController::DiagnosisController(const QSharedPointer& DiagnosisController::~DiagnosisController() { - if (mScanHasToBeStopped) - { - const auto& readerManager = Env::getSingleton(); - if (readerManager->isScanRunning(ReaderManagerPlugInType::PCSC)) - { - qCDebug(diagnosis) << "Stopping PCSC scan."; - readerManager->stopScan(ReaderManagerPlugInType::PCSC); - } - mScanHasToBeStopped = false; - } + qCDebug(diagnosis) << "Stopping PCSC scan."; + Env::getSingleton()->stopScan(ReaderManagerPlugInType::PCSC); } void DiagnosisController::run() { - const auto& readerManager = Env::getSingleton(); - if (!readerManager->isScanRunning(ReaderManagerPlugInType::PCSC)) - { - qCDebug(diagnosis) << "PCSC scan not running, starting scan ourself and stop it afterwards."; - readerManager->startScan(ReaderManagerPlugInType::PCSC); - mScanHasToBeStopped = true; - } + qCDebug(diagnosis) << "Starting PCSC scan."; + Env::getSingleton()->startScan(ReaderManagerPlugInType::PCSC); mWatcherPcscInfo.setFuture(QtConcurrent::run(&DiagnosisController::retrievePcscInfo)); collectInterfaceInformation(); diff --git a/src/diagnosis/controller/DiagnosisController.h b/src/diagnosis/controller/DiagnosisController.h index 54de24c18..abeb3c8f7 100644 --- a/src/diagnosis/controller/DiagnosisController.h +++ b/src/diagnosis/controller/DiagnosisController.h @@ -32,7 +32,6 @@ class DiagnosisController QSharedPointer mContext; QFutureWatcher mWatcherPcscInfo; - bool mScanHasToBeStopped; void collectInterfaceInformation(); diff --git a/src/export/CMakeLists.txt b/src/export/CMakeLists.txt deleted file mode 100644 index 6d82b1899..000000000 --- a/src/export/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -##################################################################### -# The module export is responsible to export certain data to other -# file formats. -# Supported: PDF -##################################################################### - -if(TARGET ${Qt}::Svg) - ADD_PLATFORM_LIBRARY(AusweisAppExport) - - target_link_libraries(AusweisAppExport ${Qt}::Core ${Qt}::Svg AusweisAppCard AusweisAppSettings) -endif() diff --git a/src/export/PdfCreator.cpp b/src/export/PdfCreator.cpp deleted file mode 100644 index a72fcdc59..000000000 --- a/src/export/PdfCreator.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ - -#include "PdfCreator.h" - -#include "LanguageLoader.h" - -#include -#include -#include -#include - -using namespace governikus; - - -PdfCreator::PdfCreator(const QString& pFilename, const QString& pTitle, const QString& pHeadline, const QString& pContent) - : mPdfWriter(pFilename) - , mHeader() - , mContent() - , mFooter() -{ - mHeader.setUndoRedoEnabled(false); - mContent.setUndoRedoEnabled(false); - mFooter.setUndoRedoEnabled(false); - - qDebug() << "Use filename for PDF:" << pFilename; - - const QPageLayout layout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMargins(20, 20, 20, 15), QPageLayout::Millimeter); - mPdfWriter.setPageLayout(layout); - mPdfWriter.setCreator(QCoreApplication::applicationName()); - mPdfWriter.setTitle(pTitle); - mPdfWriter.setPdfVersion(QPagedPaintDevice::PdfVersion_A1b); - - createHeader(pTitle, pHeadline); - createFooter(); - createContent(pContent); -} - - -void PdfCreator::createHeader(const QString& pTitle, const QString& pHeadline) -{ - const auto& header = QStringLiteral("" - "" - "" - "" - "" - "
    " - "

    %1 - %2

    " - "

    %3" - "

    " - "

    %4

    " - "
    ").arg( - pTitle, - QCoreApplication::applicationName(), - //: LABEL ALL_PLATFORMS - tr("AusweisApp2 is a product of Governikus GmbH & Co. KG - on behalf of the Federal Office for Information Security."), - pHeadline); - - QSvgRenderer renderer(QStringLiteral(":/images/npa.svg")); - QImage image(768, 768, QImage::Format_RGB32); - image.fill(0x00FFFFFF); - QPainter imagePainter(&image); - renderer.render(&imagePainter); - - mHeader.addResource(QTextDocument::ImageResource, QUrl(QStringLiteral("pdflogo")), image); - mHeader.setHtml(header); -} - - -void PdfCreator::createContent(const QString& pContent) -{ - mContent.setHtml(pContent); -} - - -void PdfCreator::createFooter() -{ - //: LABEL ALL_PLATFORMS Footer in a generated PDF document. %1 is an URL. - const auto& footer = QStringLiteral("

    %1

    ").arg(tr("For further information, please see %1").arg( - QStringLiteral("%1").arg(QStringLiteral("https://www.ausweisapp.bund.de/%1").arg(LanguageLoader::getLocaleCode())))); - - mFooter.setHtml(footer); -} - - -// inspired by void QTextDocument::drawContents(QPainter *p, const QRectF &rect) -void PdfCreator::drawContents(const QTextDocument& pTextDocument, QPainter& pPainter, const QRectF& pClipRect) -{ - QAbstractTextDocumentLayout::PaintContext paintContext; - paintContext.palette.setColor(QPalette::Text, Qt::black); - - pPainter.save(); - - if (pClipRect.isValid()) - { - pPainter.setClipRect(pClipRect); - paintContext.clip = pClipRect; - } - - pTextDocument.documentLayout()->draw(&pPainter, paintContext); - - pPainter.restore(); -} - - -int qt_defaultDpi(); -bool PdfCreator::save() -{ - mPdfWriter.setResolution(qt_defaultDpi()); - const QRect pageArea(mPdfWriter.pageLayout().paintRectPixels(mPdfWriter.resolution())); - - QPainter painter(&mPdfWriter); - if (!painter.isActive()) - { - qCritical() << "Cannot paint into pdf file. Check file system permissions!"; - return false; - } - - mHeader.setPageSize(pageArea.size()); - mFooter.setPageSize(pageArea.size()); - const qreal headerHeight = mHeader.size().height(); - const QSizeF contentMaxPageSize(pageArea.width(), pageArea.height() - headerHeight - mFooter.size().height()); - mContent.setPageSize(contentMaxPageSize); - - const QRect contentRect(QPoint(0, 0), mContent.size().toSize()); - QRect currentRect(QPoint(0, 0), contentMaxPageSize.toSize()); - while (currentRect.intersects(contentRect)) - { - painter.resetTransform(); - - drawContents(mHeader, painter); - painter.translate(0, headerHeight); - - painter.save(); - painter.translate(0, -currentRect.y()); - drawContents(mContent, painter, currentRect); - painter.restore(); - painter.translate(0, currentRect.height()); - - drawContents(mFooter, painter); - - currentRect.translate(0, currentRect.height()); - if (currentRect.intersects(contentRect)) - { - mPdfWriter.newPage(); - } - } - - return true; -} diff --git a/src/export/PdfCreator.h b/src/export/PdfCreator.h deleted file mode 100644 index 44b0726a0..000000000 --- a/src/export/PdfCreator.h +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ - -/*! - * \brief Tool to create PDF-Documents. - */ - -#pragma once - -#include -#include -#include -#include -#include - -namespace governikus -{ - -class PdfCreator -{ - Q_DECLARE_TR_FUNCTIONS(governikus::PdfCreator) - - private: - QPdfWriter mPdfWriter; - QTextDocument mHeader; - QTextDocument mContent; - QTextDocument mFooter; - - void drawContents(const QTextDocument& pTextDocument, QPainter& pPainter, const QRectF& pClipRect = QRectF()); - void createHeader(const QString& pTitle, const QString& pHeadline); - void createContent(const QString& pContent); - void createFooter(); - - public: - PdfCreator(const QString& pFilename, const QString& pTitle, const QString& pHeadline, const QString& pContent); - bool save(); -}; - - -} // namespace governikus diff --git a/src/export/PdfExporter.cpp b/src/export/PdfExporter.cpp deleted file mode 100644 index 8cbc97cf7..000000000 --- a/src/export/PdfExporter.cpp +++ /dev/null @@ -1,196 +0,0 @@ -/** - * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany - */ - -#include "PdfExporter.h" - -#include "AppSettings.h" -#include "LanguageLoader.h" -#include "PdfCreator.h" -#include "asn1/AccessRoleAndRight.h" - -#include - -using namespace governikus; - -namespace -{ -QString getValueOrWhitespace(const QStringList& pValues, int i) -{ - if (i < pValues.size() && !pValues.at(i).isEmpty()) - { - return pValues.at(i); - } - return QStringLiteral(" "); -} - - -} // namespace - - -PdfExporter::PdfExporter(const QString& pFilename, bool pOpenFile, bool pFixFilename) - : mFilename(pFilename) - , mOpenFile(pOpenFile) - , mColoredRow(false) - , mColumnCount(0) - , mContent() -{ - if (pFixFilename && !mFilename.isEmpty() - && !mFilename.endsWith(QLatin1String(".pdf"), Qt::CaseInsensitive)) - { - mFilename += QStringLiteral(".pdf"); - } -} - - -QString PdfExporter::getContent() const -{ - return mContent.join(QString()); -} - - -void PdfExporter::checkOpenFile(bool pSuccess) -{ - if (mOpenFile && pSuccess) - { - QDesktopServices::openUrl(QUrl(QStringLiteral("file:///") + mFilename)); - } -} - - -void PdfExporter::initTable(int pColumnCount, const QList& pWidth, const QStringList& pValues) -{ - Q_ASSERT(mColumnCount == 0); - - mColumnCount = pColumnCount; - mContent << QStringLiteral(""); - for (int i = 0; i < mColumnCount; ++i) - { - const auto& width = i < pWidth.size() ? QStringLiteral(" width='%1'").arg(pWidth.at(i)) : QString(); - mContent << QStringLiteral("").arg(width, getValueOrWhitespace(pValues, i)); - } - mContent << QStringLiteral(""); -} - - -void PdfExporter::addTableRow(const QStringList& pValues) -{ - mContent << (mColoredRow ? QStringLiteral("") : QStringLiteral("")); - for (int i = 0; i < mColumnCount; ++i) - { - mContent << QStringLiteral("").arg(getValueOrWhitespace(pValues, i)); - } - mContent << QStringLiteral(""); -} - - -void PdfExporter::closeTable() -{ - mContent << QStringLiteral("
    %2
    %2
    "); - mColumnCount = 0; - mColoredRow = false; -} - - -void PdfExporter::toggleRowColor() -{ - mColoredRow = !mColoredRow; -} - - -bool PdfExporter::exportHistory() -{ - if (mFilename.isEmpty()) - { - return false; - } - mContent.clear(); - - const auto& locale = LanguageLoader::getInstance().getUsedLocale(); - - initTable(3, {180, 80}, - //: LABEL ALL_PLATFORMS - {tr("Date"), - //: LABEL ALL_PLATFORMS - tr("Details")}); - //: LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString - const auto& dateTimeFormat = tr("dd.MM.yyyy hh:mm AP"); - const auto& infos = Env::getSingleton()->getHistorySettings().getHistoryInfos(); - for (const auto& entry : infos) - { - toggleRowColor(); - const QString& dateTimeEntry = locale.toString(entry.getDateTime(), dateTimeFormat); - //: LABEL ALL_PLATFORMS - addTableRow({dateTimeEntry, tr("Provider:"), entry.getSubjectName()}); - //: LABEL ALL_PLATFORMS - addTableRow({QString(), tr("Purpose:"), entry.getPurpose()}); - - const auto& readData = AccessRoleAndRightsUtil::joinFromTechnicalName(entry.getRequestedData(), AccessRoleAndRightsUtil::READ); - if (!readData.isEmpty()) - { - //: LABEL ALL_PLATFORMS - addTableRow({QString(), tr("Read access:"), readData}); - } - - const auto& writtenData = AccessRoleAndRightsUtil::joinFromTechnicalName(entry.getRequestedData(), AccessRoleAndRightsUtil::WRITE); - if (!writtenData.isEmpty()) - { - //: LABEL ALL_PLATFORMS - addTableRow({QString(), tr("Write access (update):"), writtenData}); - } - } - closeTable(); - - const auto& now = QDateTime::currentDateTime(); - //: LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString - QString date = locale.toString(now, tr("dd.MM.yyyy")); - //: LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString - QString time = locale.toString(now, tr("hh:mm AP")); - //: LABEL ALL_PLATFORMS - const auto& headline = tr("At %1 %2 the following data were saved:").arg(date, time); - - //: LABEL ALL_PLATFORMS - PdfCreator pdf(mFilename, tr("History"), headline, getContent()); - const bool success = pdf.save(); - checkOpenFile(success); - return success; -} - - -bool PdfExporter::exportSelfInfo(const QDateTime& pDate, const QVector>& pInfoData) -{ - if (mFilename.isEmpty()) - { - return false; - } - mContent.clear(); - - initTable(2, {180}, - //: LABEL ALL_PLATFORMS - {tr("Entry"), - //: LABEL ALL_PLATFORMS - tr("Content")}); - for (const auto& entry : pInfoData) - { - if (!entry.first.isEmpty()) - { - toggleRowColor(); - } - addTableRow({entry.first, entry.second}); - } - closeTable(); - - const auto& locale = LanguageLoader::getInstance().getUsedLocale(); - //: LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString - QString date = locale.toString(pDate, tr("dd.MM.yyyy")); - //: LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString - QString time = locale.toString(pDate, tr("hh:mm AP")); - //: LABEL ALL_PLATFORMS - const auto& headline = tr("At %1 %2 the following data has been read out of your ID card:").arg(date, time); - - //: LABEL ALL_PLATFORMS - PdfCreator pdf(mFilename, tr("Information"), headline, getContent()); - const bool success = pdf.save(); - checkOpenFile(success); - return success; -} diff --git a/src/export/PdfExporter.h b/src/export/PdfExporter.h deleted file mode 100644 index 80744066c..000000000 --- a/src/export/PdfExporter.h +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany - */ - -/*! - * \brief Tool to export data of history or selfauthentication result. - */ - -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace governikus -{ -class PdfExporter -{ - Q_DECLARE_TR_FUNCTIONS(governikus::PdfExporter) - - private: - QString mFilename; - bool mOpenFile; - bool mColoredRow; - int mColumnCount; - QStringList mContent; - - [[nodiscard]] QString getContent() const; - - void checkOpenFile(bool pSuccess); - void initTable(int pColumnCount, const QList& pWidth, const QStringList& pValues); - void closeTable(); - void addTableRow(const QStringList& pValues); - void toggleRowColor(); - - public: - PdfExporter(const QString& pFilename, bool pOpenFile = true, bool pFixFilename = true); - bool exportHistory(); - bool exportSelfInfo(const QDateTime& pDate, const QVector>& pInfoData); -}; - -} // namespace governikus diff --git a/src/external/http_parser/CMakeLists.txt b/src/external/http_parser/CMakeLists.txt index c59f4b0ec..0c4a97252 100644 --- a/src/external/http_parser/CMakeLists.txt +++ b/src/external/http_parser/CMakeLists.txt @@ -22,21 +22,19 @@ function(PRINT_HTTP_PARSER _include_dir _lib_dir) message(STATUS "HttpParser: ${_lib_dir} (${_version})") endfunction() -if(NOT CMAKE_VERSION VERSION_LESS "3.10") - find_path(HTTP_PARSER_INCLUDE_DIR NAMES http_parser.h) - find_library(HTTP_PARSER_LIBRARY NAMES http_parser libhttp_parser) +find_path(HTTP_PARSER_INCLUDE_DIR NAMES http_parser.h) +find_library(HTTP_PARSER_LIBRARY NAMES http_parser libhttp_parser) - if(HTTP_PARSER_INCLUDE_DIR) - PARSE_HTTP_PARSER_VERSION("${HTTP_PARSER_INCLUDE_DIR}" _version) - if(_version VERSION_LESS "2.8.0") - message(STATUS "HttpParser (system) too old: ${_version}") - unset(HTTP_PARSER_INCLUDE_DIR CACHE) - unset(HTTP_PARSER_LIBRARY CACHE) - else() - include(FindPackageHandleStandardArgs) - FIND_PACKAGE_HANDLE_STANDARD_ARGS(HTTP_PARSER REQUIRED_VARS HTTP_PARSER_INCLUDE_DIR HTTP_PARSER_LIBRARY) - mark_as_advanced(HTTP_PARSER_INCLUDE_DIR HTTP_PARSER_LIBRARY) - endif() +if(HTTP_PARSER_INCLUDE_DIR) + PARSE_HTTP_PARSER_VERSION("${HTTP_PARSER_INCLUDE_DIR}" _version) + if(_version VERSION_LESS "2.8.0") + message(STATUS "HttpParser (system) too old: ${_version}") + unset(HTTP_PARSER_INCLUDE_DIR CACHE) + unset(HTTP_PARSER_LIBRARY CACHE) + else() + include(FindPackageHandleStandardArgs) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(HTTP_PARSER REQUIRED_VARS HTTP_PARSER_INCLUDE_DIR HTTP_PARSER_LIBRARY) + mark_as_advanced(HTTP_PARSER_INCLUDE_DIR HTTP_PARSER_LIBRARY) endif() endif() diff --git a/src/external/smart/CHANGELOG.md b/src/external/smart/CHANGELOG.md index f21c598e7..eb27e1206 100644 --- a/src/external/smart/CHANGELOG.md +++ b/src/external/smart/CHANGELOG.md @@ -1,5 +1,167 @@ -Change Log -========== +# Change Log + +## Version 1.1.0 + +_2023-08-17_ + +- NEW: Upgrade TSM-API SDK to v1.3.0 (`tsm-api-sdk-1.3.0-20230807-release.aar`) +- NEW: implementation and use of `CommandAPDU` and `ResponseAPDU` to replace `ByteArray` (Kotlin only) +- NEW: eID-Service-Library returns SW=`6F00` for known OMAPI exceptions upon transmit + +## Version 1.0.0 + +_2023-06-29_ + +- NEW: improve the treatment of exceptions (#10827, #10828) +- NEW: return `ServiceResult#NETWORK_CONNECTION_ERROR` if a TSM-API SDK command was not + started or interrupted due to a network issue +- NEW: return `ServiceResult#ERROR` when calling `deleteSmartEid()` if the eID-Applet was provisioned by the TSMS but still exists after this call. + +### eid_applet_interface/jni-bridge + +- NEW: jni-bridge upgrade to v0.23.0 +- NEW: add `EidServiceResult#NETWORK_CONNECTION_ERROR` + +## Version 0.18.1 + +_2023-05-04_ + +### eid_applet_interface/jni-bridge + +- FIX: change wrong `findClass` calls +- NEW: jni-bridge upgrade to v0.22.3 +- NEW: update ndk version to `25.2.9519653` + +## Version 0.18.0 + +_2023-04-28_ + +- NEW: Upgrade TSM-API SDK to v1.2.0 (`tsm-api-sdk-1.2.0-20230420-release.aar`) +- FIX: prevent NoClassDefFoundError for the IProcessListener +- FIX: `SmartEidCard` instance could still be used without reconnecting to the eID-Applet even + if the `ActionTimer` already closed the channel. +- FIX: add missing array boundary check (#11523) + +### eid_applet_interface/jni-bridge + +- NEW: jni-bridge upgrade to v0.22.2 +- NEW: Updated jni to handle mapping between objects and integer +- FIX: add missing nullptr checks (#11562) +- FIX: resolve issues with concurrent calls of the `shutdownService()` function (#10885) +- FIX: prevent redundant `findClass()` calls (#10904) +- FIX: delete local references (#10906) + +## Version 0.17.4 + +_2023-03-03_ + +- NEW: Upgrade TSM-API SDK to v1.0.3 (`tsm-api-sdk-1.0.3-20230224-release.aar`) +- NEW: Automatically close the `SEService` if no successful binding could be established and a + timeout was exceeded. + +## Version 0.17.3 + +_2023-02-09_ + +- NEW: Upgrade TSM-API SDK to v1.0.2 (`tsm-api-sdk-1.0.2-20230207-release.aar`) +- FIX: Issue #173, Catch `ClassCastException` for `android.os.BinderProxy` in an unknown process + +## Version 0.17.2 + +_2023-01-25_ + +- NEW: upgrade Kotlin-Version +- NEW: Upgrade TSM-API SDK to v1.0.0 (`tsm-api-sdk-1.0.0-20230123-release.aar`) + +## Version 0.17.1 + +_2023-01-19_ + +- FIX: downgrade Kotlin-Version + +## Version 0.17.0 + +_2023-01-13_ + +- NEW: multiple eID-Applets on different Secure Elements are handled according to the + documentation `Description of eID-Applet Status Computation v0.2.1` +- NEW: improvement of the architecture of the eID-Service-Library +- NEW: change library package name from `de.bdr.eid_applet_service_lib` + to `de.bundesdruckerei.android.eid_applet_service_lib` +- NEW: jni-bridge interface upgrade to v0.22.0 + +## Version 0.16.1 + +_2022-12-19_ + +- NEW: Upgrade TSM-API SDK to v0.12.2 (`tsm-api-sdk-0.12.2-20221130-release.aar`) +- FIX: fix `challengeType` value in the `ServiceInformationResult` +- FIX: fix `GET CHALLENGE` response handling + +## Version 0.16.0 + +_2022-10-14_ + +- NEW: jni-bridge interface upgrade to v0.21.0 +- NEW: Upgrade TSM-API SDK to v0.12.1 (`tsm-api-sdk-0.12.1-20221012-release.aar`) +- NEW: updating the integration of the progress information from tsms-api-sdk + +## Version 0.15.0 + +_2022-09-20_ + +- NEW: jni-bridge interface upgrade to v0.20.0 +- NEW: initialization of the personalization is possible only in EidStatus `NO_PERSONALIZATION` +- NEW: the function `finalizePersonalization(status)` delete the IEA key if the eID-Applet was + rejected by the personalization system + +## Version 0.14.0 + +_2022-08-30_ + +- NEW: jni-bridge interface upgrade to v0.19.2 +- NEW: handling of the status code of a previous personalization according to the + documentation `Error_Handling_Smart-eID-Personalization_v0.5` +- FIX: detection of library support with multiple major versions supported +- FIX: Proper evaluation of the TA2,CA2 and PACE protocol within the determination of the applet + status. +- NEW: Unbind the `TSMAPIService` after calling the function `installSmartEid()` + and `smartEidSupportInfo()` +- NEW: Change within the `deleteSmartEid()` function: Delete the IEA KeyPair only after the + TSMS `terminateService()` command was successful. + +## Version 0.13.0 + +_2022-08-11_ + +- NEW: jni-bridge interface upgrade to v0.19.1 +- NEW: upgrade `smartEidStatus()` and `smartEidSupportInfo()` implementation according to the + documentation `Description of eID-Applet Status Computation v0.2.1` +- NEW: handling of ServiceInstances within the `installSmartEid()` function that are either in + state `NotDeployed` or `InError` +- NEW: implementation of eID-Service-Library support check +- NEW: automatic detection of the TSM ServiceVersionTag, which is supported by the + eID-Service-Library. Passing the ServiceVersionTag using `initializeService()` function is now + optional and should only be set explicitly for test purposes. +- NEW: Upgrade TSM-API SDK to v0.11.0 (`tsm-api-sdk-0.11.0-20220620-release.aar`) + +## Version 0.12.1 + +_2022-06-09_ + +- FIX: Avoid the call of the `PersonalizeServiceCommand` command within the service deployment +- FIX: AttestationToken encoding for calling 'initializePersonalization(...)' +- NEW: The `ActionTimer` to automatically close the eID-Applet channel is now thread-safe + +## Version 0.12.0 + +_2022-06-03_ + +- NEW: `deletePersonalization()` now executes TERMINATE APDU before deleting IEA key pair +- NEW: `finalizePersonalization()` now SELECTs eID-Applet in order to accommodate G+D for NXP CSP + case (move initial PIN to CSP Admin) +- NEW: Upgrade TSM-API SDK to v0.10.0 (`tsm-api-sdk-0.10.0-20220517-release.aar`) +- NEW: perform the `TSMS#PersonalizeServiceCommand` command within the service deployment ## Version 0.11.0 @@ -8,24 +170,31 @@ _2022-04-28_ - NEW: Upgrade TSM-API SDK to v0.9.5 (`tsm-api-sdk-0.9.5-20220413-release.aar`) - NEW: jni-bridge interface upgrade to v0.17.0 - NEW: Proper status for unsupported devices is returned (#95) -- FIX: Correction of the return values for `getSmartEidStatus()` and `getUpdateInfo()` in case of an error +- FIX: Correction of the return values for `getSmartEidStatus()` and `getUpdateInfo()` in case of an + error ## Version 0.10.3 _2022-04-08_ -- NEW: Tests the current thread used for initializing the library. If this is the main thread, the initialization is interrupted and the return value `GenericDataResult` contains an `ERROR` code. -- NEW: Catch the case when the `SEService´ is already bound and the `SEService.OnConnectedListener` callback is not called. -- NEW: Automatic closing of the open OMAPI channel after 4 minutes and 50 seconds, if no further APDU was transferred. +- NEW: Tests the current thread used for initializing the library. If this is the main thread, the + initialization is interrupted and the return value `GenericDataResult` contains an `ERROR` code. +- NEW: Catch the case when the `SEService´ is already bound and the `SEService.OnConnectedListener` + callback is not called. +- NEW: Automatic closing of the open OMAPI channel after 4 minutes and 50 seconds, if no further + APDU was transferred. - NEW: Upgrade TSM-API SDK to v0.9.4 (`tsm-api-sdk-0.9.4-20220408-release.aar`) ## Version 0.10.2 _2022-03-18_ -- FIX: Avoid throwing a `GeneralSecurityException` if the application can participate in the backup and restore infrastructure. -- FIX: A persisted and not updated `getUpdateInfo()` result is no longer considered when calling `getSmartEidStatus()`, if there is no applet present anymore. -- FIX: Ensures the support of the device if an applet is installed but no `getUpdateInfo()` has been called before. (#85) +- FIX: Avoid throwing a `GeneralSecurityException` if the application can participate in the backup + and restore infrastructure. +- FIX: A persisted and not updated `getUpdateInfo()` result is no longer considered when + calling `getSmartEidStatus()`, if there is no applet present anymore. +- FIX: Ensures the support of the device if an applet is installed but no `getUpdateInfo()` has been + called before. (#85) ## Version 0.10.1 @@ -33,18 +202,24 @@ _2022-03-16_ - NEW: Upgrade TSM-API SDK to v0.9.2 (`tsm-api-sdk-0.9.2-20220315-release.aar`) - NEW: Renamed Logger from `SmartEidServiceLib` to `bdr` -- FIX: The last known result of `getUpdateInfo()` is no longer deleted in function `deleteSmartEid()`. (according to the documentation `Description of eID-Applet Status Management v0.8.pdf`) +- FIX: The last known result of `getUpdateInfo()` is no longer deleted in + function `deleteSmartEid()`. (according to the + documentation `Description of eID-Applet Status Management v0.8`) ## Version 0.10.0 _2022-03-15_ -- FIX: Faulty binding between applet and application (IEA) when ECDSA signature size is different. (#69) +- FIX: Faulty binding between applet and application (IEA) when ECDSA signature size is different. ( + #69) - NEW: Revision of the jni-bridge in collaboration with Governikus. -- NEW: Upgrade the smartEid status management according to the documentation `Description of eID-Applet Status Management v0.8.pdf` - - Function `getSmartEidStatus()` can be used without calling `getUpdateInfo()` before, if an applet has already been installed. +- NEW: Upgrade the smartEid status management according to the + documentation `Description of eID-Applet Status Management v0.8` + - Function `getSmartEidStatus()` can be used without calling `getUpdateInfo()` before, if an + applet has already been installed. - Personalization Status and the used CSP are requested directly by the installed eID-Applet. - - A distinction is made between the CSP Types GuD and Thales. The corresponding return values for the status are produced if a personalization can no longer be used. + - A distinction is made between the CSP Types GuD and Thales. The corresponding return values + for the status are produced if a personalization can no longer be used. - NEW: Upgrade TSM-API SDK to v0.9.1 (`tsm-api-sdk-0.9.1-20220314-release.aar`) (#47) ## Version 0.9.1 @@ -63,7 +238,8 @@ _2022-02-25_ ### eid-applet-service-lib -- NEW: Add `processHandler` parameter to `installSmartEid()` and `deleteSmartEid()`. Remove global `setProgressHandler()` function and `Operation` enum. +- NEW: Add `processHandler` parameter to `installSmartEid()` and `deleteSmartEid()`. Remove + global `setProgressHandler()` function and `Operation` enum. - NEW: Initial External Authentication can no longer be disabled. Implementation has been updated. ## Version 0.8.0 @@ -76,7 +252,9 @@ _2021-02-18_ ### eid-applet-service-lib -- NEW: Remove the `TSMSServiceId` attribute from `AndroidManifest`. For the initialization of the library now three properties (`ServiceId`, `ServiceTag` and `SSD AID`) are required, which must be passed directly to the function `initializeService`. +- NEW: Remove the `TSMSServiceId` attribute from `AndroidManifest`. For the initialization of the + library now three properties (`ServiceId`, `ServiceTag` and `SSD AID`) are required, which must be + passed directly to the function `initializeService`. - NEW: Upgrade TSM-API SDK to v0.8.1 (`tsm-api-sdk-0.8.1-20220210-release.aar`) ## Version 0.7.1 @@ -85,7 +263,8 @@ _2022-02-11_ ### eid-applet-service-lib -- NEW: After calling the `deleteSmartEid` function a TSM-ServiceInstanceId is no longer queried immediately. +- NEW: After calling the `deleteSmartEid` function a TSM-ServiceInstanceId is no longer queried + immediately. - NEW: Unbind the `TSMAPIService` immediately when the `deleteSmartEid` is called. - NEW: Updated logging mechanism. Messages are now forwarded to the `java.util.logging.Logger`. @@ -95,7 +274,8 @@ _2022-02-04_ ### eid-applet-service-lib -- NEW: Integration of new API for the Personalization Data Provider Service in v1.0.0. This version is not backward compatible. +- NEW: Integration of new API for the Personalization Data Provider Service in v1.0.0. This version + is not backward compatible. ### eid_applet_interface/jni-bridge @@ -108,8 +288,10 @@ _2022-01-12_ ### eid-applet-service-lib - FIX: fix implementation of function 'initializePrePersonalization(...)' with modified signature -- FIX: Issue #34, Returns the proper response of the `getSmartEidStatus` function if a `deletePersonalization` was previously performed. IEA is disabled for the time being. -- FIX: Binding of the SEService is now performed in the `Dispatchers.Default` to avoid a blocking main thread. +- FIX: Issue #34, Returns the proper response of the `getSmartEidStatus` function if + a `deletePersonalization` was previously performed. IEA is disabled for the time being. +- FIX: Binding of the SEService is now performed in the `Dispatchers.Default` to avoid a blocking + main thread. ## Version 0.6.1 @@ -121,11 +303,17 @@ _2021-12-16_ ### eid-applet-service-lib -- NEW: function `getSmartEidStatus` returns `UNAVAILABLE` if the the function `getUpdateInfo` could not be detected the status online -- NEW: first implementation of the initial external authentication (IEA), if it is actively used by the personalization process the binding between Applet and the eID-Service-Library exists. -If this is not active, the applet can currently still be used, even without binding. -- NEW: function `deletePersonalization` is implemented and sets the status of the eID-Applet to `APPLET_UNUSABLE` -- NEW: A mandatory tag is required in the `AndroidManifest` that must contain a additional `TSMSServiceId` attribute. The value is the `ServiceId` from the TSMS that must be specified for eID-Client. Example: +- NEW: function `getSmartEidStatus` returns `UNAVAILABLE` if the the function `getUpdateInfo` could + not be detected the status online +- NEW: first implementation of the initial external authentication (IEA), if it is actively used by + the personalization process the binding between Applet and the eID-Service-Library exists. + If this is not active, the applet can currently still be used, even without binding. +- NEW: function `deletePersonalization` is implemented and sets the status of the eID-Applet + to `APPLET_UNUSABLE` +- NEW: A mandatory tag is required in the `AndroidManifest` that must contain a + additional `TSMSServiceId` attribute. The value is the `ServiceId` from the TSMS that must be + specified for eID-Client. Example: + ```xml @@ -150,10 +338,12 @@ _2021-10-14_ - NEW: Upgrade TSM-API SDK to v0.6.1 (tsm-api-sdk-0.6.1-20210916-release.aar) - NEW: first version of the function `getUpdateInfo` - execute the `TSM#performDeviceCheck` function - - currently the following return values are to be expected: `INTERNAL_ERROR`, `NO_PROVISIONING`, `UNAVAILABLE` and `UP_TO_DATE` + - currently the following return values are to be expected: `INTERNAL_ERROR`, `NO_PROVISIONING` + , `UNAVAILABLE` and `UP_TO_DATE` - if the provisioned applet be personalized, `UP_TO_DATE` is returned - NEW: first version of the function `getSmartEidStatus` - - currently the following return values are to be expected: `INTERNAL_ERROR`, `UNAVAILABLE`, `NO_PROVISIONING`, `NO_PERSONALIZATION`, `PERSONALIZED_READY` and `APPLET_UNUSABLE` + - currently the following return values are to be expected: `INTERNAL_ERROR`, `UNAVAILABLE` + , `NO_PROVISIONING`, `NO_PERSONALIZATION`, `PERSONALIZED_READY` and `APPLET_UNUSABLE` - NEW: `deletePersonalization` function returns only the static value `UNSUPPORTED` ## Version 0.5.0 @@ -166,10 +356,12 @@ _2021-09-22_ ### eid-applet-service-lib -- NEW: proper return values for the `installApplet` and `deleteApplet` functions are generated, according to the TR-03165 +- NEW: proper return values for the `installApplet` and `deleteApplet` functions are generated, + according to the TR-03165 - NEW: implementation of the `finalizePersonalization` function - NEW: personalization of the generated initial-eID-PIN -- NEW: late initialization of the `TSMAPIService` implemented, service binding is performed only before the first use +- NEW: late initialization of the `TSMAPIService` implemented, service binding is performed only + before the first use ## Version 0.4.4 @@ -177,7 +369,8 @@ _2021-09-06_ ### eid-applet-service-lib -- FIX: Updated TSM-API service version tag parameter value from 0.1.0 to 1.0.0 required for TSM_API SDK v0.5.0 +- FIX: Updated TSM-API service version tag parameter value from 0.1.0 to 1.0.0 required for TSM_API + SDK v0.5.0 ## Version 0.4.3 @@ -210,8 +403,10 @@ _2021-08-09_ ### eid-applet-service-lib -- New: first integration of the TMS-API-SDK (tsm-api-sdk-0.3.0-20210705-release.aar / TR-03165 v0.6 Draft) - - Provisioning (`InstallServiceCommand`, `ActivateServiceCommand`) and Deletion (`TerminateService`) of the eID-Applet possible +- New: first integration of the TMS-API-SDK (tsm-api-sdk-0.3.0-20210705-release.aar / TR-03165 v0.6 + Draft) + - Provisioning (`InstallServiceCommand`, `ActivateServiceCommand`) and + Deletion (`TerminateService`) of the eID-Applet possible - Personalization untested so far - upgrade `Service#installApplet()` function - add `Service#deleteApplet()` function @@ -224,7 +419,8 @@ _2021-08-09_ ### eid_applet_interface/jni-bridge - New: interface upgrade to v0.9.0 -- New: attach the current thread in some functions to get the current `JNIEnv` of the calling function +- New: attach the current thread in some functions to get the current `JNIEnv` of the calling + function ## Version 0.3.0 @@ -232,7 +428,8 @@ _2021-07-13_ ### eid-applet-service-lib -- New: Support the SELECT DF_EID that is not supported by the Android OMAPI implementation. The latest eID-Applet must be used (4a0f7c9f). +- New: Support the SELECT DF_EID that is not supported by the Android OMAPI implementation. The + latest eID-Applet must be used (4a0f7c9f). ### eid_applet_interface/jni-bridge @@ -252,14 +449,14 @@ _2021-06-30_ - `Service#appletStatus` returns only the status `AppletStatus#READY` - `Service#installApplet` returns only the status `ServiceResult#SUCCESS` - `Service#performPersonalization` returns only the `GenericDataResult` - with `ServiceResult#SUCCESS` and the RAPDU `9000` + with `ServiceResult#SUCCESS` and the RAPDU `9000` ### eid_applet_interface/jni-bridge - New: interface upgrade to v0.7.11 - New: Added class `EidAppletServiceAndroid` for better testability of the jni-bridge -- New: `eid_applet_interface` implementation instantiates and delegates now the functions of the class `EidAppletServiceAndroid` - +- New: `eid_applet_interface` implementation instantiates and delegates now the functions of the + class `EidAppletServiceAndroid` ## Version 0.1.2 @@ -274,7 +471,6 @@ _2021-04-29_ - Fix: use the `getClassLoader` method of the `android.app.NativeActivity` instance to prevent the `ClassNotFoundException` for the `Service.kt` - ## Version 0.1.1 _2021-04-21_ @@ -292,13 +488,12 @@ _2021-04-21_ - New: currently used sdk version is tested within the library initialization process - ## Version 0.1.0 _2021-04-01_ Initial version of the eid-applet-service-lib, which reflects the current work status and is used exclusively for initial integration. + - eid_applet_interface/jni-bridge version 0.7.5 - uses the legacy TSMAPI Client v0.6.1 from the project Optimos - diff --git a/src/external/smart/README.md b/src/external/smart/README.md new file mode 100644 index 000000000..45f8298e4 --- /dev/null +++ b/src/external/smart/README.md @@ -0,0 +1,52 @@ +eid-applet-service jni bridge +============================= + +- Current `eid_applet_interface.h` version: `0.23.0` +- Current `eid-applet-service-lib.aar` version: `1.1.0` + +## Description + +Creates the interface between the `eID Client` (AA2) application and the +`eid-applet-service-lib` (delivered as .aar - android archive) + +## Usage + +To use the service library, it must first be initialized correctly. The +function `initializeService(JNIEnv *mEnv, jobject mApplicationContext)` +must be called so that the `JNIEnv` reference and the android +`ApplicationContext` can be passed correctly. If the functionality is no +longer needed, the service can be released by the function +`shutdownService()`. If a function is called without previous +initialization of the library, the return value of the function contains +a corresponding error message. The function could not be executed +successfully. + +## Additional remarks + +- Currently used ndk version: `25.2.9519653` + +License +------- + +EN version: + +``` +Copyright (C) 2023 by Bundesdruckerei GmbH and Governikus GmbH & Co. KG + +The Software is licensed under EUPL-1.2, which can be downloaded from +https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 in a language of the European Union. +The German version of the EUPL-1.2 is available in LICENSE-DE.txt, the English version in +the LICENSE.txt. +``` + +DE version: + +``` +Copyright (C) 2023 by Bundesdruckerei GmbH and Governikus GmbH & Co. KG + +Die vorliegende Software steht unter der Lizenz EUPL-1.2, die unter +https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 in einer Sprache der Europäischen +Union heruntergeladen werden kann. Die deutsche Fassung der EUPL-1.2 liegt als Datei LICENSE-DE.txt +vor, die englische Fassung in der LICENSE.txt. +``` + diff --git a/src/external/smart/eid_applet_interface.cpp b/src/external/smart/eid_applet_interface.cpp index d4316e5df..adfed81dd 100644 --- a/src/external/smart/eid_applet_interface.cpp +++ b/src/external/smart/eid_applet_interface.cpp @@ -1,10 +1,12 @@ -// -// Copyright (C) 2021 Bundesdruckerei GmbH -// +/* + * Copyright (C) 2023 by Bundesdruckerei GmbH and Governikus GmbH & Co. KG + * Licensed under the EUPL-1.2 + */ #include "eid_applet_interface.h" #include "eid_applet_service_android.h" #include "eid_applet_utils.h" +#include #include @@ -13,7 +15,9 @@ using namespace appletUtils; #if defined(__ANDROID__) -EidAppletServiceAndroid* eidAppletService = nullptr; +EidAppletServiceAndroid* eidAppletService = nullptr; + +std::mutex interfaceMutex; //! Static ProgressHandler object static ProgressHandler progressHandler = nullptr; @@ -24,10 +28,10 @@ static ProgressHandler progressHandler = nullptr; \return The status of the Smart-eID e.g. EidStatus::NO_PERSONALIZATION for the eID-Applet. */ EidStatus getSmartEidStatus() { + const std::lock_guard guard(interfaceMutex); if (eidAppletService) { return eidAppletService->getSmartEidStatus(); } - return EidStatus::INTERNAL_ERROR; } @@ -37,14 +41,16 @@ EidStatus getSmartEidStatus() { //! an online-check. /*! - \return The updateInfo of the Smart-eID e.g. EidUpdateInfo::UPDATE_AVAILABLE for the eID-Applet. + \return EidSupportStatusResult with supportInfo of the Smart-eID e.g. + EidSupportStatus::UPDATE_AVAILABLE for the eID-Applet. */ -EidUpdateInfo getUpdateInfo() { +EidSupportStatusResult getSmartEidSupportInfo() { + const std::lock_guard guard(interfaceMutex); if (eidAppletService) { - return eidAppletService->getUpdateInfo(); + return eidAppletService->getSmartEidSupportInfo(); } - return EidUpdateInfo::INTERNAL_ERROR; + return {EidServiceResult::ERROR, EidSupportStatus::INTERNAL_ERROR}; } @@ -61,14 +67,15 @@ GenericDataResult initializeService( JNIEnv* env, jobject applicationContext, const std::string& pServiceId, - const std::string& pVersionTag, - const std::string& pSsdAid) { + const std::string& pSsdAid, + const std::string& pVersionTag) { + const std::lock_guard guard(interfaceMutex); if (eidAppletService) { return {EidServiceResult::ERROR, "Service is already initialized"}; } - eidAppletService = new EidAppletServiceAndroid(env, applicationContext); - return eidAppletService->initializeService(pServiceId, pVersionTag, pSsdAid); + eidAppletService = new EidAppletServiceAndroid(env, applicationContext); + return eidAppletService->initializeService(pServiceId, pSsdAid, pVersionTag); } @@ -79,6 +86,7 @@ GenericDataResult initializeService( \return GenericDataResult with byte2hex encoded APDU response */ GenericDataResult performAPDUCommand(const std::string& pCommandApdu) { + const std::lock_guard guard(interfaceMutex); if (eidAppletService) { return eidAppletService->performAPDUCommand(pCommandApdu); } @@ -95,6 +103,7 @@ GenericDataResult performAPDUCommand(const std::string& pCommandApdu) { \return EidServiceResult */ EidServiceResult installSmartEid(const ProgressHandler& pHandler) { + const std::lock_guard guard(interfaceMutex); if (eidAppletService) { progressHandler = pHandler; EidServiceResult result = eidAppletService->installSmartEid(); @@ -114,6 +123,7 @@ EidServiceResult installSmartEid(const ProgressHandler& pHandler) { \return EidServiceResult */ EidServiceResult deleteSmartEid(const ProgressHandler& pHandler) { + const std::lock_guard guard(interfaceMutex); if (eidAppletService) { progressHandler = pHandler; EidServiceResult result = eidAppletService->deleteSmartEid(); @@ -131,6 +141,7 @@ EidServiceResult deleteSmartEid(const ProgressHandler& pHandler) { \return EidServiceResult */ EidServiceResult deletePersonalization() { + const std::lock_guard guard(interfaceMutex); if (eidAppletService) { return eidAppletService->deletePersonalization(); } @@ -139,6 +150,21 @@ EidServiceResult deletePersonalization() { } +//! Return the ServiceInformationResult object. + +/*! + \return ServiceInformationResult + */ +ServiceInformationResult getServiceInformation() { + const std::lock_guard guard(interfaceMutex); + if (eidAppletService) { + return eidAppletService->getServiceInformation(); + } + + return {EidServiceResult::ERROR}; +} + + //! Performs personalization in a generic way controlled by Personalization Service /*! @@ -146,6 +172,7 @@ EidServiceResult deletePersonalization() { \return GenericDataResult with byte2hex encoded command response for the personalization step */ GenericDataResult performPersonalization(const std::string& pCommand) { + const std::lock_guard guard(interfaceMutex); if (eidAppletService) { return eidAppletService->performPersonalization(pCommand); } @@ -163,6 +190,7 @@ GenericDataResult performPersonalization(const std::string& pCommand) { \return InitializeResult with base64 encoded public key and signed challenge */ InitializeResult initializePersonalization(const std::string& pChallenge, const std::string& pPin) { + const std::lock_guard guard(interfaceMutex); if (eidAppletService) { return eidAppletService->initializePersonalization(pPin, pChallenge); } @@ -177,6 +205,7 @@ InitializeResult initializePersonalization(const std::string& pChallenge, const \return EidServiceResult */ EidServiceResult releaseAppletConnection() { + const std::lock_guard guard(interfaceMutex); if (eidAppletService) { return eidAppletService->releaseAppletConnection(); } @@ -194,9 +223,10 @@ EidServiceResult releaseAppletConnection() { \return PersonalizationResult mInitPin contains the initial-eID-PIN used for personalization. If the mInitPIN is blank, a new personalization must be started. */ -PersonalizationResult finalizePersonalization() { +PersonalizationResult finalizePersonalization(int status) { + const std::lock_guard guard(interfaceMutex); if (eidAppletService) { - return eidAppletService->finalizePersonalization(); + return eidAppletService->finalizePersonalization(status); } return {EidServiceResult::ERROR}; @@ -210,10 +240,13 @@ PersonalizationResult finalizePersonalization() { otherwise it contains an error message */ GenericDataResult shutdownService() { + const std::lock_guard guard(interfaceMutex); if (eidAppletService) { GenericDataResult result = eidAppletService->shutdownService(); - delete eidAppletService; - eidAppletService = nullptr; + if (result.mResult != EidServiceResult::ERROR) { + delete eidAppletService; + eidAppletService = nullptr; + } return result; } @@ -221,15 +254,83 @@ GenericDataResult shutdownService() { } +//! Performs the terminal and chip authentication. +//! Placeholder Impl for Android + +/*! + \param pTerminalCvcChain List representing the terminal certificate chain according to EAC1InputType in TR-03112-7 3.6.4.1. + The first element is the terminal certificate, the last element is the certificate signed by the + certificate referenced by the CAR in the prepareIdentification response. + The elements of the list are byte2hex encoded. Example: + 7f218201487f4e8201005f29010042104445445674494447564b333030303132 + 7f494f060a04007f00070202020203864104a7ba9a8cd0f294ea653ab42cb713 + 54af775d6fa98091dfe3af602cfe3837225a2e8573384b16d6fc9215815a9c47 + fbdd3fb0224a184a6146198d7ee5c77837585f200e444544454d4f5041413030 + 3436347f4c12060904007f0007030102025305000513ff075f25060201000301 + 015f2406020100040100655e732d060904007f00070301030180204ebb52e497 + c3549ca1102ecf55b6626c1afb00d2cdfcad369d37083ece26139e732d060904 + 007f00070301030280206ccf8efd02e71b274c8c4f29122310ef2d7ffdfb4c61 + 1fe267f8576da42e7ba25f37402b096b45c029b2184cba8d745431a6820e4bcb + b7ba14d3c7745dddec147cc1d208fe0547ebcc44e7384a52aafb39f7d83e43e6 + 15ad9a22b84cd911e75171e555 + \param pAuxiliaryData Authenticated Auxiliary Data according to EAC1InputType in TR-03112-7 3.6.4.1. + byte2hex encoded. Example: 67177315060904007f00070301040253083230323130333136 + \param pSignature Signature according to EAC2InputType TR-03112-7 3.6.4.2. + byte2hex encoded. Example: + 0d472d904137c057a9d7c34d675413326050549f71fc04aa625791dc5debedca + 20d6dce02bc11c2ad6b0b749e9440099924b429101255dfdb02029e720f06714 + \param pPin from AA2 validated 6 digit PIN, once the user entered the mobile-ID-PIN 2 times. + \param pEphemeralPublicKey EphemeralPublicKey according to EAC2InputType TR-03112-7 3.6.4.2. + byte2hex encoded. Example: + 045e5297e977a637b30834632934d1e00ade870053d740d64a5df9efb938bd29c4 + 682b803fc5857fc9ffe6aae16e4254c02b2cc8d861226501e152776954d6643d + \return TAandCAResult according to EAC2OutputType TR-03112-7 3.6.4.2., byte2hex encoded + */ +TAandCAResult performTAandCA(const std::list& pTerminalCvcChain, const std::string& pAuxiliaryData, + const std::string& pSignature, const std::string& pPin, + const std::string& pEphemeralPublicKey) { + (void) pTerminalCvcChain; + (void) pAuxiliaryData; + (void) pSignature; + (void) pPin; + (void) pEphemeralPublicKey; + return TAandCAResult {EidServiceResult::UNSUPPORTED, nullptr, nullptr, nullptr}; +} + + +//! Prepares the identification and returns the PrepareIdentificationResult. +//! Placeholder Impl for Android + +/*! + \param pChat CertificateHolderAuthorizationTemplate according to EAC1OutputType in TR-03112-7 3.6.4.1. + byte2hex encoded. Example: 7f4c12060904007f0007030102025305000513ff00 + \return UserAuthenticationResult according to EAC1OutputType in TR-03112-7 3.6.4.1., byte2hex encoded + */ +PrepareIdentificationResult prepareIdentification(const std::string& pChat) { + (void) pChat; + return PrepareIdentificationResult {EidServiceResult::UNSUPPORTED, nullptr, nullptr, nullptr}; +} + + +//! Get Challenge + +/*! + \return GenericDataResult with challenge according to EAC1OutputType in TR-03112-7 3.6.4.1. + byte2hex encoded and terminated with 9000. + */ +GenericDataResult getChallenge() { + return GenericDataResult {EidServiceResult::UNSUPPORTED}; +} + + #endif /** * function for relaying the info if handler is present */ - extern "C" -JNIEXPORT void JNICALL Java_de_bdr_eid_1applet_1service_1lib_tsm_ProgressUpdater_notify(JNIEnv* env __unused, +JNIEXPORT void JNICALL Java_de_bundesdruckerei_android_eid_1applet_1service_1lib_jni_NativeBridgeEventListener_notify(JNIEnv* env __unused, jobject thiz __unused, jint progress) { if (progressHandler != nullptr) { progressHandler(progress); diff --git a/src/external/smart/eid_applet_interface.h b/src/external/smart/eid_applet_interface.h index a4fc2164b..1b15f50ae 100644 --- a/src/external/smart/eid_applet_interface.h +++ b/src/external/smart/eid_applet_interface.h @@ -1,7 +1,36 @@ /* - * Copyright (C) 2021 Bundesdruckerei GmbH and Governikus GmbH + * Copyright (C) 2023 by Bundesdruckerei GmbH and Governikus GmbH & Co. KG + * Licensed under the EUPL-1.2 * - * v0.17.0 + * v0.23.0 + * + * +------------------------------+--------------+---------------+---------------+ + * | Function TOPIC | SE_CERTIFIED | SE_ENDORSED | HW_KEYSTORE | + * +------------------------------+--------------+---------------+---------------+ + * | GENERAL |--------------+---------------+---------------| + * | initializeService | X | X | X | + * | shutdownService | X | X | X | + * | getServiceInformation | X | X | X | + * | getSmartEidSupportInfo | X | X | X | + * | getSmartEidStatus | X | X | X | + * | DEVICE PREPARATION |--------------+---------------+---------------| + * | installSmartEid | X | | | + * | deleteSmartEid | X | | | + * | PERSONALIZATION |--------------+---------------+---------------| + * | initializePersonalization | X | X | X | + * | performPersonalization | X | X | X | + * | finalizePersonalization | X | X | X | + * | deletePersonalization | X | X | X | + * | releaseAppletConnection | X | | | + * | IDENTIFICATION |--------------+---------------+---------------| + * | performAPDUCommand | X | X | X 1) | + * | prepareIdentification | | | X 1) | + * | getChallenge | | | X 1) | + * | performTAandCA | | | X 1) | + * +------------------------------+--------------+---------------+---------------+ + * + * 1) performAPDUCommand is only partially implemented + and is supplemented by additional functions. */ #pragma once @@ -12,10 +41,10 @@ #include #include -#if defined(__APPLE__) - #include -#elif defined(__ANDROID__) +#if defined(__ANDROID__) #include +#elif defined(__APPLE__) + #include #endif @@ -27,14 +56,70 @@ */ using ProgressHandler = std::function; +// ------------------------------------------------------------------------------------------------- +// GENERAL +// ------------------------------------------------------------------------------------------------- + +#if defined(__ANDROID__) + +//! Performs initialization of eID-Applet-Service-Lib on Android. This method should be called from +//! the main thread / the thread that created the JVM + +/*! + \param env The android JNI Environment pointer. + \param applicationContext The android application context. + \param pServiceId The id of the service from the Trusted Service Management System. + \param pSsdAid AID of the specific security domain that is created for the given + Trusted Service Management Service. + \param pVersionTag Optional ServiceVersionTag for the Trusted Service Management usage. + By default, this string can be left blank. Passing a specific ServiceVersionTag + is required only in debug case. + \return GenericDataResult mData is blank if mResult is equal to EidServiceResult::SUCCESS, + otherwise it contains an error message + */ +GenericDataResult initializeService( + JNIEnv* env, + jobject applicationContext, + const std::string& pServiceId, + const std::string& pSsdAid, + const std::string& pVersionTag = ""); + +#else + +//! Performs initialization of eID-Applet-Service-Lib. + +/*! + \return GenericDataResult mData is blank if mResult is equal to EidServiceResult::SUCCESS, + otherwise it contains an error message + */ +GenericDataResult initializeService(); + +#endif + +//! Release all resources and shut down the eID-Applet-Service-Lib on Android + +/*! + \return GenericDataResult mData is blank if mResult is equal to EidServiceResult::SUCCESS, + otherwise it contains an error message + */ +GenericDataResult shutdownService(); + +//! Request the service information of the Smart-eID. This function does not include an online-check. + +/*! + \return ServiceInformationResult + */ +ServiceInformationResult getServiceInformation(); + //! Provides information of available updates of the installed eID-Applet and/or CSP implementation //! or whether the device is supported by Trusted Service Management System. The function includes //! an online-check. /*! - \return The updateInfo of the Smart-eID e.g. EidUpdateInfo::UPDATE_AVAILABLE for the eID-Applet. + \return EidSupportStatusResult with the supportInfo of the Smart-eID + e.g. EidSupportStatus::UPDATE_AVAILABLE for the eID-Applet. */ -EidUpdateInfo getUpdateInfo(); +EidSupportStatusResult getSmartEidSupportInfo(); //! Provides the current Smart-eID Status. This function does not include an online-check. @@ -43,6 +128,10 @@ EidUpdateInfo getUpdateInfo(); */ EidStatus getSmartEidStatus(); +// ------------------------------------------------------------------------------------------------- +// DEVICE PREPARATION +// ------------------------------------------------------------------------------------------------- + //! Performs the remote provisioning of the eID-applet from the Trusted Service Management System //! to the eSE on this device, or the ATM module initialization and the license check. @@ -61,13 +150,21 @@ EidServiceResult installSmartEid(const ProgressHandler& pHandler); */ EidServiceResult deleteSmartEid(const ProgressHandler& pHandler); -//! Performs APDU command +// ------------------------------------------------------------------------------------------------- +// PERSONALIZATION +// ------------------------------------------------------------------------------------------------- + +//! Performs initialization of the Personalization /*! - \param pCommandApdu byte2hex encoded APDU - \return GenericDataResult with byte2hex encoded APDU response + \param pChallenge base64 encoded challenge for key attestation. + \param pPin from AA2 validated 6 digit PIN, once the user entered the mobile-ID-PIN 2 times. + It is only required for HW_KEYSTORE and will be ignored in all other cases. + \return InitializeResult with base64 encoded public key and signed challenge */ -GenericDataResult performAPDUCommand(const std::string& pCommandApdu); +InitializeResult initializePersonalization( + const std::string& pChallenge, + const std::string& pPin = ""); //! Performs personalization in a generic way controlled by Personalization Service @@ -77,18 +174,18 @@ GenericDataResult performAPDUCommand(const std::string& pCommandApdu); */ GenericDataResult performPersonalization(const std::string& pCommand); -//! Performs initialization of the Personalization +//! Finalize the personalization flow and provide the init-eID-PIN as a return value. This function call +//! also closes the channel to the Supplementary Security Domain from the Service Provider and adjusts +//! the EidStatus in an error event accordingly. +//! Thus, this function must also be called in the event of an error, e.g. if personalization flow has +//! been interrupted. /*! - \param pChallenge base64 encoded challenge for key attestation. - \param pPin from AA2 validated 6 digit PIN, once the user entered the mobile-ID-PIN 2 times. - It is only required for HW_KEYSTORE and will be ignored in all other cases. - \return InitializeResult with base64 encoded public key and signed challenge + \param status The status code of the performed personalization. + \return PersonalizationResult mInitPin contains the initial-eID-PIN used for personalization. + If the mInitPIN is blank, a new personalization must be started. */ -InitializeResult initializePersonalization( - const std::string& pChallenge, - const std::string& pPin = "" - ); +PersonalizationResult finalizePersonalization(int status = 0); //! Delete Personalization from eID Applet. @@ -97,16 +194,24 @@ InitializeResult initializePersonalization( */ EidServiceResult deletePersonalization(); +//! Closes any open channel to the SE. -#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR +/*! + \return EidServiceResult + */ +EidServiceResult releaseAppletConnection(); -//! Get Challenge +// ------------------------------------------------------------------------------------------------- +// IDENTIFICATION +// ------------------------------------------------------------------------------------------------- + +//! Performs APDU command /*! - \return GenericDataResult with challenge according to EAC1OutputType in TR-03112-7 3.6.4.1. - byte2hex encoded and terminated with 9000. + \param pCommandApdu byte2hex encoded APDU + \return GenericDataResult with byte2hex encoded APDU response */ -GenericDataResult getChallenge(); +GenericDataResult performAPDUCommand(const std::string& pCommandApdu); //! Prepares the identification and returns the PrepareIdentificationResult. @@ -117,6 +222,14 @@ GenericDataResult getChallenge(); */ PrepareIdentificationResult prepareIdentification(const std::string& pChat); +//! Get Challenge + +/*! + \return GenericDataResult with challenge according to EAC1OutputType in TR-03112-7 3.6.4.1. + byte2hex encoded and terminated with 9000. + */ +GenericDataResult getChallenge(); + //! Performs the terminal and chip authentication. /*! @@ -154,54 +267,3 @@ TAandCAResult performTAandCA( const std::string& pSignature, const std::string& pPin, const std::string& pEphemeralPublicKey); - -#elif defined(__ANDROID__) - -//! Performs initialization of eID-Applet-Service-Lib on Android. This method should be called from -//! the main thread / the thread that created the JVM - -/*! - \param env The android JNI Environment pointer. - \param applicationContext The android application context. - \param pServiceId The id of the service from the Trusted Service Management System. - \param pVersionTag The version tag of the Trusted Service Management Service. - \param pSsdAid AID of the specific security domain that is created for the given - Trusted Service Management Service. - \return GenericDataResult mData is blank if mResult is equal to EidServiceResult::SUCCESS, - otherwise it contains an error message - */ -GenericDataResult initializeService( - JNIEnv* env, - jobject applicationContext, - const std::string& pServiceId, - const std::string& pVersionTag, - const std::string& pSsdAid - ); - -//! Finalize the personalization flow and provide the init-eID-PIN as a return value. This function call -//! also closes the channel to the Supplementary Security Domain from the Service Provider. -//! Thus, this function must also be called in the event of an error, e.g. if personalization flow has -//! been interrupted. - -/*! - \return PersonalizationResult mInitPin contains the initial-eID-PIN used for personalization. - If the mInitPIN is blank, a new personalization must be started. - */ -PersonalizationResult finalizePersonalization(); - -//! Closes any open channel to the SE. - -/*! - \return EidServiceResult - */ -EidServiceResult releaseAppletConnection(); - -//! Release all resources and shut down the eID-Applet-Service-Lib on Android - -/*! - \return GenericDataResult mData is blank if mResult is equal to EidServiceResult::SUCCESS, - otherwise it contains an error message - */ -GenericDataResult shutdownService(); - -#endif diff --git a/src/external/smart/eid_applet_results.h b/src/external/smart/eid_applet_results.h index fa361ff4e..33361f339 100644 --- a/src/external/smart/eid_applet_results.h +++ b/src/external/smart/eid_applet_results.h @@ -1,62 +1,91 @@ /* - * Copyright (C) 2021 Bundesdruckerei GmbH and Governikus GmbH + * Copyright (C) 2023 by Bundesdruckerei GmbH and Governikus GmbH & Co. KG + * Licensed under the EUPL-1.2 * - * v0.17.0 + * v0.23.0 */ #pragma once #include -#if defined(__APPLE__) - #include -#endif - /** * States of the eID-Applet and Smart-eID. */ enum class EidStatus : int { - ///< The device is not supported or the initial online-check - ///< with function #getUpdateInfo() has not yet been executed. - UNAVAILABLE = 0x0100010, - ///< The device is support but a provisioning is required. + ///< The Smart eID is not provisioned on this device. The support of + ///< the device is unknown. Nothing is currently installed or initialized. + ///< Applet solution: The eID-Applet is not installed. + ///< Non-Applet solution: No KeyPair is present on the device. NO_PROVISIONING = 0x0100020, - ///< The eID-Applet is installed and a personalization of + ///< The Smart eID is provisioned on this device. A personalization is + ///< necessary. + ///< Applet solution: The eID-Applet is installed; a personalization of + ///< Smart eID is required. + ///< Non-Applet solution: KeyPair is present; a personalization of ///< Smart eID is required. NO_PERSONALIZATION = 0x0100030, - ///< Smart eID is either not personalized or personalized - ///< but not accessible, the eID-Applet must be deleted. - APPLET_UNUSABLE = 0x0100050, - ///< The eID-Applet is installed, Smart eID is personalized - ///< and accessible; the Smart eID is ready to be used. - ///< The status bytes of MSE SET AT (PACE) will provide the - ///< current PIN state (initial, operational or blocked). + ///< The Smart eID is provisioned on this device but is not accessible + ///< or is corrupted. The Smart eID must be deleted. + ///< Applet solution: The eID-Applet is installed, Smart eID is either not + ///< personalized or personalized but not accessible; the eID-Applet + ///< must be deleted + ///< Non-Applet solution: Smart eID is not accessible due to no longer + ///< fulfilled security requirements. + UNUSABLE = 0x0100050, + ///< The Smart eID is provisioned, personalized and accessible on this + ///< device. The Smart eID can be used. + ///< Applet solution: The eID-Applet is installed, personalized and + ///< accessible. + ///< Non-Applet solution: The non-Applet Solution is personalized and + ///< accessible. PERSONALIZED = 0x0300010, - ///< Smart-eID Status could not be detected due to an - ///< internal error. + ///< The required certificates for the Smart eID are expired + ///< Applet solution: not applicable + ///< Non-applet solution: The Smart eID is temporarily disabled. The + ///< certificates must be refreshed to turn the Smart eID fully functional + ///< again. + CERT_EXPIRED = 0x0100060, + ///< Request could not be processed successfully and the Smart eID + ///< state could not be determined. Process must be repeated. INTERNAL_ERROR = 0x1100000 }; /** - * Update-Info of the eID-Applet and Smart-eID. + * Support Status of the eID-Applet and Smart-eID. */ -enum class EidUpdateInfo : int { +enum class EidSupportStatus : int { ///< The device is not supported. + ///< Applet solution: The device is not supported by TSMS + ///< Non-Applet solution: The device is not supported e.g., does not + ///< offer required security mechanisms UNAVAILABLE = 0x0400010, - ///< Device is supported, but the update status cannot be - ///< detected because no eID-Applet is currently installed. - NO_PROVISIONING = 0x0400020, - ///< A new version of the already installed eID-Applet or - ///< CSP implementation or both is available and may be - ///< installed. The eID-Applet is either - ///< in state EidStatus::PROVISIONED or in one of - ///< EidStatus::PERSONALIZED. - UPDATE_AVAILABLE = 0x0400030, - ///< The installed eID-Applet is up to date. + ///< The device is supported for the Smart eID. Currently nothing is + ///< provisioned + ///< Applet solution: The device is supported by TSMS. + ///< Non-Applet solution: The device is supported and fulfills all + ///< security requirements for the non-Applet solution + AVAILABLE = 0x0400020, + ///< The Smart eID is supported, already provisioned and up to date + ///< on this device. + ///< Applet solution: Latest supported version of the eID-Applet is + ///< already installed. + ///< Non-Applet solution: All required certificates and keys are up to + ///< date. UP_TO_DATE = 0x0400040, - ///< Update-Info could not be acquired due to an - ///< internal error. + ///< The Smart eID is supported and already provisioned on this + ///< device but a new version is available. It is recommended to delete + ///< and reinstall the Smart eID so that the new version is provisioned. + ///< Applet solution: A new version of the eID-Applet or CSP + ///< implementation or both is available and may be installed on the + ///< device. + ///< Non-Applet solution: A Non-Applet solution is currently used on + ///< the device. The device is now also supported by the TSMS. + ///< Provisioning of the applet solution is available. + UPDATE_AVAILABLE = 0x0400030, + ///< The online check could not be processed successfully e.g., due to + ///< a network issue. Process must be repeated. INTERNAL_ERROR = 0x2100000 }; @@ -66,7 +95,19 @@ enum class EidServiceResult : int { INFO = 0x31000000, WARN = 0x32000000, ERROR = 0x33000000, - UNSUPPORTED = 0x34000000 + UNSUPPORTED = 0x34000000, + OVERLOAD_PROTECTION = 0x35000000, + UNDER_MAINTENANCE = 0x36000000, + NFC_NOT_ACTIVATED = 0x37000000, + INTEGRITY_CHECK_FAILED = 0x38000000, + NOT_AUTHENTICATED = 0x39000000, + NETWORK_CONNECTION_ERROR = 0x40000000 +}; + +enum class SmartEidType : int { + UNKNOWN = 0x02000010, + APPLET = 0x02000020, + NON_APPLET = 0x02000030 }; /** @@ -80,10 +121,25 @@ struct GenericDataResult { } - EidServiceResult mResult; + EidServiceResult mResult = EidServiceResult::UNDEFINED; std::string mData; }; +/** + * Return value for the getSmartEidSupportInfo. + */ +struct EidSupportStatusResult { + EidSupportStatusResult( + EidServiceResult result = EidServiceResult::UNDEFINED, + EidSupportStatus status = EidSupportStatus::INTERNAL_ERROR) + : mResult(result), mStatus(status) { + } + + + EidServiceResult mResult = EidServiceResult::UNDEFINED; + EidSupportStatus mStatus = EidSupportStatus::INTERNAL_ERROR; +}; + /** * mPreparePersonalizationData is blank if mResult is not equal to EidServiceResult::SUCCESS. */ @@ -114,7 +170,24 @@ struct PersonalizationResult { std::string mInitPIN; }; -#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR +/** + * Return value for the service information of the Smart-eID. + */ +struct ServiceInformationResult { + ServiceInformationResult( + EidServiceResult result = EidServiceResult::UNDEFINED, + SmartEidType type = SmartEidType::UNKNOWN, + const std::string& challengeType = "", + const std::string& libVersionName = "") + : mResult(result), mType(type), mChallengeType(challengeType), mLibVersionName(libVersionName) { + } + + + EidServiceResult mResult = EidServiceResult::UNDEFINED; + SmartEidType mType = SmartEidType::UNKNOWN; + std::string mChallengeType; + std::string mLibVersionName; +}; /** * mCertificationAuthorityReference, mEfCardAccess and mIdIcc are blank @@ -137,5 +210,3 @@ struct TAandCAResult { std::string mAuthenticationToken; std::string mNonce; }; - -#endif diff --git a/src/external/smart/eid_applet_service_android.cpp b/src/external/smart/eid_applet_service_android.cpp index 4f7fba1bb..2fdd7b2ae 100644 --- a/src/external/smart/eid_applet_service_android.cpp +++ b/src/external/smart/eid_applet_service_android.cpp @@ -1,6 +1,6 @@ /* - * Copyright (C) 2021 Bundesdruckerei GmbH and Governikus GmbH - * + * Copyright (C) 2023 by Bundesdruckerei GmbH and Governikus GmbH & Co. KG + * Licensed under the EUPL-1.2 */ #include "eid_applet_service_android.h" @@ -13,10 +13,8 @@ * \param env The android JNI Environment pointer. * \param applicationContext The android application context. */ -template -EidAppletServiceAndroid::EidAppletServiceAndroid( - JNIEnvironment* env, jobject applicationContext) : mEnv(env) { - +EidAppletServiceAndroid::EidAppletServiceAndroid( + JNIEnv* env, jobject applicationContext) : mEnv(env) { if (mEnv) { mApplicationContext = mEnv->NewGlobalRef(applicationContext); } @@ -26,16 +24,16 @@ EidAppletServiceAndroid::EidAppletServiceAnd /*! * Release all resources and shut down the eID-Applet-Service-Lib on Android */ -template -EidAppletServiceAndroid::~EidAppletServiceAndroid() { - //get environment of current thread - JNIEnvironment* curThreadEnv; - ThreadGuard guard(mJvm); - if (!getJNIEnvForCurrentThread(curThreadEnv, guard)) { +EidAppletServiceAndroid::~EidAppletServiceAndroid() { + JNIEnv* env; + ThreadGuard threadGuard(mJvm); + if (!getJNIEnvForCurrentThread(env, threadGuard)) { return; } - curThreadEnv->DeleteGlobalRef(mApplicationContext); + deleteGlobalRef(env, mJniServiceObj); + deleteGlobalRef(env, mJniServiceClz); + deleteGlobalRef(env, mApplicationContext); } @@ -46,13 +44,19 @@ EidAppletServiceAndroid::~EidAppletServiceAn * \result mData is blank if mResult is equal to EidServiceResult::SUCCESS, * otherwise it contains an error message */ -template -GenericDataResult EidAppletServiceAndroid::initializeService( +GenericDataResult EidAppletServiceAndroid::initializeService( const std::string& pServiceId, - const std::string& pVersionTag, - const std::string& pSsdAid) { + const std::string& pSsdAid, + const std::string& pVersionTag) { + + const std::lock_guard guard(serviceMutex); + if (mEnv == nullptr) { - return {EidServiceResult::ERROR, "missing JNIEnvironment"}; + return {EidServiceResult::ERROR, "missing JNIEnv"}; + } + + if (mApplicationContext == nullptr) { + return {EidServiceResult::ERROR, "missing ApplicationContext"}; } jint getJavaVMResult = mEnv->GetJavaVM(&mJvm); @@ -62,7 +66,7 @@ GenericDataResult EidAppletServiceAndroid::i } jclass jniServiceClzRef = findClass(mEnv, mApplicationContext, jniService::path); - if (exceptionCheck(mEnv)) { + if (exceptionCheck(mEnv)) { std::string msg = "missing class:"; msg.append(jniService::path); return {EidServiceResult::ERROR, msg}; @@ -70,7 +74,7 @@ GenericDataResult EidAppletServiceAndroid::i mJniServiceClz = reinterpret_cast(mEnv->NewGlobalRef(jniServiceClzRef)); jmethodID jniCtorMethodID = mEnv->GetMethodID(mJniServiceClz, jniService::stdInit, "()V"); - if (exceptionCheck(mEnv)) { + if (exceptionCheck(mEnv)) { std::string msg = "method not found:"; msg.append(jniService::path) .append("#") @@ -80,11 +84,12 @@ GenericDataResult EidAppletServiceAndroid::i jobject handler = mEnv->NewObject(mJniServiceClz, jniCtorMethodID); mJniServiceObj = mEnv->NewGlobalRef(handler); - - jmethodID jniInitMethodID = mEnv->GetMethodID(mJniServiceClz, + jmethodID jniInitMethodID = mEnv->GetMethodID( + mJniServiceClz, jniService::init, jniService::sig); - if (exceptionCheck(mEnv)) { + deleteLocalRef(mEnv, handler); + if (exceptionCheck(mEnv)) { std::string msg = "method not found:"; msg.append(jniService::path) .append("#") @@ -101,12 +106,13 @@ GenericDataResult EidAppletServiceAndroid::i jniInitMethodID, mApplicationContext, serviceId, - versionTag, - ssdAid); - bool hasError = exceptionCheck(mEnv); - mEnv->DeleteLocalRef(serviceId); - mEnv->DeleteLocalRef(versionTag); - mEnv->DeleteLocalRef(ssdAid); + ssdAid, + versionTag); + bool hasError = exceptionCheck(mEnv); + deleteLocalRef(mEnv, serviceId); + deleteLocalRef(mEnv, versionTag); + deleteLocalRef(mEnv, ssdAid); + deleteLocalRef(mEnv, jniServiceClzRef); if (hasError) { std::string msg = "initialization of the eid_applet_service_lib failed"; @@ -118,15 +124,31 @@ GenericDataResult EidAppletServiceAndroid::i clazz, jniGenericDataResult::result, jniGenericDataResult::resultType); - int result = mEnv->GetIntField(obj, fidResult); + auto result = mEnv->GetObjectField(obj, fidResult); auto fidData = mEnv->GetFieldID( clazz, jniGenericDataResult::data, jniGenericDataResult::dataType); - auto jsData = reinterpret_cast(mEnv->GetObjectField(obj, fidData)); - return {getEidServiceResult(result), getString(mEnv, jsData)}; + auto fidObjField = mEnv->GetObjectField(obj, fidData); + auto jsData = reinterpret_cast(fidObjField); + + jclass serviceResultClazz = findClass(mEnv, mApplicationContext, jniServiceResult::path); + jmethodID getValueMethodID = mEnv->GetStaticMethodID(serviceResultClazz, + jniServiceResult::getValue, + jniServiceResult::sigGetValue); + + int serviceResultCode = mEnv->CallStaticIntMethod(serviceResultClazz, getValueMethodID, result); + GenericDataResult gDResult(getEidServiceResult(serviceResultCode), getString(mEnv, jsData)); + + deleteLocalRef(mEnv, result); + deleteLocalRef(mEnv, fidObjField); + deleteLocalRef(mEnv, obj); + deleteLocalRef(mEnv, clazz); + deleteLocalRef(mEnv, serviceResultClazz); + + return gDResult; } @@ -137,48 +159,46 @@ GenericDataResult EidAppletServiceAndroid::i * * \return EidServiceResult */ -template -EidServiceResult EidAppletServiceAndroid::installSmartEid() { - //get environment of current thread - JNIEnvironment* curThreadEnv; - ThreadGuard guard(mJvm); - if (!getJNIEnvForCurrentThread(curThreadEnv, guard)) { +EidServiceResult EidAppletServiceAndroid::installSmartEid() { + + const std::lock_guard guard(serviceMutex); + + JNIEnv* env; + ThreadGuard threadGuard(mJvm); + if (!getJNIEnvForCurrentThread(env, threadGuard) || mApplicationContext == nullptr || mJniServiceClz == nullptr || mJniServiceObj == nullptr) { return EidServiceResult::ERROR; } - //call installApplet method - jclass serviceClass = findClass(curThreadEnv, mApplicationContext, jniService::path); - jmethodID installSmartEidMethodID = curThreadEnv->GetMethodID( - serviceClass, + + jmethodID installSmartEidMethodID = env->GetMethodID( + mJniServiceClz, jniService::installSmartEidMethod, jniService::installSmartEidMethodSig); - jobject resultCode = curThreadEnv->CallObjectMethod( + jobject resultCode = env->CallObjectMethod( mJniServiceObj, installSmartEidMethodID); - if (exceptionCheck(curThreadEnv)) { + if (exceptionCheck(env)) { return EidServiceResult::ERROR; } - //cast ServiceResult to int - jclass serviceResultClass = findClass( - curThreadEnv, - mApplicationContext, - jniServiceResult::path); - - jmethodID methodId = curThreadEnv->GetStaticMethodID( + jclass serviceResultClass = findClass(env, mApplicationContext, jniServiceResult::path); + jmethodID getValueMethodID = env->GetStaticMethodID( serviceResultClass, jniServiceResult::getValue, jniServiceResult::sigGetValue); - int intResultCode = curThreadEnv->CallStaticIntMethod( + int serviceResultCode = env->CallStaticIntMethod( serviceResultClass, - methodId, + getValueMethodID, resultCode); - if (exceptionCheck(curThreadEnv)) { + if (exceptionCheck(env)) { return EidServiceResult::ERROR; } - return EidServiceResult(intResultCode); + deleteLocalRef(env, resultCode); + deleteLocalRef(env, serviceResultClass); + + return EidServiceResult(serviceResultCode); } @@ -187,48 +207,47 @@ EidServiceResult EidAppletServiceAndroid::in * * \return EidServiceResult */ -template -EidServiceResult EidAppletServiceAndroid::deleteSmartEid() { - //get environment of current thread - JNIEnvironment* curThreadEnv; - ThreadGuard guard(mJvm); - if (!getJNIEnvForCurrentThread(curThreadEnv, guard)) { +EidServiceResult EidAppletServiceAndroid::deleteSmartEid() { + + const std::lock_guard guard(serviceMutex); + + JNIEnv* env; + ThreadGuard threadGuard(mJvm); + if (!getJNIEnvForCurrentThread(env, threadGuard) || mApplicationContext == nullptr || mJniServiceClz == nullptr || mJniServiceObj == nullptr) { return EidServiceResult::ERROR; } - //call deleteApplet method - jclass serviceClass = findClass(curThreadEnv, mApplicationContext, jniService::path); - jmethodID deleteSmartEidMethodID = curThreadEnv->GetMethodID( - serviceClass, + + jmethodID deleteSmartEidMethodID = env->GetMethodID( + mJniServiceClz, jniService::deleteSmartEidMethod, jniService::deleteSmartEidMethodSig); - jobject resultCode = curThreadEnv->CallObjectMethod( + jobject resultCode = env->CallObjectMethod( mJniServiceObj, deleteSmartEidMethodID); - if (exceptionCheck(curThreadEnv)) { + if (exceptionCheck(env)) { return EidServiceResult::ERROR; } - //cast ServiceResult to int - jclass serviceResultClass = findClass( - curThreadEnv, - mApplicationContext, - jniServiceResult::path); + jclass serviceResultClass = findClass(env, mApplicationContext, jniServiceResult::path); - jmethodID methodId = curThreadEnv->GetStaticMethodID( + jmethodID getValueMethodID = env->GetStaticMethodID( serviceResultClass, jniServiceResult::getValue, jniServiceResult::sigGetValue); - int intResultCode = curThreadEnv->CallStaticIntMethod( + int serviceResultCode = env->CallStaticIntMethod( serviceResultClass, - methodId, + getValueMethodID, resultCode); - if (exceptionCheck(curThreadEnv)) { + if (exceptionCheck(env)) { return EidServiceResult::ERROR; } - return EidServiceResult(intResultCode); + deleteLocalRef(env, resultCode); + deleteLocalRef(env, serviceResultClass); + + return EidServiceResult(serviceResultCode); } @@ -237,48 +256,46 @@ EidServiceResult EidAppletServiceAndroid::de * * \return EidServiceResult */ -template -EidServiceResult EidAppletServiceAndroid::deletePersonalization() { - //get environment of current thread - JNIEnvironment* curThreadEnv; - ThreadGuard guard(mJvm); - if (!getJNIEnvForCurrentThread(curThreadEnv, guard)) { +EidServiceResult EidAppletServiceAndroid::deletePersonalization() { + + const std::lock_guard guard(serviceMutex); + + JNIEnv* env; + ThreadGuard threadGuard(mJvm); + if (!getJNIEnvForCurrentThread(env, threadGuard) || mApplicationContext == nullptr || mJniServiceClz == nullptr || mJniServiceObj == nullptr) { return EidServiceResult::ERROR; } - //call deletePersonalization method - jclass serviceClass = findClass(curThreadEnv, mApplicationContext, jniService::path); - jmethodID deletePersonalizationMethodID = curThreadEnv->GetMethodID( - serviceClass, + + jmethodID deletePersonalizationMethodID = env->GetMethodID( + mJniServiceClz, jniService::deletePersonalizationMethod, jniService::deletePersonalizationMethodSig); - jobject resultCode = curThreadEnv->CallObjectMethod( + jobject resultCode = env->CallObjectMethod( mJniServiceObj, deletePersonalizationMethodID); - if (exceptionCheck(curThreadEnv)) { + if (exceptionCheck(env)) { return EidServiceResult::ERROR; } - //cast ServiceResult to int - jclass serviceResultClass = findClass( - curThreadEnv, - mApplicationContext, - jniServiceResult::path); - - jmethodID methodId = curThreadEnv->GetStaticMethodID( + jclass serviceResultClass = findClass(env, mApplicationContext, jniServiceResult::path); + jmethodID getValueMethodID = env->GetStaticMethodID( serviceResultClass, jniServiceResult::getValue, jniServiceResult::sigGetValue); - int intResultCode = curThreadEnv->CallStaticIntMethod( + int serviceResultCode = env->CallStaticIntMethod( serviceResultClass, - methodId, + getValueMethodID, resultCode); - if (exceptionCheck(curThreadEnv)) { + if (exceptionCheck(env)) { return EidServiceResult::ERROR; } - return EidServiceResult(intResultCode); + deleteLocalRef(env, resultCode); + deleteLocalRef(env, serviceResultClass); + + return EidServiceResult(serviceResultCode); } @@ -288,55 +305,72 @@ EidServiceResult EidAppletServiceAndroid::de * \param pCommandApdu byte2hex encoded APDU * \return GenericDataResult with byte2hex encoded APDU response */ -template -GenericDataResult EidAppletServiceAndroid::performAPDUCommand( +GenericDataResult EidAppletServiceAndroid::performAPDUCommand( const std::string& pCommandApdu) { + + const std::lock_guard guard(serviceMutex); + if (pCommandApdu.empty()) { return {EidServiceResult::ERROR, "command APDU should not be empty"}; } - //get environment of current thread - JNIEnvironment* curThreadEnv; - ThreadGuard guard(mJvm); - if (!getJNIEnvForCurrentThread(curThreadEnv, guard)) { + JNIEnv* env; + ThreadGuard threadGuard(mJvm); + if (!getJNIEnvForCurrentThread(env, threadGuard) || mApplicationContext == nullptr || mJniServiceClz == nullptr || mJniServiceObj == nullptr) { return {EidServiceResult::ERROR, "Current thread of the caller could not be attached"}; } - jclass serviceClass = findClass(curThreadEnv, mApplicationContext, jniService::path); - jmethodID performMethodID = curThreadEnv->GetMethodID( - serviceClass, + jmethodID performMethodID = env->GetMethodID( + mJniServiceClz, jniService::performAPDUCommandMethod, jniService::performAPDUCommandMethodSig); - jstring apdu = curThreadEnv->NewStringUTF(pCommandApdu.c_str()); - jobject obj = curThreadEnv->CallObjectMethod(mJniServiceObj, performMethodID, apdu); - bool hasError = exceptionCheck(curThreadEnv); - curThreadEnv->DeleteLocalRef(apdu); + jstring apdu = env->NewStringUTF(pCommandApdu.c_str()); + jobject obj = env->CallObjectMethod(mJniServiceObj, performMethodID, apdu); + bool hasError = exceptionCheck(env); + deleteLocalRef(env, apdu); + if (hasError) { return {EidServiceResult::ERROR, "call of the performAPDUCommand function failed"}; } - auto clazz = curThreadEnv->GetObjectClass(obj); + auto clazz = env->GetObjectClass(obj); - auto fidResult = curThreadEnv->GetFieldID( + auto fidResult = env->GetFieldID( clazz, jniGenericDataResult::result, jniGenericDataResult::resultType); - int result = curThreadEnv->GetIntField(obj, fidResult); + auto result = env->GetObjectField(obj, fidResult); - auto fidData = curThreadEnv->GetFieldID( + auto fidData = env->GetFieldID( clazz, jniGenericDataResult::data, jniGenericDataResult::dataType); - auto jsData = reinterpret_cast(curThreadEnv->GetObjectField(obj, fidData)); - std::string data = getString(curThreadEnv, jsData); + auto objField = env->GetObjectField(obj, fidData); + auto jsData = reinterpret_cast(objField); + + std::string data = getString(env, jsData); if (data.empty()) { return {EidServiceResult::ERROR, "response APDU should not be empty"}; } - return {getEidServiceResult(result), data}; + jclass serviceResultClazz = findClass(env, mApplicationContext, jniServiceResult::path); + jmethodID getValueMethodID = env->GetStaticMethodID(serviceResultClazz, + jniServiceResult::getValue, + jniServiceResult::sigGetValue); + + int serviceResultCode = env->CallStaticIntMethod(serviceResultClazz, getValueMethodID, result); + GenericDataResult gDResult(getEidServiceResult(serviceResultCode), data); + + deleteLocalRef(env, result); + deleteLocalRef(env, objField); + deleteLocalRef(env, obj); + deleteLocalRef(env, serviceResultClazz); + deleteLocalRef(env, clazz); + + return gDResult; } @@ -347,10 +381,12 @@ GenericDataResult EidAppletServiceAndroid::p * \param pChallenge challenge for key attestation * \return InitializeResult with public key and signed challenge */ -template -InitializeResult EidAppletServiceAndroid::initializePersonalization( +InitializeResult EidAppletServiceAndroid::initializePersonalization( const std::string& pPin, const std::string& pChallenge) { + + const std::lock_guard guard(serviceMutex); + if (pPin.empty()) { // do nothing: Entering the eID-PIN is currently not necessary for Android here } @@ -359,51 +395,66 @@ InitializeResult EidAppletServiceAndroid::in return {EidServiceResult::ERROR, "Challenge should not be empty"}; } - //get environment of current thread - JNIEnvironment* curThreadEnv; - ThreadGuard guard(mJvm); - if (!getJNIEnvForCurrentThread(curThreadEnv, guard)) { + JNIEnv* env; + ThreadGuard threadGuard(mJvm); + if (!getJNIEnvForCurrentThread(env, threadGuard) || mApplicationContext == nullptr || mJniServiceClz == nullptr || mJniServiceObj == nullptr) { return {EidServiceResult::ERROR, "Current thread of the caller could not be attached"}; } - jmethodID initializePersonalizationMethodID = curThreadEnv->GetMethodID( + jmethodID initializePersonalizationMethodID = env->GetMethodID( mJniServiceClz, jniService::initializePersonalizationMethod, jniService::initializePersonalizationMethodSig); - jstring challenge = curThreadEnv->NewStringUTF(pChallenge.c_str()); - jobject obj = curThreadEnv->CallObjectMethod(mJniServiceObj, + jstring challenge = env->NewStringUTF(pChallenge.c_str()); + jobject obj = env->CallObjectMethod( + mJniServiceObj, initializePersonalizationMethodID, challenge); - curThreadEnv->DeleteLocalRef(challenge); - if (exceptionCheck(curThreadEnv)) { + deleteLocalRef(env, challenge); + if (exceptionCheck(env)) { return {EidServiceResult::ERROR, "call of the initializePersonalization function failed"}; } - auto clazz = curThreadEnv->GetObjectClass(obj); - auto fidResult = curThreadEnv->GetFieldID(clazz, jniInitializeResult::result, + auto clazz = env->GetObjectClass(obj); + auto fidResult = env->GetFieldID(clazz, jniInitializeResult::result, jniInitializeResult::resultType); - int result = curThreadEnv->GetIntField(obj, fidResult); + auto result = env->GetObjectField(obj, fidResult); - auto fidPPData = curThreadEnv->GetFieldID(clazz, + auto fidPPData = env->GetFieldID(clazz, jniInitializeResult::ppData, jniInitializeResult::ppDataType); - auto jsPPData = reinterpret_cast(curThreadEnv->GetObjectField(obj, - fidPPData)); - if (exceptionCheck(curThreadEnv)) { + + auto objField = env->GetObjectField(obj, fidPPData); + auto jsPPData = reinterpret_cast(objField); + + if (exceptionCheck(env)) { return {EidServiceResult::ERROR, "call of the initializePersonalization function failed (cannot read result)"}; } - std::string ppData = getString(curThreadEnv, jsPPData); + std::string ppData = getString(env, jsPPData); if (ppData.empty()) { return {EidServiceResult::ERROR, "PreparePersonalizationData should not be empty"}; } + jclass serviceResultClazz = findClass(env, mApplicationContext, jniServiceResult::path); + jmethodID getValueMethodID = env->GetStaticMethodID(serviceResultClazz, + jniServiceResult::getValue, + jniServiceResult::sigGetValue); + + int serviceResultCode = env->CallStaticIntMethod(serviceResultClazz, getValueMethodID, result); + InitializeResult initializeResult(getEidServiceResult(serviceResultCode), ppData); - return {getEidServiceResult(result), ppData}; + deleteLocalRef(env, result); + deleteLocalRef(env, objField); + deleteLocalRef(env, serviceResultClazz); + deleteLocalRef(env, clazz); + deleteLocalRef(env, obj); + + return initializeResult; } @@ -413,54 +464,70 @@ InitializeResult EidAppletServiceAndroid::in * \param pCommandPersonalization base64 encoded personalization step * \return GenericDataResult with base64 encoded personalization step response */ -template -GenericDataResult EidAppletServiceAndroid::performPersonalization(const std::string& pCommandPersonalization) { +GenericDataResult EidAppletServiceAndroid::performPersonalization(const std::string& pCommandPersonalization) { + + const std::lock_guard guard(serviceMutex); + if (pCommandPersonalization.empty()) { return {EidServiceResult::ERROR, "personalization C-APDU should not be empty"}; } - //get environment of current thread - JNIEnvironment* curThreadEnv; - ThreadGuard guard(mJvm); - if (!getJNIEnvForCurrentThread(curThreadEnv, guard)) { + JNIEnv* env; + ThreadGuard threadGuard(mJvm); + if (!getJNIEnvForCurrentThread(env, threadGuard) || mApplicationContext == nullptr || mJniServiceClz == nullptr || mJniServiceObj == nullptr) { return {EidServiceResult::ERROR, "Current thread of the caller could not be attached"}; } - jclass serviceClass = findClass(curThreadEnv, mApplicationContext, jniService::path); - jmethodID performMethodID = curThreadEnv->GetMethodID( - serviceClass, + jmethodID performMethodID = env->GetMethodID( + mJniServiceClz, jniService::performPersonalizationMethod, jniService::performPersonalizationMethodSig); - jstring apdu = curThreadEnv->NewStringUTF(pCommandPersonalization.c_str()); - jobject obj = curThreadEnv->CallObjectMethod(mJniServiceObj, performMethodID, apdu); - bool hasError = exceptionCheck(curThreadEnv); - curThreadEnv->DeleteLocalRef(apdu); + jstring apdu = env->NewStringUTF(pCommandPersonalization.c_str()); + jobject obj = env->CallObjectMethod(mJniServiceObj, performMethodID, apdu); + bool hasError = exceptionCheck(env); + + deleteLocalRef(env, apdu); + if (hasError) { return {EidServiceResult::ERROR, "call of the performPersonalization function failed"}; } - auto clazz = curThreadEnv->GetObjectClass(obj); + auto clazz = env->GetObjectClass(obj); - auto fidResult = curThreadEnv->GetFieldID( + auto fidResult = env->GetFieldID( clazz, jniGenericDataResult::result, jniGenericDataResult::resultType); - int result = curThreadEnv->GetIntField(obj, fidResult); + auto result = env->GetObjectField(obj, fidResult); - auto fidData = curThreadEnv->GetFieldID( + auto fidData = env->GetFieldID( clazz, jniGenericDataResult::data, jniGenericDataResult::dataType); - auto jsData = reinterpret_cast(curThreadEnv->GetObjectField(obj, fidData)); - std::string data = getString(curThreadEnv, jsData); + auto objField = env->GetObjectField(obj, fidData); + auto jsData = reinterpret_cast(objField); + std::string data = getString(env, jsData); if (data.empty()) { return {EidServiceResult::ERROR, "response APDU should not be empty"}; } + jclass serviceResultClazz = findClass(env, mApplicationContext, jniServiceResult::path); + jmethodID getValueMethodID = env->GetStaticMethodID(serviceResultClazz, + jniServiceResult::getValue, + jniServiceResult::sigGetValue); + + int serviceResultCode = env->CallStaticIntMethod(serviceResultClazz, getValueMethodID, result); + GenericDataResult gDResult(getEidServiceResult(serviceResultCode), data); - return {getEidServiceResult(result), data}; + deleteLocalRef(env, result); + deleteLocalRef(env, objField); + deleteLocalRef(env, serviceResultClazz); + deleteLocalRef(env, clazz); + deleteLocalRef(env, obj); + + return gDResult; } @@ -469,41 +536,59 @@ GenericDataResult EidAppletServiceAndroid::p * * \return a PersonalizationResult object with the init-eID-PIN */ -template -PersonalizationResult EidAppletServiceAndroid::finalizePersonalization() { - JNIEnvironment* curThreadEnv; - ThreadGuard guard(mJvm); - if (!getJNIEnvForCurrentThread(curThreadEnv, guard)) { +PersonalizationResult EidAppletServiceAndroid::finalizePersonalization(int status) { + const std::lock_guard guard(serviceMutex); + + JNIEnv* env; + ThreadGuard threadGuard(mJvm); + if (!getJNIEnvForCurrentThread(env, threadGuard) || mApplicationContext == nullptr || mJniServiceClz == nullptr || mJniServiceObj == nullptr) { return {EidServiceResult::ERROR}; } - jclass serviceClass = findClass(curThreadEnv, mApplicationContext, jniService::path); - jmethodID finalizePersonalizationMethodId = curThreadEnv->GetMethodID( - serviceClass, + jmethodID finalizePersonalizationMethodID = env->GetMethodID( + mJniServiceClz, jniService::finalizePersonalizationMethod, jniService::finalizePersonalizationMethodSig); - jobject obj = curThreadEnv->CallObjectMethod(mJniServiceObj, - finalizePersonalizationMethodId); - if (exceptionCheck(curThreadEnv)) { + jobject obj = env->CallObjectMethod( + mJniServiceObj, + finalizePersonalizationMethodID, + status); + if (exceptionCheck(env)) { return {EidServiceResult::ERROR}; } - auto clazz = curThreadEnv->GetObjectClass(obj); + auto clazz = env->GetObjectClass(obj); - auto fidResult = curThreadEnv->GetFieldID( + auto fidResult = env->GetFieldID( clazz, jniPersonalizationResult::result, jniPersonalizationResult::resultType); - int result = curThreadEnv->GetIntField(obj, fidResult); + auto result = env->GetObjectField(obj, fidResult); - auto fidPin = curThreadEnv->GetFieldID( + auto fidPin = env->GetFieldID( clazz, jniPersonalizationResult::initPINData, jniPersonalizationResult::initPINDataType); - auto jsData = reinterpret_cast(curThreadEnv->GetObjectField(obj, fidPin)); - std::string pin = getString(curThreadEnv, jsData); + auto objField = env->GetObjectField(obj, fidPin); + auto jsData = reinterpret_cast(objField); + + std::string pin = getString(env, jsData); + + jclass serviceResultClazz = findClass(env, mApplicationContext, jniServiceResult::path); + jmethodID getValueMethodID = env->GetStaticMethodID(serviceResultClazz, + jniServiceResult::getValue, + jniServiceResult::sigGetValue); - return {getEidServiceResult(result), pin}; + int serviceResultCode = env->CallStaticIntMethod(serviceResultClazz, getValueMethodID, result); + PersonalizationResult personalizationResult(getEidServiceResult(serviceResultCode), pin); + + deleteLocalRef(env, result); + deleteLocalRef(env, objField); + deleteLocalRef(env, serviceResultClazz); + deleteLocalRef(env, clazz); + deleteLocalRef(env, obj); + + return personalizationResult; } @@ -512,46 +597,45 @@ PersonalizationResult EidAppletServiceAndroid -EidStatus EidAppletServiceAndroid::getSmartEidStatus() { - //get environment of current thread - JNIEnvironment* curThreadEnv; - ThreadGuard guard(mJvm); - if (!getJNIEnvForCurrentThread(curThreadEnv, guard)) { +EidStatus EidAppletServiceAndroid::getSmartEidStatus() { + + const std::lock_guard guard(serviceMutex); + + JNIEnv* env; + ThreadGuard threadGuard(mJvm); + if (!getJNIEnvForCurrentThread(env, threadGuard) || mApplicationContext == nullptr || mJniServiceClz == nullptr || mJniServiceObj == nullptr) { return EidStatus::INTERNAL_ERROR; } - jmethodID eIDStatusMethodID = curThreadEnv->GetMethodID( + jmethodID statusMethodID = env->GetMethodID( mJniServiceClz, jniService::eIDStatusMethod, jniService::eIDStatusMethodSig); - jobject resultObj = curThreadEnv->CallObjectMethod(mJniServiceObj, eIDStatusMethodID); - if (exceptionCheck(curThreadEnv)) { + jobject resultObj = env->CallObjectMethod(mJniServiceObj, statusMethodID); + if (exceptionCheck(env)) { return EidStatus::INTERNAL_ERROR; } - //cast EidStatus to int - jclass statusClass = findClass( - curThreadEnv, - mApplicationContext, - jniEidStatus::path); - - jmethodID methodId = curThreadEnv->GetStaticMethodID( + jclass statusClass = findClass(env, mApplicationContext, jniEidStatus::path); + jmethodID getValueMethodID = env->GetStaticMethodID( statusClass, jniEidStatus::getValue, jniEidStatus::sigGetValue); - int intResultCode = curThreadEnv->CallStaticIntMethod( + int statusCode = env->CallStaticIntMethod( statusClass, - methodId, + getValueMethodID, resultObj); - if (exceptionCheck(curThreadEnv)) { + if (exceptionCheck(env)) { return EidStatus::INTERNAL_ERROR; } - return EidStatus(intResultCode); + deleteLocalRef(env, resultObj); + deleteLocalRef(env, statusClass); + + return EidStatus(statusCode); } @@ -559,48 +643,69 @@ EidStatus EidAppletServiceAndroid::getSmartE * Provides information of available updates of the installed eID-Applet and/or CSP * implementation or whether the device is supported by TSMS. * - * \return The Update-Info of the eID-Applet + * \return The Support-Info of the eID-Applet */ -template -EidUpdateInfo EidAppletServiceAndroid::getUpdateInfo() { - //get environment of current thread - JNIEnvironment* curThreadEnv; - ThreadGuard guard(mJvm); - if (!getJNIEnvForCurrentThread(curThreadEnv, guard)) { - return EidUpdateInfo::INTERNAL_ERROR; +EidSupportStatusResult EidAppletServiceAndroid::getSmartEidSupportInfo() { + + const std::lock_guard guard(serviceMutex); + + JNIEnv* env; + ThreadGuard threadGuard(mJvm); + if (!getJNIEnvForCurrentThread(env, threadGuard) || mApplicationContext == nullptr || mJniServiceClz == nullptr || mJniServiceObj == nullptr) { + return {EidServiceResult::ERROR, EidSupportStatus::INTERNAL_ERROR}; } - jmethodID updateInfoMethodeId = curThreadEnv->GetMethodID( + jmethodID supportInfoMethodID = env->GetMethodID( mJniServiceClz, - jniService::updateInfoMethod, - jniService::updateInfoMethodSig); + jniService::smartEidSupportInfo, + jniService::smartEidSupportInfoMethodSig); - jobject resultObj = curThreadEnv->CallObjectMethod(mJniServiceObj, updateInfoMethodeId); - if (exceptionCheck(curThreadEnv)) { - return EidUpdateInfo::INTERNAL_ERROR; + jobject resultObj = env->CallObjectMethod(mJniServiceObj, supportInfoMethodID); + if (exceptionCheck(env)) { + return {EidServiceResult::ERROR, EidSupportStatus::INTERNAL_ERROR}; } - //cast EidStatus to int - jclass statusClass = findClass( - curThreadEnv, - mApplicationContext, - jniEidUpdateInfo::path); - - jmethodID methodId = curThreadEnv->GetStaticMethodID( - statusClass, - jniEidUpdateInfo::getValue, - jniEidUpdateInfo::sigGetValue); + auto clazz = env->GetObjectClass(resultObj); - int intResultCode = curThreadEnv->CallStaticIntMethod( - statusClass, - methodId, - resultObj); + auto fidResult = env->GetFieldID( + clazz, + jniEidSupportStatusResult::result, + jniEidSupportStatusResult::resultType); + auto result = env->GetObjectField(resultObj, fidResult); - if (exceptionCheck(curThreadEnv)) { - return EidUpdateInfo::INTERNAL_ERROR; + auto fidStatus = env->GetFieldID( + clazz, + jniEidSupportStatusResult::status, + jniEidSupportStatusResult::statusType); + auto status = env->GetObjectField(resultObj, fidStatus); + if (exceptionCheck(env)) { + return {EidServiceResult::ERROR, EidSupportStatus::INTERNAL_ERROR}; } - return EidUpdateInfo(intResultCode); + jclass serviceResultClazz = findClass(env, mApplicationContext, jniServiceResult::path); + jmethodID serviceResultGetValueMethodID = env->GetStaticMethodID(serviceResultClazz, + jniServiceResult::getValue, + jniServiceResult::sigGetValue); + + int serviceResultCode = env->CallStaticIntMethod(serviceResultClazz, serviceResultGetValueMethodID, result); + + jclass supportStatusClazz = findClass(env, mApplicationContext, jniEidSupportStatus::path); + jmethodID supportStatusGetValueMethodID = env->GetStaticMethodID(supportStatusClazz, + jniEidSupportStatus::getValue, + jniEidSupportStatus::sigGetValue); + + int supportStatusCode = env->CallStaticIntMethod(supportStatusClazz, + supportStatusGetValueMethodID, status); + EidSupportStatusResult supportStatusResult(getEidServiceResult(serviceResultCode), getEidSupportStatus(supportStatusCode)); + + deleteLocalRef(env, result); + deleteLocalRef(env, status); + deleteLocalRef(env, supportStatusClazz); + deleteLocalRef(env, serviceResultClazz); + deleteLocalRef(env, clazz); + deleteLocalRef(env, resultObj); + + return supportStatusResult; } @@ -609,48 +714,46 @@ EidUpdateInfo EidAppletServiceAndroid::getUp * * \return EidServiceResult */ -template -EidServiceResult EidAppletServiceAndroid::releaseAppletConnection() { - JNIEnvironment* curThreadEnv; - ThreadGuard guard(mJvm); - if (!getJNIEnvForCurrentThread(curThreadEnv, guard)) { +EidServiceResult EidAppletServiceAndroid::releaseAppletConnection() { + + const std::lock_guard guard(serviceMutex); + + JNIEnv* env; + ThreadGuard threadGuard(mJvm); + if (!getJNIEnvForCurrentThread(env, threadGuard) || mApplicationContext == nullptr || mJniServiceClz == nullptr || mJniServiceObj == nullptr) { return EidServiceResult::ERROR; } - //call release method - jclass serviceClass = findClass(curThreadEnv, mApplicationContext, jniService::path); - jmethodID releaseAppletConnectionMethodId = curThreadEnv->GetMethodID( - serviceClass, + jmethodID releaseAppletConnectionMethodID = env->GetMethodID( + mJniServiceClz, jniService::releaseAppletConnectionMethod, jniService::releaseAppletConnectionMethodSig); - jobject resultCode = curThreadEnv->CallObjectMethod( + jobject resultCode = env->CallObjectMethod( mJniServiceObj, - releaseAppletConnectionMethodId); - if (exceptionCheck(curThreadEnv)) { + releaseAppletConnectionMethodID); + if (exceptionCheck(env)) { return EidServiceResult::ERROR; } - //cast ServiceResult to int - jclass serviceResultClass = findClass( - curThreadEnv, - mApplicationContext, - jniServiceResult::path); - - jmethodID methodId = curThreadEnv->GetStaticMethodID( + jclass serviceResultClass = findClass(env, mApplicationContext, jniServiceResult::path); + jmethodID getValueMethodID = env->GetStaticMethodID( serviceResultClass, jniServiceResult::getValue, jniServiceResult::sigGetValue); - int intResultCode = curThreadEnv->CallStaticIntMethod( + int serviceResultCode = env->CallStaticIntMethod( serviceResultClass, - methodId, + getValueMethodID, resultCode); - if (exceptionCheck(curThreadEnv)) { + if (exceptionCheck(env)) { return EidServiceResult::ERROR; } - return EidServiceResult(intResultCode); + deleteLocalRef(env, resultCode); + deleteLocalRef(env, serviceResultClass); + + return EidServiceResult(serviceResultCode); } @@ -660,70 +763,167 @@ EidServiceResult EidAppletServiceAndroid::re * \return GenericDataResult mData is blank if mResult is equal to * EidServiceResult::SUCCESS, otherwise it contains an error message */ -template -GenericDataResult EidAppletServiceAndroid::shutdownService() { - //get environment of current thread - JNIEnvironment* curThreadEnv; - ThreadGuard guard(mJvm); - if (!getJNIEnvForCurrentThread(curThreadEnv, guard)) { +GenericDataResult EidAppletServiceAndroid::shutdownService() { + + const std::lock_guard guard(serviceMutex); + + JNIEnv* env; + ThreadGuard threadGuard(mJvm); + if (!getJNIEnvForCurrentThread(env, threadGuard) || mApplicationContext == nullptr || mJniServiceClz == nullptr || mJniServiceObj == nullptr) { return {EidServiceResult::ERROR, "Current thread of the caller could not be attached"}; } - jmethodID shutdownMethodID = curThreadEnv->GetMethodID( + jmethodID shutdownMethodID = env->GetMethodID( mJniServiceClz, jniService::shutdownMethod, jniService::shutdownMethodSig); - if (exceptionCheck(curThreadEnv)) { + if (exceptionCheck(env)) { return {EidServiceResult::ERROR, "Couldn't shutdown eID Applet Service. Method not found."}; } - jobject obj = curThreadEnv->CallObjectMethod(mJniServiceObj, shutdownMethodID); - bool hasError = exceptionCheck(curThreadEnv); - if (hasError) { - return {EidServiceResult::ERROR, - "Couldn't shutdown eID Applet Service. Call of the shutdown function failed."}; + jobject obj = env->CallObjectMethod(mJniServiceObj, shutdownMethodID); + if (exceptionCheck(env)) { + return {EidServiceResult::ERROR, "Couldn't shutdown eID Applet Service. Call of the shutdown function failed."}; } - curThreadEnv->DeleteGlobalRef(mJniServiceClz); - curThreadEnv->DeleteGlobalRef(mJniServiceObj); - - auto clazz = curThreadEnv->GetObjectClass(obj); - auto fidResult = curThreadEnv->GetFieldID( + auto clazz = env->GetObjectClass(obj); + auto fidResult = env->GetFieldID( clazz, jniGenericDataResult::result, jniGenericDataResult::resultType); - int resultType = curThreadEnv->GetIntField(obj, fidResult); + auto resultType = env->GetObjectField(obj, fidResult); - auto fidData = curThreadEnv->GetFieldID( + auto fidData = env->GetFieldID( clazz, jniGenericDataResult::data, jniGenericDataResult::dataType); - auto jsData = reinterpret_cast(curThreadEnv->GetObjectField(obj, fidData)); - std::string data = getString(curThreadEnv, jsData); + auto objField = env->GetObjectField(obj, fidData); + auto jsData = reinterpret_cast(objField); + std::string data = getString(env, jsData); - return {getEidServiceResult(resultType), data}; + jclass serviceResultClazz = findClass(env, mApplicationContext, jniServiceResult::path); + jmethodID getValueMethodID = env->GetStaticMethodID(serviceResultClazz, + jniServiceResult::getValue, + jniServiceResult::sigGetValue); + + int serviceResultCode = env->CallStaticIntMethod(serviceResultClazz, getValueMethodID, + resultType); + GenericDataResult gDResult(getEidServiceResult(serviceResultCode), data); + + deleteLocalRef(env, resultType); + deleteLocalRef(env, objField); + deleteLocalRef(env, serviceResultClazz); + deleteLocalRef(env, clazz); + deleteLocalRef(env, obj); + + return gDResult; +} + + +ServiceInformationResult EidAppletServiceAndroid::getServiceInformation() { + + const std::lock_guard guard(serviceMutex); + + JNIEnv* env; + ThreadGuard threadGuard(mJvm); + ServiceInformationResult mServiceInfoResult; + if (!getJNIEnvForCurrentThread(env, threadGuard) || mApplicationContext == nullptr || mJniServiceClz == nullptr || mJniServiceObj == nullptr) { + mServiceInfoResult.mResult = EidServiceResult::ERROR; + return mServiceInfoResult; + } + + jmethodID updateInfoMethodID = env->GetMethodID( + mJniServiceClz, + jniService::getServiceInformationMethod, + jniService::getServiceInformationMethodSig); + + jobject resultObj = env->CallObjectMethod(mJniServiceObj, updateInfoMethodID); + if (exceptionCheck(env)) { + mServiceInfoResult.mResult = EidServiceResult::ERROR; + return mServiceInfoResult; + } + + auto clazz = env->GetObjectClass(resultObj); + + auto fidResult = env->GetFieldID( + clazz, + jniServiceInformationResult::result, + jniServiceInformationResult::resultType); + auto result = env->GetObjectField(resultObj, fidResult); + jclass serviceResultClazz = findClass(env, mApplicationContext, jniServiceResult::path); + jmethodID gatValueMethodID = env->GetStaticMethodID(serviceResultClazz, + jniServiceResult::getValue, + jniServiceResult::sigGetValue); + + int returnValue = env->CallStaticIntMethod(serviceResultClazz, gatValueMethodID, result); + + mServiceInfoResult.mResult = static_cast(returnValue); + + auto fidEidType = env->GetFieldID( + clazz, + jniServiceInformationResult::eidType, + jniServiceInformationResult::eidTypeType); + + auto eidType = env->GetObjectField(resultObj, fidEidType); + jclass eidTypeClazz = findClass(env, mApplicationContext, jniSmartEidType::path); + jmethodID eidTypeStaticMethodID = env->GetStaticMethodID(eidTypeClazz, + jniSmartEidType::getValue, + jniSmartEidType::sigGetValue); + + int eidTypeValue = env->CallStaticIntMethod(eidTypeClazz, eidTypeStaticMethodID, + eidType); + + mServiceInfoResult.mType = static_cast(eidTypeValue); + + auto fidChallenge = env->GetFieldID( + clazz, + jniServiceInformationResult::challengeData, + jniServiceInformationResult::challengeDataType); + + auto challegeField = env->GetObjectField(resultObj, fidChallenge); + auto jsData = reinterpret_cast(challegeField); + std::string challenge = getString(env, jsData); + mServiceInfoResult.mChallengeType = challenge; + + auto fidLibVersionName = env->GetFieldID( + clazz, + jniServiceInformationResult::libVersionName, + jniServiceInformationResult::libVersionNameType); + + auto versionNameField = env->GetObjectField(resultObj, fidLibVersionName); + auto jsVersionName = reinterpret_cast(versionNameField); + std::string versionName = getString(env, jsVersionName); + mServiceInfoResult.mLibVersionName = versionName; + + deleteLocalRef(env, result); + deleteLocalRef(env, eidType); + deleteLocalRef(env, challegeField); + deleteLocalRef(env, versionNameField); + deleteLocalRef(env, serviceResultClazz); + deleteLocalRef(env, clazz); + deleteLocalRef(env, resultObj); + deleteLocalRef(env, eidTypeClazz); + + return mServiceInfoResult; } -template -EidAppletServiceAndroid::ThreadGuard::ThreadGuard(JavaVirtualMachine* pJvm) +EidAppletServiceAndroid::ThreadGuard::ThreadGuard(JavaVM* pJvm) : mJvm(pJvm) , mDoDetach(false) { } -template -EidAppletServiceAndroid::ThreadGuard::~ThreadGuard() { - if (mDoDetach) { +EidAppletServiceAndroid::ThreadGuard::~ThreadGuard() { + if (mDoDetach && mJvm) { mJvm->DetachCurrentThread(); } } -template -void EidAppletServiceAndroid::ThreadGuard::doDetach() { +void EidAppletServiceAndroid::ThreadGuard::doDetach() { mDoDetach = true; } @@ -734,11 +934,10 @@ void EidAppletServiceAndroid::ThreadGuard::d * var env of the class is attached to another thread. * * \param _env the JNIEnv of the current thread (out param) - * \param guard who can be ordered to detach the current thread on destruction + * \param threadGuard who can be ordered to detach the current thread on destruction * \return true = success, false = error */ -template -bool EidAppletServiceAndroid::getJNIEnvForCurrentThread(JNIEnvironment*& _env, ThreadGuard& guard) { +bool EidAppletServiceAndroid::getJNIEnvForCurrentThread(JNIEnv*& _env, ThreadGuard& threadGuard) { int getEnvResult = mJvm->GetEnv(reinterpret_cast(&_env), JNI_VERSION_1_6); if (getEnvResult == JNI_OK) { return true; @@ -750,14 +949,10 @@ bool EidAppletServiceAndroid::getJNIEnvForCu #else int attachResult = mJvm->AttachCurrentThread(reinterpret_cast(&mEnv), nullptr); #endif - guard.doDetach(); + threadGuard.doDetach(); return attachResult == JNI_OK; } return false; } - - -//Needed so the linker knows what kinda instance of the template class we need otherwise this .cpp cant be linked to the .h! -template class EidAppletServiceAndroid; diff --git a/src/external/smart/eid_applet_service_android.h b/src/external/smart/eid_applet_service_android.h index 9de364810..23541d844 100644 --- a/src/external/smart/eid_applet_service_android.h +++ b/src/external/smart/eid_applet_service_android.h @@ -1,6 +1,6 @@ /* - * Copyright (C) 2021 Bundesdruckerei GmbH and Governikus GmbH - * + * Copyright (C) 2023 by Bundesdruckerei GmbH and Governikus GmbH & Co. KG + * Licensed under the EUPL-1.2 */ #pragma once @@ -9,6 +9,7 @@ #include "eid_applet_results.h" #include "eid_applet_utils.h" #include +#include #include @@ -16,46 +17,48 @@ using namespace appletUtils; using namespace jniUtils; -template class EidAppletServiceAndroid { public: - EidAppletServiceAndroid(JNIEnvironment* env, jobject applicationContext); + EidAppletServiceAndroid(JNIEnv* env, jobject applicationContext); ~EidAppletServiceAndroid(); GenericDataResult initializeService( const std::string& pServiceId, - const std::string& pVersionTag, - const std::string& pSsdAid); + const std::string& pSsdAid, + const std::string& pVersionTag); EidServiceResult installSmartEid(); EidServiceResult deleteSmartEid(); EidServiceResult deletePersonalization(); GenericDataResult performAPDUCommand(const std::string& pCommandApdu); InitializeResult initializePersonalization(const std::string& pPin, const std::string& pChallenge); GenericDataResult performPersonalization(const std::string& pCommandPersonalization); - PersonalizationResult finalizePersonalization(); + PersonalizationResult finalizePersonalization(jint status); EidStatus getSmartEidStatus(); - EidUpdateInfo getUpdateInfo(); + EidSupportStatusResult getSmartEidSupportInfo(); EidServiceResult releaseAppletConnection(); GenericDataResult shutdownService(); + ServiceInformationResult getServiceInformation(); private: class ThreadGuard { private: - JavaVirtualMachine* mJvm; + JavaVM* mJvm; bool mDoDetach; public: - explicit ThreadGuard(JavaVirtualMachine* pJvm); + explicit ThreadGuard(JavaVM* pJvm); ~ThreadGuard(); void doDetach(); }; - JNIEnvironment* mEnv; - JavaVirtualMachine* mJvm; - jclass mJniServiceClz; - jobject mJniServiceObj; - jobject mApplicationContext; + std::mutex serviceMutex; - bool getJNIEnvForCurrentThread(JNIEnvironment*& _env, ThreadGuard& guard); + JNIEnv* mEnv; + JavaVM* mJvm; + jobject mApplicationContext = nullptr; + jclass mJniServiceClz = nullptr; + jobject mJniServiceObj = nullptr; + + bool getJNIEnvForCurrentThread(JNIEnv*& _env, ThreadGuard& threadGuard); }; diff --git a/src/external/smart/eid_applet_utils.cpp b/src/external/smart/eid_applet_utils.cpp new file mode 100644 index 000000000..da1889b9c --- /dev/null +++ b/src/external/smart/eid_applet_utils.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2023 by Bundesdruckerei GmbH and Governikus GmbH & Co. KG + * Licensed under the EUPL-1.2 + */ + +#include "eid_applet_utils.h" +#include + + +std::string jniUtils::getString(JNIEnv* env, const jstring& dataJString) { + const jsize length = env->GetStringUTFLength(dataJString); + const char* charStr = env->GetStringUTFChars(dataJString, nullptr); + if (charStr != nullptr) { + std::string data(charStr, static_cast(length)); + env->ReleaseStringUTFChars(dataJString, charStr); + return data; + } + return ""; +} + + +bool jniUtils::exceptionCheck(JNIEnv* env) { + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + return true; + } + return false; +} + + +/** + * This findclass-method is used instead of the jni native method to avoid Crashes on Qt based applications since + * Qt on Android uses a custom class loader + * https://doc.qt.io/qt-5/qandroidjnienvironment.html#findClass + * */ +jclass jniUtils::findClass(JNIEnv* env, jobject applicationContext, const char* className) { + jclass acl = env->GetObjectClass(applicationContext); + jmethodID getClassLoader = env->GetMethodID(acl, "getClassLoader", + "()Ljava/lang/ClassLoader;"); + jobject cls = env->CallObjectMethod(applicationContext, getClassLoader); + jclass classLoader = env->FindClass("java/lang/ClassLoader"); + jmethodID findClass = env->GetMethodID(classLoader, + "loadClass", + "(Ljava/lang/String;)Ljava/lang/Class;"); + + jstring strClassName = env->NewStringUTF(className); + jclass jniClzRef = static_cast(env->CallObjectMethod(cls, findClass, strClassName)); + env->DeleteLocalRef(strClassName); + env->DeleteLocalRef(classLoader); + env->DeleteLocalRef(cls); + env->DeleteLocalRef(acl); + + return jniClzRef; +} + + +EidServiceResult appletUtils::getEidServiceResult(int value) { + for (const auto result : {EidServiceResult::SUCCESS, + EidServiceResult::INFO, + EidServiceResult::WARN, + EidServiceResult::ERROR, + EidServiceResult::UNSUPPORTED, + EidServiceResult::OVERLOAD_PROTECTION, + EidServiceResult::UNDER_MAINTENANCE, + EidServiceResult::NFC_NOT_ACTIVATED, + EidServiceResult::INTEGRITY_CHECK_FAILED, + EidServiceResult::NOT_AUTHENTICATED, + EidServiceResult::NETWORK_CONNECTION_ERROR}) { + if (static_cast(result) == value) { + return result; + } + } + + return EidServiceResult::UNDEFINED; +} + + +EidSupportStatus appletUtils::getEidSupportStatus(int value) { + for (const auto result : {EidSupportStatus::AVAILABLE, + EidSupportStatus::UNAVAILABLE, + EidSupportStatus::UPDATE_AVAILABLE, + EidSupportStatus::UP_TO_DATE}) { + if (static_cast(result) == value) { + return result; + } + } + + return EidSupportStatus::INTERNAL_ERROR; +} diff --git a/src/external/smart/eid_applet_utils.h b/src/external/smart/eid_applet_utils.h new file mode 100644 index 000000000..6e13ba0e0 --- /dev/null +++ b/src/external/smart/eid_applet_utils.h @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2023 by Bundesdruckerei GmbH and Governikus GmbH & Co. KG + * Licensed under the EUPL-1.2 + */ + +#pragma once + +#include "eid_applet_results.h" +#include +#include + +namespace jniService { + // constructor + const char*const path = "de/bundesdruckerei/android/eid_applet_service_lib/jni/SmartEidServiceNativeBridge"; + const char*const stdInit = ""; + + // methods + const char*const init = "initialize"; + const char*const sig = "(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lde/bundesdruckerei/android/eid_applet_service_lib/GenericDataResult;"; + + const char*const shutdownMethod = "shutdown"; + const char*const shutdownMethodSig = "()Lde/bundesdruckerei/android/eid_applet_service_lib/GenericDataResult;"; + + const char*const performAPDUCommandMethod = "performAPDUCommand"; + const char*const performAPDUCommandMethodSig = "(Ljava/lang/String;)Lde/bundesdruckerei/android/eid_applet_service_lib/GenericDataResult;"; + + const char*const installSmartEidMethod = "installSmartEid"; + const char*const installSmartEidMethodSig = "()Lde/bundesdruckerei/android/eid_applet_service_lib/ServiceResult;"; + + const char*const deleteSmartEidMethod = "deleteSmartEid"; + const char*const deleteSmartEidMethodSig = "()Lde/bundesdruckerei/android/eid_applet_service_lib/ServiceResult;"; + + const char*const initializePersonalizationMethod = "initializePersonalization"; + const char*const initializePersonalizationMethodSig = "(Ljava/lang/String;)Lde/bundesdruckerei/android/eid_applet_service_lib/InitializeResult;"; + + const char*const performPersonalizationMethod = "performPersonalization"; + const char*const performPersonalizationMethodSig = "(Ljava/lang/String;)Lde/bundesdruckerei/android/eid_applet_service_lib/GenericDataResult;"; + + const char*const releaseAppletConnectionMethod = "releaseAppletConnection"; + const char*const releaseAppletConnectionMethodSig = "()Lde/bundesdruckerei/android/eid_applet_service_lib/ServiceResult;"; + + const char*const eIDStatusMethod = "smartEidStatus"; + const char*const eIDStatusMethodSig = "()Lde/bundesdruckerei/android/eid_applet_service_lib/EidStatus;"; + + const char*const smartEidSupportInfo = "smartEidSupportInfo"; + const char*const smartEidSupportInfoMethodSig = "()Lde/bundesdruckerei/android/eid_applet_service_lib/EidSupportStatusResult;"; + + const char*const finalizePersonalizationMethod = "finalizePersonalization"; + const char*const finalizePersonalizationMethodSig = "(I)Lde/bundesdruckerei/android/eid_applet_service_lib/PersonalizationResult;"; + + const char*const deletePersonalizationMethod = "deletePersonalization"; + const char*const deletePersonalizationMethodSig = "()Lde/bundesdruckerei/android/eid_applet_service_lib/ServiceResult;"; + + const char*const getServiceInformationMethod = "serviceInformation"; + const char*const getServiceInformationMethodSig = "()Lde/bundesdruckerei/android/eid_applet_service_lib/ServiceInformationResult;"; +} // namespace jniService + +namespace jniGenericDataResult { + const char*const path = "de/bundesdruckerei/android/eid_applet_service_lib/GenericDataResult"; + const char*const sig = "(Lde/bundesdruckerei/android/eid_applet_service_lib/ServiceResult;Ljava/lang/String;)V"; + const char*const init = ""; + const char*const result = "result"; + const char*const resultType = "Lde/bundesdruckerei/android/eid_applet_service_lib/ServiceResult;"; + const char*const data = "data"; + const char*const dataType = "Ljava/lang/String;"; +} // namespace jniGenericDataResult + +namespace jniServiceResult { + const char*const init = ""; + const char*const sig = "()V"; + const char*const path = "de/bundesdruckerei/android/eid_applet_service_lib/jni/ServiceResultMap"; + const char*const sigGetByValue = "(I)Lde/bundesdruckerei/android/eid_applet_service_lib/ServiceResult;"; + const char*const getByValue = "getByValue"; + const char*const sigGetValue = "(Lde/bundesdruckerei/android/eid_applet_service_lib/ServiceResult;)I"; + const char*const getValue = "getValue"; +} // namespace jniServiceResult + +namespace jniSmartEidType { + const char*const init = ""; + const char*const sig = "()V"; + const char*const path = "de/bundesdruckerei/android/eid_applet_service_lib/jni/SmartEidTypeMap"; + const char*const sigGetByValue = "(I)Lde/bundesdruckerei/android/eid_applet_service_lib/SmartEidType;"; + const char*const getByValue = "getByValue"; + const char*const sigGetValue = "(Lde/bundesdruckerei/android/eid_applet_service_lib/SmartEidType;)I"; + const char*const getValue = "getValue"; +} // namespace jniSmartEidType + +namespace jniEidStatus { + const char*const path = "de/bundesdruckerei/android/eid_applet_service_lib/jni/EidStatusMap"; + const char*const sigGetByValue = "(I)Lde/bundesdruckerei/android/eid_applet_service_lib/EidStatus;"; + const char*const getByValue = "getByValue"; + const char*const sigGetValue = "(Lde/bundesdruckerei/android/eid_applet_service_lib/EidStatus;)I"; + const char*const getValue = "getValue"; +} // namespace jniEidStatus + +namespace jniEidSupportStatusResult { + const char*const path = "de/bundesdruckerei/android/eid_applet_service_lib/EidSupportStatusResult"; + const char*const sig = "(Lde/bundesdruckerei/android/eid_applet_service_lib/ServiceResult;Lde/bundesdruckerei/android/eid_applet_service_lib/EidSupportStatus;)V"; + const char*const init = ""; + // ServiceResult + const char*const result = "result"; + const char*const resultType = "Lde/bundesdruckerei/android/eid_applet_service_lib/ServiceResult;"; + // EidSupportInfo + const char*const status = "supportStatus"; + const char*const statusType = "Lde/bundesdruckerei/android/eid_applet_service_lib/EidSupportStatus;"; +} // namespace jniEidSupportStatusResult + +namespace jniEidSupportStatus { + const char*const path = "de/bundesdruckerei/android/eid_applet_service_lib/jni/EidSupportStatusMap"; + const char*const init = ""; + const char*const sig = "()V"; + const char*const sigGetByValue = "(I)Lde/bundesdruckerei/android/eid_applet_service_lib/EidSupportStatus;"; + const char*const getByValue = "getByValue"; + const char*const sigGetValue = "(Lde/bundesdruckerei/android/eid_applet_service_lib/EidSupportStatus;)I"; + const char*const getValue = "getValue"; +} // namespace jniEidSupportStatus + +namespace jniInitializeResult { + const char*const path = "de/bundesdruckerei/android/eid_applet_service_lib/InitializeResult"; + const char*const sig = "(Lde/bundesdruckerei/android/eid_applet_service_lib/ServiceResult;Ljava/lang/String;)V"; + const char*const init = ""; + const char*const result = "result"; + const char*const resultType = "Lde/bundesdruckerei/android/eid_applet_service_lib/ServiceResult;"; + const char*const ppData = "preparePersonalizationData"; + const char*const ppDataType = "Ljava/lang/String;"; +} // namespace jniInitializeResult + +namespace jniPersonalizationResult { + const char*const path = "de/bundesdruckerei/android/eid_applet_service_lib/PersonalizationResult"; + const char*const sig = "(Lde/bundesdruckerei/android/eid_applet_service_lib/ServiceResult;Ljava/lang/String;)V"; + const char*const init = ""; + const char*const result = "result"; + const char*const resultType = "Lde/bundesdruckerei/android/eid_applet_service_lib/ServiceResult;"; + const char*const initPINData = "initPIN"; + const char*const initPINDataType = "Ljava/lang/String;"; +} // namespace jniPersonalizationResult + +namespace jniServiceInformationResult { + const char*const path = "de/bundesdruckerei/android/eid_applet_service_lib/ServiceInformationResult"; + const char*const sig = "(Lde/bundesdruckerei/android/eid_applet_service_lib/ServiceResult;Lde/bundesdruckerei/android/eid_applet_service_lib/SmartEidType;Ljava/lang/String;Ljava/lang/String;)V"; + const char*const init = ""; + const char*const result = "result"; + const char*const resultType = "Lde/bundesdruckerei/android/eid_applet_service_lib/ServiceResult;"; + const char*const eidType = "type"; + const char*const eidTypeType = "Lde/bundesdruckerei/android/eid_applet_service_lib/SmartEidType;"; + const char*const challengeData = "challengeType"; + const char*const challengeDataType = "Ljava/lang/String;"; + const char*const libVersionName = "libVersionName"; + const char*const libVersionNameType = "Ljava/lang/String;"; +} // namespace jniServiceInformationResult + +namespace jniUtils { + std::string getString(JNIEnv* env, const jstring& dataJString); + bool exceptionCheck(JNIEnv* env); + jclass findClass(JNIEnv* env, jobject applicationContext, const char* className); + + template + void deleteLocalRef(JNIEnv* env, T*& ref) { + if (ref && env) { + env->DeleteLocalRef(ref); + ref = nullptr; + } + } + + + template + void deleteGlobalRef(JNIEnv* env, T*& ref) { + if (ref && env) { + env->DeleteGlobalRef(ref); + ref = nullptr; + } + } + + +} // namespace jniUtils + +namespace appletUtils { + + EidServiceResult getEidServiceResult(int value); + + EidSupportStatus getEidSupportStatus(int value); + +} // namespace appletUtils diff --git a/src/external/smart/mock/eid_applet_interface_mock.cpp b/src/external/smart/mock/eid_applet_interface_mock.cpp index 90cc2b0ae..bd80c04a5 100644 --- a/src/external/smart/mock/eid_applet_interface_mock.cpp +++ b/src/external/smart/mock/eid_applet_interface_mock.cpp @@ -6,6 +6,7 @@ #include "MockSmartEidRestClient.h" +#include #include #include @@ -17,14 +18,18 @@ QSharedPointer mRestInterface(new governikus struct Data { bool ephemeralResult = true; - EidUpdateInfo updateInfo = mRestInterface->isEnabled() ? EidUpdateInfo::UP_TO_DATE : EidUpdateInfo::UNAVAILABLE; - EidStatus smartEidStatus = mRestInterface->isEnabled() ? EidStatus::NO_PERSONALIZATION : EidStatus::UNAVAILABLE; + EidSupportStatusResult supportInfo = EidSupportStatusResult(EidServiceResult::SUCCESS, mRestInterface->isEnabled() ? EidSupportStatus::UP_TO_DATE : EidSupportStatus::UNAVAILABLE); + EidStatus smartEidStatus = mRestInterface->isEnabled() ? EidStatus::NO_PERSONALIZATION : EidStatus::INTERNAL_ERROR; + ServiceInformationResult serviceInformation = mRestInterface->isEnabled() + ? ServiceInformationResult(EidServiceResult::SUCCESS, SmartEidType::APPLET, std::string("uuid")) + : ServiceInformationResult(); EidServiceResult installSmartEidResult = mRestInterface->isEnabled() ? EidServiceResult::SUCCESS : EidServiceResult::UNSUPPORTED; EidServiceResult deleteSmartEidResult = mRestInterface->isEnabled() ? EidServiceResult::SUCCESS : EidServiceResult::UNSUPPORTED; GenericDataResult apduCommandResult; GenericDataResult personalizationResult; InitializeResult initializePersonalizationResult; EidServiceResult deletePersonalizationResult = mRestInterface->isEnabled() ? EidServiceResult::SUCCESS : EidServiceResult::UNSUPPORTED; + QQueue receivedParameter; } mData; @@ -35,15 +40,15 @@ void governikus::setEphemeralResult(bool pEphemeral) } -void governikus::setUpdateInfo(EidUpdateInfo pStatus) +void governikus::setSmartEidSupportStatus(EidSupportStatus pStatus) { - mData.updateInfo = pStatus; + mData.supportInfo.mStatus = pStatus; } -EidUpdateInfo getUpdateInfo() +EidSupportStatusResult getSmartEidSupportInfo() { - return mData.updateInfo; + return mData.supportInfo; } @@ -59,6 +64,18 @@ EidStatus getSmartEidStatus() } +void governikus::setServiceInformation(const ServiceInformationResult& pResult) +{ + mData.serviceInformation = pResult; +} + + +ServiceInformationResult getServiceInformation() +{ + return mData.serviceInformation; +} + + void governikus::setInstallSmartEidResult(EidServiceResult pResult) { mData.installSmartEidResult = pResult; @@ -147,6 +164,8 @@ void governikus::setInitializePersonalizationResult(const InitializeResult& pRes InitializeResult initializePersonalization(const std::string& pChallenge, const std::string& pPin) { + mData.receivedParameter.enqueue(QString::fromStdString(pChallenge)); + mData.receivedParameter.enqueue(QString::fromStdString(pPin)); std::cout << "Mock result for:" << pChallenge << " | " << pPin << std::endl; if (mRestInterface->isEnabled()) @@ -179,8 +198,6 @@ EidServiceResult deletePersonalization() } -#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR - PrepareIdentificationResult prepareIdentification(const std::string& pChat) { (void) pChat; @@ -210,7 +227,7 @@ TAandCAResult performTAandCA( } -#elif defined(__ANDROID__) +#if defined(__ANDROID__) GenericDataResult initializeService(JNIEnv* env, jobject applicationContext) { @@ -220,13 +237,26 @@ GenericDataResult initializeService(JNIEnv* env, jobject applicationContext) } -PersonalizationResult finalizePersonalization() +#else + +GenericDataResult initializeService() { + return {EidServiceResult::SUCCESS, ""}; +} + + +#endif + + +PersonalizationResult finalizePersonalization(int pStatus) +{ + (void) pStatus; + if (mRestInterface->isEnabled()) { return mRestInterface->deleteSession(); } - return {EidServiceResult::ERROR, ""}; + return {EidServiceResult::SUCCESS, ""}; } @@ -242,10 +272,21 @@ GenericDataResult shutdownService() } -#endif - void governikus::initMock() { mRestInterface.reset(new MockSmartEidRestClient()); mData = Data {}; } + + +QString governikus::dequeueReceivedParameter() +{ + Q_ASSERT(!mData.receivedParameter.isEmpty()); + return mData.receivedParameter.dequeue(); +} + + +void governikus::setSmartEidSupportStatusResult(EidSupportStatusResult pStatus) +{ + mData.supportInfo = pStatus; +} diff --git a/src/external/smart/mock/eid_applet_interface_mock.h b/src/external/smart/mock/eid_applet_interface_mock.h index be2132123..f860f925e 100644 --- a/src/external/smart/mock/eid_applet_interface_mock.h +++ b/src/external/smart/mock/eid_applet_interface_mock.h @@ -7,11 +7,15 @@ #include +#include + namespace governikus { void setEphemeralResult(bool pEphemeral = true); -void setUpdateInfo(EidUpdateInfo pStatus); +void setSmartEidSupportStatus(EidSupportStatus pStatus); +void setSmartEidSupportStatusResult(EidSupportStatusResult pStatus); void setSmartEidStatus(EidStatus pStatus); +void setServiceInformation(const ServiceInformationResult& pResult); void setInstallSmartEidResult(EidServiceResult pResult); void setDeleteSmartEidResult(EidServiceResult pResult); void setApduCommandResult(const GenericDataResult& pResult); @@ -20,4 +24,5 @@ void setInitializePersonalizationResult(const InitializeResult& pResult); void setDeletePersonalizationResult(EidServiceResult pResult); void initMock(); +QString dequeueReceivedParameter(); } // namespace governikus diff --git a/src/file_provider/Downloader.cpp b/src/file_provider/Downloader.cpp index 3599c105e..cbcaa9d91 100644 --- a/src/file_provider/Downloader.cpp +++ b/src/file_provider/Downloader.cpp @@ -5,6 +5,7 @@ #include "Downloader.h" #include "LogHandler.h" +#include "NetworkManager.h" #include #include diff --git a/src/file_provider/Downloader.h b/src/file_provider/Downloader.h index ca985f1cc..af45a5e66 100644 --- a/src/file_provider/Downloader.h +++ b/src/file_provider/Downloader.h @@ -11,7 +11,6 @@ #include "Env.h" #include "GlobalStatus.h" -#include "NetworkManager.h" #include #include diff --git a/src/file_provider/UpdatableFile.cpp b/src/file_provider/UpdatableFile.cpp index 8c37694ce..86f0b0f58 100644 --- a/src/file_provider/UpdatableFile.cpp +++ b/src/file_provider/UpdatableFile.cpp @@ -34,18 +34,17 @@ const QString& UpdatableFile::getName() const QDateTime UpdatableFile::cacheTimestamp() const { - const QString timestampFormat = QStringLiteral("yyyyMMddhhmmss"); - const auto timestampFormatSize = timestampFormat.size(); - const QString pathInCache = cachePath(); + const QString& pathInCache = cachePath(); + const QStringView timestamp = QStringView(pathInCache).mid(pathInCache.lastIndexOf(QLatin1Char('_')) + 1); // The path must contain at least 1 character for the filename, // the '_' separator, and the timestamp. - if (pathInCache.size() < 2 + timestampFormatSize) + if (pathInCache.size() < 2 + timestamp.size()) { return QDateTime(); } - return QDateTime::fromString(pathInCache.right(timestampFormatSize), timestampFormat); + return QDateTime::fromString(timestamp, QStringLiteral("yyyyMMddhhmmsst")); } @@ -71,7 +70,7 @@ QString UpdatableFile::cachePath() const const auto matchingFiles = folder.entryList(nameFilter, QDir::Files, QDir::Name | QDir::Reversed); // Files are saved in the cache with the suffix _, where - // the timestamp has the format "yyyyMMddhhmmss". + // the timestamp has the format "yyyyMMddhhmmsst". // Therefore, the first matching file in the list has the newest timestamp. return matchingFiles.isEmpty() ? QString() : mSectionCachePath + Sep + matchingFiles.first(); } @@ -102,7 +101,7 @@ QString UpdatableFile::sectionCachePath(const QString& pSection) const return QString(); } - const QString cacheBasePath = cachePaths.first(); + QString cacheBasePath = cachePaths.first(); if (cacheBasePath.isEmpty()) { qCWarning(fileprovider) << "Cache base folder is invalid (empty)."; @@ -110,6 +109,10 @@ QString UpdatableFile::sectionCachePath(const QString& pSection) const return QString(); } +#if defined(Q_OS_WIN) || defined(Q_OS_MACOS) + cacheBasePath.replace(QStringLiteral("AusweisApp"), QStringLiteral("AusweisApp2")); +#endif + return cacheBasePath + Sep + pSection; } @@ -163,7 +166,7 @@ void UpdatableFile::onDownloadSuccess(const QUrl& pUpdateUrl, const QDateTime& p { if (pUpdateUrl == mUpdateUrl) { - const QString dateFormat = QStringLiteral("yyyyMMddhhmmss"); + const auto dateFormat = QStringLiteral("yyyyMMddhhmmsst"); const QString filePath = mSectionCachePath + Sep + mName + QLatin1Char('_') + pNewTimestamp.toString(dateFormat); if (writeDataToFile(pData, filePath)) @@ -206,14 +209,16 @@ void UpdatableFile::onDownloadUnnecessary(const QUrl& pUpdateUrl) } -bool UpdatableFile::writeDataToFile(const QByteArray& pData, const QString& pFilePath, bool pOverwrite) +bool UpdatableFile::writeDataToFile(const QByteArray& pData, const QString& pFilePath) const { QFile file(pFilePath); - if (!pOverwrite && file.exists()) + + if (file.exists()) { - qCCritical(fileprovider) << "File already exists, aborting writing file:" << pFilePath; - return false; + qCDebug(fileprovider) << "File already up to date:" << pFilePath; + return true; } + if (!file.open(QIODevice::WriteOnly)) { qCCritical(fileprovider) << "File could not be opened for writing:" << pFilePath; diff --git a/src/file_provider/UpdatableFile.h b/src/file_provider/UpdatableFile.h index 0cad5791c..303dc684c 100644 --- a/src/file_provider/UpdatableFile.h +++ b/src/file_provider/UpdatableFile.h @@ -50,7 +50,7 @@ class UpdatableFile [[nodiscard]] QString sectionCachePath(const QString& pSection) const; [[nodiscard]] QString makeSectionCachePath(const QString& pSection) const; void cleanupAfterUpdate(const std::function& pCustomAction); - bool writeDataToFile(const QByteArray& pData, const QString& pFilePath, bool pOverwrite = false); + bool writeDataToFile(const QByteArray& pData, const QString& pFilePath) const; private Q_SLOTS: void onDownloadSuccess(const QUrl& pUpdateUrl, const QDateTime& pNewTimestamp, const QByteArray& pData); diff --git a/src/global/BuildHelper.cpp b/src/global/BuildHelper.cpp index 23e5f2176..d3b506f3e 100644 --- a/src/global/BuildHelper.cpp +++ b/src/global/BuildHelper.cpp @@ -151,11 +151,6 @@ QByteArrayList BuildHelper::getAppCertificates(const QString& pPackageName) QVector> BuildHelper::getInformationHeader() { -#if OPENSSL_VERSION_NUMBER < 0x10100000L - #define OpenSSL_version SSLeay_version - #define OPENSSL_VERSION SSLEAY_VERSION -#endif - QVector> data; const auto& add = [&data](const char* pKey, const QString& pStr) { @@ -205,7 +200,8 @@ CertificateType BuildHelper::fetchCertificateType() { return CertificateType::PRODUCTION; } - else if (hash == QByteArrayLiteral("f96fd6bba899845e06d3e6522f0843217681d473b6b09f1e313dea1a21d6b8e7")) + else if (hash == QByteArrayLiteral("f96fd6bba899845e06d3e6522f0843217681d473b6b09f1e313dea1a21d6b8e7") + || hash == QByteArrayLiteral("f4a4d85a22103ebb5f4d35aede5117f40e591ab5ddf43df39c953d08e3895138")) { return CertificateType::DEVELOPER; } diff --git a/src/global/CardReturnCode.cpp b/src/global/CardReturnCode.cpp index f021c0fae..66cde0382 100644 --- a/src/global/CardReturnCode.cpp +++ b/src/global/CardReturnCode.cpp @@ -4,7 +4,6 @@ #include "CardReturnCode.h" -#include "Initializer.h" #include "moc_CardReturnCode.cpp" using namespace governikus; @@ -48,7 +47,6 @@ GlobalStatus CardReturnCodeUtil::toGlobalStatus(CardReturnCode pCode) case CardReturnCode::INVALID_PIN: case CardReturnCode::INVALID_PIN_2: case CardReturnCode::INVALID_PIN_3: - case CardReturnCode::NO_ACTIVE_PIN_SET: return GlobalStatus::Code::Card_Invalid_Pin; case CardReturnCode::INVALID_CAN: @@ -105,7 +103,6 @@ bool CardReturnCodeUtil::equalsWrongPacePassword(CardReturnCode pCode) case CardReturnCode::OK_PUK: case CardReturnCode::CANCELLATION_BY_USER: case CardReturnCode::PUK_INOPERATIVE: - case CardReturnCode::NO_ACTIVE_PIN_SET: case CardReturnCode::INPUT_TIME_OUT: return false; } diff --git a/src/global/CardReturnCode.h b/src/global/CardReturnCode.h index 8a4da313f..691f830a7 100644 --- a/src/global/CardReturnCode.h +++ b/src/global/CardReturnCode.h @@ -35,7 +35,6 @@ defineEnumType(CardReturnCode, PIN_BLOCKED, PIN_NOT_BLOCKED, PUK_INOPERATIVE, - NO_ACTIVE_PIN_SET, PROTOCOL_ERROR, WRONG_LENGTH, UNEXPECTED_TRANSMIT_STATUS) diff --git a/src/global/DeviceInfo.cpp b/src/global/DeviceInfo.cpp index a3ee59ccd..4ff71f66e 100644 --- a/src/global/DeviceInfo.cpp +++ b/src/global/DeviceInfo.cpp @@ -50,7 +50,7 @@ QString DeviceInfo::getBuildNumber() size_t bufferSize = 0; sysctl(mib, namelen, nullptr, &bufferSize, nullptr, 0); - QByteArray buffer(bufferSize, '\0'); + QByteArray buffer(static_cast(bufferSize), '\0'); if (int error = sysctl(mib, namelen, buffer.data(), &bufferSize, nullptr, 0); error) { qDebug() << "Error trying to retrieve iOS build number:" << strerror(errno); diff --git a/src/global/ECardApiResult.cpp b/src/global/ECardApiResult.cpp index 163d7e55c..e1e99921d 100644 --- a/src/global/ECardApiResult.cpp +++ b/src/global/ECardApiResult.cpp @@ -126,12 +126,15 @@ void ECardApiResult::initConversionMaps() addConversionElement(GlobalStatus::Code::Card_Smart_Invalid, Minor::AL_Unknown_Error); addConversionElement(GlobalStatus::Code::Workflow_Smart_eID_Unavailable, Minor::AL_Unknown_Error); addConversionElement(GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed, Minor::AL_Unknown_Error); + addConversionElement(GlobalStatus::Code::Workflow_Smart_eID_Authentication_Failed, Minor::AL_Unknown_Error); + addConversionElement(GlobalStatus::Code::Workflow_Smart_eID_ServiceInformation_Query_Failed, Minor::AL_Unknown_Error); addConversionElement(GlobalStatus::Code::Workflow_Smart_eID_PrePersonalization_Failed, Minor::AL_Unknown_Error); addConversionElement(GlobalStatus::Code::Workflow_Smart_eID_Personalization_Failed, Minor::AL_Unknown_Error); addConversionElement(GlobalStatus::Code::Workflow_No_Permission_Error, Minor::AL_No_Permission); addConversionElement(GlobalStatus::Code::Card_Pin_Deactivated, Minor::AL_No_Permission); addConversionElement(GlobalStatus::Code::Card_Puk_Blocked, Minor::AL_No_Permission); + addConversionElement(GlobalStatus::Code::Workflow_Smart_eID_Personalization_Denied, Minor::AL_No_Permission); addConversionElement(GlobalStatus::Code::Paos_Error_AL_Internal_Error, Minor::AL_Internal_Error); addConversionElement(GlobalStatus::Code::Workflow_Cannot_Confirm_IdCard_Authenticity, Minor::AL_Internal_Error); @@ -147,9 +150,7 @@ void ECardApiResult::initConversionMaps() addConversionElement(GlobalStatus::Code::Paos_Error_AL_Communication_Error, Minor::AL_Communication_Error); addConversionElement(GlobalStatus::Code::Workflow_Communication_Missing_Redirect_Url, Minor::AL_Communication_Error); - addConversionElement(GlobalStatus::Code::Workflow_Error_Page_Transmission_Error, Minor::AL_Communication_Error); - addConversionElement(GlobalStatus::Code::Workflow_Redirect_Transmission_Error, Minor::AL_Communication_Error); - addConversionElement(GlobalStatus::Code::Workflow_Processing_Error, Minor::AL_Communication_Error); + addConversionElement(GlobalStatus::Code::Workflow_Browser_Transmission_Error, Minor::AL_Communication_Error); addConversionElement(GlobalStatus::Code::Workflow_Reader_Became_Inaccessible, Minor::AL_Communication_Error); addConversionElement(GlobalStatus::Code::Workflow_Server_Incomplete_Information_Provided, Minor::AL_Communication_Error); addConversionElement(GlobalStatus::Code::Network_Ssl_Establishment_Error, Minor::AL_Communication_Error); @@ -161,6 +162,8 @@ void ECardApiResult::initConversionMaps() addConversionElement(GlobalStatus::Code::Workflow_Network_Invalid_Scheme, Minor::AL_Communication_Error); addConversionElement(GlobalStatus::Code::Workflow_Network_Malformed_Redirect_Url, Minor::AL_Communication_Error); addConversionElement(GlobalStatus::Code::Network_ServiceUnavailable, Minor::AL_Communication_Error); + addConversionElement(GlobalStatus::Code::Network_ServerError, Minor::AL_Communication_Error); + addConversionElement(GlobalStatus::Code::Network_ClientError, Minor::AL_Communication_Error); addConversionElement(GlobalStatus::Code::Network_TimeOut, Minor::AL_Communication_Error); addConversionElement(GlobalStatus::Code::Network_Proxy_Error, Minor::AL_Communication_Error); addConversionElement(GlobalStatus::Code::Network_Other_Error, Minor::AL_Communication_Error); @@ -171,7 +174,8 @@ void ECardApiResult::initConversionMaps() addConversionElement(GlobalStatus::Code::Paos_Error_DP_Trusted_Channel_Establishment_Failed, Minor::DP_Trusted_Channel_Establishment_Failed); addConversionElement(GlobalStatus::Code::Workflow_TrustedChannel_Establishment_Error, Minor::DP_Trusted_Channel_Establishment_Failed); - addConversionElement(GlobalStatus::Code::Workflow_TrustedChannel_Error_From_Server, Minor::DP_Trusted_Channel_Establishment_Failed); + addConversionElement(GlobalStatus::Code::Workflow_TrustedChannel_Server_Error, Minor::DP_Trusted_Channel_Establishment_Failed); + addConversionElement(GlobalStatus::Code::Workflow_TrustedChannel_Client_Error, Minor::DP_Trusted_Channel_Establishment_Failed); addConversionElement(GlobalStatus::Code::Workflow_TrustedChannel_Hash_Not_In_Description, Minor::DP_Trusted_Channel_Establishment_Failed); addConversionElement(GlobalStatus::Code::Workflow_TrustedChannel_No_Data_Received, Minor::DP_Trusted_Channel_Establishment_Failed); addConversionElement(GlobalStatus::Code::Workflow_TrustedChannel_Ssl_Connection_Unsupported_Algorithm_Or_Length, Minor::DP_Trusted_Channel_Establishment_Failed); @@ -191,11 +195,10 @@ void ECardApiResult::initConversionMaps() addConversionElement(GlobalStatus::Code::Workflow_InternalError_BeforeTcToken, Minor::SAL_Cancellation_by_User); addConversionElement(GlobalStatus::Code::Workflow_Cancellation_By_User, Minor::SAL_Cancellation_by_User); addConversionElement(GlobalStatus::Code::Card_Cancellation_By_User, Minor::SAL_Cancellation_by_User); + addConversionElement(GlobalStatus::Code::Workflow_Card_Removed, Minor::SAL_Cancellation_by_User); addConversionElement(GlobalStatus::Code::Paos_Error_SAL_Invalid_Key, Minor::SAL_Invalid_Key); - addConversionElement(GlobalStatus::Code::Workflow_Card_Removed, Minor::IFDL_CancellationByUser); - addConversionElement(GlobalStatus::Code::Paos_Generic_Server_Error, Minor::AL_Unknown_API_Function); addConversionElement(GlobalStatus::Code::Paos_Generic_Server_Error, Minor::AL_Not_Initialized); addConversionElement(GlobalStatus::Code::Paos_Generic_Server_Error, Minor::AL_Warning_Connection_Disconnected); @@ -207,17 +210,18 @@ void ECardApiResult::initConversionMaps() addConversionElement(GlobalStatus::Code::Paos_Generic_Server_Error, Minor::DP_Unknown_Cipher_Suite); addConversionElement(GlobalStatus::Code::Paos_Generic_Server_Error, Minor::DP_Unknown_Webservice_Binding); addConversionElement(GlobalStatus::Code::Paos_Generic_Server_Error, Minor::DP_Node_Not_Reachable); - addConversionElement(GlobalStatus::Code::Paos_Generic_Server_Error, Minor::SAL_SecurityConditionNotSatisfied); - addConversionElement(GlobalStatus::Code::Paos_Generic_Server_Error, Minor::SAL_MEAC_AgeVerificationFailedWarning); - addConversionElement(GlobalStatus::Code::Paos_Generic_Server_Error, Minor::SAL_MEAC_CommunityVerificationFailedWarning); addConversionElement(GlobalStatus::Code::Paos_Generic_Server_Error, Minor::IFDL_Timeout_Error); addConversionElement(GlobalStatus::Code::Paos_Generic_Server_Error, Minor::IFDL_UnknownSlot); addConversionElement(GlobalStatus::Code::Paos_Generic_Server_Error, Minor::IFDL_InvalidSlotHandle); + addConversionElement(GlobalStatus::Code::Paos_Generic_Server_Error, Minor::IFDL_CancellationByUser); addConversionElement(GlobalStatus::Code::Paos_Generic_Server_Error, Minor::IFDL_IFD_SharingViolation); addConversionElement(GlobalStatus::Code::Paos_Generic_Server_Error, Minor::IFDL_Terminal_NoCard); addConversionElement(GlobalStatus::Code::Paos_Generic_Server_Error, Minor::IFDL_IO_RepeatedDataMismatch); addConversionElement(GlobalStatus::Code::Paos_Generic_Server_Error, Minor::IFDL_IO_UnknownPINFormat); addConversionElement(GlobalStatus::Code::Paos_Generic_Server_Error, Minor::KEY_KeyGenerationNotPossible); + addConversionElement(GlobalStatus::Code::Paos_Generic_Server_Error, Minor::SAL_SecurityConditionNotSatisfied); + addConversionElement(GlobalStatus::Code::Paos_Generic_Server_Error, Minor::SAL_MEAC_AgeVerificationFailedWarning); + addConversionElement(GlobalStatus::Code::Paos_Generic_Server_Error, Minor::SAL_MEAC_CommunityVerificationFailedWarning); } diff --git a/src/global/EnumHelper.h b/src/global/EnumHelper.h index b3147f819..384bd75e1 100644 --- a/src/global/EnumHelper.h +++ b/src/global/EnumHelper.h @@ -16,19 +16,11 @@ namespace governikus { -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - #define defineQHash(enumName)\ +#define defineQHash(enumName)\ inline size_t qHash(enumName pKey, size_t pSeed)\ {\ return ::qHash(static_cast>(pKey), pSeed);\ } -#else - #define defineQHash(enumName)\ - inline uint qHash(enumName pKey, uint pSeed)\ - {\ - return ::qHash(static_cast>(pKey), pSeed);\ - } -#endif #define defineEnumOperators(enumName)\ inline QDebug operator<<(QDebug pDbg, enumName pType)\ diff --git a/src/global/Env.h b/src/global/Env.h index 08329806d..deb9e605b 100644 --- a/src/global/Env.h +++ b/src/global/Env.h @@ -27,10 +27,6 @@ #include #ifndef QT_NO_DEBUG - #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) - #include - #endif - #include #endif diff --git a/src/global/FailureCode.h b/src/global/FailureCode.h index 621183e29..0c376a5bf 100644 --- a/src/global/FailureCode.h +++ b/src/global/FailureCode.h @@ -26,7 +26,6 @@ class FailureCode { User_Cancelled, Card_Removed, - Processing_Send_Status_Failed, Parse_TcToken_Invalid_Url, Parse_TcToken_Missing_Url, Get_TcToken_Invalid_Url, @@ -34,6 +33,9 @@ class FailureCode Get_TcToken_Invalid_Certificate_Key_Length, Get_TcToken_Invalid_Ephemeral_Key_Length, Get_TcToken_Invalid_Server_Reply, + Get_TcToken_ServiceUnavailable, + Get_TcToken_Server_Error, + Get_TcToken_Client_Error, Get_TcToken_Empty_Data, Get_TcToken_Invalid_Data, Get_TcToken_Network_Error, @@ -53,7 +55,6 @@ class FailureCode Connect_Card_Connection_Failed, Connect_Card_Eid_Inactive, Prepace_Pace_Smart_Eid_Invalidated, - Establish_Pace_Channel_No_Active_Pin, Establish_Pace_Channel_Basic_Reader_No_Pin, Establish_Pace_Channel_Puk_Inoperative, Establish_Pace_Channel_User_Cancelled, @@ -66,6 +67,7 @@ class FailureCode Generic_Send_Receive_Network_Error, Generic_Send_Receive_Tls_Error, Generic_Send_Receive_Server_Error, + Generic_Send_Receive_Service_Unavailable, Generic_Send_Receive_Client_Error, Generic_Send_Receive_Paos_Unknown, Generic_Send_Receive_Paos_Unexpected, @@ -78,6 +80,8 @@ class FailureCode Check_Refresh_Address_Fatal_Tls_Error_Before_Reply, Check_Refresh_Address_Invalid_Ephemeral_Key_Length, Check_Refresh_Address_Service_Unavailable, + Check_Refresh_Address_Server_Error, + Check_Refresh_Address_Client_Error, Check_Refresh_Address_Service_Timeout, Check_Refresh_Address_Proxy_Error, Check_Refresh_Address_Fatal_Tls_Error_After_Reply, @@ -89,12 +93,14 @@ class FailureCode Check_Refresh_Address_Fetch_Certificate_Error, Check_Refresh_Address_Unsupported_Certificate, Check_Refresh_Address_Hash_Missing_In_Certificate, - Redirect_Browser_Send_Error_Page_Failed, - Redirect_Browser_Send_Redirect_Failed, + Browser_Send_Failed, Generic_Provider_Communication_Network_Error, Generic_Provider_Communication_Invalid_Ephemeral_Key_Length, Generic_Provider_Communication_Certificate_Error, Generic_Provider_Communication_Tls_Error, + Generic_Provider_Communication_ServiceUnavailable, + Generic_Provider_Communication_Server_Error, + Generic_Provider_Communication_Client_Error, Get_SelfAuthData_Invalid_Or_Empty, Change_Pin_No_SetEidPinCommand_Response, Change_Pin_Input_Timeout, @@ -109,31 +115,54 @@ class FailureCode Establish_Pace_Ifd_Unknown, Enter_Pace_Password_Ifd_User_Cancelled, Enter_New_Pace_Pin_Ifd_User_Cancelled, + Check_Status_Unavailable, + Install_Smart_User_Cancelled, + Delete_Smart_User_Cancelled, + Delete_Personalization_User_Cancelled, + Update_Support_Info_User_Cancelled, + Install_Smart_Service_Response_Fail, + Install_Smart_Service_Response_Unsupported, + Install_Smart_Service_Response_Overload, + Install_Smart_Service_Response_Maintenance, + Install_Smart_Service_Response_Nfc_Disabled, + Install_Smart_Service_Response_Integrity_Check_Failed, + Install_Smart_Service_Response_Not_Authenticated, + Install_Smart_Service_Response_Network_Connection_Error, + Update_Support_Info_Call_Failed, + Update_Support_Info_Service_Response_Fail, + Update_Support_Info_Service_Response_Unsupported, + Update_Support_Info_Service_Response_Overload, + Update_Support_Info_Service_Response_Maintenance, + Update_Support_Info_Service_Response_Nfc_Disabled, + Update_Support_Info_Service_Response_Integrity_Check_Failed, + Update_Support_Info_Service_Response_Not_Authenticated, + Update_Support_Info_Service_Response_Network_Connection_Error, + Delete_Smart_Service_Response_Fail, + Delete_Smart_Service_Response_Unsupported, + Delete_Smart_Service_Response_Overload, + Delete_Smart_Service_Response_Maintenance, + Delete_Smart_Service_Response_Nfc_Disabled, + Delete_Smart_Service_Response_Integrity_Check_Failed, + Delete_Smart_Service_Response_Not_Authenticated, + Delete_Smart_Service_Response_Network_Connection_Error, + Delete_Personalization_Failed, + Check_Applet_Internal_Error, + Get_Session_Id_Invalid, + Smart_ServiceInformation_Query_Failed, + Get_Challenge_Invalid, + Initialize_Personalization_Failed, + Smart_PrePersonalization_Wrong_Status, + Smart_PrePersonalization_Incomplete_Information, Transmit_Personalization_Size_Mismatch, Start_Paos_Response_Personalization_Empty, Start_Paos_Response_Personalization_Invalid, - Prepare_Applet_User_Cancelled, - Prepare_Applet_Status_Call_Failed, - Prepare_Applet_Installation_Loop, - Prepare_Applet_Installation_Failed, - Prepare_Applet_Unavailable, - Prepare_Applet_Delete_Personalization_Failed, - Prepare_Applet_UpdateInfo_Call_Failed, - Prepare_Applet_Delete_Smart_Failed, + Finalize_Personalization_Failed, Insert_Card_No_SmartReader, Insert_Card_Multiple_SmartReader, Insert_Card_Unknown_Eid_Type, - Insert_Card_HW_Keystore, Insert_Card_Invalid_SmartReader, Insert_Card_Missing_Card, - Initialize_Personalization_Failed, - Get_Session_Id_Invalid, - Get_Challenge_Invalid, - Finalize_Personalization_Failed, - Change_Smart_Pin_Failed, - Check_Status_Unavailable, - Check_Applet_Error, - Check_Applet_Unavailable + Change_Smart_Pin_Failed }; Q_ENUM(Reason) diff --git a/src/global/FuncUtils.h b/src/global/FuncUtils.h index 96f810ce2..4048fb6e0 100644 --- a/src/global/FuncUtils.h +++ b/src/global/FuncUtils.h @@ -16,29 +16,6 @@ namespace governikus { -#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) - -/* - * Usage example: map([](const Reader& r){ return r.getName(); }, readers) - * - * where readers has type QVector - */ -template -std::enable_if_t, QVector> map(const std::function& pFunc, const QVector& pItems) -{ - const auto sz = pItems.size(); - QVector result(sz); - for (int index = 0; index < sz; ++index) - { - result[index] = pFunc(pItems[index]); - } - - return result; -} - - -#endif - /* * Usage example: map([](const Reader& r){ return r.getName(); }, readers) diff --git a/src/global/GlobalStatus.cpp b/src/global/GlobalStatus.cpp index 1055a7b1d..624e7d557 100644 --- a/src/global/GlobalStatus.cpp +++ b/src/global/GlobalStatus.cpp @@ -37,10 +37,9 @@ bool GlobalStatus::isMessageMasked() const case Code::Workflow_Certificate_No_Url_In_Description: case Code::Workflow_Certificate_Hash_Error: case Code::Workflow_Certificate_Sop_Error: - case Code::Workflow_Error_Page_Transmission_Error: - case Code::Workflow_Processing_Error: case Code::Workflow_TrustedChannel_Establishment_Error: - case Code::Workflow_TrustedChannel_Error_From_Server: + case Code::Workflow_TrustedChannel_Server_Error: + case Code::Workflow_TrustedChannel_Client_Error: case Code::Workflow_TrustedChannel_No_Data_Received: case Code::Workflow_TrustedChannel_Other_Network_Error: case Code::Network_Other_Error: @@ -182,19 +181,21 @@ QString GlobalStatus::toErrorDescriptionInternal() const //: ERROR_MASKED ALL_PLATFORMS return tr("The subject URL in the certificate description and the TCToken URL do not satisfy the same origin policy."); - case Code::Workflow_Error_Page_Transmission_Error: - case Code::Workflow_Processing_Error: - case Code::Workflow_Redirect_Transmission_Error: + case Code::Workflow_Browser_Transmission_Error: return getExternalInfo(); - case Code::Workflow_TrustedChannel_Error_From_Server: + case Code::Workflow_TrustedChannel_Server_Error: //: ERROR_MASKED ALL_PLATFORMS return tr("The program received an error from the server."); + case Code::Workflow_TrustedChannel_Client_Error: + //: ERROR_MASKED ALL_PLATFORMS + return tr("The server could not process the client request."); + case Code::Workflow_TrustedChannel_Hash_Not_In_Description: case Code::Workflow_Network_Ssl_Hash_Not_In_Certificate_Description: //: ERROR ALL_PLATFORMS The TLS certificate was not folded with the Authorization Certificate, thus violating the security requirements. Might also be caused by a firewall and/or the antivirus software. - return tr("Hash of TLS certificate not in certificate description (issuer: %1). This indicates a misconfiguration or manipulation of the certificate. Please check that your antivirus-software and firewalls are not interfering with TLS traffic.").arg(getExternalInfo(ExternalInformation::CERTIFICATE_ISSUER_NAME)); + return tr("Hash of TLS certificate not in certificate description (issuer: %1). This indicates a misconfiguration or manipulation of the certificate. Please check that your antivirus software and firewall are not interfering with TLS traffic.").arg(getExternalInfo(ExternalInformation::CERTIFICATE_ISSUER_NAME)); case Code::Workflow_TrustedChannel_No_Data_Received: //: ERROR_MASKED ALL_PLATFORMS Received an empty TC token. @@ -205,13 +206,29 @@ QString GlobalStatus::toErrorDescriptionInternal() const //: ERROR ALL_PLATFORMS A server has responded with an HTTP error code 503. return tr("The service is temporarily not available. Please try again later."); + case Code::Network_ServerError: + //: ERROR ALL_PLATFORMS A server has responded with an HTTP error code 5xx. + return tr("The service encountered an internal error while processing a request."); + + case Code::Network_ClientError: + //: ERROR ALL_PLATFORMS A server has responded with an HTTP error code 4xx. + return tr("The service reported an error while processing a client request."); + case Code::Workflow_Smart_eID_Unavailable: //: ERROR ALL_PLATFORMS The device does not support the Smart-eID function return tr("The device does not support Smart-eID."); case Code::Workflow_Smart_eID_Applet_Preparation_Failed: //: ERROR ANDROID The preparation of the Smart-eID Applet failed - return tr("The preparation of the Smart-eID Applet failed."); + return tr("The preparation of the Smart-eID failed."); + + case Code::Workflow_Smart_eID_Authentication_Failed: + //: ERROR ALL_PLATFORMS No sessionID, required for a personalization, was received + return tr("The authentication to the personalization service failed."); + + case Code::Workflow_Smart_eID_ServiceInformation_Query_Failed: + //: ERROR ALL_PLATFORMS Failed to get the ServiceInformation of the Smart-eID + return tr("Failed to get the ServiceInformation of the Smart-eID."); case Code::Workflow_Smart_eID_PrePersonalization_Failed: //: ERROR ALL_PLATFORMS Initialization of Personalization failed @@ -221,6 +238,10 @@ QString GlobalStatus::toErrorDescriptionInternal() const //: ERROR ALL_PLATFORMS Personalization of Smart-eID failed return tr("Personalization of Smart-eID failed."); + case Code::Workflow_Smart_eID_Personalization_Denied: + //: ERROR ALL_PLATFORMS Personalization of Smart-eID is not allowed, no remaining attempts are left. + return tr("You have reached the allowed amount of Smart-eID setups for the current period. You may set up another Smart-eID with your ID card on %1.").arg(getExternalInfo(ExternalInformation::PERSONALIZATION_RESTRICTION_DATE)); + case Code::Network_TimeOut: case Code::Workflow_TrustedChannel_TimeOut: //: ERROR_MASKED ALL_PLATFORMS The TCP connection to the server timed out. @@ -323,10 +344,12 @@ QString GlobalStatus::toErrorDescriptionInternal() const case Code::Card_Protocol_Error: case Code::Card_Unexpected_Transmit_Status: - //: ERROR ALL_PLATFORMS Communication with the card failed due to the specification of the TR (Technische Richtlinie). The protocol was faulty or invalid values were requested/received, - return tr("A protocol error occurred. Please make sure that your ID card is placed correctly on the card reader and try again. If the problem occurs again, please contact our support at %1AusweisApp2 Support%2.").arg( - QStringLiteral("").arg(LanguageLoader::getLocaleCode()), - QStringLiteral("")); + //: ERROR ALL_PLATFORMS Communication with the card failed due to the specification of the TR (Technische Richtlinie). The protocol was faulty or invalid values were requested/received. %1 is a html link to the support. + return tr("A protocol error occurred. Please make sure that your ID card is placed correctly on the card reader and try again. If the problem occurs again, please contact our support at %1.").arg( + QStringLiteral("%2").arg( + LanguageLoader::getLocaleCode(), + //: LABEL ALL_PLATFORMS Link text to the app support. %1 is the app name. + tr("%1 Support").arg(QCoreApplication::applicationName()))); case Code::Card_Invalid_Pin: //: ERROR ALL_PLATFORMS The ID card declined the PIN. @@ -366,7 +389,7 @@ QString GlobalStatus::toErrorDescriptionInternal() const case Code::Card_Smart_Invalid: //: ERROR ALL_PLATFORMS The existing Smart-eID was invalidated. - return tr("The Smart-eID is invalid. This might have been caused by entering the wrong Smart-eID PIN three times."); + return tr("The Smart-eID is no longer ready for use. This might have been caused by entering the wrong Smart-eID PIN three times. You may personalize a new Smart-eID to resolve the issue."); case Code::RemoteReader_CloseCode_AbnormalClose: //: ERROR ALL_PLATFORMS The connection to the smartphone card reader (SaK) was lost. @@ -378,7 +401,7 @@ QString GlobalStatus::toErrorDescriptionInternal() const case Code::IfdConnector_NoSupportedApiLevel: //: ERROR ALL_PLATFORMS The requested connection to the smartphone card reader (SaK) was invalid (API mismatch). - return tr("Your smartphone as card reader (SaC) version is incompatible with the local version. Please install the latest AusweisApp2 version on both your smartphone and your computer."); + return tr("Your smartphone as card reader (SaC) version is incompatible with the local version. Please install the latest %1 version on both your smartphone and your computer.").arg(QCoreApplication::applicationName()); case Code::IfdConnector_ConnectionTimeout: //: ERROR ALL_PLATFORMS The requested connection to the smartphone card reader (SaK) timed out. diff --git a/src/global/GlobalStatus.h b/src/global/GlobalStatus.h index 609fbb5a2..6dbce327e 100644 --- a/src/global/GlobalStatus.h +++ b/src/global/GlobalStatus.h @@ -30,6 +30,8 @@ class GlobalStatus No_Error, Network_ServiceUnavailable, + Network_ServerError, + Network_ClientError, Network_Ssl_Establishment_Error, Network_TimeOut, Network_Proxy_Error, @@ -62,11 +64,10 @@ class GlobalStatus Workflow_Certificate_No_Url_In_Description, Workflow_Certificate_Hash_Error, Workflow_Certificate_Sop_Error, - Workflow_Error_Page_Transmission_Error, - Workflow_Redirect_Transmission_Error, - Workflow_Processing_Error, + Workflow_Browser_Transmission_Error, Workflow_TrustedChannel_Establishment_Error, - Workflow_TrustedChannel_Error_From_Server, + Workflow_TrustedChannel_Server_Error, + Workflow_TrustedChannel_Client_Error, Workflow_TrustedChannel_Hash_Not_In_Description, Workflow_TrustedChannel_No_Data_Received, Workflow_TrustedChannel_Ssl_Connection_Unsupported_Algorithm_Or_Length, @@ -88,8 +89,11 @@ class GlobalStatus Workflow_Wrong_Parameter_Invocation, Workflow_Smart_eID_Unavailable, Workflow_Smart_eID_Applet_Preparation_Failed, + Workflow_Smart_eID_Authentication_Failed, + Workflow_Smart_eID_ServiceInformation_Query_Failed, Workflow_Smart_eID_PrePersonalization_Failed, Workflow_Smart_eID_Personalization_Failed, + Workflow_Smart_eID_Personalization_Denied, Paos_Unexpected_Warning, @@ -143,7 +147,8 @@ class GlobalStatus REDIRECT_URL, CERTIFICATE_ISSUER_NAME, URL_SCHEME, - ACTIVATION_ERROR + ACTIVATION_ERROR, + PERSONALIZATION_RESTRICTION_DATE }; using ExternalInfoMap = QMap; diff --git a/src/global/JsonValueRef.h b/src/global/JsonValueRef.h deleted file mode 100644 index f03e330c0..000000000 --- a/src/global/JsonValueRef.h +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022-2023 Governikus GmbH & Co. KG, Germany - */ - -/*! - * \brief Compatibility helper for Qt5/Qt6 JSON stuff. - */ - -#pragma once - -#include - -#if (QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)) -using JsonValueRef = const QJsonValueConstRef; -#elif (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) -using JsonValueRef = const QJsonValueRef; -#else -using JsonValueRef = const QJsonValue&; -#endif diff --git a/src/global/LogHandler.cpp b/src/global/LogHandler.cpp index b69a08d00..db3fab0c9 100644 --- a/src/global/LogHandler.cpp +++ b/src/global/LogHandler.cpp @@ -205,7 +205,7 @@ bool LogHandler::hasCriticalLog() const } -int LogHandler::getCriticalLogCapacity() const +qsizetype LogHandler::getCriticalLogCapacity() const { return mCriticalLogWindow.capacity(); } @@ -259,9 +259,9 @@ void LogHandler::copyMessageLogContext(const QMessageLogContext& pSource, const QByteArray& pFunction, const QByteArray& pCategory) const { - pDestination.file = pFilename.isNull() ? pSource.file : pFilename.constData(); - pDestination.function = pFunction.isNull() ? pSource.function : pFunction.constData(); - pDestination.category = pCategory.isNull() ? pSource.category : pCategory.constData(); + pDestination.file = pFilename.isNull() ? "" : pFilename.constData(); + pDestination.function = pFunction.isNull() ? "" : pFunction.constData(); + pDestination.category = pCategory.isNull() ? "" : pCategory.constData(); pDestination.line = pSource.line; pDestination.version = pSource.version; @@ -304,7 +304,7 @@ QByteArray LogHandler::formatFunction(const char* const pFunction, const QByteAr } // Trim function name - const auto size = mFunctionFilenameSize - 3 - pFilename.size() - QString::number(pLine).size(); + const auto size = mFunctionFilenameSize - 3 - pFilename.size() - QByteArray::number(pLine).size(); if (size >= function.size()) { @@ -338,9 +338,11 @@ QByteArray LogHandler::formatCategory(const QByteArray& pCategory) const QString LogHandler::getPaddedLogMsg(const QMessageLogContext& pContext, const QString& pMsg) const { - const auto paddingSize = (pContext.function == nullptr && pContext.file == nullptr && pContext.line == 0) ? - mFunctionFilenameSize - 18 : // padding for nullptr == "unknown(unknown:0)" - mFunctionFilenameSize - 3 - static_cast(qstrlen(pContext.function)) - static_cast(qstrlen(pContext.file)) - QString::number(pContext.line).size(); + const auto paddingSize = mFunctionFilenameSize + - 3 + - static_cast(qstrlen(pContext.function)) + - static_cast(qstrlen(pContext.file)) + - QByteArray::number(pContext.line).size(); QString padding; padding.reserve(paddingSize + pMsg.size() + 3); diff --git a/src/global/LogHandler.h b/src/global/LogHandler.h index c96c7460a..265834802 100644 --- a/src/global/LogHandler.h +++ b/src/global/LogHandler.h @@ -144,7 +144,7 @@ class LogHandler QByteArray getBacklog(bool pAll = false); QByteArray getCriticalLogWindow(); [[nodiscard]] bool hasCriticalLog() const; - [[nodiscard]] int getCriticalLogCapacity() const; + [[nodiscard]] qsizetype getCriticalLogCapacity() const; void setCriticalLogCapacity(int pSize); static QDateTime getFileDate(const QFileInfo& pInfo); diff --git a/src/global/ResourceLoader.cpp b/src/global/ResourceLoader.cpp index 9e62d177a..d6e87d648 100644 --- a/src/global/ResourceLoader.cpp +++ b/src/global/ResourceLoader.cpp @@ -19,7 +19,7 @@ defineSingleton(ResourceLoader) ResourceLoader::ResourceLoader() : mFilenames( { - QStringLiteral("AusweisApp2.rcc") + QStringLiteral("AusweisApp.rcc") }) , mLoadedResources() { diff --git a/src/global/VersionInfo.cpp b/src/global/VersionInfo.cpp index ae1735479..9da3c144c 100644 --- a/src/global/VersionInfo.cpp +++ b/src/global/VersionInfo.cpp @@ -50,13 +50,13 @@ VersionInfo::VersionInfo() VersionInfo VersionInfo::getInstance() { return VersionInfo({ - {NAME(), QCoreApplication::applicationName()}, - {IMPL_TITLE(), QCoreApplication::applicationName()}, + {NAME(), QStringLiteral("AusweisApp2")}, + {IMPL_TITLE(), QStringLiteral("AusweisApp2")}, {IMPL_VENDOR(), QCoreApplication::organizationName()}, {IMPL_VERSION(), QCoreApplication::applicationVersion()}, - {SPEC_TITLE(), QStringLiteral("TR-03124")}, + {SPEC_TITLE(), QStringLiteral("TR-03124-1")}, {SPEC_VENDOR(), QStringLiteral("Federal Office for Information Security")}, - {SPEC_VERSION(), QStringLiteral("1.3")} + {SPEC_VERSION(), QStringLiteral("1.4")} }); } @@ -65,12 +65,7 @@ VersionInfo VersionInfo::fromText(const QString& pText) { QMap infos; -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) const auto& header = QStringView(pText).split(QLatin1Char('\n')); -#else - const auto& header = pText.splitRef(QLatin1Char('\n')); -#endif - for (const auto& line : header) { const auto pair = line.split(QLatin1Char(':')); diff --git a/src/global/VersionNumber.cpp b/src/global/VersionNumber.cpp index dd5072958..ab2fa0265 100644 --- a/src/global/VersionNumber.cpp +++ b/src/global/VersionNumber.cpp @@ -17,16 +17,8 @@ VersionNumber::VersionNumber(const QString& pVersion) : mVersionNumber() , mSuffix() { -#if (QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)) qsizetype idx = 0; -#else - int idx = 0; -#endif - mVersionNumber = QVersionNumber::fromString(pVersion, &idx); -#ifdef Q_CC_GNU - __sync_synchronize(); // QTBUG-62185 -#endif mSuffix = pVersion.mid(idx).trimmed(); } @@ -51,33 +43,20 @@ bool VersionNumber::isDeveloperVersion() const bool VersionNumber::isBetaVersion() const { - return mVersionNumber.minorVersion() & 1; + return mVersionNumber.minorVersion() >= 100 || mVersionNumber.microVersion() >= 100; } auto VersionNumber::getInfoFromSuffix(QLatin1Char pStart, QLatin1Char pEnd) const { -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) QStringView view; -#else - QStringRef view; -#endif if (const auto indexStart = mSuffix.indexOf(pStart) + 1; indexStart > 0) { -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) view = QStringView(mSuffix).sliced(indexStart); -#else - view = mSuffix.midRef(indexStart); -#endif - if (const auto indexEnd = view.indexOf(pEnd); indexEnd > 0) { -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) view = view.sliced(0, indexEnd); -#else - view = view.mid(0, indexEnd); -#endif } } diff --git a/src/ifd/base/ConnectRequest.cpp b/src/ifd/base/ConnectRequest.cpp index eee296f52..4a47ea4fd 100644 --- a/src/ifd/base/ConnectRequest.cpp +++ b/src/ifd/base/ConnectRequest.cpp @@ -178,7 +178,7 @@ void ConnectRequest::onTimeout() } -void ConnectRequest::onPreSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator* pAuthenticator) +void ConnectRequest::onPreSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator* pAuthenticator) const { qCDebug(ifd) << "Request pairing..."; pAuthenticator->setPreSharedKey(mPsk); @@ -215,11 +215,7 @@ void ConnectRequest::onSslErrors(const QList& pErrors) if (ignoreErrors) { -#if defined(GOVERNIKUS_QT) || (QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)) mSocket->ignoreSslErrors(pErrors); -#else - mSocket->ignoreSslErrors(); -#endif return; } diff --git a/src/ifd/base/ConnectRequest.h b/src/ifd/base/ConnectRequest.h index 26affe5da..dbc89c1cf 100644 --- a/src/ifd/base/ConnectRequest.h +++ b/src/ifd/base/ConnectRequest.h @@ -29,7 +29,7 @@ class ConnectRequest void onConnected(); void onError(QAbstractSocket::SocketError pError); void onTimeout(); - void onPreSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator* pAuthenticator); + void onPreSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator* pAuthenticator) const; void onSslErrors(const QList& pErrors); public: diff --git a/src/ifd/base/IfdClientImpl.cpp b/src/ifd/base/IfdClientImpl.cpp index 2fec99e1b..64b2b224e 100644 --- a/src/ifd/base/IfdClientImpl.cpp +++ b/src/ifd/base/IfdClientImpl.cpp @@ -5,7 +5,6 @@ #include "IfdClientImpl.h" #include "AppSettings.h" -#include "IfdConnectorImpl.h" #include diff --git a/src/ifd/base/IfdConnector.h b/src/ifd/base/IfdConnector.h index 99d391adb..7ba73e1fc 100644 --- a/src/ifd/base/IfdConnector.h +++ b/src/ifd/base/IfdConnector.h @@ -11,7 +11,6 @@ #include "EnumHelper.h" #include "IfdDescriptor.h" #include "IfdDispatcherClient.h" -#include "messages/IfdMessage.h" #include diff --git a/src/ifd/base/IfdConnectorImpl.cpp b/src/ifd/base/IfdConnectorImpl.cpp index a910a266f..03dd7f9eb 100644 --- a/src/ifd/base/IfdConnectorImpl.cpp +++ b/src/ifd/base/IfdConnectorImpl.cpp @@ -5,17 +5,10 @@ #include "IfdConnectorImpl.h" #include "Env.h" -#include "IfdDispatcher.h" -#include "SecureStorage.h" #include "WebSocketChannel.h" #include - -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) - #include -#else - #include -#endif +#include Q_DECLARE_LOGGING_CATEGORY(ifd) @@ -100,7 +93,6 @@ void IfdConnectorImpl::onConnectRequest(const IfdDescriptor& pIfdDescriptor, con return; } - // Currently, we only support API level 1. if (!pIfdDescriptor.isSupported()) { Q_EMIT fireDispatcherError(pIfdDescriptor, IfdErrorCode::NO_SUPPORTED_API_LEVEL); diff --git a/src/ifd/base/IfdDispatcher.cpp b/src/ifd/base/IfdDispatcher.cpp index 32e206a1b..2b041ceba 100644 --- a/src/ifd/base/IfdDispatcher.cpp +++ b/src/ifd/base/IfdDispatcher.cpp @@ -5,7 +5,6 @@ #include "IfdDispatcher.h" #include "AppSettings.h" -#include "Initializer.h" #include "messages/IfdError.h" #include "messages/IfdVersion.h" @@ -123,7 +122,7 @@ IfdVersion::Version IfdDispatcher::getVersion() const } -void IfdDispatcher::saveRemoteNameInSettings(const QString& pName) +void IfdDispatcher::saveRemoteNameInSettings(const QString& pName) const { RemoteServiceSettings& settings = Env::getSingleton()->getRemoteServiceSettings(); auto info = settings.getRemoteInfo(getId()); diff --git a/src/ifd/base/IfdDispatcher.h b/src/ifd/base/IfdDispatcher.h index 883d8e8cc..40dfda30d 100644 --- a/src/ifd/base/IfdDispatcher.h +++ b/src/ifd/base/IfdDispatcher.h @@ -50,7 +50,7 @@ class IfdDispatcher [[nodiscard]] virtual QString getId() const; [[nodiscard]] virtual const QString& getContextHandle() const; [[nodiscard]] IfdVersion::Version getVersion() const; - void saveRemoteNameInSettings(const QString& pName); + void saveRemoteNameInSettings(const QString& pName) const; void close(); Q_INVOKABLE virtual void send(const QSharedPointer& pMessage); diff --git a/src/ifd/base/IfdDispatcherServer.cpp b/src/ifd/base/IfdDispatcherServer.cpp index 631df85f1..76e25c1b2 100644 --- a/src/ifd/base/IfdDispatcherServer.cpp +++ b/src/ifd/base/IfdDispatcherServer.cpp @@ -7,7 +7,6 @@ #include "AppSettings.h" #include "Initializer.h" #include "Randomizer.h" -#include "messages/IfdError.h" #include "messages/IfdEstablishContext.h" #include "messages/IfdEstablishContextResponse.h" diff --git a/src/ifd/base/IfdList.cpp b/src/ifd/base/IfdList.cpp index 45e6108f9..0c54ffcfe 100644 --- a/src/ifd/base/IfdList.cpp +++ b/src/ifd/base/IfdList.cpp @@ -2,25 +2,16 @@ * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany */ -#include "IfdList.h" - #include "Env.h" -#include "Initializer.h" +#include "IfdListImpl.h" #include using namespace governikus; -INIT_FUNCTION([] { - qRegisterMetaType>("QSharedPointer"); - qRegisterMetaType>>("QVector>"); - }) - - namespace governikus { - template<> IfdList* createNewObject() { return new IfdListImpl(); @@ -36,178 +27,7 @@ template<> IfdList* createNewObject(int&& pCheckInterval, in } // namespace governikus -IfdListEntry::IfdListEntry(const IfdDescriptor& pIfdDescriptor) - : mIfdDescriptor(pIfdDescriptor) - , mLastSeen(QTime::currentTime()) - , mLastSeenHistory() -{ -} - - -void IfdListEntry::setLastSeenToNow() -{ - if (mLastSeen.isValid()) - { - mLastSeenHistory += mLastSeen; - } - - mLastSeen = QTime::currentTime(); -} - - -bool IfdListEntry::cleanUpSeenTimestamps(int pReaderResponsiveTimeout) -{ - bool entryRemoved = false; - const int visibilityOld = getPercentSeen(); - - const QTime threshold(QTime::currentTime().addMSecs(-pReaderResponsiveTimeout)); - QMutableVectorIterator i(mLastSeenHistory); - while (i.hasNext()) - { - if (i.next() < threshold) - { - i.remove(); - entryRemoved = true; - } - } - - return entryRemoved && getPercentSeen() != visibilityOld; -} - - -int IfdListEntry::getPercentSeen(int pCheckInterval, int pTimeFrame) const -{ - const int count = mLastSeenHistory.size(); - const int expectedMax = pTimeFrame / pCheckInterval; - const int percent = 100 * count / expectedMax; - - // Maximum is calculated based on the assumption, that only IPv4 is in use. - // If IPv6 is used in parallel - even better. - return qMin(percent, 100); -} - - -void IfdListEntry::setIfdDescriptor(const IfdDescriptor& pIfdDescriptor) -{ - mIfdDescriptor = pIfdDescriptor; -} - - -bool IfdListEntry::containsEquivalent(const IfdDescriptor& pIfdDescriptor) const -{ - return mIfdDescriptor.isSameIfd(pIfdDescriptor); -} - - -bool IfdListEntry::isEqual(const IfdListEntry* const pOther) const -{ - return pOther != nullptr && - mIfdDescriptor == pOther->mIfdDescriptor && - mLastSeen == pOther->mLastSeen; -} - - -const QTime& IfdListEntry::getLastSeen() const -{ - return mLastSeen; -} - - -const IfdDescriptor& IfdListEntry::getIfdDescriptor() const -{ - return mIfdDescriptor; -} - - QVector> IfdList::getIfdList() const { return QVector>(); } - - -IfdListImpl::IfdListImpl(int pCheckInterval, int pReaderResponsiveTimeout) - : IfdList() - , mTimer() - , mReaderResponsiveTimeout(pReaderResponsiveTimeout) - , mResponsiveList() -{ - connect(&mTimer, &QTimer::timeout, this, &IfdListImpl::onProcessUnresponsiveRemoteReaders); - pCheckInterval = pCheckInterval / 2 - 1; // Nyquist-Shannon sampling theorem. Enable smooth UI updates. - mTimer.setInterval(pCheckInterval); -} - - -IfdListImpl::~IfdListImpl() -{ - mTimer.stop(); -} - - -void IfdListImpl::update(const IfdDescriptor& pDescriptor) -{ - for (const QSharedPointer& entry : std::as_const(mResponsiveList)) - { - if (entry->containsEquivalent(pDescriptor)) - { - entry->setLastSeenToNow(); - entry->setIfdDescriptor(pDescriptor); - Q_EMIT fireDeviceUpdated(entry); - - return; - } - } - - const auto& newDevice = QSharedPointer::create(pDescriptor); - mResponsiveList += newDevice; - - if (!mTimer.isActive()) - { - mTimer.start(); - } - - Q_EMIT fireDeviceAppeared(newDevice); -} - - -void IfdListImpl::clear() -{ - decltype(mResponsiveList) removedDevices; - mResponsiveList.swap(removedDevices); - for (const auto& entry : std::as_const(removedDevices)) - { - Q_EMIT fireDeviceVanished(entry); - } -} - - -QVector> IfdListImpl::getIfdList() const -{ - return mResponsiveList; -} - - -void IfdListImpl::onProcessUnresponsiveRemoteReaders() -{ - const QTime threshold(QTime::currentTime().addMSecs(-mReaderResponsiveTimeout)); - QMutableVectorIterator> i(mResponsiveList); - while (i.hasNext()) - { - const QSharedPointer entry = i.next(); - if (entry->getLastSeen() < threshold) - { - i.remove(); - Q_EMIT fireDeviceVanished(entry); - continue; - } - - if (entry->cleanUpSeenTimestamps(mReaderResponsiveTimeout)) - { - Q_EMIT fireDeviceUpdated(entry); - } - } - - if (mResponsiveList.isEmpty()) - { - mTimer.stop(); - } -} diff --git a/src/ifd/base/IfdList.h b/src/ifd/base/IfdList.h index 1d5034d44..23e68084e 100644 --- a/src/ifd/base/IfdList.h +++ b/src/ifd/base/IfdList.h @@ -9,41 +9,14 @@ #pragma once #include "IfdDescriptor.h" +#include "IfdListEntry.h" -#include -#include +#include namespace governikus { -class IfdListEntry -{ - Q_DISABLE_COPY(IfdListEntry) - - private: - IfdDescriptor mIfdDescriptor; - QTime mLastSeen; - QVector mLastSeenHistory; - - public: - explicit IfdListEntry(const IfdDescriptor& pIfdDescriptor); - - void setLastSeenToNow(); - bool cleanUpSeenTimestamps(int pReaderResponsiveTimeout); - [[nodiscard]] int getPercentSeen(int pCheckInterval = 1000, int pTimeFrame = 5000) const; - - void setIfdDescriptor(const IfdDescriptor& pIfdDescriptor); - - [[nodiscard]] bool containsEquivalent(const IfdDescriptor& pIfdDescriptor) const; - bool isEqual(const IfdListEntry* const pOther) const; - - [[nodiscard]] const QTime& getLastSeen() const; - [[nodiscard]] const IfdDescriptor& getIfdDescriptor() const; - -}; - - class IfdList : public QObject { @@ -63,28 +36,4 @@ class IfdList [[nodiscard]] virtual QVector> getIfdList() const; }; - -class IfdListImpl - : public IfdList -{ - Q_OBJECT - - private: - QTimer mTimer; - const int mReaderResponsiveTimeout; - QVector> mResponsiveList; - - private Q_SLOTS: - void onProcessUnresponsiveRemoteReaders(); - - public: - IfdListImpl(int pCheckInterval = 1000, int pReaderResponsiveTimeout = 5000); - ~IfdListImpl() override; - - void update(const IfdDescriptor& pDescriptor) override; - void clear() override; - [[nodiscard]] QVector> getIfdList() const override; -}; - - } // namespace governikus diff --git a/src/ifd/base/IfdListEntry.cpp b/src/ifd/base/IfdListEntry.cpp new file mode 100644 index 000000000..e80731b68 --- /dev/null +++ b/src/ifd/base/IfdListEntry.cpp @@ -0,0 +1,100 @@ +/** + * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany + */ + +#include "IfdListEntry.h" +#include "Initializer.h" + +#include + + +using namespace governikus; + + +INIT_FUNCTION([] { + qRegisterMetaType>("QSharedPointer"); + qRegisterMetaType>>("QVector>"); + }) + + +IfdListEntry::IfdListEntry(const IfdDescriptor& pIfdDescriptor) + : mIfdDescriptor(pIfdDescriptor) + , mLastSeen(QTime::currentTime()) + , mLastSeenHistory() +{ +} + + +void IfdListEntry::setLastSeenToNow() +{ + if (mLastSeen.isValid()) + { + mLastSeenHistory += mLastSeen; + } + + mLastSeen = QTime::currentTime(); +} + + +bool IfdListEntry::cleanUpSeenTimestamps(int pReaderResponsiveTimeout) +{ + bool entryRemoved = false; + const auto visibilityOld = getPercentSeen(); + + const QTime threshold(QTime::currentTime().addMSecs(-pReaderResponsiveTimeout)); + QMutableVectorIterator i(mLastSeenHistory); + while (i.hasNext()) + { + if (i.next() < threshold) + { + i.remove(); + entryRemoved = true; + } + } + + return entryRemoved && getPercentSeen() != visibilityOld; +} + + +int IfdListEntry::getPercentSeen(int pCheckInterval, int pTimeFrame) const +{ + const int count = static_cast(mLastSeenHistory.size()); + const int expectedMax = pTimeFrame / pCheckInterval; + const int percent = 100 * count / expectedMax; + + // Maximum is calculated based on the assumption, that only IPv4 is in use. + // If IPv6 is used in parallel - even better. + return std::min(percent, 100); +} + + +void IfdListEntry::setIfdDescriptor(const IfdDescriptor& pIfdDescriptor) +{ + mIfdDescriptor = pIfdDescriptor; +} + + +bool IfdListEntry::containsEquivalent(const IfdDescriptor& pIfdDescriptor) const +{ + return mIfdDescriptor.isSameIfd(pIfdDescriptor); +} + + +bool IfdListEntry::isEqual(const IfdListEntry* const pOther) const +{ + return pOther != nullptr && + mIfdDescriptor == pOther->mIfdDescriptor && + mLastSeen == pOther->mLastSeen; +} + + +const QTime& IfdListEntry::getLastSeen() const +{ + return mLastSeen; +} + + +const IfdDescriptor& IfdListEntry::getIfdDescriptor() const +{ + return mIfdDescriptor; +} diff --git a/src/ifd/base/IfdListEntry.h b/src/ifd/base/IfdListEntry.h new file mode 100644 index 000000000..330c89fbb --- /dev/null +++ b/src/ifd/base/IfdListEntry.h @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany + */ + +/*! + * \brief Interface for IfdList + */ + +#pragma once + +#include "IfdDescriptor.h" + +#include +#include + + +namespace governikus +{ + +class IfdListEntry +{ + Q_DISABLE_COPY(IfdListEntry) + + private: + IfdDescriptor mIfdDescriptor; + QTime mLastSeen; + QVector mLastSeenHistory; + + public: + explicit IfdListEntry(const IfdDescriptor& pIfdDescriptor); + + void setLastSeenToNow(); + bool cleanUpSeenTimestamps(int pReaderResponsiveTimeout); + [[nodiscard]] int getPercentSeen(int pCheckInterval = 1000, int pTimeFrame = 5000) const; + + void setIfdDescriptor(const IfdDescriptor& pIfdDescriptor); + + [[nodiscard]] bool containsEquivalent(const IfdDescriptor& pIfdDescriptor) const; + bool isEqual(const IfdListEntry* const pOther) const; + + [[nodiscard]] const QTime& getLastSeen() const; + [[nodiscard]] const IfdDescriptor& getIfdDescriptor() const; + +}; + +} // namespace governikus diff --git a/src/ifd/base/IfdListImpl.cpp b/src/ifd/base/IfdListImpl.cpp new file mode 100644 index 000000000..30d466e09 --- /dev/null +++ b/src/ifd/base/IfdListImpl.cpp @@ -0,0 +1,96 @@ +/** + * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany + */ + +#include "IfdListImpl.h" + + +using namespace governikus; + + +IfdListImpl::IfdListImpl(int pCheckInterval, int pReaderResponsiveTimeout) + : IfdList() + , mTimer() + , mReaderResponsiveTimeout(pReaderResponsiveTimeout) + , mResponsiveList() +{ + connect(&mTimer, &QTimer::timeout, this, &IfdListImpl::onProcessUnresponsiveRemoteReaders); + pCheckInterval = pCheckInterval / 2 - 1; // Nyquist-Shannon sampling theorem. Enable smooth UI updates. + mTimer.setInterval(pCheckInterval); +} + + +IfdListImpl::~IfdListImpl() +{ + mTimer.stop(); +} + + +void IfdListImpl::update(const IfdDescriptor& pDescriptor) +{ + for (const QSharedPointer& entry : std::as_const(mResponsiveList)) + { + if (entry->containsEquivalent(pDescriptor)) + { + entry->setLastSeenToNow(); + entry->setIfdDescriptor(pDescriptor); + Q_EMIT fireDeviceUpdated(entry); + + return; + } + } + + const auto& newDevice = QSharedPointer::create(pDescriptor); + mResponsiveList += newDevice; + + if (!mTimer.isActive()) + { + mTimer.start(); + } + + Q_EMIT fireDeviceAppeared(newDevice); +} + + +void IfdListImpl::clear() +{ + decltype(mResponsiveList) removedDevices; + mResponsiveList.swap(removedDevices); + for (const auto& entry : std::as_const(removedDevices)) + { + Q_EMIT fireDeviceVanished(entry); + } +} + + +QVector> IfdListImpl::getIfdList() const +{ + return mResponsiveList; +} + + +void IfdListImpl::onProcessUnresponsiveRemoteReaders() +{ + const QTime threshold(QTime::currentTime().addMSecs(-mReaderResponsiveTimeout)); + QMutableVectorIterator> i(mResponsiveList); + while (i.hasNext()) + { + const QSharedPointer entry = i.next(); + if (entry->getLastSeen() < threshold) + { + i.remove(); + Q_EMIT fireDeviceVanished(entry); + continue; + } + + if (entry->cleanUpSeenTimestamps(mReaderResponsiveTimeout)) + { + Q_EMIT fireDeviceUpdated(entry); + } + } + + if (mResponsiveList.isEmpty()) + { + mTimer.stop(); + } +} diff --git a/src/ifd/base/IfdListImpl.h b/src/ifd/base/IfdListImpl.h new file mode 100644 index 000000000..ca5fc3029 --- /dev/null +++ b/src/ifd/base/IfdListImpl.h @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany + */ + +/*! + * \brief Interface for IfdList + */ + +#pragma once + +#include "IfdList.h" + +#include + + +namespace governikus +{ + +class IfdListImpl + : public IfdList +{ + Q_OBJECT + + private: + QTimer mTimer; + const int mReaderResponsiveTimeout; + QVector> mResponsiveList; + + private Q_SLOTS: + void onProcessUnresponsiveRemoteReaders(); + + public: + IfdListImpl(int pCheckInterval = 1000, int pReaderResponsiveTimeout = 5000); + ~IfdListImpl() override; + + void update(const IfdDescriptor& pDescriptor) override; + void clear() override; + [[nodiscard]] QVector> getIfdList() const override; +}; + +} // namespace governikus diff --git a/src/ifd/base/IfdReader.cpp b/src/ifd/base/IfdReader.cpp index ec43fd048..c8f6d8923 100644 --- a/src/ifd/base/IfdReader.cpp +++ b/src/ifd/base/IfdReader.cpp @@ -80,15 +80,7 @@ void IfdReader::updateStatus(const IfdStatus& pIfdStatus) if (pIfdStatus.getCardAvailable()) { mCard.reset(new IfdCard(mDispatcher, getName())); - QSharedPointer cardConnection = createCardConnectionWorker(); - fetchCardInfo(cardConnection); - - if (getReaderInfo().getCardType() == CardType::SMART_EID) - { - qCDebug(card_remote) << "Card received but not inserted"; - shelveCard(); - return; - } + fetchCardInfo(); qCDebug(card_remote) << "Card inserted"; Q_EMIT fireCardInserted(getReaderInfo()); diff --git a/src/ifd/base/IfdReaderManagerPlugIn.cpp b/src/ifd/base/IfdReaderManagerPlugIn.cpp index bc2b9b45f..c886d8b72 100644 --- a/src/ifd/base/IfdReaderManagerPlugIn.cpp +++ b/src/ifd/base/IfdReaderManagerPlugIn.cpp @@ -4,7 +4,6 @@ #include "IfdReaderManagerPlugIn.h" -#include "AppSettings.h" #include "IfdReader.h" #include "messages/IfdError.h" #include "messages/IfdGetStatus.h" @@ -27,8 +26,14 @@ void IfdReaderManagerPlugIn::removeDispatcher(const QString& pId) continue; } - QScopedPointer reader(mReaderList.take(readerName)); - Q_EMIT fireReaderRemoved(reader->getReaderInfo()); + if (QScopedPointer reader(mReaderList.take(readerName)); reader) + { + Q_EMIT fireReaderRemoved(reader->getReaderInfo()); + } + else + { + Q_EMIT fireReaderRemoved(ReaderInfo(readerName)); + } mReadersForDispatcher.remove(pId, readerName); } @@ -63,49 +68,70 @@ void IfdReaderManagerPlugIn::handleIFDStatus(const QJsonObject& pJsonObject, con const QString& contextHandle = dispatcher->getContextHandle(); const QString& readerName = ifdStatus.getSlotName() + contextHandle; - if (mReaderList.contains(readerName)) + if (ifdStatus.getConnectedReader()) { - if (ifdStatus.getConnectedReader()) + bool newReader = false; + if (mReaderList.contains(readerName)) { if (auto* reader = mReaderList.value(readerName); reader) { + qCDebug(card_remote) << "Update reader" << readerName; static_cast(reader)->updateStatus(ifdStatus); + return; } + qCDebug(card_remote) << "Enable reader" << readerName; } else { - qCDebug(card_remote) << "Removed reader" << readerName; - - if (QScopedPointer reader(mReaderList.take(readerName)); reader) - { - Q_EMIT fireReaderRemoved(reader->getReaderInfo()); - mReadersForDispatcher.remove(pId, readerName); - } + qCDebug(card_remote) << "Add reader" << readerName; + newReader = true; } - return; - } - if (ifdStatus.getConnectedReader()) - { auto reader = new IfdReader(getInfo().getPlugInType(), readerName, dispatcher, ifdStatus); - connect(reader, &IfdReader::fireCardInserted, this, &IfdReaderManagerPlugIn::fireCardInserted); connect(reader, &IfdReader::fireCardRemoved, this, &IfdReaderManagerPlugIn::fireCardRemoved); connect(reader, &IfdReader::fireCardInfoChanged, this, &IfdReaderManagerPlugIn::fireCardInfoChanged); connect(reader, &IfdReader::fireReaderPropertiesUpdated, this, &IfdReaderManagerPlugIn::fireReaderPropertiesUpdated); mReaderList.insert(readerName, reader); - mReadersForDispatcher.insert(pId, readerName); - qCDebug(card_remote) << "Add reader" << readerName; - Q_EMIT fireReaderAdded(reader->getReaderInfo()); + if (newReader) + { + mReadersForDispatcher.insert(pId, readerName); + Q_EMIT fireReaderAdded(reader->getReaderInfo()); + } + else + { + Q_EMIT fireReaderPropertiesUpdated(reader->getReaderInfo()); + } // Also update card reader->updateStatus(ifdStatus); + + return; } + + ReaderInfo readerInfo(readerName); + readerInfo.setBasicReader(!ifdStatus.hasPinPad()); + readerInfo.setMaxApduLength(ifdStatus.getMaxApduLength()); + if (mReaderList.contains(readerName)) + { + qCDebug(card_remote) << "Disable reader" << readerName; + if (QScopedPointer reader(mReaderList.take(readerName)); reader) + { + mReaderList.insert(readerName, nullptr); + } + Q_EMIT fireReaderPropertiesUpdated(readerInfo); + return; + } + + qCDebug(card_remote) << "Advertise reader" << readerName; + mReaderList.insert(readerName, nullptr); + mReadersForDispatcher.insert(pId, readerName); + Q_EMIT fireReaderAdded(readerInfo); } -void IfdReaderManagerPlugIn::onContextEstablished(const QString& pIfdName, const QString& pId) +void IfdReaderManagerPlugIn::onContextEstablished(const QString& pIfdName, const QString& pId) const { const auto& dispatcher = mDispatcherList.value(pId); @@ -194,6 +220,8 @@ IfdReaderManagerPlugIn::~IfdReaderManagerPlugIn() void IfdReaderManagerPlugIn::init() { + ReaderManagerPlugIn::init(); + const auto ifdClient = getIfdClient(); connect(ifdClient, &IfdClient::fireNewDispatcher, this, &IfdReaderManagerPlugIn::addDispatcher); } @@ -201,7 +229,9 @@ void IfdReaderManagerPlugIn::init() QList IfdReaderManagerPlugIn::getReaders() const { - return mReaderList.values(); + auto readerList = mReaderList.values(); + readerList.removeAll(nullptr); + return readerList; } @@ -222,9 +252,9 @@ void IfdReaderManagerPlugIn::addDispatcher(const QSharedPointergetReaderInfo().isInsertable()) + if (!reader || !reader->getReaderInfo().isInsertable()) { - qCDebug(card_remote) << "Skipping insert because there is no card available"; + qCDebug(card_remote) << "Skipping insert because reader is not connected or there is no card available"; return; } diff --git a/src/ifd/base/IfdReaderManagerPlugIn.h b/src/ifd/base/IfdReaderManagerPlugIn.h index 07e5546f6..bb80aae28 100644 --- a/src/ifd/base/IfdReaderManagerPlugIn.h +++ b/src/ifd/base/IfdReaderManagerPlugIn.h @@ -4,7 +4,6 @@ #pragma once - #include "IfdClient.h" #include "IfdDispatcherClient.h" #include "ReaderManagerPlugIn.h" @@ -35,7 +34,7 @@ class IfdReaderManagerPlugIn void handleIFDStatus(const QJsonObject& pJsonObject, const QString& pId); private Q_SLOTS: - void onContextEstablished(const QString& pIfdName, const QString& pId); + void onContextEstablished(const QString& pIfdName, const QString& pId) const; void onMessage(IfdMessageType pMessageType, const QJsonObject& pJsonObject, const QString& pId); void onDispatcherClosed(GlobalStatus::Code pCloseCode, const QString& pId); diff --git a/src/ifd/base/IfdServer.cpp b/src/ifd/base/IfdServer.cpp index 80eb0da12..123e6a6f5 100644 --- a/src/ifd/base/IfdServer.cpp +++ b/src/ifd/base/IfdServer.cpp @@ -4,9 +4,6 @@ #include "IfdServer.h" -#include "AppSettings.h" -#include "Env.h" - using namespace governikus; diff --git a/src/ifd/base/IfdServer.h b/src/ifd/base/IfdServer.h index 6814f14fd..ba3484ab7 100644 --- a/src/ifd/base/IfdServer.h +++ b/src/ifd/base/IfdServer.h @@ -11,6 +11,7 @@ #include "ServerMessageHandler.h" +#include #include #include #include @@ -46,6 +47,7 @@ class IfdServer void fireConnectedChanged(bool pConnected); void fireIsRunningChanged(); void firePairingCompleted(const QSslCertificate& pCertificate); + void fireSocketError(QAbstractSocket::SocketError pSocketError); }; } // namespace governikus diff --git a/src/ifd/base/ServerMessageHandlerImpl.cpp b/src/ifd/base/ServerMessageHandlerImpl.cpp index 2c142aad4..f5a58a368 100644 --- a/src/ifd/base/ServerMessageHandlerImpl.cpp +++ b/src/ifd/base/ServerMessageHandlerImpl.cpp @@ -13,7 +13,6 @@ #include "messages/IfdDisconnect.h" #include "messages/IfdDisconnectResponse.h" #include "messages/IfdError.h" -#include "messages/IfdEstablishContext.h" #include "messages/IfdEstablishPaceChannel.h" #include "messages/IfdEstablishPaceChannelResponse.h" #include "messages/IfdGetStatus.h" @@ -78,8 +77,7 @@ void ServerMessageHandlerImpl::handleIfdGetStatus(const QJsonObject& pJsonObject return; } - const auto& ifdStatusMsg = QSharedPointer::create(readerInfo); - mDispatcher->send(ifdStatusMsg); + sendIfdStatus(readerInfo); return; } @@ -96,8 +94,7 @@ void ServerMessageHandlerImpl::handleIfdGetStatus(const QJsonObject& pJsonObject continue; } - const auto& ifdStatusMsg = QSharedPointer::create(readerInfo); - mDispatcher->send(ifdStatusMsg); + sendIfdStatus(readerInfo); } } @@ -302,6 +299,16 @@ void ServerMessageHandlerImpl::handleIfdModifyPIN(const QJsonObject& pJsonObject } +void ServerMessageHandlerImpl::sendIfdStatus(const ReaderInfo& pReaderInfo) +{ + if (!mDispatcher->getContextHandle().isEmpty()) + { + const bool isCardAllowed = mAllowedCardTypes.contains(pReaderInfo.getPlugInType()); + mDispatcher->send(QSharedPointer::create(pReaderInfo, isCardAllowed)); + } +} + + void ServerMessageHandlerImpl::sendModifyPinResponse(const QString& pSlotHandle, const ResponseApdu& pResponseApdu) { PinModifyOutput pinModifyOutput(pResponseApdu); @@ -342,7 +349,16 @@ void ServerMessageHandlerImpl::sendModifyPinResponse(const QString& pSlotHandle, void ServerMessageHandlerImpl::setAllowedCardTypes(const QVector& pAllowedCardTypes) { - mAllowedCardTypes = pAllowedCardTypes; + if (mAllowedCardTypes != pAllowedCardTypes) + { + mAllowedCardTypes = pAllowedCardTypes; + + const auto& readerInfos = Env::getSingleton()->getReaderInfos(ReaderFilter(mAllowedPlugInTypes)); + for (const auto& readerInfo : readerInfos) + { + sendIfdStatus(readerInfo); + } + } } @@ -453,7 +469,7 @@ void ServerMessageHandlerImpl::onReaderChanged(const ReaderInfo& pInfo) } } - mDispatcher->send(QSharedPointer::create(pInfo, mAllowedCardTypes.contains(pInfo.getPlugInType()))); + sendIfdStatus(pInfo); } @@ -464,7 +480,7 @@ void ServerMessageHandlerImpl::onReaderRemoved(const ReaderInfo& pInfo) return; } - mDispatcher->send(QSharedPointer::create(pInfo)); + sendIfdStatus(pInfo); } diff --git a/src/ifd/base/ServerMessageHandlerImpl.h b/src/ifd/base/ServerMessageHandlerImpl.h index b52f534cc..a229df68f 100644 --- a/src/ifd/base/ServerMessageHandlerImpl.h +++ b/src/ifd/base/ServerMessageHandlerImpl.h @@ -44,6 +44,7 @@ class ServerMessageHandlerImpl void handleIfdTransmit(const QJsonObject& pJsonObject); void handleIfdEstablishPaceChannel(const QJsonObject& pJsonObject); void handleIfdModifyPIN(const QJsonObject& pJsonObject); + void sendIfdStatus(const ReaderInfo& pReaderInfo); private Q_SLOTS: void onCreateCardConnectionCommandDone(QSharedPointer pCommand); diff --git a/src/ifd/base/TlsServer.cpp b/src/ifd/base/TlsServer.cpp index 18d9c7336..204f1d968 100644 --- a/src/ifd/base/TlsServer.cpp +++ b/src/ifd/base/TlsServer.cpp @@ -91,7 +91,7 @@ void TlsServer::incomingConnection(qintptr pSocketDescriptor) } -void TlsServer::onPreSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator* pAuthenticator) +void TlsServer::onPreSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator* pAuthenticator) const { qCDebug(ifd) << "Client requests PSK authentication | identity:" << pAuthenticator->identity() << "| hint:" << pAuthenticator->identityHint(); pAuthenticator->setPreSharedKey(mPsk); @@ -102,4 +102,17 @@ void TlsServer::onError(QAbstractSocket::SocketError pSocketError) { qCDebug(ifd) << "Socket error:" << pSocketError << mSocket->errorString(); mSocket->deleteLater(); + Q_EMIT fireSocketError(pSocketError); +} + + +const QByteArray& TlsServer::getPsk() const +{ + return mPsk; +} + + +const QPointer& TlsServer::getSslSocket() const +{ + return mSocket; } diff --git a/src/ifd/base/TlsServer.h b/src/ifd/base/TlsServer.h index 9022fdec8..a3c830cbc 100644 --- a/src/ifd/base/TlsServer.h +++ b/src/ifd/base/TlsServer.h @@ -25,18 +25,21 @@ class TlsServer Q_OBJECT private: + QPointer mSocket; + QByteArray mPsk; + void incomingConnection(qintptr pSocketDescriptor) override; virtual QSslConfiguration sslConfiguration() const = 0; private Q_SLOTS: - void onPreSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator* pAuthenticator); + void onPreSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator* pAuthenticator) const; void onError(QAbstractSocket::SocketError pSocketError); virtual void onSslErrors(const QList& pErrors) = 0; virtual void onEncrypted() = 0; protected: - QPointer mSocket; - QByteArray mPsk; + [[nodiscard]] const QPointer& getSslSocket() const; + [[nodiscard]] const QByteArray& getPsk() const; public: TlsServer(); @@ -49,6 +52,7 @@ class TlsServer Q_SIGNALS: void fireNewConnection(QTcpSocket* pSocket); void firePskChanged(const QByteArray& pPsk); + void fireSocketError(QAbstractSocket::SocketError pSocketError); }; } // namespace governikus diff --git a/src/ifd/base/WebSocketServer.h b/src/ifd/base/WebSocketServer.h index 4d91af571..ff733ae0f 100644 --- a/src/ifd/base/WebSocketServer.h +++ b/src/ifd/base/WebSocketServer.h @@ -44,6 +44,7 @@ class WebSocketServer void fireConnectedChanged(bool pConnected); void fireMessageHandlerAdded(QSharedPointer pHandler); void firePskChanged(const QByteArray& pPsk); + void fireSocketError(QAbstractSocket::SocketError pSocketError); }; } // namespace governikus diff --git a/src/ifd/base/WebSocketServerImpl.cpp b/src/ifd/base/WebSocketServerImpl.cpp index 882ad1b88..d78e42c7f 100644 --- a/src/ifd/base/WebSocketServerImpl.cpp +++ b/src/ifd/base/WebSocketServerImpl.cpp @@ -4,7 +4,6 @@ #include "WebSocketServerImpl.h" -#include "AppSettings.h" #include "Env.h" #include "WebSocketChannel.h" diff --git a/src/ifd/base/messages/Discovery.cpp b/src/ifd/base/messages/Discovery.cpp index 2fa707d58..0b0caefb2 100644 --- a/src/ifd/base/messages/Discovery.cpp +++ b/src/ifd/base/messages/Discovery.cpp @@ -6,7 +6,6 @@ #include "Discovery.h" #include "Initializer.h" -#include "JsonValueRef.h" #include "RemoteServiceSettings.h" #include @@ -52,7 +51,7 @@ void Discovery::parseSupportedApi(const QJsonObject& pMessageObject) } const auto& array = value.toArray(); - for (JsonValueRef entry : array) + for (const QJsonValueConstRef entry : array) { if (entry.isString()) { @@ -73,38 +72,16 @@ void Discovery::parseIfdId(const QJsonObject& pMessageObject) return; } - QVector sorted(mSupportedApis); - std::sort(sorted.rbegin(), sorted.rend()); - const bool expectCertificate = !sorted.isEmpty() && sorted.first() >= IfdVersion::Version::v2; - - const bool isFingerprint = mIfdId.size() == 64; - if (isFingerprint) + if (mIfdId.isEmpty()) { - if (expectCertificate) - { - invalidType(IFD_ID(), QLatin1String("X.509 certificate (PEM)")); - } + markIncomplete(QStringLiteral("The value of IFDID should not be emtpy")); return; } const QSslCertificate ifdCertificate(mIfdId.toLatin1()); if (!ifdCertificate.isNull()) { - if (!expectCertificate) - { - invalidType(IFD_ID(), QLatin1String("certificate fingerprint (SHA256)")); - } mIfdId = RemoteServiceSettings::generateFingerprint(ifdCertificate); - return; - } - - if (expectCertificate) - { - invalidType(IFD_ID(), QLatin1String("X.509 certificate (PEM)")); - } - else - { - invalidType(IFD_ID(), QLatin1String("certificate fingerprint (SHA256)")); } } diff --git a/src/ifd/base/messages/IfdEstablishPaceChannel.cpp b/src/ifd/base/messages/IfdEstablishPaceChannel.cpp index f1a3a8bd9..9a31acc70 100644 --- a/src/ifd/base/messages/IfdEstablishPaceChannel.cpp +++ b/src/ifd/base/messages/IfdEstablishPaceChannel.cpp @@ -19,7 +19,6 @@ namespace VALUE_NAME(SLOT_HANDLE, "SlotHandle") VALUE_NAME(INPUT_DATA, "InputData") VALUE_NAME(EXPECTED_PIN_LENGTH, "ExpectedPINLength") -VALUE_NAME(PREFERRED_PIN_LENGTH, "PreferredPinLength") } // namespace @@ -78,11 +77,6 @@ IfdEstablishPaceChannel::IfdEstablishPaceChannel(const QJsonObject& pMessageObje parseInputData(pMessageObject); - if (pMessageObject.contains(PREFERRED_PIN_LENGTH())) - { - mExpectedPinLength = getIntValue(pMessageObject, PREFERRED_PIN_LENGTH(), 0); - } - if (pMessageObject.contains(EXPECTED_PIN_LENGTH())) { mExpectedPinLength = getIntValue(pMessageObject, EXPECTED_PIN_LENGTH(), 0); @@ -124,7 +118,6 @@ QByteArray IfdEstablishPaceChannel::toByteArray(IfdVersion::Version pIfdVersion, if (mExpectedPinLength > 0) { result[EXPECTED_PIN_LENGTH()] = mExpectedPinLength; - result[PREFERRED_PIN_LENGTH()] = mExpectedPinLength; } } else diff --git a/src/ifd/base/messages/IfdStatus.cpp b/src/ifd/base/messages/IfdStatus.cpp index 8679ef26e..d62679136 100644 --- a/src/ifd/base/messages/IfdStatus.cpp +++ b/src/ifd/base/messages/IfdStatus.cpp @@ -6,6 +6,7 @@ #include "IfdStatus.h" #include "AppSettings.h" +#include "VolatileSettings.h" #include @@ -89,9 +90,20 @@ IfdStatus::IfdStatus(const ReaderInfo& pReaderInfo, bool pPublishCard) , mConnectedReader(pReaderInfo.isValid()) , mCardAvailable(pReaderInfo.hasCard() && pPublishCard) { - if (!mHasPinPad && pReaderInfo.getPlugInType() == ReaderManagerPlugInType::NFC) + if (mHasPinPad || Env::getSingleton()->isUsedAsSDK()) { - mHasPinPad = Env::getSingleton()->getRemoteServiceSettings().getPinPadMode(); + return; + } + + switch (pReaderInfo.getPlugInType()) + { + case ReaderManagerPlugInType::NFC: + case ReaderManagerPlugInType::SMART: + mHasPinPad = Env::getSingleton()->getRemoteServiceSettings().getPinPadMode(); + break; + + default: + break; } } @@ -108,7 +120,7 @@ IfdStatus::IfdStatus(const QJsonObject& pMessageObject) parsePinPad(pMessageObject); mMaxApduLength = getIntValue(pMessageObject, MAX_APDU_LENGTH(), -1); - // Support SaC with AusweisApp2 < 1.22.0 + // Support SaC with AusweisApp < 1.22.0 if (IfdVersion(IfdVersion::Version::v0).isSupported() && mMaxApduLength == 0) { mMaxApduLength = -1; diff --git a/src/ifd/local/CMakeLists.txt b/src/ifd/local/CMakeLists.txt index cf0522202..21791c109 100644 --- a/src/ifd/local/CMakeLists.txt +++ b/src/ifd/local/CMakeLists.txt @@ -6,9 +6,5 @@ ADD_PLATFORM_LIBRARY(AusweisAppIfdLocal) target_link_libraries(AusweisAppIfdLocal ${Qt}::Core ${Qt}::WebSockets AusweisAppGlobal AusweisAppIfd) - -if(QT6) - target_link_libraries(AusweisAppIfdLocal ${Qt}::CorePrivate) -endif() - +target_link_libraries(AusweisAppIfdLocal ${Qt}::CorePrivate) target_compile_definitions(AusweisAppIfdLocal PRIVATE QT_STATICPLUGIN) diff --git a/src/ifd/local/LocalIfdClient.cpp b/src/ifd/local/LocalIfdClient.cpp index a98b2ba51..1dfd73552 100644 --- a/src/ifd/local/LocalIfdClient.cpp +++ b/src/ifd/local/LocalIfdClient.cpp @@ -8,12 +8,14 @@ #include "Initializer.h" #include "PortFile.h" #include "ReaderManager.h" -#include "SecureStorage.h" #include "messages/IfdVersion.h" #include #ifdef Q_OS_ANDROID + #include "Randomizer.h" + #include "SecureStorage.h" + #include #endif @@ -68,7 +70,7 @@ void LocalIfdClient::startDetection() const auto packageName = QJniObject::fromString(Env::getSingleton()->getLocalIfdPackageName()); handle.callObjectMethod("setPackage", "(Ljava/lang/String;)Landroid/content/Intent;", packageName.object()); mPsk = Randomizer::getInstance().createUuid().toString(QUuid::Id128); - serviceIntent.putExtra(QStringLiteral("TLS_WEBSOCKET_PSK"), mPsk.toUtf8()); + serviceIntent.putExtra(QStringLiteral("PSK"), mPsk.toUtf8()); QJniObject context = QNativeInterface::QAndroidApplication::context(); if (!context.isValid()) @@ -82,7 +84,7 @@ void LocalIfdClient::startDetection() bool isBound = context.callMethod("bindService", "(Landroid/content/Intent;Landroid/content/ServiceConnection;I)Z", serviceIntent.handle().object(), mServiceConnection.object(), jint(QtAndroidPrivate::BindFlag::AutoCreate)) == JNI_TRUE; if (!isBound) { - qCWarning(ifd) << "Binding to LocalIfdService failed, is the correct AusweisApp2 version installed?"; + qCWarning(ifd) << "Binding to LocalIfdService failed, is the correct AusweisApp version installed?"; serviceDisconnected(); } #endif diff --git a/src/ifd/local/LocalIfdClient.h b/src/ifd/local/LocalIfdClient.h index 5883e5bce..0980cd126 100644 --- a/src/ifd/local/LocalIfdClient.h +++ b/src/ifd/local/LocalIfdClient.h @@ -5,7 +5,6 @@ #pragma once #include "IfdClientImpl.h" -#include "Randomizer.h" #include diff --git a/src/ifd/local/LocalIfdReaderManagerPlugIn.cpp b/src/ifd/local/LocalIfdReaderManagerPlugIn.cpp index c5f7f65e7..2d9d16d9c 100644 --- a/src/ifd/local/LocalIfdReaderManagerPlugIn.cpp +++ b/src/ifd/local/LocalIfdReaderManagerPlugIn.cpp @@ -25,7 +25,7 @@ LocalIfdReaderManagerPlugIn::LocalIfdReaderManagerPlugIn() updateState(); if (!getInfo().isAvailable()) { - qCWarning(ifd) << "Smart-eID not available, could not find correct AusweisApp2 version"; + qCWarning(ifd) << "Smart-eID not available, could not find correct AusweisApp version"; } } @@ -35,7 +35,7 @@ void LocalIfdReaderManagerPlugIn::startScan(bool pAutoConnect) updateState(); if (!getInfo().isAvailable()) { - qCWarning(ifd) << "Smart-eID not available, could not find correct AusweisApp2 version"; + qCWarning(ifd) << "Smart-eID not available, could not find correct AusweisApp version"; return; } @@ -97,7 +97,7 @@ void LocalIfdReaderManagerPlugIn::onLocalIfdConnectionClosed(GlobalStatus::Code } -bool LocalIfdReaderManagerPlugIn::isAusweisApp2Installed() +bool LocalIfdReaderManagerPlugIn::isAusweisAppInstalled() { if (mServiceConnected) { @@ -113,7 +113,7 @@ bool LocalIfdReaderManagerPlugIn::isAusweisApp2Installed() const auto& packageInfo = BuildHelper::getPackageInfo(aa2PackageName); if (!packageInfo.isValid()) { - qCWarning(ifd) << "Could not find installed AusweisApp2"; + qCWarning(ifd) << "Could not find installed AusweisApp"; setState(LocalIfdState::NOT_INSTALLED); return false; } @@ -122,7 +122,7 @@ bool LocalIfdReaderManagerPlugIn::isAusweisApp2Installed() const auto& versionNumber = VersionNumber(versionName); if (versionNumber < aa2MinVersion) { - qCWarning(ifd) << "Invalid AusweisApp2:" << versionNumber << ", required version >=" << aa2MinVersion.getVersionNumber().toString(); + qCWarning(ifd) << "Invalid AusweisApp:" << versionNumber << ", required version >=" << aa2MinVersion.getVersionNumber().toString(); setState(LocalIfdState::INCOMPATIBLE_VERSION); return false; } @@ -133,7 +133,7 @@ bool LocalIfdReaderManagerPlugIn::isAusweisApp2Installed() }); if (!hasValidCertificate) { - qCWarning(ifd) << "Invalid AusweisApp2 certificate"; + qCWarning(ifd) << "Invalid AusweisApp certificate"; setState(LocalIfdState::INVALID_CERTIFICATE); return false; } @@ -156,10 +156,10 @@ void LocalIfdReaderManagerPlugIn::setState(LocalIfdState pState) void LocalIfdReaderManagerPlugIn::updateState() { - const bool ausweisApp2Installed = isAusweisApp2Installed(); - if (getInfo().isAvailable() != ausweisApp2Installed) + const bool ausweisAppInstalled = isAusweisAppInstalled(); + if (getInfo().isAvailable() != ausweisAppInstalled) { - setPlugInAvailable(ausweisApp2Installed); + setPlugInAvailable(ausweisAppInstalled); } } diff --git a/src/ifd/local/LocalIfdReaderManagerPlugIn.h b/src/ifd/local/LocalIfdReaderManagerPlugIn.h index 7e68ebed7..488df359f 100644 --- a/src/ifd/local/LocalIfdReaderManagerPlugIn.h +++ b/src/ifd/local/LocalIfdReaderManagerPlugIn.h @@ -4,7 +4,6 @@ #pragma once - #include "EnumHelper.h" #include "IfdReaderManagerPlugIn.h" #include "LocalIfdClient.h" @@ -44,7 +43,7 @@ class LocalIfdReaderManagerPlugIn private: bool mServiceConnected; - [[nodiscard]] bool isAusweisApp2Installed(); + [[nodiscard]] bool isAusweisAppInstalled(); void setState(LocalIfdState pState); void updateState(); diff --git a/src/ifd/local/LocalIfdServer.cpp b/src/ifd/local/LocalIfdServer.cpp index 66c2c4403..24251484c 100644 --- a/src/ifd/local/LocalIfdServer.cpp +++ b/src/ifd/local/LocalIfdServer.cpp @@ -4,7 +4,6 @@ #include "LocalIfdServer.h" -#include "AppSettings.h" #include "Env.h" #include "PortFile.h" @@ -17,6 +16,7 @@ LocalIfdServer::LocalIfdServer() { connect(mWebSocketServer.data(), &LocalWebSocketServer::fireMessageHandlerAdded, this, &IfdServer::fireMessageHandlerAdded); connect(mWebSocketServer.data(), &LocalWebSocketServer::fireConnectedChanged, this, &IfdServer::fireConnectedChanged); + connect(mWebSocketServer.data(), &LocalWebSocketServer::fireSocketError, this, &IfdServer::fireSocketError); } diff --git a/src/ifd/local/LocalTlsServer.cpp b/src/ifd/local/LocalTlsServer.cpp index 23e1c9350..ff75b23ea 100644 --- a/src/ifd/local/LocalTlsServer.cpp +++ b/src/ifd/local/LocalTlsServer.cpp @@ -46,17 +46,18 @@ QSslConfiguration LocalTlsServer::sslConfiguration() const void LocalTlsServer::onSslErrors(const QList& pErrors) { - qCDebug(ifd) << "Client is not allowed | cipher:" << mSocket->sessionCipher() << "| certificate:" << mSocket->peerCertificate() << "| error:" << pErrors; + const auto& socket = getSslSocket(); + qCDebug(ifd) << "Client is not allowed | cipher:" << socket->sessionCipher() << "| certificate:" << socket->peerCertificate() << "| error:" << pErrors; } void LocalTlsServer::onEncrypted() { - const auto& cfg = mSocket->sslConfiguration(); - TlsChecker::logSslConfig(cfg, spawnMessageLogger(ifd)); + const auto& socket = getSslSocket(); + TlsChecker::logSslConfig(socket->sslConfiguration(), spawnMessageLogger(ifd)); qCDebug(ifd) << "Client connected"; - mSocket->disconnect(this); - Q_EMIT fireNewConnection(mSocket.data()); + socket->disconnect(this); + Q_EMIT fireNewConnection(socket.data()); } diff --git a/src/ifd/local/LocalWebSocketServerImpl.cpp b/src/ifd/local/LocalWebSocketServerImpl.cpp index 3478eec82..792c43f2d 100644 --- a/src/ifd/local/LocalWebSocketServerImpl.cpp +++ b/src/ifd/local/LocalWebSocketServerImpl.cpp @@ -26,12 +26,13 @@ template<> LocalWebSocketServer* createNewObject() LocalWebSocketServerImpl::LocalWebSocketServerImpl() : LocalWebSocketServer() , mLocalTlsServer(QSharedPointer::create()) - , mWebSocketServer(mLocalTlsServer, {ReaderManagerPlugInType::SMART}) + , mWebSocketServer(mLocalTlsServer, {ReaderManagerPlugInType::SMART, ReaderManagerPlugInType::UNKNOWN}) { connect(&mWebSocketServer, &WebSocketServer::fireNewConnection, this, &LocalWebSocketServerImpl::fireNewConnection); connect(&mWebSocketServer, &WebSocketServer::fireConnectedChanged, this, &LocalWebSocketServerImpl::fireConnectedChanged); connect(&mWebSocketServer, &WebSocketServer::fireMessageHandlerAdded, this, &LocalWebSocketServerImpl::fireMessageHandlerAdded); connect(&mWebSocketServer, &WebSocketServer::firePskChanged, this, &LocalWebSocketServerImpl::firePskChanged); + connect(mLocalTlsServer.data(), &TlsServer::fireSocketError, this, &LocalWebSocketServerImpl::fireSocketError); } diff --git a/src/ifd/remote/RemoteIfdClient.cpp b/src/ifd/remote/RemoteIfdClient.cpp index 2ce8f2736..8feee8cdd 100644 --- a/src/ifd/remote/RemoteIfdClient.cpp +++ b/src/ifd/remote/RemoteIfdClient.cpp @@ -5,7 +5,6 @@ #include "RemoteIfdClient.h" #include "AppSettings.h" -#include "IfdConnectorImpl.h" #include "Initializer.h" #include "ReaderManager.h" #include "messages/Discovery.h" diff --git a/src/ifd/remote/RemoteIfdReaderManagerPlugIn.cpp b/src/ifd/remote/RemoteIfdReaderManagerPlugIn.cpp index 3ceede969..5d1867ce6 100644 --- a/src/ifd/remote/RemoteIfdReaderManagerPlugIn.cpp +++ b/src/ifd/remote/RemoteIfdReaderManagerPlugIn.cpp @@ -5,8 +5,6 @@ #include "RemoteIfdReaderManagerPlugIn.h" #include "AppSettings.h" -#include "IfdReader.h" -#include "Reader.h" #include "RemoteIfdClient.h" #include @@ -19,14 +17,15 @@ Q_DECLARE_LOGGING_CATEGORY(card_remote) void RemoteIfdReaderManagerPlugIn::connectToPairedReaders() { - if (!mConnectToPairedReaders || mConnectionCheckInProgress) + if (!mConnectToPairedReaders) { return; } - mConnectionCheckInProgress = true; const auto ifdClient = getIfdClient(); connect(ifdClient, &IfdClient::fireRemoteDevicesInfo, this, &RemoteIfdReaderManagerPlugIn::continueConnectToPairedReaders); + connect(ifdClient, &IfdClient::fireDeviceVanished, this, &RemoteIfdReaderManagerPlugIn::onDeviceVanished); + connect(ifdClient, &IfdClient::fireEstablishConnectionDone, this, &RemoteIfdReaderManagerPlugIn::onEstablishConnectionDone); QMetaObject::invokeMethod(ifdClient, &IfdClient::requestRemoteDevices, Qt::QueuedConnection); } @@ -51,19 +50,42 @@ void RemoteIfdReaderManagerPlugIn::continueConnectToPairedReaders(const QVector< // If already connected: skip. if (getDispatchers().contains(ifdId)) { + mConnectionAttempts.removeAll(ifdId); continue; } const RemoteServiceSettings::RemoteInfo remoteInfo = remoteServiceSettings.getRemoteInfo(ifdId); // If we find a remote info for this fingerprint (IfdId), then the remote device is paired. - if (remoteInfo.getFingerprint() == ifdId) + if (remoteInfo.getFingerprint() == ifdId && !mConnectionAttempts.contains(ifdId)) { + mConnectionAttempts << ifdId; QMetaObject::invokeMethod(ifdClient, [ifdClient, remoteDevice] { ifdClient->establishConnection(remoteDevice, QString()); }, Qt::QueuedConnection); } } - mConnectionCheckInProgress = false; +} + + +void RemoteIfdReaderManagerPlugIn::onDeviceVanished(const QSharedPointer& pEntry) +{ + const auto& ifdId = pEntry->getIfdDescriptor().getIfdId(); + if (mConnectionAttempts.contains(ifdId)) + { + qCInfo(card_remote) << "Removing" << ifdId << "from connection attempt list as it has vanished"; + mConnectionAttempts.removeAll(ifdId); + } +} + + +void RemoteIfdReaderManagerPlugIn::onEstablishConnectionDone(const QSharedPointer& pEntry, const GlobalStatus& pStatus) +{ + const auto& ifdId = pEntry->getIfdDescriptor().getIfdId(); + if (mConnectionAttempts.contains(ifdId)) + { + qCInfo(card_remote) << "Removing" << ifdId << "from connection attempt list as the request finished with" << pStatus; + mConnectionAttempts.removeAll(ifdId); + } } @@ -71,7 +93,7 @@ RemoteIfdReaderManagerPlugIn::RemoteIfdReaderManagerPlugIn() : IfdReaderManagerPlugIn(ReaderManagerPlugInType::REMOTE_IFD, true) , mScanTimer() , mConnectToPairedReaders(true) - , mConnectionCheckInProgress(false) + , mConnectionAttempts() { mScanTimer.setInterval(1000); connect(&mScanTimer, &QTimer::timeout, this, &RemoteIfdReaderManagerPlugIn::connectToPairedReaders); diff --git a/src/ifd/remote/RemoteIfdReaderManagerPlugIn.h b/src/ifd/remote/RemoteIfdReaderManagerPlugIn.h index 47104fd8e..393f47e84 100644 --- a/src/ifd/remote/RemoteIfdReaderManagerPlugIn.h +++ b/src/ifd/remote/RemoteIfdReaderManagerPlugIn.h @@ -11,8 +11,11 @@ #include "IfdList.h" #include "IfdReaderManagerPlugIn.h" +#include #include +class test_RemoteIfdReaderManagerPlugIn; + namespace governikus { @@ -23,14 +26,18 @@ class RemoteIfdReaderManagerPlugIn Q_PLUGIN_METADATA(IID "governikus.ReaderManagerPlugIn" FILE "metadata.json") Q_INTERFACES(governikus::ReaderManagerPlugIn) + friend class ::test_RemoteIfdReaderManagerPlugIn; + private: QTimer mScanTimer; bool mConnectToPairedReaders; - bool mConnectionCheckInProgress; + QStringList mConnectionAttempts; private Q_SLOTS: void connectToPairedReaders(); void continueConnectToPairedReaders(const QVector>& pRemoteDevices); + void onDeviceVanished(const QSharedPointer& pEntry); + void onEstablishConnectionDone(const QSharedPointer& pEntry, const GlobalStatus& pStatus); public: RemoteIfdReaderManagerPlugIn(); diff --git a/src/ifd/remote/RemoteIfdServer.cpp b/src/ifd/remote/RemoteIfdServer.cpp index f9f6d6001..3abed53d8 100644 --- a/src/ifd/remote/RemoteIfdServer.cpp +++ b/src/ifd/remote/RemoteIfdServer.cpp @@ -49,6 +49,7 @@ RemoteIfdServer::RemoteIfdServer() connect(mWebSocketServer.data(), &RemoteWebSocketServer::fireConnectedChanged, this, &RemoteIfdServer::onConnectedChanged); connect(mWebSocketServer.data(), &RemoteWebSocketServer::fireMessageHandlerAdded, this, &IfdServer::fireMessageHandlerAdded); connect(mWebSocketServer.data(), &RemoteWebSocketServer::firePairingCompleted, this, &IfdServer::firePairingCompleted); + connect(mWebSocketServer.data(), &RemoteWebSocketServer::fireSocketError, this, &IfdServer::fireSocketError); } diff --git a/src/ifd/remote/RemoteTlsServer.cpp b/src/ifd/remote/RemoteTlsServer.cpp index 68290891d..5e443b201 100644 --- a/src/ifd/remote/RemoteTlsServer.cpp +++ b/src/ifd/remote/RemoteTlsServer.cpp @@ -20,14 +20,15 @@ using namespace governikus; QSslConfiguration RemoteTlsServer::sslConfiguration() const { - const auto cipherCfg = mPsk.isEmpty() ? SecureStorage::TlsSuite::DEFAULT : SecureStorage::TlsSuite::PSK; + const auto& psk = getPsk(); + const auto cipherCfg = psk.isEmpty() ? SecureStorage::TlsSuite::DEFAULT : SecureStorage::TlsSuite::PSK; QSslConfiguration config = Env::getSingleton()->getTlsConfigRemoteIfd(cipherCfg).getConfiguration(); const auto& settings = Env::getSingleton()->getRemoteServiceSettings(); config.setPrivateKey(settings.getKey()); config.setLocalCertificate(settings.getCertificate()); config.setPeerVerifyMode(QSslSocket::VerifyPeer); - if (mPsk.isEmpty()) + if (psk.isEmpty()) { config.setCaCertificates(settings.getTrustedCertificates()); } @@ -76,31 +77,33 @@ bool RemoteTlsServer::startListening(quint16 pPort) void RemoteTlsServer::onSslErrors(const QList& pErrors) { + const auto& socket = getSslSocket(); if (pErrors.size() == 1 && pErrors.first().error() == QSslError::SelfSignedCertificate) { const auto& pairingCiphers = Env::getSingleton()->getTlsConfigRemoteIfd(SecureStorage::TlsSuite::PSK).getCiphers(); - if (pairingCiphers.contains(mSocket->sessionCipher())) + if (pairingCiphers.contains(socket->sessionCipher())) { - qCDebug(ifd) << "Client requests pairing | cipher:" << mSocket->sessionCipher() << "| certificate:" << mSocket->peerCertificate(); - mSocket->ignoreSslErrors(pErrors); + qCDebug(ifd) << "Client requests pairing | cipher:" << socket->sessionCipher() << "| certificate:" << socket->peerCertificate(); + socket->ignoreSslErrors(pErrors); return; } } - qCDebug(ifd) << "Client is not allowed | cipher:" << mSocket->sessionCipher() << "| certificate:" << mSocket->peerCertificate() << "| error:" << pErrors; + qCDebug(ifd) << "Client is not allowed | cipher:" << socket->sessionCipher() << "| certificate:" << socket->peerCertificate() << "| error:" << pErrors; } void RemoteTlsServer::onEncrypted() { - const auto& cfg = mSocket->sslConfiguration(); + const auto& socket = getSslSocket(); + const auto& cfg = socket->sslConfiguration(); TlsChecker::logSslConfig(cfg, spawnMessageLogger(ifd)); if (!TlsChecker::hasValidCertificateKeyLength(cfg.peerCertificate())) { qCCritical(ifd) << "Client denied... abort connection!"; - mSocket->abort(); - mSocket->deleteLater(); + socket->abort(); + socket->deleteLater(); return; } @@ -123,8 +126,8 @@ void RemoteTlsServer::onEncrypted() settings.updateRemoteInfo(info); } - mSocket->disconnect(this); - Q_EMIT fireNewConnection(mSocket.data()); + socket->disconnect(this); + Q_EMIT fireNewConnection(socket.data()); } @@ -146,5 +149,6 @@ void RemoteTlsServer::setPairing(bool pEnable) QSslCertificate RemoteTlsServer::getCurrentCertificate() const { - return mSocket ? mSocket->sslConfiguration().peerCertificate() : QSslCertificate(); + const auto& socket = getSslSocket(); + return socket ? socket->sslConfiguration().peerCertificate() : QSslCertificate(); } diff --git a/src/ifd/remote/RemoteWebSocketServerImpl.cpp b/src/ifd/remote/RemoteWebSocketServerImpl.cpp index 963ea8392..9770a16db 100644 --- a/src/ifd/remote/RemoteWebSocketServerImpl.cpp +++ b/src/ifd/remote/RemoteWebSocketServerImpl.cpp @@ -38,7 +38,7 @@ void RemoteWebSocketServerImpl::onNewConnection(QSharedPointer pSock RemoteWebSocketServerImpl::RemoteWebSocketServerImpl() : RemoteWebSocketServer() , mRemoteTlsServer(QSharedPointer::create()) - , mWebSocketServer(mRemoteTlsServer, {ReaderManagerPlugInType::NFC}) + , mWebSocketServer(mRemoteTlsServer, {ReaderManagerPlugInType::NFC, ReaderManagerPlugInType::SMART, ReaderManagerPlugInType::UNKNOWN}) , mPairingConnection(false) { connect(mRemoteTlsServer.data(), &RemoteTlsServer::firePairingCompleted, this, &RemoteWebSocketServer::firePairingCompleted); diff --git a/src/init/Bootstrap.cpp b/src/init/Bootstrap.cpp index 69806d62f..f54c86fd8 100644 --- a/src/init/Bootstrap.cpp +++ b/src/init/Bootstrap.cpp @@ -14,6 +14,8 @@ #include #include +#include +#include #include #include #include @@ -49,6 +51,9 @@ using QAPP = QApplication; #endif +static QMutex cMutex; // clazy:exclude=non-pod-global-static + + static inline void printInfo() { qCDebug(init) << "Logging to" << *Env::getSingleton(); @@ -61,11 +66,6 @@ static inline void printInfo() } qCInfo(init) << "##################################################"; -#if OPENSSL_VERSION_NUMBER < 0x10100000L - #define OpenSSL_version SSLeay_version - #define OPENSSL_VERSION SSLEAY_VERSION -#endif - if (QSslSocket::sslLibraryVersionString() != QLatin1String(OpenSSL_version(OPENSSL_VERSION))) { qCWarning(init) << "Linked OpenSSL Version differs:" << OpenSSL_version(OPENSSL_VERSION); @@ -77,19 +77,12 @@ static inline void printInfo() qCDebug(init) << "Library path:" << path; } -#if (QT_VERSION > QT_VERSION_CHECK(6, 0, 0)) qCDebug(init) << "TLS backends:" << QSslSocket::availableBackends() << "| using:" << QSslSocket::activeBackend(); -#endif } static inline QCoreApplication* initQt(int& argc, char** argv) { -#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) - QCoreApplication::setAttribute(Qt::AA_DisableWindowContextHelpButton); - QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); -#endif - QCoreApplication::setOrganizationName(QStringLiteral(VENDOR)); QCoreApplication::setOrganizationDomain(QStringLiteral(VENDOR_DOMAIN)); QCoreApplication::setApplicationName(QStringLiteral(PRODUCT)); @@ -138,7 +131,11 @@ static void restartApp(const QString& pApplicationFilePath, QStringList pArgumen pArgumentList.removeFirst(); } - pArgumentList << QStringLiteral("--show"); + const auto& show = QStringLiteral("--show"); + if (!pArgumentList.contains(show)) + { + pArgumentList << show; + } qCInfo(init) << "Attempting to start new process:" << pApplicationFilePath << ", args:" << pArgumentList; if (qint64 pid = -1; QProcess::startDetached(pApplicationFilePath, pArgumentList, QString(), &pid)) @@ -154,6 +151,24 @@ static void restartApp(const QString& pApplicationFilePath, QStringList pArgumen #endif + +void governikus::shutdownApp() +{ + if (cMutex.try_lock()) + { + qCDebug(init) << "Shutdown trigger omitted"; + cMutex.unlock(); + return; + } + + qCDebug(init) << "Trigger shutdown..."; + Env::getSingleton()->quit(); + qCDebug(init) << "Wait for MainThread to be finished..."; + const QMutexLocker mutexLocker(&cMutex); + qCDebug(init) << "MainThread finished!"; +} + + int governikus::initApp(int& argc, char** argv) { const QScopedPointer app(initQt(argc, argv)); @@ -164,6 +179,7 @@ int governikus::initApp(int& argc, char** argv) Env::getSingleton()->init(); printInfo(); + const QMutexLocker mutexLocker(&cMutex); AppController controller; Env::getSingleton()->setController([&controller]{ QMetaObject::invokeMethod(&controller, [&controller]{ @@ -185,3 +201,18 @@ int governikus::initApp(int& argc, char** argv) qCDebug(init) << "Leaving application... bye bye!"; return returnCode; } + + +#ifdef Q_OS_ANDROID +extern "C" +{ + +JNIEXPORT void JNICALL Java_com_governikus_ausweisapp2_BootstrapHelper_triggerShutdown(JNIEnv*, jobject) +{ + shutdownApp(); +} + + +} + +#endif diff --git a/src/init/Bootstrap.h b/src/init/Bootstrap.h index 510190e94..5e71c27ae 100644 --- a/src/init/Bootstrap.h +++ b/src/init/Bootstrap.h @@ -8,5 +8,6 @@ namespace governikus { int initApp(int& argc, char** argv); +void shutdownApp(); } // namespace governikus diff --git a/src/init/CMakeLists.txt b/src/init/CMakeLists.txt index 8cef62e2c..22dd6aec6 100644 --- a/src/init/CMakeLists.txt +++ b/src/init/CMakeLists.txt @@ -5,10 +5,7 @@ ADD_PLATFORM_LIBRARY(AusweisAppInit) target_link_libraries(AusweisAppInit ${Qt}::Core OpenSSL::Crypto AusweisAppGlobal AusweisAppCore) - -if(QT6) - target_link_libraries(AusweisAppInit ${Qt}::CorePrivate) -endif() +target_link_libraries(AusweisAppInit ${Qt}::CorePrivate) if(NOT INTEGRATED_SDK) target_link_libraries(AusweisAppInit ${Qt}::Gui) # QGuiApplication diff --git a/src/init/SignalHandler.h b/src/init/SignalHandler.h index e2de2f638..9efe79d4b 100644 --- a/src/init/SignalHandler.h +++ b/src/init/SignalHandler.h @@ -32,6 +32,7 @@ class SignalHandler Q_DISABLE_COPY(SignalHandler) friend class Env; + friend void shutdownApp(); private: bool mInit; diff --git a/src/main.cpp b/src/main.cpp index ad07ea5d2..5f43812e8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -35,9 +35,9 @@ Q_IMPORT_PLUGIN(NfcReaderManagerPlugIn) #ifndef INTEGRATED_SDK Q_IMPORT_PLUGIN(UIPlugInScheme) -Q_IMPORT_PLUGIN(UIPlugInLocalIfd) #ifdef USE_SMARTEID +Q_IMPORT_PLUGIN(UIPlugInLocalIfd) Q_IMPORT_PLUGIN(SmartReaderManagerPlugIn) #endif diff --git a/src/network/HttpHandler.cpp b/src/network/HttpHandler.cpp index d214bdef6..854b093bd 100644 --- a/src/network/HttpHandler.cpp +++ b/src/network/HttpHandler.cpp @@ -34,14 +34,14 @@ void HttpHandler::handle(const QSharedPointer& pRequest) case UrlQueryRequest::SHOWUI: { qCDebug(network) << "Request type: showui"; - handleShowUiRequest(value.toUpper(), pRequest); + handleShowUiRequest(value, pRequest); return; } case UrlQueryRequest::STATUS: { qCDebug(network) << "Request type: status"; - StatusFormat statusFormat = Enum::fromString(value.toUpper(), StatusFormat::PLAIN); + const StatusFormat statusFormat = UrlUtil::prepareToEnum(value, StatusFormat::PLAIN); handleStatusRequest(statusFormat, pRequest); return; } diff --git a/src/network/HttpRequest.cpp b/src/network/HttpRequest.cpp index 7e88f52f1..5d535d3a9 100644 --- a/src/network/HttpRequest.cpp +++ b/src/network/HttpRequest.cpp @@ -46,9 +46,7 @@ HttpRequest::HttpRequest(QTcpSocket* pSocket, QObject* pParent) QTcpSocket* HttpRequest::take() { - disconnect(mSocket, &QAbstractSocket::readyRead, this, &HttpRequest::onReadyRead); - disconnect(mSocket, &QAbstractSocket::stateChanged, this, &HttpRequest::fireSocketStateChanged); - + mSocket->disconnect(this); auto socket = mSocket; socket->setParent(nullptr); mSocket.clear(); diff --git a/src/network/HttpResponse.cpp b/src/network/HttpResponse.cpp index 35edf2af8..2e41779db 100644 --- a/src/network/HttpResponse.cpp +++ b/src/network/HttpResponse.cpp @@ -34,14 +34,7 @@ HttpResponse::HttpResponse(http_status pStatus, const QByteArray& pBody, const Q , mBody() { setBody(pBody, pContentType); - - // According to TR-03124-1, chapter 2.2.2.1, the Server-header shall have the following form: - auto version = QCoreApplication::applicationVersion().toUtf8(); - if (!version.isEmpty()) - { - version.prepend('/'); - } - setHeader(HEADER_SERVER(), QCoreApplication::applicationName().toUtf8() % version % QByteArrayLiteral(" (TR-03124-1/1.3)")); + setHeader(HEADER_SERVER(), NetworkManager::getUserAgentServerHeader().toUtf8()); setHeader(HEADER_DATE(), QLocale::c().toString(QDateTime::currentDateTimeUtc(), QStringLiteral("ddd, dd MMM yyyy hh:mm:ss")).toUtf8() + QByteArrayLiteral(" GMT")); setHeader(HEADER_CONTENT_LENGTH(), QByteArray::number(mBody.size())); } diff --git a/src/network/HttpServerStatusParser.h b/src/network/HttpServerStatusParser.h index 91df65dee..787ce8907 100644 --- a/src/network/HttpServerStatusParser.h +++ b/src/network/HttpServerStatusParser.h @@ -8,7 +8,6 @@ #pragma once -#include "EnumHelper.h" #include "HttpServerRequestor.h" #include "VersionInfo.h" diff --git a/src/network/MulticastLock.cpp b/src/network/MulticastLock.cpp index c042ac313..6d5f1898b 100644 --- a/src/network/MulticastLock.cpp +++ b/src/network/MulticastLock.cpp @@ -41,7 +41,7 @@ MulticastLock::~MulticastLock() = default; #endif -void MulticastLock::invokeJniMethod(const char* const pMethodName) +void MulticastLock::invokeJniMethod(const char* const pMethodName) const { #if defined(Q_OS_ANDROID) QJniEnvironment env; diff --git a/src/network/MulticastLock.h b/src/network/MulticastLock.h index 746bde9c7..f325c3696 100644 --- a/src/network/MulticastLock.h +++ b/src/network/MulticastLock.h @@ -10,7 +10,7 @@ namespace governikus class MulticastLock { private: - void invokeJniMethod(const char* const pMethodName); + void invokeJniMethod(const char* const pMethodName) const; public: MulticastLock(); diff --git a/src/network/NetworkManager.cpp b/src/network/NetworkManager.cpp index bd935afd8..9af2abe41 100644 --- a/src/network/NetworkManager.cpp +++ b/src/network/NetworkManager.cpp @@ -190,11 +190,12 @@ QSharedPointer NetworkManager::processUpdaterRequest(QNetworkRequ } -QString NetworkManager::getUserAgentHeader() const +QString NetworkManager::getUserAgentServerHeader() { + // According to TR-03124-1, chapter 2.2.2.1, the Server-header shall have the following form: const auto& info = VersionInfo::getInstance(); const QString spec = QStringLiteral(" (%1/%2)").arg(info.getSpecificationTitle(), info.getSpecificationVersion()); - return QCoreApplication::applicationName() % QLatin1Char('/') % QCoreApplication::applicationVersion() % spec; + return info.getImplementationTitle() % QLatin1Char('/') % info.getImplementationVersion() % spec; } @@ -207,7 +208,7 @@ void NetworkManager::onShutdown() } -void NetworkManager::onProxyChanged() +void NetworkManager::onProxyChanged() const { setApplicationProxyFactory(); } @@ -216,15 +217,30 @@ void NetworkManager::onProxyChanged() NetworkManager::NetworkError NetworkManager::toNetworkError(const QSharedPointer& pNetworkReply) { qCDebug(network) << "Select error message for:" << pNetworkReply->error(); - switch (pNetworkReply->error()) + switch (pNetworkReply->error()) // See qtbase/src/network/access/qhttpthreaddelegate.cpp for details { case QNetworkReply::TimeoutError: return NetworkError::TimeOut; - case QNetworkReply::ServiceUnavailableError: + case QNetworkReply::ServiceUnavailableError: // 503 return NetworkError::ServiceUnavailable; - case QNetworkReply::ProxyAuthenticationRequiredError: + case QNetworkReply::InternalServerError: // 500 + case QNetworkReply::OperationNotImplementedError: // 501 + case QNetworkReply::UnknownServerError: // > 500 + return NetworkError::ServerError; + + case QNetworkReply::ProtocolInvalidOperationError: // 400 + case QNetworkReply::AuthenticationRequiredError: // 401 + case QNetworkReply::ContentAccessDenied: // 403 + case QNetworkReply::ContentNotFoundError: // 404 + case QNetworkReply::ContentOperationNotPermittedError: // 405 + case QNetworkReply::ContentConflictError: // 409 + case QNetworkReply::ContentGoneError: // 410 + case QNetworkReply::UnknownContentError: // >= 400 + return NetworkError::ClientError; + + case QNetworkReply::ProxyAuthenticationRequiredError: // 407 case QNetworkReply::ProxyConnectionClosedError: case QNetworkReply::ProxyConnectionRefusedError: case QNetworkReply::ProxyNotFoundError: @@ -253,6 +269,12 @@ GlobalStatus NetworkManager::toTrustedChannelStatus(const QSharedPointer& case NetworkManager::NetworkError::ServiceUnavailable: return {GlobalStatus::Code::Network_ServiceUnavailable, infoMap}; + case NetworkManager::NetworkError::ServerError: + return {GlobalStatus::Code::Network_ServerError, infoMap}; + + case NetworkManager::NetworkError::ClientError: + return {GlobalStatus::Code::Network_ClientError, infoMap}; + case NetworkManager::NetworkError::TimeOut: return {GlobalStatus::Code::Network_TimeOut, infoMap}; @@ -297,7 +325,7 @@ GlobalStatus NetworkManager::toStatus(const QSharedPointer& } -bool NetworkManager::prepareConnection(QNetworkRequest& pRequest) +bool NetworkManager::prepareConnection(QNetworkRequest& pRequest) const { if (mApplicationExitInProgress) { @@ -307,7 +335,7 @@ bool NetworkManager::prepareConnection(QNetworkRequest& pRequest) pRequest.setTransferTimeout(); if (pRequest.header(QNetworkRequest::UserAgentHeader).isNull()) { - pRequest.setHeader(QNetworkRequest::UserAgentHeader, getUserAgentHeader()); + pRequest.setHeader(QNetworkRequest::UserAgentHeader, getUserAgentServerHeader()); } if (pRequest.sslConfiguration() == QSslConfiguration::defaultConfiguration()) @@ -421,12 +449,6 @@ class SystemProxyFactory : public QNetworkProxyFactory { public: - SystemProxyFactory() - : QNetworkProxyFactory() - { - } - - QList queryProxy(const QNetworkProxyQuery& pInputQuery = QNetworkProxyQuery()) override { qCDebug(network) << pInputQuery; @@ -442,12 +464,6 @@ class CustomProxyFactory : public QNetworkProxyFactory { public: - CustomProxyFactory() - : QNetworkProxyFactory() - { - } - - QList queryProxy(const QNetworkProxyQuery& pInputQuery = QNetworkProxyQuery()) override { qCDebug(network) << pInputQuery; diff --git a/src/network/NetworkManager.h b/src/network/NetworkManager.h index 472087fe6..c3723ce8e 100644 --- a/src/network/NetworkManager.h +++ b/src/network/NetworkManager.h @@ -40,18 +40,16 @@ class NetworkManager QAtomicInt mOpenConnectionCount; QSet mUpdaterSessions; - bool prepareConnection(QNetworkRequest& pRequest); + bool prepareConnection(QNetworkRequest& pRequest) const; [[nodiscard]] QSharedPointer trackConnection(QNetworkReply* pResponse); [[nodiscard]] QSharedPointer processRequest(QNetworkRequest& pRequest, const std::function(QNetworkRequest&)>& pInvoke); [[nodiscard]] QSharedPointer processUpdaterRequest(QNetworkRequest& pRequest, const std::function(QNetworkRequest&)>& pInvoke); - [[nodiscard]] QString getUserAgentHeader() const; - public Q_SLOTS: void onShutdown(); - void onProxyChanged(); + void onProxyChanged() const; protected: NetworkManager(); @@ -61,6 +59,8 @@ class NetworkManager enum class NetworkError { ServiceUnavailable, + ServerError, + ClientError, TimeOut, ProxyError, SecurityError, @@ -68,6 +68,7 @@ class NetworkManager }; Q_ENUM(NetworkError) + [[nodiscard]] static QString getUserAgentServerHeader(); static void setApplicationProxyFactory(); static void lockProxy(bool pLocked) { diff --git a/src/network/Template.h b/src/network/Template.h index f88075052..b99221ec3 100644 --- a/src/network/Template.h +++ b/src/network/Template.h @@ -8,7 +8,6 @@ #pragma once - #include #include #include diff --git a/src/network/TlsChecker.cpp b/src/network/TlsChecker.cpp index 6646fa43e..650a21d78 100644 --- a/src/network/TlsChecker.cpp +++ b/src/network/TlsChecker.cpp @@ -109,18 +109,6 @@ QString TlsChecker::toString(QSsl::SslProtocol pProtocol) case QSsl::SslProtocol::SecureProtocols: return QStringLiteral("SecureProtocols"); -#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) || QT_DEPRECATED_SINCE(5, 15) && (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) - case QSsl::SslProtocol::SslV2: - return QStringLiteral("SslV2"); - - case QSsl::SslProtocol::SslV3: - return QStringLiteral("SslV3"); - - case QSsl::SslProtocol::TlsV1SslV3: - return QStringLiteral("TlsV1SslV3"); - -#endif - QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED diff --git a/src/network/UrlUtil.cpp b/src/network/UrlUtil.cpp index d1752f341..e8822244e 100644 --- a/src/network/UrlUtil.cpp +++ b/src/network/UrlUtil.cpp @@ -2,12 +2,10 @@ * Copyright (c) 2014-2023 Governikus GmbH & Co. KG, Germany */ - #include "UrlUtil.h" #include "AppSettings.h" #include "Env.h" -#include "Initializer.h" #include #include diff --git a/src/network/UrlUtil.h b/src/network/UrlUtil.h index 149ec38ed..943432a53 100644 --- a/src/network/UrlUtil.h +++ b/src/network/UrlUtil.h @@ -10,6 +10,8 @@ #include "ECardApiResult.h" +#include "EnumHelper.h" + #include #include #include @@ -55,6 +57,14 @@ class UrlUtil static void setHiddenSettings(const QUrlQuery& pUrl); static QPair getRequest(const QUrlQuery& pUrl); + + template + static T prepareToEnum(const QString& pStr, T pDefault) + { + return Enum::fromString(pStr.toUpper().replace(QLatin1Char('-'), QLatin1Char('_')), pDefault); + } + + }; } // namespace governikus diff --git a/src/network/WifiInfo.h b/src/network/WifiInfo.h index 6bfdcba13..f3f140b1b 100644 --- a/src/network/WifiInfo.h +++ b/src/network/WifiInfo.h @@ -6,7 +6,6 @@ * \brief Provides information about the WiFi status */ - #pragma once #include @@ -32,7 +31,7 @@ class WifiInfo static bool isPrivateIp(const QHostAddress& pAddress); static bool hasPrivateIpAddress(); - [[nodiscard]] bool getCurrentWifiEnabled(); + [[nodiscard]] bool getCurrentWifiEnabled() const; #if defined(Q_OS_ANDROID) @@ -44,7 +43,7 @@ class WifiInfo WifiInfo(); ~WifiInfo() override = default; - [[nodiscard]] bool isWifiEnabled(); + [[nodiscard]] bool isWifiEnabled() const; Q_SIGNALS: void fireWifiEnabledChanged(bool pEnabled); diff --git a/src/network/WifiInfo_android.cpp b/src/network/WifiInfo_android.cpp index f20c515fc..e05acb85e 100644 --- a/src/network/WifiInfo_android.cpp +++ b/src/network/WifiInfo_android.cpp @@ -25,7 +25,7 @@ WifiInfo::WifiInfo() } -bool WifiInfo::getCurrentWifiEnabled() +bool WifiInfo::getCurrentWifiEnabled() const { QJniEnvironment env; const QJniObject context(QNativeInterface::QAndroidApplication::context()); @@ -68,7 +68,7 @@ void WifiInfo::timerEvent(QTimerEvent* pEvent) } -bool WifiInfo::isWifiEnabled() +bool WifiInfo::isWifiEnabled() const { return mWifiEnabled; } diff --git a/src/network/WifiInfo_generic.cpp b/src/network/WifiInfo_generic.cpp index 3558ccd2a..7ca2c5bc2 100644 --- a/src/network/WifiInfo_generic.cpp +++ b/src/network/WifiInfo_generic.cpp @@ -22,13 +22,13 @@ WifiInfo::WifiInfo() } -bool WifiInfo::getCurrentWifiEnabled() +bool WifiInfo::getCurrentWifiEnabled() const { return true; } -bool WifiInfo::isWifiEnabled() +bool WifiInfo::isWifiEnabled() const { return mWifiEnabled; } diff --git a/src/network/WifiInfo_ios.mm b/src/network/WifiInfo_ios.mm index 72a9e7eb9..1a58f88e9 100644 --- a/src/network/WifiInfo_ios.mm +++ b/src/network/WifiInfo_ios.mm @@ -17,13 +17,13 @@ } -bool WifiInfo::getCurrentWifiEnabled() +bool WifiInfo::getCurrentWifiEnabled() const { return mWifiEnabled; } -bool WifiInfo::isWifiEnabled() +bool WifiInfo::isWifiEnabled() const { return getCurrentWifiEnabled(); } diff --git a/src/secure_storage/SecureStorage.cpp b/src/secure_storage/SecureStorage.cpp index cd05b4941..c853cdca0 100644 --- a/src/secure_storage/SecureStorage.cpp +++ b/src/secure_storage/SecureStorage.cpp @@ -64,7 +64,6 @@ CONFIG_NAME(CONFIGURATION_GROUP_NAME_SMART, "smart") CONFIG_NAME(CONFIGURATION_NAME_SMART_PERSONALIZATION_URL, "personalizationUrl") CONFIG_NAME(CONFIGURATION_NAME_SMART_PERSONALIZATION_TEST_URL, "personalizationTestUrl") CONFIG_NAME(CONFIGURATION_NAME_SMART_SERVICEID, "serviceId") -CONFIG_NAME(CONFIGURATION_NAME_SMART_VERSIONTAG, "versionTag") CONFIG_NAME(CONFIGURATION_NAME_SMART_SSDAID, "ssdAid") CONFIG_NAME(CONFIGURATION_GROUP_NAME_LOCAL_IFD, "localIfd") @@ -79,8 +78,7 @@ defineSingleton(SecureStorage) SecureStorage::SecureStorage() - : mLoaded(false) - , mCvcas() + : mCvcas() , mCvcasTest() , mUpdateCertificates() , mSelfAuthenticationUrl() @@ -92,7 +90,6 @@ SecureStorage::SecureStorage() , mSmartPersonalizationUrl() , mSmartPersonalizationTestUrl() , mSmartServiceId() - , mSmartVersionTag() , mSmartSsdAid() , mLocalIfdPackageName() , mLocalIfdMinVersion() @@ -110,12 +107,6 @@ SecureStorage::SecureStorage() } -bool SecureStorage::isLoaded() const -{ - return mLoaded; -} - - QString SecureStorage::getDeveloperConfig() const { if (BuildHelper::getCertificateType() == CertificateType::DEVELOPER) @@ -259,7 +250,6 @@ void SecureStorage::load() mSmartPersonalizationUrl = readGroup(config, CONFIGURATION_GROUP_NAME_SMART(), CONFIGURATION_NAME_SMART_PERSONALIZATION_URL()); mSmartPersonalizationTestUrl = readGroup(config, CONFIGURATION_GROUP_NAME_SMART(), CONFIGURATION_NAME_SMART_PERSONALIZATION_TEST_URL()); mSmartServiceId = readGroup(config, CONFIGURATION_GROUP_NAME_SMART(), CONFIGURATION_NAME_SMART_SERVICEID()); - mSmartVersionTag = readGroup(config, CONFIGURATION_GROUP_NAME_SMART(), CONFIGURATION_NAME_SMART_VERSIONTAG()); mSmartSsdAid = readGroup(config, CONFIGURATION_GROUP_NAME_SMART(), CONFIGURATION_NAME_SMART_SSDAID()); QJsonValue localIfdValue = config.value(CONFIGURATION_GROUP_NAME_LOCAL_IFD()); @@ -272,13 +262,30 @@ void SecureStorage::load() mLocalIfdMinPskSize = localIfdValueObject.value(CONFIGURATION_NAME_LOCAL_IFD_MIN_PSK_SIZE()).toInt(); } - mLoaded = true; - qCDebug(securestorage) << "SecureStorage successfully loaded"; + qCDebug(securestorage) << "SecureStorage loaded:" << isValid(); qCInfo(securestorage) << "Vendor" << mVendor; } -QByteArrayList SecureStorage::loadTestCvcsFromAppDir() +bool SecureStorage::isValid() const +{ + // check some eID required member + return !mCvcas.isEmpty() + && !mCvcasTest.isEmpty() + && !mSelfAuthenticationUrl.isEmpty() + && !mSelfAuthenticationTestUrl.isEmpty() + && mTlsConfig.isValid() + && mTlsConfigPsk.isValid() + && mTlsConfigRemoteIfd.isValid() + && mTlsConfigRemoteIfdPairing.isValid() + && mTlsConfigLocalIfd.isValid() + && !mMinStaticKeySizes.isEmpty() + && !mMinEphemeralKeySizes.isEmpty() + && mLocalIfdMinPskSize > 0; +} + + +QByteArrayList SecureStorage::loadTestCvcsFromAppDir() const { QByteArrayList testCvcs; const QDir appDir(QCoreApplication::applicationDirPath()); @@ -376,12 +383,6 @@ const QString& SecureStorage::getSmartServiceId() const } -const QString& SecureStorage::getSmartVersionTag() const -{ - return mSmartVersionTag; -} - - const QString& SecureStorage::getSmartSsdAid() const { return mSmartSsdAid; diff --git a/src/secure_storage/SecureStorage.h b/src/secure_storage/SecureStorage.h index 7d7aa9c9d..2f2cb87d5 100644 --- a/src/secure_storage/SecureStorage.h +++ b/src/secure_storage/SecureStorage.h @@ -38,7 +38,6 @@ class SecureStorage friend class ::test_SecureStorage; private: - bool mLoaded; QString mVendor; QByteArrayList mCvcas; QByteArrayList mCvcasTest; @@ -52,7 +51,6 @@ class SecureStorage QString mSmartPersonalizationUrl; QString mSmartPersonalizationTestUrl; QString mSmartServiceId; - QString mSmartVersionTag; QString mSmartSsdAid; QString mLocalIfdPackageName; QString mLocalIfdMinVersion; @@ -75,7 +73,7 @@ class SecureStorage [[nodiscard]] QJsonObject loadFile(const QStringList& pFiles) const; void load(); - QByteArrayList loadTestCvcsFromAppDir(); + QByteArrayList loadTestCvcsFromAppDir() const; [[nodiscard]] QByteArray loadTestCvc(const QString& pPath) const; protected: @@ -99,7 +97,6 @@ class SecureStorage [[nodiscard]] const QUrl& getAppcastBetaUpdateUrl() const; [[nodiscard]] const QString& getSmartPersonalizationUrl(bool pTest = false) const; [[nodiscard]] const QString& getSmartServiceId() const; - [[nodiscard]] const QString& getSmartVersionTag() const; [[nodiscard]] const QString& getSmartSsdAid() const; [[nodiscard]] const QString& getLocalIfdPackageName() const; [[nodiscard]] const QString& getLocalIfdMinVersion() const; @@ -110,7 +107,7 @@ class SecureStorage [[nodiscard]] const TlsConfiguration& getTlsConfigLocalIfd() const; [[nodiscard]] int getMinimumStaticKeySize(QSsl::KeyAlgorithm pKeyAlgorithm) const; [[nodiscard]] int getMinimumEphemeralKeySize(QSsl::KeyAlgorithm pKeyAlgorithm) const; - [[nodiscard]] bool isLoaded() const; + [[nodiscard]] bool isValid() const; [[nodiscard]] QString getDeveloperConfig() const; [[nodiscard]] QString getCustomConfig() const; diff --git a/src/secure_storage/TlsConfiguration.cpp b/src/secure_storage/TlsConfiguration.cpp index e5021bcac..cd44f3d42 100644 --- a/src/secure_storage/TlsConfiguration.cpp +++ b/src/secure_storage/TlsConfiguration.cpp @@ -4,12 +4,11 @@ #include "TlsConfiguration.h" -#include "JsonValueRef.h" - #include #include #include #include +#include using namespace governikus; @@ -64,14 +63,14 @@ void TlsConfiguration::load(const QJsonObject& pConfig) SslCipherList ciphers; const QJsonArray& pskCiphers = readJsonArray(pConfig, SETTINGS_GROUP_NAME_CIPHERS); - for (JsonValueRef line : pskCiphers) + for (const QJsonValueConstRef line : pskCiphers) { ciphers += line.toString(); } SslEllipticCurveVector ellipticCurves; const QJsonArray& allowedEcs = readJsonArray(pConfig, SETTINGS_GROUP_NAME_ELLIPTIC_CURVES); - for (JsonValueRef line : allowedEcs) + for (const QJsonValueConstRef line : allowedEcs) { ellipticCurves += line.toString(); } @@ -86,6 +85,17 @@ void TlsConfiguration::load(const QJsonObject& pConfig) mConfiguration.setCiphers(ciphers); mConfiguration.setEllipticCurves(ellipticCurves); mConfiguration.setBackendConfigurationOption(QByteArrayLiteral("SignatureAlgorithms"), signatureAlgorithms.join(':')); + +#if defined(GOVERNIKUS_QT) || (QT_VERSION >= QT_VERSION_CHECK(6, 7, 0)) + mConfiguration.setDiffieHellmanParameters(QSslDiffieHellmanParameters()); // use SSL_CTX_set_dh_auto +#endif +} + + +bool TlsConfiguration::isValid() const +{ + return !getCiphers().isEmpty() + && !getSignatureAlgorithms().isEmpty(); } @@ -208,7 +218,7 @@ QByteArrayList TlsConfiguration::readSignatureAlgorithms(const QJsonObject& pCon const QJsonArray& array = tmp.toArray(); QByteArrayList algorithms; - for (JsonValueRef line : array) + for (const QJsonValueConstRef line : array) { const auto& value = line.toString(); if (value.count(QStringLiteral("+")) != 1) diff --git a/src/secure_storage/TlsConfiguration.h b/src/secure_storage/TlsConfiguration.h index 5701b1e79..aac2399e5 100644 --- a/src/secure_storage/TlsConfiguration.h +++ b/src/secure_storage/TlsConfiguration.h @@ -62,6 +62,7 @@ class TlsConfiguration final public: void load(const QJsonObject& pConfig); + [[nodiscard]] bool isValid() const; [[nodiscard]] QSsl::SslProtocol getProtocolVersion() const; [[nodiscard]] bool getOcspStapling() const; diff --git a/src/services/AppUpdateData.cpp b/src/services/AppUpdateData.cpp index e5e510f7c..e79252d34 100644 --- a/src/services/AppUpdateData.cpp +++ b/src/services/AppUpdateData.cpp @@ -4,9 +4,6 @@ #include "AppUpdateData.h" -#include "AppSettings.h" -#include "VersionNumber.h" - #include #include #include @@ -74,7 +71,7 @@ AppUpdateData::AppUpdateData(const QByteArray& pData) mNotesUrl = QUrl(jsonObject[QLatin1String("notes")].toString()); mDate = QDateTime::fromString(jsonObject[QLatin1String("date")].toString(), Qt::ISODate); mChecksumUrl = QUrl(jsonObject[QLatin1String("checksum")].toString()); - mSize = qMax(-1, jsonObject[QLatin1String("size")].toInt(-1)); + mSize = std::max(-1, jsonObject[QLatin1String("size")].toInt(-1)); return; } } @@ -112,17 +109,8 @@ const GlobalStatus& AppUpdateData::getParsingResult() const bool AppUpdateData::isCompatible() const { #if defined(Q_OS_WIN) || defined(Q_OS_MACOS) - - #if (QT_VERSION < QT_VERSION_CHECK(6, 1, 0)) - const auto osv = QOperatingSystemVersion::current(); - const auto currentVersion = QVersionNumber(osv.majorVersion(), osv.minorVersion(), osv.microVersion()); - return currentVersion >= mMinOsVersion; - - #else return QOperatingSystemVersion::current().version() >= mMinOsVersion; - #endif - #else return true; diff --git a/src/services/AppUpdater.cpp b/src/services/AppUpdater.cpp index c7ebe45ea..111f3c4de 100644 --- a/src/services/AppUpdater.cpp +++ b/src/services/AppUpdater.cpp @@ -60,7 +60,7 @@ bool AppUpdater::download(const QUrl& pUrl) } -QString AppUpdater::save(const QByteArray& pData, const QString& pFilename) +QString AppUpdater::save(const QByteArray& pData, const QString& pFilename) const { const QDir dir(mDownloadPath); if (!dir.exists()) @@ -90,7 +90,7 @@ QString AppUpdater::save(const QByteArray& pData, const QString& pFilename) } -bool AppUpdater::abortDownload() +bool AppUpdater::abortDownload() const { if (mDownloadInProgress) { @@ -120,7 +120,7 @@ const AppUpdateData& AppUpdater::getUpdateData() const } -void AppUpdater::skipVersion(const QString& pVersion) +void AppUpdater::skipVersion(const QString& pVersion) const { qCInfo(appupdate) << "Skip application update:" << pVersion; Env::getSingleton()->getGeneralSettings().skipVersion(pVersion); diff --git a/src/services/AppUpdater.h b/src/services/AppUpdater.h index 1cc51fa0c..bdb900ad4 100644 --- a/src/services/AppUpdater.h +++ b/src/services/AppUpdater.h @@ -36,14 +36,14 @@ class AppUpdater void clearDownloaderConnection(); bool download(const QUrl& pUrl); - QString save(const QByteArray& pData, const QString& pFilename); + QString save(const QByteArray& pData, const QString& pFilename) const; public: - bool abortDownload(); + bool abortDownload() const; bool downloadUpdate(); bool checkAppUpdate(bool pForceUpdate = false); [[nodiscard]] const AppUpdateData& getUpdateData() const; - void skipVersion(const QString& pVersion); + void skipVersion(const QString& pVersion) const; #ifndef QT_NO_DEBUG [[nodiscard]] QString getDownloadPath() const; diff --git a/src/services/Service.cpp b/src/services/Service.cpp index 2b6ad7d69..e6eaf4b96 100644 --- a/src/services/Service.cpp +++ b/src/services/Service.cpp @@ -5,7 +5,7 @@ #include "Service.h" #include "AppSettings.h" -#include "AppUpdateData.h" +#include "AppUpdater.h" #include "ProviderConfiguration.h" #if defined(Q_OS_WIN) || defined(Q_OS_MACOS) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) diff --git a/src/services/Service.h b/src/services/Service.h index 8c5e50304..484f83627 100644 --- a/src/services/Service.h +++ b/src/services/Service.h @@ -4,7 +4,7 @@ #pragma once -#include "AppUpdater.h" +#include "AppUpdateData.h" #include "Env.h" #include diff --git a/src/settings/AbstractSettings.cpp b/src/settings/AbstractSettings.cpp index 902670a3b..6e82f54ba 100644 --- a/src/settings/AbstractSettings.cpp +++ b/src/settings/AbstractSettings.cpp @@ -39,10 +39,10 @@ QSharedPointer AbstractSettings::getStore(const QString& pFilename, Q Q_ASSERT(mTestDir->isValid()); } QSettings::setPath(QSettings::IniFormat, QSettings::UserScope, mTestDir->path()); - return QSharedPointer::create(QSettings::IniFormat, QSettings::UserScope, QCoreApplication::organizationName(), QCoreApplication::applicationName()); + return QSharedPointer::create(QSettings::IniFormat, QSettings::UserScope, QCoreApplication::organizationName(), QStringLiteral("AusweisApp2")); } #endif Q_ASSERT(pFilename.isEmpty() == (pFormat == QSettings::InvalidFormat)); - return pFilename.isEmpty() ? QSharedPointer::create() : QSharedPointer::create(pFilename, pFormat); + return pFilename.isEmpty() ? QSharedPointer::create(QCoreApplication::organizationName(), QStringLiteral("AusweisApp2")) : QSharedPointer::create(pFilename, pFormat); } diff --git a/src/settings/AppSettings.cpp b/src/settings/AppSettings.cpp index d430a8719..328b46631 100644 --- a/src/settings/AppSettings.cpp +++ b/src/settings/AppSettings.cpp @@ -11,7 +11,6 @@ AppSettings::AppSettings() : QObject() , mGeneralSettings() , mPreVerificationSettings() - , mHistorySettings() , mRemoteReaderSettings() { } @@ -29,12 +28,6 @@ PreVerificationSettings& AppSettings::getPreVerificationSettings() } -HistorySettings& AppSettings::getHistorySettings() -{ - return mHistorySettings; -} - - RemoteServiceSettings& AppSettings::getRemoteServiceSettings() { return mRemoteReaderSettings; diff --git a/src/settings/AppSettings.h b/src/settings/AppSettings.h index 1d531522d..4c10c4273 100644 --- a/src/settings/AppSettings.h +++ b/src/settings/AppSettings.h @@ -10,7 +10,6 @@ #include "Env.h" #include "GeneralSettings.h" -#include "HistorySettings.h" #include "PreVerificationSettings.h" #include "RemoteServiceSettings.h" @@ -36,13 +35,11 @@ class AppSettings GeneralSettings mGeneralSettings; PreVerificationSettings mPreVerificationSettings; - HistorySettings mHistorySettings; RemoteServiceSettings mRemoteReaderSettings; public: virtual GeneralSettings& getGeneralSettings(); virtual PreVerificationSettings& getPreVerificationSettings(); - virtual HistorySettings& getHistorySettings(); virtual RemoteServiceSettings& getRemoteServiceSettings(); }; diff --git a/src/settings/AutoStart.h b/src/settings/AutoStart.h index 46919612f..c785098e7 100644 --- a/src/settings/AutoStart.h +++ b/src/settings/AutoStart.h @@ -31,6 +31,9 @@ class AutoStart [[nodiscard]] static bool enabled(); [[nodiscard]] static bool isSetByAdmin(); [[nodiscard]] static bool set(bool pEnabled); +#ifdef Q_OS_WIN + [[nodiscard]] static bool removeOldAutostart(); +#endif }; diff --git a/src/settings/AutoStart_win.cpp b/src/settings/AutoStart_win.cpp index e23fa1f39..bac21c46f 100644 --- a/src/settings/AutoStart_win.cpp +++ b/src/settings/AutoStart_win.cpp @@ -5,8 +5,6 @@ #include "AutoStart.h" #include "AbstractSettings.h" -#include "Env.h" -#include "VolatileSettings.h" #include @@ -64,3 +62,16 @@ bool AutoStart::setInternal(bool pEnabled) return true; } + + +bool AutoStart::removeOldAutostart() +{ + const auto& windowsBootUpSettings = getRegistryStore(); + if (windowsBootUpSettings->contains(QStringLiteral("AusweisApp2"))) + { + qDebug() << "Detected old autostart, migrating old autostart setting..."; + windowsBootUpSettings->remove(QStringLiteral("AusweisApp2")); + return true; + } + return false; +} diff --git a/src/settings/GeneralSettings.cpp b/src/settings/GeneralSettings.cpp index c0ac3dc1f..228356dd7 100644 --- a/src/settings/GeneralSettings.cpp +++ b/src/settings/GeneralSettings.cpp @@ -9,7 +9,6 @@ #include "GeneralSettings.h" #include "AutoStart.h" -#include "BuildHelper.h" #include "Env.h" #include "LanguageLoader.h" #include "Randomizer.h" @@ -38,7 +37,6 @@ SETTINGS_NAME(SETTINGS_NAME_DEVELOPER_MODE, "developerMode") SETTINGS_NAME(SETTINGS_NAME_USE_SELF_AUTH_TEST_URI, "selfauthTestUri") SETTINGS_NAME(SETTINGS_NAME_SIMULATOR, "simulator") SETTINGS_NAME(SETTINGS_NAME_LANGUAGE, "language") -SETTINGS_NAME(SETTINGS_NAME_SCREEN_ORIENTATION, "screenOrientation") SETTINGS_NAME(SETTINGS_NAME_DEVICE_SURVEY_PENDING, "deviceSurveyPending") SETTINGS_NAME(SETTINGS_NAME_LAST_READER_PLUGIN_TYPE, "lastTechnology") SETTINGS_NAME(SETTINGS_NAME_IN_APP_NOTIFICATIONS, "showInAppNotifications") @@ -51,9 +49,12 @@ SETTINGS_NAME(SETTINGS_NAME_CUSTOM_PROXY_HOST, "customProxyHost") SETTINGS_NAME(SETTINGS_NAME_CUSTOM_PROXY_PORT, "customProxyPort") SETTINGS_NAME(SETTINGS_NAME_CUSTOM_PROXY_TYPE, "customProxyType") SETTINGS_NAME(SETTINGS_NAME_USE_CUSTOM_PROXY, "useCustomProxy") +SETTINGS_NAME(SETTINGS_NAME_DARK_MODE, "darkMode") +SETTINGS_NAME(SETTINGS_NAME_USE_SYSTEM_FONT, "useSystemFont") SETTINGS_NAME(SETTINGS_NAME_ENABLE_CAN_ALLOWED, "enableCanAllowed") SETTINGS_NAME(SETTINGS_NAME_SKIP_RIGHTS_ON_CAN_ALLOWED, "skipRightsOnCanAllowed") SETTINGS_NAME(SETTINGS_NAME_IFD_SERVICE_TOKEN, "ifdServiceToken") +SETTINGS_NAME(SETTINGS_NAME_SMART_AVAILABLE, "smartAvailable") } // namespace GeneralSettings::GeneralSettings() @@ -68,6 +69,18 @@ GeneralSettings::GeneralSettings(QSharedPointer pStore) , mStore(std::move(pStore)) , mIsNewAppVersion(false) { + // With 2.0.0 the option to change the screen orientation was removed + mStore->remove(QStringLiteral("screenOrientation")); + + // With 2.0.0 the history was removed + const auto& history = QStringLiteral("history"); + if (mStore->childGroups().contains(history)) + { + mStore->beginGroup(history); + mStore->remove(QString()); + mStore->endGroup(); + } + const bool isNewInstallation = getPersistentSettingsVersion().isEmpty(); if (isNewInstallation) { @@ -126,6 +139,18 @@ bool GeneralSettings::autoStartIsSetByAdmin() const } +bool GeneralSettings::showTrayIcon() const +{ +#if defined(Q_OS_WIN) || defined(Q_OS_MACOS) + return isAutoStart(); + +#else + return true; + +#endif +} + + void GeneralSettings::setAutoStartInternal(bool pAutoStart) { if (pAutoStart != mAutoStart) @@ -365,23 +390,6 @@ void GeneralSettings::setLanguage(const QLocale::Language pLanguage) } -QString GeneralSettings::getScreenOrientation() const -{ - return mStore->value(SETTINGS_NAME_SCREEN_ORIENTATION(), QStringLiteral("auto")).toString(); -} - - -void GeneralSettings::setScreenOrientation(const QString& pScreenOrientation) -{ - if (pScreenOrientation != getScreenOrientation()) - { - mStore->setValue(SETTINGS_NAME_SCREEN_ORIENTATION(), pScreenOrientation); - save(mStore); - Q_EMIT fireSettingsChanged(); - } -} - - bool GeneralSettings::askForDeviceSurvey() const { return !mStore->contains(SETTINGS_NAME_DEVICE_SURVEY_PENDING()); @@ -677,6 +685,40 @@ void GeneralSettings::setUseCustomProxy(bool pUseCustomProxy) } +bool GeneralSettings::isUseSystemFont() const +{ + return mStore->value(SETTINGS_NAME_USE_SYSTEM_FONT(), false).toBool(); +} + + +void GeneralSettings::setUseSystemFont(bool pUseSystemFont) +{ + if (isUseSystemFont() != pUseSystemFont) + { + mStore->setValue(SETTINGS_NAME_USE_SYSTEM_FONT(), pUseSystemFont); + save(mStore); + Q_EMIT fireUseSystemFontChanged(); + } +} + + +QString GeneralSettings::getDarkMode() const +{ + return mStore->value(SETTINGS_NAME_DARK_MODE(), QString()).toString(); +} + + +void GeneralSettings::setDarkMode(const QString& pMode) +{ + if (getDarkMode() != pMode) + { + mStore->setValue(SETTINGS_NAME_DARK_MODE(), pMode); + save(mStore); + Q_EMIT fireDarkModeChanged(); + } +} + + QString GeneralSettings::getIfdServiceToken() { if (!mStore->contains(SETTINGS_NAME_IFD_SERVICE_TOKEN())) @@ -688,3 +730,48 @@ QString GeneralSettings::getIfdServiceToken() return mStore->value(SETTINGS_NAME_IFD_SERVICE_TOKEN(), QString()).toString(); } + + +bool GeneralSettings::doSmartUpdate() const +{ + return !mStore->contains(SETTINGS_NAME_SMART_AVAILABLE()); +} + + +bool GeneralSettings::isSmartAvailable() const +{ + return mStore->value(SETTINGS_NAME_SMART_AVAILABLE(), false).toBool(); +} + + +void GeneralSettings::setSmartAvailable(bool pSmartAvailable) +{ + const bool valueChanged = pSmartAvailable != isSmartAvailable(); + if (doSmartUpdate() || valueChanged) + { + mStore->setValue(SETTINGS_NAME_SMART_AVAILABLE(), pSmartAvailable); + save(mStore); + } + if (valueChanged) + { + Q_EMIT fireSmartAvailableChanged(pSmartAvailable); + } +} + + +#ifdef Q_OS_WIN +void GeneralSettings::migrateSettings() +{ + if (!isAutoStartAvailable()) + { + qCDebug(settings) << "AutoStart is not available, migration not possible."; + return; + } + if (AutoStart::removeOldAutostart()) + { + setAutoStart(true); + } +} + + +#endif diff --git a/src/settings/GeneralSettings.h b/src/settings/GeneralSettings.h index cc9ee8e1e..ef5fa7946 100644 --- a/src/settings/GeneralSettings.h +++ b/src/settings/GeneralSettings.h @@ -50,6 +50,7 @@ class GeneralSettings [[nodiscard]] bool isAutoStartAvailable() const; [[nodiscard]] bool isAutoStart() const; [[nodiscard]] bool autoStartIsSetByAdmin() const; + [[nodiscard]] bool showTrayIcon() const; void setAutoStart(bool pAutoStart); [[nodiscard]] QString getSkipVersion() const; @@ -84,9 +85,6 @@ class GeneralSettings [[nodiscard]] QLocale::Language getLanguage() const; void setLanguage(const QLocale::Language pLanguage); - [[nodiscard]] QString getScreenOrientation() const; - void setScreenOrientation(const QString& pScreenOrientation); - [[nodiscard]] bool askForDeviceSurvey() const; [[nodiscard]] bool isDeviceSurveyPending() const; void setDeviceSurveyPending(bool pDeviceSurveyPending); @@ -134,13 +132,30 @@ class GeneralSettings [[nodiscard]] bool useCustomProxy() const; void setUseCustomProxy(bool pUseCustomProxy); + [[nodiscard]] bool isUseSystemFont() const; + void setUseSystemFont(bool pUseSystemFont); + + [[nodiscard]] QString getDarkMode() const; + void setDarkMode(const QString& pMode); + [[nodiscard]] QString getIfdServiceToken(); + [[nodiscard]] bool doSmartUpdate() const; + [[nodiscard]] bool isSmartAvailable() const; + void setSmartAvailable(bool pSmartAvailable); + +#ifdef Q_OS_WIN + void migrateSettings(); +#endif + Q_SIGNALS: void fireLanguageChanged(); void fireDeveloperOptionsChanged(); void fireShowInAppNotificationsChanged(); void fireProxyChanged(); + void fireUseSystemFontChanged(); + void fireDarkModeChanged(); + void fireSmartAvailableChanged(bool pSmartAvailable); }; diff --git a/src/settings/HistoryInfo.cpp b/src/settings/HistoryInfo.cpp deleted file mode 100644 index df58fe7af..000000000 --- a/src/settings/HistoryInfo.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany - */ - -#include "HistoryInfo.h" - -#include -#include - - -using namespace governikus; - - -HistoryInfo::HistoryInfo(const QString& pSubjectName, const QString& pSubjectUrl, const QString& pUsage, const QDateTime& pDateTime, const QString& pTermOfUsage, const QStringList& pRequestedData) - : mSubjectName(pSubjectName) - , mSubjectUrl(pSubjectUrl) - , mPurpose(pUsage) - , mDateTime(roundToSeconds(pDateTime)) - , mTermOfUsage(pTermOfUsage) - , mRequestedData(pRequestedData) -{ -} - - -QDateTime HistoryInfo::roundToSeconds(const QDateTime& pDateTime) -{ - QDateTime roundedDateTime; - roundedDateTime.setMSecsSinceEpoch(pDateTime.toMSecsSinceEpoch() - pDateTime.toMSecsSinceEpoch() % 1000); - return roundedDateTime; -} - - -const QStringList& HistoryInfo::getRequestedData() const -{ - return mRequestedData; -} - - -const QString& HistoryInfo::getTermOfUsage() const -{ - return mTermOfUsage; -} - - -const QDateTime& HistoryInfo::getDateTime() const -{ - return mDateTime; -} - - -const QString& HistoryInfo::getPurpose() const -{ - return mPurpose; -} - - -const QString& HistoryInfo::getSubjectName() const -{ - return mSubjectName; -} - - -const QString& HistoryInfo::getSubjectUrl() const -{ - return mSubjectUrl; -} diff --git a/src/settings/HistoryInfo.h b/src/settings/HistoryInfo.h deleted file mode 100644 index d7512b469..000000000 --- a/src/settings/HistoryInfo.h +++ /dev/null @@ -1,85 +0,0 @@ -/** - * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany - */ - -/*! - * \brief Represents history settings. - */ - -#pragma once - -#include "AbstractSettings.h" - -#include -#include - - -namespace governikus -{ - -/*! - * \brief Represents a history entry, i.e. information of a successful authentication - */ -class HistoryInfo -{ - private: - static QDateTime roundToSeconds(const QDateTime& pDateTime); - - /*! - * The subject name contained in the certificate description - */ - QString mSubjectName; - - /*! - * The subject url contained in the certificate description - */ - QString mSubjectUrl; - - /*! - * The purpose contained in the certificate description - */ - QString mPurpose; - - /*! - * The authentication date and time - */ - QDateTime mDateTime; - - /*! - * The terms of usage contained in the certificate description - */ - QString mTermOfUsage; - - /*! - * The requested data fields during authentication - */ - QStringList mRequestedData; - - public: - HistoryInfo() = default; - - HistoryInfo(const QString& pSubjectName, const QString& pSubjectUrl, const QString& pUsage, const QDateTime& pDateTime, const QString& pTermOfUsage, const QStringList& pRequestedData); - - bool operator==(const HistoryInfo& pOther) const - { - return mSubjectName == pOther.mSubjectName && mSubjectUrl == pOther.mSubjectUrl && mPurpose == pOther.mPurpose - && mDateTime == pOther.mDateTime && mTermOfUsage == pOther.mTermOfUsage && mRequestedData == pOther.mRequestedData; - } - - - bool operator!=(const HistoryInfo& pOther) const - { - return !(*this == pOther); - } - - - [[nodiscard]] const QString& getSubjectName() const; - [[nodiscard]] const QString& getSubjectUrl() const; - [[nodiscard]] const QString& getPurpose() const; - [[nodiscard]] const QDateTime& getDateTime() const; - [[nodiscard]] const QString& getTermOfUsage() const; - [[nodiscard]] const QStringList& getRequestedData() const; -}; - - -} // namespace governikus diff --git a/src/settings/HistorySettings.cpp b/src/settings/HistorySettings.cpp deleted file mode 100644 index d6e6522e6..000000000 --- a/src/settings/HistorySettings.cpp +++ /dev/null @@ -1,175 +0,0 @@ -/** - * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany - */ - -#include "HistorySettings.h" - -#include "Env.h" -#include "VolatileSettings.h" - -#include - -namespace -{ -SETTINGS_NAME(SETTINGS_GROUP_NAME_CHRONIC, "history") -SETTINGS_NAME(SETTINGS_NAME_HISTORY_ITEMS, "items") -SETTINGS_NAME(SETTINGS_NAME_HISTORY_ENABLED, "enable") -SETTINGS_NAME(SETTINGS_NAME_CHRONIC_SUBJECTNAME, "subjectName") -SETTINGS_NAME(SETTINGS_NAME_CHRONIC_SUBJECTURL, "subjectUrl") -SETTINGS_NAME(SETTINGS_NAME_CHRONIC_USAGE, "usage") -SETTINGS_NAME(SETTINGS_NAME_CHRONIC_DATETIME, "dateTime") -SETTINGS_NAME(SETTINGS_NAME_CHRONIC_TOU, "termOfUsage") -SETTINGS_NAME(SETTINGS_NAME_CHRONIC_REQUESTED_DATA, "requestedData") -} // namespace - -using namespace governikus; - -Q_DECLARE_LOGGING_CATEGORY(settings) - -HistorySettings::HistorySettings() - : AbstractSettings() - , mStore(getStore()) - , mHistoryInfos() -{ - mStore->beginGroup(SETTINGS_GROUP_NAME_CHRONIC()); - mHistoryInfos = getHistoryInfosFromStore(); -} - - -bool HistorySettings::isEnabled() const -{ - return mStore->value(SETTINGS_NAME_HISTORY_ENABLED(), true).toBool(); -} - - -void HistorySettings::setEnabled(bool pEnabled) -{ - if (isEnabled() != pEnabled) - { - mStore->setValue(SETTINGS_NAME_HISTORY_ENABLED(), pEnabled); - save(mStore); - Q_EMIT fireEnabledChanged(pEnabled); - } -} - - -const QVector& HistorySettings::getHistoryInfos() const -{ - return mHistoryInfos; -} - - -QVector HistorySettings::getHistoryInfosFromStore() const -{ - const int itemCount = mStore->beginReadArray(SETTINGS_NAME_HISTORY_ITEMS()); - - QVector historyInfos; - historyInfos.reserve(itemCount); - for (int i = 0; i < itemCount; ++i) - { - mStore->setArrayIndex(i); - const QString subjectName = mStore->value(SETTINGS_NAME_CHRONIC_SUBJECTNAME(), QString()).toString(); - const QString subjectUrl = mStore->value(SETTINGS_NAME_CHRONIC_SUBJECTURL(), QString()).toString(); - const QString usage = mStore->value(SETTINGS_NAME_CHRONIC_USAGE(), QString()).toString(); - const QDateTime dateTime = QDateTime::fromString(mStore->value(SETTINGS_NAME_CHRONIC_DATETIME(), QString()).toString(), Qt::ISODate); - const QString termsOfUsage = mStore->value(SETTINGS_NAME_CHRONIC_TOU(), QString()).toString(); - const QStringList requestData = mStore->value(SETTINGS_NAME_CHRONIC_REQUESTED_DATA(), QStringList()).toStringList(); - historyInfos += HistoryInfo(subjectName, subjectUrl, usage, dateTime, termsOfUsage, requestData); - } - - mStore->endArray(); - return historyInfos; -} - - -void HistorySettings::setHistoryInfos(const QVector& pHistoryInfos) -{ - mStore->beginGroup(SETTINGS_NAME_HISTORY_ITEMS()); - mStore->remove(QString()); - mStore->endGroup(); - - mStore->beginWriteArray(SETTINGS_NAME_HISTORY_ITEMS()); - for (int i = 0; i < pHistoryInfos.size(); ++i) - { - const HistoryInfo& item = pHistoryInfos.at(i); - - mStore->setArrayIndex(i); - mStore->setValue(SETTINGS_NAME_CHRONIC_SUBJECTNAME(), item.getSubjectName()); - mStore->setValue(SETTINGS_NAME_CHRONIC_SUBJECTURL(), item.getSubjectUrl()); - mStore->setValue(SETTINGS_NAME_CHRONIC_USAGE(), item.getPurpose()); - mStore->setValue(SETTINGS_NAME_CHRONIC_DATETIME(), item.getDateTime().toString(Qt::ISODate)); - mStore->setValue(SETTINGS_NAME_CHRONIC_TOU(), item.getTermOfUsage()); - mStore->setValue(SETTINGS_NAME_CHRONIC_REQUESTED_DATA(), item.getRequestedData()); - } - mStore->endArray(); - save(mStore); - - mHistoryInfos = pHistoryInfos; - - Q_EMIT fireHistoryInfosChanged(); -} - - -void HistorySettings::addHistoryInfo(const HistoryInfo& pHistoryInfo) -{ - if (Env::getSingleton()->isUsedAsSDK()) - { - qCDebug(settings) << "Running as SDK. Ignoring save request for history."; - return; - } - - auto historyInfos = getHistoryInfos(); - historyInfos.prepend(pHistoryInfo); - setHistoryInfos(historyInfos); -} - - -int HistorySettings::deleteSettings(const QDateTime& pLatestToKeep) -{ - const auto historyInfos = getHistoryInfos(); - QVector remainingItems; - for (const auto& item : historyInfos) - { - if (!pLatestToKeep.isNull() && item.getDateTime() <= pLatestToKeep) - { - remainingItems += item; - } - } - int numberOfItemsToRemove = historyInfos.size() - remainingItems.size(); - setHistoryInfos(remainingItems); - return numberOfItemsToRemove; -} - - -int HistorySettings::deleteSettings(const TimePeriod& pPeriodToRemove) -{ - QDateTime latestToKeep = QDateTime::currentDateTime(); - switch (pPeriodToRemove) - { - case TimePeriod::PAST_HOUR: - latestToKeep = latestToKeep.addSecs(-60 * 60); - break; - - case TimePeriod::PAST_DAY: - latestToKeep = latestToKeep.addDays(-1); - break; - - case TimePeriod::PAST_WEEK: - latestToKeep = latestToKeep.addDays(-7); - break; - - case TimePeriod::LAST_FOUR_WEEKS: - latestToKeep = latestToKeep.addDays(-7 * 4); - break; - - case TimePeriod::ALL_HISTORY: - latestToKeep = QDateTime::fromMSecsSinceEpoch(1); - break; - - case TimePeriod::UNKNOWN: - return 0; - } - - qCDebug(settings) << "Remove history entries until timestamp:" << latestToKeep; - return deleteSettings(latestToKeep); -} diff --git a/src/settings/HistorySettings.h b/src/settings/HistorySettings.h deleted file mode 100644 index de5d4a0f2..000000000 --- a/src/settings/HistorySettings.h +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany - */ - -/*! - * \brief Represents history settings. - */ - -#pragma once - -#include "AbstractSettings.h" - -#include "EnumHelper.h" -#include "HistoryInfo.h" - -#include - - -class test_HistorySettings; - - -namespace governikus -{ - -defineEnumType(TimePeriod, - PAST_HOUR, - PAST_DAY, - PAST_WEEK, - LAST_FOUR_WEEKS, - ALL_HISTORY, - UNKNOWN - ) - -class HistorySettings - : public AbstractSettings -{ - Q_OBJECT - friend class AppSettings; - - private: - QSharedPointer mStore; - QVector mHistoryInfos; - - HistorySettings(); - [[nodiscard]] QVector getHistoryInfosFromStore() const; - - public: - ~HistorySettings() override = default; - - [[nodiscard]] bool isEnabled() const; - void setEnabled(bool pEnabled); - - [[nodiscard]] const QVector& getHistoryInfos() const; - void setHistoryInfos(const QVector& pHistoryInfos); - void addHistoryInfo(const HistoryInfo& pHistoryInfo); - int deleteSettings(const QDateTime& pLatestToKeep = QDateTime()); - int deleteSettings(const TimePeriod& pPeriodToRemove); - - Q_SIGNALS: - void fireEnabledChanged(bool pValue); - void fireHistoryInfosChanged(); -}; - - -} // namespace governikus diff --git a/src/settings/KeyPair.cpp b/src/settings/KeyPair.cpp index d0f150327..3d3a83cab 100644 --- a/src/settings/KeyPair.cpp +++ b/src/settings/KeyPair.cpp @@ -8,6 +8,7 @@ #include "Randomizer.h" #include +#include #include #include #include @@ -58,7 +59,7 @@ KeyPair::KeyPair(const QSslKey& pKey, const QSslCertificate& pCert) } -KeyPair KeyPair::generate() +KeyPair KeyPair::generate(const char* pCurve) { if (!Randomizer::getInstance().isSecureRandom()) { @@ -66,7 +67,7 @@ KeyPair KeyPair::generate() return KeyPair(); } - if (auto* pkey = createKey(); pkey) + if (auto* pkey = createKey(pCurve); pkey) { auto cert = createCertificate(pkey); if (cert) @@ -95,9 +96,9 @@ const QSslCertificate& KeyPair::getCertificate() const } -EVP_PKEY* KeyPair::createKey() +EVP_PKEY* KeyPair::createKey(const char* pCurve) { - QScopedPointer pkeyCtx(EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr)); + QScopedPointer pkeyCtx(EVP_PKEY_CTX_new_id(pCurve ? EVP_PKEY_EC : EVP_PKEY_RSA, nullptr)); if (pkeyCtx.isNull()) { @@ -107,20 +108,28 @@ EVP_PKEY* KeyPair::createKey() if (!EVP_PKEY_keygen_init(pkeyCtx.data())) { - qCCritical(settings) << "Cannot init rsa key ctx"; + qCCritical(settings) << "Cannot init key ctx"; return nullptr; } - if (!EVP_PKEY_CTX_set_rsa_keygen_bits(pkeyCtx.data(), 2048)) + if (pCurve) { - qCCritical(settings) << "Cannot generate rsa key bits"; + if (!EVP_PKEY_CTX_ctrl_str(pkeyCtx.data(), "ec_paramgen_curve", pCurve)) + { + qCCritical(settings) << "Cannot set curve"; + return nullptr; + } + } + else if (!EVP_PKEY_CTX_set_rsa_keygen_bits(pkeyCtx.data(), 2048)) + { + qCCritical(settings) << "Cannot generate key bits"; return nullptr; } EVP_PKEY* pkey = nullptr; if (!EVP_PKEY_keygen(pkeyCtx.data(), &pkey)) { - qCCritical(settings) << "Cannot generate rsa key"; + qCCritical(settings) << "Cannot generate key"; return nullptr; } @@ -141,11 +150,6 @@ QSharedPointer KeyPair::createCertificate(EVP_PKEY* pPkey) std::uniform_int_distribution uni_long(1); std::uniform_int_distribution uni_qulonglong(1); -#if OPENSSL_VERSION_NUMBER < 0x10100000L - #define X509_getm_notBefore X509_get_notBefore - #define X509_getm_notAfter X509_get_notAfter -#endif - ASN1_INTEGER_set(X509_get_serialNumber(x509.data()), uni_long(randomizer)); // see: https://tools.ietf.org/html/rfc5280#section-4.1.2.5 ASN1_TIME_set_string(X509_getm_notBefore(x509.data()), "19700101000000Z"); diff --git a/src/settings/KeyPair.h b/src/settings/KeyPair.h index 2183075ec..0b2b67b43 100644 --- a/src/settings/KeyPair.h +++ b/src/settings/KeyPair.h @@ -30,10 +30,10 @@ class KeyPair static QByteArray rewriteCertificate(X509* pX509); static QSharedPointer createCertificate(EVP_PKEY* pPkey); - static EVP_PKEY* createKey(); + static EVP_PKEY* createKey(const char* pCurve); public: - static KeyPair generate(); + static KeyPair generate(const char* pCurve = nullptr); [[nodiscard]] const QSslKey& getKey() const; [[nodiscard]] const QSslCertificate& getCertificate() const; diff --git a/src/settings/RemoteServiceSettings.cpp b/src/settings/RemoteServiceSettings.cpp index 6edd21af0..291ff8191 100644 --- a/src/settings/RemoteServiceSettings.cpp +++ b/src/settings/RemoteServiceSettings.cpp @@ -5,7 +5,6 @@ #include "RemoteServiceSettings.h" #include "DeviceInfo.h" -#include "JsonValueRef.h" #include "KeyPair.h" #include @@ -13,12 +12,8 @@ #include #include #include +#include -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) - #include -#else - #include -#endif using namespace governikus; @@ -186,7 +181,7 @@ void RemoteServiceSettings::removeTrustedCertificate(const QString& pFingerprint } -bool RemoteServiceSettings::checkAndGenerateKey(bool pForceGeneration) +bool RemoteServiceSettings::checkAndGenerateKey(bool pForceGeneration) const { if (getKey().isNull() || getCertificate().isNull() @@ -229,6 +224,10 @@ QSslKey RemoteServiceSettings::getKey() const { return QSslKey(data, QSsl::Rsa); } + else if (data.contains("BEGIN EC PRIVATE KEY")) + { + return QSslKey(data, QSsl::Ec); + } return QSslKey(); } @@ -273,7 +272,7 @@ QVector RemoteServiceSettings::getRemoteInfos const auto& data = mStore->value(SETTINGS_NAME_TRUSTED_REMOTE_INFO(), QByteArray()).toByteArray(); const auto& array = QJsonDocument::fromJson(data).array(); - for (JsonValueRef item : array) + for (const QJsonValueConstRef item : array) { infos << RemoteInfo::fromJson(item.toObject()); } diff --git a/src/settings/RemoteServiceSettings.h b/src/settings/RemoteServiceSettings.h index 658973cd7..f75bae742 100644 --- a/src/settings/RemoteServiceSettings.h +++ b/src/settings/RemoteServiceSettings.h @@ -97,7 +97,7 @@ class RemoteServiceSettings void removeTrustedCertificate(const QSslCertificate& pCertificate); void removeTrustedCertificate(const QString& pFingerprint); - bool checkAndGenerateKey(bool pForceGeneration = false); + bool checkAndGenerateKey(bool pForceGeneration = false) const; [[nodiscard]] QSslCertificate getCertificate() const; void setCertificate(const QSslCertificate& pCert) const; diff --git a/src/ui/aidl/UIPlugInAidl.cpp b/src/ui/aidl/UIPlugInAidl.cpp index 891b41ca6..128e1fdde 100644 --- a/src/ui/aidl/UIPlugInAidl.cpp +++ b/src/ui/aidl/UIPlugInAidl.cpp @@ -7,6 +7,7 @@ #include "Env.h" #include "ReaderManager.h" #include "UILoader.h" +#include "WorkflowRequest.h" #ifdef Q_OS_ANDROID #include "Randomizer.h" #include @@ -83,18 +84,18 @@ bool UIPlugInAidl::isSuccessfullInitialized() const } -void UIPlugInAidl::onWorkflowStarted(QSharedPointer pContext) +void UIPlugInAidl::onWorkflowStarted(const QSharedPointer& pRequest) { mWorkflowIsActive.lock(); - pContext->setReaderPlugInTypes({ReaderManagerPlugInType::NFC, ReaderManagerPlugInType::LOCAL_IFD, ReaderManagerPlugInType::SIMULATOR}); - mContext = pContext; + mContext = pRequest->getContext(); + mContext->setReaderPlugInTypes({ReaderManagerPlugInType::NFC, ReaderManagerPlugInType::LOCAL_IFD, ReaderManagerPlugInType::SIMULATOR}); mContext->claim(this); } -void UIPlugInAidl::onWorkflowFinished(QSharedPointer pContext) +void UIPlugInAidl::onWorkflowFinished(const QSharedPointer& pRequest) { - Q_UNUSED(pContext) + Q_UNUSED(pRequest) mContext.clear(); mJson->blockSignals(false); @@ -139,7 +140,7 @@ void UIPlugInAidl::startReaderManagerScans() const } -void UIPlugInAidl::onToSend(const QByteArray& pMessage) +void UIPlugInAidl::onToSend(const QByteArray& pMessage) const { #ifdef Q_OS_ANDROID const QString json = QString::fromUtf8(pMessage); diff --git a/src/ui/aidl/UIPlugInAidl.h b/src/ui/aidl/UIPlugInAidl.h index aa1598495..577c9e039 100644 --- a/src/ui/aidl/UIPlugInAidl.h +++ b/src/ui/aidl/UIPlugInAidl.h @@ -47,10 +47,10 @@ class UIPlugInAidl private Q_SLOTS: void doShutdown() override; - void onWorkflowStarted(QSharedPointer pContext) override; - void onWorkflowFinished(QSharedPointer pContext) override; + void onWorkflowStarted(const QSharedPointer& pRequest) override; + void onWorkflowFinished(const QSharedPointer& pRequest) override; - void onToSend(const QByteArray& pMessage); + void onToSend(const QByteArray& pMessage) const; }; } // namespace governikus diff --git a/src/ui/automatic/UIPlugInAutomatic.cpp b/src/ui/automatic/UIPlugInAutomatic.cpp index 4fa967e20..eaa51cac3 100644 --- a/src/ui/automatic/UIPlugInAutomatic.cpp +++ b/src/ui/automatic/UIPlugInAutomatic.cpp @@ -7,6 +7,7 @@ #include "Env.h" #include "ReaderManager.h" #include "VolatileSettings.h" +#include "WorkflowRequest.h" #include "context/AuthContext.h" #include "states/StateEnterPacePassword.h" #include "states/StateSelectReader.h" @@ -36,19 +37,20 @@ void UIPlugInAutomatic::doShutdown() } -void UIPlugInAutomatic::onWorkflowStarted(QSharedPointer pContext) +void UIPlugInAutomatic::onWorkflowStarted(const QSharedPointer& pRequest) { if (isDominated()) { return; } - pContext->claim(this); - if (pContext.objectCast()) + const auto& context = pRequest->getContext(); + context->claim(this); + if (context.objectCast()) { qCDebug(automatic) << "Fallback to full automatic UI"; - mContext = pContext; + mContext = context; mContext->setReaderPlugInTypes({ReaderManagerPlugInType::SIMULATOR, ReaderManagerPlugInType::PCSC}); connect(mContext.data(), &WorkflowContext::fireStateChanged, this, &UIPlugInAutomatic::onStateChanged); mPrevUsedAsSDK = Env::getSingleton()->isUsedAsSDK(); @@ -65,14 +67,14 @@ void UIPlugInAutomatic::onWorkflowStarted(QSharedPointer pConte else { qCWarning(automatic) << "Cannot handle context... abort automatic workflow"; - pContext->killWorkflow(); + context->killWorkflow(); } } -void UIPlugInAutomatic::onWorkflowFinished(QSharedPointer pContext) +void UIPlugInAutomatic::onWorkflowFinished(const QSharedPointer& pRequest) { - Q_UNUSED(pContext) + Q_UNUSED(pRequest) if (isDominated()) { @@ -90,11 +92,11 @@ void UIPlugInAutomatic::onStateChanged(const QString& pState) { if (mContext) { - if (AbstractState::isState(pState)) + if (StateBuilder::isState(pState)) { handleInsertCard(); } - else if (AbstractState::isState(pState)) + else if (StateBuilder::isState(pState)) { handlePassword(); } diff --git a/src/ui/automatic/UIPlugInAutomatic.h b/src/ui/automatic/UIPlugInAutomatic.h index 856f501b3..664ee992f 100644 --- a/src/ui/automatic/UIPlugInAutomatic.h +++ b/src/ui/automatic/UIPlugInAutomatic.h @@ -36,8 +36,8 @@ class UIPlugInAutomatic private Q_SLOTS: void onApplicationStarted() override; void doShutdown() override; - void onWorkflowStarted(QSharedPointer pContext) override; - void onWorkflowFinished(QSharedPointer pContext) override; + void onWorkflowStarted(const QSharedPointer& pRequest) override; + void onWorkflowFinished(const QSharedPointer& pRequest) override; void onUiDomination(const UIPlugIn* pUi, const QString& pInformation, bool pAccepted) override; void onUiDominationReleased() override; void onStateChanged(const QString& pState); diff --git a/src/ui/base/UIPlugIn.cpp b/src/ui/base/UIPlugIn.cpp index f4a37f05e..39e10ebf0 100644 --- a/src/ui/base/UIPlugIn.cpp +++ b/src/ui/base/UIPlugIn.cpp @@ -28,6 +28,12 @@ bool UIPlugIn::initialize() } +void UIPlugIn::onWorkflowUnhandled(const QSharedPointer& pRequest) +{ + Q_UNUSED(pRequest) +} + + void UIPlugIn::onHideUi() { } diff --git a/src/ui/base/UIPlugIn.h b/src/ui/base/UIPlugIn.h index de1e4518a..a83db24cf 100644 --- a/src/ui/base/UIPlugIn.h +++ b/src/ui/base/UIPlugIn.h @@ -28,9 +28,7 @@ defineEnumType(UiModule, IDENTIFY, SETTINGS, PINMANAGEMENT, - HISTORY, HELP, - PROVIDER, SELF_AUTHENTICATION, // Desktop only @@ -40,7 +38,7 @@ defineEnumType(UiModule, // Mobile only REMOTE_SERVICE, CHECK_ID_CARD, - SMART + SMART_EID ) class UIPlugIn @@ -56,8 +54,9 @@ class UIPlugIn public Q_SLOTS: virtual void doShutdown() = 0; - virtual void onWorkflowStarted(QSharedPointer pContext) = 0; - virtual void onWorkflowFinished(QSharedPointer pContext) = 0; + virtual void onWorkflowStarted(const QSharedPointer& pRequest) = 0; + virtual void onWorkflowFinished(const QSharedPointer& pRequest) = 0; + virtual void onWorkflowUnhandled(const QSharedPointer& pRequest); virtual void onApplicationInitialized(); virtual void onApplicationStarted(); virtual void onShowUi(UiModule pModule); diff --git a/src/ui/functional/UIPlugInFunctional.cpp b/src/ui/functional/UIPlugInFunctional.cpp index 3ce9dbf28..1a21f4ae3 100644 --- a/src/ui/functional/UIPlugInFunctional.cpp +++ b/src/ui/functional/UIPlugInFunctional.cpp @@ -10,6 +10,7 @@ #include "Env.h" #include "ReaderManager.h" #include "UILoader.h" +#include "WorkflowRequest.h" #include #include @@ -60,26 +61,26 @@ void UIPlugInFunctional::onApplicationStarted() } -void UIPlugInFunctional::onWorkflowStarted(QSharedPointer pContext) +void UIPlugInFunctional::onWorkflowStarted(const QSharedPointer& pRequest) { + mContext = pRequest->getContext(); + mContext->claim(this); + #if defined(Q_OS_IOS) || defined(Q_OS_ANDROID) - pContext->setReaderPlugInTypes({ReaderManagerPlugInType::NFC, ReaderManagerPlugInType::SIMULATOR}); + mContext->setReaderPlugInTypes({ReaderManagerPlugInType::NFC, ReaderManagerPlugInType::SIMULATOR}); #else - pContext->setReaderPlugInTypes({ReaderManagerPlugInType::PCSC, ReaderManagerPlugInType::SIMULATOR}); + mContext->setReaderPlugInTypes({ReaderManagerPlugInType::PCSC, ReaderManagerPlugInType::SIMULATOR}); #endif - pContext->claim(this); - mContext = pContext; - #if !defined(Q_OS_IOS) Env::getSingleton()->startScanAll(); #endif } -void UIPlugInFunctional::onWorkflowFinished(QSharedPointer pContext) +void UIPlugInFunctional::onWorkflowFinished(const QSharedPointer& pRequest) { - Q_UNUSED(pContext) + Q_UNUSED(pRequest) #if !defined(Q_OS_IOS) Env::getSingleton()->stopScanAll(); diff --git a/src/ui/functional/UIPlugInFunctional.h b/src/ui/functional/UIPlugInFunctional.h index 0f50c2431..2cccc750e 100644 --- a/src/ui/functional/UIPlugInFunctional.h +++ b/src/ui/functional/UIPlugInFunctional.h @@ -28,8 +28,8 @@ class UIPlugInFunctional private Q_SLOTS: void onApplicationStarted() override; void doShutdown() override; - void onWorkflowStarted(QSharedPointer pContext) override; - void onWorkflowFinished(QSharedPointer pContext) override; + void onWorkflowStarted(const QSharedPointer& pRequest) override; + void onWorkflowFinished(const QSharedPointer& pRequest) override; void onJsonMessage(const QByteArray& pMessage); public Q_SLOTS: diff --git a/src/ui/json/MessageDispatcher.cpp b/src/ui/json/MessageDispatcher.cpp index 45e5930f1..c65cfb7b5 100644 --- a/src/ui/json/MessageDispatcher.cpp +++ b/src/ui/json/MessageDispatcher.cpp @@ -20,7 +20,6 @@ #include "messages/MsgHandlerInternalError.h" #include "messages/MsgHandlerInvalid.h" #include "messages/MsgHandlerLog.h" -#include "messages/MsgHandlerPersonalization.h" #include "messages/MsgHandlerReader.h" #include "messages/MsgHandlerReaderList.h" #include "messages/MsgHandlerStatus.h" @@ -34,6 +33,7 @@ #if __has_include("context/PersonalizationContext.h") #include "context/PersonalizationContext.h" + #include "messages/MsgHandlerPersonalization.h" #endif #include @@ -387,18 +387,17 @@ MsgHandler MessageDispatcher::interrupt() #ifdef Q_OS_IOS { const auto allowedStates = {MsgType::ENTER_PIN, MsgType::ENTER_CAN, MsgType::ENTER_PUK, MsgType::ENTER_NEW_PIN}; - const auto& workflowContext = mContext.getContext(); - return handleCurrentState(cmdType, allowedStates, [&workflowContext] { - workflowContext->setInterruptRequested(true); - switch (workflowContext->getLastPaceResult()) + const auto lastPaceResult = mContext.getContext()->getLastPaceResult(); + return handleCurrentState(cmdType, allowedStates, [lastPaceResult] { + switch (lastPaceResult) { case CardReturnCode::OK: case CardReturnCode::OK_PUK: - Env::getSingleton()->stopScanAll(); // Null string is interpreted as 'success' + Env::getSingleton()->stopScan(ReaderManagerPlugInType::NFC); // Null string is interpreted as 'success' break; default: - Env::getSingleton()->stopScanAll(Env::getSingleton()->getMessages().getSessionFailed()); + Env::getSingleton()->stopScan(ReaderManagerPlugInType::NFC, Env::getSingleton()->getMessages().getSessionFailed()); } return MsgHandler::Void; diff --git a/src/ui/json/UIPlugInJson.cpp b/src/ui/json/UIPlugInJson.cpp index f8528ee18..a7b577094 100644 --- a/src/ui/json/UIPlugInJson.cpp +++ b/src/ui/json/UIPlugInJson.cpp @@ -5,6 +5,7 @@ #include "UIPlugInJson.h" #include "ReaderManager.h" +#include "WorkflowRequest.h" #include "context/AuthContext.h" #include "context/ChangePinContext.h" #include "messages/MsgTypes.h" @@ -69,25 +70,28 @@ void UIPlugInJson::callFireMessage(const QByteArray& pMsg, bool pLogging) } -void UIPlugInJson::onWorkflowStarted(QSharedPointer pContext) +void UIPlugInJson::onWorkflowStarted(const QSharedPointer& pRequest) { if (!mEnabled) { return; } - if (pContext.objectCast() || pContext.objectCast()) + const auto& context = pRequest->getContext(); + if (context.objectCast() || context.objectCast()) { - connect(pContext.data(), &WorkflowContext::fireStateChanged, this, &UIPlugInJson::onStateChanged); - connect(pContext.data(), &WorkflowContext::fireProgressChanged, this, &UIPlugInJson::onProgressChanged); + connect(context.data(), &WorkflowContext::fireStateChanged, this, &UIPlugInJson::onStateChanged); + connect(context.data(), &WorkflowContext::fireProgressChanged, this, &UIPlugInJson::onProgressChanged); } - callFireMessage(mMessageDispatcher.init(pContext)); + callFireMessage(mMessageDispatcher.init(context)); } -void UIPlugInJson::onWorkflowFinished(QSharedPointer) +void UIPlugInJson::onWorkflowFinished(const QSharedPointer& pRequest) { + Q_UNUSED(pRequest) + if (!mEnabled) { mMessageDispatcher.reset(); diff --git a/src/ui/json/UIPlugInJson.h b/src/ui/json/UIPlugInJson.h index 3272ce543..2c7e058f6 100644 --- a/src/ui/json/UIPlugInJson.h +++ b/src/ui/json/UIPlugInJson.h @@ -42,8 +42,8 @@ class UIPlugInJson private Q_SLOTS: void doShutdown() override; - void onWorkflowStarted(QSharedPointer pContext) override; - void onWorkflowFinished(QSharedPointer pContext) override; + void onWorkflowStarted(const QSharedPointer& pRequest) override; + void onWorkflowFinished(const QSharedPointer& pRequest) override; void onCardInfoChanged(const ReaderInfo& pInfo); void onReaderEvent(const ReaderInfo& pInfo); void onStateChanged(const QString& pNewState); diff --git a/src/ui/json/messages/MsgHandler.cpp b/src/ui/json/messages/MsgHandler.cpp index a79623cc4..0e669553c 100644 --- a/src/ui/json/messages/MsgHandler.cpp +++ b/src/ui/json/messages/MsgHandler.cpp @@ -20,7 +20,7 @@ const MsgHandler MsgHandler::Void = MsgHandler(); MsgType MsgHandler::getStateMsgType(const QString& pState, PacePasswordId pPasswordId) { - if (AbstractState::isState(pState)) + if (StateBuilder::isState(pState)) { if (pPasswordId == PacePasswordId::PACE_PIN) { @@ -35,15 +35,15 @@ MsgType MsgHandler::getStateMsgType(const QString& pState, PacePasswordId pPassw return MsgType::ENTER_PUK; } } - else if (AbstractState::isState(pState)) + else if (StateBuilder::isState(pState)) { return MsgType::ENTER_NEW_PIN; } - else if (AbstractState::isState(pState)) + else if (StateBuilder::isState(pState)) { return MsgType::ACCESS_RIGHTS; } - else if (AbstractState::isState(pState)) + else if (StateBuilder::isState(pState)) { return MsgType::INSERT_CARD; } diff --git a/src/ui/json/messages/MsgHandlerAccessRights.cpp b/src/ui/json/messages/MsgHandlerAccessRights.cpp index 26c12b41e..8e4317beb 100644 --- a/src/ui/json/messages/MsgHandlerAccessRights.cpp +++ b/src/ui/json/messages/MsgHandlerAccessRights.cpp @@ -4,8 +4,6 @@ #include "MsgHandlerAccessRights.h" -#include "JsonValueRef.h" - #include using namespace governikus; @@ -49,7 +47,7 @@ void MsgHandlerAccessRights::handleSetChatData(const QJsonArray& pChat, const QS if (!pContext->getAccessRightManager()->getOptionalAccessRights().isEmpty()) { - for (JsonValueRef entry : pChat) + for (const QJsonValueConstRef entry : pChat) { if (!entry.isString()) { @@ -93,7 +91,7 @@ QJsonArray MsgHandlerAccessRights::getAccessRights(const QSet& pRig QList accessRights = pRights.values(); std::sort(accessRights.rbegin(), accessRights.rend()); - for (auto entry : std::as_const(accessRights)) + for (const auto& entry : std::as_const(accessRights)) { const QLatin1String name = AccessRoleAndRightsUtil::toTechnicalName(entry); if (name.size()) @@ -106,6 +104,20 @@ QJsonArray MsgHandlerAccessRights::getAccessRights(const QSet& pRig } +QJsonArray MsgHandlerAccessRights::getAcceptedEidTypes(const QSharedPointer& pContext) const +{ + QJsonArray array; + + const auto& eidTypes = pContext->getAcceptedEidTypes(); + for (const auto& type : eidTypes) + { + array += Enum::getName(type); + } + + return array; +} + + void MsgHandlerAccessRights::fillAccessRights(const QSharedPointer& pContext) { Q_ASSERT(pContext); @@ -115,8 +127,12 @@ void MsgHandlerAccessRights::fillAccessRights(const QSharedPointergetRequiredAccessRights()); chat[QLatin1String("optional")] = getAccessRights(accessRightManager->getOptionalAccessRights()); chat[QLatin1String("effective")] = getAccessRights(accessRightManager->getEffectiveAccessRights()); - mJsonObject[QLatin1String("chat")] = chat; + +#if __has_include("SmartManager.h") + mJsonObject[QLatin1String("acceptedEidTypes")] = getAcceptedEidTypes(pContext); +#endif + if (const auto& transactionInfo = pContext->getDidAuthenticateEac1()->getTransactionInfo(); !transactionInfo.isEmpty()) { mJsonObject[QLatin1String("transactionInfo")] = transactionInfo; diff --git a/src/ui/json/messages/MsgHandlerAccessRights.h b/src/ui/json/messages/MsgHandlerAccessRights.h index 1b3e443b2..bdf5076db 100644 --- a/src/ui/json/messages/MsgHandlerAccessRights.h +++ b/src/ui/json/messages/MsgHandlerAccessRights.h @@ -25,6 +25,7 @@ class MsgHandlerAccessRights void handleSetChatData(const QJsonArray& pChat, const QSharedPointer& pContext); [[nodiscard]] QJsonArray getAccessRights(const QSet& pRights) const; + [[nodiscard]] QJsonArray getAcceptedEidTypes(const QSharedPointer& pContext) const; void fillAccessRights(const QSharedPointer& pContext); [[nodiscard]] QJsonObject getAuxiliaryData(const QSharedPointer& pContext) const; diff --git a/src/ui/json/messages/MsgHandlerAuth.cpp b/src/ui/json/messages/MsgHandlerAuth.cpp index 9aa5c4175..ce52cc18b 100644 --- a/src/ui/json/messages/MsgHandlerAuth.cpp +++ b/src/ui/json/messages/MsgHandlerAuth.cpp @@ -89,7 +89,7 @@ QUrl MsgHandlerAuth::createUrl(const QString& pUrl) } -void MsgHandlerAuth::initAuth(const QUrl& pTcTokenUrl) +void MsgHandlerAuth::initAuth(const QUrl& pTcTokenUrl) const { auto* ui = Env::getSingleton()->getLoaded(); Q_ASSERT(ui); diff --git a/src/ui/json/messages/MsgHandlerAuth.h b/src/ui/json/messages/MsgHandlerAuth.h index 9fbae0616..63d5b80f0 100644 --- a/src/ui/json/messages/MsgHandlerAuth.h +++ b/src/ui/json/messages/MsgHandlerAuth.h @@ -20,7 +20,7 @@ class MsgHandlerAuth { private: QUrl createUrl(const QString& pUrl); - void initAuth(const QUrl& pTcTokenUrl); + void initAuth(const QUrl& pTcTokenUrl) const; public: MsgHandlerAuth(); diff --git a/src/ui/json/messages/MsgHandlerInfo.cpp b/src/ui/json/messages/MsgHandlerInfo.cpp index be6636fff..cf1d98241 100644 --- a/src/ui/json/messages/MsgHandlerInfo.cpp +++ b/src/ui/json/messages/MsgHandlerInfo.cpp @@ -4,15 +4,28 @@ #include "MsgHandlerInfo.h" -#include "Env.h" -#include "ReaderManager.h" -#include "ReaderManagerPlugInInfo.h" +#ifdef Q_OS_ANDROID + #include "ReaderManager.h" +#endif #include "VersionInfo.h" + using namespace governikus; + MsgHandlerInfo::MsgHandlerInfo() : MsgHandler(MsgType::INFO) { mJsonObject[QLatin1String("VersionInfo")] = VersionInfo::getInstance().toJsonObject(); + + QString localIfd = QStringLiteral("UNKNOWN"); +#ifdef Q_OS_ANDROID + const auto& localIfdInfo = Env::getSingleton()->getPlugInInfo(ReaderManagerPlugInType::LOCAL_IFD); + if (localIfdInfo.hasValue(ReaderManagerPlugInInfo::Key::LOCAL_IFD_STATE)) + { + localIfd = localIfdInfo.getValue(ReaderManagerPlugInInfo::Key::LOCAL_IFD_STATE).toString(); + } +#endif + + mJsonObject[QLatin1String("AusweisApp")] = localIfd; } diff --git a/src/ui/json/messages/MsgHandlerReader.cpp b/src/ui/json/messages/MsgHandlerReader.cpp index 4dd780fe8..86138c415 100644 --- a/src/ui/json/messages/MsgHandlerReader.cpp +++ b/src/ui/json/messages/MsgHandlerReader.cpp @@ -69,6 +69,9 @@ void MsgHandlerReader::setReaderInfo(QJsonObject& pObj, const ReaderInfo& pInfo) if (pInfo.hasEid()) { QJsonObject card; +#if __has_include("SmartManager.h") + card[QLatin1String("eidType")] = Enum::getName(static_cast(pInfo.getCardInfo().getMobileEidType())); +#endif card[QLatin1String("deactivated")] = pInfo.isPinDeactivated(); card[QLatin1String("inoperative")] = pInfo.isPukInoperative(); card[QLatin1String("retryCounter")] = pInfo.getRetryCounter(); diff --git a/src/ui/json/messages/MsgHandlerWorkflows.cpp b/src/ui/json/messages/MsgHandlerWorkflows.cpp index 0a2c82420..e167b587c 100644 --- a/src/ui/json/messages/MsgHandlerWorkflows.cpp +++ b/src/ui/json/messages/MsgHandlerWorkflows.cpp @@ -18,7 +18,7 @@ void MsgHandlerWorkflows::handleWorkflowProperties(const QJsonObject& pObj, MsgC } -void MsgHandlerWorkflows::initMessages(const QJsonObject& pUi) +void MsgHandlerWorkflows::initMessages(const QJsonObject& pUi) const { if (!pUi.isEmpty()) { @@ -32,7 +32,7 @@ void MsgHandlerWorkflows::initMessages(const QJsonObject& pUi) } -void MsgHandlerWorkflows::initHandleInterrupt(const QJsonValue& pValue, const MsgContext& pContext) +void MsgHandlerWorkflows::initHandleInterrupt(const QJsonValue& pValue, const MsgContext& pContext) const { if (pContext.getApiLevel() < MsgLevel::v2) { @@ -41,7 +41,7 @@ void MsgHandlerWorkflows::initHandleInterrupt(const QJsonValue& pValue, const Ms } -void MsgHandlerWorkflows::initDeveloperMode(const QJsonValue& pValue) +void MsgHandlerWorkflows::initDeveloperMode(const QJsonValue& pValue) const { if (pValue.isBool()) { @@ -51,7 +51,7 @@ void MsgHandlerWorkflows::initDeveloperMode(const QJsonValue& pValue) } -void MsgHandlerWorkflows::initProgressStatus(const QJsonValue& pValue, MsgContext& pContext) +void MsgHandlerWorkflows::initProgressStatus(const QJsonValue& pValue, MsgContext& pContext) const { if (pValue.isBool()) { diff --git a/src/ui/json/messages/MsgHandlerWorkflows.h b/src/ui/json/messages/MsgHandlerWorkflows.h index 59def741a..c8b9dd326 100644 --- a/src/ui/json/messages/MsgHandlerWorkflows.h +++ b/src/ui/json/messages/MsgHandlerWorkflows.h @@ -20,10 +20,10 @@ class MsgHandlerWorkflows protected: void handleWorkflowProperties(const QJsonObject& pObj, MsgContext& pContext); - void initMessages(const QJsonObject& pUi); - void initDeveloperMode(const QJsonValue& pValue); - void initHandleInterrupt(const QJsonValue& pValue, const MsgContext& pContext); - void initProgressStatus(const QJsonValue& pValue, MsgContext& pContext); + void initMessages(const QJsonObject& pUi) const; + void initDeveloperMode(const QJsonValue& pValue) const; + void initHandleInterrupt(const QJsonValue& pValue, const MsgContext& pContext) const; + void initProgressStatus(const QJsonValue& pValue, MsgContext& pContext) const; void setError(const QLatin1String pError); using MsgHandler::MsgHandler; diff --git a/src/ui/local_ifd/UIPlugInLocalIfd.cpp b/src/ui/local_ifd/UIPlugInLocalIfd.cpp index a218acd4e..372c25242 100644 --- a/src/ui/local_ifd/UIPlugInLocalIfd.cpp +++ b/src/ui/local_ifd/UIPlugInLocalIfd.cpp @@ -4,15 +4,16 @@ #include "UIPlugInLocalIfd.h" -#include "AppSettings.h" #include "Env.h" #include "LocalIfdServer.h" #include "SecureStorage.h" -#include "UILoader.h" #include "context/IfdServiceContext.h" #include "controller/IfdServiceController.h" #ifdef Q_OS_ANDROID + #include "AppSettings.h" + #include "UILoader.h" + #include #include #endif @@ -32,6 +33,22 @@ void UIPlugInLocalIfd::onStateChanged(const QString& pNewState) } +void UIPlugInLocalIfd::onConnectedChanged(bool pConnected) +{ + if (!pConnected) + { + Q_EMIT fireQuitApplicationRequest(); + } +} + + +void UIPlugInLocalIfd::onSocketError(QAbstractSocket::SocketError pSocketError) +{ + Q_UNUSED(pSocketError) + Q_EMIT fireQuitApplicationRequest(EXIT_FAILURE); +} + + UIPlugInLocalIfd::UIPlugInLocalIfd() : UIPlugIn() , mContext() @@ -45,17 +62,17 @@ void UIPlugInLocalIfd::doShutdown() } -void UIPlugInLocalIfd::onWorkflowStarted(QSharedPointer pContext) +void UIPlugInLocalIfd::onWorkflowStarted(const QSharedPointer& pRequest) { - pContext->claim(this); - mContext = pContext; + mContext = pRequest->getContext(); + mContext->claim(this); connect(mContext.data(), &WorkflowContext::fireStateChanged, this, &UIPlugInLocalIfd::onStateChanged); } -void UIPlugInLocalIfd::onWorkflowFinished(QSharedPointer pContext) +void UIPlugInLocalIfd::onWorkflowFinished(const QSharedPointer& pRequest) { - Q_ASSERT(mContext == pContext); + Q_ASSERT(mContext == pRequest->getContext()); disconnect(mContext.data(), &WorkflowContext::fireStateChanged, this, &UIPlugInLocalIfd::onStateChanged); mContext.reset(); @@ -78,7 +95,9 @@ bool UIPlugInLocalIfd::onStartWorkflowRequested(const QString& pPsk) return false; } - Q_EMIT fireWorkflowRequested(WorkflowRequest::createWorkflowRequest(localIfdServer)); + connect(localIfdServer.data(), &IfdServer::fireConnectedChanged, this, &UIPlugInLocalIfd::onConnectedChanged); + connect(localIfdServer.data(), &IfdServer::fireSocketError, this, &UIPlugInLocalIfd::onSocketError); + Q_EMIT fireWorkflowRequested(WorkflowRequest::create(localIfdServer)); return localIfdServer->isRunning(); } diff --git a/src/ui/local_ifd/UIPlugInLocalIfd.h b/src/ui/local_ifd/UIPlugInLocalIfd.h index 9c7db7940..ddfd29733 100644 --- a/src/ui/local_ifd/UIPlugInLocalIfd.h +++ b/src/ui/local_ifd/UIPlugInLocalIfd.h @@ -24,13 +24,15 @@ class UIPlugInLocalIfd private Q_SLOTS: void onStateChanged(const QString& pNewState); + void onConnectedChanged(bool pConnected); + void onSocketError(QAbstractSocket::SocketError pSocketError); public: UIPlugInLocalIfd(); void doShutdown() override; - void onWorkflowStarted(QSharedPointer pContext) override; - void onWorkflowFinished(QSharedPointer pContext) override; + void onWorkflowStarted(const QSharedPointer& pRequest) override; + void onWorkflowFinished(const QSharedPointer& pRequest) override; public Q_SLOTS: bool onStartWorkflowRequested(const QString& pPsk); diff --git a/src/ui/proxy/PortWrapper.h b/src/ui/proxy/PortWrapper.h index ab4f9bc39..f476258f8 100644 --- a/src/ui/proxy/PortWrapper.h +++ b/src/ui/proxy/PortWrapper.h @@ -30,10 +30,10 @@ class PortWrapper #ifdef Q_OS_WIN static QString getUserOfProcessID(DWORD pPid); static QString getExecutableOfProcessID(DWORD pPid); - static quint16 getPortOfRunningProcess(const QVector& pConnections, const QString& pUser, int pSelfPort, const in_addr& pRemoteAddr); - static QString getUserOfConnection(const QVector& pConnections, int pLocalPort, int pRemotePort, const in_addr& pProxyAddr); + static quint16 getPortOfRunningProcess(const QVector& pConnections, const QString& pUser, quint16 pSelfPort, const in_addr& pRemoteAddr); + static QString getUserOfConnection(const QVector& pConnections, quint16 pLocalPort, quint16 pRemotePort, const in_addr& pProxyAddr); static QVector getConnections(); - static quint16 getProcessPort(int pLocalPort, int pRemotePort); + static quint16 getProcessPort(quint16 pLocalPort, quint16 pRemotePort); #else static quint16 readPortFile(const QString& pFile); #endif diff --git a/src/ui/proxy/PortWrapper_win.cpp b/src/ui/proxy/PortWrapper_win.cpp index 15959cb7b..8376285ad 100644 --- a/src/ui/proxy/PortWrapper_win.cpp +++ b/src/ui/proxy/PortWrapper_win.cpp @@ -147,7 +147,7 @@ QString PortWrapper::getExecutableOfProcessID(DWORD pPid) } -quint16 PortWrapper::getPortOfRunningProcess(const QVector& pConnections, const QString& pUser, int pSelfPort, const in_addr& pProxyAddr) +quint16 PortWrapper::getPortOfRunningProcess(const QVector& pConnections, const QString& pUser, quint16 pSelfPort, const in_addr& pProxyAddr) { for (const auto& connection : pConnections) { @@ -162,7 +162,7 @@ quint16 PortWrapper::getPortOfRunningProcess(const QVector continue; } - if (ntohs(connection.dwLocalPort) == pSelfPort) + if (ntohs(static_cast(connection.dwLocalPort)) == pSelfPort) { continue; } @@ -173,14 +173,14 @@ quint16 PortWrapper::getPortOfRunningProcess(const QVector continue; } - return ntohs(connection.dwLocalPort); + return ntohs(static_cast(connection.dwLocalPort)); } return 0; } -QString PortWrapper::getUserOfConnection(const QVector& pConnections, int pLocalPort, int pRemotePort, const in_addr& pRemoteAddr) +QString PortWrapper::getUserOfConnection(const QVector& pConnections, quint16 pLocalPort, quint16 pRemotePort, const in_addr& pRemoteAddr) { for (const auto& connection : pConnections) { @@ -191,8 +191,8 @@ QString PortWrapper::getUserOfConnection(const QVector& pC continue; } - if (ntohs(connection.dwLocalPort) == pRemotePort - && ntohs(connection.dwRemotePort) == pLocalPort) + if (ntohs(static_cast(connection.dwLocalPort)) == pRemotePort + && ntohs(static_cast(connection.dwRemotePort)) == pLocalPort) { return getUserOfProcessID(connection.dwOwningPid); } @@ -234,9 +234,13 @@ QVector PortWrapper::getConnections() } -quint16 PortWrapper::getProcessPort(int pLocalPort, int pRemotePort) +quint16 PortWrapper::getProcessPort(quint16 pLocalPort, quint16 pRemotePort) { - struct in_addr localhost = {127, 0, 0, 1}; + struct in_addr localhost = { + { + {127, 0, 0, 1} + } + }; const auto& connections = getConnections(); const auto& user = getUserOfConnection(connections, pLocalPort, pRemotePort, localhost); if (user.isEmpty()) diff --git a/src/ui/proxy/RedirectRequest.cpp b/src/ui/proxy/RedirectRequest.cpp index 61543b742..9245f9bb3 100644 --- a/src/ui/proxy/RedirectRequest.cpp +++ b/src/ui/proxy/RedirectRequest.cpp @@ -7,6 +7,7 @@ #include "LanguageLoader.h" #include "Template.h" +#include #include #include @@ -84,12 +85,12 @@ RedirectRequest::~RedirectRequest() { Template htmlTemplate = Template::fromFile(QStringLiteral(":/template.html")); //: ERROR ALL_PLATFORMS The local AusweisApp (access via reverse proxy) is not reachable, part of an HTML error page. - htmlTemplate.setContextParameter(QStringLiteral("TITLE"), tr("Cannot reach local AusweisApp2")); + htmlTemplate.setContextParameter(QStringLiteral("TITLE"), tr("Cannot reach local %1").arg(QCoreApplication::applicationName())); htmlTemplate.setContextParameter(QStringLiteral("APPLICATION_LINK"), QStringLiteral("https://www.ausweisapp.bund.de/%1").arg(LanguageLoader::getLocaleCode())); //: ERROR ALL_PLATFORMS The local AusweisApp (access via reverse proxy) is not reachable, part of an HTML error page. - htmlTemplate.setContextParameter(QStringLiteral("MESSAGE_HEADER"), tr("Cannot reach local AusweisApp2")); + htmlTemplate.setContextParameter(QStringLiteral("MESSAGE_HEADER"), tr("Cannot reach local %1").arg(QCoreApplication::applicationName())); //: ERROR ALL_PLATFORMS The local AusweisApp (access via reverse proxy) is not reachable, part of an HTML error page. - htmlTemplate.setContextParameter(QStringLiteral("MESSAGE_HEADER_EXPLANATION"), tr("Your local AusweisApp2 is not running. Please start your local AusweisApp2 and try again.")); + htmlTemplate.setContextParameter(QStringLiteral("MESSAGE_HEADER_EXPLANATION"), tr("Your local %1 is not running. Please start your local %1 and try again.").arg(QCoreApplication::applicationName())); //: ERROR ALL_PLATFORMS The local AusweisApp (access via reverse proxy) is not reachable, part of an HTML error page. htmlTemplate.setContextParameter(QStringLiteral("CONTENT_HEADER"), tr("Would you like to try again?")); htmlTemplate.setContextParameter(QStringLiteral("CONTENT_LINK"), mRequest->getUrl().toString()); diff --git a/src/ui/proxy/UIPlugInProxy.cpp b/src/ui/proxy/UIPlugInProxy.cpp index 6617a4676..801a144ec 100644 --- a/src/ui/proxy/UIPlugInProxy.cpp +++ b/src/ui/proxy/UIPlugInProxy.cpp @@ -17,6 +17,7 @@ Q_DECLARE_LOGGING_CATEGORY(rproxy) UIPlugInProxy::UIPlugInProxy() : UIPlugIn() + , HttpHandler() , mServer() { } @@ -90,18 +91,23 @@ void UIPlugInProxy::onUiDominationReleased() } -void UIPlugInProxy::onWorkflowStarted(QSharedPointer pContext) +void UIPlugInProxy::onWorkflowStarted(const QSharedPointer& pRequest) { - Q_UNUSED(pContext) + Q_UNUSED(pRequest) } -void UIPlugInProxy::onWorkflowFinished(QSharedPointer pContext) +void UIPlugInProxy::onWorkflowFinished(const QSharedPointer& pRequest) { - Q_UNUSED(pContext) + Q_UNUSED(pRequest) } void UIPlugInProxy::doShutdown() { + if (mServer) + { + mServer->disconnect(this); + mServer.reset(); + } } diff --git a/src/ui/proxy/UIPlugInProxy.h b/src/ui/proxy/UIPlugInProxy.h index b429506e0..3a1fccb3f 100644 --- a/src/ui/proxy/UIPlugInProxy.h +++ b/src/ui/proxy/UIPlugInProxy.h @@ -36,8 +36,8 @@ class UIPlugInProxy private Q_SLOTS: void doShutdown() override; - void onWorkflowStarted(QSharedPointer pContext) override; - void onWorkflowFinished(QSharedPointer pContext) override; + void onWorkflowStarted(const QSharedPointer& pRequest) override; + void onWorkflowFinished(const QSharedPointer& pRequest) override; void onUiDomination(const UIPlugIn* pUi, const QString& pInformation, bool pAccepted) override; void onUiDominationReleased() override; void onNewRequest(const QSharedPointer& pRequest); diff --git a/src/ui/qml/AppUpdateDataModel.cpp b/src/ui/qml/AppUpdateDataModel.cpp index 4df1b8733..49647e8d6 100644 --- a/src/ui/qml/AppUpdateDataModel.cpp +++ b/src/ui/qml/AppUpdateDataModel.cpp @@ -2,10 +2,9 @@ * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -#include "AppUpdateDataModel.h" +#include "AppUpdateDataModel.h" #include "AppUpdater.h" -#include "Env.h" #include #include diff --git a/src/ui/qml/AppUpdateDataModel.h b/src/ui/qml/AppUpdateDataModel.h index 6c1a9522d..8024b3844 100644 --- a/src/ui/qml/AppUpdateDataModel.h +++ b/src/ui/qml/AppUpdateDataModel.h @@ -4,10 +4,10 @@ #pragma once -#include "AppUpdateData.h" #include "Env.h" #include "GlobalStatus.h" +#include #include diff --git a/src/ui/qml/ApplicationModel.cpp b/src/ui/qml/ApplicationModel.cpp index 88eb64b24..6e8070c18 100644 --- a/src/ui/qml/ApplicationModel.cpp +++ b/src/ui/qml/ApplicationModel.cpp @@ -11,7 +11,6 @@ #include "BuildHelper.h" #include "Env.h" -#include "HelpAction.h" #include "LanguageLoader.h" #include "Randomizer.h" #include "ReaderFilter.h" @@ -54,7 +53,6 @@ void ApplicationModel::onStatusChanged(const ReaderManagerPlugInInfo& pInfo) ApplicationModel::ApplicationModel() : mContext() - , mScaleFactor(DEFAULT_SCALE_FACTOR) , mWifiInfo() , mWifiEnabled(false) , mFeedback() @@ -156,7 +154,7 @@ ApplicationModel::QmlNfcState ApplicationModel::getNfcState() const return QmlNfcState::NFC_DISABLED; } - if (!Env::getSingleton()->isScanRunning(type)) + if (!pluginInfo.isScanRunning()) { return QmlNfcState::NFC_INACTIVE; } @@ -189,24 +187,6 @@ bool ApplicationModel::isWifiEnabled() const } -qreal ApplicationModel::getScaleFactor() const -{ - return mScaleFactor; -} - - -void ApplicationModel::setScaleFactor(qreal pScaleFactor) -{ - pScaleFactor *= DEFAULT_SCALE_FACTOR; - - if (qAbs(pScaleFactor - mScaleFactor) > 0) - { - mScaleFactor = pScaleFactor; - Q_EMIT fireScaleFactorChanged(); - } -} - - ApplicationModel::Workflow ApplicationModel::getCurrentWorkflow() const { if (mContext.objectCast()) @@ -235,7 +215,7 @@ ApplicationModel::Workflow ApplicationModel::getCurrentWorkflow() const } -int ApplicationModel::getAvailableReader() const +qsizetype ApplicationModel::getAvailableReader() const { if (!mContext) { @@ -309,13 +289,18 @@ void ApplicationModel::showFeedback(const QString& pMessage, bool pReplaceExisti qCInfo(feedback).noquote() << pMessage; #if defined(Q_OS_ANDROID) - Q_UNUSED(pReplaceExisting) - QNativeInterface::QAndroidApplication::runOnAndroidMainThread([pMessage](){ + QNativeInterface::QAndroidApplication::runOnAndroidMainThread([pMessage, pReplaceExisting](){ QJniEnvironment env; + static thread_local QJniObject toast; + + if (toast.isValid() && pReplaceExisting) + { + toast.callMethod("cancel"); + } QJniObject context = QNativeInterface::QAndroidApplication::context(); const QJniObject& jMessage = QJniObject::fromString(pMessage); - const QJniObject& toast = QJniObject::callStaticObjectMethod( + toast = QJniObject::callStaticObjectMethod( "android/widget/Toast", "makeText", "(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;", @@ -356,7 +341,7 @@ void ApplicationModel::showFeedback(const QString& pMessage, bool pReplaceExisti #ifndef Q_OS_IOS -void ApplicationModel::keepScreenOn(bool pActive) +void ApplicationModel::keepScreenOn(bool pActive) const { #if defined(Q_OS_ANDROID) QNativeInterface::QAndroidApplication::runOnAndroidMainThread([pActive](){ @@ -392,9 +377,6 @@ QStringList ApplicationModel::getLicenseText() const } QTextStream in(&licenseFile); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - in.setCodec("UTF-8"); -#endif while (!in.atEnd()) { lines << in.readLine(); @@ -406,19 +388,7 @@ QStringList ApplicationModel::getLicenseText() const #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) -QString ApplicationModel::onlineHelpUrl(const QString& pHelpSectionName) -{ - return HelpAction::getOnlineUrl(pHelpSectionName); -} - - -void ApplicationModel::openOnlineHelp(const QString& pHelpSectionName) -{ - HelpAction::openContextHelp(pHelpSectionName); -} - - -QUrl ApplicationModel::getCustomConfigPath() +QUrl ApplicationModel::getCustomConfigPath() const { QFileInfo info(Env::getSingleton()->getCustomConfig()); QUrl url(info.absolutePath()); @@ -427,7 +397,7 @@ QUrl ApplicationModel::getCustomConfigPath() } -void ApplicationModel::saveEmbeddedConfig(const QUrl& pFilename) +void ApplicationModel::saveEmbeddedConfig(const QUrl& pFilename) const { bool success = true; if (QFile::exists(pFilename.toLocalFile())) @@ -470,7 +440,7 @@ void ApplicationModel::onTranslationChanged() } -void ApplicationModel::enableWifi() +void ApplicationModel::enableWifi() const { #ifdef Q_OS_ANDROID showSettings(Settings::SETTING_WIFI); diff --git a/src/ui/qml/ApplicationModel.h b/src/ui/qml/ApplicationModel.h index d028710f2..edc496fcc 100644 --- a/src/ui/qml/ApplicationModel.h +++ b/src/ui/qml/ApplicationModel.h @@ -23,6 +23,9 @@ Q_FORWARD_DECLARE_OBJC_CLASS(VoiceOverObserver); #endif +class test_UIPlugInQml; + + namespace governikus { @@ -31,6 +34,7 @@ class ApplicationModel { Q_OBJECT friend class Env; + friend class ::test_UIPlugInQml; Q_PROPERTY(QString storeUrl READ getStoreUrl NOTIFY fireStoreUrlChanged) Q_PROPERTY(QUrl releaseNotesUrl READ getReleaseNotesUrl CONSTANT) @@ -38,11 +42,10 @@ class ApplicationModel Q_PROPERTY(QmlNfcState nfcState READ getNfcState NOTIFY fireNfcStateChanged) Q_PROPERTY(bool extendedLengthApdusUnsupported READ isExtendedLengthApdusUnsupported NOTIFY fireReaderPropertiesUpdated) - Q_PROPERTY(qreal scaleFactor READ getScaleFactor WRITE setScaleFactor NOTIFY fireScaleFactorChanged) Q_PROPERTY(bool wifiEnabled READ isWifiEnabled NOTIFY fireWifiEnabledChanged) Q_PROPERTY(Workflow currentWorkflow READ getCurrentWorkflow NOTIFY fireCurrentWorkflowChanged) - Q_PROPERTY(int availableReader READ getAvailableReader NOTIFY fireAvailableReaderChanged) + Q_PROPERTY(qsizetype availableReader READ getAvailableReader NOTIFY fireAvailableReaderChanged) Q_PROPERTY(QString feedback READ getFeedback NOTIFY fireFeedbackChanged) @@ -52,8 +55,6 @@ class ApplicationModel private: QSharedPointer mContext; - constexpr static qreal DEFAULT_SCALE_FACTOR = 0.6; - qreal mScaleFactor; WifiInfo mWifiInfo; bool mWifiEnabled; QStringList mFeedback; @@ -122,11 +123,8 @@ class ApplicationModel [[nodiscard]] bool isExtendedLengthApdusUnsupported() const; [[nodiscard]] bool isWifiEnabled() const; - [[nodiscard]] qreal getScaleFactor() const; - void setScaleFactor(qreal pScaleFactor); - [[nodiscard]] Workflow getCurrentWorkflow() const; - [[nodiscard]] int getAvailableReader() const; + [[nodiscard]] qsizetype getAvailableReader() const; [[nodiscard]] QString getFeedback() const; @@ -134,18 +132,17 @@ class ApplicationModel [[nodiscard]] Q_INVOKABLE bool isReaderTypeAvailable(ReaderManagerPlugInType pPlugInType) const; - Q_INVOKABLE void enableWifi(); + Q_INVOKABLE void enableWifi()const; Q_INVOKABLE void setClipboardText(const QString& pText) const; - Q_INVOKABLE void showSettings(const Settings& pAction); + Q_INVOKABLE void showSettings(const Settings& pAction) const; Q_INVOKABLE void showFeedback(const QString& pMessage, bool pReplaceExisting = false); - Q_INVOKABLE void keepScreenOn(bool pActive); + Q_INVOKABLE void keepScreenOn(bool pActive) const; + [[nodiscard]] Q_INVOKABLE QStringList getLicenseText() const; #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) - [[nodiscard]] Q_INVOKABLE QString onlineHelpUrl(const QString& pHelpSectionName); - Q_INVOKABLE void openOnlineHelp(const QString& pHelpSectionName); - [[nodiscard]] Q_INVOKABLE QUrl getCustomConfigPath(); - Q_INVOKABLE void saveEmbeddedConfig(const QUrl& pFilename); + [[nodiscard]] Q_INVOKABLE QUrl getCustomConfigPath() const; + Q_INVOKABLE void saveEmbeddedConfig(const QUrl& pFilename) const; #endif [[nodiscard]] Q_INVOKABLE QString stripHtmlTags(QString pString) const; #ifdef Q_OS_IOS @@ -164,7 +161,6 @@ class ApplicationModel void fireCurrentWorkflowChanged(); void fireAvailableReaderChanged(); - void fireScaleFactorChanged(); void fireWifiEnabledChanged(); void fireFeedbackChanged(); diff --git a/src/ui/qml/ApplicationModel_android.cpp b/src/ui/qml/ApplicationModel_android.cpp index 3735ef24e..653d95c75 100644 --- a/src/ui/qml/ApplicationModel_android.cpp +++ b/src/ui/qml/ApplicationModel_android.cpp @@ -37,7 +37,7 @@ static void showSystemSettings(const QString& pAction) } -void ApplicationModel::showSettings(const ApplicationModel::Settings& pAction) +void ApplicationModel::showSettings(const ApplicationModel::Settings& pAction) const { const auto& androidQ = QOperatingSystemVersion(QOperatingSystemVersion::Android, 10); diff --git a/src/ui/qml/ApplicationModel_generic.cpp b/src/ui/qml/ApplicationModel_generic.cpp index 7046da8fa..ee86e5cc6 100644 --- a/src/ui/qml/ApplicationModel_generic.cpp +++ b/src/ui/qml/ApplicationModel_generic.cpp @@ -8,7 +8,7 @@ using namespace governikus; Q_DECLARE_LOGGING_CATEGORY(qml) -void ApplicationModel::showSettings(const ApplicationModel::Settings& pAction) +void ApplicationModel::showSettings(const ApplicationModel::Settings& pAction) const { qCWarning(qml) << "NOT IMPLEMENTED:" << pAction; } diff --git a/src/ui/qml/ApplicationModel_ios.mm b/src/ui/qml/ApplicationModel_ios.mm index 939e52727..fc8a8d2f1 100644 --- a/src/ui/qml/ApplicationModel_ios.mm +++ b/src/ui/qml/ApplicationModel_ios.mm @@ -73,7 +73,7 @@ - (void)receiveNotification:(NSNotification*)notification { } -void ApplicationModel::keepScreenOn(bool pActive) +void ApplicationModel::keepScreenOn(bool pActive) const { if (pActive) { @@ -89,11 +89,14 @@ - (void)receiveNotification:(NSNotification*)notification { void ApplicationModel::showAppStoreRatingDialog() { qCDebug(feedback) << "Requesting iOS AppStore review"; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" [SKStoreReviewController requestReview]; +#pragma clang diagnostic pop } -void ApplicationModel::showSettings(const ApplicationModel::Settings& pAction) +void ApplicationModel::showSettings(const ApplicationModel::Settings& pAction) const { if (pAction == Settings::SETTING_APP) { diff --git a/src/ui/qml/AuthModel.h b/src/ui/qml/AuthModel.h index 881ea4b98..be428b23e 100644 --- a/src/ui/qml/AuthModel.h +++ b/src/ui/qml/AuthModel.h @@ -17,6 +17,10 @@ #include #include + +class test_UIPlugInQml; + + namespace governikus { @@ -25,6 +29,7 @@ class AuthModel { Q_OBJECT friend class Env; + friend class ::test_UIPlugInQml; Q_PROPERTY(QString transactionInfo READ getTransactionInfo NOTIFY fireTransactionInfoChanged) Q_PROPERTY(int progressValue READ getProgressValue NOTIFY fireProgressChanged) diff --git a/src/ui/qml/CMakeLists.txt b/src/ui/qml/CMakeLists.txt index cb32f4441..405130625 100644 --- a/src/ui/qml/CMakeLists.txt +++ b/src/ui/qml/CMakeLists.txt @@ -5,11 +5,9 @@ ADD_PLATFORM_LIBRARY(AusweisAppUiQml) target_link_libraries(AusweisAppUiQml ${Qt}::Core ${Qt}::Svg ${Qt}::Qml ${Qt}::Quick ${Qt}::QuickControls2) -target_link_libraries(AusweisAppUiQml AusweisAppGlobal AusweisAppUi AusweisAppIfdRemote AusweisAppExport AusweisAppServices AusweisAppWorkflowsSelfAuth) +target_link_libraries(AusweisAppUiQml AusweisAppGlobal AusweisAppUi AusweisAppIfdRemote AusweisAppServices AusweisAppWorkflowsSelfAuth) -if(QT6) - target_link_libraries(AusweisAppUiQml ${Qt}::CorePrivate) -endif() +target_link_libraries(AusweisAppUiQml ${Qt}::CorePrivate) if(TARGET ${Qt}::Widgets) target_link_libraries(AusweisAppUiQml ${Qt}::Widgets) # QSystemTrayIcon @@ -19,10 +17,6 @@ if(TARGET ${Qt}::QmlWorkerScript) target_link_libraries(AusweisAppUiQml ${Qt}::QmlWorkerScript) endif() -if(NOT DESKTOP AND NOT QT6) - target_link_libraries(AusweisAppUiQml ${Qt}::QuickShapes) -endif() - if(TARGET AusweisAppDiagnosis) target_link_libraries(AusweisAppUiQml AusweisAppDiagnosis) endif() diff --git a/src/ui/qml/CardPositionModel.cpp b/src/ui/qml/CardPositionModel.cpp index a5ec26c9f..65c15f2f2 100644 --- a/src/ui/qml/CardPositionModel.cpp +++ b/src/ui/qml/CardPositionModel.cpp @@ -95,7 +95,7 @@ void CardPositionModel::setIsRunning(bool pRunning) int CardPositionModel::getCardPositionCount() const { - return mCardPositions.count(); + return static_cast(mCardPositions.count()); } diff --git a/src/ui/qml/CardPositionModel.h b/src/ui/qml/CardPositionModel.h index 92b1ecec0..1303884b6 100644 --- a/src/ui/qml/CardPositionModel.h +++ b/src/ui/qml/CardPositionModel.h @@ -31,7 +31,7 @@ class CardPositionModel private: int mCyclingClock; - int mCurrentIndex; + qsizetype mCurrentIndex; QTimer mCyclingTimer; const QVector mCardPositions; diff --git a/src/ui/qml/CertificateDescriptionModel.cpp b/src/ui/qml/CertificateDescriptionModel.cpp index adecdd9a5..fb3747de1 100644 --- a/src/ui/qml/CertificateDescriptionModel.cpp +++ b/src/ui/qml/CertificateDescriptionModel.cpp @@ -147,7 +147,7 @@ QString CertificateDescriptionModel::getValidity() const int CertificateDescriptionModel::rowCount(const QModelIndex&) const { - return mData.size(); + return static_cast(mData.size()); } diff --git a/src/ui/qml/CertificateDescriptionModel.h b/src/ui/qml/CertificateDescriptionModel.h index 00735db83..cb631f11a 100644 --- a/src/ui/qml/CertificateDescriptionModel.h +++ b/src/ui/qml/CertificateDescriptionModel.h @@ -18,6 +18,10 @@ #include #include + +class test_UIPlugInQml; + + namespace governikus { @@ -26,6 +30,7 @@ class CertificateDescriptionModel { Q_OBJECT friend class Env; + friend class ::test_UIPlugInQml; Q_PROPERTY(QString subjectName READ getSubjectName NOTIFY fireChanged) Q_PROPERTY(QString purpose READ getPurpose NOTIFY fireChanged) diff --git a/src/ui/qml/ChangePinModel.cpp b/src/ui/qml/ChangePinModel.cpp index 50b0f57e4..1380528b5 100644 --- a/src/ui/qml/ChangePinModel.cpp +++ b/src/ui/qml/ChangePinModel.cpp @@ -4,7 +4,6 @@ #include "ChangePinModel.h" -#include "ReaderManager.h" #include "controller/ChangePinController.h" using namespace governikus; @@ -20,16 +19,15 @@ void ChangePinModel::resetChangePinContext(const QSharedPointer ChangePinModel::getSupportedReaderPlugInTypes() } +bool ChangePinModel::isRequestTransportPin() const +{ + if (!mContext) + { + return false; + } + return mContext->isRequestTransportPin(); +} + + void ChangePinModel::onPaceResultUpdated() { if (mContext->getLastPaceResult() == CardReturnCode::OK_PUK) diff --git a/src/ui/qml/ChangePinModel.h b/src/ui/qml/ChangePinModel.h index 92782e0c7..439d105fa 100644 --- a/src/ui/qml/ChangePinModel.h +++ b/src/ui/qml/ChangePinModel.h @@ -18,6 +18,10 @@ #include #include + +class test_UIPlugInQml; + + namespace governikus { @@ -26,6 +30,8 @@ class ChangePinModel { Q_OBJECT friend class Env; + friend class ::test_UIPlugInQml; + Q_PROPERTY(bool requestTransportPin READ isRequestTransportPin NOTIFY fireWorkflowStarted) private: QSharedPointer mContext; @@ -35,16 +41,16 @@ class ChangePinModel public: void resetChangePinContext(const QSharedPointer& pContext = QSharedPointer()); - Q_INVOKABLE void startWorkflow(bool pRequestTransportPin); + Q_INVOKABLE void startWorkflow(bool pRequestTransportPin, bool pActivateUi = true); [[nodiscard]] QString getResultString() const override; [[nodiscard]] QVector getSupportedReaderPlugInTypes() const override; + [[nodiscard]] bool isRequestTransportPin() const; private Q_SLOTS: void onPaceResultUpdated(); Q_SIGNALS: void fireStartWorkflow(const QSharedPointer& pRequest); - void fireNewContextSet(); void fireOnPinUnlocked(); }; diff --git a/src/ui/qml/ChatModel.cpp b/src/ui/qml/ChatModel.cpp index dfc78a623..5317d5783 100644 --- a/src/ui/qml/ChatModel.cpp +++ b/src/ui/qml/ChatModel.cpp @@ -10,10 +10,8 @@ #include "AppSettings.h" #include "asn1/AccessRoleAndRight.h" -#include "asn1/CVCertificate.h" #include "context/AuthContext.h" #include "context/IfdServiceContext.h" -#include "context/SelfAuthContext.h" using namespace governikus; @@ -43,7 +41,7 @@ ChatModel::ChatModel() } -void ChatModel::initFilterModel(QSortFilterProxyModel& pModel, QAbstractItemModel* pSourceModel, int pFilterRole, const QString& pFilter) +void ChatModel::initFilterModel(QSortFilterProxyModel& pModel, QAbstractItemModel* pSourceModel, int pFilterRole, const QString& pFilter) const { pModel.setSourceModel(pSourceModel); pModel.setFilterRole(pFilterRole); @@ -113,7 +111,7 @@ void ChatModel::setOrderedAllRights(const QSet& pAllRights) int ChatModel::rowCount(const QModelIndex&) const { - return mAllRights.size(); + return static_cast(mAllRights.size()); } @@ -198,7 +196,7 @@ bool ChatModel::setData(const QModelIndex& pIndex, const QVariant& pValue, int p } -void ChatModel::transferAccessRights() +void ChatModel::transferAccessRights() const { if (auto authContext = mContext.objectCast()) { diff --git a/src/ui/qml/ChatModel.h b/src/ui/qml/ChatModel.h index f50db1001..d84351167 100644 --- a/src/ui/qml/ChatModel.h +++ b/src/ui/qml/ChatModel.h @@ -18,7 +18,10 @@ #include "context/AccessRightManager.h" #include "context/WorkflowContext.h" + class test_ChatModel; +class test_UIPlugInQml; + namespace governikus { @@ -31,6 +34,7 @@ class ChatModel Q_OBJECT friend class Env; friend class ::test_ChatModel; + friend class ::test_UIPlugInQml; Q_PROPERTY(QSortFilterProxyModel * optional READ getFilterOptionalModel CONSTANT) Q_PROPERTY(QSortFilterProxyModel * required READ getFilterRequiredModel CONSTANT) @@ -57,7 +61,7 @@ class ChatModel ChatModel(); ~ChatModel() override = default; - void initFilterModel(QSortFilterProxyModel& pModel, QAbstractItemModel* pSourceModel, int pFilterRole, const QString& pFilter); + void initFilterModel(QSortFilterProxyModel& pModel, QAbstractItemModel* pSourceModel, int pFilterRole, const QString& pFilter) const; void setOrderedAllRights(const QSet& pAllRights); private Q_SLOTS: @@ -71,7 +75,7 @@ class ChatModel [[nodiscard]] bool setData(const QModelIndex& pIndex, const QVariant& pValue, int pRole) override; [[nodiscard]] QHash roleNames() const override; - Q_INVOKABLE void transferAccessRights(); + Q_INVOKABLE void transferAccessRights() const; [[nodiscard]] Q_INVOKABLE QSortFilterProxyModel* getFilterOptionalModel(); [[nodiscard]] Q_INVOKABLE QSortFilterProxyModel* getFilterRequiredModel(); [[nodiscard]] Q_INVOKABLE QSortFilterProxyModel* getFilterWriteModel(); diff --git a/src/ui/qml/CheckIDCardModel.cpp b/src/ui/qml/CheckIDCardModel.cpp index 9fdd6edec..21545da95 100644 --- a/src/ui/qml/CheckIDCardModel.cpp +++ b/src/ui/qml/CheckIDCardModel.cpp @@ -134,8 +134,6 @@ void CheckIDCardModel::startScan() connect(readerManager, &ReaderManager::fireReaderPropertiesUpdated, this, &CheckIDCardModel::onReaderPropertiesUpdated); startScanIfNecessary(); - - Q_EMIT fireIsRunningChanged(); } @@ -148,7 +146,7 @@ void CheckIDCardModel::startScanIfNecessary() const auto readerManager = Env::getSingleton(); - if (readerManager->isScanRunning(ReaderManagerPlugInType::NFC)) + if (readerManager->getPlugInInfo(ReaderManagerPlugInType::NFC).isScanRunning()) { return; } @@ -192,7 +190,6 @@ void CheckIDCardModel::stopScan() mIsRunning = false; mReaderWithCard.clear(); - Q_EMIT fireIsRunningChanged(); } diff --git a/src/ui/qml/CheckIDCardModel.h b/src/ui/qml/CheckIDCardModel.h index ff592c57e..e3f6b9196 100644 --- a/src/ui/qml/CheckIDCardModel.h +++ b/src/ui/qml/CheckIDCardModel.h @@ -64,7 +64,6 @@ class CheckIDCardModel void stopScanWithResult(CheckIDCardResult result); Q_SIGNALS: - void fireIsRunningChanged(); void fireResultChanged(); void fireScanCompleted(); }; diff --git a/src/ui/qml/ConnectivityManager.cpp b/src/ui/qml/ConnectivityManager.cpp index 3837f5ebc..9018ff1b2 100644 --- a/src/ui/qml/ConnectivityManager.cpp +++ b/src/ui/qml/ConnectivityManager.cpp @@ -8,11 +8,40 @@ #include #include + using namespace governikus; + Q_DECLARE_LOGGING_CATEGORY(network) +void ConnectivityManager::setActive(bool pActive) +{ + if (mActive != pActive) + { + if (pActive) + { + qCDebug(network) << "A network interface is now available"; + } + else + { + qCDebug(network) << "An active network interface is no longer available"; + } + mActive = pActive; + Q_EMIT fireNetworkInterfaceActiveChanged(mActive); + } +} + + +void ConnectivityManager::timerEvent(QTimerEvent* pTimerEvent) +{ + if (pTimerEvent->timerId() == mTimerId) + { + setActive(checkConnectivity()); + } +} + + ConnectivityManager::ConnectivityManager() : QObject() , mTimerId(0) @@ -23,32 +52,41 @@ ConnectivityManager::ConnectivityManager() ConnectivityManager::~ConnectivityManager() { - if (mTimerId != 0) + if (isWatching()) { killTimer(mTimerId); } } -void ConnectivityManager::setActive(bool pActive, const QString& pInterfaceName) +bool ConnectivityManager::isWatching() const { - if (mActive != pActive) + return mTimerId != 0; +} + + +void ConnectivityManager::setWatching(bool pWatching) +{ + if (pWatching == isWatching()) { - if (pActive) - { - qCDebug(network) << "Found active network interface" << pInterfaceName; - } - else - { - qCDebug(network) << "Found no active network interface"; - } - mActive = pActive; - Q_EMIT fireNetworkInterfaceActiveChanged(mActive); + return; } + + if (pWatching) + { + mTimerId = startTimer(1000); + Q_EMIT fireWatchingChanged(); + setActive(checkConnectivity()); + return; + } + + killTimer(mTimerId); + mTimerId = 0; + Q_EMIT fireWatchingChanged(); } -void ConnectivityManager::updateConnectivity() +bool ConnectivityManager::checkConnectivity() { const auto& allInterfaces = QNetworkInterface::allInterfaces(); for (const auto& iface : allInterfaces) @@ -79,19 +117,28 @@ void ConnectivityManager::updateConnectivity() continue; } - setActive(true, iface.name()); - return; + if (!mActive) + { + qCDebug(network) << "Found active network interface" << iface.name(); + } + return true; } - setActive(false); -} - -void ConnectivityManager::timerEvent(QTimerEvent* pTimerEvent) -{ - if (pTimerEvent->timerId() == mTimerId) + // QNetworkInterface has no operator== so we use allAddresses() + // to check if something changed. We don't want to log + // all interfaces for every check here. + const auto& addresses = QNetworkInterface::allAddresses(); + if (mAllAddresses != addresses) { - updateConnectivity(); + mAllAddresses = addresses; + qCDebug(network) << "No active network interface found"; + for (const auto& interface : allInterfaces) + { + qCDebug(network) << interface; + } } + + return false; } @@ -99,27 +146,3 @@ bool ConnectivityManager::isNetworkInterfaceActive() const { return mActive; } - - -void ConnectivityManager::startWatching() -{ - if (mTimerId != 0) - { - qCWarning(network) << "Already started, skip"; - return; - } - mTimerId = startTimer(1000); - updateConnectivity(); -} - - -void ConnectivityManager::stopWatching() -{ - if (mTimerId == 0) - { - qCWarning(network) << "Already stopped, skip"; - return; - } - killTimer(mTimerId); - mTimerId = 0; -} diff --git a/src/ui/qml/ConnectivityManager.h b/src/ui/qml/ConnectivityManager.h index 04e3794a3..89c10ec5b 100644 --- a/src/ui/qml/ConnectivityManager.h +++ b/src/ui/qml/ConnectivityManager.h @@ -8,13 +8,13 @@ #pragma once - -#include "Env.h" - +#include +#include #include class test_ConnectivityManager; + namespace governikus { @@ -22,28 +22,30 @@ class ConnectivityManager : public QObject { Q_OBJECT - friend class Env; friend class ::test_ConnectivityManager; + Q_PROPERTY(bool watching READ isWatching WRITE setWatching NOTIFY fireWatchingChanged) Q_PROPERTY(bool networkInterfaceActive READ isNetworkInterfaceActive NOTIFY fireNetworkInterfaceActiveChanged) private: int mTimerId; bool mActive; + QList mAllAddresses; - ConnectivityManager(); - ~ConnectivityManager() override; - - void setActive(bool pActive, const QString& pInterfaceName = QString()); - void updateConnectivity(); + void setActive(bool pActive); void timerEvent(QTimerEvent* pEvent) override; public: + ConnectivityManager(); + ~ConnectivityManager() override; + + [[nodiscard]] bool isWatching() const; + void setWatching(bool pWatching); + Q_INVOKABLE bool checkConnectivity(); [[nodiscard]] bool isNetworkInterfaceActive() const; - void startWatching(); - void stopWatching(); Q_SIGNALS: + void fireWatchingChanged(); void fireNetworkInterfaceActiveChanged(bool pActive); }; diff --git a/src/ui/qml/FormattedTextModel.cpp b/src/ui/qml/FormattedTextModel.cpp index 2e811209e..f288d9a71 100644 --- a/src/ui/qml/FormattedTextModel.cpp +++ b/src/ui/qml/FormattedTextModel.cpp @@ -29,7 +29,7 @@ FormattedTextModel::FormattedTextModel(QObject* pParent, const QStringList& pLin int FormattedTextModel::rowCount(const QModelIndex& pIndex) const { Q_UNUSED(pIndex) - return mLines.size(); + return static_cast(mLines.size()); } @@ -162,10 +162,6 @@ FormattedTextModel::ReadLinesResult FormattedTextModel::readLines(const QString& } QTextStream in(&file); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - in.setCodec("UTF-8"); -#endif - QStringList lines; while (!in.atEnd()) { diff --git a/src/ui/qml/HelpAction.cpp b/src/ui/qml/HelpAction.cpp deleted file mode 100644 index 681a112bf..000000000 --- a/src/ui/qml/HelpAction.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/** - * Copyright (c) 2014-2023 Governikus GmbH & Co. KG, Germany - */ - -#include "HelpAction.h" - -#include "LanguageLoader.h" -#include "SingletonHelper.h" -#include "VersionNumber.h" - -#include -#include -#include -#include -#include -#include -#include - - -using namespace governikus; - -defineSingleton(HelpAction) // clazy:exclude=wrong-qglobalstatic - -Q_DECLARE_LOGGING_CATEGORY(gui) - -const QMap HelpAction::mQmlHelpMapping = { - {QStringLiteral("applicationOverview"), QStringLiteral("index.html")}, - {QStringLiteral("index"), QStringLiteral("index.html")}, - {QStringLiteral("selfauthentication"), QStringLiteral("selfauthentication.html")}, - {QStringLiteral("authentication"), QStringLiteral("provider-identify.html")}, - {QStringLiteral("provider"), QStringLiteral("provider.html")}, - {QStringLiteral("providerDetails"), QStringLiteral("provider-list.html#provider-details")}, - {QStringLiteral("history"), QStringLiteral("history.html")}, - {QStringLiteral("settings"), QStringLiteral("settings.html")}, - {QStringLiteral("settingsGeneral"), QStringLiteral("settings-general.html")}, - {QStringLiteral("settingsRemoteReader"), QStringLiteral("settings-remote-reader.html")}, - {QStringLiteral("settingsPcscReader"), QStringLiteral("settings-pcsc-reader.html")}, - {QStringLiteral("settingsSecurityPrivacy"), QStringLiteral("settings-security-privacy.html")}, - {QStringLiteral("settingsDeveloper"), QStringLiteral("settings-developer.html")}, - {QStringLiteral("pinManagement"), QStringLiteral("pin-management.html")}, - {QStringLiteral("helpSection"), QStringLiteral("help-section.html")}, - {QStringLiteral("diagnosis"), QStringLiteral("help-section-diagnosis.html")}, - {QStringLiteral("applicationLog"), QStringLiteral("help-section-application-log.html")}, - {QStringLiteral("helpVersioninformation"), QStringLiteral("help-section-versioninformation.html")}, - {QStringLiteral("helpLicenseinformation"), QStringLiteral("help-section-software-license.html")}, - {QStringLiteral("setupAssistant"), QStringLiteral("setup-assistant.html")}, - {QStringLiteral("applicationUpdate"), QStringLiteral("updates.html")} -}; - -const QString HelpAction::mBaseUrl = QStringLiteral("https://www.ausweisapp.bund.de/ausweisapp2/"); - - -QString HelpAction::getHelpPath(QLocale::Language pLang) const -{ - const QString langDir = QCoreApplication::applicationDirPath() % QStringLiteral("/help/") % LanguageLoader::getLocaleCode(QLocale(pLang)) % QLatin1Char('/'); - - if (QDir(langDir).exists()) - { - return langDir; - } - - return QString(); -} - - -QLocale::Language HelpAction::getExistingHelpLanguage() const -{ - QLocale::Language lang = LanguageLoader::getInstance().getUsedLocale().language(); - if (!getHelpPath(lang).isNull()) - { - return lang; - } - - lang = LanguageLoader::getInstance().getFallbackLanguage(); - if (!getHelpPath(lang).isNull()) - { - return lang; - } - - return QLocale::AnyLanguage; -} - - -QString HelpAction::getContextMapping(const QString& pObjectName) const -{ - if (mQmlHelpMapping.contains(pObjectName)) - { - return mQmlHelpMapping.value(pObjectName); - } - else - { - qCWarning(gui) << "Cannot find help mapping:" << pObjectName; - } - - return QStringLiteral("index.html"); -} - - -QString HelpAction::getHelpUrl(const QString& pObjectName) const -{ - QLocale::Language lang = getExistingHelpLanguage(); - if (lang == QLocale::AnyLanguage) - { - return getOnlineUrl(QString()); - } - - return QUrl::fromLocalFile(getHelpPath(lang)).toString() + getContextMapping(pObjectName); -} - - -QString HelpAction::getOnlineUrl(const QString& pObjectName) -{ -#ifdef Q_OS_MACOS - const QLatin1String osPath("macOS"); -#else - const QLatin1String osPath("Windows"); -#endif - - const auto& appVersion = VersionNumber::getApplicationVersion().getVersionNumber(); - const QString ver = QString::number(appVersion.majorVersion()) % QLatin1Char('.') % QString::number(appVersion.minorVersion()); - const QString locale = LanguageLoader::getLocaleCode(); - const QString mapping = getInstance().getContextMapping(pObjectName); - return mBaseUrl % QStringLiteral("help") % QLatin1Char('/') % ver % QLatin1Char('/') % locale % QLatin1Char('/') % osPath % QLatin1Char('/') % mapping; -} - - -void HelpAction::openContextHelp(const QString& pObjectName) -{ - const auto& url = QUrl(getOnlineUrl(pObjectName)); - qCDebug(gui) << "Open online help:" << pObjectName << '|' << url; - QDesktopServices::openUrl(url); -} diff --git a/src/ui/qml/HelpAction.h b/src/ui/qml/HelpAction.h deleted file mode 100644 index e36502492..000000000 --- a/src/ui/qml/HelpAction.h +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Copyright (c) 2014-2023 Governikus GmbH & Co. KG, Germany - */ - -/*! - * \brief Helper class for mapping object name to help file. - */ - -#pragma once - -#include -#include -#include - -class test_HelpAction; - -namespace governikus -{ - -class HelpAction -{ - Q_DISABLE_COPY(HelpAction) - friend class ::test_HelpAction; - - private: - static const QMap mQmlHelpMapping; - static const QString mBaseUrl; - - [[nodiscard]] QLocale::Language getExistingHelpLanguage() const; - [[nodiscard]] QString getContextMapping(const QString& pObjectName) const; - [[nodiscard]] QString getHelpPath(QLocale::Language pLang) const; - [[nodiscard]] QString getHelpUrl(const QString& pObjectName) const; - - protected: - static HelpAction& getInstance(); - HelpAction() = default; - ~HelpAction() = default; - - public: - [[nodiscard]] static QString getOnlineUrl(const QString& pObjectName = QString()); - static void openContextHelp(const QString& pObjectName = QStringLiteral("applicationPage")); -}; - -} // namespace governikus diff --git a/src/ui/qml/HistoryModel.cpp b/src/ui/qml/HistoryModel.cpp deleted file mode 100644 index 2e68b9fc9..000000000 --- a/src/ui/qml/HistoryModel.cpp +++ /dev/null @@ -1,333 +0,0 @@ -/** - * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany - */ - -/*! - * \brief Model implementation for the history entries. - */ - -#include "HistoryModel.h" - -#include "AppSettings.h" -#include "Env.h" -#include "asn1/AccessRoleAndRight.h" - -#include "PdfExporter.h" -#include "ProviderConfiguration.h" -#include "ProviderModel.h" - -#include - -using namespace governikus; - - -auto& HistoryModel::getHistorySettings() -{ - return Env::getSingleton()->getHistorySettings(); -} - - -HistoryModel::HistoryModel(QObject* pParent) - : QAbstractListModel(pParent) - , mFilterModel() - , mNameFilterModel() - , mHistoryModelSearchFilter() -{ - updateConnections(); - mFilterModel.setSourceModel(this); - mFilterModel.setFilterCaseSensitivity(Qt::CaseInsensitive); - mNameFilterModel.setSourceModel(this); - mHistoryModelSearchFilter.setSourceModel(this); - - const auto& historySettings = getHistorySettings(); - connect(&historySettings, &HistorySettings::fireHistoryInfosChanged, this, &HistoryModel::onHistoryEntriesChanged); - connect(&historySettings, &HistorySettings::fireEnabledChanged, this, &HistoryModel::fireEnabledChanged); - connect(Env::getSingleton(), &ProviderConfiguration::fireUpdated, this, &HistoryModel::onProvidersChanged); - - QQmlEngine::setObjectOwnership(&mFilterModel, QQmlEngine::CppOwnership); - QQmlEngine::setObjectOwnership(&mNameFilterModel, QQmlEngine::CppOwnership); - QQmlEngine::setObjectOwnership(&mHistoryModelSearchFilter, QQmlEngine::CppOwnership); -} - - -void HistoryModel::updateConnections() -{ - for (const auto& connection : std::as_const(mConnections)) - { - disconnect(connection); - } - mConnections.clear(); - - const auto& historyEntries = getHistorySettings().getHistoryInfos(); - mConnections.reserve(historyEntries.size() * 2); - for (int i = 0; i < historyEntries.size(); i++) - { - const auto& provider = determineProviderFor(historyEntries.at(i)); - const QModelIndex& modelIndex = createIndex(i, 0); - - mConnections += connect(provider.getIcon().data(), &UpdatableFile::fireUpdated, this, [this, modelIndex] { - Q_EMIT dataChanged(modelIndex, modelIndex, {PROVIDER_ICON}); - }); - mConnections += connect(provider.getImage().data(), &UpdatableFile::fireUpdated, this, [this, modelIndex] { - Q_EMIT dataChanged(modelIndex, modelIndex, {PROVIDER_IMAGE}); - }); - } -} - - -void HistoryModel::onHistoryEntriesChanged() -{ - beginResetModel(); - updateConnections(); - endResetModel(); - Q_EMIT fireEmptyChanged(isEmpty()); -} - - -void HistoryModel::onProvidersChanged() -{ - const static QVector PROVIDER_ROLES({PROVIDER_CATEGORY, - PROVIDER_SHORTNAME, - PROVIDER_LONGNAME, - PROVIDER_LONGDESCRIPTION, - PROVIDER_ADDRESS, - PROVIDER_ADDRESS_DOMAIN, - PROVIDER_HOMEPAGE, - PROVIDER_HOMEPAGE_BASE, - PROVIDER_PHONE, - PROVIDER_PHONE_COST, - PROVIDER_EMAIL, - PROVIDER_POSTALADDRESS, - PROVIDER_ICON, - PROVIDER_IMAGE}); - Q_EMIT dataChanged(index(0), index(rowCount() - 1), PROVIDER_ROLES); -} - - -int HistoryModel::rowCount(const QModelIndex&) const -{ - return getHistorySettings().getHistoryInfos().size(); -} - - -QVariant HistoryModel::data(const QModelIndex& pIndex, int pRole) const -{ - if (pIndex.isValid() && pIndex.row() < rowCount()) - { - const auto& infos = getHistorySettings().getHistoryInfos(); - const auto& entry = infos[pIndex.row()]; - const auto& provider = determineProviderFor(entry); - switch (pRole) - { - case Qt::DisplayRole: - case SUBJECT: - return entry.getSubjectName(); - - case PURPOSE: - return entry.getPurpose(); - - case DATETIME: - return entry.getDateTime(); - - case TERMSOFUSAGE: - { - auto tos = entry.getTermOfUsage(); - return tos.remove(QLatin1Char('\r')).replace(QLatin1Char('\t'), QLatin1Char(' ')); - } - - case REQUESTEDDATA: - if (const auto& data = entry.getRequestedData(); !data.isEmpty()) - { - return AccessRoleAndRightsUtil::joinFromTechnicalName(data, AccessRoleAndRightsUtil::READ); - } - - //: LABEL ALL_PLATFORMS - return tr("No data stored on your ID card was read, only confirmed whether you are in possession of a valid ID card."); - - case WRITTENDATA: - return AccessRoleAndRightsUtil::joinFromTechnicalName(entry.getRequestedData(), AccessRoleAndRightsUtil::WRITE); - - case PROVIDER_CATEGORY: - return provider.getCategory(); - - case PROVIDER_SHORTNAME: - return provider.getShortName().toString(); - - case PROVIDER_LONGNAME: - return provider.getLongName().toString(); - - case PROVIDER_LONGDESCRIPTION: - return provider.getLongDescription().toString(); - - case PROVIDER_ADDRESS: - return provider.getAddress(); - - case PROVIDER_ADDRESS_DOMAIN: - return provider.getAddressDomain(); - - case PROVIDER_HOMEPAGE: - return provider.getHomepage(); - - case PROVIDER_HOMEPAGE_BASE: - return provider.getHomepageBase(); - - case PROVIDER_PHONE: - return provider.getPhone(); - - case PROVIDER_PHONE_COST: - { - const auto& cost = Env::getSingleton()->getCallCost(provider); - return ProviderModel::createCostString(cost); - } - - case PROVIDER_EMAIL: - return provider.getEMail(); - - case PROVIDER_POSTALADDRESS: - return provider.getPostalAddress(); - - case PROVIDER_ICON: - return provider.getIcon()->lookupUrl(); - - case PROVIDER_IMAGE: - return provider.getImage()->lookupUrl(); - } - } - return QVariant(); -} - - -ProviderConfigurationInfo HistoryModel::determineProviderFor(const HistoryInfo& pHistoryInfo) const -{ - QVector matchingProviders; - const auto& providers = Env::getSingleton()->getProviderConfigurationInfos(); - for (const auto& provider : providers) - { - if (provider.matchWithSubjectUrl(pHistoryInfo.getSubjectUrl())) - { - matchingProviders += provider; - } - } - if (matchingProviders.size() == 1) - { - return matchingProviders.at(0); - } - return ProviderConfigurationInfo(); -} - - -bool HistoryModel::isEnabled() const -{ - return getHistorySettings().isEnabled(); -} - - -void HistoryModel::setEnabled(bool pEnabled) -{ - if (pEnabled != isEnabled()) - { - auto& historySettings = getHistorySettings(); - historySettings.setEnabled(pEnabled); - } -} - - -bool HistoryModel::isEmpty() const -{ - const auto& historyEntries = getHistorySettings().getHistoryInfos(); - return historyEntries.isEmpty(); -} - - -QHash HistoryModel::roleNames() const -{ - QHash roles = QAbstractListModel::roleNames(); - roles.insert(SUBJECT, "subject"); - roles.insert(PURPOSE, "purpose"); - roles.insert(DATETIME, "dateTime"); - roles.insert(TERMSOFUSAGE, "termsOfUsage"); - roles.insert(REQUESTEDDATA, "requestedData"); - roles.insert(WRITTENDATA, "writtenData"); - roles.insert(PROVIDER_CATEGORY, "providerCategory"); - roles.insert(PROVIDER_SHORTNAME, "providerShortName"); - roles.insert(PROVIDER_LONGNAME, "providerLongName"); - roles.insert(PROVIDER_LONGDESCRIPTION, "providerLongDescription"); - roles.insert(PROVIDER_ADDRESS, "providerAddress"); - roles.insert(PROVIDER_ADDRESS_DOMAIN, "providerAddressDomain"); - roles.insert(PROVIDER_HOMEPAGE, "providerHomepage"); - roles.insert(PROVIDER_HOMEPAGE_BASE, "providerHomepageBase"); - roles.insert(PROVIDER_PHONE, "providerPhone"); - roles.insert(PROVIDER_PHONE_COST, "providerPhoneCost"); - roles.insert(PROVIDER_EMAIL, "providerEmail"); - roles.insert(PROVIDER_POSTALADDRESS, "providerPostalAddress"); - roles.insert(PROVIDER_ICON, "providerIcon"); - roles.insert(PROVIDER_IMAGE, "providerImage"); - return roles; -} - - -bool HistoryModel::removeRows(int pRow, int pCount, const QModelIndex& pParent) -{ - if (pCount <= 0 || pRow < 0) - { - return false; - } - beginRemoveRows(pParent, pRow, pRow + pCount - 1); - - auto& historySettings = getHistorySettings(); - auto entries = historySettings.getHistoryInfos(); - entries.remove(pRow, pCount); - - // disconnect the signal, otherwise this model gets reset - disconnect(&historySettings, &HistorySettings::fireHistoryInfosChanged, this, &HistoryModel::onHistoryEntriesChanged); - historySettings.setHistoryInfos(entries); - connect(&historySettings, &HistorySettings::fireHistoryInfosChanged, this, &HistoryModel::onHistoryEntriesChanged); - - endRemoveRows(); - return true; -} - - -HistoryProxyModel* HistoryModel::getFilterModel() -{ - return &mFilterModel; -} - - -ProviderNameFilterModel* HistoryModel::getNameFilterModel() -{ - return &mNameFilterModel; -} - - -HistoryModelSearchFilter* HistoryModel::getHistoryModelSearchFilter() -{ - return &mHistoryModelSearchFilter; -} - - -void HistoryModel::exportHistory(const QUrl& pFilename) const -{ - PdfExporter exporter(pFilename.toLocalFile()); - exporter.exportHistory(); -} - - -#ifndef QT_NO_DEBUG -void HistoryModel::createDummyEntry() -{ - const auto& now = QDateTime::currentDateTime(); - const QList dates = {now.addDays(-7), now.addDays(-2), now.addDays(-1), now}; - - for (const auto& date : dates) - { - - getHistorySettings().addHistoryInfo(HistoryInfo( - QStringLiteral("Dummy Subject"), QStringLiteral("Dummy Subject URL"), QStringLiteral("Dummy Usage"), - date, QStringLiteral("Dummy Term Of Usage"), - {QStringLiteral("GivenNames"), QStringLiteral("Address"), QStringLiteral("WriteAddress")})); - } -} - - -#endif diff --git a/src/ui/qml/HistoryModel.h b/src/ui/qml/HistoryModel.h deleted file mode 100644 index bce6b4f0f..000000000 --- a/src/ui/qml/HistoryModel.h +++ /dev/null @@ -1,103 +0,0 @@ -/** - * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany - */ - -/*! - * \brief Model implementation for the history entries. - */ - -#pragma once - -#include "HistoryModelSearchFilter.h" -#include "HistoryProxyModel.h" -#include "HistorySettings.h" -#include "ProviderConfigurationInfo.h" -#include "ProviderNameFilterModel.h" - -#include - - -class test_HistoryModel; - -namespace governikus -{ - -class HistoryModel - : public QAbstractListModel -{ - Q_OBJECT - friend class ::test_HistoryModel; - - Q_PROPERTY(HistoryProxyModel * filter READ getFilterModel CONSTANT) - Q_PROPERTY(ProviderNameFilterModel * nameFilter READ getNameFilterModel CONSTANT) - Q_PROPERTY(HistoryModelSearchFilter * searchFilter READ getHistoryModelSearchFilter CONSTANT) - Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY fireEnabledChanged) - Q_PROPERTY(bool empty READ isEmpty NOTIFY fireEmptyChanged) - - private: - HistoryProxyModel mFilterModel; - ProviderNameFilterModel mNameFilterModel; - HistoryModelSearchFilter mHistoryModelSearchFilter; - QVector mConnections; - - ProviderConfigurationInfo determineProviderFor(const HistoryInfo& pHistoryInfo) const; - static auto& getHistorySettings(); - - [[nodiscard]] bool isEnabled() const; - void setEnabled(bool pEnabled); - [[nodiscard]] bool isEmpty() const; - void updateConnections(); - - private Q_SLOTS: - void onHistoryEntriesChanged(); - void onProvidersChanged(); - - Q_SIGNALS: - void fireEnabledChanged(bool pValue); - void fireEmptyChanged(bool pValue); - - public: - explicit HistoryModel(QObject* pParent = nullptr); - ~HistoryModel() override = default; - - enum HistoryRoles - { - SUBJECT = Qt::UserRole + 1, - PURPOSE, - DATETIME, - TERMSOFUSAGE, - REQUESTEDDATA, - WRITTENDATA, - PROVIDER_CATEGORY, - PROVIDER_SHORTNAME, - PROVIDER_LONGNAME, - PROVIDER_LONGDESCRIPTION, - PROVIDER_ADDRESS, - PROVIDER_ADDRESS_DOMAIN, - PROVIDER_HOMEPAGE, - PROVIDER_HOMEPAGE_BASE, - PROVIDER_PHONE, - PROVIDER_PHONE_COST, - PROVIDER_EMAIL, - PROVIDER_POSTALADDRESS, - PROVIDER_ICON, - PROVIDER_IMAGE - }; - - [[nodiscard]] int rowCount(const QModelIndex& = QModelIndex()) const override; - [[nodiscard]] QVariant data(const QModelIndex& pIndex, int pRole = Qt::DisplayRole) const override; - [[nodiscard]] QHash roleNames() const override; - [[nodiscard]] Q_INVOKABLE bool removeRows(int pRow, int pCount, const QModelIndex& pParent = QModelIndex()) override; - - [[nodiscard]] Q_INVOKABLE HistoryProxyModel* getFilterModel(); - [[nodiscard]] Q_INVOKABLE ProviderNameFilterModel* getNameFilterModel(); - [[nodiscard]] HistoryModelSearchFilter* getHistoryModelSearchFilter(); - - Q_INVOKABLE void exportHistory(const QUrl& pFilename) const; - -#ifndef QT_NO_DEBUG - Q_INVOKABLE void createDummyEntry(); -#endif -}; - -} // namespace governikus diff --git a/src/ui/qml/HistoryModelSearchFilter.cpp b/src/ui/qml/HistoryModelSearchFilter.cpp deleted file mode 100644 index 2a7bed308..000000000 --- a/src/ui/qml/HistoryModelSearchFilter.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ - -#include "HistoryModelSearchFilter.h" - -#include "HistoryModel.h" - -#include - -using namespace governikus; - - -bool HistoryModelSearchFilter::filterAcceptsRow(int pSourceRow, const QModelIndex&) const -{ - if (mFilterString.isEmpty()) - { - return true; - } - - const HistoryModel* const dataSourceModel = qobject_cast(sourceModel()); - if (dataSourceModel == nullptr) - { - return false; - } - - const QModelIndex& modelIndex = dataSourceModel->index(pSourceRow, 0); - //: LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString - if (dataSourceModel->data(modelIndex, HistoryModel::DATETIME).toDateTime().toString(tr("dd.MM.yyyy")).contains(mFilterString, Qt::CaseInsensitive) - || dataSourceModel->data(modelIndex, HistoryModel::SUBJECT).toString().contains(mFilterString, Qt::CaseInsensitive) - || dataSourceModel->data(modelIndex, HistoryModel::PURPOSE).toString().contains(mFilterString, Qt::CaseInsensitive) - || dataSourceModel->data(modelIndex, HistoryModel::REQUESTEDDATA).toString().contains(mFilterString, Qt::CaseInsensitive)) - { - return true; - } - - return false; -} - - -void governikus::HistoryModelSearchFilter::setFilterString(const QString& pFilterString) -{ - mFilterString = pFilterString; - invalidateFilter(); -} diff --git a/src/ui/qml/HistoryModelSearchFilter.h b/src/ui/qml/HistoryModelSearchFilter.h deleted file mode 100644 index 2849b1023..000000000 --- a/src/ui/qml/HistoryModelSearchFilter.h +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ - -/*! - * \brief A filter to search the history model - */ - -#pragma once - -#include -#include -#include - -namespace governikus -{ - -class HistoryModelSearchFilter - : public QSortFilterProxyModel -{ - Q_OBJECT - - private: - QString mFilterString; - - protected: - [[nodiscard]] bool filterAcceptsRow(int pSourceRow, const QModelIndex&) const override; - - public: - Q_INVOKABLE void setFilterString(const QString& pFilterString); -}; - -} // namespace governikus diff --git a/src/ui/qml/HistoryProxyModel.cpp b/src/ui/qml/HistoryProxyModel.cpp deleted file mode 100644 index 1471c3bcd..000000000 --- a/src/ui/qml/HistoryProxyModel.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany - */ - -#include "HistoryProxyModel.h" - -using namespace governikus; - - -bool HistoryProxyModel::removeRows(int pRow, int pCount, const QModelIndex& pParent) -{ - return QSortFilterProxyModel::removeRows(pRow, pCount, pParent); -} diff --git a/src/ui/qml/HistoryProxyModel.h b/src/ui/qml/HistoryProxyModel.h deleted file mode 100644 index 08e60fe74..000000000 --- a/src/ui/qml/HistoryProxyModel.h +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany - */ - -#pragma once - -#include - -namespace governikus -{ - -class HistoryProxyModel - : public QSortFilterProxyModel -{ - Q_OBJECT - - public: - [[nodiscard]] Q_INVOKABLE bool removeRows(int pRow, int pCount, const QModelIndex& pParent = QModelIndex()) override; - - HistoryProxyModel() = default; - - ~HistoryProxyModel() override = default; -}; - - -} // namespace governikus diff --git a/src/ui/qml/LogModel.cpp b/src/ui/qml/LogModel.cpp index d5d1095c4..397a5da5b 100644 --- a/src/ui/qml/LogModel.cpp +++ b/src/ui/qml/LogModel.cpp @@ -57,7 +57,7 @@ void LogModel::addLogEntry(const QString& pEntry) mLogEntries.append(pEntry); - QModelIndex idx = index(mLogEntries.size() - 1, 0); + QModelIndex idx = index(static_cast(mLogEntries.size()) - 1, 0); const auto& level = data(idx, LogModel::LogModelRoles::LevelRole).toString(); if (!mLevels.contains(level)) @@ -102,7 +102,8 @@ void LogModel::onNewLogMsg(const QString& pMsg) { if (mSelectedLogFile == 0) { - beginInsertRows(QModelIndex(), mLogEntries.size(), mLogEntries.size()); + const auto size = static_cast(mLogEntries.size()); + beginInsertRows(QModelIndex(), size, size); addLogEntry(pMsg); endInsertRows(); Q_EMIT fireNewLogMsg(); @@ -204,10 +205,6 @@ void LogModel::setLogFile(int pIndex) if (pIndex == 0) { QTextStream in(logHandler->useLogFile() ? logHandler->getBacklog() : tr("The logfile is disabled.").toUtf8()); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - in.setCodec("UTF-8"); -#endif - setLogEntries(in); connect(logHandler->getEventHandler(), &LogEventHandler::fireLog, this, &LogModel::onNewLogMsg); } @@ -218,9 +215,6 @@ void LogModel::setLogFile(int pIndex) if (inputFile.open(QIODevice::ReadOnly)) { QTextStream in(&inputFile); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - in.setCodec("UTF-8"); -#endif setLogEntries(in); inputFile.close(); } @@ -270,7 +264,7 @@ void LogModel::saveDummyLogFile(const QDateTime& pTimestamp) int LogModel::rowCount(const QModelIndex& pIndex) const { Q_UNUSED(pIndex) - return mLogEntries.size(); + return static_cast(mLogEntries.size()); } diff --git a/src/ui/qml/LogModel.h b/src/ui/qml/LogModel.h index e8c914d3a..f963b9ee2 100644 --- a/src/ui/qml/LogModel.h +++ b/src/ui/qml/LogModel.h @@ -74,10 +74,10 @@ class LogModel Q_INVOKABLE void mailLog(const QString& pEmail = QStringLiteral("support@ausweisapp.de"), const QString& pSubject = tr("Mobile logfile"), - const QString& pMsg = tr("")); + const QString& pMsg = tr("")) const; // \a popupPosition will be used on an iPad as the origin of the share bubble - Q_INVOKABLE void shareLog(QPoint popupPosition); + Q_INVOKABLE void shareLog(QPoint popupPosition) const; int rowCount(const QModelIndex& pIndex = QModelIndex()) const override; QHash roleNames() const override; diff --git a/src/ui/qml/LogModel_android.cpp b/src/ui/qml/LogModel_android.cpp index 5711b33ec..180327ce6 100644 --- a/src/ui/qml/LogModel_android.cpp +++ b/src/ui/qml/LogModel_android.cpp @@ -38,7 +38,7 @@ static QString getPublicLogFileName(const QDateTime& pDateTime = QDateTime::curr } -void LogModel::mailLog(const QString& pEmail, const QString& pSubject, const QString& pMsg) +void LogModel::mailLog(const QString& pEmail, const QString& pSubject, const QString& pMsg) const { QJniEnvironment env; const QJniObject javaActivity(QNativeInterface::QAndroidApplication::context()); @@ -81,7 +81,7 @@ void LogModel::mailLog(const QString& pEmail, const QString& pSubject, const QSt } -void LogModel::shareLog(const QPoint /*popupPosition*/) +void LogModel::shareLog(const QPoint /*popupPosition*/) const { QJniEnvironment env; const QJniObject javaActivity(QNativeInterface::QAndroidApplication::context()); diff --git a/src/ui/qml/LogModel_generic.cpp b/src/ui/qml/LogModel_generic.cpp index 85a6a47c4..1fa848046 100644 --- a/src/ui/qml/LogModel_generic.cpp +++ b/src/ui/qml/LogModel_generic.cpp @@ -13,7 +13,7 @@ Q_DECLARE_LOGGING_CATEGORY(qml) using namespace governikus; -void LogModel::mailLog(const QString& pEmail, const QString& pSubject, const QString& pMsg) +void LogModel::mailLog(const QString& pEmail, const QString& pSubject, const QString& pMsg) const { Q_UNUSED(pEmail) Q_UNUSED(pSubject) @@ -23,7 +23,7 @@ void LogModel::mailLog(const QString& pEmail, const QString& pSubject, const QSt } -void LogModel::shareLog(const QPoint /*popupPosition*/) +void LogModel::shareLog(const QPoint /*popupPosition*/) const { qCWarning(qml) << "NOT IMPLEMENTED"; } diff --git a/src/ui/qml/LogModel_ios.mm b/src/ui/qml/LogModel_ios.mm index 2d6e5f43f..986596934 100644 --- a/src/ui/qml/LogModel_ios.mm +++ b/src/ui/qml/LogModel_ios.mm @@ -75,7 +75,7 @@ static QString getTemporaryLogFile(const QString& pSourceFile = QString()) } -void LogModel::mailLog(const QString& pEmail, const QString& pSubject, const QString& pMsg) +void LogModel::mailLog(const QString& pEmail, const QString& pSubject, const QString& pMsg) const { if (![MFMailComposeViewController canSendMail]) { @@ -107,7 +107,7 @@ static QString getTemporaryLogFile(const QString& pSourceFile = QString()) } -void LogModel::shareLog(const QPoint popupPosition) +void LogModel::shareLog(const QPoint popupPosition) const { const QString& logFile = mSelectedLogFile == 0 ? getTemporaryLogFile() : getTemporaryLogFile(mLogFiles.at(mSelectedLogFile)); if (logFile.isEmpty()) diff --git a/src/ui/qml/NotificationModel.cpp b/src/ui/qml/NotificationModel.cpp index f5074c7a2..d6cf6a602 100644 --- a/src/ui/qml/NotificationModel.cpp +++ b/src/ui/qml/NotificationModel.cpp @@ -40,7 +40,8 @@ void NotificationModel::onNewLogMsg(const QString& pMsg, const QString& pCategor endRemoveRows(); } - beginInsertRows(QModelIndex(), mNotificationEntries.size(), mNotificationEntries.size()); + const auto size = static_cast(mNotificationEntries.size()); + beginInsertRows(QModelIndex(), size, size); //: LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString const auto& time = QTime::currentTime().toString(tr("hh:mm:ss")); mNotificationEntries.append({pCategoryName, time, pMsg}); @@ -54,7 +55,7 @@ void NotificationModel::onNewLogMsg(const QString& pMsg, const QString& pCategor int NotificationModel::rowCount(const QModelIndex& pIndex) const { Q_UNUSED(pIndex) - return mNotificationEntries.count(); + return static_cast(mNotificationEntries.size()); } diff --git a/src/ui/qml/NumberModel.cpp b/src/ui/qml/NumberModel.cpp index 2ee6d8155..bafde9f5e 100644 --- a/src/ui/qml/NumberModel.cpp +++ b/src/ui/qml/NumberModel.cpp @@ -4,7 +4,6 @@ #include "NumberModel.h" -#include "ApplicationModel.h" #include "ReaderManager.h" #include "context/ChangePinContext.h" #include "context/IfdServiceContext.h" @@ -18,6 +17,8 @@ using namespace governikus; NumberModel::NumberModel() : QObject() , mContext() + , mNewPin() + , mNewPinConfirmation() { const auto readerManager = Env::getSingleton(); connect(readerManager, &ReaderManager::fireReaderPropertiesUpdated, this, &NumberModel::onReaderInfoChanged); @@ -31,6 +32,8 @@ NumberModel::NumberModel() void NumberModel::resetContext(const QSharedPointer& pContext) { mContext = pContext; + clearNewPinAndConfirmation(); + if (mContext) { connect(mContext.data(), &WorkflowContext::fireCanChanged, this, &NumberModel::fireCanChanged); @@ -54,6 +57,14 @@ void NumberModel::resetContext(const QSharedPointer& pContext) connect(remoteServiceContext.data(), &IfdServiceContext::fireEstablishPaceChannelUpdated, this, &NumberModel::fireInputErrorChanged); } +#if __has_include("context/PersonalizationContext.h") + const auto personalizationContext = mContext.objectCast(); + if (personalizationContext) + { + connect(personalizationContext.data(), &PersonalizationContext::fireSessionIdentifierChanged, this, &NumberModel::firePasswordTypeChanged); + } +#endif + connect(mContext.data(), &WorkflowContext::fireCardConnectionChanged, this, &NumberModel::onCardConnectionChanged); connect(mContext.data(), &WorkflowContext::fireReaderNameChanged, this, &NumberModel::fireReaderInfoChanged); connect(mContext.data(), &WorkflowContext::fireReaderNameChanged, this, &NumberModel::fireInputErrorChanged); @@ -79,22 +90,25 @@ PasswordType NumberModel::getPasswordType() const } const auto& changePinContext = mContext.objectCast(); - if (changePinContext && !changePinContext->getPin().isEmpty()) - { - return mContext->isSmartCardUsed() ? PasswordType::NEW_SMART_PIN : PasswordType::NEW_PIN; - } - const auto& remoteServiceContext = mContext.objectCast(); - if (remoteServiceContext && remoteServiceContext->modifyPinRunning()) + if ((changePinContext && !changePinContext->getPin().isEmpty()) || (remoteServiceContext && remoteServiceContext->modifyPinRunning())) { - return PasswordType::NEW_PIN; + if (mNewPin.isEmpty()) + { + return mContext->isSmartCardUsed() ? PasswordType::NEW_SMART_PIN : PasswordType::NEW_PIN; + } + return mContext->isSmartCardUsed() ? PasswordType::NEW_SMART_PIN_CONFIRMATION : PasswordType::NEW_PIN_CONFIRMATION; } #if __has_include("context/PersonalizationContext.h") const auto& smartContext = mContext.objectCast(); if (smartContext && !smartContext->getSessionIdentifier().isNull()) { - return PasswordType::NEW_SMART_PIN; + if (mNewPin.isEmpty()) + { + return PasswordType::NEW_SMART_PIN; + } + return PasswordType::NEW_SMART_PIN_CONFIRMATION; } #endif @@ -154,35 +168,83 @@ void NumberModel::setPin(const QString& pPin) QString NumberModel::getNewPin() const { - const auto changePinContext = mContext.objectCast(); - - return changePinContext ? changePinContext->getNewPin() : QString(); + return mNewPin; } void NumberModel::setNewPin(const QString& pNewPin) { + if (!mContext) + { + return; + } + + if (mNewPin != pNewPin) + { + mNewPin = pNewPin; + Q_EMIT fireNewPinChanged(); + } + + Q_EMIT firePasswordTypeChanged(); + if (!mNewPinConfirmation.isEmpty()) + { + mNewPinConfirmation.clear(); + Q_EMIT fireInputErrorChanged(); + } +} + + +QString NumberModel::getNewPinConfirmation() const +{ + return mNewPinConfirmation; +} + + +void NumberModel::setNewPinConfirmation(const QString& pNewPinConfirmation) +{ + if (mNewPinConfirmation != pNewPinConfirmation) + { + mNewPinConfirmation = pNewPinConfirmation; + Q_EMIT fireNewPinConfirmationChanged(); + Q_EMIT firePasswordTypeChanged(); + } +} + + +bool NumberModel::commitNewPin() +{ + if (!newPinAndConfirmationMatch()) + { + mNewPin.clear(); + Q_EMIT firePasswordTypeChanged(); + Q_EMIT fireInputErrorChanged(); + return false; + } + const auto changePinContext = mContext.objectCast(); if (changePinContext) { - changePinContext->setNewPin(pNewPin); + changePinContext->setNewPin(mNewPin); } const auto remoteServiceContext = mContext.objectCast(); if (remoteServiceContext) { - remoteServiceContext->setNewPin(pNewPin); + remoteServiceContext->setNewPin(mNewPin); } #if __has_include("context/PersonalizationContext.h") const auto smartContext = mContext.objectCast(); if (smartContext) { - smartContext->setNewPin(pNewPin); + smartContext->setNewPin(mNewPin); } #endif + clearNewPinAndConfirmation(); Q_EMIT firePasswordTypeChanged(); + + return true; } @@ -221,12 +283,38 @@ CardReturnCode NumberModel::getInputErrorCode() const } +void NumberModel::clearNewPinAndConfirmation() +{ + mNewPin.clear(); + mNewPinConfirmation.clear(); +} + + +bool NumberModel::newPinAndConfirmationMatch() const +{ + return !mNewPin.isEmpty() && !mNewPinConfirmation.isEmpty() && mNewPin == mNewPinConfirmation; +} + + QString NumberModel::getInputError() const { const CardReturnCode paceResult = getInputErrorCode(); const bool isRequestTransportPin = mContext && mContext->isRequestTransportPin(); const bool isSmartCard = mContext && mContext->isSmartCardUsed(); + if (!mNewPinConfirmation.isEmpty() && !newPinAndConfirmationMatch()) + { +#if __has_include("context/PersonalizationContext.h") + return isSmartCard || (mContext && mContext.objectCast()) +#else + return isSmartCard +#endif + //: ALL_PLATFORMS Error message if the new pin confirmation mismatches. + ? tr("The input does not match. Please choose a new Smart-eID PIN.") + //: ALL_PLATFORMS Error message if the new pin confirmation mismatches. + : tr("The input does not match. Please choose a new ID card PIN."); + } + switch (paceResult) { case CardReturnCode::OK: @@ -235,13 +323,9 @@ QString NumberModel::getInputError() const case CardReturnCode::INVALID_PIN: if (isRequestTransportPin) { - return QStringLiteral("%1

    %2") - //: INFO ALL_PLATFORMS The wrong Transport PIN was entered on the first attempt. - .arg(tr("You have entered an incorrect, five-digit Transport PIN. " - "You have two further attempts to enter the correct Transport PIN."), - //: INFO ALL_PLATFORMS - tr("Please note that you may use the five-digit Transport PIN only once to change to a six-digit ID card PIN. " - "If you already set a six-digit ID card PIN, the five-digit Transport PIN is no longer valid.")); + //: INFO ALL_PLATFORMS The wrong Transport PIN was entered on the first attempt. + return tr("You have entered an incorrect, five-digit Transport PIN. " + "You have two further attempts to enter the correct Transport PIN."); } else if (isSmartCard) { @@ -257,21 +341,17 @@ QString NumberModel::getInputError() const case CardReturnCode::INVALID_PIN_2: if (isRequestTransportPin) { - return QStringLiteral("%1

    %2") - //: INFO ALL_PLATFORMS The wrong Transport PIN was entered twice, the next attempt requires the CAN for additional verification. - .arg(tr("You have entered an incorrect, five-digit Transport PIN twice. " - "For a third attempt, the six-digit Card Access Number (CAN) must be entered first. " - "You can find your CAN in the bottom right on the front of your ID card."), - //: INFO ALL_PLATFORMS - tr("Please note that you may use the five-digit Transport PIN only once to change to a six-digit ID card PIN. " - "If you already set a six-digit ID card PIN, the five-digit Transport PIN is no longer valid.")); + //: INFO ALL_PLATFORMS The wrong Transport PIN was entered twice, the next attempt requires the CAN for additional verification. + return tr("You have entered an incorrect, five-digit Transport PIN twice. " + "For a third attempt, the six-digit Card Access Number (CAN) must be entered first. " + "You can find your CAN in the bottom right on the front of your ID card."); } else if (isSmartCard) { //: INFO ANDROID IOS The wrong Smart-eID PIN was entered twice, a third wrong attempt could invalidate the Smart-eID. return tr("You have entered an incorrect, six-digit Smart-eID PIN twice. " - "An incorrect third attempt will invalidate your Smart-eID and you will have to set it up again."); + "After the next failed attempt you will no longer be able to use your Smart-eID and will need to set it up again."); } else { @@ -284,13 +364,9 @@ QString NumberModel::getInputError() const case CardReturnCode::INVALID_PIN_3: if (isRequestTransportPin) { - return QStringLiteral("%1

    %2") - //: INFO ALL_PLATFORMS The Transport PIN was entered wrongfully three times, the ID card needs to be unlocked using the PUK. - .arg(tr("You have entered an incorrect, five-digit Transport PIN thrice, your Transport PIN is now blocked. " - "To remove the block, the ten-digit PUK must be entered first."), - //: INFO ALL_PLATFORMS - tr("Please note that you may use the five-digit Transport PIN only once to change to a six-digit ID card PIN. " - "If you already set a six-digit ID card PIN, the five-digit Transport PIN is no longer valid.")); + //: INFO ALL_PLATFORMS The Transport PIN was entered wrongfully three times, the ID card needs to be unlocked using the PUK. + return tr("You have entered an incorrect, five-digit Transport PIN thrice, your Transport PIN is now blocked. " + "To remove the block, the ten-digit PUK must be entered first."); } else if (isSmartCard) { diff --git a/src/ui/qml/NumberModel.h b/src/ui/qml/NumberModel.h index 4b0a0bf2c..959570640 100644 --- a/src/ui/qml/NumberModel.h +++ b/src/ui/qml/NumberModel.h @@ -16,21 +16,27 @@ #include #include + +class test_UIPlugInQml; + + namespace governikus { -defineEnumType(PasswordType, TRANSPORT_PIN, PIN, CAN, PUK, NEW_PIN, REMOTE_PIN, SMART_PIN, NEW_SMART_PIN, SMART_BLOCKING_CODE) +defineEnumType(PasswordType, TRANSPORT_PIN, PIN, CAN, PUK, NEW_PIN, NEW_PIN_CONFIRMATION, REMOTE_PIN, SMART_PIN, NEW_SMART_PIN, NEW_SMART_PIN_CONFIRMATION, SMART_BLOCKING_CODE) class NumberModel : public QObject { Q_OBJECT friend class Env; + friend class ::test_UIPlugInQml; Q_PROPERTY(PasswordType passwordType READ getPasswordType NOTIFY firePasswordTypeChanged) Q_PROPERTY(QString can READ getCan WRITE setCan NOTIFY fireCanChanged) Q_PROPERTY(QString pin READ getPin WRITE setPin NOTIFY firePinChanged) Q_PROPERTY(QString newPin READ getNewPin WRITE setNewPin NOTIFY fireNewPinChanged) + Q_PROPERTY(QString newPinConfirmation READ getNewPinConfirmation WRITE setNewPinConfirmation NOTIFY fireNewPinConfirmationChanged) Q_PROPERTY(QString puk READ getPuk WRITE setPuk NOTIFY firePukChanged) Q_PROPERTY(bool hasPasswordError READ hasPasswordError NOTIFY fireInputErrorChanged) Q_PROPERTY(QString inputError READ getInputError NOTIFY fireInputErrorChanged) @@ -39,11 +45,15 @@ class NumberModel private: QSharedPointer mContext; + QString mNewPin; + QString mNewPinConfirmation; NumberModel(); ~NumberModel() override = default; CardReturnCode getInputErrorCode() const; + void clearNewPinAndConfirmation(); + bool newPinAndConfirmationMatch() const; private Q_SLOTS: void onCardConnectionChanged(); @@ -61,6 +71,9 @@ class NumberModel [[nodiscard]] QString getNewPin() const; void setNewPin(const QString& pNewPin); + [[nodiscard]] QString getNewPinConfirmation() const; + void setNewPinConfirmation(const QString& pNewPinConfirmation); + Q_INVOKABLE bool commitNewPin(); [[nodiscard]] QString getPuk() const; void setPuk(const QString& pPuk); @@ -78,6 +91,7 @@ class NumberModel void fireCanChanged(); void firePinChanged(); void fireNewPinChanged(); + void fireNewPinConfirmationChanged(); void firePukChanged(); void fireInputErrorChanged(); void fireReaderInfoChanged(); diff --git a/src/ui/qml/PersonalizationModel.cpp b/src/ui/qml/PersonalizationModel.cpp index ec9c38e62..3d24f0bcd 100644 --- a/src/ui/qml/PersonalizationModel.cpp +++ b/src/ui/qml/PersonalizationModel.cpp @@ -4,6 +4,7 @@ #include "PersonalizationModel.h" +#include "GlobalStatus.h" #include "LanguageLoader.h" #if __has_include("controller/PersonalizationController.h") #include "AppSettings.h" @@ -11,8 +12,6 @@ #include "controller/PersonalizationController.h" #endif -#include - using namespace governikus; @@ -22,7 +21,7 @@ PersonalizationModel::PersonalizationModel() } -void PersonalizationModel::startWorkflow() +void PersonalizationModel::startWorkflow() const { #if __has_include("controller/PersonalizationController.h") const bool useTestUri = Env::getSingleton()->getGeneralSettings().useSelfAuthTestUri(); @@ -58,15 +57,35 @@ int PersonalizationModel::getRemainingAttempts() const QString PersonalizationModel::getRestrictionDate() const { - QDate restrictionDate = QDate::currentDate(); #if __has_include("context/PersonalizationContext.h") if (mContext) { - restrictionDate = restrictionDate.addDays(qAbs(mContext->getRemainingDays())); + return mContext->getRestrictionDate(); } #endif - const auto& usedLocale = LanguageLoader::getInstance().getUsedLocale(); - return usedLocale.toString(restrictionDate, QStringLiteral("d. MMMM yyyy")); + return QStringLiteral("N/A"); +} + + +QString PersonalizationModel::getBlockingPeriodMessage() const +{ + const auto& restrictionDate = getRestrictionDate(); + const GlobalStatus status = {GlobalStatus::Code::Workflow_Smart_eID_Personalization_Denied, + {GlobalStatus::ExternalInformation::PERSONALIZATION_RESTRICTION_DATE, restrictionDate} + }; + return status.toErrorDescription(); +} + + +bool PersonalizationModel::isApplet() const +{ +#if __has_include("context/PersonalizationContext.h") + return mContext->getSmartEidType() == SmartEidType::APPLET; + +#else + return false; + +#endif } @@ -81,6 +100,7 @@ void PersonalizationModel::resetPersonalizationContext(const QSharedPointer getSupportedReaderPlugInTypes() const override; public Q_SLOTS: void onTranslationChanged(); Q_SIGNALS: - void fireStartWorkflow(const QSharedPointer& pRequest); + void fireStartWorkflow(const QSharedPointer& pRequest) const; void fireBlockingCodeChanged(); void fireRemainingAttemptsChanged(); void fireRestrictionDateChanged(); + void fireIsAppletChanged(); }; } // namespace governikus diff --git a/src/ui/qml/PlatformTools_osx.mm b/src/ui/qml/PlatformTools_osx.mm index 6756d9e05..33a326a87 100644 --- a/src/ui/qml/PlatformTools_osx.mm +++ b/src/ui/qml/PlatformTools_osx.mm @@ -39,15 +39,14 @@ void ensureNotificationPermission(std::function pCallback) { #ifdef QT_NO_DEBUG - if (@available(macOS 10.14, *)) - { - UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter]; - [center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings* _Nonnull settings){ - if (settings.authorizationStatus == UNAuthorizationStatusAuthorized) - { - pCallback(); - return; - } + UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter]; + [center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings* _Nonnull settings){ + if (settings.authorizationStatus == UNAuthorizationStatusAuthorized) + { + pCallback(); + } + else + { const auto& requestedOptions = UNAuthorizationOptionProvidesAppNotificationSettings & UNAuthorizationOptionAlert; [center requestAuthorizationWithOptions:requestedOptions completionHandler:^(BOOL granted, NSError* _Nullable error){ if (error != nil) @@ -59,8 +58,8 @@ void ensureNotificationPermission(std::function pCallback) pCallback(); } }]; - }]; - } + } + }]; #else Q_UNUSED(pCallback) #endif @@ -70,22 +69,19 @@ void ensureNotificationPermission(std::function pCallback) void PlatformTools::postNotification(const QString& pTitle, const QString& pMessage) { #ifdef QT_NO_DEBUG - if (@available(macOS 10.14, *)) - { - ensureNotificationPermission([pTitle, pMessage]{ - UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter]; - UNMutableNotificationContent* content = [[UNMutableNotificationContent alloc] init]; - content.title = pTitle.toNSString(); - content.body = pMessage.toNSString(); - UNNotificationRequest* request = [UNNotificationRequest requestWithIdentifier:@"AA2Notification" content:content trigger:nil]; - [center addNotificationRequest:request withCompletionHandler:^(NSError* _Nullable error){ - if (error != nil) - { - qCDebug(gui) << "Failed to post notification:" << error.localizedDescription; - } - }]; - }); - } + ensureNotificationPermission([pTitle, pMessage]{ + UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter]; + UNMutableNotificationContent* content = [[UNMutableNotificationContent alloc] init]; + content.title = pTitle.toNSString(); + content.body = pMessage.toNSString(); + UNNotificationRequest* request = [UNNotificationRequest requestWithIdentifier:@"AA2Notification" content:content trigger:nil]; + [center addNotificationRequest:request withCompletionHandler:^(NSError* _Nullable error){ + if (error != nil) + { + qCDebug(gui) << "Failed to post notification:" << error.localizedDescription; + } + }]; + }); #else Q_UNUSED(pTitle) Q_UNUSED(pMessage) diff --git a/src/ui/qml/ProviderCategoryFilterModel.cpp b/src/ui/qml/ProviderCategoryFilterModel.cpp deleted file mode 100644 index 7fd366e5c..000000000 --- a/src/ui/qml/ProviderCategoryFilterModel.cpp +++ /dev/null @@ -1,216 +0,0 @@ -/** - * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany - */ - -#include "ProviderCategoryFilterModel.h" - - -using namespace governikus; - -QString ProviderCategoryFilterModel::getSearchString() const -{ - return mSearchString; -} - - -void ProviderCategoryFilterModel::updateSearchString(const QString& pSearchString) -{ - const QString& newSearchString = pSearchString.trimmed(); - if (mSearchString != newSearchString) - { - mSearchString = newSearchString; - invalidateFilter(); - Q_EMIT fireCriteriaChanged(); - } -} - - -QStringList ProviderCategoryFilterModel::getSelectedCategories() const -{ - return mSelectedCategories; -} - - -int ProviderCategoryFilterModel::getAdditionalResultCount() const -{ - if (mSearchString.isEmpty() || mSelectedCategories.isEmpty()) - { - return 0; - } - - const auto excludedCategories = getFilteredProviderCategories(); - if (excludedCategories.isEmpty()) - { - return 0; - } - - return resultCountForFilter(excludedCategories, mSearchString); -} - - -QStringList ProviderCategoryFilterModel::getFilteredProviderCategories() const -{ - auto filteredCats = ProviderModel::getProviderCategories(); - filteredCats.removeOne(QStringLiteral("all")); - for (const auto& cat : std::as_const(mSelectedCategories)) - { - filteredCats.removeOne(cat); - } - return filteredCats; -} - - -int ProviderCategoryFilterModel::resultCountForFilter(const QStringList& pCategories, const QString& pSearchString) const -{ - const QAbstractItemModel* const model = sourceModel(); - Q_ASSERT(model != nullptr); - const int rowCount = model->rowCount(); - - int matchCount = 0; - for (int sourceRow = 0; sourceRow < rowCount; ++sourceRow) - { - if (rowMatchesFilter(sourceRow, QModelIndex(), pCategories, pSearchString, false)) - { - matchCount++; - } - } - - return matchCount; -} - - -bool ProviderCategoryFilterModel::filterAcceptsRow(int pSourceRow, const QModelIndex& pSourceParent) const -{ - return rowMatchesFilter(pSourceRow, pSourceParent, mSelectedCategories, mSearchString, mProviderModel.getIncludeCategories()); -} - - -bool ProviderCategoryFilterModel::rowMatchesFilter(int pSourceRow, const QModelIndex& pSourceParent, const QStringList& pSelectedCategories, const QString& pSearchString, bool pMatchCategoryType) const -{ - const QAbstractItemModel* const model = sourceModel(); - Q_ASSERT(model != nullptr); - const QModelIndex idx = model->index(pSourceRow, 0, pSourceParent); - - const QString providerCategory = model->data(idx, ProviderModel::CATEGORY).toString().toLower(); - bool isRowInSelectedCategory = pSelectedCategories.isEmpty() || - pSelectedCategories.contains(QLatin1String("all")) || - pSelectedCategories.contains(providerCategory); - - if (!isRowInSelectedCategory) - { - return false; - } - - const QString type = model->data(idx, ProviderModel::TYPE).toString(); - if (type == QLatin1String("category")) - { - if (!pMatchCategoryType) - { - return false; - } - - if (!pSearchString.isEmpty() && providerCategory == QLatin1String("all")) - { - return false; - } - - return resultCountForFilter({providerCategory}, pSearchString) > 0; - } - - if (pSearchString.isEmpty()) - { - return !pMatchCategoryType; - } - - const QString display = model->data(idx, Qt::DisplayRole).toString(); - const QString shortname = model->data(idx, ProviderModel::SHORTNAME).toString(); - const QString longname = model->data(idx, ProviderModel::LONGNAME).toString(); - const QString address = model->data(idx, ProviderModel::ADDRESS).toString(); - const QString homepage = model->data(idx, ProviderModel::HOMEPAGE).toString(); - const QString longdescription = model->data(idx, ProviderModel::LONGDESCRIPTION).toString(); - - return display.contains(pSearchString, Qt::CaseInsensitive) || - shortname.contains(pSearchString, Qt::CaseInsensitive) || - longname.contains(pSearchString, Qt::CaseInsensitive) || - address.contains(pSearchString, Qt::CaseInsensitive) || - homepage.contains(pSearchString, Qt::CaseInsensitive) || - longdescription.contains(pSearchString, Qt::CaseInsensitive); -} - - -ProviderCategoryFilterModel::ProviderCategoryFilterModel() : - mProviderModel() -{ - QSortFilterProxyModel::setSourceModel(&mProviderModel); - - QSortFilterProxyModel::sort(0); - sortByCategoryFirst(false); - setSortCaseSensitivity(Qt::CaseInsensitive); -} - - -void ProviderCategoryFilterModel::setIncludeCategoriesInModel(bool pIncludeCategories) -{ - mProviderModel.setIncludeCategories(pIncludeCategories); -} - - -void ProviderCategoryFilterModel::sortByCategoryFirst(bool pEnabled) -{ - setSortRole(pEnabled ? ProviderModel::SORT_ROLE : ProviderModel::SHORTNAME); -} - - -void ProviderCategoryFilterModel::setCategorySelection(const QString& pCategory) -{ - mSelectedCategories.clear(); - - if (!pCategory.isEmpty()) - { - mSelectedCategories += pCategory.toLower(); - } - invalidateFilter(); - Q_EMIT fireCriteriaChanged(); -} - - -void ProviderCategoryFilterModel::updateCategorySelection(const QString& pCategory, bool pSelected) -{ - const auto categoryCount = mSelectedCategories.count(); - if (pSelected) - { - mSelectedCategories += pCategory.toLower(); - } - else - { - mSelectedCategories.removeAll(pCategory.toLower()); - } - - mSelectedCategories.removeDuplicates(); - if (mSelectedCategories.count() != categoryCount) - { - invalidateFilter(); - Q_EMIT fireCriteriaChanged(); - } -} - - -void ProviderCategoryFilterModel::addAdditionalResultCategories() -{ - bool filterChanged = false; - const auto excludedCategories = getFilteredProviderCategories(); - for (const QString& category : excludedCategories) - { - if (resultCountForFilter({category}, mSearchString) > 0) - { - filterChanged = true; - mSelectedCategories += category; - } - } - - if (filterChanged) - { - invalidateFilter(); - Q_EMIT fireCriteriaChanged(); - } -} diff --git a/src/ui/qml/ProviderCategoryFilterModel.h b/src/ui/qml/ProviderCategoryFilterModel.h deleted file mode 100644 index ce7ce3b52..000000000 --- a/src/ui/qml/ProviderCategoryFilterModel.h +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany - */ - -/*! - * \brief Model implementation for the providers. - */ - -#pragma once - -#include "ProviderModel.h" - -#include -#include -#include -#include - -class test_ProviderCategoryFilterModel; - -namespace governikus -{ - -class ProviderCategoryFilterModel - : public QSortFilterProxyModel -{ - Q_OBJECT - Q_PROPERTY(QString searchString READ getSearchString WRITE updateSearchString NOTIFY fireCriteriaChanged) - Q_PROPERTY(QStringList categories READ getSelectedCategories NOTIFY fireCriteriaChanged) - Q_PROPERTY(int rowCount READ rowCount NOTIFY fireCriteriaChanged) - Q_PROPERTY(int additionalResultCount READ getAdditionalResultCount NOTIFY fireCriteriaChanged) - friend class ::test_ProviderCategoryFilterModel; - - private: - QString mSearchString; - QStringList mSelectedCategories; - - ProviderModel mProviderModel; - - [[nodiscard]] QString getSearchString() const; - void updateSearchString(const QString& pSearchString); - [[nodiscard]] QStringList getSelectedCategories() const; - [[nodiscard]] int getAdditionalResultCount() const; - [[nodiscard]] QStringList getFilteredProviderCategories() const; - [[nodiscard]] int resultCountForFilter(const QStringList& pCategories, const QString& pSearchString) const; - [[nodiscard]] bool rowMatchesFilter(int pSourceRow, const QModelIndex& pSourceParent, const QStringList& pSelectedCategories, const QString& pSearchString, bool pMatchCategoryType) const; - - protected: - [[nodiscard]] bool filterAcceptsRow(int pSourceRow, const QModelIndex& pSourceParent) const override; - - public: - ProviderCategoryFilterModel(); - ~ProviderCategoryFilterModel() override = default; - - Q_INVOKABLE void setIncludeCategoriesInModel(bool pIncludeCategories); - Q_INVOKABLE void sortByCategoryFirst(bool pEnabled); - Q_INVOKABLE void setCategorySelection(const QString& pCategory); - Q_INVOKABLE void updateCategorySelection(const QString& pCategory, bool pSelected); - Q_INVOKABLE void addAdditionalResultCategories(); - - Q_SIGNALS: - void fireCriteriaChanged(); -}; - - -} // namespace governikus diff --git a/src/ui/qml/ProviderModel.cpp b/src/ui/qml/ProviderModel.cpp deleted file mode 100644 index 76aa637f0..000000000 --- a/src/ui/qml/ProviderModel.cpp +++ /dev/null @@ -1,253 +0,0 @@ -/** - * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany - */ - -#include "ProviderModel.h" - -#include "ProviderConfiguration.h" - - -using namespace governikus; - - -QString ProviderModel::createCostString(double pCostsPerMinute, double pCostsPerCall) -{ - if (pCostsPerMinute > 0.0) - { - //: INFO ALL_PLATFORMS Unit for expenses for calling the hotline (per minute). - return tr("%1/min").arg(createAmountString(pCostsPerMinute)); - } - if (pCostsPerCall > 0.0) - { - //: INFO ALL_PLATFORMS Unit for expenses for calling the hotline (per call). - return tr("%1/call").arg(createAmountString(pCostsPerCall)); - } - return QString(); -} - - -QString ProviderModel::createAmountString(double pCents) -{ - //: INFO ALL_PLATFORMS Currency unit for expenses for calling the hotline (Euro/Cent). - return pCents > 100 ? tr("%1 EUR").arg(pCents / 100.0) : tr("%1 ct").arg(pCents); -} - - -void ProviderModel::updateConnections() -{ - for (const auto& connection : std::as_const(mConnections)) - { - disconnect(connection); - } - mConnections.clear(); - - const auto& providerConfigurationInfos = Env::getSingleton()->getProviderConfigurationInfos(); - mConnections.reserve(providerConfigurationInfos.size() * 2); - for (int i = 0; i < providerConfigurationInfos.size(); i++) - { - const auto& provider = providerConfigurationInfos.at(i); - const QModelIndex& modelIndex = createIndex(i, 0); - - mConnections += connect(provider.getIcon().data(), &UpdatableFile::fireUpdated, this, [this, modelIndex] { - Q_EMIT dataChanged(modelIndex, modelIndex, {ProviderRoles::ICON}); - }); - mConnections += connect(provider.getImage().data(), &UpdatableFile::fireUpdated, this, [this, modelIndex] { - Q_EMIT dataChanged(modelIndex, modelIndex, {ProviderRoles::IMAGE}); - }); - } -} - - -void ProviderModel::onProvidersChanged() -{ - beginResetModel(); - updateConnections(); - endResetModel(); -} - - -ProviderModel::ProviderModel(QObject* pParent) - : QAbstractListModel(pParent) - , mIncludeCategories(false) -{ - updateConnections(); - connect(Env::getSingleton(), &ProviderConfiguration::fireUpdated, this, &ProviderModel::onProvidersChanged); -} - - -int ProviderModel::rowCount(const QModelIndex&) const -{ - return Env::getSingleton()->getProviderConfigurationInfos().size() + (mIncludeCategories ? getProviderCategories().size() : 0); -} - - -QVariant ProviderModel::data(const QModelIndex& pIndex, int pRole) const -{ - if (!pIndex.isValid()) - { - return {}; - } - - const auto& providerConfiguration = Env::getSingleton(); - const auto& providerConfigurationInfos = providerConfiguration->getProviderConfigurationInfos(); - - if (pIndex.row() >= providerConfigurationInfos.size()) - { - const auto categoryRow = pIndex.row() - providerConfigurationInfos.size(); - const auto category = getProviderCategories().at(categoryRow); - - switch (pRole) - { - case TYPE: - return QStringLiteral("category"); - - case CATEGORY: - case SORT_ROLE: - return category; - - default: - return QVariant(); - } - } - - const auto& provider = providerConfigurationInfos.at(pIndex.row()); - - if (pRole == TYPE) - { - return QStringLiteral("provider"); - } - if (pRole == Qt::DisplayRole) - { - return provider.getLongName().toString(); - } - if (pRole == CATEGORY) - { - return provider.getCategory(); - } - if (pRole == SHORTNAME) - { - return provider.getShortName().toString(); - } - if (pRole == LONGNAME) - { - return provider.getLongName().toString(); - } - if (pRole == LONGDESCRIPTION) - { - return provider.getLongDescription().toString(); - } - if (pRole == ADDRESS) - { - return provider.getAddress(); - } - if (pRole == ADDRESS_DOMAIN) - { - return provider.getAddressDomain(); - } - if (pRole == HOMEPAGE) - { - return provider.getHomepage(); - } - if (pRole == HOMEPAGE_BASE) - { - return provider.getHomepageBase(); - } - if (pRole == PHONE) - { - return provider.getPhone(); - } - if (pRole == PHONE_COST) - { - const auto& cost = providerConfiguration->getCallCost(provider); - return createCostString(cost); - } - if (pRole == EMAIL) - { - return provider.getEMail(); - } - if (pRole == POSTALADDRESS) - { - return provider.getPostalAddress(); - } - if (pRole == ICON) - { - return provider.getIcon()->lookupUrl(); - } - if (pRole == IMAGE) - { - return provider.getImage()->lookupUrl(); - } - if (pRole == SORT_ROLE) - { - const auto& value = provider.getLongName(); - return provider.getCategory() + (value.isEmpty() ? provider.getShortName() : value); - } - - return QVariant(); -} - - -QHash ProviderModel::roleNames() const -{ - QHash roles = QAbstractListModel::roleNames(); - roles.insert(CATEGORY, "providerCategory"); - roles.insert(SHORTNAME, "providerShortName"); - roles.insert(LONGNAME, "providerLongName"); - roles.insert(LONGDESCRIPTION, "providerLongDescription"); - roles.insert(ADDRESS, "providerAddress"); - roles.insert(ADDRESS_DOMAIN, "providerAddressDomain"); - roles.insert(HOMEPAGE, "providerHomepage"); - roles.insert(HOMEPAGE_BASE, "providerHomepageBase"); - roles.insert(PHONE, "providerPhone"); - roles.insert(PHONE_COST, "providerPhoneCost"); - roles.insert(EMAIL, "providerEmail"); - roles.insert(POSTALADDRESS, "providerPostalAddress"); - roles.insert(ICON, "providerIcon"); - roles.insert(IMAGE, "providerImage"); - roles.insert(TYPE, "itemType"); - - return roles; -} - - -void ProviderModel::setIncludeCategories(bool pIncludeCategories) -{ - beginResetModel(); - mIncludeCategories = pIncludeCategories; - endResetModel(); -} - - -bool ProviderModel::getIncludeCategories() const -{ - return mIncludeCategories; -} - - -const QStringList& ProviderModel::getProviderCategories() -{ - static QStringList cats({QStringLiteral("all"), QStringLiteral("citizen"), QStringLiteral("insurance"), QStringLiteral("finance"), QStringLiteral("other")}); - return cats; -} - - -QString ProviderModel::createCostString(const CallCost& pCosts) -{ - if (pCosts.isNull()) - { - return QString(); - } - - QString msg; - if (pCosts.getFreeSeconds() > 0) - { - //: INFO ALL_PLATFORMS Free of charge seconds when calling the hotline. - msg += tr("%1 seconds free, afterwards ").arg(pCosts.getFreeSeconds()); - } - //: INFO ALL_PLATFORMS Land line charges when calling the hotline. - msg += tr("landline costs %1; ").arg(createCostString(pCosts.getLandlineCentsPerMinute(), pCosts.getLandlineCentsPerCall())); - const auto mobileCosts = createCostString(pCosts.getMobileCentsPerMinute(), pCosts.getMobileCentsPerCall()); - //: INFO ALL_PLATFORMS Cell phone charges when calling the hotline. - msg += mobileCosts.isEmpty() ? tr("mobile costs may vary.") : tr("mobile costs %1").arg(mobileCosts); - return msg; -} diff --git a/src/ui/qml/ProviderModel.h b/src/ui/qml/ProviderModel.h deleted file mode 100644 index 4ba072171..000000000 --- a/src/ui/qml/ProviderModel.h +++ /dev/null @@ -1,75 +0,0 @@ -/** - * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany - */ - -/*! - * \brief Model implementation for the providers. - */ - -#pragma once - -#include "CallCost.h" - -#include -#include -#include - - -namespace governikus -{ - -class ProviderModel - : public QAbstractListModel -{ - Q_OBJECT - - static QString createCostString(double pCostsPerMinute, double pCostsPerCall); - static QString createAmountString(double pCents); - - private: - QVector mConnections; - bool mIncludeCategories; - - void updateConnections(); - - private Q_SLOTS: - void onProvidersChanged(); - - public: - enum ProviderRoles - { - CATEGORY = Qt::UserRole + 1, - SHORTNAME, - LONGNAME, - LONGDESCRIPTION, - ADDRESS, - ADDRESS_DOMAIN, - HOMEPAGE, - HOMEPAGE_BASE, - PHONE, - PHONE_COST, - EMAIL, - POSTALADDRESS, - ICON, - IMAGE, - SORT_ROLE, - TYPE - }; - - explicit ProviderModel(QObject* pParent = nullptr); - ~ProviderModel() override = default; - - [[nodiscard]] int rowCount(const QModelIndex&) const override; - [[nodiscard]] QVariant data(const QModelIndex& pIndex, int pRole = Qt::DisplayRole) const override; - [[nodiscard]] QHash roleNames() const override; - - void setIncludeCategories(bool pIncludeCategories); - [[nodiscard]] bool getIncludeCategories() const; - - [[nodiscard]] static const QStringList& getProviderCategories(); - - [[nodiscard]] static QString createCostString(const CallCost& pCosts); -}; - - -} // namespace governikus diff --git a/src/ui/qml/ProviderNameFilterModel.cpp b/src/ui/qml/ProviderNameFilterModel.cpp deleted file mode 100644 index d7664b387..000000000 --- a/src/ui/qml/ProviderNameFilterModel.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/** - * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany - */ - -#include "ProviderNameFilterModel.h" - -#include "AppSettings.h" -#include "Env.h" -#include "HistoryModel.h" -#include "HistorySettings.h" -#include "ProviderConfiguration.h" -#include "ProviderModel.h" - -#include - -using namespace governikus; - - -bool ProviderNameFilterModel::filterAcceptsRow(int pSourceRow, const QModelIndex& /* pSourceParent */) const -{ - const auto* const dataSourceModel = qobject_cast(sourceModel()); - if (dataSourceModel == nullptr) - { - return false; - } - - const auto& infos = Env::getSingleton()->getHistorySettings().getHistoryInfos(); - if (pSourceRow >= infos.size()) - { - return false; - } - - const auto& entry = infos.at(pSourceRow); - return mProvider.matchWithSubjectUrl(entry.getSubjectUrl()); -} - - -ProviderNameFilterModel::ProviderNameFilterModel() - : mProvider() -{ -} - - -void ProviderNameFilterModel::setProviderAddress(const QString& pProviderAddress) -{ - if (mProvider.getAddress() != pProviderAddress) - { - const auto& providers = Env::getSingleton()->getProviderConfigurationInfos(); - for (const auto& provider : providers) - { - if (provider.getAddress() == pProviderAddress) - { - mProvider = provider; - - invalidateFilter(); - - return; - } - } - - // If we get here, no provider for pProviderAddress was found in the settings. - qWarning() << "Cannot select provider with address" << pProviderAddress; - } -} diff --git a/src/ui/qml/ProviderNameFilterModel.h b/src/ui/qml/ProviderNameFilterModel.h deleted file mode 100644 index bbbde08b1..000000000 --- a/src/ui/qml/ProviderNameFilterModel.h +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany - */ - -#pragma once - -#include "ProviderConfigurationInfo.h" - -#include -#include - -class test_ProviderNameFilterModel; - -namespace governikus -{ - - -class ProviderNameFilterModel - : public QSortFilterProxyModel -{ - Q_OBJECT - friend class ::test_ProviderNameFilterModel; - - private: - ProviderConfigurationInfo mProvider; - - protected: - bool filterAcceptsRow(int pSourceRow, const QModelIndex& pSourceParent) const override; - - public: - ProviderNameFilterModel(); - - - Q_INVOKABLE void setProviderAddress(const QString& pProviderAddress); -}; - -} // namespace governikus diff --git a/src/ui/qml/ReaderModel.cpp b/src/ui/qml/ReaderModel.cpp index 19b65e4b5..5833c32a3 100644 --- a/src/ui/qml/ReaderModel.cpp +++ b/src/ui/qml/ReaderModel.cpp @@ -5,7 +5,6 @@ #include "ReaderModel.h" #include "Env.h" -#include "HelpAction.h" #include "LanguageLoader.h" #include "ReaderConfiguration.h" #include "ReaderManager.h" @@ -20,27 +19,23 @@ using namespace governikus; -ReaderModel::ReaderModel(QObject* pParent) - : QAbstractListModel(pParent) - , mKnownDrivers() - , mConnectedReaders() - , mConnectedReadersUpdateTime() - , mSortedModel() +QString ReaderModel::getLastUpdatedInformation() const { - const ReaderManager* const readerManager = Env::getSingleton(); - connect(readerManager, &ReaderManager::fireReaderAdded, this, &ReaderModel::onUpdateContent); - connect(readerManager, &ReaderManager::fireReaderRemoved, this, &ReaderModel::onUpdateContent); - connect(readerManager, &ReaderManager::fireStatusChanged, this, &ReaderModel::onUpdateContent); - connect(Env::getSingleton(), &ReaderConfiguration::fireUpdated, this, &ReaderModel::onUpdateContent); -#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) - connect(Env::getSingleton(), &ReaderDetector::fireReaderChangeDetected, this, &ReaderModel::onUpdateContent); -#endif + if (!mConnectedReadersUpdateTime.isValid()) + { + return QString(); + } - mSortedModel.setSourceModel(this); - QQmlEngine::setObjectOwnership(&mSortedModel, QQmlEngine::CppOwnership); - connect(this, &ReaderModel::fireModelChanged, &mSortedModel, &SortedReaderModel::onDataChanged); + //: LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString + const auto& updateTime = LanguageLoader::getInstance().getUsedLocale().toString(mConnectedReadersUpdateTime, tr("hh:mm:ss AP")); + //: LABEL ALL_PLATFORMS + return tr("The list of card readers was last updated at %1.").arg(updateTime); +} - onUpdateContent(); + +SortedReaderModel* ReaderModel::getSortedModel() +{ + return &mSortedModel; } @@ -93,77 +88,6 @@ bool ReaderModel::indexIsValid(const QModelIndex& pIndex) const } -void ReaderModel::onUpdateContent() -{ - beginResetModel(); - - collectReaderData(); - mConnectedReadersUpdateTime = QTime::currentTime(); - - endResetModel(); - - Q_EMIT fireModelChanged(); -} - - -void ReaderModel::onTranslationChanged() -{ - onUpdateContent(); -} - - -int ReaderModel::rowCount(const QModelIndex&) const -{ - return mConnectedReaders.size(); -} - - -QVariant ReaderModel::data(const QModelIndex& pIndex, int pRole) const -{ - if (!indexIsValid(pIndex)) - { - return QVariant(); - } - - const auto& reader = mConnectedReaders.at(pIndex.row()); - switch (pRole) - { - case READER_NAME: - return reader.getName(); - - case READER_IMAGE_PATH: - return getReaderImageUrl(pIndex); - - case READER_HTML_DESCRIPTION: - return getHTMLDescription(pIndex); - - case READER_DRIVER_URL: - return mConnectedReaders.at(pIndex.row()).getUrl(); - - case READER_SUPPORTED: - return isSupportedReader(pIndex); - - case READER_INSTALLED: - return isInstalledReader(pIndex); - - default: - return QVariant(); - } -} - - -QHash ReaderModel::roleNames() const -{ - QHash roles; - roles.insert(READER_NAME, "readerName"); - roles.insert(READER_IMAGE_PATH, "readerImagePath"); - roles.insert(READER_HTML_DESCRIPTION, "readerHTMLDescription"); - roles.insert(READER_SUPPORTED, "readerSupported"); - roles.insert(READER_INSTALLED, "readerInstalled"); - return roles; -} - - QUrl ReaderModel::getReaderImageUrl(const QModelIndex& pIndex) const { return mConnectedReaders.at(pIndex.row()).getIcon()->lookupUrl(); @@ -193,7 +117,7 @@ QString ReaderModel::getHTMLDescription(const QModelIndex& pIndex) const return tr("Driver installed"); } - if (!Env::getSingleton()->isScanRunning(ReaderManagerPlugInType::PCSC)) + if (!Env::getSingleton()->getPlugInInfo(ReaderManagerPlugInType::PCSC).isScanRunning()) { //: LABEL ALL_PLATFORMS return tr("The smartcard service of your system is not reachable."); @@ -213,17 +137,6 @@ QString ReaderModel::getHTMLDescription(const QModelIndex& pIndex) const } -QString ReaderModel::getEmptyListDescriptionString() const -{ - const QString& onlineHelpSection = QStringLiteral("settingsPcscReader"); - const QString& url = HelpAction::getOnlineUrl(onlineHelpSection); - //: Is embedded in a sentence. - const QString& hyperlink = QStringLiteral("%2").arg(url, tr("online help")); - //: INFO ALL_PLATFORMS No card reader was found, the message contains a link to the installation section of the manual. - return tr("No connected card reader found. See %1 for installation of card readers.").arg(hyperlink); -} - - bool ReaderModel::isSupportedReader(const QModelIndex& pIndex) const { if (!indexIsValid(pIndex)) @@ -248,21 +161,96 @@ bool ReaderModel::isInstalledReader(const QModelIndex& pIndex) const } -QString ReaderModel::getLastUpdatedInformation() const +void ReaderModel::onUpdateContent() { - if (!mConnectedReadersUpdateTime.isValid()) + beginResetModel(); + + collectReaderData(); + mConnectedReadersUpdateTime = QTime::currentTime(); + + endResetModel(); + + Q_EMIT fireModelChanged(); +} + + +ReaderModel::ReaderModel(QObject* pParent) + : QAbstractListModel(pParent) + , mKnownDrivers() + , mConnectedReaders() + , mConnectedReadersUpdateTime() + , mSortedModel() +{ + const ReaderManager* const readerManager = Env::getSingleton(); + connect(readerManager, &ReaderManager::fireReaderAdded, this, &ReaderModel::onUpdateContent); + connect(readerManager, &ReaderManager::fireReaderRemoved, this, &ReaderModel::onUpdateContent); + connect(readerManager, &ReaderManager::fireStatusChanged, this, &ReaderModel::onUpdateContent); + connect(Env::getSingleton(), &ReaderConfiguration::fireUpdated, this, &ReaderModel::onUpdateContent); +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) + connect(Env::getSingleton(), &ReaderDetector::fireReaderChangeDetected, this, &ReaderModel::onUpdateContent); +#endif + + mSortedModel.setSourceModel(this); + QQmlEngine::setObjectOwnership(&mSortedModel, QQmlEngine::CppOwnership); + connect(this, &ReaderModel::fireModelChanged, &mSortedModel, &SortedReaderModel::onDataChanged); + + onUpdateContent(); +} + + +int ReaderModel::rowCount(const QModelIndex&) const +{ + return static_cast(mConnectedReaders.size()); +} + + +QVariant ReaderModel::data(const QModelIndex& pIndex, int pRole) const +{ + if (!indexIsValid(pIndex)) { - return QString(); + return QVariant(); } - //: LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString - const auto& updateTime = LanguageLoader::getInstance().getUsedLocale().toString(mConnectedReadersUpdateTime, tr("hh:mm:ss AP")); - //: LABEL ALL_PLATFORMS - return tr("The list of card readers was last updated at %1.").arg(updateTime); + const auto& reader = mConnectedReaders.at(pIndex.row()); + switch (pRole) + { + case READER_NAME: + return reader.getName(); + + case READER_IMAGE_PATH: + return getReaderImageUrl(pIndex); + + case READER_HTML_DESCRIPTION: + return getHTMLDescription(pIndex); + + case READER_DRIVER_URL: + return mConnectedReaders.at(pIndex.row()).getUrl(); + + case READER_SUPPORTED: + return isSupportedReader(pIndex); + + case READER_INSTALLED: + return isInstalledReader(pIndex); + + default: + return QVariant(); + } } -SortedReaderModel* ReaderModel::getSortedModel() +QHash ReaderModel::roleNames() const { - return &mSortedModel; + QHash roles; + roles.insert(READER_NAME, "readerName"); + roles.insert(READER_IMAGE_PATH, "readerImagePath"); + roles.insert(READER_HTML_DESCRIPTION, "readerHTMLDescription"); + roles.insert(READER_SUPPORTED, "readerSupported"); + roles.insert(READER_INSTALLED, "readerInstalled"); + return roles; +} + + +void ReaderModel::onTranslationChanged() +{ + onUpdateContent(); } diff --git a/src/ui/qml/ReaderModel.h b/src/ui/qml/ReaderModel.h index cc091f066..d9164486d 100644 --- a/src/ui/qml/ReaderModel.h +++ b/src/ui/qml/ReaderModel.h @@ -26,7 +26,6 @@ class ReaderModel { Q_OBJECT - Q_PROPERTY(QString emptyListDescriptionString READ getEmptyListDescriptionString NOTIFY fireModelChanged) Q_PROPERTY(QString lastUpdatedInformation READ getLastUpdatedInformation NOTIFY fireModelChanged) Q_PROPERTY(SortedReaderModel * sortedModel READ getSortedModel CONSTANT) @@ -36,12 +35,18 @@ class ReaderModel QTime mConnectedReadersUpdateTime; SortedReaderModel mSortedModel; - [[nodiscard]] QString getStatus(const ReaderConfigurationInfo& pReaderConfigurationInfo) const; - void collectReaderData(); + [[nodiscard]] QString getLastUpdatedInformation() const; + [[nodiscard]] SortedReaderModel* getSortedModel(); + void collectReaderData(); [[nodiscard]] bool indexIsValid(const QModelIndex& pIndex) const; - [[nodiscard]] QUrl getReaderImageUrl(const QModelIndex& pIndex) const; + [[nodiscard]] QString getHTMLDescription(const QModelIndex& pIndex) const; + [[nodiscard]] bool isSupportedReader(const QModelIndex& pIndex) const; + [[nodiscard]] bool isInstalledReader(const QModelIndex& pIndex) const; + + private Q_SLOTS: + void onUpdateContent(); public: enum UserRoles @@ -60,17 +65,6 @@ class ReaderModel [[nodiscard]] QVariant data(const QModelIndex& pIndex, int pRole = Qt::DisplayRole) const override; [[nodiscard]] QHash roleNames() const override; - [[nodiscard]] QString getHTMLDescription(const QModelIndex& pIndex) const; - [[nodiscard]] QString getEmptyListDescriptionString() const; - [[nodiscard]] bool isSupportedReader(const QModelIndex& pIndex) const; - [[nodiscard]] bool isInstalledReader(const QModelIndex& pIndex) const; - [[nodiscard]] QString getLastUpdatedInformation() const; - - [[nodiscard]] SortedReaderModel* getSortedModel(); - - private Q_SLOTS: - void onUpdateContent(); - public Q_SLOTS: void onTranslationChanged(); diff --git a/src/ui/qml/ReaderScanEnabler.cpp b/src/ui/qml/ReaderScanEnabler.cpp index e86c5ab5b..d26406a77 100644 --- a/src/ui/qml/ReaderScanEnabler.cpp +++ b/src/ui/qml/ReaderScanEnabler.cpp @@ -61,7 +61,7 @@ void ReaderScanEnabler::enableScanIfVisible() bool ReaderScanEnabler::isScanRunning() const { - return Env::getSingleton()->isScanRunning(mPlugInType); + return Env::getSingleton()->getPlugInInfo(mPlugInType).isScanRunning(); } diff --git a/src/ui/qml/ReaderScanEnabler.h b/src/ui/qml/ReaderScanEnabler.h index c5c756799..42e7b425a 100644 --- a/src/ui/qml/ReaderScanEnabler.h +++ b/src/ui/qml/ReaderScanEnabler.h @@ -28,7 +28,7 @@ class ReaderScanEnabler void enableScan(const bool pEnable); void enableScanIfVisible(); - bool isScanRunning() const; + [[nodiscard]] bool isScanRunning() const; private Q_SLOTS: void onStatusChanged(const ReaderManagerPlugInInfo& pInfo); diff --git a/src/ui/qml/ReleaseInformationModel.cpp b/src/ui/qml/ReleaseInformationModel.cpp index e72e87319..16dca1973 100644 --- a/src/ui/qml/ReleaseInformationModel.cpp +++ b/src/ui/qml/ReleaseInformationModel.cpp @@ -26,7 +26,7 @@ FormattedTextModel* ReleaseInformationModel::createModel(const ReleaseInformatio fileList << pInformation.pathAnnouncements(); fileList << pInformation.pathIssues(); - const int emptyFilepathCount = fileList.removeAll(QString()); + const auto emptyFilepathCount = fileList.removeAll(QString()); if (emptyFilepathCount > 0) { qCWarning(qml) << "Missing" << emptyFilepathCount << "release information file(s)"; @@ -98,7 +98,7 @@ FormattedTextModel* ReleaseInformationModel::getUpdateRelease() const } -void ReleaseInformationModel::update() +void ReleaseInformationModel::update() const { Env::getSingleton()->update(); } diff --git a/src/ui/qml/ReleaseInformationModel.h b/src/ui/qml/ReleaseInformationModel.h index 5dbaa63aa..a0a217c78 100644 --- a/src/ui/qml/ReleaseInformationModel.h +++ b/src/ui/qml/ReleaseInformationModel.h @@ -47,7 +47,7 @@ class ReleaseInformationModel ~ReleaseInformationModel() override = default; [[nodiscard]] FormattedTextModel* getCurrentRelease() const; [[nodiscard]] FormattedTextModel* getUpdateRelease() const; - Q_INVOKABLE void update(); + Q_INVOKABLE void update() const; [[nodiscard]] bool allowRetry() const; public Q_SLOTS: diff --git a/src/ui/qml/RemoteDeviceFilterModel.h b/src/ui/qml/RemoteDeviceFilterModel.h index b9ab5b544..18d8a3e7b 100644 --- a/src/ui/qml/RemoteDeviceFilterModel.h +++ b/src/ui/qml/RemoteDeviceFilterModel.h @@ -14,6 +14,8 @@ namespace governikus class RemoteDeviceFilterModel : public QSortFilterProxyModel { + Q_OBJECT + friend class ::test_RemoteDeviceFilterModel; private: diff --git a/src/ui/qml/RemoteDeviceModel.cpp b/src/ui/qml/RemoteDeviceModel.cpp index 06406ed7c..0df9944b1 100644 --- a/src/ui/qml/RemoteDeviceModel.cpp +++ b/src/ui/qml/RemoteDeviceModel.cpp @@ -6,174 +6,17 @@ #include "AppSettings.h" #include "ApplicationModel.h" -#include "Env.h" -#include "HelpAction.h" #include "LanguageLoader.h" #include "RemoteIfdClient.h" -#include - using namespace governikus; -RemoteDeviceModelEntry::RemoteDeviceModelEntry(const QSharedPointer& pListEntry) - : mDeviceName(RemoteServiceSettings::escapeDeviceName(pListEntry->getIfdDescriptor().getIfdName())) - , mId(pListEntry->getIfdDescriptor().getIfdId()) - , mPaired(false) - , mIsPairing(pListEntry->getIfdDescriptor().isPairingAnnounced()) - , mNetworkVisible(false) - , mConnected(false) - , mSupported(pListEntry->getIfdDescriptor().isSupported()) - , mLastConnected() - , mRemoteDeviceListEntry(pListEntry) -{ - Q_ASSERT(!mDeviceName.contains(QLatin1Char('<'))); -} - - -RemoteDeviceModelEntry::RemoteDeviceModelEntry(const QString& pDeviceNameEscaped, - const QString& pId, - bool pNetworkVisible, - bool pConnected, - bool pSupported, - bool pIsPairing, - const QDateTime& pLastConnected, - const QSharedPointer& pRemoteDeviceListEntry) - : mDeviceName(pDeviceNameEscaped) - , mId(pId) - , mPaired(true) - , mIsPairing(pIsPairing) - , mNetworkVisible(pNetworkVisible) - , mConnected(pConnected) - , mSupported(pSupported) - , mLastConnected(pLastConnected) - , mRemoteDeviceListEntry(pRemoteDeviceListEntry) -{ - Q_ASSERT(!mDeviceName.contains(QLatin1Char('<'))); -} - - -RemoteDeviceModelEntry::RemoteDeviceModelEntry(const QString& pDeviceNameEscaped) - : mDeviceName(pDeviceNameEscaped) - , mId() - , mPaired(false) - , mIsPairing(false) - , mNetworkVisible(false) - , mConnected(false) - , mSupported(false) - , mLastConnected() - , mRemoteDeviceListEntry(nullptr) -{ - Q_ASSERT(!mDeviceName.contains(QLatin1Char('<'))); -} - - -const QSharedPointer& RemoteDeviceModelEntry::getRemoteDeviceListEntry() const -{ - return mRemoteDeviceListEntry; -} - - -QString RemoteDeviceModelEntry::getDeviceNameEscaped() const -{ - return mDeviceName; -} - - -bool RemoteDeviceModelEntry::isPaired() const -{ - return mPaired; -} - - -void RemoteDeviceModelEntry::setPaired(bool pPaired) -{ - mPaired = pPaired; -} - - -bool RemoteDeviceModelEntry::isPairing() const -{ - return mIsPairing; -} - - -void RemoteDeviceModelEntry::setIsPairing(bool pIsPairing) -{ - mIsPairing = pIsPairing; -} - - -const QString& RemoteDeviceModelEntry::getId() const -{ - return mId; -} - - -void RemoteDeviceModelEntry::setId(const QString& pId) -{ - mId = pId; -} - - -bool RemoteDeviceModelEntry::isNetworkVisible() const -{ - return mNetworkVisible; -} - - -int RemoteDeviceModelEntry::getLinkQuality() const -{ - if (mConnected) - { - return 100; - } - - if (mRemoteDeviceListEntry.isNull()) - { - return 0; - } - - return mRemoteDeviceListEntry->getPercentSeen(); -} - - -bool RemoteDeviceModelEntry::isSupported() const -{ - return mSupported; -} - - -void RemoteDeviceModelEntry::setNetworkVisible(bool pNetworkVisible) -{ - mNetworkVisible = pNetworkVisible; -} - -const QDateTime& RemoteDeviceModelEntry::getLastConnected() const -{ - return mLastConnected; -} - - -void RemoteDeviceModelEntry::setLastConnected(const QDateTime& pLastConnected) -{ - mLastConnected = pLastConnected; -} - - -bool RemoteDeviceModelEntry::operator==(const RemoteDeviceModelEntry& pOther) const -{ - return getId() == pOther.getId(); -} - - -RemoteDeviceModel::RemoteDeviceModel(QObject* pParent, bool pShowPairedReaders, bool pShowUnpairedReaders) +RemoteDeviceModel::RemoteDeviceModel(QObject* pParent) : QAbstractListModel(pParent) , mPairedReaders() , mAllRemoteReaders() - , mShowPairedReaders(pShowPairedReaders) - , mShowUnpairedReaders(pShowUnpairedReaders) , mTimer() , mIsDetectingRemoteDevices(false) #if defined(Q_OS_IOS) @@ -334,19 +177,17 @@ void RemoteDeviceModel::updateUnpairedReaders() void RemoteDeviceModel::removeVanishedReaders() { const auto availableReaders = presentReaders(); - for (int i = mAllRemoteReaders.size() - 1; i >= 0; --i) + for (int i = static_cast(mAllRemoteReaders.size()) - 1; i >= 0; --i) { const auto& reader = mAllRemoteReaders.value(i); const bool readerIsPaired = mPairedReaders.contains(reader.getId()); - if (mShowPairedReaders && readerIsPaired) + if (readerIsPaired) { continue; } const bool readerIsAvailable = availableReaders.contains(reader); - const bool showOnlyPairedReader = mShowPairedReaders && !mShowUnpairedReaders; - const bool showOnlyUnpairedReader = mShowUnpairedReaders && !mShowPairedReaders; - if (!readerIsAvailable || (showOnlyPairedReader && !readerIsPaired) || (showOnlyUnpairedReader && readerIsPaired)) + if (!readerIsAvailable) { beginRemoveRows(QModelIndex(), i, i); mAllRemoteReaders.remove(i); @@ -375,16 +216,16 @@ bool RemoteDeviceModel::addOrUpdateReader(const RemoteDeviceModelEntry& pModelEn { if (!mAllRemoteReaders.contains(pModelEntry)) { - const int readerCount = mAllRemoteReaders.size(); + const int readerCount = static_cast(mAllRemoteReaders.size()); beginInsertRows(index(readerCount, 0), readerCount, readerCount); mAllRemoteReaders.append(pModelEntry); endInsertRows(); return true; } - const int readerIndex = mAllRemoteReaders.indexOf(pModelEntry); + const auto readerIndex = mAllRemoteReaders.indexOf(pModelEntry); mAllRemoteReaders[readerIndex] = pModelEntry; - const auto modelIndex = index(readerIndex, 0); + const auto modelIndex = index(static_cast(readerIndex), 0); Q_EMIT dataChanged(modelIndex, modelIndex); return false; } @@ -392,7 +233,7 @@ bool RemoteDeviceModel::addOrUpdateReader(const RemoteDeviceModelEntry& pModelEn int RemoteDeviceModel::rowCount(const QModelIndex&) const { - return mAllRemoteReaders.size(); + return static_cast(mAllRemoteReaders.size()); } @@ -508,7 +349,7 @@ bool RemoteDeviceModel::isSupported(const QModelIndex& pIndex) const void RemoteDeviceModel::setDetectRemoteDevices(bool pNewStatus) { - if (!mShowUnpairedReaders || mIsDetectingRemoteDevices == pNewStatus) + if (mIsDetectingRemoteDevices == pNewStatus) { return; } @@ -547,7 +388,7 @@ void RemoteDeviceModel::onKnownRemoteReadersChanged() void RemoteDeviceModel::onApplicationStateChanged(bool pIsAppInForeground) { - if (!mShowUnpairedReaders || !mIsDetectingRemoteDevices) + if (!mIsDetectingRemoteDevices) { return; } @@ -574,15 +415,9 @@ void RemoteDeviceModel::onApplicationStateChanged(bool pIsAppInForeground) void RemoteDeviceModel::onUpdateReaderList() { - if (mShowPairedReaders) - { - updatePairedReaders(); - } + updatePairedReaders(); - if (mShowUnpairedReaders) - { - updateUnpairedReaders(); - } + updateUnpairedReaders(); removeVanishedReaders(); @@ -618,17 +453,6 @@ void RemoteDeviceModel::forgetDevice(const QString& pDeviceId) } -QString RemoteDeviceModel::getEmptyListDescriptionString() const -{ - const QString& onlineHelpSection = QStringLiteral("settingsRemoteReader"); - const QString& url = HelpAction::getOnlineUrl(onlineHelpSection); - //: Is embedded in a sentence. - const QString& hyperlink = QStringLiteral("%2").arg(url, tr("online help")); - //: INFO ALL_PLATFORMS No smartphone with enabled remote service was found on the same network. - return tr("No smartphone as card reader (Sac) available. Please make sure to activate the \"remote service\" on your smartphone and to connect both devices to the same WiFi. See %1 for details of use.").arg(hyperlink); -} - - void RemoteDeviceModel::setLastPairedReader(const QSslCertificate& pCert) { const RemoteServiceSettings& settings = Env::getSingleton()->getRemoteServiceSettings(); diff --git a/src/ui/qml/RemoteDeviceModel.h b/src/ui/qml/RemoteDeviceModel.h index a0528886d..cf83b8a43 100644 --- a/src/ui/qml/RemoteDeviceModel.h +++ b/src/ui/qml/RemoteDeviceModel.h @@ -9,74 +9,29 @@ #pragma once #include "GlobalStatus.h" -#include "IfdDescriptor.h" -#include "IfdDispatcher.h" -#include "IfdList.h" -#include "ReaderConfigurationInfo.h" +#include "RemoteDeviceModelEntry.h" #include "RemoteServiceSettings.h" -#include -#include +#include +#include +#include #include +#include +#include #include + class test_RemoteDeviceModel; class test_RemoteDeviceFilterModel; -namespace governikus -{ -class RemoteDeviceModelEntry +namespace governikus { - friend class ::test_RemoteDeviceModel; - - private: - QString mDeviceName; - QString mId; - bool mPaired; - bool mIsPairing; - bool mNetworkVisible; - bool mConnected; - bool mSupported; - QDateTime mLastConnected; - QSharedPointer mRemoteDeviceListEntry; - - public: - explicit RemoteDeviceModelEntry(const QSharedPointer& pListEntry); - RemoteDeviceModelEntry(const QString& pDeviceNameEscaped, - const QString& mId, - bool pNetworkVisible, - bool pConnected, - bool pSupported, - bool pIsPairing, - const QDateTime& pLastConnected, - const QSharedPointer& pRemoteDeviceListEntry); - explicit RemoteDeviceModelEntry(const QString& pDeviceNameEscaped = QStringLiteral("UnknownReader")); - - [[nodiscard]] bool isPaired() const; - void setPaired(bool pPaired); - [[nodiscard]] bool isPairing() const; - void setIsPairing(bool pIsPairing); - [[nodiscard]] const QString& getId() const; - void setId(const QString& pId); - [[nodiscard]] bool isNetworkVisible() const; - [[nodiscard]] int getLinkQuality() const; - [[nodiscard]] bool isSupported() const; - void setNetworkVisible(bool pNetworkVisible); - [[nodiscard]] const QDateTime& getLastConnected() const; - void setLastConnected(const QDateTime& pLastConnected); - [[nodiscard]] bool operator==(const RemoteDeviceModelEntry& pOther) const; - - [[nodiscard]] const QSharedPointer& getRemoteDeviceListEntry() const; - [[nodiscard]] QString getDeviceNameEscaped() const; - -}; class RemoteDeviceModel : public QAbstractListModel { Q_OBJECT - Q_PROPERTY(QString emptyListDescriptionString READ getEmptyListDescriptionString NOTIFY fireModelChanged) friend class ::test_RemoteDeviceModel; friend class ::test_RemoteDeviceFilterModel; @@ -84,8 +39,6 @@ class RemoteDeviceModel QMap mPairedReaders; QVector mAllRemoteReaders; RemoteServiceSettings::RemoteInfo mLastPairedDevice; - const bool mShowPairedReaders; - const bool mShowUnpairedReaders; QTimer mTimer; bool mIsDetectingRemoteDevices; #if defined(Q_OS_IOS) @@ -122,7 +75,7 @@ class RemoteDeviceModel IS_LAST_ADDED_DEVICE }; - RemoteDeviceModel(QObject* pParent = nullptr, bool pShowPairedReaders = true, bool pShowUnpairedReaders = true); + explicit RemoteDeviceModel(QObject* pParent = nullptr); [[nodiscard]] int rowCount(const QModelIndex& pParent = QModelIndex()) const override; [[nodiscard]] QVariant data(const QModelIndex& pIndex, int pRole = Qt::DisplayRole) const override; @@ -135,9 +88,6 @@ class RemoteDeviceModel [[nodiscard]] bool isSupported(const QModelIndex& pIndex) const; void forgetDevice(const QModelIndex& pIndex); void forgetDevice(const QString& pDeviceId); - - [[nodiscard]] QString getEmptyListDescriptionString() const; - void setLastPairedReader(const QSslCertificate& pCert); public Q_SLOTS: diff --git a/src/ui/qml/RemoteDeviceModelEntry.cpp b/src/ui/qml/RemoteDeviceModelEntry.cpp new file mode 100644 index 000000000..425f76b26 --- /dev/null +++ b/src/ui/qml/RemoteDeviceModelEntry.cpp @@ -0,0 +1,162 @@ +/** + * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany + */ + +#include "RemoteDeviceModelEntry.h" + +#include "RemoteServiceSettings.h" + + +using namespace governikus; + + +RemoteDeviceModelEntry::RemoteDeviceModelEntry(const QSharedPointer& pListEntry) + : mDeviceName(RemoteServiceSettings::escapeDeviceName(pListEntry->getIfdDescriptor().getIfdName())) + , mId(pListEntry->getIfdDescriptor().getIfdId()) + , mPaired(false) + , mIsPairing(pListEntry->getIfdDescriptor().isPairingAnnounced()) + , mNetworkVisible(false) + , mConnected(false) + , mSupported(pListEntry->getIfdDescriptor().isSupported()) + , mLastConnected() + , mRemoteDeviceListEntry(pListEntry) +{ + Q_ASSERT(!mDeviceName.contains(QLatin1Char('<'))); +} + + +RemoteDeviceModelEntry::RemoteDeviceModelEntry(const QString& pDeviceNameEscaped, + const QString& pId, + bool pNetworkVisible, + bool pConnected, + bool pSupported, + bool pIsPairing, + const QDateTime& pLastConnected, + const QSharedPointer& pRemoteDeviceListEntry) + : mDeviceName(pDeviceNameEscaped) + , mId(pId) + , mPaired(true) + , mIsPairing(pIsPairing) + , mNetworkVisible(pNetworkVisible) + , mConnected(pConnected) + , mSupported(pSupported) + , mLastConnected(pLastConnected) + , mRemoteDeviceListEntry(pRemoteDeviceListEntry) +{ + Q_ASSERT(!mDeviceName.contains(QLatin1Char('<'))); +} + + +RemoteDeviceModelEntry::RemoteDeviceModelEntry(const QString& pDeviceNameEscaped) + : mDeviceName(pDeviceNameEscaped) + , mId() + , mPaired(false) + , mIsPairing(false) + , mNetworkVisible(false) + , mConnected(false) + , mSupported(false) + , mLastConnected() + , mRemoteDeviceListEntry(nullptr) +{ + Q_ASSERT(!mDeviceName.contains(QLatin1Char('<'))); +} + + +const QSharedPointer& RemoteDeviceModelEntry::getRemoteDeviceListEntry() const +{ + return mRemoteDeviceListEntry; +} + + +QString RemoteDeviceModelEntry::getDeviceNameEscaped() const +{ + return mDeviceName; +} + + +bool RemoteDeviceModelEntry::isPaired() const +{ + return mPaired; +} + + +void RemoteDeviceModelEntry::setPaired(bool pPaired) +{ + mPaired = pPaired; +} + + +bool RemoteDeviceModelEntry::isPairing() const +{ + return mIsPairing; +} + + +void RemoteDeviceModelEntry::setIsPairing(bool pIsPairing) +{ + mIsPairing = pIsPairing; +} + + +const QString& RemoteDeviceModelEntry::getId() const +{ + return mId; +} + + +void RemoteDeviceModelEntry::setId(const QString& pId) +{ + mId = pId; +} + + +bool RemoteDeviceModelEntry::isNetworkVisible() const +{ + return mNetworkVisible; +} + + +int RemoteDeviceModelEntry::getLinkQuality() const +{ + if (mConnected) + { + return 100; + } + + if (mRemoteDeviceListEntry.isNull()) + { + return 0; + } + + return mRemoteDeviceListEntry->getPercentSeen(); +} + + +bool RemoteDeviceModelEntry::isSupported() const +{ + return mSupported; +} + + +void RemoteDeviceModelEntry::setNetworkVisible(bool pNetworkVisible) +{ + mNetworkVisible = pNetworkVisible; +} + + +const QDateTime& RemoteDeviceModelEntry::getLastConnected() const +{ + return mLastConnected; +} + + +void RemoteDeviceModelEntry::setLastConnected(const QDateTime& pLastConnected) +{ + mLastConnected = pLastConnected; +} + + +bool RemoteDeviceModelEntry::operator==(const RemoteDeviceModelEntry& pOther) const +{ + return getId() == pOther.getId(); +} diff --git a/src/ui/qml/RemoteDeviceModelEntry.h b/src/ui/qml/RemoteDeviceModelEntry.h new file mode 100644 index 000000000..a20374aa3 --- /dev/null +++ b/src/ui/qml/RemoteDeviceModelEntry.h @@ -0,0 +1,70 @@ +/** + * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany + */ + +/*! + * \brief Model implementation for the remote device table + */ + +#pragma once + +#include "IfdListEntry.h" + +#include +#include +#include +#include + + +class test_RemoteDeviceModel; + + +namespace governikus +{ + +class RemoteDeviceModelEntry +{ + friend class ::test_RemoteDeviceModel; + + private: + QString mDeviceName; + QString mId; + bool mPaired; + bool mIsPairing; + bool mNetworkVisible; + bool mConnected; + bool mSupported; + QDateTime mLastConnected; + QSharedPointer mRemoteDeviceListEntry; + + public: + explicit RemoteDeviceModelEntry(const QSharedPointer& pListEntry); + RemoteDeviceModelEntry(const QString& pDeviceNameEscaped, + const QString& mId, + bool pNetworkVisible, + bool pConnected, + bool pSupported, + bool pIsPairing, + const QDateTime& pLastConnected, + const QSharedPointer& pRemoteDeviceListEntry); + explicit RemoteDeviceModelEntry(const QString& pDeviceNameEscaped = QStringLiteral("UnknownReader")); + + [[nodiscard]] bool isPaired() const; + void setPaired(bool pPaired); + [[nodiscard]] bool isPairing() const; + void setIsPairing(bool pIsPairing); + [[nodiscard]] const QString& getId() const; + void setId(const QString& pId); + [[nodiscard]] bool isNetworkVisible() const; + [[nodiscard]] int getLinkQuality() const; + [[nodiscard]] bool isSupported() const; + void setNetworkVisible(bool pNetworkVisible); + [[nodiscard]] const QDateTime& getLastConnected() const; + void setLastConnected(const QDateTime& pLastConnected); + [[nodiscard]] bool operator==(const RemoteDeviceModelEntry& pOther) const; + + [[nodiscard]] const QSharedPointer& getRemoteDeviceListEntry() const; + [[nodiscard]] QString getDeviceNameEscaped() const; +}; + +} // namespace governikus diff --git a/src/ui/qml/RemoteServiceModel.cpp b/src/ui/qml/RemoteServiceModel.cpp index ad4e0707b..24a21faec 100644 --- a/src/ui/qml/RemoteServiceModel.cpp +++ b/src/ui/qml/RemoteServiceModel.cpp @@ -6,6 +6,7 @@ #include "AppSettings.h" #include "ApplicationModel.h" +#include "ReaderManager.h" #include "RemoteIfdClient.h" #include "RemoteIfdServer.h" #include "RemoteServiceSettings.h" @@ -34,7 +35,7 @@ RemoteServiceModel::RemoteServiceModel() , mPairingRequested(false) , mErrorMessage() , mPsk() - , mAllDevices(this, true, true) + , mAllDevices(this) , mAvailableDevicesInPairingMode(&mAllDevices, RemoteDeviceFilterModel::showActivePairingMode) , mAvailablePairedDevices(&mAllDevices, RemoteDeviceFilterModel::showAvailableAndPaired) , mUnavailablePairedDevices(&mAllDevices, RemoteDeviceFilterModel::showUnavailableAndPaired) @@ -160,15 +161,25 @@ void RemoteServiceModel::onReaderPlugInTypesChanged(bool pExplicitStart) { mContext->getIfdServer()->getMessageHandler()->setAllowedCardTypes({plugInType}); } + auto* readerManager = Env::getSingleton(); - readerManager->stopScanAll(); + const auto& readerPlugInTypes = Enum::getList(); + for (const auto t : readerPlugInTypes) + { + if (t != plugInType) + { + readerManager->stopScan(t); + continue; + } + #ifdef Q_OS_IOS - if (plugInType != ReaderManagerPlugInType::NFC || pExplicitStart) + if (plugInType != ReaderManagerPlugInType::NFC || pExplicitStart) #else - Q_UNUSED(pExplicitStart) + Q_UNUSED(pExplicitStart) #endif - { - readerManager->startScan(plugInType); + { + readerManager->startScan(plugInType); + } } } @@ -204,7 +215,7 @@ void RemoteServiceModel::setRunning(bool pState, bool pEnablePairing) { setStarting(true); const auto ifdServer = QSharedPointer(new RemoteIfdServer()); - const auto request = WorkflowRequest::createWorkflowRequest(ifdServer); + const auto request = WorkflowRequest::create(ifdServer); Q_EMIT fireStartWorkflow(request); } } @@ -324,13 +335,13 @@ void RemoteServiceModel::onConnectionInfoChanged(bool pConnected) } -void RemoteServiceModel::onCardConnected(const QSharedPointer& pConnection) +void RemoteServiceModel::onCardConnected(const QSharedPointer& pConnection) const { pConnection->setProgressMessage(mConnectionInfo); } -void RemoteServiceModel::onCardDisconnected(const QSharedPointer& pConnection) +void RemoteServiceModel::onCardDisconnected(const QSharedPointer& pConnection) const { pConnection->setProgressMessage(mConnectionInfo); } @@ -375,7 +386,7 @@ void RemoteServiceModel::resetRemoteServiceContext(const QSharedPointerisPinAuthentication(); +} + + void RemoteServiceModel::onConnectedDevicesChanged() { auto* const ifdClient = Env::getSingleton(); diff --git a/src/ui/qml/RemoteServiceModel.h b/src/ui/qml/RemoteServiceModel.h index efc04af01..aeaa3a1db 100644 --- a/src/ui/qml/RemoteServiceModel.h +++ b/src/ui/qml/RemoteServiceModel.h @@ -9,7 +9,6 @@ #pragma once #include "Env.h" -#include "ReaderManager.h" #include "RemoteDeviceFilterModel.h" #include "RemoteDeviceModel.h" #include "WorkflowModel.h" @@ -19,6 +18,10 @@ #include #include + +class test_UIPlugInQml; + + namespace governikus { @@ -27,6 +30,7 @@ class RemoteServiceModel { Q_OBJECT friend class Env; + friend class ::test_UIPlugInQml; Q_PROPERTY(bool running READ isRunning NOTIFY fireIsRunningChanged) Q_PROPERTY(bool isStarting READ isStarting NOTIFY fireIsStartingChanged) @@ -82,8 +86,8 @@ class RemoteServiceModel private Q_SLOTS: void onEstablishConnectionDone(const QSharedPointer& pEntry, const GlobalStatus& pStatus); void onConnectionInfoChanged(bool pConnected); - void onCardConnected(const QSharedPointer& pConnection); - void onCardDisconnected(const QSharedPointer& pConnection); + void onCardConnected(const QSharedPointer& pConnection) const; + void onCardDisconnected(const QSharedPointer& pConnection) const; void onConnectedDevicesChanged(); void onEnvironmentChanged(); void onApplicationStateChanged(const bool pIsAppInForeground); @@ -110,8 +114,8 @@ class RemoteServiceModel [[nodiscard]] QVector getSupportedReaderPlugInTypes() const override; void resetRemoteServiceContext(const QSharedPointer& pContext = QSharedPointer()); - void setPairing(bool pEnabled); - [[nodiscard]] bool isPairing(); + void setPairing(bool pEnabled) const; + [[nodiscard]] bool isPairing() const; [[nodiscard]] bool isConnectedToPairedDevice() const; [[nodiscard]] bool enableTransportPinLink() const; [[nodiscard]] bool isRunnable() const; @@ -130,6 +134,7 @@ class RemoteServiceModel Q_INVOKABLE void forgetDevice(const QString& pId); Q_INVOKABLE void cancelPasswordRequest(); Q_INVOKABLE void changePinLength(); + [[nodiscard]] Q_INVOKABLE bool isPinAuthentication() const; Q_SIGNALS: void fireStartWorkflow(const QSharedPointer& pRequest); diff --git a/src/ui/qml/SelfAuthModel.cpp b/src/ui/qml/SelfAuthModel.cpp index 32b9fa9bd..46181544f 100644 --- a/src/ui/qml/SelfAuthModel.cpp +++ b/src/ui/qml/SelfAuthModel.cpp @@ -4,7 +4,6 @@ #include "SelfAuthModel.h" -#include "PdfExporter.h" #include "context/SelfAuthContext.h" #include "controller/SelfAuthController.h" @@ -53,14 +52,15 @@ void SelfAuthModel::resetContext(const QSharedPointer& pContext if (mContext) { connect(mContext.data(), &SelfAuthContext::fireSelfAuthenticationDataChanged, this, &SelfAuthModel::onSelfAuthenticationDataChanged); + connect(mContext.data(), &SelfAuthContext::fireCancelWorkflow, this, &SelfAuthModel::fireCancelWorkflow); } onSelfAuthenticationDataChanged(); } -void SelfAuthModel::startWorkflow() +void SelfAuthModel::startWorkflow(bool pActivateUi) { - Q_EMIT fireStartWorkflow(SelfAuthController::createWorkflowRequest()); + Q_EMIT fireStartWorkflow(SelfAuthController::createWorkflowRequest(pActivateUi)); } @@ -73,34 +73,30 @@ void SelfAuthModel::cancelWorkflow() } -bool SelfAuthModel::isBasicReader() const +bool SelfAuthModel::isWorkflowCancelled() const { if (mContext) { - return mContext->getCardConnection()->getReaderInfo().isBasicReader(); + return mContext->isWorkflowCancelled(); } - - return true; + return false; } -void SelfAuthModel::exportData(const QUrl& pFilename) const +bool SelfAuthModel::isBasicReader() const { - const auto& selfdata = mContext->getSelfAuthenticationData(); - const auto& orderedSelfData = selfdata.getOrderedSelfData(); - if (!orderedSelfData.isEmpty()) + if (mContext) { - const auto& dataTime = selfdata.getDateTime(); - - PdfExporter exporter(pFilename.toLocalFile()); - exporter.exportSelfInfo(dataTime, orderedSelfData); + return mContext->getCardConnection()->getReaderInfo().isBasicReader(); } + + return true; } int SelfAuthModel::rowCount(const QModelIndex&) const { - return mSelfData.size(); + return static_cast(mSelfData.size()); } diff --git a/src/ui/qml/SelfAuthModel.h b/src/ui/qml/SelfAuthModel.h index 01c42df3f..e1a9c0ad6 100644 --- a/src/ui/qml/SelfAuthModel.h +++ b/src/ui/qml/SelfAuthModel.h @@ -17,6 +17,10 @@ #include #include + +class test_UIPlugInQml; + + namespace governikus { @@ -27,6 +31,9 @@ class SelfAuthModel { Q_OBJECT friend class Env; + friend class ::test_UIPlugInQml; + + Q_PROPERTY(bool workflowCancelled READ isWorkflowCancelled NOTIFY fireCancelWorkflow FINAL) private: SelfAuthModel(); @@ -46,10 +53,10 @@ class SelfAuthModel void resetContext(const QSharedPointer& pContext = QSharedPointer()); - Q_INVOKABLE void startWorkflow(); + Q_INVOKABLE void startWorkflow(bool pActivateUi = true); Q_INVOKABLE void cancelWorkflow(); + [[nodiscard]] bool isWorkflowCancelled() const; [[nodiscard]] Q_INVOKABLE bool isBasicReader() const; - Q_INVOKABLE void exportData(const QUrl& pFilename) const; [[nodiscard]] int rowCount(const QModelIndex& = QModelIndex()) const override; [[nodiscard]] QVariant data(const QModelIndex& pIndex, int pRole = Qt::DisplayRole) const override; @@ -59,6 +66,7 @@ class SelfAuthModel Q_SIGNALS: void fireStartWorkflow(const QSharedPointer& pRequest); + void fireCancelWorkflow(); }; diff --git a/src/ui/qml/SettingsModel.cpp b/src/ui/qml/SettingsModel.cpp index fb1ce3b60..d467e52b3 100644 --- a/src/ui/qml/SettingsModel.cpp +++ b/src/ui/qml/SettingsModel.cpp @@ -5,7 +5,6 @@ #include "SettingsModel.h" #include "AppSettings.h" -#include "HistorySettings.h" #include "LanguageLoader.h" #include "Service.h" @@ -25,9 +24,6 @@ SettingsModel::SettingsModel() , mIsStartedByAuth(false) , mShowBetaTesting(true) { - const auto& settings = Env::getSingleton()->getHistorySettings(); - connect(&settings, &HistorySettings::fireEnabledChanged, this, &SettingsModel::fireHistoryEnabledChanged); - connect(Env::getSingleton(), &AppUpdateDataModel::fireAppUpdateDataChanged, this, &SettingsModel::fireAppUpdateDataChanged); const auto& generalSettings = Env::getSingleton()->getGeneralSettings(); @@ -35,6 +31,8 @@ SettingsModel::SettingsModel() connect(&generalSettings, &GeneralSettings::fireShowInAppNotificationsChanged, this, &SettingsModel::fireShowInAppNotificationsChanged); connect(&generalSettings, &GeneralSettings::fireDeveloperOptionsChanged, this, &SettingsModel::fireDeveloperOptionsChanged); connect(&generalSettings, &GeneralSettings::fireProxyChanged, this, &SettingsModel::fireUseCustomProxyChanged); + connect(&generalSettings, &GeneralSettings::fireUseSystemFontChanged, this, &SettingsModel::fireUseSystemFontChanged); + connect(&generalSettings, &GeneralSettings::fireDarkModeChanged, this, &SettingsModel::fireDarkModeChanged); #ifdef Q_OS_ANDROID mIsStartedByAuth = QJniObject::callStaticMethod("com/governikus/ausweisapp2/MainActivity", "isStartedByAuth"); @@ -48,7 +46,7 @@ QString SettingsModel::getLanguage() const } -void SettingsModel::setLanguage(const QString& pLanguage) +void SettingsModel::setLanguage(const QString& pLanguage) const { if (getLanguage() != pLanguage) { @@ -87,7 +85,7 @@ bool SettingsModel::isDeveloperOptions() const } -void SettingsModel::setDeveloperOptions(bool pEnable) +void SettingsModel::setDeveloperOptions(bool pEnable) const { if (isDeveloperOptions() != pEnable) { @@ -103,7 +101,7 @@ bool SettingsModel::isDeveloperMode() const } -void SettingsModel::setDeveloperMode(bool pEnable) +void SettingsModel::setDeveloperMode(bool pEnable) const { if (isDeveloperMode() != pEnable) { @@ -119,7 +117,7 @@ bool SettingsModel::useSelfauthenticationTestUri() const } -void SettingsModel::setUseSelfauthenticationTestUri(bool pUse) +void SettingsModel::setUseSelfauthenticationTestUri(bool pUse) const { if (useSelfauthenticationTestUri() != pUse) { @@ -143,20 +141,12 @@ void SettingsModel::setServerName(const QString& name) } -void SettingsModel::removeTrustedCertificate(const QString& pFingerprint) +void SettingsModel::removeTrustedCertificate(const QString& pFingerprint) const { Env::getSingleton()->getRemoteServiceSettings().removeTrustedCertificate(pFingerprint); } -int SettingsModel::removeHistory(const QString& pPeriodToRemove) -{ - auto& settings = Env::getSingleton()->getHistorySettings(); - int removedItemCount = settings.deleteSettings(Enum::fromString(pPeriodToRemove, TimePeriod::UNKNOWN)); - return removedItemCount; -} - - bool SettingsModel::getPinPadMode() const { return Env::getSingleton()->getRemoteServiceSettings().getPinPadMode(); @@ -191,30 +181,6 @@ void SettingsModel::setShowAccessRights(bool pShowAccessRights) } -bool SettingsModel::isHistoryEnabled() const -{ - const auto& settings = Env::getSingleton()->getHistorySettings(); - return settings.isEnabled(); -} - - -void SettingsModel::setHistoryEnabled(bool pEnabled) -{ - if (isHistoryEnabled() != pEnabled) - { - auto& settings = Env::getSingleton()->getHistorySettings(); - settings.setEnabled(pEnabled); - } -} - - -int SettingsModel::removeEntireHistory() -{ - auto& settings = Env::getSingleton()->getHistorySettings(); - return settings.deleteSettings(TimePeriod::ALL_HISTORY); -} - - bool SettingsModel::isUseScreenKeyboard() const { return Env::getSingleton()->getGeneralSettings().isUseScreenKeyboard(); @@ -306,7 +272,7 @@ bool SettingsModel::isSimulatorEnabled() const } -void SettingsModel::setSimulatorEnabled(bool pEnabled) +void SettingsModel::setSimulatorEnabled(bool pEnabled) const { if (isSimulatorEnabled() != pEnabled) { @@ -370,6 +336,7 @@ void SettingsModel::setAutoStart(bool pEnabled) auto& settings = Env::getSingleton()->getGeneralSettings(); settings.setAutoStart(pEnabled); Q_EMIT fireAutoStartChanged(); + Q_EMIT fireShowTrayIconChanged(); } } @@ -388,7 +355,7 @@ bool SettingsModel::requestStoreFeedback() const } -void SettingsModel::hideFutureStoreFeedbackDialogs() +void SettingsModel::hideFutureStoreFeedbackDialogs() const { Env::getSingleton()->getGeneralSettings().setRequestStoreFeedback(false); } @@ -440,6 +407,12 @@ void SettingsModel::setAutoUpdateCheck(bool pAutoUpdateCheck) } +bool SettingsModel::showTrayIcon() const +{ + return Env::getSingleton()->getGeneralSettings().showTrayIcon(); +} + + bool SettingsModel::isRemindUserToClose() const { return Env::getSingleton()->getGeneralSettings().isRemindUserToClose(); @@ -481,7 +454,7 @@ bool SettingsModel::isShowInAppNotifications() const } -void SettingsModel::setShowInAppNotifications(bool pShowInAppNotifications) +void SettingsModel::setShowInAppNotifications(bool pShowInAppNotifications) const { if (isShowInAppNotifications() != pShowInAppNotifications) { @@ -491,7 +464,7 @@ void SettingsModel::setShowInAppNotifications(bool pShowInAppNotifications) } -void SettingsModel::updateAppcast() +void SettingsModel::updateAppcast() const { Env::getSingleton()->updateAppcast(); } @@ -541,7 +514,47 @@ bool SettingsModel::isUseCustomProxy() const } -void SettingsModel::setUseCustomProxy(bool pUseCustomProxy) +void SettingsModel::setUseCustomProxy(bool pUseCustomProxy) const { Env::getSingleton()->getGeneralSettings().setUseCustomProxy(pUseCustomProxy); } + + +bool SettingsModel::isUseSystemFont() const +{ + return Env::getSingleton()->getGeneralSettings().isUseSystemFont(); +} + + +void SettingsModel::setUseSystemFont(bool pUseSystemFont) const +{ + Env::getSingleton()->getGeneralSettings().setUseSystemFont(pUseSystemFont); +} + + +ModeOption SettingsModel::getDarkMode() const +{ + return Enum::fromString( + Env::getSingleton()->getGeneralSettings().getDarkMode(), + ModeOption::OFF); +} + + +void SettingsModel::setDarkMode(ModeOption pMode) +{ + Env::getSingleton()->getGeneralSettings().setDarkMode( + Enum::getName(pMode)); +} + + +#ifndef QT_NO_DEBUG +void SettingsModel::resetHideableDialogs() const +{ + GeneralSettings& settings = Env::getSingleton()->getGeneralSettings(); + settings.setTransportPinReminder(true); + settings.setRemindUserToClose(true); + settings.setRequestStoreFeedback(true); +} + + +#endif diff --git a/src/ui/qml/SettingsModel.h b/src/ui/qml/SettingsModel.h index 374de486c..d129649a7 100644 --- a/src/ui/qml/SettingsModel.h +++ b/src/ui/qml/SettingsModel.h @@ -18,6 +18,12 @@ namespace governikus { +defineEnumType(ModeOption, + ON, + OFF, + AUTO + ) + class SettingsModel : public QObject { @@ -33,7 +39,6 @@ class SettingsModel Q_PROPERTY(bool pinPadMode READ getPinPadMode WRITE setPinPadMode NOTIFY firePinPadModeChanged) Q_PROPERTY(bool showAccessRights READ getShowAccessRights WRITE setShowAccessRights NOTIFY fireShowAccessRightsChanged) Q_PROPERTY(QString serverName READ getServerName WRITE setServerName NOTIFY fireDeviceNameChanged) - Q_PROPERTY(bool historyEnabled READ isHistoryEnabled WRITE setHistoryEnabled NOTIFY fireHistoryEnabledChanged) Q_PROPERTY(bool useScreenKeyboard READ isUseScreenKeyboard WRITE setUseScreenKeyboard NOTIFY fireScreenKeyboardChanged) Q_PROPERTY(bool visualPrivacy READ isVisualPrivacy WRITE setVisualPrivacy NOTIFY fireScreenKeyboardChanged) Q_PROPERTY(bool shuffleScreenKeyboard READ isShuffleScreenKeyboard WRITE setShuffleScreenKeyboard NOTIFY fireScreenKeyboardChanged) @@ -43,6 +48,7 @@ class SettingsModel Q_PROPERTY(UiModule startupModule READ getStartupModule WRITE setStartupModule NOTIFY fireStartupModuleChanged) Q_PROPERTY(bool autoStartAvailable READ isAutoStartAvailable CONSTANT) Q_PROPERTY(bool autoStartApp READ isAutoStart WRITE setAutoStart NOTIFY fireAutoStartChanged) + Q_PROPERTY(bool showTrayIcon READ showTrayIcon NOTIFY fireShowTrayIconChanged) Q_PROPERTY(bool autoStartSetByAdmin READ autoStartIsSetByAdmin CONSTANT) Q_PROPERTY(bool autoUpdateAvailable READ isAutoUpdateAvailable CONSTANT) Q_PROPERTY(bool autoCloseWindowAfterAuthentication READ isAutoCloseWindowAfterAuthentication WRITE setAutoCloseWindowAfterAuthentication NOTIFY fireAutoCloseWindowAfterAuthenticationChanged) @@ -55,6 +61,8 @@ class SettingsModel Q_PROPERTY(QUrl customProxyUrl READ getCustomProxyUrl CONSTANT) Q_PROPERTY(bool customProxyAttributesPresent READ isCustomProxyAttributesPresent CONSTANT) Q_PROPERTY(bool useCustomProxy READ isUseCustomProxy WRITE setUseCustomProxy NOTIFY fireUseCustomProxyChanged) + Q_PROPERTY(bool useSystemFont READ isUseSystemFont WRITE setUseSystemFont NOTIFY fireUseSystemFontChanged) + Q_PROPERTY(ModeOption userDarkMode READ getDarkMode WRITE setDarkMode NOTIFY fireDarkModeChanged) private: bool mAdvancedSettings; @@ -66,26 +74,24 @@ class SettingsModel public: [[nodiscard]] QString getLanguage() const; - void setLanguage(const QString& pLanguage); + void setLanguage(const QString& pLanguage) const; [[nodiscard]] bool isAdvancedSettings() const; void setAdvancedSettings(bool pEnabled); [[nodiscard]] bool isDeveloperOptions() const; - void setDeveloperOptions(bool pEnabled); + void setDeveloperOptions(bool pEnabled) const; [[nodiscard]] bool isDeveloperMode() const; - void setDeveloperMode(bool pEnabled); + void setDeveloperMode(bool pEnabled) const; [[nodiscard]] bool useSelfauthenticationTestUri() const; - void setUseSelfauthenticationTestUri(bool pUse); + void setUseSelfauthenticationTestUri(bool pUse) const; [[nodiscard]] QString getServerName() const; void setServerName(const QString& name); - Q_INVOKABLE void removeTrustedCertificate(const QString& pFingerprint); - [[nodiscard]] Q_INVOKABLE int removeHistory(const QString& pPeriodToRemove); - [[nodiscard]] Q_INVOKABLE int removeEntireHistory(); + Q_INVOKABLE void removeTrustedCertificate(const QString& pFingerprint) const; [[nodiscard]] bool getPinPadMode() const; void setPinPadMode(bool pPinPadMode); @@ -93,9 +99,6 @@ class SettingsModel [[nodiscard]] bool getShowAccessRights() const; void setShowAccessRights(bool pShowAccessRights); - [[nodiscard]] bool isHistoryEnabled() const; - void setHistoryEnabled(bool pEnabled); - [[nodiscard]] bool isUseScreenKeyboard() const; void setUseScreenKeyboard(bool pUseScreenKeyboard); @@ -112,7 +115,7 @@ class SettingsModel void setSkipRightsOnCanAllowed(bool pSkipRightsOnCanAllowed); [[nodiscard]] bool isSimulatorEnabled() const; - void setSimulatorEnabled(bool pEnabled); + void setSimulatorEnabled(bool pEnabled) const; [[nodiscard]] UiModule getStartupModule() const; void setStartupModule(UiModule pModule); @@ -129,6 +132,7 @@ class SettingsModel [[nodiscard]] bool isAutoUpdateCheck() const; [[nodiscard]] bool autoUpdateCheckIsSetByAdmin() const; void setAutoUpdateCheck(bool pAutoUpdateCheck); + [[nodiscard]] bool showTrayIcon() const; [[nodiscard]] bool isRemindUserToClose() const; void setRemindUserToClose(bool pRemindUser); @@ -137,20 +141,30 @@ class SettingsModel void setTransportPinReminder(bool pTransportPinReminder); [[nodiscard]] bool isShowInAppNotifications() const; - void setShowInAppNotifications(bool pShowInAppNotifications); + void setShowInAppNotifications(bool pShowInAppNotifications) const; [[nodiscard]] QUrl getCustomProxyUrl() const; [[nodiscard]] bool isCustomProxyAttributesPresent() const; [[nodiscard]] bool isUseCustomProxy() const; - void setUseCustomProxy(bool pUseCustomProxy); + void setUseCustomProxy(bool pUseCustomProxy) const; + + [[nodiscard]] bool isUseSystemFont() const; + void setUseSystemFont(bool pUseSystemFont) const; + + [[nodiscard]] ModeOption getDarkMode() const; + void setDarkMode(ModeOption pMode); [[nodiscard]] Q_INVOKABLE bool requestStoreFeedback() const; - Q_INVOKABLE void hideFutureStoreFeedbackDialogs(); + Q_INVOKABLE void hideFutureStoreFeedbackDialogs() const; - Q_INVOKABLE void updateAppcast(); + Q_INVOKABLE void updateAppcast() const; [[nodiscard]] AppUpdateDataModel* getAppUpdateData() const; +#ifndef QT_NO_DEBUG + Q_INVOKABLE void resetHideableDialogs() const; +#endif + public Q_SLOTS: void onTranslationChanged(); @@ -161,7 +175,6 @@ class SettingsModel void fireDeviceNameChanged(); void firePinPadModeChanged(); void fireShowAccessRightsChanged(); - void fireHistoryEnabledChanged(); void fireScreenKeyboardChanged(); void fireCanAllowedChanged(); void fireStartupModuleChanged(); @@ -173,6 +186,9 @@ class SettingsModel void fireAppUpdateDataChanged(); void fireShowInAppNotificationsChanged(); void fireUseCustomProxyChanged(); + void fireUseSystemFontChanged(); + void fireDarkModeChanged(); + void fireShowTrayIconChanged(); }; diff --git a/src/ui/qml/SmartModel.cpp b/src/ui/qml/SmartModel.cpp index 69082ed1d..89b1a0d2c 100644 --- a/src/ui/qml/SmartModel.cpp +++ b/src/ui/qml/SmartModel.cpp @@ -24,6 +24,7 @@ Q_DECLARE_LOGGING_CATEGORY(card_smart) SmartModel::SmartModel() : QObject(nullptr) , mStatus(QmlSmartState::SMART_UNAVAILABLE) + , mErrorString() , mCachedCardInfo(CardType::NONE) , mProgress(0) { @@ -35,31 +36,49 @@ SmartModel::SmartModel() void SmartModel::updateStatus() { #if __has_include("SmartManager.h") - if (mStatus != QmlSmartState::SMART_UPDATING_STATUS) + const auto& readerManager = Env::getSingleton(); + const auto& smartInfo = readerManager->getPlugInInfo(ReaderManagerPlugInType::SMART); + if (smartInfo.isAvailable()) { setStatus(QmlSmartState::SMART_UPDATING_STATUS); Env::getSingleton()->callExecuteCommand([] { return QVariant::fromValue(SmartManager::get()->status()); }, this, &SmartModel::onUpdateStatusDone); + + return; } + + setStatus(QmlSmartState::SMART_UNAVAILABLE); #endif } +void SmartModel::setErrorString(const QString& pError) +{ + if (pError != mErrorString) + { + mErrorString = pError; + Q_EMIT fireErrorStringChanged(); + } +} + + void SmartModel::updatePinStatus() { - const auto& readerManager = Env::getSingleton(); - const auto& smartInfo = readerManager->getPlugInInfo(ReaderManagerPlugInType::SMART); - if (smartInfo.isAvailable()) + if (getSmartState() == QmlSmartState::SMART_READY || getSmartState() == QmlSmartState::SMART_UPDATING_STATUS) { setStatus(QmlSmartState::SMART_UPDATING_STATUS); - connect(readerManager, &ReaderManager::fireStatusChanged, this, &SmartModel::onUpdatePinStatusDone); + const auto& readerManager = Env::getSingleton(); + connect(readerManager, &ReaderManager::fireReaderPropertiesUpdated, this, &SmartModel::onUpdatePinStatusDone); + connect(readerManager, &ReaderManager::fireCardInfoChanged, this, &SmartModel::onUpdatePinStatusDone); readerManager->startScan(ReaderManagerPlugInType::SMART); + if (Env::getSingleton()->getCurrentWorkflow() == ApplicationModel::Workflow::WORKFLOW_NONE) + { + readerManager->stopScan(ReaderManagerPlugInType::SMART); + } return; } - - setStatus(QmlSmartState::SMART_UNAVAILABLE); } @@ -83,30 +102,150 @@ void SmartModel::setStatus(QmlSmartState pNewStatus) } +void SmartModel::onUpdateSupportInfoDone(const QVariant& pResult) +{ + QmlSmartState newStatus = QmlSmartState::SMART_UNAVAILABLE; +#if __has_include("SmartManager.h") + const auto& [result, status] = pResult.value(); + switch (result) + { + case EidServiceResult::UNDEFINED: + case EidServiceResult::INFO: + case EidServiceResult::WARN: + case EidServiceResult::ERROR: + case EidServiceResult::UNSUPPORTED: + //: ERROR ANDROID IOS The check for Smart-eID support failed without any specific reason. + setErrorString(tr("The online check for the Smart-eID support on your device failed. Please note that this process requires an internet connection.")); + break; + + case EidServiceResult::OVERLOAD_PROTECTION: + //: ERROR ANDROID IOS The check for Smart-eID support failed because the server is overloaded. + setErrorString(tr("The online check for the Smart-eID support on your device failed because the server is currently facing too many requests. Please try again later.")); + break; + + case EidServiceResult::UNDER_MAINTENANCE: + //: ERROR ANDROID IOS The check for Smart-eID support failed because the server is being maintained. + setErrorString(tr("The online check for the Smart-eID support on your device failed because the server is currently under maintenance. Please try again later.")); + break; + + case EidServiceResult::NFC_NOT_ACTIVATED: + //: ERROR ANDROID IOS The check for Smart-eID support failed because the NFC functionality is not activated. + setErrorString(tr("The online check for the Smart-eID support on your device failed. In order to access the necessary device storage, active NFC functionality is required. Please activate NFC and try again.")); + break; + + case EidServiceResult::INTEGRITY_CHECK_FAILED: + //: ERROR ANDROID IOS The check for Smart-eID support failed because Google Play Integrity Check failed. + setErrorString(tr("The online check for the Smart-eID support on your device failed. The Google Play Integrity Check failed.")); + return; + + case EidServiceResult::NOT_AUTHENTICATED: + //: ERROR ANDROID IOS The check for Smart-eID support failed because an authorization issue occurred. + setErrorString(tr("The online check for the Smart-eID support on your device failed. An authentication issue occurred (e.g. a resource was accessed without authorization or an unauthorized app tried to access a security component).")); + break; + + case EidServiceResult::NETWORK_CONNECTION_ERROR: + //: ERROR ANDROID IOS The check for Smart-eID support failed because a network connection error occurred. + setErrorString(tr("The online check for the Smart-eID support on your device failed. Please ensure that you have an internet connection and your antivirus software and firewall are not blocking the connection.")); + break; + + case EidServiceResult::SUCCESS: + break; + } + + if (result == EidServiceResult::SUCCESS) + { + switch (status) + { + case EidSupportStatus::UNAVAILABLE: + case EidSupportStatus::INTERNAL_ERROR: + newStatus = QmlSmartState::SMART_UNAVAILABLE; + break; + + case EidSupportStatus::AVAILABLE: + case EidSupportStatus::UP_TO_DATE: + case EidSupportStatus::UPDATE_AVAILABLE: + newStatus = QmlSmartState::SMART_NO_PROVISIONING; + break; + } + } +#else + Q_UNUSED(pResult) +#endif + + if (newStatus != mStatus) + { + if (newStatus == QmlSmartState::SMART_NO_PROVISIONING) + { + updateStatus(); + return; + } + + mCachedCardInfo = CardInfo(CardType::NONE); + setStatus(newStatus); + } +} + + void SmartModel::onDeletePersonalizationDone(const QVariant& pResult) { - Env::getSingleton()->showFeedback( - pResult.value() ? - //: LABEL ANDROID IOS - tr("Delete data was successful.") : - //: LABEL ANDROID IOS - tr("Delete data failed.")); - - Q_EMIT fireDeletePersonalizationDone(); + Q_EMIT fireDeletePersonalizationDone(pResult.value()); } void SmartModel::onDeleteSmartDone(const QVariant& pResult) { - Env::getSingleton()->showFeedback( - pResult.value() ? - //: LABEL ANDROID IOS - tr("Delete Smart-eID was successful.") : - //: LABEL ANDROID IOS - tr("Delete Smart-eID failed.")); +#if __has_include("SmartManager.h") + switch (pResult.value()) + { + case EidServiceResult::UNDEFINED: + case EidServiceResult::INFO: + case EidServiceResult::WARN: + case EidServiceResult::ERROR: + case EidServiceResult::UNSUPPORTED: + //: ERROR ANDROID IOS Deletion of the Smart-eID failed without a specific reason. + setErrorString(tr("The Smart-eID data and provisioning could not be successfully deleted from your device. Please note that this process requires an internet connection.")); + break; + + case EidServiceResult::OVERLOAD_PROTECTION: + //: ERROR ANDROID IOS Deletion of the Smart-eID failed because the server is overloaded. + setErrorString(tr("The Smart-eID data and provisioning could not be successfully deleted from your device because the server is currently facing too many requests. Please try again later.")); + break; + + case EidServiceResult::UNDER_MAINTENANCE: + //: ERROR ANDROID IOS Deletion of the Smart-eID failed because the server is being maintained. + setErrorString(tr("The Smart-eID data and provisioning could not be successfully deleted from your device because the server is currently under maintenance. Please try again later.")); + break; + + case EidServiceResult::NFC_NOT_ACTIVATED: + //: ERROR ANDROID IOS Deletion of the Smart-eID failed because NFC is not activated. + setErrorString(tr("The Smart-eID data and provisioning could not be successfully deleted from your device. In order to access the necessary device storage, active NFC functionality is required. Please activate NFC and restart the process.")); + break; + + case EidServiceResult::INTEGRITY_CHECK_FAILED: + //: ERROR ANDROID IOS Deletion of the Smart-eID failed because the Google Play Integrity Check failed. + setErrorString(tr("The Smart-eID data and provisioning could not be successfully deleted from your device. The Google Play Integrity Check failed.")); + break; + + case EidServiceResult::NOT_AUTHENTICATED: + //: ERROR ANDROID IOS Deletion of the Smart-eID failed because an authorization issue occurred. + setErrorString(tr("The Smart-eID data and provisioning could not be successfully deleted from your device. An authentication issue occurred (e.g. a resource was accessed without authorization or an unauthorized app tried to access a security component).")); + break; + + case EidServiceResult::NETWORK_CONNECTION_ERROR: + //: ERROR ANDROID IOS Deletion of the Smart-eID failed because a network connection error occurred. + setErrorString(tr("The Smart-eID data and provisioning could not be successfully deleted from your device. Please ensure that you have an internet connection and your antivirus software and firewall are not blocking the connection.")); + break; + + case EidServiceResult::SUCCESS: + break; + + } Q_EMIT fireDeleteSmartDone(); setProgress(0); +#else + Q_UNUSED(pResult) +#endif } @@ -117,7 +256,6 @@ void SmartModel::onUpdateStatusDone(const QVariant& pResult) switch (pResult.value()) { case EidStatus::INTERNAL_ERROR: - case EidStatus::UNAVAILABLE: newStatus = QmlSmartState::SMART_UNAVAILABLE; break; @@ -129,7 +267,8 @@ void SmartModel::onUpdateStatusDone(const QVariant& pResult) newStatus = QmlSmartState::SMART_NO_PERSONALIZATION; break; - case EidStatus::APPLET_UNUSABLE: + case EidStatus::UNUSABLE: + case EidStatus::CERT_EXPIRED: newStatus = QmlSmartState::SMART_UNUSABLE; break; @@ -162,7 +301,7 @@ int SmartModel::getProgress() const } -void SmartModel::onUpdatePinStatusDone(const ReaderManagerPlugInInfo& pInfo) +void SmartModel::onUpdatePinStatusDone(const ReaderInfo& pInfo) { if (pInfo.getPlugInType() != ReaderManagerPlugInType::SMART) { @@ -170,23 +309,12 @@ void SmartModel::onUpdatePinStatusDone(const ReaderManagerPlugInInfo& pInfo) } const auto& readerManager = Env::getSingleton(); - disconnect(readerManager, &ReaderManager::fireStatusChanged, this, &SmartModel::onUpdatePinStatusDone); + disconnect(readerManager, &ReaderManager::fireReaderPropertiesUpdated, this, &SmartModel::onUpdatePinStatusDone); + disconnect(readerManager, &ReaderManager::fireCardInfoChanged, this, &SmartModel::onUpdatePinStatusDone); - const auto& smartInfos = readerManager->getReaderInfos(ReaderFilter({ReaderManagerPlugInType::SMART})); - auto newStatus = QmlSmartState::SMART_READY; - - if (smartInfos.size() == 1) - { - mCachedCardInfo = smartInfos.constFirst().getCardInfo(); - } - else - { - newStatus = QmlSmartState::SMART_UNUSABLE; - qCCritical(card_smart) << "Expecting exactly one SmartReader!"; - } + mCachedCardInfo = pInfo.getCardInfo(); - readerManager->stopScan(ReaderManagerPlugInType::SMART); - setStatus(newStatus); + setStatus(QmlSmartState::SMART_READY); } @@ -197,6 +325,11 @@ void SmartModel::onStatusChanged(const ReaderManagerPlugInInfo& pInfo) return; } + if (mStatus == QmlSmartState::SMART_UNAVAILABLE && pInfo.isAvailable()) + { + updateStatus(); + } + Q_EMIT fireScanRunningChanged(); } @@ -212,6 +345,12 @@ SmartModel::QmlSmartState SmartModel::getSmartState() const } +QString SmartModel::getErrorString() const +{ + return mErrorString; +} + + void SmartModel::workflowFinished(QSharedPointer pContext) { if (pContext->hasNextWorkflowPending()) @@ -230,6 +369,23 @@ void SmartModel::workflowFinished(QSharedPointer pContext) } +void SmartModel::updateSupportInfo() +{ +#if __has_include("SmartManager.h") + if (mStatus != QmlSmartState::SMART_UPDATING_STATUS && mStatus != QmlSmartState::SMART_READY) + { + setErrorString(QString()); + setStatus(QmlSmartState::SMART_UPDATING_STATUS); + + Env::getSingleton()->callExecuteCommand([] { + return QVariant::fromValue(SmartManager::get()->updateSupportInfo()); + }, this, &SmartModel::onUpdateSupportInfoDone); + return; + } +#endif +} + + void SmartModel::deletePersonalization() { #if __has_include("SmartManager.h") @@ -252,9 +408,10 @@ void SmartModel::deleteSmart() }; setProgress(0); + setErrorString(QString()); Env::getSingleton()->callExecuteCommand([progressHandler] { - return SmartManager::get()->deleteSmart(progressHandler); + return QVariant::fromValue(SmartManager::get()->deleteSmart(progressHandler)); }, this, &SmartModel::onDeleteSmartDone); #endif @@ -262,7 +419,7 @@ void SmartModel::deleteSmart() } -MobileEidType SmartModel::getMobileEidType() +MobileEidType SmartModel::getMobileEidType() const { return mCachedCardInfo.getMobileEidType(); } @@ -270,5 +427,5 @@ MobileEidType SmartModel::getMobileEidType() bool SmartModel::isScanRunning() const { - return Env::getSingleton()->isScanRunning(ReaderManagerPlugInType::SMART); + return Env::getSingleton()->getPlugInInfo(ReaderManagerPlugInType::SMART).isScanRunning(); } diff --git a/src/ui/qml/SmartModel.h b/src/ui/qml/SmartModel.h index 553b4a220..a12137d5b 100644 --- a/src/ui/qml/SmartModel.h +++ b/src/ui/qml/SmartModel.h @@ -9,7 +9,6 @@ #pragma once #include "Env.h" -#include "ReaderInfo.h" #include "ReaderManagerPlugInInfo.h" #include "context/WorkflowContext.h" @@ -32,6 +31,7 @@ class SmartModel friend class ::test_SmartModel; Q_PROPERTY(QmlSmartState smartState READ getSmartState NOTIFY fireSmartStateChanged) + Q_PROPERTY(QString errorString READ getErrorString NOTIFY fireErrorStringChanged) Q_PROPERTY(int progress READ getProgress NOTIFY fireProgressChanged) Q_PROPERTY(bool isScanRunning READ isScanRunning NOTIFY fireScanRunningChanged) @@ -50,40 +50,46 @@ class SmartModel private: SmartModel(); QmlSmartState mStatus; + QString mErrorString; CardInfo mCachedCardInfo; int mProgress; void updateStatus(); + void setErrorString(const QString& pError); void updatePinStatus(); void setProgress(int pProgress); void setStatus(QmlSmartState pNewStatus); - bool isScanRunning() const; + [[nodiscard]] bool isScanRunning() const; private Q_SLOTS: + void onUpdateSupportInfoDone(const QVariant& pResult); void onDeletePersonalizationDone(const QVariant& pResult); void onDeleteSmartDone(const QVariant& pResult); void onUpdateStatusDone(const QVariant& pResult); - void onUpdatePinStatusDone(const ReaderManagerPlugInInfo& pInfo); + void onUpdatePinStatusDone(const ReaderInfo& pInfo); void onStatusChanged(const ReaderManagerPlugInInfo& pInfo); public: QmlSmartState getSmartState() const; + [[nodiscard]] QString getErrorString() const; [[nodiscard]] int getProgress() const; void workflowFinished(QSharedPointer pContext); - [[nodiscard]] MobileEidType getMobileEidType(); + [[nodiscard]] MobileEidType getMobileEidType() const; + Q_INVOKABLE void updateSupportInfo(); Q_INVOKABLE void deletePersonalization(); Q_INVOKABLE void deleteSmart(); Q_SIGNALS: void fireSmartStateChanged(); void fireDeleteSmartDone(); - void fireDeletePersonalizationDone(); + void fireDeletePersonalizationDone(bool pSuccess); void fireProgressChanged(); void fireScanRunningChanged(); + void fireErrorStringChanged(); }; } // namespace governikus diff --git a/src/ui/qml/TrayIcon.cpp b/src/ui/qml/TrayIcon.cpp index b813f804f..2d13fc3ae 100644 --- a/src/ui/qml/TrayIcon.cpp +++ b/src/ui/qml/TrayIcon.cpp @@ -77,15 +77,13 @@ void TrayIcon::create() mTrayIcon->setToolTip(QCoreApplication::applicationName()); - const auto& autoStartEnabled = Env::getSingleton()->getGeneralSettings().isAutoStart(); - #ifdef Q_OS_MACOS - if (autoStartEnabled) - #endif + const auto& generalSettings = Env::getSingleton()->getGeneralSettings(); + if (generalSettings.showTrayIcon()) { mTrayIcon->show(); } - if (!autoStartEnabled) + if (!generalSettings.isAutoStart()) { //: LABEL DESKTOP Env::getSingleton()->showFeedback(tr("Application was started.")); @@ -120,7 +118,7 @@ void TrayIcon::updateMenu() #endif //: LABEL DESKTOP - const auto quitAction = new QAction(tr("Quit AusweisApp2"), trayIconMenu); + const auto quitAction = new QAction(tr("Quit %1").arg(QCoreApplication::applicationName()), trayIconMenu); connect(quitAction, &QAction::triggered, this, &TrayIcon::fireQuit); trayIconMenu->addAction(quitAction); } diff --git a/src/ui/qml/UIPlugInQml.cpp b/src/ui/qml/UIPlugInQml.cpp index 527fde531..7c616b20a 100644 --- a/src/ui/qml/UIPlugInQml.cpp +++ b/src/ui/qml/UIPlugInQml.cpp @@ -26,28 +26,30 @@ #include "PersonalizationModel.h" #include "PinResetInformationModel.h" #include "PlatformTools.h" -#include "ProviderCategoryFilterModel.h" #include "ReaderScanEnabler.h" #include "ReleaseInformationModel.h" #include "RemoteServiceModel.h" #include "SelfAuthModel.h" #include "Service.h" +#include "SettingsModel.h" #include "SmartModel.h" #include "SurveyModel.h" #include "UILoader.h" #include "VersionInformationModel.h" #include "VersionNumber.h" #include "VolatileSettings.h" +#include "WorkflowRequest.h" #include "context/AuthContext.h" #include "context/ChangePinContext.h" #include "context/SelfAuthContext.h" #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) - #include "SelfDiagnosisModel.h" + #include "DiagnosisModel.h" #endif #if defined(Q_OS_WIN) || (defined(Q_OS_BSD4) && !defined(Q_OS_IOS)) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) #include "ReaderModel.h" + #define ENABLE_READERMODEL #endif #if __has_include("context/PersonalizationContext.h") @@ -55,7 +57,6 @@ #endif #if defined(Q_OS_ANDROID) - #include "DeviceInfo.h" #include "UILoader.h" #include @@ -80,6 +81,9 @@ #include #include #include +#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)) + #include +#endif #include #include @@ -96,6 +100,7 @@ INIT_FUNCTION([] { namespace { +#if defined(ENABLE_READERMODEL) template [[nodiscard]] QObject* provideQmlType(const QQmlEngine*, const QJSEngine*) { @@ -103,6 +108,9 @@ template } +#endif + + template [[nodiscard]] QObject* provideSingletonQmlType(const QQmlEngine*, const QJSEngine*) { @@ -158,42 +166,21 @@ UIPlugInQml::UIPlugInQml() , mUpdateInformationPending(false) , mTrayIcon() , mHighContrastEnabled(false) + , mDarkMode(false) #if defined(Q_OS_MACOS) , mMenuBar() #endif , mShowFocusIndicator(false) + , mScaleFactor(DEFAULT_SCALE_FACTOR) + , mFontScaleFactor(getSystemFontScaleFactor()) +#ifdef Q_OS_IOS + , mPrivate(new Private()) +#endif { Env::getSingleton()->setUsedAsSDK(false); -#if defined(Q_OS_ANDROID) - // see QTBUG-69494 - if (DeviceInfo::getFingerprint().contains(QLatin1String("OnePlus"))) - { - const QDir dir(QStringLiteral("/system/fonts")); - const auto entries = dir.entryInfoList({QStringLiteral("Roboto-*.ttf")}, QDir::Files); - for (const auto& file : entries) - { - if (file.fileName().contains(QLatin1String("_subset"))) - { - qCDebug(qml) << "Ignore font" << file; - continue; - } - qCDebug(qml) << "Add font" << file; - QFontDatabase::addApplicationFont(file.absoluteFilePath()); - } - } - - QGuiApplication::setFont(QFont(QStringLiteral("Roboto"))); -#elif defined(Q_OS_LINUX) - if (auto font = QGuiApplication::font(); QFontMetrics(font.family()).horizontalAdvance(QLatin1Char('m')) > 15) - { - // Fonts like "DejaVu Sans" (used on some Linux distributions) are unusually wide when compared to Windows' and macOS' default font. This will break some layouts where this wasn't taken into account. - const auto oldFamily = QFontInfo(font).family(); - font.setFamily(QStringLiteral("Arial")); // will usually resolve to "Liberation Sans" or "Arimo" - qCDebug(qml) << "Changing font family from" << oldFamily << "to" << QFontInfo(font).family(); - QGuiApplication::setFont(font); - } -#endif + QFontDatabase::addApplicationFont(QStringLiteral(":/fonts/Roboto-Medium.ttf")); + onUseSystemFontChanged(); #ifdef Q_OS_WIN QQuickWindow::setTextRenderType(QQuickWindow::NativeTextRendering); @@ -207,6 +194,8 @@ UIPlugInQml::UIPlugInQml() connect(&mTrayIcon, &TrayIcon::fireQuit, this, [this] { Q_EMIT fireQuitApplicationRequest(); }); + connect(this, &UIPlugInQml::fireAppConfigChanged, this, &UIPlugInQml::onAppConfigChanged); + onAppConfigChanged(); qApp->installEventFilter(this); } @@ -219,6 +208,7 @@ void UIPlugInQml::registerQmlTypes() qmlRegisterUncreatableMetaObject(EnumReaderManagerPlugInType::staticMetaObject, "Governikus.Type.ReaderPlugIn", 1, 0, "ReaderPlugIn", QStringLiteral("Not creatable as it is an enum type")); qmlRegisterUncreatableMetaObject(EnumPasswordType::staticMetaObject, "Governikus.Type.PasswordType", 1, 0, "PasswordType", QStringLiteral("Not creatable as it is an enum type")); qmlRegisterUncreatableMetaObject(FormattedTextModel::staticMetaObject, "Governikus.Type.FormattedTextModel", 1, 0, "LineType", QStringLiteral("Not creatable as it is an enum type")); + qmlRegisterUncreatableMetaObject(EnumModeOption::staticMetaObject, "Governikus.Type.ModeOption", 1, 0, "ModeOption", QStringLiteral("Not creatable as it is an enum type")); registerQmlType(); registerQmlType(); @@ -226,15 +216,13 @@ void UIPlugInQml::registerQmlTypes() registerQmlType(); registerQmlType(); registerQmlType(); - - registerQmlSingletonType(&provideQmlType); - registerQmlSingletonType(&provideQmlType); -#if defined(Q_OS_WIN) || (defined(Q_OS_BSD4) && !defined(Q_OS_IOS)) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) - registerQmlSingletonType(&provideQmlType); + registerQmlType(); +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) + registerQmlType(); #endif -#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) - registerQmlSingletonType(&provideSingletonQmlType); +#if defined(ENABLE_READERMODEL) + registerQmlSingletonType(&provideQmlType); #endif registerQmlSingletonType(&provideSingletonQmlType); @@ -253,7 +241,6 @@ void UIPlugInQml::registerQmlTypes() registerQmlSingletonType(&provideSingletonQmlType); registerQmlSingletonType(&provideSingletonQmlType); registerQmlSingletonType(&provideSingletonQmlType); - registerQmlSingletonType(&provideSingletonQmlType); registerQmlSingletonType(&provideSingletonQmlType); registerQmlSingletonType(&provideSingletonQmlType); } @@ -264,12 +251,15 @@ void UIPlugInQml::init() // Activate logging of Qt scenegraph information on startup, e.g. GL_RENDERER, GL_VERSION, ... qputenv("QSG_INFO", "1"); -#ifdef Q_OS_ANDROID - const auto orientation = isTabletLayout() - ? "SCREEN_ORIENTATION_SENSOR_LANDSCAPE" - : "SCREEN_ORIENTATION_PORTRAIT"; - QJniObject context = QNativeInterface::QAndroidApplication::context(); - context.callMethod("setRequestedOrientation", "(I)V", QJniObject::getStaticField("android/content/pm/ActivityInfo", orientation)); +#if defined(Q_OS_WIN) || defined(Q_OS_MACOS) + const QStringList cachePaths = QStandardPaths::standardLocations(QStandardPaths::CacheLocation); + if (!cachePaths.isEmpty() && !cachePaths.first().isEmpty()) + { + QString cacheBasePath = cachePaths.first(); + cacheBasePath.replace(QStringLiteral("AusweisApp"), QStringLiteral("AusweisApp2")); + cacheBasePath.append(QStringLiteral("/qmlcache")); + qputenv("QML_DISK_CACHE_PATH", cacheBasePath.toUtf8()); + } #endif // https://bugreports.qt.io/browse/QTBUG-98098 @@ -281,11 +271,7 @@ void UIPlugInQml::init() connect(mEngine.data(), &QQmlApplicationEngine::objectCreated, this, &UIPlugInQml::onQmlObjectCreated, Qt::QueuedConnection); mEngine->rootContext()->setContextProperty(QStringLiteral("plugin"), this); -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) mEngine->setExtraFileSelectors(mExplicitPlatformStyle.split(QLatin1Char(','))); -#else - (new QQmlFileSelector(mEngine.data()))->setExtraSelectors(mExplicitPlatformStyle.split(QLatin1Char(','))); -#endif UIPlugInQml::registerQmlTypes(); @@ -298,13 +284,16 @@ void UIPlugInQml::init() QQuickWindow* rootWindow = getRootWindow(); if (rootWindow != nullptr) { - connect(rootWindow, &QQuickWindow::sceneGraphInitialized, this, &UIPlugInQml::fireSafeAreaMarginsChanged); - connect(rootWindow->screen(), &QScreen::orientationChanged, this, &UIPlugInQml::fireSafeAreaMarginsChanged); + connect(rootWindow, &QQuickWindow::sceneGraphInitialized, this, &UIPlugInQml::fireSafeAreaMarginsChanged, Qt::QueuedConnection); + connect(rootWindow->screen(), &QScreen::orientationChanged, this, &UIPlugInQml::fireSafeAreaMarginsChanged, Qt::QueuedConnection); connect(rootWindow, &QQuickWindow::sceneGraphError, this, &UIPlugInQml::onSceneGraphError); qCDebug(qml) << "Using renderer interface:" << rootWindow->rendererInterface()->graphicsApi(); #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) rootWindow->resize(getInitialWindowSize()); +#endif +#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)) + setOsDarkMode(qApp->styleHints()->colorScheme() == Qt::ColorScheme::Dark); #endif } @@ -312,7 +301,7 @@ void UIPlugInQml::init() } -void UIPlugInQml::hideFromTaskbar() +void UIPlugInQml::hideFromTaskbar() const { PlatformTools::hideFromTaskbar(); } @@ -320,11 +309,7 @@ void UIPlugInQml::hideFromTaskbar() QString UIPlugInQml::getPlatformSelectors() const { -#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) - QString qtVersion = QStringLiteral("qt5,"); -#else - QString qtVersion = QStringLiteral("qt6,"); -#endif + const auto& qtVersion = QStringLiteral("qt6,"); #ifndef QT_NO_DEBUG const char* const overrideSelector = "OVERRIDE_PLATFORM_SELECTOR"; @@ -342,11 +327,9 @@ QString UIPlugInQml::getPlatformSelectors() const #if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) const QString platform = QStringLiteral("mobile,"); - const QString tablet = (isTabletLayout() ? QStringLiteral("tablet,") : QStringLiteral("phone,")); const QString brand = QGuiApplication::platformName(); #else const QString platform = QStringLiteral("desktop,"); - const QString tablet; #if defined(Q_OS_WIN) const QString brand = QStringLiteral("win"); #else @@ -354,57 +337,62 @@ QString UIPlugInQml::getPlatformSelectors() const #endif #endif - return qtVersion + platform + tablet + brand; + return qtVersion + platform + brand; } -void UIPlugInQml::onWorkflowStarted(QSharedPointer pContext) +void UIPlugInQml::onWorkflowStarted(const QSharedPointer& pRequest) { if (isDominated()) { return; } - pContext->claim(this); + const auto& context = pRequest->getContext(); + context->claim(this); Env::getSingleton()->keepScreenOn(true); - Env::getSingleton()->resetContext(pContext); - Env::getSingleton()->resetContext(pContext); + Env::getSingleton()->resetContext(context); + Env::getSingleton()->resetContext(context); Env::getSingleton()->setDelay(1000); - if (auto changePinContext = pContext.objectCast()) + if (auto changePinContext = context.objectCast()) { - onShowUi(UiModule::PINMANAGEMENT); + if (changePinContext->isActivateUi()) + { + onShowUi(UiModule::PINMANAGEMENT); + } Env::getSingleton()->resetChangePinContext(changePinContext); } #if __has_include("context/PersonalizationContext.h") - if (auto smartContext = pContext.objectCast()) + if (auto smartContext = context.objectCast()) { - onShowUi(UiModule::SMART); - Env::getSingleton()->startWatching(); + onShowUi(UiModule::SMART_EID); Env::getSingleton()->resetPersonalizationContext(smartContext); Env::getSingleton()->resetContext(smartContext); Env::getSingleton()->resetContext(smartContext); } else #endif - - if (auto authContext = pContext.objectCast()) { - onShowUi(UiModule::IDENTIFY); - Env::getSingleton()->startWatching(); - Env::getSingleton()->resetAuthContext(authContext); - Env::getSingleton()->resetContext(authContext); - Env::getSingleton()->resetContext(authContext); + if (auto authContext = context.objectCast()) + { + if (authContext->isActivateUi()) + { + onShowUi(UiModule::IDENTIFY); + } + Env::getSingleton()->resetAuthContext(authContext); + Env::getSingleton()->resetContext(authContext); + Env::getSingleton()->resetContext(authContext); + } } - if (auto authContext = pContext.objectCast()) + if (auto authContext = context.objectCast()) { - onShowUi(UiModule::IDENTIFY); Env::getSingleton()->resetContext(authContext); } - if (auto remoteServiceContext = pContext.objectCast()) + if (auto remoteServiceContext = context.objectCast()) { Env::getSingleton()->resetRemoteServiceContext(remoteServiceContext); Env::getSingleton()->resetContext(remoteServiceContext); @@ -413,21 +401,21 @@ void UIPlugInQml::onWorkflowStarted(QSharedPointer pContext) } -void UIPlugInQml::onWorkflowFinished(QSharedPointer pContext) +void UIPlugInQml::onWorkflowFinished(const QSharedPointer& pRequest) { + const auto& context = pRequest->getContext(); Env::getSingleton()->keepScreenOn(false); Env::getSingleton()->resetContext(); Env::getSingleton()->resetContext(); Env::getSingleton()->setDelay(); - if (pContext.objectCast()) + if (context.objectCast()) { Env::getSingleton()->resetChangePinContext(); } - if (const auto& context = pContext.objectCast()) + if (const auto& authContext = context.objectCast()) { - Env::getSingleton()->stopWatching(); Env::getSingleton()->resetAuthContext(); Env::getSingleton()->resetContext(); Env::getSingleton()->resetContext(); @@ -437,25 +425,25 @@ void UIPlugInQml::onWorkflowFinished(QSharedPointer pContext) // Only hide the UI if we don't need to show the update information view. This behaviour ensures that // the user is (aggressively) notified about a pending update if the AA2 is only shown for authentication // workflows and never manually brought to foreground in between. - if (!pContext.objectCast() + if (!context.objectCast() #if __has_include("context/PersonalizationContext.h") - && !pContext.objectCast() + && !context.objectCast() #endif - && !pContext->hasNextWorkflowPending() + && !context->hasNextWorkflowPending() && generalSettings.isAutoCloseWindowAfterAuthentication() && !showUpdateInformationIfPending() - && !context->showChangePinView()) + && !authContext->showChangePinView()) { onHideUi(); } } - if (pContext.objectCast()) + if (context.objectCast()) { Env::getSingleton()->resetContext(); } - if (pContext.objectCast()) + if (context.objectCast()) { Env::getSingleton()->resetRemoteServiceContext(); Env::getSingleton()->resetContext(); @@ -463,24 +451,26 @@ void UIPlugInQml::onWorkflowFinished(QSharedPointer pContext) } #if __has_include("context/PersonalizationContext.h") - if (pContext.objectCast()) + if (context.objectCast()) { Env::getSingleton()->resetPersonalizationContext(); } #endif - Env::getSingleton()->workflowFinished(pContext); + Env::getSingleton()->workflowFinished(context); } void UIPlugInQml::onApplicationInitialized() { + connect(Env::getSingleton(), &AuthModel::fireShowUiRequest, this, &UIPlugIn::fireShowUiRequested); connect(Env::getSingleton(), &ChangePinModel::fireStartWorkflow, this, &UIPlugIn::fireWorkflowRequested); connect(Env::getSingleton(), &SelfAuthModel::fireStartWorkflow, this, &UIPlugIn::fireWorkflowRequested); connect(Env::getSingleton(), &RemoteServiceModel::fireStartWorkflow, this, &UIPlugIn::fireWorkflowRequested); connect(Env::getSingleton(), &PersonalizationModel::fireStartWorkflow, this, &UIPlugIn::fireWorkflowRequested); connect(Env::getSingleton()->getEventHandler(), &LogEventHandler::fireRawLog, this, &UIPlugInQml::onRawLog, Qt::QueuedConnection); connect(Env::getSingleton(), &SettingsModel::fireAutoStartChanged, this, &UIPlugInQml::onAutoStartChanged); + connect(Env::getSingleton(), &SettingsModel::fireUseSystemFontChanged, this, &UIPlugInQml::onUseSystemFontChanged); const auto* service = Env::getSingleton(); connect(service, &Service::fireAppcastFinished, this, &UIPlugInQml::onUpdateAvailable); @@ -495,14 +485,11 @@ void UIPlugInQml::onApplicationStarted() mTrayIcon.create(); connect(this, &UIPlugInQml::fireTranslationChanged, &mTrayIcon, &TrayIcon::onTranslationChanged); -#if defined(Q_OS_WIN) || (defined(Q_OS_BSD4) && !defined(Q_OS_IOS)) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) +#if defined(ENABLE_READERMODEL) const auto& generalSettings = Env::getSingleton()->getGeneralSettings(); const bool showSetupAssistant = Enum::fromString(generalSettings.getStartupModule(), UiModule::TUTORIAL) == UiModule::TUTORIAL; const bool developerMode = generalSettings.isDeveloperMode(); - bool missingTrayIcon = !QSystemTrayIcon::isSystemTrayAvailable(); - #ifdef Q_OS_MACOS - missingTrayIcon |= !Env::getSingleton()->getGeneralSettings().isAutoStart(); - #endif + const bool missingTrayIcon = !QSystemTrayIcon::isSystemTrayAvailable() || !Env::getSingleton()->getGeneralSettings().showTrayIcon(); if (missingTrayIcon || showSetupAssistant || developerMode) #endif { @@ -512,6 +499,10 @@ void UIPlugInQml::onApplicationStarted() #if defined(Q_OS_ANDROID) QNativeInterface::QAndroidApplication::hideSplashScreen(250); #endif + +#ifdef Q_OS_WIN + Env::getSingleton()->getGeneralSettings().migrateSettings(); +#endif } @@ -591,7 +582,7 @@ void UIPlugInQml::onShowUserInformation(const QString& pMessage) } -void UIPlugInQml::onUpdateScheduled() +void UIPlugInQml::onUpdateScheduled() const { if (!isHidden()) { @@ -616,21 +607,6 @@ void UIPlugInQml::show() } -bool UIPlugInQml::isTabletLayout() const -{ - const auto screenOrientationSetting = Env::getSingleton()->getGeneralSettings().getScreenOrientation(); - if (screenOrientationSetting == QLatin1String("landscape")) - { - return true; - } - if (screenOrientationSetting == QLatin1String("portrait")) - { - return false; - } - return isTablet(); -} - - bool UIPlugInQml::showUpdateInformationIfPending() { if (!mUpdateInformationPending) @@ -653,6 +629,14 @@ bool UIPlugInQml::eventFilter(QObject* pObj, QEvent* pEvent) return true; } +#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)) + if (pEvent->type() == QEvent::ThemeChange) + { + setOsDarkMode(qApp->styleHints()->colorScheme() == Qt::ColorScheme::Dark); + return true; + } +#endif + if (pEvent->type() == QEvent::Quit) { Q_EMIT fireQuitApplicationRequest(); @@ -739,17 +723,7 @@ bool UIPlugInQml::isTablet() const void UIPlugInQml::onQmlWarnings(const QList& pWarnings) { -#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 1)) - for (const auto& entry : pWarnings) - { - if (!entry.description().contains(QLatin1String("QML Connections: Implicitly defined onFoo properties in Connections are deprecated. Use this syntax instead:"))) - { - ++mQmlEngineWarningCount; - } - } -#else mQmlEngineWarningCount += pWarnings.size(); -#endif #ifndef QT_NO_DEBUG for (const auto& warning : pWarnings) @@ -918,6 +892,34 @@ bool UIPlugInQml::isHighContrastEnabled() const #endif +bool UIPlugInQml::isOsDarkModeEnabled() const +{ + return mDarkMode; +} + + +void UIPlugInQml::setOsDarkMode(bool pState) +{ + if (mDarkMode != pState) + { + qCDebug(qml) << "Dark mode setting has changed"; + mDarkMode = pState; + Q_EMIT fireOsDarkModeChanged(); + } +} + + +bool UIPlugInQml::isOsDarkModeSupported() const +{ +#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)) + return true; + +#else + return false; + +#endif +} + QString UIPlugInQml::getFixedFontFamily() const { @@ -928,22 +930,51 @@ QString UIPlugInQml::getFixedFontFamily() const QSize UIPlugInQml::getInitialWindowSize() const { const QString platform = getPlatformSelectors(); - bool isTablet = platform.contains(QLatin1String("tablet")); - bool isPhone = platform.contains(QLatin1String("phone")); + bool isMobile = platform.contains(QLatin1String("mobile")); + return isMobile ? QSize(432, 768) : QSize(960, 720); +} + - if (isTablet || isPhone) +bool UIPlugInQml::getShowFocusIndicator() const +{ + return mShowFocusIndicator; +} + + +qreal UIPlugInQml::getScaleFactor() const +{ + + return mScaleFactor; +} + + +void UIPlugInQml::setScaleFactor(qreal pScaleFactor) +{ + pScaleFactor *= DEFAULT_SCALE_FACTOR; + + if (qAbs(pScaleFactor - mScaleFactor) > 0) { - // Use 4:3 in landscape for tablets and 16:9 in portrait for phones. - return QSize(isTablet ? 1024 : 432, 768); + mScaleFactor = pScaleFactor; + Q_EMIT fireScaleFactorChanged(); } - return QSize(960, 720); } -bool UIPlugInQml::getShowFocusIndicator() const +qreal UIPlugInQml::getFontScaleFactor() const { - return mShowFocusIndicator; + return mFontScaleFactor; +} + + +void UIPlugInQml::setFontScaleFactor(qreal pFactor) +{ + if (pFactor != mFontScaleFactor) + { + qCDebug(qml) << "System font scale factor has changed"; + mFontScaleFactor = pFactor; + Q_EMIT fireFontScaleFactorChanged(); + } } @@ -958,26 +989,58 @@ void UIPlugInQml::onWindowPaletteChanged() } +void UIPlugInQml::onUseSystemFontChanged() const +{ + if (Env::getSingleton()->getGeneralSettings().isUseSystemFont()) + { + auto font = QFontDatabase::systemFont(QFontDatabase::GeneralFont); + if (QFontMetrics(font.family()).horizontalAdvance(QLatin1Char('m')) > 15) + { + // Fonts like "DejaVu Sans" (used on some Linux distributions) are unusually wide when compared to Windows' and macOS' default font. This will break some layouts where this wasn't taken into account. + const auto oldFamily = QFontInfo(font).family(); + font.setFamily(QStringLiteral("Arial")); // will usually resolve to "Liberation Sans" or "Arimo" + qCDebug(qml) << "Changing font family from" << oldFamily << "to" << QFontInfo(font).family(); + } + QGuiApplication::setFont(font); + return; + } + + const auto robotoMedium = QStringLiteral("Roboto Medium"); + const auto roboto = QStringLiteral("Roboto"); + const auto families = QFontDatabase::families(); + if (families.contains(robotoMedium)) + { + QGuiApplication::setFont(QFont(robotoMedium)); + } + else if (families.contains(roboto)) + { + QGuiApplication::setFont(QFont(roboto)); + } + else + { + qCCritical(qml) << "Roboto was not found in the FontDatabase. Staying on system default."; + } +} + + void UIPlugInQml::onAutoStartChanged() { -#ifdef Q_OS_MACOS - mTrayIcon.setVisible(Env::getSingleton()->getGeneralSettings().isAutoStart()); -#endif + mTrayIcon.setVisible(Env::getSingleton()->getGeneralSettings().showTrayIcon()); } -void UIPlugInQml::applyPlatformStyle(const QString& pPlatformStyle) +void UIPlugInQml::onAppConfigChanged() { -#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) - QString platformStyle = QStringLiteral("qt5,%1").arg(pPlatformStyle); -#else - QString platformStyle = QStringLiteral("qt6,%1").arg(pPlatformStyle); -#endif + setFontScaleFactor(getSystemFontScaleFactor()); +} + +void UIPlugInQml::applyPlatformStyle(const QString& pPlatformStyle) +{ + const auto& platformStyle = QStringLiteral("qt6,%1").arg(pPlatformStyle); if (mExplicitPlatformStyle != platformStyle) { mExplicitPlatformStyle = platformStyle; - Env::getSingleton()->getGeneralSettings().setScreenOrientation(pPlatformStyle.indexOf(QLatin1String("tablet")) == -1 ? QStringLiteral("portrait") : QStringLiteral("landscape")); doRefresh(); } } diff --git a/src/ui/qml/UIPlugInQml.h b/src/ui/qml/UIPlugInQml.h index 91f1499e2..b06544087 100644 --- a/src/ui/qml/UIPlugInQml.h +++ b/src/ui/qml/UIPlugInQml.h @@ -9,10 +9,7 @@ #pragma once #include "GlobalStatus.h" -#include "HistoryModel.h" -#include "NumberModel.h" #include "ProxyCredentials.h" -#include "SettingsModel.h" #include "TrayIcon.h" #include "UIPlugIn.h" @@ -23,6 +20,14 @@ #include #endif +#ifdef Q_OS_IOS +Q_FORWARD_DECLARE_OBJC_CLASS(FontChangeTracker); +#endif + + +class test_UIPlugInQml; + + namespace governikus { @@ -39,32 +44,51 @@ class UIPlugInQml Q_PROPERTY(bool dominated READ isDominated NOTIFY fireDominatorChanged) Q_PROPERTY(QVariantMap safeAreaMargins READ getSafeAreaMargins NOTIFY fireSafeAreaMarginsChanged) Q_PROPERTY(bool highContrastEnabled READ isHighContrastEnabled NOTIFY fireHighContrastEnabledChanged) + Q_PROPERTY(bool osDarkModeEnabled READ isOsDarkModeEnabled NOTIFY fireOsDarkModeChanged) + Q_PROPERTY(bool osDarkModeSupported READ isOsDarkModeSupported) Q_PROPERTY(QString fixedFontFamily READ getFixedFontFamily CONSTANT) - Q_PROPERTY(bool tablet READ isTablet CONSTANT) - Q_PROPERTY(bool isTabletLayout READ isTabletLayout CONSTANT) Q_PROPERTY(QSize initialWindowSize READ getInitialWindowSize CONSTANT) Q_PROPERTY(bool showFocusIndicator READ getShowFocusIndicator NOTIFY fireShowFocusIndicator) + Q_PROPERTY(qreal scaleFactor READ getScaleFactor WRITE setScaleFactor NOTIFY fireScaleFactorChanged) + Q_PROPERTY(qreal fontScaleFactor READ getFontScaleFactor NOTIFY fireFontScaleFactorChanged) + friend class ::test_UIPlugInQml; private: QScopedPointer mEngine; - int mQmlEngineWarningCount; + qsizetype mQmlEngineWarningCount; QString mExplicitPlatformStyle; bool mUpdateInformationPending; TrayIcon mTrayIcon; QString mDominator; bool mHighContrastEnabled; + bool mDarkMode; #if defined(Q_OS_MACOS) QMenuBar mMenuBar; #endif bool mShowFocusIndicator; + constexpr static qreal DEFAULT_SCALE_FACTOR = 0.6; + qreal mScaleFactor; + qreal mFontScaleFactor; [[nodiscard]] QString getPlatformSelectors() const; [[nodiscard]] static QUrl getPath(const QString& pRelativePath, bool pQrc = true); [[nodiscard]] QQuickWindow* getRootWindow() const; [[nodiscard]] bool isHidden() const; [[nodiscard]] bool isTablet() const; - [[nodiscard]] bool isTabletLayout() const; [[nodiscard]] bool showUpdateInformationIfPending(); + [[nodiscard]] qreal getSystemFontScaleFactor() const; + void setFontScaleFactor(qreal pFactor); + void setOsDarkMode(bool pState); + +#ifdef Q_OS_IOS + struct Private + { + Private(); + ~Private(); + FontChangeTracker* const mFontChangeTracker; + }; + const QScopedPointer mPrivate; +#endif protected: [[nodiscard]] bool eventFilter(QObject* pObj, QEvent* pEvent) override; @@ -82,13 +106,19 @@ class UIPlugInQml [[nodiscard]] bool isDominated() const; [[nodiscard]] QVariantMap getSafeAreaMargins() const; [[nodiscard]] bool isHighContrastEnabled() const; + [[nodiscard]] bool isOsDarkModeEnabled() const; + [[nodiscard]] bool isOsDarkModeSupported() const; [[nodiscard]] QString getFixedFontFamily() const; [[nodiscard]] QSize getInitialWindowSize() const; [[nodiscard]] bool getShowFocusIndicator() const; + [[nodiscard]] qreal getScaleFactor() const; + void setScaleFactor(qreal pScaleFactor); + [[nodiscard]] qreal getFontScaleFactor() const; + Q_INVOKABLE void applyPlatformStyle(const QString& pPlatformStyle); Q_INVOKABLE void init(); - Q_INVOKABLE void hideFromTaskbar(); + Q_INVOKABLE void hideFromTaskbar() const; Q_SIGNALS: void fireShowRequest(UiModule pModule); @@ -96,15 +126,19 @@ class UIPlugInQml void fireDominatorChanged(); void fireSafeAreaMarginsChanged(); void fireHighContrastEnabledChanged(); + void fireOsDarkModeChanged(); void fireProxyAuthenticationRequired(ProxyCredentials* pProxyCredentials); void fireTranslationChanged(); void fireShowFocusIndicator(); + void fireScaleFactorChanged(); + void fireFontScaleFactorChanged(); + void fireAppConfigChanged(); private Q_SLOTS: void show(); void doShutdown() override; - void onWorkflowStarted(QSharedPointer pContext) override; - void onWorkflowFinished(QSharedPointer pContext) override; + void onWorkflowStarted(const QSharedPointer& pRequest) override; + void onWorkflowFinished(const QSharedPointer& pRequest) override; void onApplicationInitialized() override; void onApplicationStarted() override; void onShowUi(UiModule pModule) override; @@ -114,7 +148,7 @@ class UIPlugInQml void onUiDomination(const UIPlugIn* pUi, const QString& pInformation, bool pAccepted) override; void onUiDominationReleased() override; void onShowUserInformation(const QString& pMessage) override; - void onUpdateScheduled(); + void onUpdateScheduled() const; void onUpdateAvailable(bool pUpdateAvailable, const GlobalStatus& pStatus); void onQmlWarnings(const QList& pWarnings); @@ -124,7 +158,9 @@ class UIPlugInQml void onRawLog(const QString& pMessage, const QString& pCategoryName); void onWindowPaletteChanged(); + void onUseSystemFontChanged() const; void onAutoStartChanged(); + void onAppConfigChanged(); public Q_SLOTS: void doRefresh(); diff --git a/src/ui/qml/UIPlugInQml_android.cpp b/src/ui/qml/UIPlugInQml_android.cpp new file mode 100644 index 000000000..f0f5ae086 --- /dev/null +++ b/src/ui/qml/UIPlugInQml_android.cpp @@ -0,0 +1,68 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ + +#include "UIPlugInQml.h" + +#include "Env.h" +#include "UILoader.h" + +#include +#include +#include + +Q_DECLARE_LOGGING_CATEGORY(qml) + +using namespace governikus; + + +extern "C" +{ +JNIEXPORT void JNICALL Java_com_governikus_ausweisapp2_MainActivity_notifyConfigurationChanged(JNIEnv* pEnv, jobject pObj) +{ + Q_UNUSED(pEnv) + Q_UNUSED(pObj) + QMetaObject::invokeMethod(QCoreApplication::instance(), [] { + if (auto* uiPlugIn = Env::getSingleton()->getLoaded()) + { + Q_EMIT uiPlugIn->fireAppConfigChanged(); + } + }, Qt::QueuedConnection); +} + + +qreal UIPlugInQml::getSystemFontScaleFactor() const +{ + QJniObject ctx = QNativeInterface::QAndroidApplication::context(); + if (!ctx.isValid()) + { + qCWarning(qml) << "Android context is invalid" << ctx.toString(); + return 1.0; + } + auto rsc = ctx.callObjectMethod( + "getResources", + "()Landroid/content/res/Resources;"); + if (!rsc.isValid()) + { + qCWarning(qml) << "Android resources are invalid" << rsc.toString(); + return 1.0; + } + auto cfg = rsc.callObjectMethod("getConfiguration", "()Landroid/content/res/Configuration;"); + if (!cfg.isValid()) + { + qCWarning(qml) << "Android configuration is invalid" << cfg.toString(); + return 1.0; + } + auto displayMetrics = rsc.callObjectMethod("getDisplayMetrics", "()Landroid/util/DisplayMetrics;"); + if (!displayMetrics.isValid()) + { + qCWarning(qml) << "Android DisplayMetrics object is invalid" << displayMetrics.toString(); + return 1.0; + } + const auto density = displayMetrics.getField("density"); + const auto scaledDensity = displayMetrics.getField("scaledDensity"); + return scaledDensity / density; +} + + +} diff --git a/src/ui/qml/UIPlugInQml_generic.cpp b/src/ui/qml/UIPlugInQml_generic.cpp new file mode 100644 index 000000000..a43c46bc9 --- /dev/null +++ b/src/ui/qml/UIPlugInQml_generic.cpp @@ -0,0 +1,16 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ + +#include "UIPlugInQml.h" + +#include + +Q_DECLARE_LOGGING_CATEGORY(qml) + +using namespace governikus; + +qreal UIPlugInQml::getSystemFontScaleFactor() const +{ + return 1.0; +} diff --git a/src/ui/qml/UIPlugInQml_ios.mm b/src/ui/qml/UIPlugInQml_ios.mm index 059616daa..1ba8d936f 100644 --- a/src/ui/qml/UIPlugInQml_ios.mm +++ b/src/ui/qml/UIPlugInQml_ios.mm @@ -4,10 +4,68 @@ #include "UIPlugInQml.h" +#include "Env.h" +#include "UILoader.h" + +#include + #import +Q_DECLARE_LOGGING_CATEGORY(qml) + using namespace governikus; +@interface FontChangeTracker + : NSObject +- (instancetype) init; +- (void) receiveNotification: (NSNotification*) notification; +@end +@implementation FontChangeTracker +- (instancetype) init +{ + self = [super init]; + if (!self) + { + return nil; + } + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(receiveNotification:) + name:UIContentSizeCategoryDidChangeNotification + object:nil]; + return self; +} + + +- (void)receiveNotification:(NSNotification*)notification +{ + if ([notification.name + isEqualToString: + UIContentSizeCategoryDidChangeNotification]) + { + QMetaObject::invokeMethod(QCoreApplication::instance(), [] { + if (auto* uiPlugIn = Env::getSingleton()->getLoaded()) + { + Q_EMIT uiPlugIn->fireAppConfigChanged(); + } + }, Qt::QueuedConnection); + } +} + + +@end + + +UIPlugInQml::Private::Private() : mFontChangeTracker([[FontChangeTracker alloc] init]) +{ +} + + +// It's important that the definition of the destructor is in a .mm file: Otherwise the compiler won't compile it in Objective-C++ mode and ARC won't work. +UIPlugInQml::Private::~Private() +{ +} + bool UIPlugInQml::isTablet() const { @@ -30,3 +88,10 @@ return insetMap; } + + +qreal UIPlugInQml::getSystemFontScaleFactor() const +{ + UIFont* font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody]; + return font.pointSize / 14.0; +} diff --git a/src/ui/qml/UIPlugInQml_osx.mm b/src/ui/qml/UIPlugInQml_osx.mm index 581491b3b..7cf56bd4f 100644 --- a/src/ui/qml/UIPlugInQml_osx.mm +++ b/src/ui/qml/UIPlugInQml_osx.mm @@ -1,10 +1,18 @@ /** - * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany */ #include "UIPlugInQml.h" +#include "Env.h" +#include "UILoader.h" + +#include + #include +#include + +Q_DECLARE_LOGGING_CATEGORY(qml) using namespace governikus; @@ -12,3 +20,9 @@ { return NSWorkspace.sharedWorkspace.accessibilityDisplayShouldIncreaseContrast; } + + +qreal UIPlugInQml::getSystemFontScaleFactor() const +{ + return 1.0; +} diff --git a/src/ui/qml/VersionInformationModel.cpp b/src/ui/qml/VersionInformationModel.cpp index e140aa742..0bbf9dc67 100644 --- a/src/ui/qml/VersionInformationModel.cpp +++ b/src/ui/qml/VersionInformationModel.cpp @@ -10,7 +10,6 @@ #include "AppSettings.h" #include "BuildHelper.h" -#include "DeviceInfo.h" #include #include @@ -49,7 +48,7 @@ void VersionInformationModel::init() int VersionInformationModel::rowCount(const QModelIndex&) const { - return mData.size(); + return static_cast(mData.size()); } diff --git a/src/ui/qml/VersionInformationModel.h b/src/ui/qml/VersionInformationModel.h index 94af97380..b36aeb66f 100644 --- a/src/ui/qml/VersionInformationModel.h +++ b/src/ui/qml/VersionInformationModel.h @@ -21,7 +21,7 @@ class VersionInformationModel friend class Env; private: - enum HistoryRoles + enum VersionRoles { LABEL = Qt::UserRole + 1, TEXT diff --git a/src/ui/qml/WorkflowModel.cpp b/src/ui/qml/WorkflowModel.cpp index d37c06f71..3b26ff170 100644 --- a/src/ui/qml/WorkflowModel.cpp +++ b/src/ui/qml/WorkflowModel.cpp @@ -37,7 +37,7 @@ WorkflowModel::WorkflowModel(QObject* pParent) connect(Env::getSingleton(), &ReaderManager::fireCardRemoved, this, &WorkflowModel::onReaderManagerSignal); connect(Env::getSingleton(), &ReaderManager::fireReaderAdded, this, &WorkflowModel::onReaderManagerSignal); connect(Env::getSingleton(), &ReaderManager::fireReaderRemoved, this, &WorkflowModel::onReaderManagerSignal); - connect(Env::getSingleton(), &SmartModel::fireSmartStateChanged, this, &WorkflowModel::fireIsSmartCardAllowedChanged); + connect(Env::getSingleton(), &SmartModel::fireSmartStateChanged, this, &WorkflowModel::fireIsCurrentSmartCardAllowedChanged); connect(Env::getSingleton(), &ApplicationModel::fireApplicationStateChanged, this, &WorkflowModel::onApplicationStateChanged); @@ -53,18 +53,23 @@ void WorkflowModel::resetWorkflowContext(const QSharedPointer& if (mContext) { connect(mContext.data(), &WorkflowContext::fireStateChanged, this, &WorkflowModel::fireCurrentStateChanged); + connect(mContext.data(), &WorkflowContext::fireStateChanged, this, &WorkflowModel::fireStateEntered); connect(mContext.data(), &WorkflowContext::fireResultChanged, this, &WorkflowModel::fireResultChanged); connect(mContext.data(), &WorkflowContext::fireReaderPlugInTypesChanged, this, &WorkflowModel::fireReaderPlugInTypeChanged); + connect(mContext.data(), &WorkflowContext::fireReaderPlugInTypesChanged, this, &WorkflowModel::fireHasCardChanged); connect(mContext.data(), &WorkflowContext::fireCardConnectionChanged, this, &WorkflowModel::fireSelectedReaderChanged); connect(mContext.data(), &WorkflowContext::fireCardConnectionChanged, this, &WorkflowModel::fireHasCardChanged); - connect(mContext.data(), &WorkflowContext::fireIsSmartCardAllowedChanged, this, &WorkflowModel::fireIsSmartCardAllowedChanged); + connect(mContext.data(), &WorkflowContext::fireEidTypeMismatchChanged, this, &WorkflowModel::fireIsCurrentSmartCardAllowedChanged); + connect(mContext.data(), &WorkflowContext::fireEidTypeMismatchChanged, this, &WorkflowModel::fireEidTypeMismatchErrorChanged); connect(mContext.data(), &WorkflowContext::fireNextWorkflowPending, this, &WorkflowModel::fireNextWorkflowPendingChanged); connect(mContext.data(), &WorkflowContext::fireRemoveCardFeedbackChanged, this, &WorkflowModel::fireRemoveCardFeedbackChanged); + Q_EMIT fireWorkflowStarted(); + } + else + { + Q_EMIT fireWorkflowFinished(); } - /* - * Only this state change is emitted when the context is reset, i.e. after the end of the workflow - */ Q_EMIT fireCurrentStateChanged(getCurrentState()); Q_EMIT fireResultChanged(); } @@ -118,7 +123,7 @@ void WorkflowModel::setReaderPlugInType(ReaderManagerPlugInType pReaderPlugInTyp } -void WorkflowModel::insertCard(ReaderManagerPlugInType pType) +void WorkflowModel::insertCard(ReaderManagerPlugInType pType) const { auto* const readerManager = Env::getSingleton(); const auto& readerInfos = readerManager->getReaderInfos(ReaderFilter({pType})); @@ -204,35 +209,10 @@ bool WorkflowModel::hasCard() const } -bool WorkflowModel::isSmartCardAllowed() const +bool WorkflowModel::isCurrentSmartCardAllowed() const { - if (!mContext) - { - return false; - } - - MobileEidType mobileEidType = Env::getSingleton()->getMobileEidType(); - if (mobileEidType == MobileEidType::UNKNOWN) - { - return false; - } - - const auto& acceptedEidTypes = mContext->getAcceptedEidTypes(); - switch (mobileEidType) - { - case MobileEidType::SE_CERTIFIED: - return acceptedEidTypes.contains(AcceptedEidType::SE_CERTIFIED); - - case MobileEidType::SE_ENDORSED: - return acceptedEidTypes.contains(AcceptedEidType::SE_ENDORSED); - - case MobileEidType::HW_KEYSTORE: - return acceptedEidTypes.contains(AcceptedEidType::HW_KEYSTORE); - - case MobileEidType::UNKNOWN: - return false; - } - Q_UNREACHABLE(); + const auto& mobileEidType = Env::getSingleton()->getMobileEidType(); + return mContext && mContext->isMobileEidTypeAllowed(mobileEidType); } @@ -277,6 +257,56 @@ QString WorkflowModel::getReaderImage() const } +QString WorkflowModel::getStatusCodeImage() const +{ + switch (getStatusCode()) + { + case GlobalStatus::Code::Network_ServiceUnavailable: + case GlobalStatus::Code::Network_ServerError: + case GlobalStatus::Code::Network_ClientError: + case GlobalStatus::Code::Network_Ssl_Establishment_Error: + case GlobalStatus::Code::Network_TimeOut: + case GlobalStatus::Code::Network_Proxy_Error: + case GlobalStatus::Code::Network_Other_Error: + return QStringLiteral("qrc:///images/workflow_error_network_%1.svg"); + + case GlobalStatus::Code::Paos_Generic_Server_Error: + case GlobalStatus::Code::Workflow_Cannot_Confirm_IdCard_Authenticity: + case GlobalStatus::Code::Card_Not_Found: + case GlobalStatus::Code::Card_Communication_Error: + case GlobalStatus::Code::Card_Protocol_Error: + case GlobalStatus::Code::Card_Unexpected_Transmit_Status: + case GlobalStatus::Code::Card_Cancellation_By_User: + case GlobalStatus::Code::Card_Input_TimeOut: + case GlobalStatus::Code::Card_Pin_Deactivated: + case GlobalStatus::Code::Card_Pin_Blocked: + case GlobalStatus::Code::Card_Pin_Not_Blocked: + case GlobalStatus::Code::Card_NewPin_Mismatch: + case GlobalStatus::Code::Card_NewPin_Invalid_Length: + case GlobalStatus::Code::Card_ValidityVerificationFailed: + return QStringLiteral("qrc:///images/workflow_error_card_%1.svg"); + + case GlobalStatus::Code::Card_Invalid_Pin: + return QStringLiteral("qrc:///images/workflow_error_wrong_pin_%1.svg"); + + case GlobalStatus::Code::Card_Invalid_Can: + return QStringLiteral("qrc:///images/workflow_error_wrong_can_%1.svg"); + + case GlobalStatus::Code::Card_Invalid_Puk: + return QStringLiteral("qrc:///images/workflow_error_wrong_puk_%1.svg"); + + case GlobalStatus::Code::Card_Puk_Blocked: + return QStringLiteral("qrc:///images/workflow_error_puk_blocked_%1.svg"); + + case GlobalStatus::Code::No_Error: + return QStringLiteral("qrc:///images/status_ok_%1.svg"); + + default: + return QStringLiteral("qrc:///images/status_error_%1.svg"); + } +} + + QString WorkflowModel::getStatusHintText() const { switch (getStatusCode()) @@ -290,6 +320,10 @@ QString WorkflowModel::getStatusHintText() const case GlobalStatus::Code::Card_ValidityVerificationFailed: return tr("Contact your local citizens' office (B\u00FCrgeramt) to apply for a new ID card or to unblock the ID card."); + case GlobalStatus::Code::Card_Smart_Invalid: + //: LABEL ANDROID IOS The hint text that is shwon right above the redirect button that appears when a user tried to usa an unusable Smart-eID + return tr("Renew your Smart-eID and set a new PIN in the Smart-eID menu."); + default: return QString(); } @@ -306,6 +340,10 @@ QString WorkflowModel::getStatusHintActionText() const case GlobalStatus::Code::Card_Pin_Deactivated: return Env::getSingleton()->getActivateOnlineFunctionActionText(); + case GlobalStatus::Code::Card_Smart_Invalid: + //: LABEL ANDROID IOS The text on the redirect button that appears when the user tried to use an unusable Smart-eID + return tr("Go to Smart-eID menu"); + default: return QString(); } @@ -321,6 +359,10 @@ bool WorkflowModel::invokeStatusHintAction() QDesktopServices::openUrl(Env::getSingleton()->getPinResetUrl()); return true; + case GlobalStatus::Code::Card_Smart_Invalid: + Q_EMIT fireShowUiRequest(UiModule::SMART_EID); + return true; + default: return false; } @@ -395,7 +437,7 @@ QString WorkflowModel::getEmailHeader() const return QString(); } - return tr("AusweisApp2 error report - %1").arg(mContext->getStatus().toErrorDescription()); + return tr("%1 error report - %2").arg(QCoreApplication::applicationName(), mContext->getStatus().toErrorDescription()); } @@ -440,7 +482,7 @@ void WorkflowModel::onApplicationStateChanged(bool pIsAppInForeground) } else { - mRemoteScanWasRunning = Env::getSingleton()->isScanRunning(ReaderManagerPlugInType::REMOTE_IFD); + mRemoteScanWasRunning = Env::getSingleton()->getPlugInInfo(ReaderManagerPlugInType::REMOTE_IFD).isScanRunning(); if (mRemoteScanWasRunning) { Env::getSingleton()->stopScan(ReaderManagerPlugInType::REMOTE_IFD); @@ -482,3 +524,29 @@ void WorkflowModel::onReaderManagerSignal() Q_EMIT fireHasCardChanged(); } + + +QString WorkflowModel::eidTypeMismatchError() const +{ + if (mContext && mContext->eidTypeMismatch()) + { + if (mContext->isSmartCardUsed()) + { + if (mContext->getAcceptedEidTypes().contains(AcceptedEidType::CARD_CERTIFIED)) + { + //: INFO ALL_PLATFORMS + return tr("The used Smart-eID is not accepted by the server. Please restart the remote service on your connected smartphone and try again with a physical ID card."); + } + else + { + //: INFO ALL_PLATFORMS + return tr("The used Smart-eID is not accepted by the server. Please stop the remote service and use another Smart-eID or contact the service provider."); + } + } + + //: INFO ALL_PLATFORMS + return tr("The used ID card is not accepted by the server. Please remove the ID card from your device or card reader and use a Smart-eID or contact the service provider."); + } + + return QString(); +} diff --git a/src/ui/qml/WorkflowModel.h b/src/ui/qml/WorkflowModel.h index 9012e6dba..42372c5f4 100644 --- a/src/ui/qml/WorkflowModel.h +++ b/src/ui/qml/WorkflowModel.h @@ -9,6 +9,7 @@ #pragma once #include "ReaderManagerPlugInInfo.h" +#include "UIPlugIn.h" #include "context/WorkflowContext.h" #include @@ -33,11 +34,13 @@ class WorkflowModel Q_PROPERTY(QVector supportedPlugInTypes READ getSupportedReaderPlugInTypes NOTIFY fireSupportedPlugInTypesChanged) Q_PROPERTY(bool isBasicReader READ isBasicReader NOTIFY fireSelectedReaderChanged) Q_PROPERTY(bool isRemoteReader READ isRemoteReader NOTIFY fireSelectedReaderChanged) - Q_PROPERTY(bool isSmartCardAllowed READ isSmartCardAllowed NOTIFY fireIsSmartCardAllowedChanged) + Q_PROPERTY(bool isCurrentSmartCardAllowed READ isCurrentSmartCardAllowed NOTIFY fireIsCurrentSmartCardAllowedChanged) + Q_PROPERTY(QString eidTypeMismatchError READ eidTypeMismatchError NOTIFY fireEidTypeMismatchErrorChanged) Q_PROPERTY(QString readerImage READ getReaderImage NOTIFY fireReaderImageChanged) Q_PROPERTY(bool hasNextWorkflowPending READ getNextWorkflowPending NOTIFY fireNextWorkflowPendingChanged) Q_PROPERTY(QString statusHintText READ getStatusHintText NOTIFY fireResultChanged) Q_PROPERTY(QString statusHintActionText READ getStatusHintActionText NOTIFY fireResultChanged) + Q_PROPERTY(QString statusCodeImage READ getStatusCodeImage NOTIFY fireResultChanged) Q_PROPERTY(bool showRemoveCardFeedback READ showRemoveCardFeedback WRITE setRemoveCardFeedback NOTIFY fireRemoveCardFeedbackChanged) Q_PROPERTY(bool hasCard READ hasCard NOTIFY fireHasCardChanged) friend class ::test_WorkflowModel; @@ -48,7 +51,7 @@ class WorkflowModel #if defined(Q_OS_IOS) bool mRemoteScanWasRunning; #endif - void insertCard(ReaderManagerPlugInType pType); + void insertCard(ReaderManagerPlugInType pType) const; public: explicit WorkflowModel(QObject* pParent = nullptr); @@ -68,7 +71,7 @@ class WorkflowModel [[nodiscard]] bool isRemoteReader() const; [[nodiscard]] bool hasCard() const; - [[nodiscard]] bool isSmartCardAllowed() const; + [[nodiscard]] bool isCurrentSmartCardAllowed() const; [[nodiscard]] bool isSmartSupported() const; [[nodiscard]] virtual QVector getSupportedReaderPlugInTypes() const; @@ -77,6 +80,8 @@ class WorkflowModel [[nodiscard]] GlobalStatus::Code getStatusCode() const; [[nodiscard]] QString getReaderImage() const; + [[nodiscard]] QString getStatusCodeImage() const; + [[nodiscard]] QString getStatusHintText() const; [[nodiscard]] QString getStatusHintActionText() const; @@ -97,6 +102,8 @@ class WorkflowModel [[nodiscard]] Q_INVOKABLE QString getEmailBody(bool pPercentEncoding = false, bool pAddLogNotice = false) const; Q_INVOKABLE void sendResultMail() const; + [[nodiscard]] QString eidTypeMismatchError() const; + private Q_SLOTS: void onApplicationStateChanged(bool pIsAppInForeground); @@ -104,16 +111,21 @@ class WorkflowModel void onReaderManagerSignal(); Q_SIGNALS: + void fireWorkflowStarted(); void fireCurrentStateChanged(const QString& pState); + void fireStateEntered(const QString& pState); void fireResultChanged(); void fireReaderPlugInTypeChanged(bool pExplicitStart = false); void fireSelectedReaderChanged(); - void fireIsSmartCardAllowedChanged(); + void fireIsCurrentSmartCardAllowedChanged(); void fireReaderImageChanged(); void fireNextWorkflowPendingChanged(); void fireSupportedPlugInTypesChanged(); void fireRemoveCardFeedbackChanged(); void fireHasCardChanged(); + void fireEidTypeMismatchErrorChanged(); + void fireShowUiRequest(UiModule pModule); + void fireWorkflowFinished(); }; diff --git a/src/ui/scheme/CustomSchemeActivationContext.cpp b/src/ui/scheme/CustomSchemeActivationContext.cpp deleted file mode 100644 index 67ad68af8..000000000 --- a/src/ui/scheme/CustomSchemeActivationContext.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/** - * Copyright (c) 2014-2023 Governikus GmbH & Co. KG, Germany - */ - -#include "CustomSchemeActivationContext.h" - -#include "UrlUtil.h" - -#include -#include - -#ifdef Q_OS_ANDROID - #include -#endif - - -using namespace governikus; - - -CustomSchemeActivationContext::CustomSchemeActivationContext(const QUrl& pActivationUrl, const QString& pReferrer) - : ActivationContext() - , mActivationUrl(pActivationUrl) - , mReferrer(pReferrer) - , mRedirectAddress() -{ -} - - -CustomSchemeActivationContext::~CustomSchemeActivationContext() -{ - if (!mRedirectAddress.isEmpty()) - { - /* - * Opening an URL on iOS will bring Safari to the foreground, our app - * will go to the background, causing the authentication controller to stop. - * - * Therefore we open the URL during deletion, which takes place when authentication - * has finished and the AuthModel is deleted. - */ - qDebug() << "Perform redirect to URL" << mRedirectAddress; - -#ifdef Q_OS_ANDROID - QJniObject context = QNativeInterface::QAndroidApplication::context(); - if (context.callMethod("openUrl", "(Ljava/lang/String;Ljava/lang/String;)Z", QJniObject::fromString(mRedirectAddress.url()).object(), QJniObject::fromString(mReferrer).object())) - { - return; - } -#endif - - QDesktopServices::openUrl(mRedirectAddress); - } -} - - -QUrl CustomSchemeActivationContext::getActivationURL() const -{ - return mActivationUrl; -} - - -bool CustomSchemeActivationContext::sendProcessing() -{ - // nothing to be done in this case - return true; -} - - -bool CustomSchemeActivationContext::sendOperationAlreadyActive() -{ - Q_EMIT fireShowUserInformation(GlobalStatus(GlobalStatus::Code::Workflow_AlreadyInProgress_Error).toErrorDescription()); - return true; -} - - -bool CustomSchemeActivationContext::sendErrorPage(http_status, const GlobalStatus&) -{ - // The error is displayed in the application, - // so here is nothing to be done in this case. - return true; -} - - -bool CustomSchemeActivationContext::sendRedirect(const QUrl& pRedirectAddress, const GlobalStatus& pStatus) -{ - mRedirectAddress = UrlUtil::addMajorMinor(pRedirectAddress, pStatus); - qDebug() << "Determined redirect URL" << mRedirectAddress; - return true; - - /* - * Don't redirect now, but when deleting this object --> see comment in destructor - */ -} diff --git a/src/ui/scheme/CustomSchemeActivationContext.h b/src/ui/scheme/CustomSchemeActivationContext.h deleted file mode 100644 index b9ab25a4f..000000000 --- a/src/ui/scheme/CustomSchemeActivationContext.h +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (c) 2014-2023 Governikus GmbH & Co. KG, Germany - */ - -#pragma once - -#include "context/ActivationContext.h" - -namespace governikus -{ - -class CustomSchemeActivationContext - : public ActivationContext -{ - Q_OBJECT - - private: - const QUrl mActivationUrl; - const QString mReferrer; - QUrl mRedirectAddress; - - public: - explicit CustomSchemeActivationContext(const QUrl& pActivationUrl, const QString& pReferrer); - ~CustomSchemeActivationContext() override; - - [[nodiscard]] QUrl getActivationURL() const override; - - bool sendProcessing() override; - bool sendOperationAlreadyActive() override; - bool sendErrorPage(http_status pStatusCode, const GlobalStatus& pStatus) override; - bool sendRedirect(const QUrl& pRedirectAddress, const GlobalStatus& pResult) override; - - Q_SIGNALS: - void fireShowUserInformation(const QString& pMessage); -}; - -} // namespace governikus diff --git a/src/ui/scheme/UIPlugInScheme.cpp b/src/ui/scheme/UIPlugInScheme.cpp index 87efc6016..58d0ce19e 100644 --- a/src/ui/scheme/UIPlugInScheme.cpp +++ b/src/ui/scheme/UIPlugInScheme.cpp @@ -4,7 +4,6 @@ #include "UIPlugInScheme.h" -#include "CustomSchemeActivationContext.h" #include "UrlUtil.h" #include "controller/AuthController.h" @@ -17,7 +16,6 @@ using namespace governikus; - Q_DECLARE_LOGGING_CATEGORY(scheme) @@ -73,7 +71,7 @@ void UIPlugInScheme::onCustomUrl(const QUrl& pUrl) case UrlQueryRequest::SHOWUI: { qCDebug(scheme) << "Request type: showui"; - const UiModule showModule = Enum::fromString(value.toUpper(), UiModule::DEFAULT); + const UiModule showModule = UrlUtil::prepareToEnum(value, UiModule::DEFAULT); Q_EMIT fireShowUiRequested(showModule); return; } @@ -81,9 +79,7 @@ void UIPlugInScheme::onCustomUrl(const QUrl& pUrl) case UrlQueryRequest::TCTOKENURL: { qCDebug(scheme) << "Request type: authentication"; - const auto& context = QSharedPointer::create(pUrl, referrer); - connect(context.data(), &CustomSchemeActivationContext::fireShowUserInformation, this, &UIPlugIn::fireShowUserInformationRequested); - Q_EMIT fireWorkflowRequested(AuthController::createWorkflowRequest(context)); + handleTcTokenUrl(pUrl, referrer); return; } @@ -93,18 +89,82 @@ void UIPlugInScheme::onCustomUrl(const QUrl& pUrl) } +void UIPlugInScheme::handleTcTokenUrl(const QUrl& pActivationUrl, const QString& pReferrer) +{ + const RedirectHandler handler = [pReferrer](const QUrl& pRefreshUrl, const GlobalStatus& pStatus){ + const auto& redirectAddress = UrlUtil::addMajorMinor(pRefreshUrl, pStatus); + qCDebug(scheme) << "Determined redirect URL" << redirectAddress; + + if (!redirectAddress.isEmpty()) + { + qCDebug(scheme) << "Perform redirect to URL" << redirectAddress; +#ifdef Q_OS_ANDROID + QJniObject context = QNativeInterface::QAndroidApplication::context(); + if (context.callMethod("openUrl", "(Ljava/lang/String;Ljava/lang/String;)Z", QJniObject::fromString(redirectAddress.url()).object(), QJniObject::fromString(pReferrer).object())) + { + return; + } +#else + Q_UNUSED(pReferrer) +#endif + QDesktopServices::openUrl(redirectAddress); + } + }; + + Q_EMIT fireWorkflowRequested(AuthController::createWorkflowRequest(pActivationUrl, QVariant::fromValue(handler))); +} + + void UIPlugInScheme::doShutdown() { } -void UIPlugInScheme::onWorkflowStarted(QSharedPointer pContext) +void UIPlugInScheme::onWorkflowStarted(const QSharedPointer& pRequest) +{ + Q_UNUSED(pRequest) +} + + +void UIPlugInScheme::onWorkflowFinished(const QSharedPointer& pRequest) { - Q_UNUSED(pContext) + if (const auto& handler = pRequest->getData().value(); handler) + { + if (const auto& context = pRequest->getContext().objectCast(); context) + { +#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) + // Only skip redirects on mobile platforms because it induces a forced focus change + if (context->isSkipMobileRedirect()) + { + qDebug() << "Skipping redirect, Workflow pending"; + return; + } +#endif + + const auto& url = context->getRefreshUrl(); + if (!url.isEmpty()) + { + const auto& status = context->getStatus(); + + /* + * Opening an URL on iOS will bring Safari to the foreground, our app + * will go to the background, causing the authentication controller to stop. + * + * Therefore we open the URL after workflow finished. + */ + QMetaObject::invokeMethod(QCoreApplication::instance(), [handler, url, status] { + handler(url, status); + }, Qt::QueuedConnection); + } + } + } } -void UIPlugInScheme::onWorkflowFinished(QSharedPointer pContext) +void UIPlugInScheme::onWorkflowUnhandled(const QSharedPointer& pRequest) { - Q_UNUSED(pContext) + if (pRequest->getData().value()) // workflow is started by this plugin + { + Q_EMIT fireShowUserInformationRequested(GlobalStatus(GlobalStatus::Code::Workflow_AlreadyInProgress_Error).toErrorDescription()); + } } diff --git a/src/ui/scheme/UIPlugInScheme.h b/src/ui/scheme/UIPlugInScheme.h index 418815baa..f29186296 100644 --- a/src/ui/scheme/UIPlugInScheme.h +++ b/src/ui/scheme/UIPlugInScheme.h @@ -4,8 +4,11 @@ #pragma once +#include "GlobalStatus.h" #include "UIPlugIn.h" +class test_UIPlugInScheme; + namespace governikus { @@ -21,11 +24,19 @@ class UIPlugInScheme Q_PLUGIN_METADATA(IID "governikus.UIPlugIn" FILE "metadata.json") Q_INTERFACES(governikus::UIPlugIn) + friend class ::test_UIPlugInScheme; + + using RedirectHandler = std::function; + + private: + void handleTcTokenUrl(const QUrl& pActivationUrl, const QString& pReferrer); + private Q_SLOTS: void onCustomUrl(const QUrl& pUrl); void doShutdown() override; - void onWorkflowStarted(QSharedPointer pContext) override; - void onWorkflowFinished(QSharedPointer pContext) override; + void onWorkflowStarted(const QSharedPointer& pRequest) override; + void onWorkflowFinished(const QSharedPointer& pRequest) override; + void onWorkflowUnhandled(const QSharedPointer& pRequest) override; public: UIPlugInScheme(); diff --git a/src/ui/webservice/UIPlugInWebService.cpp b/src/ui/webservice/UIPlugInWebService.cpp index c38b381e4..43964f19e 100644 --- a/src/ui/webservice/UIPlugInWebService.cpp +++ b/src/ui/webservice/UIPlugInWebService.cpp @@ -6,9 +6,12 @@ #include "Env.h" #include "HttpServerStatusParser.h" +#include "LanguageLoader.h" +#include "Template.h" +#include "UrlUtil.h" #include "VersionInfo.h" #include "VersionNumber.h" -#include "WebserviceActivationContext.h" +#include "context/AuthContext.h" #include "controller/AuthController.h" #include @@ -25,6 +28,7 @@ Q_DECLARE_LOGGING_CATEGORY(webservice) UIPlugInWebService::UIPlugInWebService() : UIPlugIn() + , HttpHandler() , mServer() { } @@ -51,54 +55,40 @@ bool UIPlugInWebService::listening() for (const auto& address : std::as_const(HttpServer::cAddresses)) { HttpServerStatusParser parser(port, address); - QString serverAppName = parser.request() ? parser.getVersionInfo().getName() : parser.getServerHeader(); - if (serverAppName.startsWith(VersionInfo::getInstance().getName())) + const QString serverAppName = parser.request() ? parser.getVersionInfo().getImplementationTitle() : parser.getServerHeader(); + if (serverAppName.startsWith(VersionInfo::getInstance().getImplementationTitle())) { - qCDebug(webservice) << "We are already started... calling ShowUI"; - HttpServerRequestor requestor; - const auto& reply = requestor.getRequest(HttpServerRequestor::createUrl(QStringLiteral("ShowUI=") + UiModule::CURRENT, port, address)); - if (reply.isNull()) + switch (handleExistingApp(port, address)) { - qCWarning(webservice) << "ShowUI request timed out"; - showMessage.clear(); - } - else if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == HTTP_STATUS_BAD_GATEWAY) - { - qCDebug(webservice) << "Proxy is started... rebind!"; - mServer->rebind(); - if (mServer->isListening()) - { - connect(mServer.data(), &HttpServer::fireNewHttpRequest, this, &UIPlugInWebService::onNewRequest); + case ExistingAppResult::REBIND_SUCCEED: return true; - } - else - { - showMessage = tr("Reverse-Proxy of AusweisApp2 is started and this instance cannot rebind port. Please ask your administrator!"); - } - } - else - { - qCDebug(webservice) << "ShowUI request succeeded"; - showMessage.clear(); + + case ExistingAppResult::REBIND_FAILED: + showMessage = tr("Reverse-Proxy of %1 is started and this instance cannot rebind port. Please ask your administrator!").arg(QCoreApplication::applicationName()); + break; + + case ExistingAppResult::SHOWUI_SUCCEED: + case ExistingAppResult::SHOWUI_TIMEOUT: + showMessage.clear(); + break; + } break; } - else - { - qCCritical(webservice) << "Cannot start application. Port on address is probably already bound by another program:" << serverAppName; - if (showMessage.isEmpty()) - { - //: ERROR ALL_PLATFORMS An unknown programme is using the local port on which the AA2 listens. - showMessage = tr("An unknown program uses the required port (%1). Please exit the other program and try again!").arg(port); - } + qCCritical(webservice) << "Cannot start application. Port on address is probably already bound by another program:" << serverAppName; - if (!serverAppName.isEmpty()) - { - //: ERROR ALL_PLATFORMS A known programme is using the local port on which the AA2 listens. - showMessage = tr("The program (%1) uses the required port (%2). Please close %1 and try again!").arg(serverAppName).arg(port); - } + if (showMessage.isEmpty()) + { + //: ERROR ALL_PLATFORMS An unknown programme is using the local port on which the AA2 listens. + showMessage = tr("An unknown program uses the required port (%1). Please exit the other program and try again!").arg(port); + } + + if (!serverAppName.isEmpty()) + { + //: ERROR ALL_PLATFORMS A known programme is using the local port on which the AA2 listens. + showMessage = tr("The program (%1) uses the required port (%2). Please close %1 and try again!").arg(serverAppName).arg(port); } } @@ -112,6 +102,35 @@ bool UIPlugInWebService::listening() } +UIPlugInWebService::ExistingAppResult UIPlugInWebService::handleExistingApp(quint16 pPort, const QHostAddress& pHost) const +{ + qCDebug(webservice) << "We are already started... calling ShowUI"; + HttpServerRequestor requestor; + const auto& reply = requestor.getRequest(HttpServerRequestor::createUrl(QStringLiteral("ShowUI=") + UiModule::CURRENT, pPort, pHost)); + if (reply.isNull()) + { + qCWarning(webservice) << "ShowUI request timed out"; + return ExistingAppResult::SHOWUI_TIMEOUT; + } + + if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == HTTP_STATUS_BAD_GATEWAY) + { + qCDebug(webservice) << "Proxy is started... rebind!"; + mServer->rebind(); + if (mServer->isListening()) + { + connect(mServer.data(), &HttpServer::fireNewHttpRequest, this, &UIPlugInWebService::onNewRequest); + return ExistingAppResult::REBIND_SUCCEED; + } + + return ExistingAppResult::REBIND_FAILED; + } + + qCDebug(webservice) << "ShowUI request succeeded"; + return ExistingAppResult::SHOWUI_SUCCEED; +} + + void UIPlugInWebService::onNewRequest(const QSharedPointer& pRequest) { handle(pRequest); @@ -120,7 +139,10 @@ void UIPlugInWebService::onNewRequest(const QSharedPointer& pReques void UIPlugInWebService::handleWorkflowRequest(const QSharedPointer& pRequest) { - Q_EMIT fireWorkflowRequested(AuthController::createWorkflowRequest(QSharedPointer::create(pRequest))); + const AuthContext::BrowserHandler handler = [this, pRequest](const QSharedPointer& pContext){ + return sendRedirect(pRequest, pContext); + }; + Q_EMIT fireWorkflowRequested(AuthController::createWorkflowRequest(pRequest->getUrl(), QVariant::fromValue(pRequest), handler)); } @@ -129,43 +151,190 @@ void UIPlugInWebService::handleShowUiRequest(const QString& pUiModule, const QSh pRequest->send(HTTP_STATUS_OK); QString userAgent = QString::fromLatin1(pRequest->getHeader(QByteArrayLiteral("user-agent"))); - if (userAgent.startsWith(QCoreApplication::applicationName())) + if (userAgent.startsWith(VersionInfo::getInstance().getImplementationTitle())) { - QString version = userAgent.remove(QCoreApplication::applicationName() + QLatin1Char('/')).split(QLatin1Char(' ')).at(0); + QString version = userAgent.remove(VersionInfo::getInstance().getImplementationTitle() + QLatin1Char('/')).split(QLatin1Char(' ')).at(0); VersionNumber callerVersion(version); if (callerVersion > VersionNumber::getApplicationVersion()) { qCWarning(webservice) << "Current version is lower than caller version"; //: ERROR ALL_PLATFORMS The external request to show the UI requested a newer version than the one currently installed. - Q_EMIT fireShowUserInformationRequested(tr("You tried to start a newer version (%1) of currently running AusweisApp2. Please stop the current version (%2) and start again!").arg(version, QCoreApplication::applicationVersion())); + Q_EMIT fireShowUserInformationRequested(tr("You tried to start a newer version (%1) of currently running %2. Please stop the current version (%3) and start again!").arg(version, QCoreApplication::applicationName(), QCoreApplication::applicationVersion())); return; } else if (callerVersion < VersionNumber::getApplicationVersion()) { qCWarning(webservice) << "Current version is higher than caller version"; //: ERROR ALL_PLATFORMS The external request to show the UI requested an older version than the one currently installed. - Q_EMIT fireShowUserInformationRequested(tr("You tried to start an older version (%1) of currently running AusweisApp2. Please open the currently running version (%2)!").arg(version, QCoreApplication::applicationVersion())); + Q_EMIT fireShowUserInformationRequested(tr("You tried to start an older version (%1) of currently running %2. Please open the currently running version (%3)!").arg(version, QCoreApplication::applicationName(), QCoreApplication::applicationVersion())); return; } } - Q_EMIT fireShowUiRequested(Enum::fromString(pUiModule, UiModule::DEFAULT)); + Q_EMIT fireShowUiRequested(UrlUtil::prepareToEnum(pUiModule, UiModule::DEFAULT)); +} + + +void UIPlugInWebService::onWorkflowStarted(const QSharedPointer& pRequest) +{ + if (pRequest->getContext().objectCast()) + { + const auto& request = pRequest->getData().value>(); + if (request) + { + if (request->isConnected()) + { + request->send(HTTP_STATUS_PROCESSING); + } + else + { + qCCritical(webservice) << "Cannot send 'Processing' to caller as connection is lost"; + } + } + } } -void UIPlugInWebService::onWorkflowStarted(QSharedPointer pContext) +void UIPlugInWebService::onWorkflowFinished(const QSharedPointer& pRequest) { - Q_UNUSED(pContext) + Q_UNUSED(pRequest) } -void UIPlugInWebService::onWorkflowFinished(QSharedPointer pContext) +void UIPlugInWebService::onWorkflowUnhandled(const QSharedPointer& pRequest) { - Q_UNUSED(pContext) + const auto& request = pRequest->getData().value>(); + if (request) + { + sendWorkflowAlreadyActive(request); + } } void UIPlugInWebService::doShutdown() { + if (mServer) + { + mServer->disconnect(this); + mServer.reset(); + } +} + + +void UIPlugInWebService::sendWorkflowAlreadyActive(const QSharedPointer& pRequest) const +{ + if (!pRequest || !pRequest->isConnected()) + { + qCCritical(webservice) << "Cannot send to caller as connection is lost"; + return; + } + + Template htmlTemplate = Template::fromFile(QStringLiteral(":/template.html")); + //: ERROR ALL_PLATFORMS A new authentication request was received while the previous one was still running. Part of an HTML error page. + htmlTemplate.setContextParameter(QStringLiteral("TITLE"), tr("Cannot start authentication")); + htmlTemplate.setContextParameter(QStringLiteral("APPLICATION_LINK"), QStringLiteral("https://www.ausweisapp.bund.de/%1").arg(LanguageLoader::getLocaleCode())); + //: ERROR ALL_PLATFORMS A new authentication request was received while the previous one was still running. Part of an HTML error page. + htmlTemplate.setContextParameter(QStringLiteral("MESSAGE_HEADER"), tr("Cannot start authentication")); + //: ERROR ALL_PLATFORMS A new authentication request was received while the previous one was still running. Part of an HTML error page. + htmlTemplate.setContextParameter(QStringLiteral("MESSAGE_HEADER_EXPLANATION"), tr("An operation is already in progress.")); + //: ERROR ALL_PLATFORMS A new authentication request was received while the previous one was still running. Part of an HTML error page. + htmlTemplate.setContextParameter(QStringLiteral("CONTENT_HEADER"), tr("Would you like to try again?")); + htmlTemplate.setContextParameter(QStringLiteral("CONTENT_LINK"), pRequest->getUrl().toString()); + //: ERROR ALL_PLATFORMS A new authentication request was received while the previous one was still running. Part of an HTML error page. + htmlTemplate.setContextParameter(QStringLiteral("CONTENT_BUTTON"), tr("Try again")); + QByteArray htmlPage = htmlTemplate.render().toUtf8(); + + HttpResponse response(HTTP_STATUS_CONFLICT); + setCommonHeaders(response); + response.setBody(htmlPage, QByteArrayLiteral("text/html; charset=utf-8")); + pRequest->send(response); +} + + +QString UIPlugInWebService::sendErrorPage(const QSharedPointer& pRequest, http_status pStatusCode, const GlobalStatus& pStatus) const +{ + if (!pRequest->isConnected()) + { + //: ERROR ALL_PLATFORMS No HTTP connection present. + return tr("The browser connection was lost."); + } + + qCDebug(webservice) << "Send error page to browser, error code" << pStatusCode; + const auto& statusMsg = NetworkManager::getFormattedStatusMessage(pStatusCode); + + Template htmlTemplate = Template::fromFile(QStringLiteral(":/template.html")); + htmlTemplate.setContextParameter(QStringLiteral("TITLE"), tr("Invalid request (%1)").arg(statusMsg)); + htmlTemplate.setContextParameter(QStringLiteral("APPLICATION_LINK"), QStringLiteral("https://www.ausweisapp.bund.de/%1").arg(LanguageLoader::getLocaleCode())); + //: ERROR ALL_PLATFORMS Invalid request by the browser, part of an HTML error page + htmlTemplate.setContextParameter(QStringLiteral("MESSAGE_HEADER"), tr("Invalid request (%1)").arg(statusMsg)); + //: ERROR ALL_PLATFORMS Invalid request by the browser, part of an HTML error page + htmlTemplate.setContextParameter(QStringLiteral("MESSAGE_HEADER_EXPLANATION"), tr("Your browser sent a request that couldn't be interpreted.")); + //: ERROR ALL_PLATFORMS Invalid request by the browser, part of an HTML error page + htmlTemplate.setContextParameter(QStringLiteral("MESSAGE_SUBHEADER_LABEL"), tr("Error message:")); + htmlTemplate.setContextParameter(QStringLiteral("MESSAGE_SUBHEADER"), pStatus.toErrorDescription(true)); + //: ERROR ALL_PLATFORMS Invalid request by the browser, part of an HTML error page + htmlTemplate.setContextParameter(QStringLiteral("CONTENT_HEADER"), tr("Would you like to report this error?")); + htmlTemplate.setContextParameter(QStringLiteral("CONTENT_LINK"), QStringLiteral("https://www.ausweisapp.bund.de/%1/aa2/report").arg(LanguageLoader::getLocaleCode())); + //: ERROR ALL_PLATFORMS Invalid request by the browser, part of an HTML error page + htmlTemplate.setContextParameter(QStringLiteral("CONTENT_BUTTON"), tr("Report now")); + QByteArray htmlPage = htmlTemplate.render().toUtf8(); + + HttpResponse response(pStatusCode); + setCommonHeaders(response); + response.setBody(htmlPage, QByteArrayLiteral("text/html; charset=utf-8")); + pRequest->send(response); + return QString(); +} + + +QString UIPlugInWebService::sendRedirect(const QSharedPointer& pRequest, const QSharedPointer& pContext) const +{ + if (pContext->getStatus() == GlobalStatus::Code::Workflow_InternalError_BeforeTcToken) + { + return sendErrorPage(pRequest, HTTP_STATUS_INTERNAL_SERVER_ERROR, pContext->getStatus()); + } + else if (pContext->isTcTokenNotFound()) + { + return sendErrorPage(pRequest, HTTP_STATUS_NOT_FOUND, pContext->getStatus()); + } + else if (pContext->getRefreshUrl().isEmpty()) + { + if (pContext->getTcToken() != nullptr && pContext->getTcToken()->getCommunicationErrorAddress().isValid()) + { + return sendRedirect(pRequest, pContext->getTcToken()->getCommunicationErrorAddress(), ECardApiResult(GlobalStatus::Code::Workflow_Communication_Missing_Redirect_Url)); + } + return sendErrorPage(pRequest, HTTP_STATUS_BAD_REQUEST, pContext->getStatus()); + } + + const auto& result = pContext->getStartPaosResult().isOk() ? ECardApiResult(pContext->getStatus()) : pContext->getStartPaosResult(); + return sendRedirect(pRequest, pContext->getRefreshUrl(), result); +} + + +QString UIPlugInWebService::sendRedirect(const QSharedPointer& pRequest, const QUrl& pRedirectAddress, const ECardApiResult& pResult) const +{ + QUrl redirectAddressWithResult = UrlUtil::addMajorMinor(pRedirectAddress, GlobalStatus(pResult)); + qCDebug(webservice) << "Redirect URL:" << redirectAddressWithResult; + + if (!pRequest->isConnected()) + { + const auto& url = QStringLiteral("%2").arg(redirectAddressWithResult.toString(), redirectAddressWithResult.host()); + //: ERROR ALL_PLATFORMS The connection to the browser was lost/timed out.. + return tr("The connection to the browser was lost. No forwarding was executed. Please try to call the URL again manually: %1").arg(url); + } + + HttpResponse response(HTTP_STATUS_SEE_OTHER); + setCommonHeaders(response); + response.setHeader(QByteArrayLiteral("Location"), redirectAddressWithResult.toEncoded()); + pRequest->send(response); + return QString(); +} + + +void UIPlugInWebService::setCommonHeaders(HttpResponse& pResponse) const +{ + pResponse.setHeader(QByteArrayLiteral("Connection"), QByteArrayLiteral("close")); + pResponse.setHeader(QByteArrayLiteral("Cache-Control"), QByteArrayLiteral("no-cache, no-store")); + pResponse.setHeader(QByteArrayLiteral("Pragma"), QByteArrayLiteral("no-cache")); } diff --git a/src/ui/webservice/UIPlugInWebService.h b/src/ui/webservice/UIPlugInWebService.h index 3f7f12b36..2365fca59 100644 --- a/src/ui/webservice/UIPlugInWebService.h +++ b/src/ui/webservice/UIPlugInWebService.h @@ -13,7 +13,10 @@ #include "HttpServer.h" #include "UIPlugIn.h" +#include "context/AuthContext.h" + class test_UIPlugInWebService; +class test_UIPlugInWebServiceBrowserHandler; namespace governikus { @@ -29,20 +32,37 @@ class UIPlugInWebService Q_PLUGIN_METADATA(IID "governikus.UIPlugIn" FILE "metadata.json") Q_INTERFACES(governikus::UIPlugIn) friend class ::test_UIPlugInWebService; + friend class ::test_UIPlugInWebServiceBrowserHandler; private: + enum class ExistingAppResult : int + { + REBIND_SUCCEED, + REBIND_FAILED, + SHOWUI_SUCCEED, + SHOWUI_TIMEOUT + }; + QSharedPointer mServer; [[nodiscard]] bool listening(); [[nodiscard]] bool initialize() override; + [[nodiscard]] ExistingAppResult handleExistingApp(quint16 pPort, const QHostAddress& pHost) const; + + void setCommonHeaders(HttpResponse& pResponse) const; + QString sendErrorPage(const QSharedPointer& pRequest, http_status pStatusCode, const GlobalStatus& pStatus) const; + QString sendRedirect(const QSharedPointer& pRequest, const QUrl& pRedirectAddress, const ECardApiResult& pResult) const; + QString sendRedirect(const QSharedPointer& pRequest, const QSharedPointer& pContext) const; + void sendWorkflowAlreadyActive(const QSharedPointer& pRequest) const; void handleShowUiRequest(const QString& pUiModule, const QSharedPointer& pRequest) override; void handleWorkflowRequest(const QSharedPointer& pRequest) override; private Q_SLOTS: void doShutdown() override; - void onWorkflowStarted(QSharedPointer pContext) override; - void onWorkflowFinished(QSharedPointer pContext) override; + void onWorkflowStarted(const QSharedPointer& pRequest) override; + void onWorkflowFinished(const QSharedPointer& pRequest) override; + void onWorkflowUnhandled(const QSharedPointer& pRequest) override; void onNewRequest(const QSharedPointer& pRequest); public: diff --git a/src/ui/webservice/WebserviceActivationContext.cpp b/src/ui/webservice/WebserviceActivationContext.cpp deleted file mode 100644 index 41f1c9f28..000000000 --- a/src/ui/webservice/WebserviceActivationContext.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/** - * Copyright (c) 2014-2023 Governikus GmbH & Co. KG, Germany - */ - -#include "WebserviceActivationContext.h" - -#include "LanguageLoader.h" -#include "NetworkManager.h" -#include "Template.h" -#include "UrlUtil.h" - -#include -#include -#include - - -using namespace governikus; - -Q_DECLARE_LOGGING_CATEGORY(webservice) - -void WebserviceActivationContext::setCommonHeaders(HttpResponse& pResponse) const -{ - pResponse.setHeader(QByteArrayLiteral("Connection"), QByteArrayLiteral("close")); - pResponse.setHeader(QByteArrayLiteral("Cache-Control"), QByteArrayLiteral("no-cache, no-store")); - pResponse.setHeader(QByteArrayLiteral("Pragma"), QByteArrayLiteral("no-cache")); -} - - -WebserviceActivationContext::WebserviceActivationContext(const QSharedPointer& pRequest) - : ActivationContext() - , mRequest(pRequest) -{ -} - - -QUrl WebserviceActivationContext::getActivationURL() const -{ - return mRequest->getUrl(); -} - - -bool WebserviceActivationContext::sendProcessing() -{ - if (!mRequest->isConnected()) - { - //: ERROR ALL_PLATFORMS No HTTP connection present. - setSendError(tr("The browser connection was lost.")); - return false; - } - - mRequest->send(HTTP_STATUS_PROCESSING); - return true; -} - - -bool WebserviceActivationContext::sendOperationAlreadyActive() -{ - if (!mRequest->isConnected()) - { - //: ERROR ALL_PLATFORMS No HTTP connection present. - setSendError(tr("The browser connection was lost.")); - return false; - } - - Template htmlTemplate = Template::fromFile(QStringLiteral(":/template.html")); - //: ERROR ALL_PLATFORMS A new authentication request was received while the previous one was still running. Part of an HTML error page. - htmlTemplate.setContextParameter(QStringLiteral("TITLE"), tr("Cannot start authentication")); - htmlTemplate.setContextParameter(QStringLiteral("APPLICATION_LINK"), QStringLiteral("https://www.ausweisapp.bund.de/%1").arg(LanguageLoader::getLocaleCode())); - //: ERROR ALL_PLATFORMS A new authentication request was received while the previous one was still running. Part of an HTML error page. - htmlTemplate.setContextParameter(QStringLiteral("MESSAGE_HEADER"), tr("Cannot start authentication")); - //: ERROR ALL_PLATFORMS A new authentication request was received while the previous one was still running. Part of an HTML error page. - htmlTemplate.setContextParameter(QStringLiteral("MESSAGE_HEADER_EXPLANATION"), tr("An operation is already in progress.")); - //: ERROR ALL_PLATFORMS A new authentication request was received while the previous one was still running. Part of an HTML error page. - htmlTemplate.setContextParameter(QStringLiteral("CONTENT_HEADER"), tr("Would you like to try again?")); - htmlTemplate.setContextParameter(QStringLiteral("CONTENT_LINK"), mRequest->getUrl().toString()); - //: ERROR ALL_PLATFORMS A new authentication request was received while the previous one was still running. Part of an HTML error page. - htmlTemplate.setContextParameter(QStringLiteral("CONTENT_BUTTON"), tr("Try again")); - QByteArray htmlPage = htmlTemplate.render().toUtf8(); - - HttpResponse response(HTTP_STATUS_CONFLICT); - response.setBody(htmlPage, QByteArrayLiteral("text/html; charset=utf-8")); - mRequest->send(response); - return true; -} - - -bool WebserviceActivationContext::sendErrorPage(http_status pStatusCode, const GlobalStatus& pStatus) -{ - if (!mRequest->isConnected()) - { - //: ERROR ALL_PLATFORMS No HTTP connection present. - setSendError(tr("The browser connection was lost.")); - return false; - } - - qCDebug(webservice) << "Send error page to browser, error code" << pStatusCode; - const auto& statusMsg = NetworkManager::getFormattedStatusMessage(pStatusCode); - - Template htmlTemplate = Template::fromFile(QStringLiteral(":/template.html")); - htmlTemplate.setContextParameter(QStringLiteral("TITLE"), tr("Invalid request (%1)").arg(statusMsg)); - htmlTemplate.setContextParameter(QStringLiteral("APPLICATION_LINK"), QStringLiteral("https://www.ausweisapp.bund.de/%1").arg(LanguageLoader::getLocaleCode())); - //: ERROR ALL_PLATFORMS Invalid request by the browser, part of an HTML error page - htmlTemplate.setContextParameter(QStringLiteral("MESSAGE_HEADER"), tr("Invalid request (%1)").arg(statusMsg)); - //: ERROR ALL_PLATFORMS Invalid request by the browser, part of an HTML error page - htmlTemplate.setContextParameter(QStringLiteral("MESSAGE_HEADER_EXPLANATION"), tr("Your browser sent a request that couldn't be interpreted.")); - //: ERROR ALL_PLATFORMS Invalid request by the browser, part of an HTML error page - htmlTemplate.setContextParameter(QStringLiteral("MESSAGE_SUBHEADER_LABEL"), tr("Error message:")); - htmlTemplate.setContextParameter(QStringLiteral("MESSAGE_SUBHEADER"), pStatus.toErrorDescription(true)); - //: ERROR ALL_PLATFORMS Invalid request by the browser, part of an HTML error page - htmlTemplate.setContextParameter(QStringLiteral("CONTENT_HEADER"), tr("Would you like to report this error?")); - htmlTemplate.setContextParameter(QStringLiteral("CONTENT_LINK"), QStringLiteral("https://www.ausweisapp.bund.de/%1/aa2/report").arg(LanguageLoader::getLocaleCode())); - //: ERROR ALL_PLATFORMS Invalid request by the browser, part of an HTML error page - htmlTemplate.setContextParameter(QStringLiteral("CONTENT_BUTTON"), tr("Report now")); - QByteArray htmlPage = htmlTemplate.render().toUtf8(); - - HttpResponse response(pStatusCode); - setCommonHeaders(response); - response.setBody(htmlPage, QByteArrayLiteral("text/html; charset=utf-8")); - mRequest->send(response); - return true; -} - - -bool WebserviceActivationContext::sendRedirect(const QUrl& pRedirectAddress, const GlobalStatus& pStatus) -{ - QUrl redirectAddressWithResult = UrlUtil::addMajorMinor(pRedirectAddress, pStatus); - qCDebug(webservice) << "Redirect URL:" << redirectAddressWithResult; - - if (!mRequest->isConnected()) - { - const auto& url = QStringLiteral("%2").arg(redirectAddressWithResult.toString(), redirectAddressWithResult.host()); - //: ERROR ALL_PLATFORMS The connection to the browser was lost/timed out.. - setSendError(tr("The connection to the browser was lost. No forwarding was executed. Please try to call the URL again manually: %1").arg(url)); - return false; - } - - qCDebug(webservice) << "Redirecting now to URL:" << redirectAddressWithResult; - HttpResponse response(HTTP_STATUS_SEE_OTHER); - setCommonHeaders(response); - response.setHeader(QByteArrayLiteral("Location"), redirectAddressWithResult.toEncoded()); - mRequest->send(response); - return true; -} diff --git a/src/ui/webservice/WebserviceActivationContext.h b/src/ui/webservice/WebserviceActivationContext.h deleted file mode 100644 index 60c62b673..000000000 --- a/src/ui/webservice/WebserviceActivationContext.h +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Copyright (c) 2014-2023 Governikus GmbH & Co. KG, Germany - */ - -#pragma once - -#include "HttpRequest.h" -#include "context/ActivationContext.h" - -#include - - -namespace governikus -{ - -class WebserviceActivationContext - : public ActivationContext -{ - Q_OBJECT - - private: - const QSharedPointer mRequest; - - void setCommonHeaders(HttpResponse& pResponse) const; - - public: - explicit WebserviceActivationContext(const QSharedPointer& pRequest); - - ~WebserviceActivationContext() override = default; - - [[nodiscard]] QUrl getActivationURL() const override; - - bool sendProcessing() override; - - bool sendOperationAlreadyActive() override; - - bool sendErrorPage(http_status pStatusCode, const GlobalStatus& pStatus) override; - - bool sendRedirect(const QUrl& pRedirectAddress, const GlobalStatus& pStatus) override; -}; - -} // namespace governikus diff --git a/src/ui/websocket/UIPlugInWebSocket.cpp b/src/ui/websocket/UIPlugInWebSocket.cpp index 471bf22b4..2c79338f7 100644 --- a/src/ui/websocket/UIPlugInWebSocket.cpp +++ b/src/ui/websocket/UIPlugInWebSocket.cpp @@ -8,6 +8,7 @@ #include "ReaderManager.h" #include "UILoader.h" #include "VolatileSettings.h" +#include "WorkflowRequest.h" #include #include @@ -72,20 +73,20 @@ bool UIPlugInWebSocket::initialize() } -void UIPlugInWebSocket::onWorkflowStarted(QSharedPointer pContext) +void UIPlugInWebSocket::onWorkflowStarted(const QSharedPointer& pRequest) { if (mUiDomination) { - pContext->claim(this); - pContext->setReaderPlugInTypes({ReaderManagerPlugInType::PCSC, ReaderManagerPlugInType::REMOTE_IFD, ReaderManagerPlugInType::SIMULATOR}); - mContext = pContext; + mContext = pRequest->getContext(); + mContext->claim(this); + mContext->setReaderPlugInTypes({ReaderManagerPlugInType::PCSC, ReaderManagerPlugInType::REMOTE_IFD, ReaderManagerPlugInType::SIMULATOR}); } } -void UIPlugInWebSocket::onWorkflowFinished(QSharedPointer pContext) +void UIPlugInWebSocket::onWorkflowFinished(const QSharedPointer& pRequest) { - Q_UNUSED(pContext) + Q_UNUSED(pRequest) mContext.clear(); } @@ -212,7 +213,13 @@ void UIPlugInWebSocket::doShutdown() if (mConnection) { mConnection->close(QWebSocketProtocol::CloseCodeGoingAway); + mConnection->disconnect(this); + mConnection.reset(); } - mHttpServer.reset(); + if (mHttpServer) + { + mHttpServer->disconnect(this); + mHttpServer.reset(); + } } diff --git a/src/ui/websocket/UIPlugInWebSocket.h b/src/ui/websocket/UIPlugInWebSocket.h index 1e8891e7f..d642e3f99 100644 --- a/src/ui/websocket/UIPlugInWebSocket.h +++ b/src/ui/websocket/UIPlugInWebSocket.h @@ -41,8 +41,8 @@ class UIPlugInWebSocket private Q_SLOTS: void doShutdown() override; - void onWorkflowStarted(QSharedPointer pContext) override; - void onWorkflowFinished(QSharedPointer pContext) override; + void onWorkflowStarted(const QSharedPointer& pRequest) override; + void onWorkflowFinished(const QSharedPointer& pRequest) override; void onUiDomination(const UIPlugIn* pUi, const QString& pInformation, bool pAccepted) override; void onUiDominationReleased() override; void onNewWebSocketRequest(const QSharedPointer& pRequest); diff --git a/src/whitelist_client/SurveyModel.cpp b/src/whitelist_client/SurveyModel.cpp index 6deac52b9..7e7998e90 100644 --- a/src/whitelist_client/SurveyModel.cpp +++ b/src/whitelist_client/SurveyModel.cpp @@ -65,7 +65,7 @@ SurveyModel::SurveyModel() int SurveyModel::rowCount(const QModelIndex&) const { - return mData.size(); + return static_cast(mData.size()); } @@ -107,7 +107,7 @@ void SurveyModel::buildDataObject() mData += qMakePair(tr("OS version"), mOsVersion); mData += qMakePair(tr("Kernel version"), mKernelVersion); mData += qMakePair(tr("Max. NFC Packet Length"), QString::number(mMaximumNfcPacketLength)); - mData += qMakePair(tr("AusweisApp2 Version"), mAusweisAppVersionNumber); + mData += qMakePair(tr("%1 Version").arg(QCoreApplication::applicationName()), mAusweisAppVersionNumber); mData += qMakePair(tr("NFC Tag Type"), mNfcTagType); endResetModel(); } @@ -195,21 +195,21 @@ void SurveyModel::setAuthWasSuccessful(bool pSuccess) } -bool SurveyModel::askForDeviceSurvey() +bool SurveyModel::askForDeviceSurvey() const { const auto& settings = Env::getSingleton()->getGeneralSettings(); return mNfcDataAvailable && mAuthWasSuccessful && settings.askForDeviceSurvey(); } -bool SurveyModel::isDeviceSurveyPending() +bool SurveyModel::isDeviceSurveyPending() const { const auto& settings = Env::getSingleton()->getGeneralSettings(); return mNfcDataAvailable && mAuthWasSuccessful && settings.isDeviceSurveyPending(); } -void SurveyModel::setDeviceSurveyPending(bool pValue) +void SurveyModel::setDeviceSurveyPending(bool pValue) const { Env::getSingleton()->getGeneralSettings().setDeviceSurveyPending(pValue); } diff --git a/src/whitelist_client/SurveyModel.h b/src/whitelist_client/SurveyModel.h index 4725903c8..8809b49b6 100644 --- a/src/whitelist_client/SurveyModel.h +++ b/src/whitelist_client/SurveyModel.h @@ -69,9 +69,9 @@ class SurveyModel void setReaderInfo(const ReaderInfo& pReaderInfo); void setAuthWasSuccessful(bool pSuccess); - Q_INVOKABLE [[nodiscard]] bool askForDeviceSurvey(); - [[nodiscard]] bool isDeviceSurveyPending(); - Q_INVOKABLE void setDeviceSurveyPending(bool pValue); + [[nodiscard]] Q_INVOKABLE bool askForDeviceSurvey() const; + [[nodiscard]] bool isDeviceSurveyPending() const; + Q_INVOKABLE void setDeviceSurveyPending(bool pValue) const; void transmitSurvey(); diff --git a/src/workflows/base/TcToken.cpp b/src/workflows/base/TcToken.cpp index 52a0c426a..f5c710a2c 100644 --- a/src/workflows/base/TcToken.cpp +++ b/src/workflows/base/TcToken.cpp @@ -102,7 +102,7 @@ void TcToken::parse(const QByteArray& pData) } -QString TcToken::readElementValue(QXmlStreamReader& pReader) +QString TcToken::readElementValue(QXmlStreamReader& pReader) const { // helper method to distinguish between the cases, // 1) where the element was present but empty (so the value is not null but empty) and diff --git a/src/workflows/base/TcToken.h b/src/workflows/base/TcToken.h index 9cefe2972..eb4b84e8f 100644 --- a/src/workflows/base/TcToken.h +++ b/src/workflows/base/TcToken.h @@ -41,7 +41,7 @@ class TcToken const QString& pRefreshAddress) const; [[nodiscard]] bool isAnyUri(const QString& pCandidate) const; [[nodiscard]] bool isHexBinary(const QString& pCandidate) const; - QString readElementValue(QXmlStreamReader& pReader); + QString readElementValue(QXmlStreamReader& pReader) const; public: explicit TcToken(const QByteArray& pData); diff --git a/src/workflows/base/WorkflowRequest.cpp b/src/workflows/base/WorkflowRequest.cpp index b81f9ab4b..16c8c4b7c 100644 --- a/src/workflows/base/WorkflowRequest.cpp +++ b/src/workflows/base/WorkflowRequest.cpp @@ -13,10 +13,12 @@ INIT_FUNCTION([] { WorkflowRequest::WorkflowRequest(const std::function(const QSharedPointer&)>& pGeneratorController, const std::function()>& pGeneratorContext, - const BusyHandler& pBusyHandler) + const BusyHandler& pHandler, + const QVariant& pData) : mGeneratorController(pGeneratorController) , mGeneratorContext(pGeneratorContext) - , mBusyHandler(pBusyHandler) + , mBusyHandler(pHandler) + , mData(pData) , mController() , mContext(mGeneratorContext()) { @@ -56,7 +58,13 @@ QSharedPointer WorkflowRequest::getContext() const } -WorkflowControl WorkflowRequest::handleBusyWorkflow(const QSharedPointer& pActiveWorkflow, const QSharedPointer& pWaitingWorkflow) +QVariant WorkflowRequest::getData() const { - return mBusyHandler ? mBusyHandler(*this, pActiveWorkflow, pWaitingWorkflow) : WorkflowControl::UNHANDLED; + return mData; +} + + +WorkflowControl WorkflowRequest::handleBusyWorkflow(const QSharedPointer& pActiveWorkflow, const QSharedPointer& pWaitingWorkflow) const +{ + return mBusyHandler ? mBusyHandler(pActiveWorkflow, pWaitingWorkflow) : WorkflowControl::UNHANDLED; } diff --git a/src/workflows/base/WorkflowRequest.h b/src/workflows/base/WorkflowRequest.h index 13cf4721a..61d0420bd 100644 --- a/src/workflows/base/WorkflowRequest.h +++ b/src/workflows/base/WorkflowRequest.h @@ -7,6 +7,7 @@ #include "context/WorkflowContext.h" #include +#include #include #include @@ -25,12 +26,13 @@ class WorkflowRequest final { Q_GADGET - using BusyHandler = std::function&, const QSharedPointer&)>; + using BusyHandler = std::function&, const QSharedPointer&)>; private: const std::function(const QSharedPointer& pContext)> mGeneratorController; const std::function()> mGeneratorContext; const BusyHandler mBusyHandler; + const QVariant mData; QSharedPointer mController; QSharedPointer mContext; @@ -51,7 +53,7 @@ class WorkflowRequest final public: template - static QSharedPointer createWorkflowRequest(Args&& ... pArgs) + static QSharedPointer create(Args&& ... pArgs) { auto [controller, context] = getGenerator(std::forward(pArgs) ...); return QSharedPointer::create(controller, context); @@ -59,23 +61,39 @@ class WorkflowRequest final template - static QSharedPointer createWorkflowRequestHandler(const BusyHandler& pBusyHandler, Args&& ... pArgs) + static QSharedPointer createHandler(const BusyHandler& pBusyHandler, Args&& ... pArgs) + { + return createHandler(pBusyHandler, QVariant(), std::forward(pArgs) ...); + } + + + template + static QSharedPointer createHandler(const QVariant& pData, Args&& ... pArgs) + { + return createHandler(BusyHandler(), pData, std::forward(pArgs) ...); + } + + + template + static QSharedPointer createHandler(const BusyHandler& pBusyHandler, const QVariant& pData, Args&& ... pArgs) { auto [controller, context] = getGenerator(std::forward(pArgs) ...); - return QSharedPointer::create(controller, context, pBusyHandler); + return QSharedPointer::create(controller, context, pBusyHandler, pData); } WorkflowRequest(const std::function(const QSharedPointer& pContext)>& pGeneratorController, const std::function()>& pGeneratorContext, - const BusyHandler& pBusyHandler = BusyHandler()); + const BusyHandler& pHandler = BusyHandler(), + const QVariant& pData = QVariant()); void initialize(); [[nodiscard]] bool isInitialized() const; [[nodiscard]] Action getAction() const; [[nodiscard]] QSharedPointer getController() const; [[nodiscard]] QSharedPointer getContext() const; - [[nodiscard]] WorkflowControl handleBusyWorkflow(const QSharedPointer& pActiveWorkflow, const QSharedPointer& pWaitingWorkflow); + [[nodiscard]] QVariant getData() const; + [[nodiscard]] WorkflowControl handleBusyWorkflow(const QSharedPointer& pActiveWorkflow, const QSharedPointer& pWaitingWorkflow) const; }; } // namespace governikus diff --git a/src/workflows/base/context/AccessRightManager.cpp b/src/workflows/base/context/AccessRightManager.cpp index ac12beee0..531b26d3a 100644 --- a/src/workflows/base/context/AccessRightManager.cpp +++ b/src/workflows/base/context/AccessRightManager.cpp @@ -42,7 +42,7 @@ AccessRightManager::AccessRightManager(QSharedPointer pDIDA mOptionalAccessRights = optionalChat.data()->getAccessRights(); removeForbiddenAccessRights(mOptionalAccessRights); - if (mOptionalAccessRights.size() > 0 && mRequiredAccessRights.size() > 0) + if (!mOptionalAccessRights.isEmpty() && !mRequiredAccessRights.isEmpty()) { mOptionalAccessRights -= mRequiredAccessRights; } diff --git a/src/workflows/base/context/ActivationContext.cpp b/src/workflows/base/context/ActivationContext.cpp deleted file mode 100644 index c5df773f2..000000000 --- a/src/workflows/base/context/ActivationContext.cpp +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ - -#include "ActivationContext.h" - -using namespace governikus; - - -ActivationContext::ActivationContext() - : mSendError() -{ -} - - -void ActivationContext::setSendError(const QString& pError) -{ - mSendError = pError; -} diff --git a/src/workflows/base/context/ActivationContext.h b/src/workflows/base/context/ActivationContext.h deleted file mode 100644 index 045e4ebf3..000000000 --- a/src/workflows/base/context/ActivationContext.h +++ /dev/null @@ -1,73 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ - -#pragma once - -#include "GlobalStatus.h" - -#include -#include -#include -#include - -namespace governikus -{ - -class ActivationContext - : public QObject -{ - Q_OBJECT - - private: - QString mSendError; - - protected: - void setSendError(const QString& pError); - - public: - ActivationContext(); - ~ActivationContext() override = default; - - [[nodiscard]] virtual QUrl getActivationURL() const = 0; - - /*! - * Sends a processing status response to the caller. - * - * \return true, if sending succeeded, false otherwise. On failure an error message can be retrieved via getSendError. - */ - virtual bool sendProcessing() = 0; - - /*! - * Sends a response to the caller indicating that another operation is already in progress - * - * \return true, if sending succeeded, false otherwise. On failure an error message can be retrieved via getSendError. - */ - virtual bool sendOperationAlreadyActive() = 0; - - /*! - * Sends an error page to the caller. - * - * \return true, if sending succeeded, false otherwise. On failure an error message can be retrieved via getSendError. - */ - virtual bool sendErrorPage(http_status pStatusCode, const GlobalStatus& pStatus) = 0; - - /*! - * Sends a redirect to the caller. - * - * \return true, if sending succeeded, false otherwise. On failure an error message can be retrieved via getSendError. - */ - virtual bool sendRedirect(const QUrl& pRedirectAddress, const GlobalStatus& pStatus) = 0; - - /*! - * Returns the last error that occurred during a send operation. - */ - [[nodiscard]] const QString& getSendError() const - { - return mSendError; - } - - -}; - -} // namespace governikus diff --git a/src/workflows/base/context/AuthContext.cpp b/src/workflows/base/context/AuthContext.cpp index 7b3f757eb..b7f1186fd 100644 --- a/src/workflows/base/context/AuthContext.cpp +++ b/src/workflows/base/context/AuthContext.cpp @@ -13,13 +13,13 @@ using namespace governikus; -AuthContext::AuthContext(const Action pAction, const QSharedPointer& pActivationContext) - : WorkflowContext(pAction) +AuthContext::AuthContext(const Action pAction, bool pActivateUi, const QUrl& pActivationUrl, const BrowserHandler& pHandler) + : WorkflowContext(pAction, pActivateUi) , mTcTokenNotFound(true) , mErrorReportedToServer(false) - , mSkipRedirect(false) + , mSkipMobileRedirect(false) , mShowChangePinView(false) - , mActivationContext(pActivationContext) + , mActivationUrl(pActivationUrl) , mTcTokenUrl() , mTcToken() , mRefreshUrl() @@ -42,12 +42,13 @@ AuthContext::AuthContext(const Action pAction, const QSharedPointer& pActivationContext) - : AuthContext(Action::AUTH, pActivationContext) +AuthContext::AuthContext(bool pActivateUi, const QUrl& pActivationUrl, const BrowserHandler& pHandler) + : AuthContext(Action::AUTH, pActivateUi, pActivationUrl, pHandler) { } @@ -59,7 +60,7 @@ void AuthContext::requestChangePinView() return; } - mSkipRedirect = true; + setMobileSkipRedirect(); mShowChangePinView = true; Q_EMIT fireShowChangePinViewChanged(); } diff --git a/src/workflows/base/context/AuthContext.h b/src/workflows/base/context/AuthContext.h index d68bf724d..ba71e1afb 100644 --- a/src/workflows/base/context/AuthContext.h +++ b/src/workflows/base/context/AuthContext.h @@ -14,7 +14,6 @@ #include "asn1/CVCertificate.h" #include "asn1/CVCertificateChainBuilder.h" #include "context/AccessRightManager.h" -#include "context/ActivationContext.h" #include "context/WorkflowContext.h" #include "paos/invoke/DidAuthenticateResponseEac1.h" #include "paos/invoke/DidAuthenticateResponseEac2.h" @@ -34,6 +33,8 @@ #include #include +#include + class test_StateRedirectBrowser; class test_StatePreVerification; class test_StateCertificateDescriptionCheck; @@ -52,13 +53,16 @@ class AuthContext friend class ::test_StateCertificateDescriptionCheck; friend class TestAuthContext; + public: + using BrowserHandler = std::function&)>; + private: bool mTcTokenNotFound; bool mErrorReportedToServer; - bool mSkipRedirect; + bool mSkipMobileRedirect; bool mShowChangePinView; - QSharedPointer mActivationContext; + QUrl mActivationUrl; QUrl mTcTokenUrl; QSharedPointer mTcToken; QUrl mRefreshUrl; @@ -81,6 +85,7 @@ class AuthContext CVCertificateChainBuilder mCvcChainBuilderProd; CVCertificateChainBuilder mCvcChainBuilderTest; QByteArray mSslSession; + BrowserHandler mBrowserHandler; Q_SIGNALS: void fireShowChangePinViewChanged(); @@ -88,10 +93,16 @@ class AuthContext void fireAccessRightManagerCreated(QSharedPointer pAccessRightManager); protected: - explicit AuthContext(const Action pAction, const QSharedPointer& pActivationContext); + explicit AuthContext(const Action pAction, bool pActivateUi = true, const QUrl& pActivationUrl = QUrl(), const BrowserHandler& pHandler = BrowserHandler()); public: - explicit AuthContext(const QSharedPointer& pActivationContext); + explicit AuthContext(bool pActivateUi = true, const QUrl& pActivationUrl = QUrl(), const BrowserHandler& pHandler = BrowserHandler()); + + [[nodiscard]] QUrl getActivationUrl() const + { + return mActivationUrl; + } + [[nodiscard]] bool isErrorReportedToServer() const { @@ -138,15 +149,15 @@ class AuthContext } - [[nodiscard]] bool isSkipRedirect() const + [[nodiscard]] bool isSkipMobileRedirect() const { - return mSkipRedirect; + return mSkipMobileRedirect; } - void setSkipRedirect(bool pSkipRedirect) + void setMobileSkipRedirect(bool pSkipRedirect = true) { - mSkipRedirect = pSkipRedirect; + mSkipMobileRedirect = pSkipRedirect; } @@ -164,9 +175,9 @@ class AuthContext } - [[nodiscard]] ActivationContext* getActivationContext() const + [[nodiscard]] BrowserHandler getBrowserHandler() const { - return mActivationContext.data(); + return mBrowserHandler; } @@ -228,7 +239,8 @@ class AuthContext { mDIDAuthenticateEAC1 = pDIDAuthenticateEAC1; Q_EMIT fireDidAuthenticateEac1Changed(); - Q_EMIT fireIsSmartCardAllowedChanged(); + Q_EMIT fireAcceptedEidTypesChanged(); + Q_EMIT fireEidTypeMismatchChanged(); } diff --git a/src/workflows/base/context/ChangePinContext.cpp b/src/workflows/base/context/ChangePinContext.cpp index b50745613..b62dc3fdc 100644 --- a/src/workflows/base/context/ChangePinContext.cpp +++ b/src/workflows/base/context/ChangePinContext.cpp @@ -7,8 +7,8 @@ using namespace governikus; -ChangePinContext::ChangePinContext(bool pRequestTransportPin) - : WorkflowContext(Action::PIN) +ChangePinContext::ChangePinContext(bool pRequestTransportPin, bool pActivateUi) + : WorkflowContext(Action::PIN, pActivateUi) , mNewPin() , mSuccessMessage() , mRequestTransportPin(pRequestTransportPin) diff --git a/src/workflows/base/context/ChangePinContext.h b/src/workflows/base/context/ChangePinContext.h index 770426d67..ec976dd9b 100644 --- a/src/workflows/base/context/ChangePinContext.h +++ b/src/workflows/base/context/ChangePinContext.h @@ -24,7 +24,7 @@ class ChangePinContext const bool mRequestTransportPin; public: - explicit ChangePinContext(bool pRequestTransportPin = false); + explicit ChangePinContext(bool pRequestTransportPin = false, bool pActivateUi = true); ~ChangePinContext() override; [[nodiscard]] const QString& getNewPin() const; diff --git a/src/workflows/base/context/InternalActivationContext.cpp b/src/workflows/base/context/InternalActivationContext.cpp deleted file mode 100644 index 024db7d40..000000000 --- a/src/workflows/base/context/InternalActivationContext.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ - -#include "InternalActivationContext.h" - -using namespace governikus; - - -InternalActivationContext::InternalActivationContext(const QUrl& pUrl) - : ActivationContext() - , mTcTokenUrl(pUrl) -{ -} - - -QUrl InternalActivationContext::getActivationURL() const -{ - return mTcTokenUrl; -} - - -bool InternalActivationContext::sendProcessing() -{ - return true; -} - - -bool InternalActivationContext::sendOperationAlreadyActive() -{ - return true; -} - - -bool InternalActivationContext::sendErrorPage(http_status pStatusCode, const GlobalStatus& pStatus) -{ - Q_UNUSED(pStatusCode) - Q_UNUSED(pStatus) - return true; -} - - -bool InternalActivationContext::sendRedirect(const QUrl& pRedirectAddress, const GlobalStatus& pStatus) -{ - Q_UNUSED(pRedirectAddress) - Q_UNUSED(pStatus) - return true; -} diff --git a/src/workflows/base/context/InternalActivationContext.h b/src/workflows/base/context/InternalActivationContext.h deleted file mode 100644 index a91d83a9d..000000000 --- a/src/workflows/base/context/InternalActivationContext.h +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ - -#pragma once - -#include "ActivationContext.h" - -namespace governikus -{ - -class InternalActivationContext - : public ActivationContext -{ - Q_OBJECT - - private: - const QUrl mTcTokenUrl; - - public: - explicit InternalActivationContext(const QUrl& pUrl); - ~InternalActivationContext() override = default; - - [[nodiscard]] QUrl getActivationURL() const override; - bool sendProcessing() override; - bool sendOperationAlreadyActive() override; - bool sendErrorPage(http_status pStatusCode, const GlobalStatus& pStatus) override; - bool sendRedirect(const QUrl& pRedirectAddress, const GlobalStatus& pStatus) override; -}; - -} // namespace governikus diff --git a/src/workflows/base/context/WorkflowContext.cpp b/src/workflows/base/context/WorkflowContext.cpp index 21568799c..733abdf26 100644 --- a/src/workflows/base/context/WorkflowContext.cpp +++ b/src/workflows/base/context/WorkflowContext.cpp @@ -14,12 +14,13 @@ using namespace governikus; -WorkflowContext::WorkflowContext(const Action pAction) +WorkflowContext::WorkflowContext(const Action pAction, bool pActivateUi) : QObject() , mAction(pAction) + , mActivateUi(pActivateUi) , mStateApproved(false) , mWorkflowKilled(false) - , mCurrentState(QStringLiteral("Initial")) + , mCurrentState() , mReaderPlugInTypes() , mReaderName() , mCardConnection() @@ -47,7 +48,6 @@ WorkflowContext::WorkflowContext(const Action pAction) , mProgressMessage() , mShowRemoveCardFeedback(false) , mClaimedBy() - , mInterruptRequested(false) { connect(this, &WorkflowContext::fireCancelWorkflow, this, &WorkflowContext::onWorkflowCancelled); } @@ -221,7 +221,9 @@ void WorkflowContext::setCardConnection(const QSharedPointer& pC if (mCardConnection != pCardConnection) { mCardConnection = pCardConnection; + Q_EMIT fireCardConnectionChanged(); + Q_EMIT fireEidTypeMismatchChanged(); } } @@ -589,23 +591,47 @@ void WorkflowContext::setRemoveCardFeedback(bool pEnabled) } -bool WorkflowContext::isPhysicalCardRequired() const +bool WorkflowContext::eidTypeMismatch() const { + if (!getCardConnection()) + { + return false; + } + const auto& acceptedEidTypes = getAcceptedEidTypes(); - return acceptedEidTypes.contains(AcceptedEidType::CARD_CERTIFIED) - && !(acceptedEidTypes.contains(AcceptedEidType::SE_CERTIFIED) - || acceptedEidTypes.contains(AcceptedEidType::SE_ENDORSED) - || acceptedEidTypes.contains(AcceptedEidType::HW_KEYSTORE)); -} + const auto& cardType = getCardConnection()->getReaderInfo().getCardInfo().getCardType(); + const auto& mobileEidType = getCardConnection()->getReaderInfo().getCardInfo().getMobileEidType(); + if (cardType == CardType::NONE) + { + return false; + } -bool WorkflowContext::interruptRequested() const -{ - return mInterruptRequested; + if (cardType == CardType::EID_CARD) + { + return !acceptedEidTypes.contains(AcceptedEidType::CARD_CERTIFIED); + } + + return !isMobileEidTypeAllowed(mobileEidType); } -void WorkflowContext::setInterruptRequested(bool pInterruptRequested) +bool WorkflowContext::isMobileEidTypeAllowed(const MobileEidType& mobileEidType) const { - mInterruptRequested = pInterruptRequested; + const auto& acceptedEidTypes = getAcceptedEidTypes(); + switch (mobileEidType) + { + case MobileEidType::SE_CERTIFIED: + return acceptedEidTypes.contains(AcceptedEidType::SE_CERTIFIED); + + case MobileEidType::SE_ENDORSED: + return acceptedEidTypes.contains(AcceptedEidType::SE_ENDORSED); + + case MobileEidType::HW_KEYSTORE: + return acceptedEidTypes.contains(AcceptedEidType::HW_KEYSTORE); + + case MobileEidType::UNKNOWN: + return false; + } + Q_UNREACHABLE(); } diff --git a/src/workflows/base/context/WorkflowContext.h b/src/workflows/base/context/WorkflowContext.h index c0e221316..3c75a1a3f 100644 --- a/src/workflows/base/context/WorkflowContext.h +++ b/src/workflows/base/context/WorkflowContext.h @@ -36,6 +36,7 @@ class WorkflowContext private: const Action mAction; + const bool mActivateUi; bool mStateApproved; bool mWorkflowKilled; QString mCurrentState; @@ -66,7 +67,6 @@ class WorkflowContext QString mProgressMessage; bool mShowRemoveCardFeedback; QString mClaimedBy; - bool mInterruptRequested; private Q_SLOTS: void onWorkflowCancelled(); @@ -78,7 +78,8 @@ class WorkflowContext void fireReaderInfoChanged(); void fireReaderNameChanged(); void fireCardConnectionChanged(); - void fireIsSmartCardAllowedChanged(); + void fireAcceptedEidTypesChanged(); + void fireEidTypeMismatchChanged(); void fireCanChanged(); void firePinChanged(); void firePukChanged(); @@ -94,7 +95,7 @@ class WorkflowContext void fireNextWorkflowPending(); public: - explicit WorkflowContext(const Action mAction); + explicit WorkflowContext(const Action mAction, bool pActivateUi = true); ~WorkflowContext() override; [[nodiscard]] Action getAction() const @@ -103,6 +104,12 @@ class WorkflowContext } + [[nodiscard]] bool isActivateUi() const + { + return mActivateUi; + } + + [[nodiscard]] bool wasClaimed() const; void claim(const QObject* pClaimant); @@ -220,10 +227,8 @@ class WorkflowContext [[nodiscard]] virtual QVector getAcceptedEidTypes() const = 0; - bool isPhysicalCardRequired() const; - - [[nodiscard]] bool interruptRequested() const; - void setInterruptRequested(bool pInterruptRequested); + [[nodiscard]] bool eidTypeMismatch() const; + [[nodiscard]] bool isMobileEidTypeAllowed(const MobileEidType& mobileEidType) const; }; } // namespace governikus diff --git a/src/workflows/base/controller/AuthController.cpp b/src/workflows/base/controller/AuthController.cpp index e5ee20927..57db55145 100644 --- a/src/workflows/base/controller/AuthController.cpp +++ b/src/workflows/base/controller/AuthController.cpp @@ -5,17 +5,14 @@ #include "controller/AuthController.h" #include "context/AuthContext.h" -#include "context/InternalActivationContext.h" #include "states/CompositeStateTrustedChannel.h" #include "states/FinalState.h" #include "states/StateActivateStoreFeedbackDialog.h" #include "states/StateCheckError.h" #include "states/StateCheckRefreshAddress.h" #include "states/StateParseTcTokenUrl.h" -#include "states/StateProcessing.h" #include "states/StateRedirectBrowser.h" #include "states/StateSendWhitelistSurvey.h" -#include "states/StateWriteHistory.h" #include #include @@ -27,22 +24,15 @@ using namespace governikus; AuthController::AuthController(QSharedPointer pContext) : WorkflowController(pContext) { - auto sProcessing = addState(); - mStateMachine.setInitialState(sProcessing); - auto sParseTcTokenUrl = addState(); - auto sTrustedChannel = new CompositeStateTrustedChannel(pContext); - mStateMachine.addState(sTrustedChannel); + auto sParseTcTokenUrl = addInitialState(); + auto sTrustedChannel = addState(); auto sCheckRefreshAddress = addState(); auto sCheckError = addState(); auto sActivateStoreFeedbackDialog = addState(); - auto sWriteHistory = addState(); auto sSendWhitelistSurvey = addState(); auto sRedirectBrowser = addState(); auto sFinal = addState(); - sProcessing->addTransition(sProcessing, &AbstractState::fireContinue, sParseTcTokenUrl); - sProcessing->addTransition(sProcessing, &AbstractState::fireAbort, sCheckRefreshAddress); - sParseTcTokenUrl->addTransition(sParseTcTokenUrl, &AbstractState::fireContinue, sTrustedChannel); sParseTcTokenUrl->addTransition(sParseTcTokenUrl, &AbstractState::fireAbort, sCheckRefreshAddress); @@ -56,11 +46,8 @@ AuthController::AuthController(QSharedPointer pContext) sCheckError->addTransition(sCheckError, &AbstractState::fireAbort, sRedirectBrowser); sCheckError->addTransition(sCheckError, &StateCheckError::firePropagateAbort, sRedirectBrowser); - sActivateStoreFeedbackDialog->addTransition(sActivateStoreFeedbackDialog, &AbstractState::fireContinue, sWriteHistory); - sActivateStoreFeedbackDialog->addTransition(sActivateStoreFeedbackDialog, &AbstractState::fireAbort, sWriteHistory); - - sWriteHistory->addTransition(sWriteHistory, &AbstractState::fireContinue, sSendWhitelistSurvey); - sWriteHistory->addTransition(sWriteHistory, &AbstractState::fireAbort, sRedirectBrowser); + sActivateStoreFeedbackDialog->addTransition(sActivateStoreFeedbackDialog, &AbstractState::fireContinue, sSendWhitelistSurvey); + sActivateStoreFeedbackDialog->addTransition(sActivateStoreFeedbackDialog, &AbstractState::fireAbort, sRedirectBrowser); sSendWhitelistSurvey->addTransition(sSendWhitelistSurvey, &AbstractState::fireContinue, sRedirectBrowser); sSendWhitelistSurvey->addTransition(sSendWhitelistSurvey, &AbstractState::fireAbort, sRedirectBrowser); @@ -70,9 +57,9 @@ AuthController::AuthController(QSharedPointer pContext) } -QSharedPointer AuthController::createWorkflowRequest(const QSharedPointer& pActivationContext) +QSharedPointer AuthController::createWorkflowRequest(const QUrl& pUrl, const QVariant& pData, const AuthContext::BrowserHandler& pBrowserHandler) { - const auto& handler = [](const WorkflowRequest& pRequest, const QSharedPointer& pActiveWorkflow, const QSharedPointer& pWaitingWorkflow){ + const auto& handler = [](const QSharedPointer& pActiveWorkflow, const QSharedPointer& pWaitingWorkflow){ if (QVector{Action::AUTH, Action::SELF, Action::PIN}.contains(pActiveWorkflow->getAction())) { const auto activeContext = pActiveWorkflow->getContext(); @@ -87,20 +74,8 @@ QSharedPointer AuthController::createWorkflowRequest(const QSha } } - auto context = pRequest.getContext().objectCast(); - if (context && !context->getActivationContext()->sendOperationAlreadyActive()) - { - qCritical() << "Cannot send \"Operation already active\" to caller:" << context->getActivationContext()->getSendError(); - } - return WorkflowControl::SKIP; }; - return WorkflowRequest::createWorkflowRequestHandler(handler, pActivationContext); -} - - -QSharedPointer AuthController::createWorkflowRequest(const QUrl& pUrl) -{ - return createWorkflowRequest(QSharedPointer::create(pUrl)); + return WorkflowRequest::createHandler(handler, pData, true, pUrl, pBrowserHandler); } diff --git a/src/workflows/base/controller/AuthController.h b/src/workflows/base/controller/AuthController.h index 9c990aa19..9646374fd 100644 --- a/src/workflows/base/controller/AuthController.h +++ b/src/workflows/base/controller/AuthController.h @@ -10,21 +10,20 @@ #include "WorkflowController.h" #include "WorkflowRequest.h" -#include "context/ActivationContext.h" +#include "context/AuthContext.h" namespace governikus { -class AuthContext; - class AuthController : public WorkflowController { Q_OBJECT public: - static QSharedPointer createWorkflowRequest(const QSharedPointer& pActivationContext); - static QSharedPointer createWorkflowRequest(const QUrl& pUrl); + static QSharedPointer createWorkflowRequest(const QUrl& pUrl, + const QVariant& pData = QVariant(), + const AuthContext::BrowserHandler& pBrowserHandler = AuthContext::BrowserHandler()); explicit AuthController(QSharedPointer pContext); ~AuthController() override = default; diff --git a/src/workflows/base/controller/ChangePinController.cpp b/src/workflows/base/controller/ChangePinController.cpp index e6dfed37a..839cd1155 100644 --- a/src/workflows/base/controller/ChangePinController.cpp +++ b/src/workflows/base/controller/ChangePinController.cpp @@ -25,8 +25,7 @@ using namespace governikus; ChangePinController::ChangePinController(QSharedPointer pContext) : WorkflowController(pContext) { - auto sStatePace = new CompositeStatePace(pContext); - mStateMachine.addState(sStatePace); + auto sStatePace = addInitialState(); auto sPrepareChangePin = addState(); auto sEnterNewPacePin = addState(); auto sChangePin = addState(); @@ -34,9 +33,7 @@ ChangePinController::ChangePinController(QSharedPointer pConte auto sDestroyPace = addState(); auto sUpdateRetryCounterFinal = addState(); auto sCleanUpReaderManager = addState(); - auto sFinal = addState(); - mStateMachine.setInitialState(sStatePace); sStatePace->addTransition(sStatePace, &CompositeStatePace::fireContinue, sPrepareChangePin); sStatePace->addTransition(sStatePace, &CompositeStatePace::fireAbort, sClearPacePasswords); @@ -68,10 +65,9 @@ ChangePinController::ChangePinController(QSharedPointer pConte } -QSharedPointer ChangePinController::createWorkflowRequest(bool pRequestTransportPin) +QSharedPointer ChangePinController::createWorkflowRequest(bool pRequestTransportPin, bool pActivateUi) { - const auto& handler = [](const WorkflowRequest& pRequest, const QSharedPointer& pActiveWorkflow, const QSharedPointer& pWaitingWorkflow){ - Q_UNUSED(pRequest) + const auto& handler = [](const QSharedPointer& pActiveWorkflow, const QSharedPointer& pWaitingWorkflow){ Q_UNUSED(pActiveWorkflow) if (pWaitingWorkflow.isNull()) @@ -82,5 +78,5 @@ QSharedPointer ChangePinController::createWorkflowRequest(bool return WorkflowControl::SKIP; }; - return WorkflowRequest::createWorkflowRequestHandler(handler, pRequestTransportPin); + return WorkflowRequest::createHandler(handler, pRequestTransportPin, pActivateUi); } diff --git a/src/workflows/base/controller/ChangePinController.h b/src/workflows/base/controller/ChangePinController.h index 6a7b835e2..49dc1147a 100644 --- a/src/workflows/base/controller/ChangePinController.h +++ b/src/workflows/base/controller/ChangePinController.h @@ -23,7 +23,7 @@ class ChangePinController Q_OBJECT public: - static QSharedPointer createWorkflowRequest(bool pRequestTransportPin = false); + static QSharedPointer createWorkflowRequest(bool pRequestTransportPin = false, bool pActivateUi = true); explicit ChangePinController(QSharedPointer pContext); ~ChangePinController() override = default; diff --git a/src/workflows/base/controller/WorkflowController.cpp b/src/workflows/base/controller/WorkflowController.cpp index cff04cf2e..0fb2b417b 100644 --- a/src/workflows/base/controller/WorkflowController.cpp +++ b/src/workflows/base/controller/WorkflowController.cpp @@ -4,14 +4,12 @@ #include "controller/WorkflowController.h" -#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) - #include "ReaderManager.h" -#endif +#include "states/AbstractState.h" -#include using namespace governikus; + WorkflowController::WorkflowController(const QSharedPointer& pContext) : mStateMachine() , mContext(pContext) @@ -20,6 +18,12 @@ WorkflowController::WorkflowController(const QSharedPointer& pC } +void WorkflowController::forceStartStopScan() +{ + mStateMachine.setProperty(AbstractState::cFORCE_START_STOP_SCAN, true); +} + + void WorkflowController::run() { mStateMachine.start(); diff --git a/src/workflows/base/controller/WorkflowController.h b/src/workflows/base/controller/WorkflowController.h index 406d09d9d..da3af83f6 100644 --- a/src/workflows/base/controller/WorkflowController.h +++ b/src/workflows/base/controller/WorkflowController.h @@ -8,12 +8,14 @@ #pragma once +#include "context/WorkflowContext.h" #include "states/StateBuilder.h" -#include #include #include +class test_AppController; + namespace governikus { @@ -21,36 +23,38 @@ class WorkflowController : public QObject { Q_OBJECT + friend class ::test_AppController; - protected: + private: QStateMachine mStateMachine; const QSharedPointer mContext; - public: - explicit WorkflowController(const QSharedPointer& pContext); - - void run(); - - [[nodiscard]] Action getAction() const - { - return mContext->getAction(); - } - - - [[nodiscard]] QSharedPointer getContext() const + protected: + template + [[nodiscard]] T* addState() { - return mContext; + auto state = StateBuilder::createState(mContext); + mStateMachine.addState(state); + return state; } template - T* addState() + [[nodiscard]] T* addInitialState() { - auto state = StateBuilder::createState(mContext); - mStateMachine.addState(state); + auto state = addState(); + mStateMachine.setInitialState(state); return state; } + + void forceStartStopScan(); + + public: + explicit WorkflowController(const QSharedPointer& pContext); + + void run(); + Q_SIGNALS: void fireComplete(); diff --git a/src/workflows/base/paos/ElementDetector.cpp b/src/workflows/base/paos/ElementDetector.cpp index 680a969e8..70c3a7d88 100644 --- a/src/workflows/base/paos/ElementDetector.cpp +++ b/src/workflows/base/paos/ElementDetector.cpp @@ -15,7 +15,6 @@ Q_DECLARE_LOGGING_CATEGORY(paos) ElementDetector::ElementDetector(const QByteArray& pXmlData) : mReader(pXmlData) - , mXmlData(pXmlData) { } diff --git a/src/workflows/base/paos/ElementDetector.h b/src/workflows/base/paos/ElementDetector.h index 9f2b19bba..25d03032b 100644 --- a/src/workflows/base/paos/ElementDetector.h +++ b/src/workflows/base/paos/ElementDetector.h @@ -19,10 +19,10 @@ class ElementDetector { Q_DISABLE_COPY(ElementDetector) - protected: + private: QXmlStreamReader mReader; - const QByteArray mXmlData; + protected: void handleStartElements(const QStringList& pStartElementNames); void detectStartElements(const QStringList& pStartElementNames); virtual bool handleFoundElement(const QString& pElementName, const QString& pValue, const QXmlStreamAttributes& pAttributes) = 0; diff --git a/src/workflows/base/paos/PaosHandler.cpp b/src/workflows/base/paos/PaosHandler.cpp index 589ab5016..d928b55e5 100644 --- a/src/workflows/base/paos/PaosHandler.cpp +++ b/src/workflows/base/paos/PaosHandler.cpp @@ -16,6 +16,7 @@ using namespace governikus; PaosHandler::PaosHandler(const QByteArray& pXmlData) : ElementDetector(pXmlData) + , mXmlData(pXmlData) , mDetectedType(PaosType::UNKNOWN) , mParsedObject() { diff --git a/src/workflows/base/paos/PaosHandler.h b/src/workflows/base/paos/PaosHandler.h index b5b3e1b79..dc3bb3ab6 100644 --- a/src/workflows/base/paos/PaosHandler.h +++ b/src/workflows/base/paos/PaosHandler.h @@ -23,6 +23,7 @@ class PaosHandler Q_DISABLE_COPY(PaosHandler) private: + const QByteArray mXmlData; PaosType mDetectedType; QSharedPointer mParsedObject; diff --git a/src/workflows/base/paos/element/UserAgent.cpp b/src/workflows/base/paos/element/UserAgent.cpp index c7fe3c1fb..45432e90f 100644 --- a/src/workflows/base/paos/element/UserAgent.cpp +++ b/src/workflows/base/paos/element/UserAgent.cpp @@ -4,6 +4,7 @@ #include "UserAgent.h" +#include "VersionInfo.h" #include "VersionNumber.h" #include @@ -24,7 +25,7 @@ UserAgent::UserAgent() QString UserAgent::getName() const { - return QCoreApplication::applicationName(); + return VersionInfo::getInstance().getImplementationTitle(); } diff --git a/src/workflows/base/paos/retrieve/StartPaosResponse.cpp b/src/workflows/base/paos/retrieve/StartPaosResponse.cpp index 11cf382be..c0fe6c5b1 100644 --- a/src/workflows/base/paos/retrieve/StartPaosResponse.cpp +++ b/src/workflows/base/paos/retrieve/StartPaosResponse.cpp @@ -12,6 +12,7 @@ StartPaosResponse::StartPaosResponse(const QByteArray& pXmlData) , mResultMajor() , mResultMinor() , mResultMessage() + , mStatusCode(0) , mRemainingDays(-1) , mRemainingAttempts(-1) , mBlockingCode() @@ -21,6 +22,12 @@ StartPaosResponse::StartPaosResponse(const QByteArray& pXmlData) } +int StartPaosResponse::getStatusCode() const +{ + return mStatusCode; +} + + int StartPaosResponse::getRemainingDays() const { return mRemainingDays; @@ -47,6 +54,7 @@ void StartPaosResponse::parse() QStringLiteral("ResultMajor"), QStringLiteral("ResultMinor"), QStringLiteral("ResultMessage"), + QStringLiteral("statusCode"), QStringLiteral("remainingDays"), QStringLiteral("remainingAttempts"), QStringLiteral("blockingCode") @@ -74,6 +82,10 @@ bool StartPaosResponse::handleFoundElement(const QString& pElementName, const QS { mResultMessage = pValue; } + else if (pElementName == QLatin1String("statusCode")) + { + mStatusCode = valuetoInt(pValue); + } else if (pElementName == QLatin1String("remainingDays")) { mRemainingDays = valuetoInt(pValue); diff --git a/src/workflows/base/paos/retrieve/StartPaosResponse.h b/src/workflows/base/paos/retrieve/StartPaosResponse.h index 11357ee49..1ddd63f89 100644 --- a/src/workflows/base/paos/retrieve/StartPaosResponse.h +++ b/src/workflows/base/paos/retrieve/StartPaosResponse.h @@ -25,6 +25,7 @@ class StartPaosResponse QString mResultMajor; QString mResultMinor; QString mResultMessage; + int mStatusCode; int mRemainingDays; int mRemainingAttempts; QString mBlockingCode; @@ -32,6 +33,7 @@ class StartPaosResponse public: explicit StartPaosResponse(const QByteArray& pXmlData); + [[nodiscard]] int getStatusCode() const; [[nodiscard]] int getRemainingDays() const; [[nodiscard]] int getRemainingAttempts() const; [[nodiscard]] const QString& getBlockingCode() const; diff --git a/src/workflows/base/paos/retrieve/TransmitParser.cpp b/src/workflows/base/paos/retrieve/TransmitParser.cpp index 22801753f..f322aea45 100644 --- a/src/workflows/base/paos/retrieve/TransmitParser.cpp +++ b/src/workflows/base/paos/retrieve/TransmitParser.cpp @@ -45,7 +45,7 @@ PaosMessage* TransmitParser::parseMessage() } -void TransmitParser::parseSlotHandle() +void TransmitParser::parseSlotHandle() const { } diff --git a/src/workflows/base/paos/retrieve/TransmitParser.h b/src/workflows/base/paos/retrieve/TransmitParser.h index 801601424..4c222a8e0 100644 --- a/src/workflows/base/paos/retrieve/TransmitParser.h +++ b/src/workflows/base/paos/retrieve/TransmitParser.h @@ -29,7 +29,7 @@ class TransmitParser PaosMessage* parseMessage() override; private: - void parseSlotHandle(); + void parseSlotHandle() const; void parseInputApduInfo(); private: diff --git a/src/workflows/base/states/AbstractState.cpp b/src/workflows/base/states/AbstractState.cpp index 05f8cab85..5b024e893 100644 --- a/src/workflows/base/states/AbstractState.cpp +++ b/src/workflows/base/states/AbstractState.cpp @@ -5,7 +5,9 @@ #include "AbstractState.h" #include "ReaderManager.h" -#include "VolatileSettings.h" +#if defined(Q_OS_IOS) + #include "VolatileSettings.h" +#endif #include #include @@ -22,9 +24,9 @@ const char* const AbstractState::cFORCE_START_STOP_SCAN = "FORCE_START_STOP_SCAN AbstractState::AbstractState(const QSharedPointer& pContext) : mContext(pContext) + , mConnections() , mAbortOnCardRemoved(false) , mKeepCardConnectionAlive(false) - , mConnections() { Q_ASSERT(mContext); connect(this, &AbstractState::fireAbort, this, &AbstractState::onAbort); @@ -50,12 +52,6 @@ QString AbstractState::getStateName() const } -void AbstractState::setStateName(const QString& pName) -{ - setObjectName(pName); -} - - void AbstractState::onAbort(const FailureCode& pFailure) const { if (mContext) @@ -66,17 +62,6 @@ void AbstractState::onAbort(const FailureCode& pFailure) const } -QString AbstractState::getClassName(const char* const pName) -{ - QString className = QString::fromLatin1(pName); - if (className.contains(QLatin1Char(':'))) - { - className = className.mid(className.lastIndexOf(QLatin1Char(':')) + 1); - } - return className; -} - - void AbstractState::onStateApprovedChanged(bool pApproved) { if (pApproved) @@ -89,6 +74,12 @@ void AbstractState::onStateApprovedChanged(bool pApproved) void AbstractState::onEntry(QEvent* pEvent) { + if (!mConnections.isEmpty()) + { + dumpObjectInfo(); + } + Q_ASSERT(mConnections.isEmpty()); + if (mAbortOnCardRemoved) { const auto readerManager = Env::getSingleton(); @@ -108,7 +99,7 @@ void AbstractState::onEntry(QEvent* pEvent) if (mContext->isWorkflowCancelled() && !mContext->isWorkflowCancelledInState()) { - onUserCancelled(); + QMetaObject::invokeMethod(this, &AbstractState::onUserCancelled, Qt::QueuedConnection); } QState::onEntry(pEvent); @@ -130,6 +121,12 @@ void AbstractState::onExit(QEvent* pEvent) } +void AbstractState::operator<<(const QMetaObject::Connection& connection) +{ + mConnections += connection; +} + + void AbstractState::clearConnections() { for (const auto& connection : std::as_const(mConnections)) @@ -140,7 +137,7 @@ void AbstractState::clearConnections() } -bool AbstractState::isCancellationByUser() +bool AbstractState::isCancellationByUser() const { return mContext->getStatus().isCancellationByUser(); } @@ -195,7 +192,7 @@ bool AbstractState::isStartStopEnabled() const } -void AbstractState::stopNfcScanIfNecessary(const QString& pError) +void AbstractState::stopNfcScanIfNecessary(const QString& pError) const { #if defined(Q_OS_IOS) const auto& volatileSettings = Env::getSingleton(); diff --git a/src/workflows/base/states/AbstractState.h b/src/workflows/base/states/AbstractState.h index 876aa1076..763e52346 100644 --- a/src/workflows/base/states/AbstractState.h +++ b/src/workflows/base/states/AbstractState.h @@ -9,12 +9,25 @@ #pragma once #include "FailureCode.h" +#include "StateBuilder.h" #include "context/WorkflowContext.h" #include #include +class test_StateChangePinIfd; +class test_StateChangeSmartPin; +class test_StateEstablishPaceChannelIfd; +class test_StateProcessIfdMessages; +class test_StateChangePin; +class test_StateDestroyPace; +class test_StateDidAuthenticateEac1; +class test_StateDidAuthenticateEac2; +class test_StateGetTcToken; +class test_StateTransmit; + + namespace governikus { @@ -22,9 +35,21 @@ class AbstractState : public QState { Q_OBJECT + friend class ::test_StateChangePinIfd; + friend class ::test_StateChangeSmartPin; + friend class ::test_StateEstablishPaceChannelIfd; + friend class ::test_StateProcessIfdMessages; + friend class ::test_StateChangePin; + friend class ::test_StateDestroyPace; + friend class ::test_StateDidAuthenticateEac1; + friend class ::test_StateDidAuthenticateEac2; + friend class ::test_StateGetTcToken; + friend class ::test_StateTransmit; + friend class ::test_StateChangeSmartPin; private: const QSharedPointer mContext; + QVector mConnections; bool mAbortOnCardRemoved; bool mKeepCardConnectionAlive; @@ -32,8 +57,6 @@ class AbstractState [[nodiscard]] bool isStartStopEnabled() const; protected: - QVector mConnections; - explicit AbstractState(const QSharedPointer& pContext); void setAbortOnCardRemoved(); @@ -42,35 +65,21 @@ class AbstractState void onEntry(QEvent* pEvent) override; void onExit(QEvent* pEvent) override; + void operator<<(const QMetaObject::Connection& connection); + void clearConnections(); - bool isCancellationByUser(); + bool isCancellationByUser() const; void updateStatus(const GlobalStatus& pStatus); void updateStartPaosResult(const ECardApiResult& pStartPaosResult); - void stopNfcScanIfNecessary(const QString& pError = QString()); + void stopNfcScanIfNecessary(const QString& pError = QString()) const; public: static const char* const cFORCE_START_STOP_SCAN; - static QString getClassName(const char* const pName); - - template - [[nodiscard]] static QString getClassName() - { - return getClassName(T::staticMetaObject.className()); - } - - - template - static bool isState(const QString& pState) - { - return pState == getClassName(); - } - ~AbstractState() override = default; [[nodiscard]] QString getStateName() const; - void setStateName(const QString& pName); Q_SIGNALS: void fireContinue(); diff --git a/src/workflows/base/states/StateBuilder.cpp b/src/workflows/base/states/StateBuilder.cpp new file mode 100644 index 000000000..397ce328e --- /dev/null +++ b/src/workflows/base/states/StateBuilder.cpp @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2014-2023 Governikus GmbH & Co. KG, Germany + */ + +#include "StateBuilder.h" + + +using namespace governikus; + + +QString StateBuilder::getUnqualifiedClassName(const char* const pName) +{ + QString className = QString::fromLatin1(pName); + if (className.contains(QLatin1Char(':'))) + { + className = className.mid(className.lastIndexOf(QLatin1Char(':')) + 1); + } + return className; +} diff --git a/src/workflows/base/states/StateBuilder.h b/src/workflows/base/states/StateBuilder.h index 387c98df7..bd6199c06 100644 --- a/src/workflows/base/states/StateBuilder.h +++ b/src/workflows/base/states/StateBuilder.h @@ -8,7 +8,6 @@ #pragma once -#include "AbstractState.h" #include #include @@ -24,12 +23,28 @@ class StateBuilder StateBuilder() = delete; ~StateBuilder() = delete; + static QString getUnqualifiedClassName(const char* const pName); + public: + template + [[nodiscard]] static QString generateStateName() + { + return getUnqualifiedClassName(T::staticMetaObject.className()); + } + + + template + static bool isState(const QString& pState) + { + return pState == generateStateName(); + } + + template static T* createState(const QSharedPointer& pContext) { auto state = new T(pContext); - state->setStateName(AbstractState::getClassName(state->metaObject()->className())); + state->setObjectName(getUnqualifiedClassName(state->metaObject()->className())); return state; } diff --git a/src/workflows/base/states/StateChangePin.cpp b/src/workflows/base/states/StateChangePin.cpp index 76bc5308f..b8ad509e1 100644 --- a/src/workflows/base/states/StateChangePin.cpp +++ b/src/workflows/base/states/StateChangePin.cpp @@ -28,7 +28,7 @@ void StateChangePin::run() Q_ASSERT(cardConnection); qDebug() << "Invoke set Eid PIN command"; - mConnections += cardConnection->callSetEidPinCommand(this, &StateChangePin::onSetEidPinDone, getContext()->getNewPin().toLatin1()); + *this << cardConnection->callSetEidPinCommand(this, &StateChangePin::onSetEidPinDone, getContext()->getNewPin().toLatin1()); } diff --git a/src/workflows/base/states/StateCheckRefreshAddress.cpp b/src/workflows/base/states/StateCheckRefreshAddress.cpp index c2cfddfe5..c99dc9821 100644 --- a/src/workflows/base/states/StateCheckRefreshAddress.cpp +++ b/src/workflows/base/states/StateCheckRefreshAddress.cpp @@ -128,7 +128,7 @@ void StateCheckRefreshAddress::run() } -QUrl StateCheckRefreshAddress::determineSubjectUrl() +QUrl StateCheckRefreshAddress::determineSubjectUrl() const { QUrl subjectUrl; auto eac1 = getContext()->getDidAuthenticateEac1(); @@ -162,9 +162,10 @@ void StateCheckRefreshAddress::sendGetRequest() qDebug() << "Send GET request to URL:" << mUrl.toString(); QNetworkRequest request(mUrl); mReply = Env::getSingleton()->get(request); - mConnections += connect(mReply.data(), &QNetworkReply::sslErrors, this, &StateCheckRefreshAddress::onSslErrors); - mConnections += connect(mReply.data(), &QNetworkReply::encrypted, this, &StateCheckRefreshAddress::onSslHandshakeDone); - mConnections += connect(mReply.data(), &QNetworkReply::finished, this, &StateCheckRefreshAddress::onNetworkReply); + + *this << connect(mReply.data(), &QNetworkReply::sslErrors, this, &StateCheckRefreshAddress::onSslErrors); + *this << connect(mReply.data(), &QNetworkReply::encrypted, this, &StateCheckRefreshAddress::onSslHandshakeDone); + *this << connect(mReply.data(), &QNetworkReply::finished, this, &StateCheckRefreshAddress::onNetworkReply); } @@ -222,30 +223,30 @@ bool StateCheckRefreshAddress::checkSslConnectionAndSaveCertificate(const QSslCo } const auto statusCode = CertificateChecker::checkAndSaveCertificate(pSslConfiguration.peerCertificate(), mUrl, context); - if (statusCode != CertificateChecker::CertificateStatus::Good) + if (statusCode == CertificateChecker::CertificateStatus::Good) { - infoMap.insert(GlobalStatus::ExternalInformation::CERTIFICATE_ISSUER_NAME, TlsChecker::getCertificateIssuerName(pSslConfiguration.peerCertificate())); - switch (statusCode) - { - case CertificateChecker::CertificateStatus::Good: - break; + mVerifiedRefreshUrlHosts << mUrl; + return true; + } - case CertificateChecker::CertificateStatus::Unsupported_Algorithm_Or_Length: - reportCommunicationError({CertificateChecker::getGlobalStatus(statusCode, false), infoMap}, - FailureCode::Reason::Check_Refresh_Address_Unsupported_Certificate); - break; + infoMap.insert(GlobalStatus::ExternalInformation::CERTIFICATE_ISSUER_NAME, TlsChecker::getCertificateIssuerName(pSslConfiguration.peerCertificate())); + switch (statusCode) + { + case CertificateChecker::CertificateStatus::Good: + break; - case CertificateChecker::CertificateStatus::Hash_Not_In_Description: - reportCommunicationError({CertificateChecker::getGlobalStatus(statusCode, false), infoMap}, - FailureCode::Reason::Check_Refresh_Address_Hash_Missing_In_Certificate); + case CertificateChecker::CertificateStatus::Unsupported_Algorithm_Or_Length: + reportCommunicationError({CertificateChecker::getGlobalStatus(statusCode, false), infoMap}, + FailureCode::Reason::Check_Refresh_Address_Unsupported_Certificate); + break; - } + case CertificateChecker::CertificateStatus::Hash_Not_In_Description: + reportCommunicationError({CertificateChecker::getGlobalStatus(statusCode, false), infoMap}, + FailureCode::Reason::Check_Refresh_Address_Hash_Missing_In_Certificate); - return false; } - mVerifiedRefreshUrlHosts << mUrl; - return true; + return false; } @@ -261,6 +262,16 @@ void StateCheckRefreshAddress::onNetworkReply() }, FailureCode::Reason::Check_Refresh_Address_Service_Unavailable, mReply->errorString()); break; + case NetworkManager::NetworkError::ServerError: + reportCommunicationError({GlobalStatus::Code::Network_ServerError, {GlobalStatus::ExternalInformation::LAST_URL, mUrl.toString()} + }, FailureCode::Reason::Check_Refresh_Address_Server_Error, mReply->errorString()); + break; + + case NetworkManager::NetworkError::ClientError: + reportCommunicationError({GlobalStatus::Code::Network_ClientError, {GlobalStatus::ExternalInformation::LAST_URL, mUrl.toString()} + }, FailureCode::Reason::Check_Refresh_Address_Client_Error, mReply->errorString()); + break; + case NetworkManager::NetworkError::TimeOut: reportCommunicationError({GlobalStatus::Code::Network_TimeOut, {GlobalStatus::ExternalInformation::LAST_URL, mUrl.toString()} }, FailureCode::Reason::Check_Refresh_Address_Service_Timeout, mReply->errorString()); @@ -386,9 +397,9 @@ void StateCheckRefreshAddress::fetchServerCertificate() Env::getSingleton()->clearConnections(); mReply = Env::getSingleton()->get(request); - mConnections += connect(mReply.data(), &QNetworkReply::encrypted, this, &StateCheckRefreshAddress::onSslHandshakeDoneFetchingServerCertificate); - mConnections += connect(mReply.data(), &QNetworkReply::sslErrors, this, &StateCheckRefreshAddress::onSslErrors); - mConnections += connect(mReply.data(), &QNetworkReply::errorOccurred, this, &StateCheckRefreshAddress::onNetworkErrorFetchingServerCertificate); + *this << connect(mReply.data(), &QNetworkReply::encrypted, this, &StateCheckRefreshAddress::onSslHandshakeDoneFetchingServerCertificate); + *this << connect(mReply.data(), &QNetworkReply::sslErrors, this, &StateCheckRefreshAddress::onSslErrors); + *this << connect(mReply.data(), &QNetworkReply::errorOccurred, this, &StateCheckRefreshAddress::onNetworkErrorFetchingServerCertificate); } diff --git a/src/workflows/base/states/StateCheckRefreshAddress.h b/src/workflows/base/states/StateCheckRefreshAddress.h index 3fd10e1c0..469659d65 100644 --- a/src/workflows/base/states/StateCheckRefreshAddress.h +++ b/src/workflows/base/states/StateCheckRefreshAddress.h @@ -44,7 +44,7 @@ class StateCheckRefreshAddress [[nodiscard]] bool isMatchingSameOriginPolicyInDevMode() const; void run() override; - QUrl determineSubjectUrl(); + QUrl determineSubjectUrl() const; void sendGetRequest(); void fetchServerCertificate(); diff --git a/src/workflows/base/states/StateConnectCard.cpp b/src/workflows/base/states/StateConnectCard.cpp index 9ab124e74..28f7f87f5 100644 --- a/src/workflows/base/states/StateConnectCard.cpp +++ b/src/workflows/base/states/StateConnectCard.cpp @@ -25,8 +25,9 @@ StateConnectCard::StateConnectCard(const QSharedPointer& pConte void StateConnectCard::run() { const auto readerManager = Env::getSingleton(); - mConnections += connect(readerManager, &ReaderManager::fireCardInserted, this, &StateConnectCard::onCardInserted); - mConnections += connect(readerManager, &ReaderManager::fireReaderRemoved, this, &StateConnectCard::onReaderRemoved); + *this << connect(readerManager, &ReaderManager::fireCardInserted, this, &StateConnectCard::onCardInserted); + *this << connect(readerManager, &ReaderManager::fireCardRemoved, this, &StateConnectCard::onUnusableCardConnectionLost); + *this << connect(readerManager, &ReaderManager::fireReaderRemoved, this, &StateConnectCard::onUnusableCardConnectionLost); onCardInserted(); } @@ -40,7 +41,7 @@ void StateConnectCard::onCardInserted() if (readerInfo.hasEid()) { qCDebug(statemachine) << "Card has been inserted, trying to connect"; - mConnections += readerManager->callCreateCardConnectionCommand(readerInfo.getName(), this, &StateConnectCard::onCommandDone); + *this << readerManager->callCreateCardConnectionCommand(readerInfo.getName(), this, &StateConnectCard::onCommandDone); } } @@ -65,13 +66,15 @@ void StateConnectCard::onCommandDone(QSharedPointer const auto& readerInfo = cardConnection->getReaderInfo(); if (readerInfo.insufficientApduLength()) { + //: INFO IOS context->getCardConnection()->setProgressMessage(tr("The used card reader does not meet the technical requirements (Extended Length not supported).")); return; } - if (context->isSmartCardUsed() && context->isPhysicalCardRequired()) + if (context->eidTypeMismatch()) { - context->getCardConnection()->setProgressMessage(tr("The provider requires a physical ID card.")); + //: INFO IOS + context->getCardConnection()->setProgressMessage(tr("The used ID card type is not accepted by the server.")); return; } @@ -95,10 +98,12 @@ void StateConnectCard::onCommandDone(QSharedPointer } -void StateConnectCard::onReaderRemoved(const ReaderInfo& pInfo) +void StateConnectCard::onUnusableCardConnectionLost(const ReaderInfo& pInfo) { if (pInfo.getName() == getContext()->getReaderName()) { + getContext()->setReaderName(QString()); + getContext()->resetCardConnection(); Q_EMIT fireRetry(); } } @@ -106,6 +111,8 @@ void StateConnectCard::onReaderRemoved(const ReaderInfo& pInfo) void StateConnectCard::onEntry(QEvent* pEvent) { + AbstractState::onEntry(pEvent); + const WorkflowContext* const context = getContext().data(); Q_ASSERT(context); @@ -113,7 +120,5 @@ void StateConnectCard::onEntry(QEvent* pEvent) * Note: the plugin types to be used in this state must be already set in the workflow context before this state is entered. * Changing the plugin types in the context, e.g. from {NFC} to {REMOTE}, causes the state to be left with a fireRetry signal. */ - mConnections += connect(context, &WorkflowContext::fireReaderPlugInTypesChanged, this, &StateConnectCard::fireRetry); - - AbstractState::onEntry(pEvent); + *this << connect(context, &WorkflowContext::fireReaderPlugInTypesChanged, this, &StateConnectCard::fireRetry); } diff --git a/src/workflows/base/states/StateConnectCard.h b/src/workflows/base/states/StateConnectCard.h index 7ca38522e..0c6f06419 100644 --- a/src/workflows/base/states/StateConnectCard.h +++ b/src/workflows/base/states/StateConnectCard.h @@ -28,7 +28,7 @@ class StateConnectCard private Q_SLOTS: void onCardInserted(); void onCommandDone(QSharedPointer pCommand); - void onReaderRemoved(const ReaderInfo& pInfo); + void onUnusableCardConnectionLost(const ReaderInfo& pInfo); public: void onEntry(QEvent* pEvent) override; diff --git a/src/workflows/base/states/StateDestroyPace.cpp b/src/workflows/base/states/StateDestroyPace.cpp index e55688aa2..292cdd01d 100644 --- a/src/workflows/base/states/StateDestroyPace.cpp +++ b/src/workflows/base/states/StateDestroyPace.cpp @@ -29,7 +29,7 @@ void StateDestroyPace::run() return; } - mConnections += cardConnection->callDestroyPaceChannelCommand(this, &StateDestroyPace::onDestroyPaceDone); + *this << cardConnection->callDestroyPaceChannelCommand(this, &StateDestroyPace::onDestroyPaceDone); } diff --git a/src/workflows/base/states/StateDidAuthenticateEac1.cpp b/src/workflows/base/states/StateDidAuthenticateEac1.cpp index 5e38b9cff..65a44eb31 100644 --- a/src/workflows/base/states/StateDidAuthenticateEac1.cpp +++ b/src/workflows/base/states/StateDidAuthenticateEac1.cpp @@ -28,7 +28,7 @@ void StateDidAuthenticateEac1::run() auto cardConnection = getContext()->getCardConnection(); Q_ASSERT(cardConnection); - mConnections += cardConnection->callDidAuthenticateEAC1Command(this, &StateDidAuthenticateEac1::onCardCommandDone); + *this << cardConnection->callDidAuthenticateEAC1Command(this, &StateDidAuthenticateEac1::onCardCommandDone); } diff --git a/src/workflows/base/states/StateDidAuthenticateEac2.cpp b/src/workflows/base/states/StateDidAuthenticateEac2.cpp index 0737a6961..76cff0c3e 100644 --- a/src/workflows/base/states/StateDidAuthenticateEac2.cpp +++ b/src/workflows/base/states/StateDidAuthenticateEac2.cpp @@ -44,7 +44,7 @@ void StateDidAuthenticateEac2::run() return; } - mConnections += cardConnection->callDidAuthenticateEAC2Command(this, + *this << cardConnection->callDidAuthenticateEAC2Command(this, &StateDidAuthenticateEac2::onCardCommandDone, cvcChain, ephemeralPublicKeyAsHex, signatureAsHex, authenticatedAuxiliaryDataAsBinary, context->getPin().toLatin1()); } diff --git a/src/workflows/base/states/StateEnterPacePassword.cpp b/src/workflows/base/states/StateEnterPacePassword.cpp index be4ef387f..8811ae385 100644 --- a/src/workflows/base/states/StateEnterPacePassword.cpp +++ b/src/workflows/base/states/StateEnterPacePassword.cpp @@ -4,7 +4,6 @@ #include "StateEnterPacePassword.h" -#include "ReaderManager.h" #include "VolatileSettings.h" @@ -15,9 +14,6 @@ StateEnterPacePassword::StateEnterPacePassword(const QSharedPointer(); - mConnections += connect(readerManager, &ReaderManager::fireStatusChanged, this, &StateEnterPacePassword::onReaderStatusChanged); - setKeepCardConnectionAlive(); } @@ -53,29 +49,3 @@ void StateEnterPacePassword::onEntry(QEvent* pEvent) AbstractState::onEntry(pEvent); } - - -void StateEnterPacePassword::onReaderStatusChanged(const ReaderManagerPlugInInfo& pInfo) const -{ -#if defined(Q_OS_IOS) - const auto& volatileSettings = Env::getSingleton(); - if (!volatileSettings->isUsedAsSDK() || pInfo.getPlugInType() != ReaderManagerPlugInType::NFC) - { - return; - } - - if (!Env::getSingleton()->isScanRunning(ReaderManagerPlugInType::NFC)) - { - if (getContext()->interruptRequested()) - { - getContext()->setInterruptRequested(false); - } - else - { - Q_EMIT getContext()->fireCancelWorkflow(); - } - } -#else - Q_UNUSED(pInfo) -#endif -} diff --git a/src/workflows/base/states/StateEnterPacePassword.h b/src/workflows/base/states/StateEnterPacePassword.h index 869348d24..f2743e14a 100644 --- a/src/workflows/base/states/StateEnterPacePassword.h +++ b/src/workflows/base/states/StateEnterPacePassword.h @@ -25,9 +25,6 @@ class StateEnterPacePassword explicit StateEnterPacePassword(const QSharedPointer& pContext); void run() override; - private Q_SLOTS: - void onReaderStatusChanged(const ReaderManagerPlugInInfo& pInfo) const; - public: void onEntry(QEvent* pEvent) override; diff --git a/src/workflows/base/states/StateEstablishPaceChannel.cpp b/src/workflows/base/states/StateEstablishPaceChannel.cpp index 52b7609d1..acb2d2ffd 100644 --- a/src/workflows/base/states/StateEstablishPaceChannel.cpp +++ b/src/workflows/base/states/StateEstablishPaceChannel.cpp @@ -95,7 +95,7 @@ void StateEstablishPaceChannel::run() } //: INFO ALL_PLATFORMS First status message after the PIN was entered. - context->setProgress(0, tr("The secure channel is opened")); + context->setProgress(context->getProgressValue(), tr("The secure channel is opened")); qDebug() << "Establish connection using" << mPasswordId; Q_ASSERT(!password.isEmpty() || !cardConnection->getReaderInfo().isBasicReader()); @@ -109,7 +109,7 @@ void StateEstablishPaceChannel::run() } } - mConnections += cardConnection->callEstablishPaceChannelCommand(this, + *this << cardConnection->callEstablishPaceChannelCommand(this, &StateEstablishPaceChannel::onEstablishConnectionDone, mPasswordId, password, @@ -125,19 +125,7 @@ void StateEstablishPaceChannel::onUserCancelled() } -void StateEstablishPaceChannel::abortToChangePin(FailureCode::Reason pReason) -{ - if (auto authContext = getContext().objectCast()) - { - authContext->setSkipRedirect(true); - authContext->setLastPaceResult(CardReturnCode::NO_ACTIVE_PIN_SET); - } - updateStatus(GlobalStatus::Code::Workflow_Cancellation_By_User); - Q_EMIT fireAbort(pReason); -} - - -void StateEstablishPaceChannel::handleNpaPosition(CardReturnCode pReturnCode) +void StateEstablishPaceChannel::handleNpaPosition(CardReturnCode pReturnCode) const { if (pReturnCode == CardReturnCode::CARD_NOT_FOUND || pReturnCode == CardReturnCode::RETRY_ALLOWED) { @@ -207,10 +195,6 @@ void StateEstablishPaceChannel::onEstablishConnectionDone(QSharedPointer pCommand); diff --git a/src/workflows/base/states/StateGenericProviderCommunication.cpp b/src/workflows/base/states/StateGenericProviderCommunication.cpp index ce66842f8..2ee419e3c 100644 --- a/src/workflows/base/states/StateGenericProviderCommunication.cpp +++ b/src/workflows/base/states/StateGenericProviderCommunication.cpp @@ -9,6 +9,7 @@ #include "NetworkManager.h" #include "TlsChecker.h" +#include Q_DECLARE_LOGGING_CATEGORY(secure) Q_DECLARE_LOGGING_CATEGORY(network) @@ -34,9 +35,6 @@ void StateGenericProviderCommunication::setProgress() const void StateGenericProviderCommunication::run() { setProgress(); -#if !defined(GOVERNIKUS_QT) || QT_VERSION < QT_VERSION_CHECK(6, 2, 0) - Env::getSingleton()->clearConnections(); -#endif const QUrl address = getRequestUrl(); qDebug() << address; @@ -53,9 +51,9 @@ void StateGenericProviderCommunication::run() request.setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String("application/json")); mReply = Env::getSingleton()->post(request, payload); } - mConnections += connect(mReply.data(), &QNetworkReply::sslErrors, this, &StateGenericProviderCommunication::onSslErrors); - mConnections += connect(mReply.data(), &QNetworkReply::encrypted, this, &StateGenericProviderCommunication::onSslHandshakeDone); - mConnections += connect(mReply.data(), &QNetworkReply::finished, this, &StateGenericProviderCommunication::onNetworkReply); + *this << connect(mReply.data(), &QNetworkReply::sslErrors, this, &StateGenericProviderCommunication::onSslErrors); + *this << connect(mReply.data(), &QNetworkReply::encrypted, this, &StateGenericProviderCommunication::onSslHandshakeDone); + *this << connect(mReply.data(), &QNetworkReply::finished, this, &StateGenericProviderCommunication::onNetworkReply); } @@ -147,36 +145,59 @@ void StateGenericProviderCommunication::onSslHandshakeDone() void StateGenericProviderCommunication::onNetworkReply() { const auto statusCode = NetworkManager::getLoggedStatusCode(mReply, spawnMessageLogger(network)); - if (statusCode == HTTP_STATUS_OK) + + if (mReply->error() != QNetworkReply::NoError || statusCode != HTTP_STATUS_OK) { - const QByteArray message = mReply->readAll(); - if (NetworkManager::isLoggingAllowed(mReply) && isLoggingAllowed()) + const auto& status = NetworkManager::toTrustedChannelStatus(mReply); + qCCritical(network) << GlobalStatus(status); + updateStatus(status); + FailureCode::FailureInfoMap infoMap { + {FailureCode::Info::Network_Error, mReply->errorString()}, + {FailureCode::Info::State_Name, getStateName()} + }; + if (statusCode > 0) { - qCDebug(network).noquote() << "Received raw data:\n" << message; + infoMap[FailureCode::Info::Http_Status_Code] = QString::number(statusCode); } - else + FailureCode::Reason reason; + switch (NetworkManager::toNetworkError(mReply)) { - if (secure().isDebugEnabled()) - { - qCDebug(secure).noquote() << "Received raw data:\n" << message; - } - else - { - qCDebug(network) << "no-log was requested, skip logging of raw data"; - } + case NetworkManager::NetworkError::ServiceUnavailable: + reason = FailureCode::Reason::Generic_Provider_Communication_ServiceUnavailable; + break; + + case NetworkManager::NetworkError::ServerError: + reason = FailureCode::Reason::Generic_Provider_Communication_Server_Error; + break; + + case NetworkManager::NetworkError::ClientError: + reason = FailureCode::Reason::Generic_Provider_Communication_Client_Error; + break; + + default: + reason = FailureCode::Reason::Generic_Provider_Communication_Network_Error; } - handleNetworkReply(message); + Q_EMIT fireAbort({reason, infoMap}); return; } - qDebug() << "Network request failed"; - updateStatus(GlobalStatus::Code::Workflow_Server_Incomplete_Information_Provided); - const FailureCode::FailureInfoMap infoMap { - {FailureCode::Info::Network_Error, mReply->errorString()}, - {FailureCode::Info::Http_Status_Code, QString::number(statusCode)}, - {FailureCode::Info::State_Name, getStateName()} - }; - Q_EMIT fireAbort({FailureCode::Reason::Generic_Provider_Communication_Network_Error, infoMap}); + const QByteArray message = mReply->readAll(); + if (NetworkManager::isLoggingAllowed(mReply) && isLoggingAllowed()) + { + qCDebug(network).noquote() << "Received raw data:\n" << message; + } + else + { + if (secure().isDebugEnabled()) + { + qCDebug(secure).noquote() << "Received raw data:\n" << message; + } + else + { + qCDebug(network) << "no-log was requested, skip logging of raw data"; + } + } + handleNetworkReply(message); } diff --git a/src/workflows/base/states/StateGenericProviderCommunication.h b/src/workflows/base/states/StateGenericProviderCommunication.h index 8405d06d5..f5af4a5d6 100644 --- a/src/workflows/base/states/StateGenericProviderCommunication.h +++ b/src/workflows/base/states/StateGenericProviderCommunication.h @@ -38,9 +38,10 @@ class StateGenericProviderCommunication friend class ::test_StateGetSessionId; friend class ::test_StateGetChallenge; - protected: + private: QSharedPointer mReply; + protected: explicit StateGenericProviderCommunication(const QSharedPointer& pContext); virtual void handleNetworkReply(const QByteArray& pContent) = 0; diff --git a/src/workflows/base/states/StateGenericSendReceive.cpp b/src/workflows/base/states/StateGenericSendReceive.cpp index 3289ffb08..d2e993779 100644 --- a/src/workflows/base/states/StateGenericSendReceive.cpp +++ b/src/workflows/base/states/StateGenericSendReceive.cpp @@ -44,7 +44,27 @@ void StateGenericSendReceive::emitStateMachineSignal(PaosType pResponseType) } -void StateGenericSendReceive::setReceivedMessage(const QSharedPointer& pMessage) +void StateGenericSendReceive::logRawData(const QByteArray& pMessage) +{ + if (NetworkManager::isLoggingAllowed(mReply)) + { + qCDebug(network).noquote() << "Received raw data:\n" << pMessage; + } + else + { + if (secure().isDebugEnabled()) + { + qCDebug(secure).noquote() << "Received raw data:\n" << pMessage; + } + else + { + qCDebug(network) << "no-log was requested, skip logging of raw data"; + } + } +} + + +void StateGenericSendReceive::setReceivedMessage(const QSharedPointer& pMessage) const { getContext()->setReceivedMessageId(pMessage->getMessageId()); @@ -147,7 +167,7 @@ void StateGenericSendReceive::onSslHandshakeDone() } -void StateGenericSendReceive::onPreSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator* pAuthenticator) +void StateGenericSendReceive::onPreSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator* pAuthenticator) const { qCDebug(network) << "pre-shared key authentication requested:" << pAuthenticator->identityHint(); @@ -252,10 +272,10 @@ void StateGenericSendReceive::run() const QByteArray& paosNamespace = PaosCreator::getNamespace(PaosCreator::Namespace::PAOS).toUtf8(); const auto& session = token->usePsk() ? QByteArray() : getContext()->getSslSession(); mReply = Env::getSingleton()->paos(request, paosNamespace, data, token->usePsk(), session); - mConnections += connect(mReply.data(), &QNetworkReply::sslErrors, this, &StateGenericSendReceive::onSslErrors); - mConnections += connect(mReply.data(), &QNetworkReply::encrypted, this, &StateGenericSendReceive::onSslHandshakeDone); - mConnections += connect(mReply.data(), &QNetworkReply::finished, this, &StateGenericSendReceive::onReplyFinished); - mConnections += connect(mReply.data(), &QNetworkReply::preSharedKeyAuthenticationRequired, this, &StateGenericSendReceive::onPreSharedKeyAuthenticationRequired); + *this << connect(mReply.data(), &QNetworkReply::sslErrors, this, &StateGenericSendReceive::onSslErrors); + *this << connect(mReply.data(), &QNetworkReply::encrypted, this, &StateGenericSendReceive::onSslHandshakeDone); + *this << connect(mReply.data(), &QNetworkReply::finished, this, &StateGenericSendReceive::onReplyFinished); + *this << connect(mReply.data(), &QNetworkReply::preSharedKeyAuthenticationRequired, this, &StateGenericSendReceive::onPreSharedKeyAuthenticationRequired); } @@ -269,57 +289,40 @@ void StateGenericSendReceive::onReplyFinished() const auto& channelStatus = NetworkManager::toTrustedChannelStatus(mReply); qCCritical(network) << GlobalStatus(channelStatus); updateStatus(channelStatus); - const FailureCode::FailureInfoMap infoMap { + FailureCode::FailureInfoMap infoMap { {FailureCode::Info::Network_Error, mReply->errorString()}, {FailureCode::Info::State_Name, getStateName()} }; - Q_EMIT fireAbort({FailureCode::Reason::Generic_Send_Receive_Network_Error, infoMap}); - return; - } - - if (statusCode >= 500) - { - qCCritical(network) << GlobalStatus(GlobalStatus::Code::Workflow_TrustedChannel_Error_From_Server); - updateStatus({GlobalStatus::Code::Workflow_TrustedChannel_Error_From_Server, {GlobalStatus::ExternalInformation::LAST_URL, mReply->url().toString()} - }); - const FailureCode::FailureInfoMap infoMap { - {FailureCode::Info::State_Name, getStateName()}, - {FailureCode::Info::Http_Status_Code, QString::number(statusCode)} - }; - Q_EMIT fireAbort({FailureCode::Reason::Generic_Send_Receive_Server_Error, infoMap}); - return; - } - - if (statusCode >= 400) - { - qCCritical(network) << GlobalStatus(GlobalStatus::Code::Workflow_Unexpected_Message_From_EidServer); - updateStatus({GlobalStatus::Code::Workflow_Unexpected_Message_From_EidServer, {GlobalStatus::ExternalInformation::LAST_URL, mReply->url().toString()} - }); - const FailureCode::FailureInfoMap infoMap { - {FailureCode::Info::State_Name, getStateName()}, - {FailureCode::Info::Http_Status_Code, QString::number(statusCode)} - }; - Q_EMIT fireAbort({FailureCode::Reason::Generic_Send_Receive_Client_Error, infoMap}); - return; - } - - QByteArray message = mReply->readAll(); - if (NetworkManager::isLoggingAllowed(mReply)) - { - qCDebug(network).noquote() << "Received raw data:\n" << message; - } - else - { - if (secure().isDebugEnabled()) + if (statusCode > 0) { - qCDebug(secure).noquote() << "Received raw data:\n" << message; + infoMap[FailureCode::Info::Http_Status_Code] = QString::number(statusCode); } - else + FailureCode::Reason reason; + switch (NetworkManager::toNetworkError(mReply)) { - qCDebug(network) << "no-log was requested, skip logging of raw data"; + case NetworkManager::NetworkError::ServiceUnavailable: + reason = FailureCode::Reason::Generic_Send_Receive_Service_Unavailable; + break; + + case NetworkManager::NetworkError::ServerError: + reason = FailureCode::Reason::Generic_Send_Receive_Server_Error; + break; + + case NetworkManager::NetworkError::ClientError: + reason = FailureCode::Reason::Generic_Send_Receive_Client_Error; + break; + + default: + reason = FailureCode::Reason::Generic_Send_Receive_Network_Error; } + + Q_EMIT fireAbort({reason, infoMap}); + return; } + const auto& message = mReply->readAll(); + logRawData(message); + PaosHandler paosHandler(message); const auto receivedType = paosHandler.getDetectedPaosType(); qCDebug(network) << "Received PAOS message of type:" << receivedType; diff --git a/src/workflows/base/states/StateGenericSendReceive.h b/src/workflows/base/states/StateGenericSendReceive.h index 65147ea89..281459ba2 100644 --- a/src/workflows/base/states/StateGenericSendReceive.h +++ b/src/workflows/base/states/StateGenericSendReceive.h @@ -34,7 +34,8 @@ class StateGenericSendReceive const bool mPersonalization; QSharedPointer mReply; - void setReceivedMessage(const QSharedPointer& pMessage); + void logRawData(const QByteArray& pMessage); + void setReceivedMessage(const QSharedPointer& pMessage) const; std::optional checkSslConnectionAndSaveCertificate(const QSslConfiguration& pSslConfiguration); void onSslErrors(const QList& pErrors); void onSslHandshakeDone(); @@ -53,7 +54,7 @@ class StateGenericSendReceive private Q_SLOTS: void onReplyFinished(); - void onPreSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator* pAuthenticator); + void onPreSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator* pAuthenticator) const; public: void onExit(QEvent* pEvent) override; diff --git a/src/workflows/base/states/StateGetTcToken.cpp b/src/workflows/base/states/StateGetTcToken.cpp index e183f1605..5bcf5fe03 100644 --- a/src/workflows/base/states/StateGetTcToken.cpp +++ b/src/workflows/base/states/StateGetTcToken.cpp @@ -90,9 +90,9 @@ void StateGetTcToken::sendRequest(const QUrl& pUrl) qCDebug(network) << "Fetch TCToken URL:" << pUrl; QNetworkRequest request(pUrl); mReply = Env::getSingleton()->get(request); - mConnections += connect(mReply.data(), &QNetworkReply::sslErrors, this, &StateGetTcToken::onSslErrors); - mConnections += connect(mReply.data(), &QNetworkReply::encrypted, this, &StateGetTcToken::onSslHandshakeDone); - mConnections += connect(mReply.data(), &QNetworkReply::finished, this, &StateGetTcToken::onNetworkReply); + *this << connect(mReply.data(), &QNetworkReply::sslErrors, this, &StateGetTcToken::onSslErrors); + *this << connect(mReply.data(), &QNetworkReply::encrypted, this, &StateGetTcToken::onSslHandshakeDone); + *this << connect(mReply.data(), &QNetworkReply::finished, this, &StateGetTcToken::onNetworkReply); } @@ -172,28 +172,54 @@ void StateGetTcToken::onNetworkReply() return; } - const QUrl& redirectUrl = mReply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); - if (!isValidRedirectUrl(redirectUrl)) + if (statusCode == HTTP_STATUS_SEE_OTHER || statusCode == HTTP_STATUS_FOUND || statusCode == HTTP_STATUS_TEMPORARY_REDIRECT) { - Q_EMIT fireAbort(FailureCode::Reason::Get_TcToken_Invalid_Redirect_Url); + const QUrl& redirectUrl = mReply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); + if (!isValidRedirectUrl(redirectUrl)) + { + Q_EMIT fireAbort(FailureCode::Reason::Get_TcToken_Invalid_Redirect_Url); + return; + } + sendRequest(redirectUrl); return; } - if (statusCode != HTTP_STATUS_SEE_OTHER && statusCode != HTTP_STATUS_FOUND && statusCode != HTTP_STATUS_TEMPORARY_REDIRECT) + qCritical() << "Error while connecting to the provider. The server returns an unexpected status code:" << statusCode; + + GlobalStatus::Code errorStatus = GlobalStatus::Code::No_Error; + FailureCode::Reason reason; + if (statusCode >= 500) { - qCritical() << "Error while connecting to the provider. The server returns an unexpected status code:" << statusCode; - const GlobalStatus::ExternalInfoMap infoMap { - {GlobalStatus::ExternalInformation::HTTP_STATUS_CODE, QString::number(statusCode)}, - {GlobalStatus::ExternalInformation::LAST_URL, mReply->url().toString()} - }; - updateStatus({GlobalStatus::Code::Workflow_TrustedChannel_Server_Format_Error, infoMap}); - Q_EMIT fireAbort({FailureCode::Reason::Get_TcToken_Invalid_Server_Reply, - {FailureCode::Info::Http_Status_Code, QString::number(statusCode)} - }); - return; + if (statusCode == 503) + { + errorStatus = GlobalStatus::Code::Workflow_TrustedChannel_ServiceUnavailable; + reason = FailureCode::Reason::Get_TcToken_ServiceUnavailable; + } + else + { + errorStatus = GlobalStatus::Code::Workflow_TrustedChannel_Server_Error; + reason = FailureCode::Reason::Get_TcToken_Server_Error; + } + } + else if (statusCode >= 400) + { + errorStatus = GlobalStatus::Code::Workflow_TrustedChannel_Client_Error; + reason = FailureCode::Reason::Get_TcToken_Client_Error; + } + else + { + errorStatus = GlobalStatus::Code::Workflow_TrustedChannel_Server_Format_Error; + reason = FailureCode::Reason::Get_TcToken_Invalid_Server_Reply; } - sendRequest(redirectUrl); + const GlobalStatus::ExternalInfoMap infoMap { + {GlobalStatus::ExternalInformation::HTTP_STATUS_CODE, QString::number(statusCode)}, + {GlobalStatus::ExternalInformation::LAST_URL, mReply->url().toString()} + }; + updateStatus({errorStatus, infoMap}); + Q_EMIT fireAbort({reason, + {FailureCode::Info::Http_Status_Code, QString::number(statusCode)} + }); } diff --git a/src/workflows/base/states/StateMaintainCardConnection.cpp b/src/workflows/base/states/StateMaintainCardConnection.cpp index 62e2392db..5e3e365eb 100644 --- a/src/workflows/base/states/StateMaintainCardConnection.cpp +++ b/src/workflows/base/states/StateMaintainCardConnection.cpp @@ -12,6 +12,26 @@ Q_DECLARE_LOGGING_CATEGORY(statemachine) using namespace governikus; +void StateMaintainCardConnection::handleWrongPacePassword() +{ + auto context = getContext(); + + qCDebug(statemachine) << "Resetting all PACE passwords."; + context->resetPacePasswords(); + + if (context->getCardConnection()) + { + qCDebug(statemachine) << "Trigger retry counter update."; + Q_EMIT fireForceUpdateRetryCounter(); + } + else + { + qCDebug(statemachine) << "No card connection available."; + Q_EMIT fireNoCardConnection(); + } +} + + StateMaintainCardConnection::StateMaintainCardConnection(const QSharedPointer& pContext) : AbstractState(pContext) , GenericContextContainer(pContext) @@ -36,7 +56,6 @@ void StateMaintainCardConnection::run() { case CardReturnCode::CANCELLATION_BY_USER: case CardReturnCode::PUK_INOPERATIVE: - case CardReturnCode::NO_ACTIVE_PIN_SET: case CardReturnCode::INPUT_TIME_OUT: case CardReturnCode::UNKNOWN: case CardReturnCode::UNDEFINED: @@ -68,19 +87,7 @@ void StateMaintainCardConnection::run() { Q_ASSERT(CardReturnCodeUtil::equalsWrongPacePassword(lastPaceResult)); - qCDebug(statemachine) << "Resetting all PACE passwords."; - context->resetPacePasswords(); - - if (context->getCardConnection()) - { - qCDebug(statemachine) << "Trigger retry counter update."; - Q_EMIT fireForceUpdateRetryCounter(); - } - else - { - qCDebug(statemachine) << "No card connection available."; - Q_EMIT fireNoCardConnection(); - } + handleWrongPacePassword(); return; } diff --git a/src/workflows/base/states/StateMaintainCardConnection.h b/src/workflows/base/states/StateMaintainCardConnection.h index a7a5c7940..6652a294b 100644 --- a/src/workflows/base/states/StateMaintainCardConnection.h +++ b/src/workflows/base/states/StateMaintainCardConnection.h @@ -18,6 +18,9 @@ class StateMaintainCardConnection Q_OBJECT friend class StateBuilder; + private: + void handleWrongPacePassword(); + public: explicit StateMaintainCardConnection(const QSharedPointer& pContext); void run() override; diff --git a/src/workflows/base/states/StateParseTcTokenUrl.cpp b/src/workflows/base/states/StateParseTcTokenUrl.cpp index a01dde0c1..1c31e72c9 100644 --- a/src/workflows/base/states/StateParseTcTokenUrl.cpp +++ b/src/workflows/base/states/StateParseTcTokenUrl.cpp @@ -21,7 +21,7 @@ StateParseTcTokenUrl::StateParseTcTokenUrl(const QSharedPointer void StateParseTcTokenUrl::run() { - QUrlQuery query(getContext()->getActivationContext()->getActivationURL()); + QUrlQuery query(getContext()->getActivationUrl()); QUrl tcTokenURL(query.queryItemValue(QStringLiteral("tcTokenURL"), QUrl::FullyDecoded)); if (tcTokenURL.isValid()) { diff --git a/src/workflows/base/states/StatePreVerification.cpp b/src/workflows/base/states/StatePreVerification.cpp index 5576dfa44..82d1ff576 100644 --- a/src/workflows/base/states/StatePreVerification.cpp +++ b/src/workflows/base/states/StatePreVerification.cpp @@ -99,7 +99,7 @@ void StatePreVerification::run() } -bool StatePreVerification::isValid(const QVector>& pCertificates) +bool StatePreVerification::isValid(const QVector>& pCertificates) const { qDebug() << "Check certificate chain validity on" << mValidationDateTime.toString(Qt::ISODate); @@ -132,7 +132,7 @@ bool StatePreVerification::isValid(const QVector>& pCertificates) +void StatePreVerification::saveCvcaLinkCertificates(const QVector>& pCertificates) const { const auto& contains = [](const QVector>& pStore, const CVCertificate& pCert) { diff --git a/src/workflows/base/states/StatePreVerification.h b/src/workflows/base/states/StatePreVerification.h index da38631d1..677515858 100644 --- a/src/workflows/base/states/StatePreVerification.h +++ b/src/workflows/base/states/StatePreVerification.h @@ -33,8 +33,8 @@ class StatePreVerification explicit StatePreVerification(const QSharedPointer& pContext); void run() override; - bool isValid(const QVector>& pCertificates); - void saveCvcaLinkCertificates(const QVector>& pCertificates); + bool isValid(const QVector>& pCertificates) const; + void saveCvcaLinkCertificates(const QVector>& pCertificates) const; }; } // namespace governikus diff --git a/src/workflows/base/states/StatePreparePace.cpp b/src/workflows/base/states/StatePreparePace.cpp index 085a309e2..a7957c79e 100644 --- a/src/workflows/base/states/StatePreparePace.cpp +++ b/src/workflows/base/states/StatePreparePace.cpp @@ -17,53 +17,11 @@ StatePreparePace::StatePreparePace(const QSharedPointer& pConte } -void StatePreparePace::run() +void StatePreparePace::handleRetryCounter(int pRetryCounter) { const auto& context = getContext(); - context->setEstablishPaceChannelType(PacePasswordId::UNKNOWN); - const auto& cardConnection = context->getCardConnection(); - if (!cardConnection) - { - qCDebug(statemachine) << "Card connection lost."; - Q_EMIT fireNoCardConnection(); - return; - } - const int currentRetryCounter = cardConnection->getReaderInfo().getRetryCounter(); - if (context->isSmartCardUsed()) - { - if (currentRetryCounter == 0) - { - qCDebug(statemachine) << "Smart-eID was invalidated during workflow"; - updateStatus(GlobalStatus::Code::Card_Smart_Invalid); - Q_EMIT fireAbort(FailureCode::Reason::Prepace_Pace_Smart_Eid_Invalidated); - } - - qCDebug(statemachine) << "Smart-eID PIN required"; - context->setEstablishPaceChannelType(PacePasswordId::PACE_PIN); - if (context->getPin().isEmpty()) - { - Q_EMIT fireEnterPacePassword(); - return; - } - - Q_EMIT fireEstablishPaceChannel(); - return; - } - - if (context->isCanAllowedMode()) - { - qCDebug(statemachine) << "CAN allowed required"; - if (!requestPaceCanIfStillRequired()) - { - Q_ASSERT(false && "This state must not be invoked any more if PACE_CAN was successful in CAN allowed mode."); - Q_EMIT fireContinue(); - } - return; - } - - Q_ASSERT(currentRetryCounter != -1); - switch (currentRetryCounter) + switch (pRetryCounter) { case 0: { @@ -95,7 +53,7 @@ void StatePreparePace::run() qCDebug(statemachine) << "PIN allowed"; context->setEstablishPaceChannelType(PacePasswordId::PACE_PIN); - const bool pacePinDone = cardConnection->getPacePinSuccessful(); + const bool pacePinDone = context->getCardConnection()->getPacePinSuccessful(); qCDebug(statemachine) << "PACE_PIN done:" << pacePinDone; if (!pacePinDone) { @@ -109,11 +67,62 @@ void StatePreparePace::run() return; } - Q_UNREACHABLE(); + Q_ASSERT(false && "This state must not be invoked any more if PACE_PIN already was successful."); + Q_EMIT fireContinue(); + return; + } + } +} + + +void StatePreparePace::run() +{ + const auto& context = getContext(); + context->setEstablishPaceChannelType(PacePasswordId::UNKNOWN); + const auto& cardConnection = context->getCardConnection(); + if (!cardConnection) + { + qCDebug(statemachine) << "Card connection lost."; + Q_EMIT fireNoCardConnection(); + return; + } + + const int currentRetryCounter = cardConnection->getReaderInfo().getRetryCounter(); + if (context->isSmartCardUsed()) + { + if (currentRetryCounter == 0) + { + qCDebug(statemachine) << "Smart-eID was invalidated during workflow"; + updateStatus(GlobalStatus::Code::Card_Smart_Invalid); + Q_EMIT fireAbort(FailureCode::Reason::Prepace_Pace_Smart_Eid_Invalidated); + return; } + + qCDebug(statemachine) << "Smart-eID PIN required"; + context->setEstablishPaceChannelType(PacePasswordId::PACE_PIN); + if (context->getPin().isEmpty()) + { + Q_EMIT fireEnterPacePassword(); + return; + } + + Q_EMIT fireEstablishPaceChannel(); + return; } - Q_UNREACHABLE(); + if (context->isCanAllowedMode()) + { + qCDebug(statemachine) << "CAN allowed required"; + if (!requestPaceCanIfStillRequired()) + { + Q_ASSERT(false && "This state must not be invoked any more if PACE_CAN was successful in CAN allowed mode."); + Q_EMIT fireContinue(); + } + return; + } + + Q_ASSERT(currentRetryCounter != -1); + handleRetryCounter(currentRetryCounter); } diff --git a/src/workflows/base/states/StatePreparePace.h b/src/workflows/base/states/StatePreparePace.h index 5e177cf05..c13833e55 100644 --- a/src/workflows/base/states/StatePreparePace.h +++ b/src/workflows/base/states/StatePreparePace.h @@ -25,6 +25,7 @@ class StatePreparePace private: explicit StatePreparePace(const QSharedPointer& pContext); + void handleRetryCounter(int pRetryCounter); void run() override; bool requestPaceCanIfStillRequired(); diff --git a/src/workflows/base/states/StateProcessing.cpp b/src/workflows/base/states/StateProcessing.cpp deleted file mode 100644 index 15cb68ad5..000000000 --- a/src/workflows/base/states/StateProcessing.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright (c) 2014-2023 Governikus GmbH & Co. KG, Germany - */ - -#include "states/StateProcessing.h" - -using namespace governikus; - -StateProcessing::StateProcessing(const QSharedPointer& pContext) - : AbstractState(pContext) - , GenericContextContainer(pContext) -{ -} - - -void StateProcessing::run() -{ - auto activationContext = getContext()->getActivationContext(); - if (activationContext->sendProcessing()) - { - Q_EMIT fireContinue(); - } - else - { - qCritical() << "Cannot send \"Processing\" to caller:" << activationContext->getSendError(); - updateStatus({GlobalStatus::Code::Workflow_Processing_Error, {GlobalStatus::ExternalInformation::ACTIVATION_ERROR, activationContext->getSendError()} - }); - Q_EMIT fireAbort(FailureCode::Reason::Processing_Send_Status_Failed); - } -} diff --git a/src/workflows/base/states/StateProcessing.h b/src/workflows/base/states/StateProcessing.h deleted file mode 100644 index 76a5205bb..000000000 --- a/src/workflows/base/states/StateProcessing.h +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright (c) 2014-2023 Governikus GmbH & Co. KG, Germany - */ - -/*! - * \brief Sends a HTTP-Processing to the browser. - */ - -#pragma once - -#include "AbstractState.h" -#include "GenericContextContainer.h" -#include "context/AuthContext.h" - -namespace governikus -{ - -class StateProcessing - : public AbstractState - , public GenericContextContainer -{ - Q_OBJECT - friend class StateBuilder; - - private: - explicit StateProcessing(const QSharedPointer& pContext); - void run() override; -}; - -} // namespace governikus diff --git a/src/workflows/base/states/StateRedirectBrowser.cpp b/src/workflows/base/states/StateRedirectBrowser.cpp index aeeb20195..9674783d1 100644 --- a/src/workflows/base/states/StateRedirectBrowser.cpp +++ b/src/workflows/base/states/StateRedirectBrowser.cpp @@ -4,12 +4,7 @@ #include "StateRedirectBrowser.h" -#include "UrlUtil.h" - -#include #include -#include - using namespace governikus; @@ -23,92 +18,17 @@ StateRedirectBrowser::StateRedirectBrowser(const QSharedPointer void StateRedirectBrowser::run() { -#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) - // Only skip redirects on mobile platforms because it induces a forced focus change - if (getContext()->isSkipRedirect()) - { - qDebug() << "Skipping redirect, Workflow pending"; - Q_EMIT fireContinue(); - } - else -#endif - if (getContext()->getStatus() == GlobalStatus::Code::Workflow_InternalError_BeforeTcToken) - { - sendErrorPage(HTTP_STATUS_INTERNAL_SERVER_ERROR); - } - else if (getContext()->isTcTokenNotFound()) - { - sendErrorPage(HTTP_STATUS_NOT_FOUND); - } - else if (getContext()->getRefreshUrl().isEmpty()) - { - reportCommunicationError(); - } - else + if (const auto& handler = getContext()->getBrowserHandler(); handler) { - bool redirectSuccess; - if (getContext()->getStartPaosResult().isOk()) + if (const auto& error = handler(getContext()); !error.isEmpty()) { - redirectSuccess = sendRedirect(getContext()->getRefreshUrl(), ECardApiResult(getContext()->getStatus())); + qCritical() << "Cannot send page to caller:" << error; + updateStatus({GlobalStatus::Code::Workflow_Browser_Transmission_Error, {GlobalStatus::ExternalInformation::ACTIVATION_ERROR, error} + }); + Q_EMIT fireAbort(FailureCode::Reason::Browser_Send_Failed); + return; } - else - { - redirectSuccess = sendRedirect(getContext()->getRefreshUrl(), getContext()->getStartPaosResult()); - } - - if (redirectSuccess) - { - Q_EMIT fireContinue(); - } - } -} - - -void StateRedirectBrowser::sendErrorPage(http_status pStatus) -{ - auto activationContext = getContext()->getActivationContext(); - if (activationContext->sendErrorPage(pStatus, getContext()->getStatus())) - { - Q_EMIT fireContinue(); - } - else - { - qCritical() << "Cannot send error page to caller:" << activationContext->getSendError(); - updateStatus({GlobalStatus::Code::Workflow_Error_Page_Transmission_Error, {GlobalStatus::ExternalInformation::ACTIVATION_ERROR, activationContext->getSendError()} - }); - Q_EMIT fireAbort(FailureCode::Reason::Redirect_Browser_Send_Error_Page_Failed); - } -} - - -void StateRedirectBrowser::reportCommunicationError() -{ - qDebug() << "Report communication error"; - if (getContext()->getTcToken() != nullptr && getContext()->getTcToken()->getCommunicationErrorAddress().isValid()) - { - if (sendRedirect(getContext()->getTcToken()->getCommunicationErrorAddress(), ECardApiResult(GlobalStatus::Code::Workflow_Communication_Missing_Redirect_Url))) - { - Q_EMIT fireContinue(); - } - } - else - { - sendErrorPage(HTTP_STATUS_BAD_REQUEST); - } -} - - -bool StateRedirectBrowser::sendRedirect(const QUrl& pRedirectAddress, const ECardApiResult& pResult) -{ - auto activationContext = getContext()->getActivationContext(); - if (!activationContext->sendRedirect(pRedirectAddress, GlobalStatus(pResult))) - { - qCritical() << "Cannot send redirect to caller:" << activationContext->getSendError(); - updateStatus({GlobalStatus::Code::Workflow_Redirect_Transmission_Error, {GlobalStatus::ExternalInformation::ACTIVATION_ERROR, activationContext->getSendError()} - }); - Q_EMIT fireAbort(FailureCode::Reason::Redirect_Browser_Send_Redirect_Failed); - return false; } - return true; + Q_EMIT fireContinue(); } diff --git a/src/workflows/base/states/StateRedirectBrowser.h b/src/workflows/base/states/StateRedirectBrowser.h index c222748f0..58c4590be 100644 --- a/src/workflows/base/states/StateRedirectBrowser.h +++ b/src/workflows/base/states/StateRedirectBrowser.h @@ -9,13 +9,9 @@ #pragma once #include "AbstractState.h" -#include "ECardApiResult.h" #include "GenericContextContainer.h" #include "context/AuthContext.h" -#include - - class test_StateRedirectBrowser; @@ -33,9 +29,6 @@ class StateRedirectBrowser private: explicit StateRedirectBrowser(const QSharedPointer& pContext); - void reportCommunicationError(); - void sendErrorPage(http_status pStatus); - bool sendRedirect(const QUrl& pRedirectAddress, const ECardApiResult& pResult); void run() override; }; diff --git a/src/workflows/base/states/StateSelectReader.cpp b/src/workflows/base/states/StateSelectReader.cpp index d846d36a0..51322b4cb 100644 --- a/src/workflows/base/states/StateSelectReader.cpp +++ b/src/workflows/base/states/StateSelectReader.cpp @@ -26,11 +26,11 @@ StateSelectReader::StateSelectReader(const QSharedPointer& pCon void StateSelectReader::run() { const auto readerManager = Env::getSingleton(); - mConnections += connect(readerManager, &ReaderManager::fireReaderAdded, this, &StateSelectReader::onReaderInfoChanged); - mConnections += connect(readerManager, &ReaderManager::fireReaderRemoved, this, &StateSelectReader::onReaderInfoChanged); - mConnections += connect(readerManager, &ReaderManager::fireCardInserted, this, &StateSelectReader::onReaderInfoChanged); - mConnections += connect(readerManager, &ReaderManager::fireCardRemoved, this, &StateSelectReader::onReaderInfoChanged); - mConnections += connect(readerManager, &ReaderManager::fireStatusChanged, this, &StateSelectReader::onReaderStatusChanged); + *this << connect(readerManager, &ReaderManager::fireReaderAdded, this, &StateSelectReader::onReaderInfoChanged); + *this << connect(readerManager, &ReaderManager::fireReaderRemoved, this, &StateSelectReader::onReaderInfoChanged); + *this << connect(readerManager, &ReaderManager::fireCardInserted, this, &StateSelectReader::onReaderInfoChanged); + *this << connect(readerManager, &ReaderManager::fireCardRemoved, this, &StateSelectReader::onReaderInfoChanged); + *this << connect(readerManager, &ReaderManager::fireStatusChanged, this, &StateSelectReader::onReaderStatusChanged); onReaderInfoChanged(); @@ -103,7 +103,7 @@ void StateSelectReader::onReaderStatusChanged(const ReaderManagerPlugInInfo& pIn return; } - if (!Env::getSingleton()->isScanRunning(ReaderManagerPlugInType::NFC)) + if (!pInfo.isScanRunning()) { Q_EMIT getContext()->fireCancelWorkflow(); } @@ -115,6 +115,8 @@ void StateSelectReader::onReaderStatusChanged(const ReaderManagerPlugInInfo& pIn void StateSelectReader::onEntry(QEvent* pEvent) { + AbstractState::onEntry(pEvent); + const WorkflowContext* const context = getContext().data(); Q_ASSERT(context); @@ -122,7 +124,6 @@ void StateSelectReader::onEntry(QEvent* pEvent) * Note: the plugin types to be used in this state must be already set in the workflow context before this state is entered. * Changing the plugin types in the context, e.g. from {NFC} to {REMOTE}, causes the state to be left with a fireRetry signal. */ - mConnections += connect(context, &WorkflowContext::fireReaderPlugInTypesChanged, this, &StateSelectReader::fireRetry); + *this << connect(context, &WorkflowContext::fireReaderPlugInTypesChanged, this, &StateSelectReader::fireRetry); - AbstractState::onEntry(pEvent); } diff --git a/src/workflows/base/states/StateTransmit.cpp b/src/workflows/base/states/StateTransmit.cpp index 52178782f..0a9cbc88a 100644 --- a/src/workflows/base/states/StateTransmit.cpp +++ b/src/workflows/base/states/StateTransmit.cpp @@ -24,7 +24,7 @@ void StateTransmit::run() auto cardConnection = getContext()->getCardConnection(); Q_ASSERT(cardConnection != nullptr); - mConnections += cardConnection->callTransmitCommand(this, &StateTransmit::onCardCommandDone, transmit->getInputApduInfos()); + *this << cardConnection->callTransmitCommand(this, &StateTransmit::onCardCommandDone, transmit->getInputApduInfos()); } diff --git a/src/workflows/base/states/StateUpdateRetryCounter.cpp b/src/workflows/base/states/StateUpdateRetryCounter.cpp index d6ff7d92e..bd8a05d38 100644 --- a/src/workflows/base/states/StateUpdateRetryCounter.cpp +++ b/src/workflows/base/states/StateUpdateRetryCounter.cpp @@ -31,7 +31,7 @@ void StateUpdateRetryCounter::run() } Q_ASSERT(cardConnection != nullptr); - mConnections += cardConnection->callUpdateRetryCounterCommand(this, &StateUpdateRetryCounter::onUpdateRetryCounterDone); + *this << cardConnection->callUpdateRetryCounterCommand(this, &StateUpdateRetryCounter::onUpdateRetryCounterDone); } @@ -42,7 +42,7 @@ void StateUpdateRetryCounter::onUpdateRetryCounterDone(QSharedPointergetReturnCode(); if (returnCode != CardReturnCode::OK) { - qCCritical(statemachine) << "An error (" << returnCode << ") occurred while communicating with the card reader, cannot determine retry counter, abort state"; + qCCritical(statemachine).nospace() << "An error (" << returnCode << ") occurred while communicating with the card reader, cannot determine retry counter, abort state"; getContext()->resetCardConnection(); Q_EMIT fireNoCardConnection(); return; diff --git a/src/workflows/base/states/StateWriteHistory.cpp b/src/workflows/base/states/StateWriteHistory.cpp deleted file mode 100644 index beb80b8c5..000000000 --- a/src/workflows/base/states/StateWriteHistory.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/** - * Copyright (c) 2014-2023 Governikus GmbH & Co. KG, Germany - */ - -#include "StateWriteHistory.h" - -#include "asn1/AccessRoleAndRight.h" - -#include "AppSettings.h" -#include "LanguageLoader.h" - -using namespace governikus; - - -StateWriteHistory::StateWriteHistory(const QSharedPointer& pContext) - : AbstractState(pContext) - , GenericContextContainer(pContext) -{ -} - - -void StateWriteHistory::run() -{ - if (!Env::getSingleton()->getHistorySettings().isEnabled()) - { - qDebug() << "History disabled"; - Q_EMIT fireContinue(); - return; - } - - const auto& context = getContext(); - if (context->getStatus().isError()) - { - Q_EMIT fireContinue(); - return; - } - - Q_ASSERT(context->getDidAuthenticateEac1()); - if (const auto& eac1 = context->getDidAuthenticateEac1(); eac1&& eac1->getCertificateDescription()) - { - auto certDesc = eac1->getCertificateDescription(); - auto subjectName = certDesc->getSubjectName(); - auto termsOfUsage = certDesc->getTermsOfUsage(); - auto subjectUrl = certDesc->getSubjectUrl(); - - CVCertificateBody body = context->getAccessRightManager()->getTerminalCvc()->getBody(); - const auto locale = LanguageLoader::getInstance().getUsedLocale(); - const auto effectiveDate = locale.toString(body.getCertificateEffectiveDate(), QLocale::ShortFormat); - const auto expirationDate = locale.toString(body.getCertificateExpirationDate(), QLocale::ShortFormat); - //: LABEL ALL_PLATFORMS - QString validity = tr("Validity:\n%1 - %2").arg(effectiveDate, expirationDate); - - QStringList requestedData; - QList rights = context->getAccessRightManager()->getEffectiveAccessRights().values(); - std::sort(rights.begin(), rights.end()); - for (const auto& entry : std::as_const(rights)) - { - const auto data = AccessRoleAndRightsUtil::toTechnicalName(entry); - if (!data.isEmpty()) - { - requestedData += data; - } - } - - if (!subjectName.isNull()) - { - termsOfUsage = termsOfUsage.isEmpty() ? validity : termsOfUsage + QStringLiteral("\n\n") + validity; - HistoryInfo info(subjectName, subjectUrl, certDesc->getPurpose(), QDateTime::currentDateTime(), termsOfUsage, requestedData); - Env::getSingleton()->getHistorySettings().addHistoryInfo(info); - } - } - - Q_EMIT fireContinue(); -} - - -void StateWriteHistory::onEntry(QEvent* pEvent) -{ - const auto& context = getContext(); - if (context->getAction() == Action::AUTH) - { - //: INFO ALL_PLATFORMS Status message after the authentication was completed, the results are prepared for the user and the process will be continued in the browser - const auto text = context->getStatus().isNoError() ? tr("Preparing results") : QString(); // The empty string is set to not confuse users when they get redirected to the provider - context->setProgress(100, text); - } - AbstractState::onEntry(pEvent); -} diff --git a/src/workflows/base/states/StateWriteHistory.h b/src/workflows/base/states/StateWriteHistory.h deleted file mode 100644 index 516a5808b..000000000 --- a/src/workflows/base/states/StateWriteHistory.h +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright (c) 2014-2023 Governikus GmbH & Co. KG, Germany - */ - -/* - * - * \brief Writes the history entry . - */ - -#pragma once - -#include "AbstractState.h" -#include "GenericContextContainer.h" -#include "context/AuthContext.h" - - -class test_StateWriteHistory; - - -namespace governikus -{ - -class StateWriteHistory - : public AbstractState - , public GenericContextContainer -{ - Q_OBJECT - friend class StateBuilder; - friend class ::test_StateWriteHistory; - - private: - explicit StateWriteHistory(const QSharedPointer& pContext); - void run() override; - - public: - void onEntry(QEvent* pEvent) override; -}; - -} // namespace governikus diff --git a/src/workflows/ifd/context/IfdServiceContext.cpp b/src/workflows/ifd/context/IfdServiceContext.cpp index ca3d059a9..2ca9745eb 100644 --- a/src/workflows/ifd/context/IfdServiceContext.cpp +++ b/src/workflows/ifd/context/IfdServiceContext.cpp @@ -14,7 +14,7 @@ bool IfdServiceContext::isPaceRequestingRights() const } -void IfdServiceContext::onMessageHandlerAdded(QSharedPointer pHandler) +void IfdServiceContext::onMessageHandlerAdded(QSharedPointer pHandler) const { connect(pHandler.data(), &ServerMessageHandler::fireCardConnected, this, &IfdServiceContext::fireCardConnected); connect(pHandler.data(), &ServerMessageHandler::fireCardDisconnected, this, &IfdServiceContext::fireCardDisconnected); @@ -266,6 +266,7 @@ void IfdServiceContext::reset() { qDebug() << "Resetting all PACE passwords and further relevant context information."; + setDisplayText(QString()); resetPacePasswords(); resetCardConnection(); resetLastPaceResult(); diff --git a/src/workflows/ifd/context/IfdServiceContext.h b/src/workflows/ifd/context/IfdServiceContext.h index 25430d601..a8a5a5de9 100644 --- a/src/workflows/ifd/context/IfdServiceContext.h +++ b/src/workflows/ifd/context/IfdServiceContext.h @@ -47,7 +47,7 @@ class IfdServiceContext [[nodiscard]] bool isPaceRequestingRights() const; public Q_SLOTS: - void onMessageHandlerAdded(QSharedPointer pHandler); + void onMessageHandlerAdded(QSharedPointer pHandler) const; Q_SIGNALS: void fireCardConnected(const QSharedPointer& pConnection); diff --git a/src/workflows/ifd/controller/IfdServiceController.cpp b/src/workflows/ifd/controller/IfdServiceController.cpp index 9990c83ac..08ace1b4e 100644 --- a/src/workflows/ifd/controller/IfdServiceController.cpp +++ b/src/workflows/ifd/controller/IfdServiceController.cpp @@ -31,10 +31,9 @@ using namespace governikus; IfdServiceController::IfdServiceController(QSharedPointer pContext) : WorkflowController(pContext) { - mStateMachine.setProperty(AbstractState::cFORCE_START_STOP_SCAN, true); + forceStartStopScan(); - auto sStartIfdService = addState(); - mStateMachine.setInitialState(sStartIfdService); + auto sStartIfdService = addInitialState(); auto sProcessIfdMessages = addState(); auto sUpdateRetryCounter = addState(); auto sVerifyRetryCounter = addState(); diff --git a/src/workflows/ifd/states/StateChangePinIfd.cpp b/src/workflows/ifd/states/StateChangePinIfd.cpp index fe532d9ba..904c5f2dc 100644 --- a/src/workflows/ifd/states/StateChangePinIfd.cpp +++ b/src/workflows/ifd/states/StateChangePinIfd.cpp @@ -42,7 +42,7 @@ void StateChangePinIfd::run() const quint8 timeoutSeconds = pinModify.getTimeoutSeconds(); Q_ASSERT(cardConnection); - mConnections += cardConnection->callSetEidPinCommand(this, + *this << cardConnection->callSetEidPinCommand(this, &StateChangePinIfd::onChangePinDone, context->getNewPin().toLatin1(), timeoutSeconds); diff --git a/src/workflows/ifd/states/StateEnterNewPacePinIfd.cpp b/src/workflows/ifd/states/StateEnterNewPacePinIfd.cpp index d5189ede0..69db574d6 100644 --- a/src/workflows/ifd/states/StateEnterNewPacePinIfd.cpp +++ b/src/workflows/ifd/states/StateEnterNewPacePinIfd.cpp @@ -34,14 +34,15 @@ void StateEnterNewPacePinIfd::onCancelChangePin() void StateEnterNewPacePinIfd::onEntry(QEvent* pEvent) { + AbstractState::onEntry(pEvent); + stopNfcScanIfNecessary(); if (getContext() && getContext()->getIfdServer() && getContext()->getIfdServer()->getMessageHandler()) { const auto& handler = getContext()->getIfdServer()->getMessageHandler(); - mConnections += connect(handler.data(), &ServerMessageHandler::destroyed, this, &StateEnterNewPacePinIfd::onCancelChangePin); + *this << connect(handler.data(), &ServerMessageHandler::destroyed, this, &StateEnterNewPacePinIfd::onCancelChangePin); } - mConnections += connect(getContext().data(), &IfdServiceContext::fireCancelPasswordRequest, this, &StateEnterNewPacePinIfd::onCancelChangePin); - AbstractState::onEntry(pEvent); + *this << connect(getContext().data(), &IfdServiceContext::fireCancelPasswordRequest, this, &StateEnterNewPacePinIfd::onCancelChangePin); } diff --git a/src/workflows/ifd/states/StateEnterPacePasswordIfd.cpp b/src/workflows/ifd/states/StateEnterPacePasswordIfd.cpp index 386acaf1e..971ca45e0 100644 --- a/src/workflows/ifd/states/StateEnterPacePasswordIfd.cpp +++ b/src/workflows/ifd/states/StateEnterPacePasswordIfd.cpp @@ -37,14 +37,14 @@ void StateEnterPacePasswordIfd::onCancelEstablishPaceChannel() void StateEnterPacePasswordIfd::onEntry(QEvent* pEvent) { + AbstractState::onEntry(pEvent); stopNfcScanIfNecessary(); if (getContext() && getContext()->getIfdServer() && getContext()->getIfdServer()->getMessageHandler()) { const auto& handler = getContext()->getIfdServer()->getMessageHandler(); - mConnections += connect(handler.data(), &ServerMessageHandler::destroyed, this, &StateEnterPacePasswordIfd::onCancelEstablishPaceChannel); + *this << connect(handler.data(), &ServerMessageHandler::destroyed, this, &StateEnterPacePasswordIfd::onCancelEstablishPaceChannel); } - mConnections += connect(getContext().data(), &IfdServiceContext::fireCancelPasswordRequest, this, &StateEnterPacePasswordIfd::onCancelEstablishPaceChannel); - AbstractState::onEntry(pEvent); + *this << connect(getContext().data(), &IfdServiceContext::fireCancelPasswordRequest, this, &StateEnterPacePasswordIfd::onCancelEstablishPaceChannel); } diff --git a/src/workflows/ifd/states/StateEstablishPaceChannelIfd.cpp b/src/workflows/ifd/states/StateEstablishPaceChannelIfd.cpp index ff7452ecf..eeb34a820 100644 --- a/src/workflows/ifd/states/StateEstablishPaceChannelIfd.cpp +++ b/src/workflows/ifd/states/StateEstablishPaceChannelIfd.cpp @@ -60,7 +60,7 @@ void StateEstablishPaceChannelIfd::run() qDebug() << "Establish connection using" << mPasswordId; Q_ASSERT(!pacePassword.isEmpty() && cardConnection); - mConnections += cardConnection->callEstablishPaceChannelCommand(this, + *this << cardConnection->callEstablishPaceChannelCommand(this, &StateEstablishPaceChannelIfd::onEstablishConnectionDone, mPasswordId, pacePassword, diff --git a/src/workflows/ifd/states/StateProcessIfdMessages.cpp b/src/workflows/ifd/states/StateProcessIfdMessages.cpp index a0b405141..68e721bc0 100644 --- a/src/workflows/ifd/states/StateProcessIfdMessages.cpp +++ b/src/workflows/ifd/states/StateProcessIfdMessages.cpp @@ -29,7 +29,9 @@ void StateProcessIfdMessages::run() const QSharedPointer server = context->getIfdServer(); Q_ASSERT(server); - mConnections += connect(server.data(), &IfdServer::fireMessageHandlerAdded, this, &StateProcessIfdMessages::onMessageHandlerAdded); + *this << connect(server.data(), &IfdServer::fireMessageHandlerAdded, this, &StateProcessIfdMessages::onMessageHandlerAdded); + *this << connect(server.data(), &IfdServer::fireConnectedChanged, this, &StateProcessIfdMessages::onConnectedChanged); + *this << connect(Env::getSingleton(), &ReaderManager::fireReaderPropertiesUpdated, this, &StateProcessIfdMessages::onReaderPropertiesUpdated); const auto messageHandler = server->getMessageHandler(); if (messageHandler) @@ -73,6 +75,38 @@ void StateProcessIfdMessages::onClosed() } +void StateProcessIfdMessages::onConnectedChanged(bool pConnected) const +{ + if (!Env::getSingleton()->isUsedAsSDK()) + { + return; + } + + if (pConnected && !getContext()->getIfdServer()->isPairingConnection()) + { + Env::getSingleton()->startScan(ReaderManagerPlugInType::SMART); + } + else + { + Env::getSingleton()->stopScan(ReaderManagerPlugInType::SMART); + } +} + + +void StateProcessIfdMessages::onReaderPropertiesUpdated(const ReaderInfo& pInfo) const +{ + if (!Env::getSingleton()->isUsedAsSDK()) + { + return; + } + + if (pInfo.isInsertable() && pInfo.getCardInfo().getCardType() == CardType::NONE) + { + Env::getSingleton()->insert(pInfo); + } +} + + void StateProcessIfdMessages::onCardConnected() { mResetContextOnDisconnect = false; @@ -112,7 +146,7 @@ void StateProcessIfdMessages::onModifyPin(const QSharedPointersetDisplayText(QString()); if (mResetContextOnDisconnect) diff --git a/src/workflows/ifd/states/StateProcessIfdMessages.h b/src/workflows/ifd/states/StateProcessIfdMessages.h index 8bd63b714..d1671f0fd 100644 --- a/src/workflows/ifd/states/StateProcessIfdMessages.h +++ b/src/workflows/ifd/states/StateProcessIfdMessages.h @@ -10,6 +10,7 @@ #pragma once +#include "ReaderManager.h" #include "context/IfdServiceContext.h" #include "states/AbstractState.h" #include "states/GenericContextContainer.h" @@ -37,11 +38,13 @@ class StateProcessIfdMessages private Q_SLOTS: void onMessageHandlerAdded(const QSharedPointer& pHandler); void onClosed(); + void onConnectedChanged(bool pConnected) const; + void onReaderPropertiesUpdated(const ReaderInfo& pInfo) const; void onCardConnected(); void onDisplayTextChanged(const QString& pDisplayText) const; void onModifyPin(const QSharedPointer& pMessage, const QSharedPointer& pConnection); void onEstablishPaceChannel(const QSharedPointer& pMessage, const QSharedPointer& pConnection); - void onCardDisconnected(); + void onCardDisconnected() const; protected: void onExit(QEvent* pEvent) override; diff --git a/src/workflows/ifd/states/StateStopIfdService.cpp b/src/workflows/ifd/states/StateStopIfdService.cpp index 01d8eed01..a27165588 100644 --- a/src/workflows/ifd/states/StateStopIfdService.cpp +++ b/src/workflows/ifd/states/StateStopIfdService.cpp @@ -32,9 +32,6 @@ void StateStopIfdService::onExit(QEvent* pEvent) server->setPairing(false); server->stop(); - // Request an asynchronous update of all retry counters - Env::getSingleton()->updateRetryCounters(); - stopNfcScanIfNecessary(); Env::getSingleton()->stopScan(ReaderManagerPlugInType::SMART); diff --git a/src/workflows/personalization/context/PersonalizationContext.cpp b/src/workflows/personalization/context/PersonalizationContext.cpp index 9413f9e8b..f7946d650 100644 --- a/src/workflows/personalization/context/PersonalizationContext.cpp +++ b/src/workflows/personalization/context/PersonalizationContext.cpp @@ -8,33 +8,71 @@ #include "PersonalizationContext.h" +#include "LanguageLoader.h" + +#include + using namespace governikus; PersonalizationContext::PersonalizationContext(const QString& pAppletServiceUrl) - : AuthContext(Action::PERSONALIZATION, QSharedPointer()) + : AuthContext(Action::PERSONALIZATION) , mAllowSmartEidInstallation(true) + , mSmartEidType(SmartEidType::UNKNOWN) + , mChallengeType() + , mFinalizeStatus(0) , mSessionIdentifier() , mChallenge() , mPreparePersonalizationData() , mNewPin() , mAppletServiceUrl(pAppletServiceUrl) + , mLibVersion() , mRemainingAttempts(-1) , mRemainingDays(-1) { } -[[nodiscard]] bool PersonalizationContext::allowSmartEidInstallation() const +SmartEidType PersonalizationContext::getSmartEidType() const +{ + return mSmartEidType; +} + + +const QString& PersonalizationContext::getChallengeType() const +{ + return mChallengeType; +} + + +[[nodiscard]] const QString& PersonalizationContext::getLibVersion() const { - return mAllowSmartEidInstallation; + return mLibVersion; } -void PersonalizationContext::smartEidInstallationSuccessfull() +void PersonalizationContext::setServiceInformation(SmartEidType pType, const QString& pChallengeType, const QString& pLibVersion) { - mAllowSmartEidInstallation = false; + if (mSmartEidType != pType || mChallenge != pChallengeType || mLibVersion != pLibVersion) + { + mSmartEidType = pType; + mChallengeType = pChallengeType; + mLibVersion = pLibVersion; + Q_EMIT fireServiceInformationChanged(); + } +} + + +int PersonalizationContext::getFinalizeStatus() const +{ + return mFinalizeStatus; +} + + +void PersonalizationContext::setFinalizeStatus(int pStatus) +{ + mFinalizeStatus = pStatus; } @@ -46,7 +84,11 @@ const QUuid& PersonalizationContext::getSessionIdentifier() const void PersonalizationContext::setSessionIdentifier(const QUuid& pSessionIdentifier) { - mSessionIdentifier = pSessionIdentifier; + if (mSessionIdentifier != pSessionIdentifier) + { + mSessionIdentifier = pSessionIdentifier; + Q_EMIT fireSessionIdentifierChanged(); + } } @@ -122,9 +164,12 @@ void PersonalizationContext::setRemainingAttempts(int pRemainingAttempts) } -int PersonalizationContext::getRemainingDays() const +QString PersonalizationContext::getRestrictionDate() const { - return mRemainingDays; + QDate restrictionDate = QDate::currentDate(); + restrictionDate = restrictionDate.addDays(qAbs(mRemainingDays)); + const auto& usedLocale = LanguageLoader::getInstance().getUsedLocale(); + return usedLocale.toString(restrictionDate, QStringLiteral("d. MMMM yyyy")); } @@ -153,3 +198,12 @@ QVector PersonalizationContext::getAcceptedEidTypes() const return AuthContext::getAcceptedEidTypes(); } + + +void PersonalizationContext::setProgress(int pProgress, const QString& pMessage, int pInitialValue, int pMaxValue) +{ + Q_ASSERT(pMaxValue > pInitialValue); + + // rewrite progress to combine two progresses from 0-100 in single progress bar. + setProgress(pInitialValue + static_cast((pMaxValue - pInitialValue) / 100.0 * pProgress), pMessage); +} diff --git a/src/workflows/personalization/context/PersonalizationContext.h b/src/workflows/personalization/context/PersonalizationContext.h index 1a40de25a..3c77a869f 100644 --- a/src/workflows/personalization/context/PersonalizationContext.h +++ b/src/workflows/personalization/context/PersonalizationContext.h @@ -9,6 +9,8 @@ #include #include +#include + namespace governikus { @@ -22,12 +24,16 @@ class PersonalizationContext private: bool mAllowSmartEidInstallation; + SmartEidType mSmartEidType; + QString mChallengeType; + int mFinalizeStatus; QUuid mSessionIdentifier; QString mChallenge; QString mPreparePersonalizationData; QString mNewPin; QString mBlockingCode; QString mAppletServiceUrl; + QString mLibVersion; int mRemainingAttempts; int mRemainingDays; @@ -36,12 +42,19 @@ class PersonalizationContext void fireBlockingCodeChanged(); void fireRemainingAttemptsChanged(); void fireRemainingDaysChanged(); + void fireServiceInformationChanged(); + void fireSessionIdentifierChanged(); public: explicit PersonalizationContext(const QString& pAppletServiceUrl); - [[nodiscard]] bool allowSmartEidInstallation() const; - void smartEidInstallationSuccessfull(); + [[nodiscard]] SmartEidType getSmartEidType() const; + [[nodiscard]] const QString& getChallengeType() const; + [[nodiscard]] const QString& getLibVersion() const; + void setServiceInformation(SmartEidType pType, const QString& pChallengeType, const QString& pLibVersion); + + [[nodiscard]] int getFinalizeStatus() const; + void setFinalizeStatus(int pStatus); [[nodiscard]] const QUuid& getSessionIdentifier() const; void setSessionIdentifier(const QUuid& pSessionIdentifier); @@ -61,13 +74,16 @@ class PersonalizationContext [[nodiscard]] int getRemainingAttempts() const; void setRemainingAttempts(int pRemainingAttempts); - [[nodiscard]] int getRemainingDays() const; + [[nodiscard]] QString getRestrictionDate() const; void setRemainingDays(int pRemainingDays); [[nodiscard]] QUrl getAppletServiceUrl(const QString& pArg) const; [[nodiscard]] QVector getAcceptedEidTypes() const override; + using WorkflowContext::setProgress; + void setProgress(int pProgress, const QString& pMessage, int pInitialValue, int pMaxValue = 100); + }; diff --git a/src/workflows/personalization/controller/PersonalizationController.cpp b/src/workflows/personalization/controller/PersonalizationController.cpp index e0f7a53a7..df5e2ea93 100644 --- a/src/workflows/personalization/controller/PersonalizationController.cpp +++ b/src/workflows/personalization/controller/PersonalizationController.cpp @@ -6,11 +6,11 @@ #include "context/PersonalizationContext.h" #include "states/CompositeStatePace.h" +#include "states/CompositeStatePrepareApplet.h" #include "states/CompositeStateTrustedChannel.h" #include "states/FinalState.h" #include "states/StateActivateStoreFeedbackDialog.h" #include "states/StateChangeSmartPin.h" -#include "states/StateCheckApplet.h" #include "states/StateCheckError.h" #include "states/StateCheckRefreshAddress.h" #include "states/StateCheckStatus.h" @@ -20,20 +20,19 @@ #include "states/StateEnterNewPacePin.h" #include "states/StateFinalizePersonalization.h" #include "states/StateGetChallenge.h" +#include "states/StateGetServiceInformation.h" #include "states/StateGetSessionId.h" #include "states/StateInitializePersonalization.h" #include "states/StateInsertCard.h" #include "states/StateLoadSmartTcTokenUrl.h" -#include "states/StatePrepareApplet.h" #include "states/StatePreparePersonalization.h" #include "states/StateSendStartPaosPersonalization.h" #include "states/StateSendTransmitResponsePersonalization.h" #include "states/StateSendWhitelistSurvey.h" #include "states/StateShowResult.h" #include "states/StateStartPaosPersonalization.h" -#include "states/StateStartPaosResponsePersonalization.h" +#include "states/StateStartPaosPersonalizationResponse.h" #include "states/StateTransmitPersonalization.h" -#include "states/StateWriteHistory.h" #include @@ -44,17 +43,14 @@ using namespace governikus; PersonalizationController::PersonalizationController(QSharedPointer pContext) : WorkflowController(pContext) { - auto sCheckStatus = addState(); - mStateMachine.setInitialState(sCheckStatus); - auto sPrepareApplet = addState(); - auto sCheckApplet = addState(); + auto sCheckStatus = addInitialState(); + auto sPrepareApplet = addState(); auto sLoadTcTokenUrl = addState(); - auto sTrustedChannel = new CompositeStateTrustedChannel(pContext); - mStateMachine.addState(sTrustedChannel); + auto sTrustedChannel = addState(); auto sCheckError = addState(); auto sCheckRefreshAddress = addState(); - auto sWriteHistory = addState(); auto sGetSessionId = addState(); + auto sGetServiceInformation = addState(); auto sEnterNewPin = addState(); auto sGetChallenge = addState(); auto sInitializePersonalization = addState(); @@ -63,12 +59,11 @@ PersonalizationController::PersonalizationController(QSharedPointer(); auto sTransmit = addState(); auto sSendTransmitResponse = addState(); - auto sStartPaosResponse = addState(); + auto sStartPaosResponse = addState(); auto sFinalizePersonalization = addState(); auto sClearPacePasswordsNewPin = addState(); auto sInsertCard = addState(); - auto sPace = new CompositeStatePace(pContext); - mStateMachine.addState(sPace); + auto sPace = addState(); auto sChangeSmartPin = addState(); auto sDestroyPace = addState(); auto sClearPacePasswordsAll = addState(); @@ -81,12 +76,8 @@ PersonalizationController::PersonalizationController(QSharedPointeraddTransition(sCheckStatus, &AbstractState::fireContinue, sPrepareApplet); sCheckStatus->addTransition(sCheckStatus, &AbstractState::fireAbort, sFinal); - sPrepareApplet->addTransition(sPrepareApplet, &AbstractState::fireContinue, sCheckApplet); - sPrepareApplet->addTransition(sPrepareApplet, &AbstractState::fireAbort, sFinal); - - sCheckApplet->addTransition(sCheckApplet, &AbstractState::fireContinue, sLoadTcTokenUrl); - sCheckApplet->addTransition(sCheckApplet, &AbstractState::fireAbort, sFinal); - sCheckApplet->addTransition(sCheckApplet, &StateCheckApplet::fireFurtherStepRequired, sPrepareApplet); + sPrepareApplet->addTransition(sPrepareApplet, &CompositeStatePrepareApplet::fireContinue, sLoadTcTokenUrl); + sPrepareApplet->addTransition(sPrepareApplet, &CompositeStatePrepareApplet::fireAbort, sFinal); sLoadTcTokenUrl->addTransition(sLoadTcTokenUrl, &AbstractState::fireContinue, sTrustedChannel); sLoadTcTokenUrl->addTransition(sLoadTcTokenUrl, &AbstractState::fireAbort, sTrustedChannel); @@ -98,15 +89,15 @@ PersonalizationController::PersonalizationController(QSharedPointeraddTransition(sCheckError, &AbstractState::fireAbort, sFinal); sCheckError->addTransition(sCheckError, &StateCheckError::firePropagateAbort, sFinal); - sCheckRefreshAddress->addTransition(sCheckRefreshAddress, &AbstractState::fireContinue, sWriteHistory); + sCheckRefreshAddress->addTransition(sCheckRefreshAddress, &AbstractState::fireContinue, sGetSessionId); sCheckRefreshAddress->addTransition(sCheckRefreshAddress, &AbstractState::fireAbort, sFinal); - sWriteHistory->addTransition(sWriteHistory, &AbstractState::fireContinue, sGetSessionId); - sWriteHistory->addTransition(sWriteHistory, &AbstractState::fireAbort, sFinal); - - sGetSessionId->addTransition(sGetSessionId, &AbstractState::fireContinue, sEnterNewPin); + sGetSessionId->addTransition(sGetSessionId, &AbstractState::fireContinue, sGetServiceInformation); sGetSessionId->addTransition(sGetSessionId, &AbstractState::fireAbort, sFinal); + sGetServiceInformation->addTransition(sGetServiceInformation, &AbstractState::fireContinue, sEnterNewPin); + sGetServiceInformation->addTransition(sGetServiceInformation, &AbstractState::fireAbort, sFinal); + sEnterNewPin->addTransition(sEnterNewPin, &AbstractState::fireContinue, sGetChallenge); sEnterNewPin->addTransition(sEnterNewPin, &AbstractState::fireAbort, sFinal); @@ -145,6 +136,7 @@ PersonalizationController::PersonalizationController(QSharedPointeraddTransition(sInsertCard, &AbstractState::fireContinue, sPace); sInsertCard->addTransition(sInsertCard, &AbstractState::fireAbort, sClearPacePasswordsAll); + sInsertCard->addTransition(sInsertCard, &StateInsertCard::fireSkipPinChange, sClearPacePasswordsAll); sPace->addTransition(sPace, &CompositeStatePace::fireContinue, sChangeSmartPin); sPace->addTransition(sPace, &CompositeStatePace::fireAbort, sClearPacePasswordsAll); @@ -175,5 +167,5 @@ PersonalizationController::PersonalizationController(QSharedPointer PersonalizationController::createWorkflowRequest(const QString& pAppletServiceUrl) { - return WorkflowRequest::createWorkflowRequest(pAppletServiceUrl); + return WorkflowRequest::create(pAppletServiceUrl); } diff --git a/src/workflows/personalization/states/CompositeStatePrepareApplet.cpp b/src/workflows/personalization/states/CompositeStatePrepareApplet.cpp new file mode 100644 index 000000000..5081eb653 --- /dev/null +++ b/src/workflows/personalization/states/CompositeStatePrepareApplet.cpp @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ + +#include "CompositeStatePrepareApplet.h" + +#include "states/StateBuilder.h" +#include "states/StateCheckApplet.h" +#include "states/StateDeleteApplet.h" +#include "states/StateDeletePersonalization.h" +#include "states/StateInstallApplet.h" +#include "states/StateUpdateSupportInfo.h" + + +using namespace governikus; + + +CompositeStatePrepareApplet::CompositeStatePrepareApplet(const QSharedPointer& pContext) + : QState() + , mContext(pContext) +{ + auto sCheckApplet = StateBuilder::createState(mContext); + auto sInstallApplet = StateBuilder::createState(mContext); + auto sDeletePersonalization = StateBuilder::createState(mContext); + auto sDeleteApplet = StateBuilder::createState(mContext); + auto sUpdateSupportInfo = StateBuilder::createState(mContext); + + sCheckApplet->setParent(this); + sInstallApplet->setParent(this); + sDeletePersonalization->setParent(this); + sDeleteApplet->setParent(this); + sUpdateSupportInfo->setParent(this); + + setInitialState(sCheckApplet); + + sCheckApplet->addTransition(sCheckApplet, &StateCheckApplet::fireInstallApplet, sInstallApplet); + sCheckApplet->addTransition(sCheckApplet, &StateCheckApplet::fireDeletePersonalization, sDeletePersonalization); + sCheckApplet->addTransition(sCheckApplet, &StateCheckApplet::fireDeleteApplet, sDeleteApplet); + sCheckApplet->addTransition(sCheckApplet, &StateCheckApplet::fireContinue, sUpdateSupportInfo); + connect(sCheckApplet, &AbstractState::fireAbort, this, &CompositeStatePrepareApplet::fireAbort); + + connect(sInstallApplet, &AbstractState::fireContinue, this, &CompositeStatePrepareApplet::fireContinue); + connect(sInstallApplet, &AbstractState::fireAbort, this, &CompositeStatePrepareApplet::fireAbort); + + sDeletePersonalization->addTransition(sDeletePersonalization, &AbstractState::fireContinue, sCheckApplet); + connect(sDeletePersonalization, &AbstractState::fireAbort, this, &CompositeStatePrepareApplet::fireAbort); + + sUpdateSupportInfo->addTransition(sUpdateSupportInfo, &StateUpdateSupportInfo::fireUpdateAvailable, sDeleteApplet); + connect(sUpdateSupportInfo, &AbstractState::fireContinue, this, &CompositeStatePrepareApplet::fireContinue); + connect(sUpdateSupportInfo, &AbstractState::fireAbort, this, &CompositeStatePrepareApplet::fireAbort); + + sDeleteApplet->addTransition(sDeleteApplet, &AbstractState::fireContinue, sInstallApplet); + connect(sDeleteApplet, &AbstractState::fireAbort, this, &CompositeStatePrepareApplet::fireAbort); +} diff --git a/src/workflows/personalization/states/CompositeStatePrepareApplet.h b/src/workflows/personalization/states/CompositeStatePrepareApplet.h new file mode 100644 index 000000000..1eb90183c --- /dev/null +++ b/src/workflows/personalization/states/CompositeStatePrepareApplet.h @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "FailureCode.h" + +#include +#include + + +namespace governikus +{ + +class WorkflowContext; + +class CompositeStatePrepareApplet + : public QState +{ + Q_OBJECT + + private: + const QSharedPointer mContext; + + public: + explicit CompositeStatePrepareApplet(const QSharedPointer& pContext); + ~CompositeStatePrepareApplet() override = default; + + Q_SIGNALS: + void fireContinue(); + void fireAbort(const FailureCode& pFailure); +}; + +} // namespace governikus diff --git a/src/workflows/personalization/states/StateChangeSmartPin.cpp b/src/workflows/personalization/states/StateChangeSmartPin.cpp index 3eb3b94a3..8a4c2f63f 100644 --- a/src/workflows/personalization/states/StateChangeSmartPin.cpp +++ b/src/workflows/personalization/states/StateChangeSmartPin.cpp @@ -5,25 +5,34 @@ #include "StateChangeSmartPin.h" #include "AppSettings.h" -#include "ReaderManager.h" +#include "ReaderManagerPlugInInfo.h" +#include "VolatileSettings.h" + using namespace governikus; + StateChangeSmartPin::StateChangeSmartPin(const QSharedPointer& pContext) : AbstractState(pContext) , GenericContextContainer(pContext) { + setKeepCardConnectionAlive(); } void StateChangeSmartPin::run() { - const auto& context = getContext(); - if (context->getNewPin().isEmpty()) +#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || !defined(QT_NO_DEBUG) + if (!Env::getSingleton()->isUsedAsSDK()) { - mConnections += connect(context.data(), &PersonalizationContext::fireNewPinChanged, this, &StateChangeSmartPin::callSetEidPin); - return; + const auto& context = getContext(); + if (context->getNewPin().isEmpty()) + { + *this << connect(context.data(), &PersonalizationContext::fireNewPinChanged, this, &StateChangeSmartPin::callSetEidPin); + return; + } } +#endif callSetEidPin(); } @@ -35,7 +44,7 @@ void StateChangeSmartPin::callSetEidPin() Q_ASSERT(cardConnection); qDebug() << "Invoke set Eid PIN command"; - mConnections += cardConnection->callSetEidPinCommand(this, &StateChangeSmartPin::onSetEidPinDone, getContext()->getNewPin().toLatin1()); + *this << cardConnection->callSetEidPinCommand(this, &StateChangeSmartPin::onSetEidPinDone, getContext()->getNewPin().toLatin1()); } diff --git a/src/workflows/personalization/states/StateCheckApplet.cpp b/src/workflows/personalization/states/StateCheckApplet.cpp index 9fb2a04f9..28b338369 100644 --- a/src/workflows/personalization/states/StateCheckApplet.cpp +++ b/src/workflows/personalization/states/StateCheckApplet.cpp @@ -11,6 +11,9 @@ using namespace governikus; +Q_DECLARE_LOGGING_CATEGORY(card_smart) + + StateCheckApplet::StateCheckApplet(const QSharedPointer& pContext) : AbstractState(pContext) , GenericContextContainer(pContext) @@ -20,7 +23,7 @@ StateCheckApplet::StateCheckApplet(const QSharedPointer& pConte void StateCheckApplet::run() { - mConnections += Env::getSingleton()->callExecuteCommand([] { + *this << Env::getSingleton()->callExecuteCommand([] { return QVariant::fromValue(SmartManager::get()->status()); }, this, &StateCheckApplet::onCommandDone); } @@ -28,26 +31,31 @@ void StateCheckApplet::run() void StateCheckApplet::onCommandDone(const QVariant& pResult) { + Q_ASSERT(ReaderManager::isResultType(pResult)); + switch (pResult.value()) { case EidStatus::INTERNAL_ERROR: updateStatus(GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed); - Q_EMIT fireAbort(FailureCode::Reason::Check_Applet_Error); + Q_EMIT fireAbort(FailureCode::Reason::Check_Applet_Internal_Error); + return; + + case EidStatus::NO_PROVISIONING: + Q_EMIT fireInstallApplet(); return; - case EidStatus::UNAVAILABLE: - updateStatus(GlobalStatus::Code::Workflow_Smart_eID_Unavailable); - Q_EMIT fireAbort(FailureCode::Reason::Check_Applet_Unavailable); + case EidStatus::CERT_EXPIRED: + case EidStatus::PERSONALIZED: + Q_EMIT fireDeletePersonalization(); return; case EidStatus::NO_PERSONALIZATION: Q_EMIT fireContinue(); return; - case EidStatus::NO_PROVISIONING: - case EidStatus::APPLET_UNUSABLE: - case EidStatus::PERSONALIZED: - Q_EMIT fireFurtherStepRequired(); + case EidStatus::UNUSABLE: + Q_EMIT fireDeleteApplet(); return; + } } diff --git a/src/workflows/personalization/states/StateCheckApplet.h b/src/workflows/personalization/states/StateCheckApplet.h index 0f99bb986..45aaab78f 100644 --- a/src/workflows/personalization/states/StateCheckApplet.h +++ b/src/workflows/personalization/states/StateCheckApplet.h @@ -3,7 +3,7 @@ */ /*! - * \brief Helper state that installs the Smart-eID applet + * \brief Helper state that checks the current Smart-eID state */ #pragma once @@ -37,7 +37,9 @@ class StateCheckApplet void onCommandDone(const QVariant& pResult); Q_SIGNALS: - void fireFurtherStepRequired(); + void fireInstallApplet(); + void fireDeleteApplet(); + void fireDeletePersonalization(); }; diff --git a/src/workflows/personalization/states/StateDeleteApplet.cpp b/src/workflows/personalization/states/StateDeleteApplet.cpp new file mode 100644 index 000000000..94db27214 --- /dev/null +++ b/src/workflows/personalization/states/StateDeleteApplet.cpp @@ -0,0 +1,129 @@ +/** + * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany + */ + +#include "StateDeleteApplet.h" + +#include "ReaderManager.h" +#include "SmartManager.h" + +#include +#include + + +using namespace governikus; + + +Q_DECLARE_LOGGING_CATEGORY(card_smart) + + +StateDeleteApplet::StateDeleteApplet(const QSharedPointer& pContext) + : AbstractState(pContext) + , GenericContextContainer(pContext) +{ +} + + +void StateDeleteApplet::run() +{ + const auto func = [this]() { + const auto& context = getContext(); + const auto& smartManager = SmartManager::get(); + const int initialProgress = context->getProgressValue(); + const auto& progressHandler = [this, &context, &initialProgress](int pProgress) { + QMetaObject::invokeMethod(this, [pProgress, &context, &initialProgress]{ + //: LABEL ANDROID IOS + context->setProgress(pProgress, tr("Cleaning up old Smart-eID"), initialProgress, 50); + }, Qt::QueuedConnection); + }; + //: LABEL ANDROID IOS + context->setProgress(initialProgress, tr("Cleaning up old Smart-eID")); + return QVariant::fromValue(smartManager->deleteSmart(progressHandler)); + }; + + *this << Env::getSingleton()->callExecuteCommand(func, this, &StateDeleteApplet::onCommandDone); +} + + +void StateDeleteApplet::handleEidServiceResult(const EidServiceResult& pResult) +{ + switch (pResult) + { + case EidServiceResult::SUCCESS: + Q_EMIT fireContinue(); + return; + + case EidServiceResult::UNDEFINED: + case EidServiceResult::INFO: + case EidServiceResult::WARN: + case EidServiceResult::ERROR: + updateStatus(GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed); + Q_EMIT fireAbort(FailureCode::Reason::Delete_Smart_Service_Response_Fail); + return; + + case EidServiceResult::UNSUPPORTED: + updateStatus(GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed); + Q_EMIT fireAbort(FailureCode::Reason::Delete_Smart_Service_Response_Unsupported); + return; + + case EidServiceResult::OVERLOAD_PROTECTION: + updateStatus(GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed); + Q_EMIT fireAbort(FailureCode::Reason::Delete_Smart_Service_Response_Overload); + return; + + case EidServiceResult::UNDER_MAINTENANCE: + updateStatus(GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed); + Q_EMIT fireAbort(FailureCode::Reason::Delete_Smart_Service_Response_Maintenance); + return; + + case EidServiceResult::NFC_NOT_ACTIVATED: + updateStatus(GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed); + Q_EMIT fireAbort(FailureCode::Reason::Delete_Smart_Service_Response_Nfc_Disabled); + return; + + case EidServiceResult::INTEGRITY_CHECK_FAILED: + updateStatus(GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed); + Q_EMIT fireAbort(FailureCode::Reason::Delete_Smart_Service_Response_Integrity_Check_Failed); + return; + + case EidServiceResult::NOT_AUTHENTICATED: + updateStatus(GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed); + Q_EMIT fireAbort(FailureCode::Reason::Delete_Smart_Service_Response_Not_Authenticated); + return; + + case EidServiceResult::NETWORK_CONNECTION_ERROR: + updateStatus(GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed); + Q_EMIT fireAbort(FailureCode::Reason::Delete_Smart_Service_Response_Network_Connection_Error); + return; + } +} + + +void StateDeleteApplet::onCommandDone(const QVariant& pResult) +{ + Q_ASSERT(ReaderManager::isResultType(pResult)); + + if (getContext()->isWorkflowCancelledInState()) + { + Q_EMIT fireAbort(FailureCode::Reason::Delete_Smart_User_Cancelled); + return; + } + + const auto& result = pResult.value(); + if (result == EidServiceResult::SUCCESS) + { + qCDebug(card_smart) << "Successfully deleted Smart-eID"; + } + else + { + qCDebug(card_smart) << "Deletion of Smart-eID failed"; + } + handleEidServiceResult(result); +} + + +void StateDeleteApplet::onUserCancelled() +{ + const QSignalBlocker blocker(this); + AbstractState::onUserCancelled(); +} diff --git a/src/workflows/personalization/states/StateDeleteApplet.h b/src/workflows/personalization/states/StateDeleteApplet.h new file mode 100644 index 000000000..a8e423df8 --- /dev/null +++ b/src/workflows/personalization/states/StateDeleteApplet.h @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany + */ + +/*! + * \brief Helper state that deletes the Smart-eID applet + */ + +#pragma once + +#include "context/PersonalizationContext.h" +#include "states/AbstractState.h" +#include "states/GenericContextContainer.h" + +#include + + +class test_StateDeleteApplet; + + +namespace governikus +{ + +class StateDeleteApplet + : public AbstractState + , public GenericContextContainer +{ + Q_OBJECT + friend class StateBuilder; + friend class ::test_StateDeleteApplet; + + private: + explicit StateDeleteApplet(const QSharedPointer& pContext); + void run() override; + void handleEidServiceResult(const EidServiceResult& pResult); + + private Q_SLOTS: + void onCommandDone(const QVariant& pResult); + + public Q_SLOTS: + void onUserCancelled() override; + +}; + +} // namespace governikus diff --git a/src/workflows/personalization/states/StateDeletePersonalization.cpp b/src/workflows/personalization/states/StateDeletePersonalization.cpp new file mode 100644 index 000000000..f43aed230 --- /dev/null +++ b/src/workflows/personalization/states/StateDeletePersonalization.cpp @@ -0,0 +1,71 @@ +/** + * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany + */ + +#include "StateDeletePersonalization.h" + +#include "ReaderManager.h" +#include "SmartManager.h" + +#include +#include + + +using namespace governikus; + + +Q_DECLARE_LOGGING_CATEGORY(card_smart) + + +StateDeletePersonalization::StateDeletePersonalization(const QSharedPointer& pContext) + : AbstractState(pContext) + , GenericContextContainer(pContext) +{ +} + + +void StateDeletePersonalization::run() +{ + const auto func = []() -> QVariant { + const auto& smartManager = SmartManager::get(); + if (!smartManager->deletePersonalization()) + { + qCDebug(card_smart) << "Deletion of Smart-eID personalization failed"; + return false; + } + + qCDebug(card_smart) << "Successfully deleted the Smart-eID personalization"; + return true; + }; + + *this << Env::getSingleton()->callExecuteCommand(func, this, &StateDeletePersonalization::onCommandDone); +} + + +void StateDeletePersonalization::onCommandDone(const QVariant& pResult) +{ + Q_ASSERT(ReaderManager::isResultType(pResult)); + + if (getContext()->isWorkflowCancelledInState()) + { + Q_EMIT fireAbort(FailureCode::Reason::Delete_Personalization_User_Cancelled); + return; + } + + if (pResult.value()) + { + Q_EMIT fireContinue(); + return; + } + + updateStatus(GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed); + Q_EMIT fireAbort(FailureCode::Reason::Delete_Personalization_Failed); + +} + + +void StateDeletePersonalization::onUserCancelled() +{ + const QSignalBlocker blocker(this); + AbstractState::onUserCancelled(); +} diff --git a/src/workflows/personalization/states/StateDeletePersonalization.h b/src/workflows/personalization/states/StateDeletePersonalization.h new file mode 100644 index 000000000..4670f345b --- /dev/null +++ b/src/workflows/personalization/states/StateDeletePersonalization.h @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany + */ + +/*! + * \brief Helper state that deletes the Smart-eID personalization + */ + +#pragma once + +#include "context/PersonalizationContext.h" +#include "states/AbstractState.h" +#include "states/GenericContextContainer.h" + +#include + + +class test_StateDeletePersonalization; + + +namespace governikus +{ + +class StateDeletePersonalization + : public AbstractState + , public GenericContextContainer +{ + Q_OBJECT + friend class StateBuilder; + friend class ::test_StateDeletePersonalization; + + private: + explicit StateDeletePersonalization(const QSharedPointer& pContext); + void run() override; + + private Q_SLOTS: + void onCommandDone(const QVariant& pResult); + + public Q_SLOTS: + void onUserCancelled() override; + +}; + +} // namespace governikus diff --git a/src/workflows/personalization/states/StateFinalizePersonalization.cpp b/src/workflows/personalization/states/StateFinalizePersonalization.cpp index e6daf9ee7..78a081af4 100644 --- a/src/workflows/personalization/states/StateFinalizePersonalization.cpp +++ b/src/workflows/personalization/states/StateFinalizePersonalization.cpp @@ -31,13 +31,14 @@ void StateFinalizePersonalization::run() //: LABEL ANDROID IOS context->setProgress(90, tr("Finalizing the Smart-eID")); - const auto func = [] { - const auto& result = QVariant::fromValue(SmartManager::get()->finalizePersonalization()); + const int finalizeStatus = context->getFinalizeStatus(); + const auto func = [finalizeStatus] { + const auto& result = QVariant::fromValue(SmartManager::get()->finalizePersonalization(finalizeStatus)); SmartManager::releaseConnection(); return result; }; - mConnections += Env::getSingleton()->callExecuteCommand(func, this, &StateFinalizePersonalization::onCommandDone); + *this << Env::getSingleton()->callExecuteCommand(func, this, &StateFinalizePersonalization::onCommandDone); } diff --git a/src/workflows/personalization/states/StateGetChallenge.cpp b/src/workflows/personalization/states/StateGetChallenge.cpp index 0cd10813e..ab4664073 100644 --- a/src/workflows/personalization/states/StateGetChallenge.cpp +++ b/src/workflows/personalization/states/StateGetChallenge.cpp @@ -38,7 +38,7 @@ QByteArray StateGetChallenge::getPayload() const QJsonObject body; body[QLatin1String("sessionID")] = context->getSessionIdentifier().toString(QUuid::WithoutBraces); - body[QLatin1String("osType")] = getOsType(); + body[QLatin1String("challengeType")] = context->getChallengeType(); return QJsonDocument(body).toJson(QJsonDocument::Compact); } @@ -53,24 +53,6 @@ void StateGetChallenge::setProgress() const } -QString StateGetChallenge::getOsType() const -{ -#if defined(Q_OS_IOS) - return QStringLiteral("iOS"); - -#elif defined(Q_OS_ANDROID) - return QStringLiteral("Android"); - -#else - static const char* SMART_EID_MOCK_OS_TYPE = "AUSWEISAPP2_SMART_EID_MOCK_OS_TYPE"; - const auto os = qEnvironmentVariable(SMART_EID_MOCK_OS_TYPE, QStringLiteral("Unknown")); - qDebug() << "Using" << SMART_EID_MOCK_OS_TYPE << ":" << os; - return os; - -#endif -} - - bool StateGetChallenge::parseChallenge(const QByteArray& pData) { QJsonParseError jsonError {}; diff --git a/src/workflows/personalization/states/StateGetChallenge.h b/src/workflows/personalization/states/StateGetChallenge.h index 8f2e56b1f..dbd2c3fa8 100644 --- a/src/workflows/personalization/states/StateGetChallenge.h +++ b/src/workflows/personalization/states/StateGetChallenge.h @@ -31,7 +31,6 @@ class StateGetChallenge [[nodiscard]] QByteArray getPayload() const override; void setProgress() const override; - [[nodiscard]] QString getOsType() const; [[nodiscard]] bool parseChallenge(const QByteArray& pData); void handleNetworkReply(const QByteArray& pContent) override; diff --git a/src/workflows/personalization/states/StateGetServiceInformation.cpp b/src/workflows/personalization/states/StateGetServiceInformation.cpp new file mode 100644 index 000000000..da65c4031 --- /dev/null +++ b/src/workflows/personalization/states/StateGetServiceInformation.cpp @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2022-2023 Governikus GmbH & Co. KG, Germany + */ + +#include "StateGetServiceInformation.h" + +#include "ReaderManager.h" +#include "SmartManager.h" + +#include + + +using namespace governikus; + + +Q_DECLARE_LOGGING_CATEGORY(card_smart) + + +StateGetServiceInformation::StateGetServiceInformation(const QSharedPointer& pContext) + : AbstractState(pContext) + , GenericContextContainer(pContext) +{ +} + + +void StateGetServiceInformation::run() +{ + *this << Env::getSingleton()->callExecuteCommand([] { + return QVariant::fromValue(SmartManager::get()->serviceInformation()); + }, this, &StateGetServiceInformation::onCommandDone); +} + + +void StateGetServiceInformation::onCommandDone(const QVariant& pResult) +{ + const auto [result, smartEidType, challengeType, libVersion] = pResult.value(); + + if (result == EidServiceResult::SUCCESS) + { + getContext()->setServiceInformation(smartEidType, QString::fromStdString(challengeType), QString::fromStdString(libVersion)); + Q_EMIT fireContinue(); + return; + } + + qCWarning(card_smart) << "ServiceInformation query failed"; + updateStatus(GlobalStatus::Code::Workflow_Smart_eID_ServiceInformation_Query_Failed); + Q_EMIT fireAbort(FailureCode::Reason::Smart_ServiceInformation_Query_Failed); +} diff --git a/src/workflows/personalization/states/StateGetServiceInformation.h b/src/workflows/personalization/states/StateGetServiceInformation.h new file mode 100644 index 000000000..77e356a9d --- /dev/null +++ b/src/workflows/personalization/states/StateGetServiceInformation.h @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2022-2023 Governikus GmbH & Co. KG, Germany + */ + +/*! + * \brief State that initializes the personalization of the Smart-eID applet + */ + +#pragma once + +#include "context/PersonalizationContext.h" +#include "states/AbstractState.h" +#include "states/GenericContextContainer.h" + +#include + +class test_StateGetServiceInformation; + +namespace governikus +{ + +class StateGetServiceInformation + : public AbstractState + , public GenericContextContainer +{ + Q_OBJECT + friend class StateBuilder; + friend class ::test_StateGetServiceInformation; + + private: + explicit StateGetServiceInformation(const QSharedPointer& pContext); + void run() override; + + private Q_SLOTS: + void onCommandDone(const QVariant& pResult); +}; + +} // namespace governikus diff --git a/src/workflows/personalization/states/StateGetSessionId.cpp b/src/workflows/personalization/states/StateGetSessionId.cpp index 296911479..183200ae5 100644 --- a/src/workflows/personalization/states/StateGetSessionId.cpp +++ b/src/workflows/personalization/states/StateGetSessionId.cpp @@ -4,7 +4,6 @@ #include "StateGetSessionId.h" -#include "LogHandler.h" #include "context/PersonalizationContext.h" #include @@ -37,7 +36,7 @@ void StateGetSessionId::setProgress() const } -bool StateGetSessionId::parseSessionId(const QByteArray& pData) +bool StateGetSessionId::parseResponse(const QByteArray& pData) const { QJsonParseError jsonError {}; const auto& json = QJsonDocument::fromJson(pData, &jsonError); @@ -47,16 +46,15 @@ bool StateGetSessionId::parseSessionId(const QByteArray& pData) return false; } - const auto& context = qobject_cast(getContext()); - Q_ASSERT(context); - - const auto obj = json.object(); - const auto sessionId = QUuid(obj.value(QLatin1String("sessionID")).toString()); + const auto sessionId = QUuid(json.object().value(QLatin1String("sessionID")).toString()); if (sessionId.isNull()) { + qDebug() << "No valid sessionID to prepare personalization"; return false; } + const auto& context = qobject_cast(getContext()); + Q_ASSERT(context); context->setSessionIdentifier(sessionId); return true; } @@ -64,13 +62,12 @@ bool StateGetSessionId::parseSessionId(const QByteArray& pData) void StateGetSessionId::handleNetworkReply(const QByteArray& pContent) { - if (parseSessionId(pContent)) + if (parseResponse(pContent)) { Q_EMIT fireContinue(); return; } - qDebug() << "No valid sessionID to prepare personalization"; - updateStatus(GlobalStatus::Code::Workflow_Server_Incomplete_Information_Provided); + updateStatus(GlobalStatus::Code::Workflow_Smart_eID_Authentication_Failed); Q_EMIT fireAbort(FailureCode::Reason::Get_Session_Id_Invalid); } diff --git a/src/workflows/personalization/states/StateGetSessionId.h b/src/workflows/personalization/states/StateGetSessionId.h index 4aff35598..65315e009 100644 --- a/src/workflows/personalization/states/StateGetSessionId.h +++ b/src/workflows/personalization/states/StateGetSessionId.h @@ -30,7 +30,7 @@ class StateGetSessionId QUrl getRequestUrl() const override; void setProgress() const override; - [[nodiscard]] bool parseSessionId(const QByteArray& pData); + [[nodiscard]] bool parseResponse(const QByteArray& pData) const; void handleNetworkReply(const QByteArray& pContent) override; }; diff --git a/src/workflows/personalization/states/StateInitializePersonalization.cpp b/src/workflows/personalization/states/StateInitializePersonalization.cpp index dbf002c04..a18bd3fda 100644 --- a/src/workflows/personalization/states/StateInitializePersonalization.cpp +++ b/src/workflows/personalization/states/StateInitializePersonalization.cpp @@ -31,20 +31,21 @@ void StateInitializePersonalization::run() //: LABEL ANDROID IOS context->setProgress(20, tr("Personalizing the Smart-eID")); - const auto& pin = context->getPin(); + const auto& smartEidType = context->getSmartEidType(); + const auto& pin = smartEidType == SmartEidType::NON_APPLET ? context->getNewPin() : QString(); const auto& challenge = context->getChallenge(); const auto func = [pin, challenge] { const auto& smartManager = SmartManager::get(true); const auto& result = smartManager->initializePersonalization(challenge, pin); if (result.mResult != EidServiceResult::SUCCESS) { - smartManager->releaseConnection(); + SmartManager::releaseConnection(); } return QVariant::fromValue(result); }; - mConnections += Env::getSingleton()->callExecuteCommand(func, this, &StateInitializePersonalization::onCommandDone); + *this << Env::getSingleton()->callExecuteCommand(func, this, &StateInitializePersonalization::onCommandDone); } diff --git a/src/workflows/personalization/states/StateInsertCard.cpp b/src/workflows/personalization/states/StateInsertCard.cpp index 7054ab2ea..a80e243c4 100644 --- a/src/workflows/personalization/states/StateInsertCard.cpp +++ b/src/workflows/personalization/states/StateInsertCard.cpp @@ -7,9 +7,12 @@ #include "Env.h" #include "ReaderFilter.h" #include "ReaderManager.h" +#include "VolatileSettings.h" + Q_DECLARE_LOGGING_CATEGORY(statemachine) + using namespace governikus; @@ -22,28 +25,36 @@ StateInsertCard::StateInsertCard(const QSharedPointer& pContext void StateInsertCard::run() { - auto* readerManager = Env::getSingleton(); - - const auto& readerInfos = readerManager->getReaderInfos(ReaderFilter({ReaderManagerPlugInType::SMART})); - if (readerInfos.isEmpty()) - { - qCWarning(statemachine) << "No Smart reader present"; - updateStatus(GlobalStatus::Code::Workflow_Smart_eID_Personalization_Failed); - Q_EMIT fireAbort(FailureCode::Reason::Insert_Card_No_SmartReader); - return; - } - if (readerInfos.size() > 1) +#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || !defined(QT_NO_DEBUG) + if (!Env::getSingleton()->isUsedAsSDK()) { - qCWarning(statemachine) << "Multiple Smart readers present"; - updateStatus(GlobalStatus::Code::Workflow_Smart_eID_Personalization_Failed); - Q_EMIT fireAbort(FailureCode::Reason::Insert_Card_Multiple_SmartReader); + auto* readerManager = Env::getSingleton(); + + const auto& readerInfos = readerManager->getReaderInfos(ReaderFilter({ReaderManagerPlugInType::SMART})); + if (readerInfos.isEmpty()) + { + qCWarning(statemachine) << "No Smart reader present"; + updateStatus(GlobalStatus::Code::Workflow_Smart_eID_Personalization_Failed); + Q_EMIT fireAbort(FailureCode::Reason::Insert_Card_No_SmartReader); + return; + } + if (readerInfos.size() > 1) + { + qCWarning(statemachine) << "Multiple Smart readers present"; + updateStatus(GlobalStatus::Code::Workflow_Smart_eID_Personalization_Failed); + Q_EMIT fireAbort(FailureCode::Reason::Insert_Card_Multiple_SmartReader); + return; + } + + getContext()->setReaderPlugInTypes({ReaderManagerPlugInType::SMART}); + *this << connect(readerManager, &ReaderManager::fireCardInfoChanged, this, &StateInsertCard::onCardInfoChanged); + *this << connect(readerManager, &ReaderManager::fireStatusChanged, this, &StateInsertCard::onStatusChanged); + readerManager->startScan(ReaderManagerPlugInType::SMART); return; } +#endif - getContext()->setReaderPlugInTypes({ReaderManagerPlugInType::SMART}); - mConnections += connect(readerManager, &ReaderManager::fireCardInfoChanged, this, &StateInsertCard::onCardInfoChanged); - mConnections += connect(readerManager, &ReaderManager::fireStatusChanged, this, &StateInsertCard::onStatusChanged); - readerManager->startScan(ReaderManagerPlugInType::SMART); + Q_EMIT fireContinue(); } @@ -68,7 +79,7 @@ void StateInsertCard::onCardInfoChanged(const ReaderInfo& pInfo) case MobileEidType::HW_KEYSTORE: qCDebug(statemachine) << "Skipping PIN change because of eID-Type:" << type; - Q_EMIT fireAbort(FailureCode::Reason::Insert_Card_HW_Keystore); + Q_EMIT fireSkipPinChange(); return; } diff --git a/src/workflows/personalization/states/StateInsertCard.h b/src/workflows/personalization/states/StateInsertCard.h index 3d2960bd6..bb9f86bab 100644 --- a/src/workflows/personalization/states/StateInsertCard.h +++ b/src/workflows/personalization/states/StateInsertCard.h @@ -29,6 +29,9 @@ class StateInsertCard private Q_SLOTS: void onCardInfoChanged(const ReaderInfo& pInfo); void onStatusChanged(const ReaderManagerPlugInInfo& pInfo); + + Q_SIGNALS: + void fireSkipPinChange(); }; } // namespace governikus diff --git a/src/workflows/personalization/states/StateInstallApplet.cpp b/src/workflows/personalization/states/StateInstallApplet.cpp new file mode 100644 index 000000000..50c965e2c --- /dev/null +++ b/src/workflows/personalization/states/StateInstallApplet.cpp @@ -0,0 +1,130 @@ +/** + * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany + */ + +#include "StateInstallApplet.h" + +#include "ReaderManager.h" +#include "SmartManager.h" + +#include +#include + + +using namespace governikus; + + +Q_DECLARE_LOGGING_CATEGORY(card_smart) + + +StateInstallApplet::StateInstallApplet(const QSharedPointer& pContext) + : AbstractState(pContext) + , GenericContextContainer(pContext) +{ +} + + +void StateInstallApplet::run() +{ + const auto func = [this]() { + const auto& context = getContext(); + const auto& smartManager = SmartManager::get(); + + const int initialProgress = context->getProgressValue(); + const auto& progressHandler = [this, &context, &initialProgress](int pProgress) { + QMetaObject::invokeMethod(this, [pProgress, &context, &initialProgress]{ + //: LABEL ANDROID IOS + context->setProgress(pProgress, tr("Installing Smart-eID"), initialProgress); + }, Qt::QueuedConnection); + }; + //: LABEL ANDROID IOS + context->setProgress(initialProgress, tr("Installing Smart-eID")); + return QVariant::fromValue(smartManager->installSmart(progressHandler)); + }; + + *this << Env::getSingleton()->callExecuteCommand(func, this, &StateInstallApplet::onCommandDone); +} + + +void StateInstallApplet::handleEidServiceResult(const EidServiceResult& pResult) +{ + switch (pResult) + { + case EidServiceResult::SUCCESS: + Q_EMIT fireContinue(); + return; + + case EidServiceResult::UNDEFINED: + case EidServiceResult::INFO: + case EidServiceResult::WARN: + case EidServiceResult::ERROR: + updateStatus(GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed); + Q_EMIT fireAbort(FailureCode::Reason::Install_Smart_Service_Response_Fail); + return; + + case EidServiceResult::UNSUPPORTED: + updateStatus(GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed); + Q_EMIT fireAbort(FailureCode::Reason::Install_Smart_Service_Response_Unsupported); + return; + + case EidServiceResult::OVERLOAD_PROTECTION: + updateStatus(GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed); + Q_EMIT fireAbort(FailureCode::Reason::Install_Smart_Service_Response_Overload); + return; + + case EidServiceResult::UNDER_MAINTENANCE: + updateStatus(GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed); + Q_EMIT fireAbort(FailureCode::Reason::Install_Smart_Service_Response_Maintenance); + return; + + case EidServiceResult::NFC_NOT_ACTIVATED: + updateStatus(GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed); + Q_EMIT fireAbort(FailureCode::Reason::Install_Smart_Service_Response_Nfc_Disabled); + return; + + case EidServiceResult::INTEGRITY_CHECK_FAILED: + updateStatus(GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed); + Q_EMIT fireAbort(FailureCode::Reason::Install_Smart_Service_Response_Integrity_Check_Failed); + return; + + case EidServiceResult::NOT_AUTHENTICATED: + updateStatus(GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed); + Q_EMIT fireAbort(FailureCode::Reason::Install_Smart_Service_Response_Not_Authenticated); + return; + + case EidServiceResult::NETWORK_CONNECTION_ERROR: + updateStatus(GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed); + Q_EMIT fireAbort(FailureCode::Reason::Install_Smart_Service_Response_Network_Connection_Error); + return; + } +} + + +void StateInstallApplet::onCommandDone(const QVariant& pResult) +{ + Q_ASSERT(ReaderManager::isResultType(pResult)); + + if (getContext()->isWorkflowCancelledInState()) + { + Q_EMIT fireAbort(FailureCode::Reason::Install_Smart_User_Cancelled); + return; + } + + const auto& result = pResult.value(); + if (result == EidServiceResult::SUCCESS) + { + qCDebug(card_smart) << "Successfully installed Smart-eID"; + } + else + { + qCDebug(card_smart) << "Installation of Smart-eID failed"; + } + handleEidServiceResult(result); +} + + +void StateInstallApplet::onUserCancelled() +{ + const QSignalBlocker blocker(this); + AbstractState::onUserCancelled(); +} diff --git a/src/workflows/personalization/states/StatePrepareApplet.h b/src/workflows/personalization/states/StateInstallApplet.h similarity index 70% rename from src/workflows/personalization/states/StatePrepareApplet.h rename to src/workflows/personalization/states/StateInstallApplet.h index 0ccf46b9a..c3729dff8 100644 --- a/src/workflows/personalization/states/StatePrepareApplet.h +++ b/src/workflows/personalization/states/StateInstallApplet.h @@ -15,24 +15,24 @@ #include -class test_StatePrepareApplet; +class test_StateInstallApplet; namespace governikus { -class StatePrepareApplet +class StateInstallApplet : public AbstractState , public GenericContextContainer { Q_OBJECT friend class StateBuilder; - friend class ::test_StatePrepareApplet; + friend class ::test_StateInstallApplet; private: - explicit StatePrepareApplet(const QSharedPointer& pContext); + explicit StateInstallApplet(const QSharedPointer& pContext); void run() override; - void setProgress(int pProgress, const QString& pMessage, int pInitialValue = 0, int pMaxValue = 100) const; + void handleEidServiceResult(const EidServiceResult& pResult); private Q_SLOTS: void onCommandDone(const QVariant& pResult); diff --git a/src/workflows/personalization/states/StateLoadSmartTcTokenUrl.cpp b/src/workflows/personalization/states/StateLoadSmartTcTokenUrl.cpp index beefbb09b..fa05cb891 100644 --- a/src/workflows/personalization/states/StateLoadSmartTcTokenUrl.cpp +++ b/src/workflows/personalization/states/StateLoadSmartTcTokenUrl.cpp @@ -4,11 +4,10 @@ #include "StateLoadSmartTcTokenUrl.h" -#include "AppSettings.h" -#include "SecureStorage.h" using namespace governikus; + StateLoadSmartTcTokenUrl::StateLoadSmartTcTokenUrl(const QSharedPointer& pContext) : AbstractState(pContext) , GenericContextContainer(pContext) @@ -18,10 +17,7 @@ StateLoadSmartTcTokenUrl::StateLoadSmartTcTokenUrl(const QSharedPointer(getContext()); - Q_ASSERT(context); - - const QUrl url = context->getAppletServiceUrl(QStringLiteral("tcToken")); + const QUrl url = getContext()->getAppletServiceUrl(QStringLiteral("tcToken")); qDebug() << "Loaded tcTokenUrl for Smart-eID personalization:" << url; getContext()->setTcTokenUrl(url); diff --git a/src/workflows/personalization/states/StatePrepareApplet.cpp b/src/workflows/personalization/states/StatePrepareApplet.cpp deleted file mode 100644 index ff80d4ff0..000000000 --- a/src/workflows/personalization/states/StatePrepareApplet.cpp +++ /dev/null @@ -1,168 +0,0 @@ -/** - * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany - */ - -#include "StatePrepareApplet.h" - -#include "ReaderManager.h" -#include "SmartManager.h" - -#include -#include - - -using namespace governikus; - - -Q_DECLARE_LOGGING_CATEGORY(card_smart) - - -StatePrepareApplet::StatePrepareApplet(const QSharedPointer& pContext) - : AbstractState(pContext) - , GenericContextContainer(pContext) -{ -} - - -void StatePrepareApplet::run() -{ - const auto func = [this] { - const auto& context = getContext(); - const auto& smartManager = SmartManager::get(); - //: LABEL ANDROID IOS - setProgress(context->getProgressValue(), tr("Checking Smart-eID status")); - - switch (smartManager->status()) - { - case EidStatus::INTERNAL_ERROR: - qCDebug(card_smart) << "getSmartEidStatus() failed"; - return QVariant::fromValue(FailureCode::Reason::Prepare_Applet_Status_Call_Failed); - - case EidStatus::NO_PROVISIONING: - { - if (!context->allowSmartEidInstallation()) - { - qCDebug(card_smart) << "Loop detected: A previous Smart-eID installation seems to be broken."; - return QVariant::fromValue(FailureCode::Reason::Prepare_Applet_Installation_Loop); - } - - const int initialProgress = context->getProgressValue(); - const auto& progressHandler = [this, &initialProgress](int pProgress) { - QMetaObject::invokeMethod(this, [this, pProgress, &initialProgress]{ - //: LABEL ANDROID IOS - setProgress(pProgress, tr("Installing Smart-eID"), initialProgress); - }, Qt::QueuedConnection); - }; - //: LABEL ANDROID IOS - setProgress(initialProgress, tr("Installing Smart-eID")); - if (smartManager->installSmart(progressHandler)) - { - context->smartEidInstallationSuccessfull(); - qCDebug(card_smart) << "Successfully installed Smart-eID"; - return QVariant(); - } - - qCDebug(card_smart) << "Installation of Smart-eID failed"; - return QVariant::fromValue(FailureCode::Reason::Prepare_Applet_Installation_Failed); - } - - case EidStatus::UNAVAILABLE: - qCDebug(card_smart) << "Smart-eID is not available on this device"; - return QVariant::fromValue(FailureCode::Reason::Prepare_Applet_Unavailable); - - case EidStatus::PERSONALIZED: - if (!smartManager->deletePersonalization()) - { - qCDebug(card_smart) << "Deletion of Smart-eID personalization failed"; - return QVariant::fromValue(FailureCode::Reason::Prepare_Applet_Delete_Personalization_Failed); - } - - qCDebug(card_smart) << "Successfully deleted the Smart-eID personalization"; - Q_FALLTHROUGH(); - - case EidStatus::NO_PERSONALIZATION: - switch (smartManager->updateInfo()) - { - case EidUpdateInfo::INTERNAL_ERROR: - qCDebug(card_smart) << "updateInfo() failed"; - return QVariant::fromValue(FailureCode::Reason::Prepare_Applet_UpdateInfo_Call_Failed); - - case EidUpdateInfo::UPDATE_AVAILABLE: - qCDebug(card_smart) << "Update available, delete the Smart-eID first"; - break; - - default: - qCDebug(card_smart) << "No update available"; - return QVariant(); - } - - Q_FALLTHROUGH(); - - case EidStatus::APPLET_UNUSABLE: - { - const int initialProgress = context->getProgressValue(); - const auto& progressHandler = [this, &initialProgress](int pProgress) { - QMetaObject::invokeMethod(this, [this, pProgress, &initialProgress]{ - //: LABEL ANDROID IOS - setProgress(pProgress, tr("Cleaning up old Smart-eID"), initialProgress, 50); - }, Qt::QueuedConnection); - }; - //: LABEL ANDROID IOS - setProgress(initialProgress, tr("Cleaning up old Smart-eID")); - if (!smartManager->deleteSmart(progressHandler)) - { - qCDebug(card_smart) << "Deletion of Smart-eID failed"; - return QVariant::fromValue(FailureCode::Reason::Prepare_Applet_Delete_Smart_Failed); - } - - qCDebug(card_smart) << "Successfully deleted Smart-eID"; - return QVariant(); - } - } - - Q_UNREACHABLE(); - }; - - mConnections += Env::getSingleton()->callExecuteCommand(func, this, &StatePrepareApplet::onCommandDone); -} - - -void StatePrepareApplet::setProgress(int pProgress, const QString& pMessage, int pInitialValue, int pMaxValue) const -{ - auto context = getContext(); - Q_ASSERT(context); - Q_ASSERT(pMaxValue > pInitialValue); - - // rewrite progress if we combine two progresses from 0-100 in single progress bar. - const int progress = (pInitialValue > 0 || pMaxValue < 100) - ? pInitialValue + static_cast((pMaxValue - pInitialValue) / 100.0 * pProgress) - : pProgress; - - context->setProgress(progress, pMessage); -} - - -void StatePrepareApplet::onCommandDone(const QVariant& pFailure) -{ - if (getContext()->isWorkflowCancelledInState()) - { - Q_EMIT fireAbort(FailureCode::Reason::Prepare_Applet_User_Cancelled); - return; - } - - if (pFailure.isNull()) - { - Q_EMIT fireContinue(); - return; - } - - updateStatus(GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed); - Q_EMIT fireAbort(pFailure.value()); -} - - -void StatePrepareApplet::onUserCancelled() -{ - const QSignalBlocker blocker(this); - AbstractState::onUserCancelled(); -} diff --git a/src/workflows/personalization/states/StatePreparePersonalization.cpp b/src/workflows/personalization/states/StatePreparePersonalization.cpp index 548d2f0bc..d3eb2c8c1 100644 --- a/src/workflows/personalization/states/StatePreparePersonalization.cpp +++ b/src/workflows/personalization/states/StatePreparePersonalization.cpp @@ -4,7 +4,6 @@ #include "StatePreparePersonalization.h" -#include "DeviceInfo.h" #include "context/PersonalizationContext.h" #include @@ -45,8 +44,57 @@ QByteArray StatePreparePersonalization::getPayload() const } +bool StatePreparePersonalization::parseStatusCode(const QByteArray& pData) const +{ + QJsonParseError jsonError {}; + const auto& json = QJsonDocument::fromJson(pData, &jsonError); + if (jsonError.error != QJsonParseError::NoError) + { + qDebug() << "JSON parsing failed:" << jsonError.errorString(); + return false; + } + + const auto obj = json.object(); + if (!obj.contains(QLatin1String("statusCode"))) + { + qDebug() << "JSON parsing failed: statusCode is missing"; + return false; + } + + const auto statusCode = obj.value(QLatin1String("statusCode")); + if (!statusCode.isDouble()) + { + qDebug() << "JSON parsing failed: statusCode has wrong format"; + return false; + } + + const auto& context = qobject_cast(getContext()); + Q_ASSERT(context); + + context->setFinalizeStatus(statusCode.toInt()); + return true; +} + + void StatePreparePersonalization::handleNetworkReply(const QByteArray& pContent) { - Q_UNUSED(pContent) - Q_EMIT fireContinue(); + if (parseStatusCode(pContent)) + { + const auto& statusCode = qobject_cast(getContext())->getFinalizeStatus(); + if (statusCode < 0) + { + qWarning() << "preparePersonalization failed with statusCode" << statusCode; + updateStatus(GlobalStatus::Code::Workflow_Smart_eID_PrePersonalization_Failed); + Q_EMIT fireAbort(FailureCode::Reason::Smart_PrePersonalization_Wrong_Status); + return; + } + + qDebug() << "preparePersonalization finished with statusCode" << statusCode; + Q_EMIT fireContinue(); + return; + } + + qDebug() << "No valid network response"; + updateStatus(GlobalStatus::Code::Workflow_Server_Incomplete_Information_Provided); + Q_EMIT fireAbort(FailureCode::Reason::Smart_PrePersonalization_Incomplete_Information); } diff --git a/src/workflows/personalization/states/StatePreparePersonalization.h b/src/workflows/personalization/states/StatePreparePersonalization.h index d42d12e50..102e57077 100644 --- a/src/workflows/personalization/states/StatePreparePersonalization.h +++ b/src/workflows/personalization/states/StatePreparePersonalization.h @@ -30,6 +30,8 @@ class StatePreparePersonalization [[nodiscard]] QUrl getRequestUrl() const override; [[nodiscard]] QByteArray getPayload() const override; + [[nodiscard]] bool parseStatusCode(const QByteArray& pData) const; + void handleNetworkReply(const QByteArray& pContent) override; }; diff --git a/src/workflows/personalization/states/StateStartPaosResponsePersonalization.cpp b/src/workflows/personalization/states/StateStartPaosPersonalizationResponse.cpp similarity index 51% rename from src/workflows/personalization/states/StateStartPaosResponsePersonalization.cpp rename to src/workflows/personalization/states/StateStartPaosPersonalizationResponse.cpp index 432cb8cfc..36682365c 100644 --- a/src/workflows/personalization/states/StateStartPaosResponsePersonalization.cpp +++ b/src/workflows/personalization/states/StateStartPaosPersonalizationResponse.cpp @@ -2,23 +2,23 @@ * Copyright (c) 2014-2023 Governikus GmbH & Co. KG, Germany */ -#include "StateStartPaosResponsePersonalization.h" +#include "StateStartPaosPersonalizationResponse.h" -#include "context/PersonalizationContext.h" Q_DECLARE_LOGGING_CATEGORY(secure) + using namespace governikus; -StateStartPaosResponsePersonalization::StateStartPaosResponsePersonalization(const QSharedPointer& pContext) +StateStartPaosPersonalizationResponse::StateStartPaosPersonalizationResponse(const QSharedPointer& pContext) : AbstractState(pContext) , GenericContextContainer(pContext) { } -void StateStartPaosResponsePersonalization::run() +void StateStartPaosPersonalizationResponse::run() { const QSharedPointer& startPaosResponse = getContext()->getStartPaosResponse(); if (!startPaosResponse) @@ -28,18 +28,26 @@ void StateStartPaosResponsePersonalization::run() return; } + const auto& remainingAttempts = startPaosResponse->getRemainingAttempts(); + const auto& remainingDays = startPaosResponse->getRemainingDays(); + qCDebug(secure) << remainingAttempts << "attempt(s) left in the next" << remainingDays << "day(s)"; + + const auto& context = getContext(); + if (context) + { + context->setFinalizeStatus(startPaosResponse->getStatusCode()); + context->setRemainingAttempts(remainingAttempts); + context->setRemainingDays(remainingDays); + } + const ECardApiResult& result = startPaosResponse->getResult(); if (result.isOk()) { - const auto& context = qobject_cast(getContext()); const auto& blockingCode = startPaosResponse->getBlockingCode(); if (context && !blockingCode.isEmpty()) { context->setBlockingCode(blockingCode); - context->setRemainingAttempts(startPaosResponse->getRemainingAttempts()); - context->setRemainingDays(startPaosResponse->getRemainingDays()); qDebug() << "Personalization was successful."; - qCDebug(secure) << context->getRemainingAttempts() << "attempt(s) left in the next" << context->getRemainingDays() << "day(s)"; } Q_EMIT fireContinue(); @@ -47,6 +55,13 @@ void StateStartPaosResponsePersonalization::run() } qDebug() << "Processing server result:" << result.getMajorString() << result.getMinorString() << result.getMessage(); + if (result.getMinor() == ECardApiResult::Minor::AL_No_Permission && remainingDays < 0) + { + const auto& dateString = context ? context->getRestrictionDate() : QString(); + updateStatus({GlobalStatus::Code::Workflow_Smart_eID_Personalization_Denied, {GlobalStatus::ExternalInformation::PERSONALIZATION_RESTRICTION_DATE, dateString} + }); + } updateStartPaosResult(result); + Q_EMIT fireAbort(FailureCode::Reason::Start_Paos_Response_Personalization_Invalid); } diff --git a/src/workflows/personalization/states/StateStartPaosResponsePersonalization.h b/src/workflows/personalization/states/StateStartPaosPersonalizationResponse.h similarity index 56% rename from src/workflows/personalization/states/StateStartPaosResponsePersonalization.h rename to src/workflows/personalization/states/StateStartPaosPersonalizationResponse.h index c463e00e3..707b67c04 100644 --- a/src/workflows/personalization/states/StateStartPaosResponsePersonalization.h +++ b/src/workflows/personalization/states/StateStartPaosPersonalizationResponse.h @@ -8,22 +8,26 @@ #pragma once -#include "context/AuthContext.h" +#include "context/PersonalizationContext.h" #include "states/AbstractState.h" #include "states/GenericContextContainer.h" + +class test_StateStartPaosPersonalizationResponse; + namespace governikus { -class StateStartPaosResponsePersonalization +class StateStartPaosPersonalizationResponse : public AbstractState - , public GenericContextContainer + , public GenericContextContainer { Q_OBJECT friend class StateBuilder; + friend class ::test_StateStartPaosPersonalizationResponse; private: - explicit StateStartPaosResponsePersonalization(const QSharedPointer& pContext); + explicit StateStartPaosPersonalizationResponse(const QSharedPointer& pContext); void run() override; }; diff --git a/src/workflows/personalization/states/StateTransmitPersonalization.cpp b/src/workflows/personalization/states/StateTransmitPersonalization.cpp index b8ce08905..2cda55d78 100644 --- a/src/workflows/personalization/states/StateTransmitPersonalization.cpp +++ b/src/workflows/personalization/states/StateTransmitPersonalization.cpp @@ -28,7 +28,7 @@ void StateTransmitPersonalization::run() return QVariant::fromValue(SmartManager::get()->performPersonalization(inputApduInfos)); }; - mConnections += Env::getSingleton()->callExecuteCommand(func, this, &StateTransmitPersonalization::onCommandDone); + *this << Env::getSingleton()->callExecuteCommand(func, this, &StateTransmitPersonalization::onCommandDone); } @@ -48,6 +48,7 @@ void StateTransmitPersonalization::onCommandDone(const QVariant& pResult) return; } - context->setProgress(context->getProgressValue() + outputApduAsHex.size(), context->getProgressMessage()); + const int newProgress = context->getProgressValue() + static_cast(outputApduAsHex.size()); + context->setProgress(qMin(90, newProgress), context->getProgressMessage()); Q_EMIT fireContinue(); } diff --git a/src/workflows/personalization/states/StateUpdateSupportInfo.cpp b/src/workflows/personalization/states/StateUpdateSupportInfo.cpp new file mode 100644 index 000000000..f93728a3a --- /dev/null +++ b/src/workflows/personalization/states/StateUpdateSupportInfo.cpp @@ -0,0 +1,150 @@ +/** + * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany + */ + +#include "StateUpdateSupportInfo.h" + +#include "ReaderManager.h" +#include "SmartManager.h" + +#include +#include + + +using namespace governikus; + + +Q_DECLARE_LOGGING_CATEGORY(card_smart) + + +StateUpdateSupportInfo::StateUpdateSupportInfo(const QSharedPointer& pContext) + : AbstractState(pContext) + , GenericContextContainer(pContext) +{ +} + + +void StateUpdateSupportInfo::run() +{ + const auto func = [this]() { + const auto& context = getContext(); + const auto& smartManager = SmartManager::get(); + //: LABEL ANDROID IOS + context->setProgress(context->getProgressValue(), tr("Checking Smart-eID status")); + + const auto& supportResult = smartManager->updateSupportInfo(); + if (supportResult.mResult != EidServiceResult::SUCCESS) + { + qCDebug(card_smart) << "updateSupportInfo() failed with" << supportResult.mResult; + return QVariant::fromValue(supportResult.mResult); + } + + return QVariant::fromValue(supportResult.mStatus); + }; + + *this << Env::getSingleton()->callExecuteCommand(func, this, &StateUpdateSupportInfo::onCommandDone); +} + + +void StateUpdateSupportInfo::handleEidServiceResult(const EidServiceResult& pResult) +{ + switch (pResult) + { + case EidServiceResult::SUCCESS: + Q_EMIT fireContinue(); + return; + + case EidServiceResult::UNDEFINED: + case EidServiceResult::INFO: + case EidServiceResult::WARN: + case EidServiceResult::ERROR: + updateStatus(GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed); + Q_EMIT fireAbort(FailureCode::Reason::Update_Support_Info_Service_Response_Fail); + return; + + case EidServiceResult::UNSUPPORTED: + updateStatus(GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed); + Q_EMIT fireAbort(FailureCode::Reason::Update_Support_Info_Service_Response_Unsupported); + return; + + case EidServiceResult::OVERLOAD_PROTECTION: + updateStatus(GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed); + Q_EMIT fireAbort(FailureCode::Reason::Update_Support_Info_Service_Response_Overload); + return; + + case EidServiceResult::UNDER_MAINTENANCE: + updateStatus(GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed); + Q_EMIT fireAbort(FailureCode::Reason::Update_Support_Info_Service_Response_Maintenance); + return; + + case EidServiceResult::NFC_NOT_ACTIVATED: + updateStatus(GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed); + Q_EMIT fireAbort(FailureCode::Reason::Update_Support_Info_Service_Response_Nfc_Disabled); + return; + + case EidServiceResult::INTEGRITY_CHECK_FAILED: + updateStatus(GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed); + Q_EMIT fireAbort(FailureCode::Reason::Update_Support_Info_Service_Response_Integrity_Check_Failed); + return; + + case EidServiceResult::NOT_AUTHENTICATED: + updateStatus(GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed); + Q_EMIT fireAbort(FailureCode::Reason::Update_Support_Info_Service_Response_Not_Authenticated); + return; + + case EidServiceResult::NETWORK_CONNECTION_ERROR: + updateStatus(GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed); + Q_EMIT fireAbort(FailureCode::Reason::Update_Support_Info_Service_Response_Network_Connection_Error); + return; + } +} + + +void StateUpdateSupportInfo::handleEidSupportStatus(const EidSupportStatus& pStatus) +{ + if (pStatus == EidSupportStatus::UP_TO_DATE) + { + Q_EMIT fireContinue(); + return; + } + + if (pStatus == EidSupportStatus::UPDATE_AVAILABLE) + { + qCDebug(card_smart) << "Update available, delete the Smart-eID first"; + Q_EMIT fireUpdateAvailable(); + return; + } + + updateStatus(GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed); + Q_EMIT fireAbort(FailureCode::Reason::Update_Support_Info_Call_Failed); +} + + +void StateUpdateSupportInfo::onCommandDone(const QVariant& pResult) +{ + if (getContext()->isWorkflowCancelledInState()) + { + Q_EMIT fireAbort(FailureCode::Reason::Update_Support_Info_User_Cancelled); + return; + } + + if (ReaderManager::isResultType(pResult)) + { + handleEidServiceResult(pResult.value()); + } + else if (ReaderManager::isResultType(pResult)) + { + handleEidSupportStatus(pResult.value()); + } + else + { + Q_ASSERT(false); + } +} + + +void StateUpdateSupportInfo::onUserCancelled() +{ + const QSignalBlocker blocker(this); + AbstractState::onUserCancelled(); +} diff --git a/src/workflows/personalization/states/StateUpdateSupportInfo.h b/src/workflows/personalization/states/StateUpdateSupportInfo.h new file mode 100644 index 000000000..ed1754765 --- /dev/null +++ b/src/workflows/personalization/states/StateUpdateSupportInfo.h @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany + */ + +/*! + * \brief Helper state that updates the Smart-eID support info + */ + +#pragma once + +#include "context/PersonalizationContext.h" +#include "states/AbstractState.h" +#include "states/GenericContextContainer.h" + +#include + + +class test_StateUpdateSupportInfo; + + +namespace governikus +{ + +class StateUpdateSupportInfo + : public AbstractState + , public GenericContextContainer +{ + Q_OBJECT + friend class StateBuilder; + friend class ::test_StateUpdateSupportInfo; + + private: + explicit StateUpdateSupportInfo(const QSharedPointer& pContext); + void run() override; + void handleEidServiceResult(const EidServiceResult& pResult); + void handleEidSupportStatus(const EidSupportStatus& pStatus); + + private Q_SLOTS: + void onCommandDone(const QVariant& pResult); + + public Q_SLOTS: + void onUserCancelled() override; + + Q_SIGNALS: + void fireUpdateAvailable(); + +}; + +} // namespace governikus diff --git a/src/workflows/selfauth/context/SelfAuthContext.cpp b/src/workflows/selfauth/context/SelfAuthContext.cpp index 0d3e7ee22..959f5a7cd 100644 --- a/src/workflows/selfauth/context/SelfAuthContext.cpp +++ b/src/workflows/selfauth/context/SelfAuthContext.cpp @@ -6,8 +6,8 @@ using namespace governikus; -SelfAuthContext::SelfAuthContext() - : AuthContext(Action::SELF, QSharedPointer()) +SelfAuthContext::SelfAuthContext(bool pActivateUi) + : AuthContext(Action::SELF, pActivateUi) , mSelfAuthenticationData() { } diff --git a/src/workflows/selfauth/context/SelfAuthContext.h b/src/workflows/selfauth/context/SelfAuthContext.h index 2af16f3e5..5be846226 100644 --- a/src/workflows/selfauth/context/SelfAuthContext.h +++ b/src/workflows/selfauth/context/SelfAuthContext.h @@ -27,7 +27,7 @@ class SelfAuthContext void fireSelfAuthenticationDataChanged(); public: - SelfAuthContext(); + explicit SelfAuthContext(bool pActivateUi = true); [[nodiscard]] const SelfAuthenticationData& getSelfAuthenticationData() const { diff --git a/src/workflows/selfauth/controller/SelfAuthController.cpp b/src/workflows/selfauth/controller/SelfAuthController.cpp index 6daf214f2..b7f085be0 100644 --- a/src/workflows/selfauth/controller/SelfAuthController.cpp +++ b/src/workflows/selfauth/controller/SelfAuthController.cpp @@ -14,7 +14,6 @@ #include "states/StateLoadTcTokenUrl.h" #include "states/StateSendWhitelistSurvey.h" #include "states/StateShowResult.h" -#include "states/StateWriteHistory.h" #include #include @@ -26,14 +25,11 @@ using namespace governikus; SelfAuthController::SelfAuthController(QSharedPointer pContext) : WorkflowController(pContext) { - auto sLoadTcTokenUrl = addState(); - mStateMachine.setInitialState(sLoadTcTokenUrl); - auto sTrustedChannel = new CompositeStateTrustedChannel(pContext); - mStateMachine.addState(sTrustedChannel); + auto sLoadTcTokenUrl = addInitialState(); + auto sTrustedChannel = addState(); auto sCheckError = addState(); auto sCheckRefreshAddress = addState(); auto sActivateStoreFeedbackDialog = addState(); - auto sWriteHistory = addState(); auto sSendWhitelistSurvey = addState(); auto sGetSelfAuthenticationData = addState(); auto sShowResult = addState(); @@ -51,11 +47,8 @@ SelfAuthController::SelfAuthController(QSharedPointer pContext) sCheckRefreshAddress->addTransition(sCheckRefreshAddress, &AbstractState::fireContinue, sActivateStoreFeedbackDialog); sCheckRefreshAddress->addTransition(sCheckRefreshAddress, &AbstractState::fireAbort, sFinal); - sActivateStoreFeedbackDialog->addTransition(sActivateStoreFeedbackDialog, &AbstractState::fireContinue, sWriteHistory); - sActivateStoreFeedbackDialog->addTransition(sActivateStoreFeedbackDialog, &AbstractState::fireAbort, sWriteHistory); - - sWriteHistory->addTransition(sWriteHistory, &AbstractState::fireContinue, sGetSelfAuthenticationData); - sWriteHistory->addTransition(sWriteHistory, &AbstractState::fireAbort, sGetSelfAuthenticationData); + sActivateStoreFeedbackDialog->addTransition(sActivateStoreFeedbackDialog, &AbstractState::fireContinue, sGetSelfAuthenticationData); + sActivateStoreFeedbackDialog->addTransition(sActivateStoreFeedbackDialog, &AbstractState::fireAbort, sGetSelfAuthenticationData); sGetSelfAuthenticationData->addTransition(sGetSelfAuthenticationData, &AbstractState::fireContinue, sShowResult); sGetSelfAuthenticationData->addTransition(sGetSelfAuthenticationData, &AbstractState::fireAbort, sFinal); @@ -68,7 +61,7 @@ SelfAuthController::SelfAuthController(QSharedPointer pContext) } -QSharedPointer SelfAuthController::createWorkflowRequest() +QSharedPointer SelfAuthController::createWorkflowRequest(bool pActivateUi) { - return WorkflowRequest::createWorkflowRequest(); + return WorkflowRequest::create(pActivateUi); } diff --git a/src/workflows/selfauth/controller/SelfAuthController.h b/src/workflows/selfauth/controller/SelfAuthController.h index 797543fd3..be0f0503b 100644 --- a/src/workflows/selfauth/controller/SelfAuthController.h +++ b/src/workflows/selfauth/controller/SelfAuthController.h @@ -22,7 +22,7 @@ class SelfAuthController Q_OBJECT public: - static QSharedPointer createWorkflowRequest(); + static QSharedPointer createWorkflowRequest(bool pActivateUi = true); explicit SelfAuthController(QSharedPointer pContext); ~SelfAuthController() override = default; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8eea27836..29018e85b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -21,7 +21,7 @@ endfunction() function(GET_TEST_ENV testenv testname) set(IS_QML_TEST "${testname}" MATCHES "qml") - set(IS_GUI_TEST IS_QML_TEST OR "${testname}" MATCHES "PdfExporter") + set(IS_GUI_TEST IS_QML_TEST) if(NOT WIN32 AND IS_GUI_TEST) list(APPEND ENV "QT_QPA_PLATFORM=offscreen") @@ -77,12 +77,7 @@ function(ADD_QML_TEST_FILES) return() endif() - if(QT6) - set(qt_selector qt6) - else() - set(qt_selector qt5) - endif() - + set(qt_selector qt6) file(GLOB_RECURSE TEST_SUBFILES "${CMAKE_CURRENT_SOURCE_DIR}/test_*.qml") foreach(sourcefile ${TEST_SUBFILES}) string(REGEX MATCHALL "\\+[a-z]+" PLATFORM_FILTER ${sourcefile}) @@ -95,21 +90,11 @@ function(ADD_QML_TEST_FILES) endif() endif() if(NOT "+desktop" IN_LIST PLATFORM_FILTER) - if(NOT "+tablet" IN_LIST PLATFORM_FILTER) - if(NOT "+ios" IN_LIST PLATFORM_FILTER) - ADD_QML_TEST(${sourcefile} SELECTORS "${qt_selector};mobile;phone;android") - endif() - if(NOT "+android" IN_LIST PLATFORM_FILTER) - ADD_QML_TEST(${sourcefile} SELECTORS "${qt_selector};mobile;phone;ios") - endif() + if(NOT "+ios" IN_LIST PLATFORM_FILTER) + ADD_QML_TEST(${sourcefile} SELECTORS "${qt_selector};mobile;android") endif() - if(NOT "+phone" IN_LIST PLATFORM_FILTER) - if(NOT "+ios" IN_LIST PLATFORM_FILTER) - ADD_QML_TEST(${sourcefile} SELECTORS "${qt_selector};mobile;tablet;android") - endif() - if(NOT "+android" IN_LIST PLATFORM_FILTER) - ADD_QML_TEST(${sourcefile} SELECTORS "${qt_selector};mobile;tablet;ios") - endif() + if(NOT "+android" IN_LIST PLATFORM_FILTER) + ADD_QML_TEST(${sourcefile} SELECTORS "${qt_selector};mobile;ios") endif() endif() endforeach() diff --git a/test/fixture/card/smartEfCardAccess.hex b/test/fixture/card/smartEfCardAccess.hex new file mode 100644 index 000000000..1f71f460d --- /dev/null +++ b/test/fixture/card/smartEfCardAccess.hex @@ -0,0 +1 @@ +3166300d060804007f0007020202020102300f060a04007f000703020302020201013012060a04007f000702020302020201020201453012060a04007f0007020204020202010202010d301c060904007f000702020302300c060704007f0007010202010d020145 diff --git a/test/fixture/core/diagnosis/antivir_one_antivirus.txt b/test/fixture/core/diagnosis/antivir_one_antivirus.txt index 0ed47290d..53786afd1 100644 --- a/test/fixture/core/diagnosis/antivir_one_antivirus.txt +++ b/test/fixture/core/diagnosis/antivir_one_antivirus.txt @@ -1,19 +1,19 @@ - -__GENUS : 2 -__CLASS : AntiVirusProduct -__SUPERCLASS : -__DYNASTY : AntiVirusProduct -__RELPATH : AntiVirusProduct.instanceGuid="{D68DDC3A-831F-4fae-9E44-DA132C1ACF46}" -__PROPERTY_COUNT : 6 -__DERIVATION : {} -__SERVER : DESKTOP-DGTBB4H -__NAMESPACE : ROOT\SecurityCenter2 -__PATH : \\DESKTOP-DGTBB4H\ROOT\SecurityCenter2:AntiVirusProduct.instanceGuid="{D68DDC3A-831F-4fae-9E - 44-DA132C1ACF46}" -displayName : Windows Defender -instanceGuid : {D68DDC3A-831F-4fae-9E44-DA132C1ACF46} -pathToSignedProductExe : windowsdefender:// -pathToSignedReportingExe : %ProgramFiles%\Windows Defender\MsMpeng.exe -productState : 393472 -timestamp : Mon, 26 Nov 2018 10:34:23 GMT -PSComputerName : DESKTOP-DGTBB4H + +__GENUS : 2 +__CLASS : AntiVirusProduct +__SUPERCLASS : +__DYNASTY : AntiVirusProduct +__RELPATH : AntiVirusProduct.instanceGuid="{D68DDC3A-831F-4fae-9E44-DA132C1ACF46}" +__PROPERTY_COUNT : 6 +__DERIVATION : {} +__SERVER : DESKTOP-DGTBB4H +__NAMESPACE : ROOT\SecurityCenter2 +__PATH : \\DESKTOP-DGTBB4H\ROOT\SecurityCenter2:AntiVirusProduct.instanceGuid="{D68DDC3A-831F-4fae-9E + 44-DA132C1ACF46}" +displayName : Windows Defender +instanceGuid : {D68DDC3A-831F-4fae-9E44-DA132C1ACF46} +pathToSignedProductExe : windowsdefender:// +pathToSignedReportingExe : %ProgramFiles%\Windows Defender\MsMpeng.exe +productState : 393472 +timestamp : Mon, 26 Nov 2018 10:34:23 GMT +PSComputerName : DESKTOP-DGTBB4H diff --git a/test/fixture/core/diagnosis/antivir_one_antivirus_missing_timestamp.txt b/test/fixture/core/diagnosis/antivir_one_antivirus_missing_timestamp.txt index 9d1cb9a7a..e2748854e 100644 --- a/test/fixture/core/diagnosis/antivir_one_antivirus_missing_timestamp.txt +++ b/test/fixture/core/diagnosis/antivir_one_antivirus_missing_timestamp.txt @@ -1,19 +1,19 @@ - -__GENUS : 2 -__CLASS : AntiVirusProduct -__SUPERCLASS : -__DYNASTY : AntiVirusProduct -__RELPATH : AntiVirusProduct.instanceGuid="{D68DDC3A-831F-4fae-9E44-DA132C1ACF46}" -__PROPERTY_COUNT : 6 -__DERIVATION : {} -__SERVER : DESKTOP-DGTBB4H -__NAMESPACE : ROOT\SecurityCenter2 -__PATH : \\DESKTOP-DGTBB4H\ROOT\SecurityCenter2:AntiVirusProduct.instanceGuid="{D68DDC3A-831F-4fae-9E - 44-DA132C1ACF46}" -displayName : Windows Defender -instanceGuid : {D68DDC3A-831F-4fae-9E44-DA132C1ACF46} -pathToSignedProductExe : windowsdefender:// -pathToSignedReportingExe : %ProgramFiles%\Windows Defender\MsMpeng.exe -productState : 393472 -timestamp : -PSComputerName : DESKTOP-DGTBB4H + +__GENUS : 2 +__CLASS : AntiVirusProduct +__SUPERCLASS : +__DYNASTY : AntiVirusProduct +__RELPATH : AntiVirusProduct.instanceGuid="{D68DDC3A-831F-4fae-9E44-DA132C1ACF46}" +__PROPERTY_COUNT : 6 +__DERIVATION : {} +__SERVER : DESKTOP-DGTBB4H +__NAMESPACE : ROOT\SecurityCenter2 +__PATH : \\DESKTOP-DGTBB4H\ROOT\SecurityCenter2:AntiVirusProduct.instanceGuid="{D68DDC3A-831F-4fae-9E + 44-DA132C1ACF46}" +displayName : Windows Defender +instanceGuid : {D68DDC3A-831F-4fae-9E44-DA132C1ACF46} +pathToSignedProductExe : windowsdefender:// +pathToSignedReportingExe : %ProgramFiles%\Windows Defender\MsMpeng.exe +productState : 393472 +timestamp : +PSComputerName : DESKTOP-DGTBB4H diff --git a/test/fixture/core/diagnosis/antivir_two_antivirus.txt b/test/fixture/core/diagnosis/antivir_two_antivirus.txt index 7dc2ea58b..ece256fb6 100644 --- a/test/fixture/core/diagnosis/antivir_two_antivirus.txt +++ b/test/fixture/core/diagnosis/antivir_two_antivirus.txt @@ -1,38 +1,38 @@ - -__GENUS : 2 -__CLASS : AntiVirusProduct -__SUPERCLASS : -__DYNASTY : AntiVirusProduct -__RELPATH : AntiVirusProduct.instanceGuid="{13E9CAA5-762A-794E-2DA9-245D5622A105}" -__PROPERTY_COUNT : 6 -__DERIVATION : {} -__SERVER : DESKTOP-DGTBB4H -__NAMESPACE : ROOT\SecurityCenter2 -__PATH : \\DESKTOP-DGTBB4H\ROOT\SecurityCenter2:AntiVirusProduct.instanceGuid="{13E9CAA5-762A-794E-2D - A9-245D5622A105}" -displayName : BullGuard Antivirus -instanceGuid : {13E9CAA5-762A-794E-2DA9-245D5622A105} -pathToSignedProductExe : C:\Program Files\BullGuard Ltd\BullGuard\BullGuard.exe -pathToSignedReportingExe : C:\Program Files\BullGuard Ltd\BullGuard\BgWsc.exe -productState : 266240 -timestamp : Fri, 30 Nov 2018 15:04:13 GMT -PSComputerName : DESKTOP-DGTBB4H - -__GENUS : 2 -__CLASS : AntiVirusProduct -__SUPERCLASS : -__DYNASTY : AntiVirusProduct -__RELPATH : AntiVirusProduct.instanceGuid="{D68DDC3A-831F-4fae-9E44-DA132C1ACF46}" -__PROPERTY_COUNT : 6 -__DERIVATION : {} -__SERVER : DESKTOP-DGTBB4H -__NAMESPACE : ROOT\SecurityCenter2 -__PATH : \\DESKTOP-DGTBB4H\ROOT\SecurityCenter2:AntiVirusProduct.instanceGuid="{D68DDC3A-831F-4fae-9E - 44-DA132C1ACF46}" -displayName : Windows Defender -instanceGuid : {D68DDC3A-831F-4fae-9E44-DA132C1ACF46} -pathToSignedProductExe : windowsdefender:// -pathToSignedReportingExe : %ProgramFiles%\Windows Defender\MsMpeng.exe -productState : 393472 -timestamp : Mon, 26 Nov 2018 10:34:23 GMT -PSComputerName : DESKTOP-DGTBB4H + +__GENUS : 2 +__CLASS : AntiVirusProduct +__SUPERCLASS : +__DYNASTY : AntiVirusProduct +__RELPATH : AntiVirusProduct.instanceGuid="{13E9CAA5-762A-794E-2DA9-245D5622A105}" +__PROPERTY_COUNT : 6 +__DERIVATION : {} +__SERVER : DESKTOP-DGTBB4H +__NAMESPACE : ROOT\SecurityCenter2 +__PATH : \\DESKTOP-DGTBB4H\ROOT\SecurityCenter2:AntiVirusProduct.instanceGuid="{13E9CAA5-762A-794E-2D + A9-245D5622A105}" +displayName : BullGuard Antivirus +instanceGuid : {13E9CAA5-762A-794E-2DA9-245D5622A105} +pathToSignedProductExe : C:\Program Files\BullGuard Ltd\BullGuard\BullGuard.exe +pathToSignedReportingExe : C:\Program Files\BullGuard Ltd\BullGuard\BgWsc.exe +productState : 266240 +timestamp : Fri, 30 Nov 2018 15:04:13 GMT +PSComputerName : DESKTOP-DGTBB4H + +__GENUS : 2 +__CLASS : AntiVirusProduct +__SUPERCLASS : +__DYNASTY : AntiVirusProduct +__RELPATH : AntiVirusProduct.instanceGuid="{D68DDC3A-831F-4fae-9E44-DA132C1ACF46}" +__PROPERTY_COUNT : 6 +__DERIVATION : {} +__SERVER : DESKTOP-DGTBB4H +__NAMESPACE : ROOT\SecurityCenter2 +__PATH : \\DESKTOP-DGTBB4H\ROOT\SecurityCenter2:AntiVirusProduct.instanceGuid="{D68DDC3A-831F-4fae-9E + 44-DA132C1ACF46}" +displayName : Windows Defender +instanceGuid : {D68DDC3A-831F-4fae-9E44-DA132C1ACF46} +pathToSignedProductExe : windowsdefender:// +pathToSignedReportingExe : %ProgramFiles%\Windows Defender\MsMpeng.exe +productState : 393472 +timestamp : Mon, 26 Nov 2018 10:34:23 GMT +PSComputerName : DESKTOP-DGTBB4H diff --git a/test/fixture/core/diagnosis/antivir_two_broken_antivirus.txt b/test/fixture/core/diagnosis/antivir_two_broken_antivirus.txt index 150194b3e..5ea450edc 100644 --- a/test/fixture/core/diagnosis/antivir_two_broken_antivirus.txt +++ b/test/fixture/core/diagnosis/antivir_two_broken_antivirus.txt @@ -1,34 +1,34 @@ - -__GENUS : 2 -__CLASS : AntiVirusProduct -__SUPERCLASS : -__DYNASTY : AntiVirusProduct -__RELPATH : AntiVirusProduct.instanceGuid="{13E9CAA5-762A-794E-2DA9-245D5622A105}" -__PROPERTY_COUNT : 6 -__DERIVATION : {} -__SERVER : DESKTOP-DGTBB4H -__NAMESPACE : ROOT\SecurityCenter2 -__PATH : \\DESKTOP-DGTBB4H\ROOT\SecurityCenter2:AntiVirusProduct.instanceGuid="{13E9CAA5-762A-794E-2D - A9-245D5622A105}" -displayName : BullGuard Antivirus -instanceGuid : {13E9CAA5-762A-794E-2DA9-245D5622A105} -productState : 266240 -timestamp : Fri, 30 Nov 2018 15:04:13 GMT -PSComputerName : DESKTOP-DGTBB4H - -__GENUS : 2 -__CLASS : AntiVirusProduct -__SUPERCLASS : -__DYNASTY : AntiVirusProduct -__RELPATH : AntiVirusProduct.instanceGuid="{D68DDC3A-831F-4fae-9E44-DA132C1ACF46}" -__PROPERTY_COUNT : 6 -__DERIVATION : {} -__SERVER : DESKTOP-DGTBB4H -__NAMESPACE : ROOT\SecurityCenter2 -__PATH : \\DESKTOP-DGTBB4H\ROOT\SecurityCenter2:AntiVirusProduct.instanceGuid="{D68DDC3A-831F-4fae-9E - 44-DA132C1ACF46}" -instanceGuid : {D68DDC3A-831F-4fae-9E44-DA132C1ACF46} -pathToSignedProductExe : windowsdefender:// -pathToSignedReportingExe : %ProgramFiles%\Windows Defender\MsMpeng.exe -productState : 393472 -PSComputerName : DESKTOP-DGTBB4H + +__GENUS : 2 +__CLASS : AntiVirusProduct +__SUPERCLASS : +__DYNASTY : AntiVirusProduct +__RELPATH : AntiVirusProduct.instanceGuid="{13E9CAA5-762A-794E-2DA9-245D5622A105}" +__PROPERTY_COUNT : 6 +__DERIVATION : {} +__SERVER : DESKTOP-DGTBB4H +__NAMESPACE : ROOT\SecurityCenter2 +__PATH : \\DESKTOP-DGTBB4H\ROOT\SecurityCenter2:AntiVirusProduct.instanceGuid="{13E9CAA5-762A-794E-2D + A9-245D5622A105}" +displayName : BullGuard Antivirus +instanceGuid : {13E9CAA5-762A-794E-2DA9-245D5622A105} +productState : 266240 +timestamp : Fri, 30 Nov 2018 15:04:13 GMT +PSComputerName : DESKTOP-DGTBB4H + +__GENUS : 2 +__CLASS : AntiVirusProduct +__SUPERCLASS : +__DYNASTY : AntiVirusProduct +__RELPATH : AntiVirusProduct.instanceGuid="{D68DDC3A-831F-4fae-9E44-DA132C1ACF46}" +__PROPERTY_COUNT : 6 +__DERIVATION : {} +__SERVER : DESKTOP-DGTBB4H +__NAMESPACE : ROOT\SecurityCenter2 +__PATH : \\DESKTOP-DGTBB4H\ROOT\SecurityCenter2:AntiVirusProduct.instanceGuid="{D68DDC3A-831F-4fae-9E + 44-DA132C1ACF46}" +instanceGuid : {D68DDC3A-831F-4fae-9E44-DA132C1ACF46} +pathToSignedProductExe : windowsdefender:// +pathToSignedReportingExe : %ProgramFiles%\Windows Defender\MsMpeng.exe +productState : 393472 +PSComputerName : DESKTOP-DGTBB4H diff --git a/test/fixture/core/diagnosis/firewallSoftwareParametersBullguard.txt b/test/fixture/core/diagnosis/firewallSoftwareParametersBullguard.txt index b17520f68..736d589a0 100644 --- a/test/fixture/core/diagnosis/firewallSoftwareParametersBullguard.txt +++ b/test/fixture/core/diagnosis/firewallSoftwareParametersBullguard.txt @@ -1,17 +1,17 @@ -__GENUS : 2 -__CLASS : FirewallProduct -__SUPERCLASS : -__DYNASTY : FirewallProduct -__RELPATH : FirewallProduct.instanceGuid="{2BD24B80-3C45-7816-06F6-8D68A8F1E67E}" -__PROPERTY_COUNT : 6 -__DERIVATION : {} -__SERVER : DESKTOP-DGTBB4H -__NAMESPACE : ROOT\SecurityCenter2 -__PATH : \\DESKTOP-DGTBB4H\ROOT\SecurityCenter2:FirewallProduct.instanceGuid="{2BD24B80-3C45-7816-06F6-8D68A8F1E67E}" -displayName : BullGuard Firewall -instanceGuid : {2BD24B80-3C45-7816-06F6-8D68A8F1E67E} -pathToSignedProductExe : C:\Program Files\BullGuard Ltd\BullGuard\BullGuard.exe -pathToSignedReportingExe : C:\Program Files\BullGuard Ltd\BullGuard\BgWsc.exe -productState : 266240 -timestamp : Tue, 11 Jun 2019 08:01:19 GMT -PSComputerName : DESKTOP-DGTBB4H +__GENUS : 2 +__CLASS : FirewallProduct +__SUPERCLASS : +__DYNASTY : FirewallProduct +__RELPATH : FirewallProduct.instanceGuid="{2BD24B80-3C45-7816-06F6-8D68A8F1E67E}" +__PROPERTY_COUNT : 6 +__DERIVATION : {} +__SERVER : DESKTOP-DGTBB4H +__NAMESPACE : ROOT\SecurityCenter2 +__PATH : \\DESKTOP-DGTBB4H\ROOT\SecurityCenter2:FirewallProduct.instanceGuid="{2BD24B80-3C45-7816-06F6-8D68A8F1E67E}" +displayName : BullGuard Firewall +instanceGuid : {2BD24B80-3C45-7816-06F6-8D68A8F1E67E} +pathToSignedProductExe : C:\Program Files\BullGuard Ltd\BullGuard\BullGuard.exe +pathToSignedReportingExe : C:\Program Files\BullGuard Ltd\BullGuard\BgWsc.exe +productState : 266240 +timestamp : Tue, 11 Jun 2019 08:01:19 GMT +PSComputerName : DESKTOP-DGTBB4H diff --git a/test/fixture/core/diagnosis/firewallSoftwareParametersKaspersky.txt b/test/fixture/core/diagnosis/firewallSoftwareParametersKaspersky.txt index b971ff713..32e88349a 100644 --- a/test/fixture/core/diagnosis/firewallSoftwareParametersKaspersky.txt +++ b/test/fixture/core/diagnosis/firewallSoftwareParametersKaspersky.txt @@ -1,17 +1,17 @@ -__GENUS : 2 -__CLASS : FirewallProduct -__SUPERCLASS : -__DYNASTY : FirewallProduct -__RELPATH : FirewallProduct.instanceGuid="{774D7037-0984-41B0-3A87-5E88E680AD58}" -__PROPERTY_COUNT : 6 -__DERIVATION : {} -__SERVER : DESKTOP-DGTBB4H -__NAMESPACE : ROOT\SecurityCenter2 -__PATH : \\DESKTOP-DGTBB4H\ROOT\SecurityCenter2:FirewallProduct.instanceGuid="{774D7037-0984-41B0-3A87-5E88E680AD58}" -displayName : Kaspersky Internet Security -instanceGuid : {774D7037-0984-41B0-3A87-5E88E680AD58} -pathToSignedProductExe : C:\Program Files (x86)\Kaspersky Lab\Kaspersky Internet Security 21.2\wmiav.exe -pathToSignedReportingExe : C:\Program Files (x86)\Kaspersky Lab\Kaspersky Internet Security 21.2\avp.exe -productState : 266240 -timestamp : Fri, 22 Jan 2021 12:00:38 GMT -PSComputerName : DESKTOP-DGTBB4H +__GENUS : 2 +__CLASS : FirewallProduct +__SUPERCLASS : +__DYNASTY : FirewallProduct +__RELPATH : FirewallProduct.instanceGuid="{774D7037-0984-41B0-3A87-5E88E680AD58}" +__PROPERTY_COUNT : 6 +__DERIVATION : {} +__SERVER : DESKTOP-DGTBB4H +__NAMESPACE : ROOT\SecurityCenter2 +__PATH : \\DESKTOP-DGTBB4H\ROOT\SecurityCenter2:FirewallProduct.instanceGuid="{774D7037-0984-41B0-3A87-5E88E680AD58}" +displayName : Kaspersky Internet Security +instanceGuid : {774D7037-0984-41B0-3A87-5E88E680AD58} +pathToSignedProductExe : C:\Program Files (x86)\Kaspersky Lab\Kaspersky Internet Security 21.2\wmiav.exe +pathToSignedReportingExe : C:\Program Files (x86)\Kaspersky Lab\Kaspersky Internet Security 21.2\avp.exe +productState : 266240 +timestamp : Fri, 22 Jan 2021 12:00:38 GMT +PSComputerName : DESKTOP-DGTBB4H diff --git a/test/fixture/core/diagnosis/firewall_profiles.txt b/test/fixture/core/diagnosis/firewall_profiles.txt index 0b8a11118..ee30b9e09 100644 --- a/test/fixture/core/diagnosis/firewall_profiles.txt +++ b/test/fixture/core/diagnosis/firewall_profiles.txt @@ -1,57 +1,57 @@ - -Name : Domain -Enabled : True -DefaultInboundAction : NotConfigured -DefaultOutboundAction : NotConfigured -AllowInboundRules : NotConfigured -AllowLocalFirewallRules : NotConfigured -AllowLocalIPsecRules : NotConfigured -AllowUserApps : NotConfigured -AllowUserPorts : NotConfigured -AllowUnicastResponseToMulticast : NotConfigured -NotifyOnListen : True -EnableStealthModeForIPsec : NotConfigured -LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log -LogMaxSizeKilobytes : 4096 -LogAllowed : False -LogBlocked : False -LogIgnored : NotConfigured -DisabledInterfaceAliases : {NotConfigured} - -Name : Private -Enabled : True -DefaultInboundAction : NotConfigured -DefaultOutboundAction : NotConfigured -AllowInboundRules : NotConfigured -AllowLocalFirewallRules : NotConfigured -AllowLocalIPsecRules : NotConfigured -AllowUserApps : NotConfigured -AllowUserPorts : NotConfigured -AllowUnicastResponseToMulticast : NotConfigured -NotifyOnListen : True -EnableStealthModeForIPsec : NotConfigured -LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log -LogMaxSizeKilobytes : 4096 -LogAllowed : False -LogBlocked : False -LogIgnored : NotConfigured -DisabledInterfaceAliases : {NotConfigured} - -Name : Public -Enabled : True -DefaultInboundAction : NotConfigured -DefaultOutboundAction : NotConfigured -AllowInboundRules : NotConfigured -AllowLocalFirewallRules : NotConfigured -AllowLocalIPsecRules : NotConfigured -AllowUserApps : NotConfigured -AllowUserPorts : NotConfigured -AllowUnicastResponseToMulticast : NotConfigured -NotifyOnListen : True -EnableStealthModeForIPsec : NotConfigured -LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log -LogMaxSizeKilobytes : 4096 -LogAllowed : False -LogBlocked : False -LogIgnored : NotConfigured -DisabledInterfaceAliases : {NotConfigured} + +Name : Domain +Enabled : True +DefaultInboundAction : NotConfigured +DefaultOutboundAction : NotConfigured +AllowInboundRules : NotConfigured +AllowLocalFirewallRules : NotConfigured +AllowLocalIPsecRules : NotConfigured +AllowUserApps : NotConfigured +AllowUserPorts : NotConfigured +AllowUnicastResponseToMulticast : NotConfigured +NotifyOnListen : True +EnableStealthModeForIPsec : NotConfigured +LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log +LogMaxSizeKilobytes : 4096 +LogAllowed : False +LogBlocked : False +LogIgnored : NotConfigured +DisabledInterfaceAliases : {NotConfigured} + +Name : Private +Enabled : True +DefaultInboundAction : NotConfigured +DefaultOutboundAction : NotConfigured +AllowInboundRules : NotConfigured +AllowLocalFirewallRules : NotConfigured +AllowLocalIPsecRules : NotConfigured +AllowUserApps : NotConfigured +AllowUserPorts : NotConfigured +AllowUnicastResponseToMulticast : NotConfigured +NotifyOnListen : True +EnableStealthModeForIPsec : NotConfigured +LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log +LogMaxSizeKilobytes : 4096 +LogAllowed : False +LogBlocked : False +LogIgnored : NotConfigured +DisabledInterfaceAliases : {NotConfigured} + +Name : Public +Enabled : True +DefaultInboundAction : NotConfigured +DefaultOutboundAction : NotConfigured +AllowInboundRules : NotConfigured +AllowLocalFirewallRules : NotConfigured +AllowLocalIPsecRules : NotConfigured +AllowUserApps : NotConfigured +AllowUserPorts : NotConfigured +AllowUnicastResponseToMulticast : NotConfigured +NotifyOnListen : True +EnableStealthModeForIPsec : NotConfigured +LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log +LogMaxSizeKilobytes : 4096 +LogAllowed : False +LogBlocked : False +LogIgnored : NotConfigured +DisabledInterfaceAliases : {NotConfigured} diff --git a/test/fixture/core/diagnosis/firewall_profiles_disabled.txt b/test/fixture/core/diagnosis/firewall_profiles_disabled.txt index 7fc85fa8d..23294ed0c 100644 --- a/test/fixture/core/diagnosis/firewall_profiles_disabled.txt +++ b/test/fixture/core/diagnosis/firewall_profiles_disabled.txt @@ -1,57 +1,57 @@ - -Name : Domain -Enabled : False -DefaultInboundAction : NotConfigured -DefaultOutboundAction : NotConfigured -AllowInboundRules : NotConfigured -AllowLocalFirewallRules : NotConfigured -AllowLocalIPsecRules : NotConfigured -AllowUserApps : NotConfigured -AllowUserPorts : NotConfigured -AllowUnicastResponseToMulticast : NotConfigured -NotifyOnListen : True -EnableStealthModeForIPsec : NotConfigured -LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log -LogMaxSizeKilobytes : 4096 -LogAllowed : False -LogBlocked : False -LogIgnored : NotConfigured -DisabledInterfaceAliases : {NotConfigured} - -Name : Private -Enabled : False -DefaultInboundAction : NotConfigured -DefaultOutboundAction : NotConfigured -AllowInboundRules : NotConfigured -AllowLocalFirewallRules : NotConfigured -AllowLocalIPsecRules : NotConfigured -AllowUserApps : NotConfigured -AllowUserPorts : NotConfigured -AllowUnicastResponseToMulticast : NotConfigured -NotifyOnListen : True -EnableStealthModeForIPsec : NotConfigured -LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log -LogMaxSizeKilobytes : 4096 -LogAllowed : False -LogBlocked : False -LogIgnored : NotConfigured -DisabledInterfaceAliases : {NotConfigured} - -Name : Public -Enabled : False -DefaultInboundAction : NotConfigured -DefaultOutboundAction : NotConfigured -AllowInboundRules : NotConfigured -AllowLocalFirewallRules : NotConfigured -AllowLocalIPsecRules : NotConfigured -AllowUserApps : NotConfigured -AllowUserPorts : NotConfigured -AllowUnicastResponseToMulticast : NotConfigured -NotifyOnListen : True -EnableStealthModeForIPsec : NotConfigured -LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log -LogMaxSizeKilobytes : 4096 -LogAllowed : False -LogBlocked : False -LogIgnored : NotConfigured -DisabledInterfaceAliases : {NotConfigured} + +Name : Domain +Enabled : False +DefaultInboundAction : NotConfigured +DefaultOutboundAction : NotConfigured +AllowInboundRules : NotConfigured +AllowLocalFirewallRules : NotConfigured +AllowLocalIPsecRules : NotConfigured +AllowUserApps : NotConfigured +AllowUserPorts : NotConfigured +AllowUnicastResponseToMulticast : NotConfigured +NotifyOnListen : True +EnableStealthModeForIPsec : NotConfigured +LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log +LogMaxSizeKilobytes : 4096 +LogAllowed : False +LogBlocked : False +LogIgnored : NotConfigured +DisabledInterfaceAliases : {NotConfigured} + +Name : Private +Enabled : False +DefaultInboundAction : NotConfigured +DefaultOutboundAction : NotConfigured +AllowInboundRules : NotConfigured +AllowLocalFirewallRules : NotConfigured +AllowLocalIPsecRules : NotConfigured +AllowUserApps : NotConfigured +AllowUserPorts : NotConfigured +AllowUnicastResponseToMulticast : NotConfigured +NotifyOnListen : True +EnableStealthModeForIPsec : NotConfigured +LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log +LogMaxSizeKilobytes : 4096 +LogAllowed : False +LogBlocked : False +LogIgnored : NotConfigured +DisabledInterfaceAliases : {NotConfigured} + +Name : Public +Enabled : False +DefaultInboundAction : NotConfigured +DefaultOutboundAction : NotConfigured +AllowInboundRules : NotConfigured +AllowLocalFirewallRules : NotConfigured +AllowLocalIPsecRules : NotConfigured +AllowUserApps : NotConfigured +AllowUserPorts : NotConfigured +AllowUnicastResponseToMulticast : NotConfigured +NotifyOnListen : True +EnableStealthModeForIPsec : NotConfigured +LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log +LogMaxSizeKilobytes : 4096 +LogAllowed : False +LogBlocked : False +LogIgnored : NotConfigured +DisabledInterfaceAliases : {NotConfigured} diff --git a/test/fixture/core/diagnosis/firewall_profiles_domain_disabled.txt b/test/fixture/core/diagnosis/firewall_profiles_domain_disabled.txt index 95d80a21b..f8ecc3ea5 100644 --- a/test/fixture/core/diagnosis/firewall_profiles_domain_disabled.txt +++ b/test/fixture/core/diagnosis/firewall_profiles_domain_disabled.txt @@ -1,57 +1,57 @@ - -Name : Domain -Enabled : False -DefaultInboundAction : NotConfigured -DefaultOutboundAction : NotConfigured -AllowInboundRules : NotConfigured -AllowLocalFirewallRules : NotConfigured -AllowLocalIPsecRules : NotConfigured -AllowUserApps : NotConfigured -AllowUserPorts : NotConfigured -AllowUnicastResponseToMulticast : NotConfigured -NotifyOnListen : True -EnableStealthModeForIPsec : NotConfigured -LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log -LogMaxSizeKilobytes : 4096 -LogAllowed : False -LogBlocked : False -LogIgnored : NotConfigured -DisabledInterfaceAliases : {NotConfigured} - -Name : Private -Enabled : True -DefaultInboundAction : NotConfigured -DefaultOutboundAction : NotConfigured -AllowInboundRules : NotConfigured -AllowLocalFirewallRules : NotConfigured -AllowLocalIPsecRules : NotConfigured -AllowUserApps : NotConfigured -AllowUserPorts : NotConfigured -AllowUnicastResponseToMulticast : NotConfigured -NotifyOnListen : True -EnableStealthModeForIPsec : NotConfigured -LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log -LogMaxSizeKilobytes : 4096 -LogAllowed : False -LogBlocked : False -LogIgnored : NotConfigured -DisabledInterfaceAliases : {NotConfigured} - -Name : Public -Enabled : True -DefaultInboundAction : NotConfigured -DefaultOutboundAction : NotConfigured -AllowInboundRules : NotConfigured -AllowLocalFirewallRules : NotConfigured -AllowLocalIPsecRules : NotConfigured -AllowUserApps : NotConfigured -AllowUserPorts : NotConfigured -AllowUnicastResponseToMulticast : NotConfigured -NotifyOnListen : True -EnableStealthModeForIPsec : NotConfigured -LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log -LogMaxSizeKilobytes : 4096 -LogAllowed : False -LogBlocked : False -LogIgnored : NotConfigured -DisabledInterfaceAliases : {NotConfigured} + +Name : Domain +Enabled : False +DefaultInboundAction : NotConfigured +DefaultOutboundAction : NotConfigured +AllowInboundRules : NotConfigured +AllowLocalFirewallRules : NotConfigured +AllowLocalIPsecRules : NotConfigured +AllowUserApps : NotConfigured +AllowUserPorts : NotConfigured +AllowUnicastResponseToMulticast : NotConfigured +NotifyOnListen : True +EnableStealthModeForIPsec : NotConfigured +LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log +LogMaxSizeKilobytes : 4096 +LogAllowed : False +LogBlocked : False +LogIgnored : NotConfigured +DisabledInterfaceAliases : {NotConfigured} + +Name : Private +Enabled : True +DefaultInboundAction : NotConfigured +DefaultOutboundAction : NotConfigured +AllowInboundRules : NotConfigured +AllowLocalFirewallRules : NotConfigured +AllowLocalIPsecRules : NotConfigured +AllowUserApps : NotConfigured +AllowUserPorts : NotConfigured +AllowUnicastResponseToMulticast : NotConfigured +NotifyOnListen : True +EnableStealthModeForIPsec : NotConfigured +LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log +LogMaxSizeKilobytes : 4096 +LogAllowed : False +LogBlocked : False +LogIgnored : NotConfigured +DisabledInterfaceAliases : {NotConfigured} + +Name : Public +Enabled : True +DefaultInboundAction : NotConfigured +DefaultOutboundAction : NotConfigured +AllowInboundRules : NotConfigured +AllowLocalFirewallRules : NotConfigured +AllowLocalIPsecRules : NotConfigured +AllowUserApps : NotConfigured +AllowUserPorts : NotConfigured +AllowUnicastResponseToMulticast : NotConfigured +NotifyOnListen : True +EnableStealthModeForIPsec : NotConfigured +LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log +LogMaxSizeKilobytes : 4096 +LogAllowed : False +LogBlocked : False +LogIgnored : NotConfigured +DisabledInterfaceAliases : {NotConfigured} diff --git a/test/fixture/core/diagnosis/firewall_profiles_domain_private_disabled.txt b/test/fixture/core/diagnosis/firewall_profiles_domain_private_disabled.txt index 11abb43bc..f96a23814 100644 --- a/test/fixture/core/diagnosis/firewall_profiles_domain_private_disabled.txt +++ b/test/fixture/core/diagnosis/firewall_profiles_domain_private_disabled.txt @@ -1,57 +1,57 @@ - -Name : Domain -Enabled : False -DefaultInboundAction : NotConfigured -DefaultOutboundAction : NotConfigured -AllowInboundRules : NotConfigured -AllowLocalFirewallRules : NotConfigured -AllowLocalIPsecRules : NotConfigured -AllowUserApps : NotConfigured -AllowUserPorts : NotConfigured -AllowUnicastResponseToMulticast : NotConfigured -NotifyOnListen : True -EnableStealthModeForIPsec : NotConfigured -LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log -LogMaxSizeKilobytes : 4096 -LogAllowed : False -LogBlocked : False -LogIgnored : NotConfigured -DisabledInterfaceAliases : {NotConfigured} - -Name : Private -Enabled : False -DefaultInboundAction : NotConfigured -DefaultOutboundAction : NotConfigured -AllowInboundRules : NotConfigured -AllowLocalFirewallRules : NotConfigured -AllowLocalIPsecRules : NotConfigured -AllowUserApps : NotConfigured -AllowUserPorts : NotConfigured -AllowUnicastResponseToMulticast : NotConfigured -NotifyOnListen : True -EnableStealthModeForIPsec : NotConfigured -LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log -LogMaxSizeKilobytes : 4096 -LogAllowed : False -LogBlocked : False -LogIgnored : NotConfigured -DisabledInterfaceAliases : {NotConfigured} - -Name : Public -Enabled : True -DefaultInboundAction : NotConfigured -DefaultOutboundAction : NotConfigured -AllowInboundRules : NotConfigured -AllowLocalFirewallRules : NotConfigured -AllowLocalIPsecRules : NotConfigured -AllowUserApps : NotConfigured -AllowUserPorts : NotConfigured -AllowUnicastResponseToMulticast : NotConfigured -NotifyOnListen : True -EnableStealthModeForIPsec : NotConfigured -LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log -LogMaxSizeKilobytes : 4096 -LogAllowed : False -LogBlocked : False -LogIgnored : NotConfigured -DisabledInterfaceAliases : {NotConfigured} + +Name : Domain +Enabled : False +DefaultInboundAction : NotConfigured +DefaultOutboundAction : NotConfigured +AllowInboundRules : NotConfigured +AllowLocalFirewallRules : NotConfigured +AllowLocalIPsecRules : NotConfigured +AllowUserApps : NotConfigured +AllowUserPorts : NotConfigured +AllowUnicastResponseToMulticast : NotConfigured +NotifyOnListen : True +EnableStealthModeForIPsec : NotConfigured +LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log +LogMaxSizeKilobytes : 4096 +LogAllowed : False +LogBlocked : False +LogIgnored : NotConfigured +DisabledInterfaceAliases : {NotConfigured} + +Name : Private +Enabled : False +DefaultInboundAction : NotConfigured +DefaultOutboundAction : NotConfigured +AllowInboundRules : NotConfigured +AllowLocalFirewallRules : NotConfigured +AllowLocalIPsecRules : NotConfigured +AllowUserApps : NotConfigured +AllowUserPorts : NotConfigured +AllowUnicastResponseToMulticast : NotConfigured +NotifyOnListen : True +EnableStealthModeForIPsec : NotConfigured +LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log +LogMaxSizeKilobytes : 4096 +LogAllowed : False +LogBlocked : False +LogIgnored : NotConfigured +DisabledInterfaceAliases : {NotConfigured} + +Name : Public +Enabled : True +DefaultInboundAction : NotConfigured +DefaultOutboundAction : NotConfigured +AllowInboundRules : NotConfigured +AllowLocalFirewallRules : NotConfigured +AllowLocalIPsecRules : NotConfigured +AllowUserApps : NotConfigured +AllowUserPorts : NotConfigured +AllowUnicastResponseToMulticast : NotConfigured +NotifyOnListen : True +EnableStealthModeForIPsec : NotConfigured +LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log +LogMaxSizeKilobytes : 4096 +LogAllowed : False +LogBlocked : False +LogIgnored : NotConfigured +DisabledInterfaceAliases : {NotConfigured} diff --git a/test/fixture/core/diagnosis/firewall_profiles_domain_public_disabled.txt b/test/fixture/core/diagnosis/firewall_profiles_domain_public_disabled.txt index 9f0b94dc3..80ad9a663 100644 --- a/test/fixture/core/diagnosis/firewall_profiles_domain_public_disabled.txt +++ b/test/fixture/core/diagnosis/firewall_profiles_domain_public_disabled.txt @@ -1,57 +1,57 @@ - -Name : Domain -Enabled : False -DefaultInboundAction : NotConfigured -DefaultOutboundAction : NotConfigured -AllowInboundRules : NotConfigured -AllowLocalFirewallRules : NotConfigured -AllowLocalIPsecRules : NotConfigured -AllowUserApps : NotConfigured -AllowUserPorts : NotConfigured -AllowUnicastResponseToMulticast : NotConfigured -NotifyOnListen : True -EnableStealthModeForIPsec : NotConfigured -LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log -LogMaxSizeKilobytes : 4096 -LogAllowed : False -LogBlocked : False -LogIgnored : NotConfigured -DisabledInterfaceAliases : {NotConfigured} - -Name : Private -Enabled : True -DefaultInboundAction : NotConfigured -DefaultOutboundAction : NotConfigured -AllowInboundRules : NotConfigured -AllowLocalFirewallRules : NotConfigured -AllowLocalIPsecRules : NotConfigured -AllowUserApps : NotConfigured -AllowUserPorts : NotConfigured -AllowUnicastResponseToMulticast : NotConfigured -NotifyOnListen : True -EnableStealthModeForIPsec : NotConfigured -LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log -LogMaxSizeKilobytes : 4096 -LogAllowed : False -LogBlocked : False -LogIgnored : NotConfigured -DisabledInterfaceAliases : {NotConfigured} - -Name : Public -Enabled : False -DefaultInboundAction : NotConfigured -DefaultOutboundAction : NotConfigured -AllowInboundRules : NotConfigured -AllowLocalFirewallRules : NotConfigured -AllowLocalIPsecRules : NotConfigured -AllowUserApps : NotConfigured -AllowUserPorts : NotConfigured -AllowUnicastResponseToMulticast : NotConfigured -NotifyOnListen : True -EnableStealthModeForIPsec : NotConfigured -LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log -LogMaxSizeKilobytes : 4096 -LogAllowed : False -LogBlocked : False -LogIgnored : NotConfigured -DisabledInterfaceAliases : {NotConfigured} + +Name : Domain +Enabled : False +DefaultInboundAction : NotConfigured +DefaultOutboundAction : NotConfigured +AllowInboundRules : NotConfigured +AllowLocalFirewallRules : NotConfigured +AllowLocalIPsecRules : NotConfigured +AllowUserApps : NotConfigured +AllowUserPorts : NotConfigured +AllowUnicastResponseToMulticast : NotConfigured +NotifyOnListen : True +EnableStealthModeForIPsec : NotConfigured +LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log +LogMaxSizeKilobytes : 4096 +LogAllowed : False +LogBlocked : False +LogIgnored : NotConfigured +DisabledInterfaceAliases : {NotConfigured} + +Name : Private +Enabled : True +DefaultInboundAction : NotConfigured +DefaultOutboundAction : NotConfigured +AllowInboundRules : NotConfigured +AllowLocalFirewallRules : NotConfigured +AllowLocalIPsecRules : NotConfigured +AllowUserApps : NotConfigured +AllowUserPorts : NotConfigured +AllowUnicastResponseToMulticast : NotConfigured +NotifyOnListen : True +EnableStealthModeForIPsec : NotConfigured +LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log +LogMaxSizeKilobytes : 4096 +LogAllowed : False +LogBlocked : False +LogIgnored : NotConfigured +DisabledInterfaceAliases : {NotConfigured} + +Name : Public +Enabled : False +DefaultInboundAction : NotConfigured +DefaultOutboundAction : NotConfigured +AllowInboundRules : NotConfigured +AllowLocalFirewallRules : NotConfigured +AllowLocalIPsecRules : NotConfigured +AllowUserApps : NotConfigured +AllowUserPorts : NotConfigured +AllowUnicastResponseToMulticast : NotConfigured +NotifyOnListen : True +EnableStealthModeForIPsec : NotConfigured +LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log +LogMaxSizeKilobytes : 4096 +LogAllowed : False +LogBlocked : False +LogIgnored : NotConfigured +DisabledInterfaceAliases : {NotConfigured} diff --git a/test/fixture/core/diagnosis/firewall_profiles_private_disabled.txt b/test/fixture/core/diagnosis/firewall_profiles_private_disabled.txt index 20881b535..e8c3f8534 100644 --- a/test/fixture/core/diagnosis/firewall_profiles_private_disabled.txt +++ b/test/fixture/core/diagnosis/firewall_profiles_private_disabled.txt @@ -1,57 +1,57 @@ - -Name : Domain -Enabled : True -DefaultInboundAction : NotConfigured -DefaultOutboundAction : NotConfigured -AllowInboundRules : NotConfigured -AllowLocalFirewallRules : NotConfigured -AllowLocalIPsecRules : NotConfigured -AllowUserApps : NotConfigured -AllowUserPorts : NotConfigured -AllowUnicastResponseToMulticast : NotConfigured -NotifyOnListen : True -EnableStealthModeForIPsec : NotConfigured -LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log -LogMaxSizeKilobytes : 4096 -LogAllowed : False -LogBlocked : False -LogIgnored : NotConfigured -DisabledInterfaceAliases : {NotConfigured} - -Name : Private -Enabled : False -DefaultInboundAction : NotConfigured -DefaultOutboundAction : NotConfigured -AllowInboundRules : NotConfigured -AllowLocalFirewallRules : NotConfigured -AllowLocalIPsecRules : NotConfigured -AllowUserApps : NotConfigured -AllowUserPorts : NotConfigured -AllowUnicastResponseToMulticast : NotConfigured -NotifyOnListen : True -EnableStealthModeForIPsec : NotConfigured -LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log -LogMaxSizeKilobytes : 4096 -LogAllowed : False -LogBlocked : False -LogIgnored : NotConfigured -DisabledInterfaceAliases : {NotConfigured} - -Name : Public -Enabled : True -DefaultInboundAction : NotConfigured -DefaultOutboundAction : NotConfigured -AllowInboundRules : NotConfigured -AllowLocalFirewallRules : NotConfigured -AllowLocalIPsecRules : NotConfigured -AllowUserApps : NotConfigured -AllowUserPorts : NotConfigured -AllowUnicastResponseToMulticast : NotConfigured -NotifyOnListen : True -EnableStealthModeForIPsec : NotConfigured -LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log -LogMaxSizeKilobytes : 4096 -LogAllowed : False -LogBlocked : False -LogIgnored : NotConfigured -DisabledInterfaceAliases : {NotConfigured} + +Name : Domain +Enabled : True +DefaultInboundAction : NotConfigured +DefaultOutboundAction : NotConfigured +AllowInboundRules : NotConfigured +AllowLocalFirewallRules : NotConfigured +AllowLocalIPsecRules : NotConfigured +AllowUserApps : NotConfigured +AllowUserPorts : NotConfigured +AllowUnicastResponseToMulticast : NotConfigured +NotifyOnListen : True +EnableStealthModeForIPsec : NotConfigured +LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log +LogMaxSizeKilobytes : 4096 +LogAllowed : False +LogBlocked : False +LogIgnored : NotConfigured +DisabledInterfaceAliases : {NotConfigured} + +Name : Private +Enabled : False +DefaultInboundAction : NotConfigured +DefaultOutboundAction : NotConfigured +AllowInboundRules : NotConfigured +AllowLocalFirewallRules : NotConfigured +AllowLocalIPsecRules : NotConfigured +AllowUserApps : NotConfigured +AllowUserPorts : NotConfigured +AllowUnicastResponseToMulticast : NotConfigured +NotifyOnListen : True +EnableStealthModeForIPsec : NotConfigured +LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log +LogMaxSizeKilobytes : 4096 +LogAllowed : False +LogBlocked : False +LogIgnored : NotConfigured +DisabledInterfaceAliases : {NotConfigured} + +Name : Public +Enabled : True +DefaultInboundAction : NotConfigured +DefaultOutboundAction : NotConfigured +AllowInboundRules : NotConfigured +AllowLocalFirewallRules : NotConfigured +AllowLocalIPsecRules : NotConfigured +AllowUserApps : NotConfigured +AllowUserPorts : NotConfigured +AllowUnicastResponseToMulticast : NotConfigured +NotifyOnListen : True +EnableStealthModeForIPsec : NotConfigured +LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log +LogMaxSizeKilobytes : 4096 +LogAllowed : False +LogBlocked : False +LogIgnored : NotConfigured +DisabledInterfaceAliases : {NotConfigured} diff --git a/test/fixture/core/diagnosis/firewall_profiles_private_public_disabled.txt b/test/fixture/core/diagnosis/firewall_profiles_private_public_disabled.txt index 1f578f1cf..bef245915 100644 --- a/test/fixture/core/diagnosis/firewall_profiles_private_public_disabled.txt +++ b/test/fixture/core/diagnosis/firewall_profiles_private_public_disabled.txt @@ -1,57 +1,57 @@ - -Name : Domain -Enabled : True -DefaultInboundAction : NotConfigured -DefaultOutboundAction : NotConfigured -AllowInboundRules : NotConfigured -AllowLocalFirewallRules : NotConfigured -AllowLocalIPsecRules : NotConfigured -AllowUserApps : NotConfigured -AllowUserPorts : NotConfigured -AllowUnicastResponseToMulticast : NotConfigured -NotifyOnListen : True -EnableStealthModeForIPsec : NotConfigured -LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log -LogMaxSizeKilobytes : 4096 -LogAllowed : False -LogBlocked : False -LogIgnored : NotConfigured -DisabledInterfaceAliases : {NotConfigured} - -Name : Private -Enabled : False -DefaultInboundAction : NotConfigured -DefaultOutboundAction : NotConfigured -AllowInboundRules : NotConfigured -AllowLocalFirewallRules : NotConfigured -AllowLocalIPsecRules : NotConfigured -AllowUserApps : NotConfigured -AllowUserPorts : NotConfigured -AllowUnicastResponseToMulticast : NotConfigured -NotifyOnListen : True -EnableStealthModeForIPsec : NotConfigured -LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log -LogMaxSizeKilobytes : 4096 -LogAllowed : False -LogBlocked : False -LogIgnored : NotConfigured -DisabledInterfaceAliases : {NotConfigured} - -Name : Public -Enabled : False -DefaultInboundAction : NotConfigured -DefaultOutboundAction : NotConfigured -AllowInboundRules : NotConfigured -AllowLocalFirewallRules : NotConfigured -AllowLocalIPsecRules : NotConfigured -AllowUserApps : NotConfigured -AllowUserPorts : NotConfigured -AllowUnicastResponseToMulticast : NotConfigured -NotifyOnListen : True -EnableStealthModeForIPsec : NotConfigured -LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log -LogMaxSizeKilobytes : 4096 -LogAllowed : False -LogBlocked : False -LogIgnored : NotConfigured -DisabledInterfaceAliases : {NotConfigured} + +Name : Domain +Enabled : True +DefaultInboundAction : NotConfigured +DefaultOutboundAction : NotConfigured +AllowInboundRules : NotConfigured +AllowLocalFirewallRules : NotConfigured +AllowLocalIPsecRules : NotConfigured +AllowUserApps : NotConfigured +AllowUserPorts : NotConfigured +AllowUnicastResponseToMulticast : NotConfigured +NotifyOnListen : True +EnableStealthModeForIPsec : NotConfigured +LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log +LogMaxSizeKilobytes : 4096 +LogAllowed : False +LogBlocked : False +LogIgnored : NotConfigured +DisabledInterfaceAliases : {NotConfigured} + +Name : Private +Enabled : False +DefaultInboundAction : NotConfigured +DefaultOutboundAction : NotConfigured +AllowInboundRules : NotConfigured +AllowLocalFirewallRules : NotConfigured +AllowLocalIPsecRules : NotConfigured +AllowUserApps : NotConfigured +AllowUserPorts : NotConfigured +AllowUnicastResponseToMulticast : NotConfigured +NotifyOnListen : True +EnableStealthModeForIPsec : NotConfigured +LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log +LogMaxSizeKilobytes : 4096 +LogAllowed : False +LogBlocked : False +LogIgnored : NotConfigured +DisabledInterfaceAliases : {NotConfigured} + +Name : Public +Enabled : False +DefaultInboundAction : NotConfigured +DefaultOutboundAction : NotConfigured +AllowInboundRules : NotConfigured +AllowLocalFirewallRules : NotConfigured +AllowLocalIPsecRules : NotConfigured +AllowUserApps : NotConfigured +AllowUserPorts : NotConfigured +AllowUnicastResponseToMulticast : NotConfigured +NotifyOnListen : True +EnableStealthModeForIPsec : NotConfigured +LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log +LogMaxSizeKilobytes : 4096 +LogAllowed : False +LogBlocked : False +LogIgnored : NotConfigured +DisabledInterfaceAliases : {NotConfigured} diff --git a/test/fixture/core/diagnosis/firewall_profiles_public_disabled.txt b/test/fixture/core/diagnosis/firewall_profiles_public_disabled.txt index 54ac5c518..9f22d1839 100644 --- a/test/fixture/core/diagnosis/firewall_profiles_public_disabled.txt +++ b/test/fixture/core/diagnosis/firewall_profiles_public_disabled.txt @@ -1,57 +1,57 @@ - -Name : Domain -Enabled : True -DefaultInboundAction : NotConfigured -DefaultOutboundAction : NotConfigured -AllowInboundRules : NotConfigured -AllowLocalFirewallRules : NotConfigured -AllowLocalIPsecRules : NotConfigured -AllowUserApps : NotConfigured -AllowUserPorts : NotConfigured -AllowUnicastResponseToMulticast : NotConfigured -NotifyOnListen : True -EnableStealthModeForIPsec : NotConfigured -LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log -LogMaxSizeKilobytes : 4096 -LogAllowed : False -LogBlocked : False -LogIgnored : NotConfigured -DisabledInterfaceAliases : {NotConfigured} - -Name : Private -Enabled : True -DefaultInboundAction : NotConfigured -DefaultOutboundAction : NotConfigured -AllowInboundRules : NotConfigured -AllowLocalFirewallRules : NotConfigured -AllowLocalIPsecRules : NotConfigured -AllowUserApps : NotConfigured -AllowUserPorts : NotConfigured -AllowUnicastResponseToMulticast : NotConfigured -NotifyOnListen : True -EnableStealthModeForIPsec : NotConfigured -LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log -LogMaxSizeKilobytes : 4096 -LogAllowed : False -LogBlocked : False -LogIgnored : NotConfigured -DisabledInterfaceAliases : {NotConfigured} - -Name : Public -Enabled : False -DefaultInboundAction : NotConfigured -DefaultOutboundAction : NotConfigured -AllowInboundRules : NotConfigured -AllowLocalFirewallRules : NotConfigured -AllowLocalIPsecRules : NotConfigured -AllowUserApps : NotConfigured -AllowUserPorts : NotConfigured -AllowUnicastResponseToMulticast : NotConfigured -NotifyOnListen : True -EnableStealthModeForIPsec : NotConfigured -LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log -LogMaxSizeKilobytes : 4096 -LogAllowed : False -LogBlocked : False -LogIgnored : NotConfigured -DisabledInterfaceAliases : {NotConfigured} + +Name : Domain +Enabled : True +DefaultInboundAction : NotConfigured +DefaultOutboundAction : NotConfigured +AllowInboundRules : NotConfigured +AllowLocalFirewallRules : NotConfigured +AllowLocalIPsecRules : NotConfigured +AllowUserApps : NotConfigured +AllowUserPorts : NotConfigured +AllowUnicastResponseToMulticast : NotConfigured +NotifyOnListen : True +EnableStealthModeForIPsec : NotConfigured +LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log +LogMaxSizeKilobytes : 4096 +LogAllowed : False +LogBlocked : False +LogIgnored : NotConfigured +DisabledInterfaceAliases : {NotConfigured} + +Name : Private +Enabled : True +DefaultInboundAction : NotConfigured +DefaultOutboundAction : NotConfigured +AllowInboundRules : NotConfigured +AllowLocalFirewallRules : NotConfigured +AllowLocalIPsecRules : NotConfigured +AllowUserApps : NotConfigured +AllowUserPorts : NotConfigured +AllowUnicastResponseToMulticast : NotConfigured +NotifyOnListen : True +EnableStealthModeForIPsec : NotConfigured +LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log +LogMaxSizeKilobytes : 4096 +LogAllowed : False +LogBlocked : False +LogIgnored : NotConfigured +DisabledInterfaceAliases : {NotConfigured} + +Name : Public +Enabled : False +DefaultInboundAction : NotConfigured +DefaultOutboundAction : NotConfigured +AllowInboundRules : NotConfigured +AllowLocalFirewallRules : NotConfigured +AllowLocalIPsecRules : NotConfigured +AllowUserApps : NotConfigured +AllowUserPorts : NotConfigured +AllowUnicastResponseToMulticast : NotConfigured +NotifyOnListen : True +EnableStealthModeForIPsec : NotConfigured +LogFileName : %systemroot%\system32\LogFiles\Firewall\pfirewall.log +LogMaxSizeKilobytes : 4096 +LogAllowed : False +LogBlocked : False +LogIgnored : NotConfigured +DisabledInterfaceAliases : {NotConfigured} diff --git a/test/fixture/core/diagnosis/firstRuleDisabled.txt b/test/fixture/core/diagnosis/firstRuleDisabled.txt index 34a4a95aa..2a5ade173 100644 --- a/test/fixture/core/diagnosis/firstRuleDisabled.txt +++ b/test/fixture/core/diagnosis/firstRuleDisabled.txt @@ -1,19 +1,19 @@ -Name : AusweisApp2-Firewall-Rule -DisplayName : AusweisApp2 -Description : AusweisApp2 firewall rule -DisplayGroup : -Group : -Enabled : False -Profile : Any -Platform : {} -Direction : Outbound -Action : Allow -EdgeTraversalPolicy : Block -LooseSourceMapping : False -LocalOnlyMapping : False -Owner : -PrimaryStatus : OK -Status : Die Regel wurde erfolgreich vom Speicher aus analysiert. (65536) -EnforcementStatus : NotApplicable -PolicyStoreSource : PersistentStore +Name : AusweisApp-Firewall-Rule +DisplayName : AusweisApp +Description : AusweisApp firewall rule +DisplayGroup : +Group : +Enabled : False +Profile : Any +Platform : {} +Direction : Outbound +Action : Allow +EdgeTraversalPolicy : Block +LooseSourceMapping : False +LocalOnlyMapping : False +Owner : +PrimaryStatus : OK +Status : Die Regel wurde erfolgreich vom Speicher aus analysiert. (65536) +EnforcementStatus : NotApplicable +PolicyStoreSource : PersistentStore PolicyStoreSourceType : Local \ No newline at end of file diff --git a/test/fixture/core/diagnosis/first_Rule.txt b/test/fixture/core/diagnosis/first_Rule.txt index 3cd7ff143..5593bb441 100644 --- a/test/fixture/core/diagnosis/first_Rule.txt +++ b/test/fixture/core/diagnosis/first_Rule.txt @@ -1,20 +1,20 @@ - -Name : AusweisApp2-Firewall-Rule -DisplayName : AusweisApp2 -Description : AusweisApp2 firewall rule -DisplayGroup : -Group : -Enabled : True -Profile : Any -Platform : {} -Direction : Outbound -Action : Allow -EdgeTraversalPolicy : Block -LooseSourceMapping : False -LocalOnlyMapping : False -Owner : -PrimaryStatus : OK -Status : Die Regel wurde erfolgreich vom Speicher aus analysiert. (65536) -EnforcementStatus : NotApplicable -PolicyStoreSource : PersistentStore -PolicyStoreSourceType : Local + +Name : AusweisApp-Firewall-Rule +DisplayName : AusweisApp +Description : AusweisApp firewall rule +DisplayGroup : +Group : +Enabled : True +Profile : Any +Platform : {} +Direction : Outbound +Action : Allow +EdgeTraversalPolicy : Block +LooseSourceMapping : False +LocalOnlyMapping : False +Owner : +PrimaryStatus : OK +Status : Die Regel wurde erfolgreich vom Speicher aus analysiert. (65536) +EnforcementStatus : NotApplicable +PolicyStoreSource : PersistentStore +PolicyStoreSourceType : Local diff --git a/test/fixture/core/diagnosis/secondRuleDisabled.txt b/test/fixture/core/diagnosis/secondRuleDisabled.txt index 505f7d24e..13cb4d4e4 100644 --- a/test/fixture/core/diagnosis/secondRuleDisabled.txt +++ b/test/fixture/core/diagnosis/secondRuleDisabled.txt @@ -1,19 +1,19 @@ -Name : {F6A3D26B-B2A3-4301-911A-C6CF3BC1941A} -DisplayName : AusweisApp2-SaC -Description : Allow inbound udp connections for Smartphone as card reader. -DisplayGroup : -Group : -Enabled : False -Profile : Any -Platform : {} -Direction : Inbound -Action : Allow -EdgeTraversalPolicy : Allow -LooseSourceMapping : False -LocalOnlyMapping : False -Owner : -PrimaryStatus : OK -Status : Die Regel wurde erfolgreich vom Speicher aus analysiert. (65536) -EnforcementStatus : NotApplicable -PolicyStoreSource : PersistentStore -PolicyStoreSourceType : Local +Name : {F6A3D26B-B2A3-4301-911A-C6CF3BC1941A} +DisplayName : AusweisApp-SaC +Description : Allow inbound udp connections for Smartphone as card reader. +DisplayGroup : +Group : +Enabled : False +Profile : Any +Platform : {} +Direction : Inbound +Action : Allow +EdgeTraversalPolicy : Allow +LooseSourceMapping : False +LocalOnlyMapping : False +Owner : +PrimaryStatus : OK +Status : Die Regel wurde erfolgreich vom Speicher aus analysiert. (65536) +EnforcementStatus : NotApplicable +PolicyStoreSource : PersistentStore +PolicyStoreSourceType : Local diff --git a/test/fixture/core/diagnosis/second_Rule.txt b/test/fixture/core/diagnosis/second_Rule.txt index b9b0d596e..c1099abf6 100644 --- a/test/fixture/core/diagnosis/second_Rule.txt +++ b/test/fixture/core/diagnosis/second_Rule.txt @@ -1,19 +1,19 @@ -Name : {BC8716ED-A024-4BD0-8519-517CF47E618C} -DisplayName : AusweisApp2-SaC -Description : Allow inbound udp connections for Smartphone as card reader. -DisplayGroup : -Group : -Enabled : True -Profile : Any -Platform : {} -Direction : Inbound -Action : Allow -EdgeTraversalPolicy : Allow -LooseSourceMapping : False -LocalOnlyMapping : False -Owner : -PrimaryStatus : OK -Status : Die Regel wurde erfolgreich vom Speicher aus analysiert. (65536) -EnforcementStatus : NotApplicable -PolicyStoreSource : PersistentStore -PolicyStoreSourceType : Local +Name : {BC8716ED-A024-4BD0-8519-517CF47E618C} +DisplayName : AusweisApp-SaC +Description : Allow inbound udp connections for Smartphone as card reader. +DisplayGroup : +Group : +Enabled : True +Profile : Any +Platform : {} +Direction : Inbound +Action : Allow +EdgeTraversalPolicy : Allow +LooseSourceMapping : False +LocalOnlyMapping : False +Owner : +PrimaryStatus : OK +Status : Die Regel wurde erfolgreich vom Speicher aus analysiert. (65536) +EnforcementStatus : NotApplicable +PolicyStoreSource : PersistentStore +PolicyStoreSourceType : Local diff --git a/test/fixture/fixture.qrc b/test/fixture/fixture.qrc index d1d2d3ddf..edafb8f23 100644 --- a/test/fixture/fixture.qrc +++ b/test/fixture/fixture.qrc @@ -65,6 +65,7 @@ card/efCardAccess.hex card/efCardSecurity.hex card/simulatorFiles.json + card/smartEfCardAccess.hex core/network/CERT_TLS_ESERVICE_1.der updatable-files/reader/img_ACS_ACR1252U.png tctoken/ok.xml @@ -92,7 +93,7 @@ paos/StartPAOSResponse1.xml paos/StartPAOSResponse2.xml paos/StartPAOSResponse3.xml - paos/StartPAOSResponse4.xml + paos/StartPAOSResponse_template.xml paos/Transmit_template.xml paos/Transmit.xml paos/Transmit2.xml diff --git a/test/fixture/paos/StartPAOS.xml b/test/fixture/paos/StartPAOS.xml index 912cf8831..3cb144ed1 100644 --- a/test/fixture/paos/StartPAOS.xml +++ b/test/fixture/paos/StartPAOS.xml @@ -24,7 +24,7 @@ 00 - Test_workflows_paos_invoke_StartPaos + AusweisApp2 123 456 789 diff --git a/test/fixture/paos/StartPAOSResponse4.xml b/test/fixture/paos/StartPAOSResponse_template.xml similarity index 76% rename from test/fixture/paos/StartPAOSResponse4.xml rename to test/fixture/paos/StartPAOSResponse_template.xml index a08b342aa..f242974fc 100644 --- a/test/fixture/paos/StartPAOSResponse4.xml +++ b/test/fixture/paos/StartPAOSResponse_template.xml @@ -25,16 +25,8 @@ xmlns:ns2="urn:oasis:names:tc:dss:1.0:core:schema" xmlns:ns4="http://www.bsi.bund.de/ecard/api/1.1" xmlns:ns3="http://www.w3.org/2000/09/xmldsig#"> - - http://www.bsi.bund.de/ecard/api/1.1/resultmajor#ok - - - - 30 - 9 - LASTWAGEN - - + + diff --git a/test/helper/common/CMakeLists.txt b/test/helper/common/CMakeLists.txt index 96044bd21..a51f4bf3d 100644 --- a/test/helper/common/CMakeLists.txt +++ b/test/helper/common/CMakeLists.txt @@ -11,10 +11,4 @@ if(DESKTOP) endif() # Enable QtHooks -if(QT5) - set(QtCore_PRIVATE_INCLUDE_DIRS "${Qt5Core_PRIVATE_INCLUDE_DIRS}") -elseif(QT6) - set(QtCore_PRIVATE_INCLUDE_DIRS "${Qt6Core_PRIVATE_INCLUDE_DIRS}") -endif() - -target_include_directories(AusweisAppTestHelperCommon SYSTEM PRIVATE ${QtCore_PRIVATE_INCLUDE_DIRS}) +target_include_directories(AusweisAppTestHelperCommon SYSTEM PRIVATE ${Qt6Core_PRIVATE_INCLUDE_DIRS}) diff --git a/test/helper/common/MockActivationContext.cpp b/test/helper/common/MockActivationContext.cpp deleted file mode 100644 index 68dc87b84..000000000 --- a/test/helper/common/MockActivationContext.cpp +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ - -#include "MockActivationContext.h" - -using namespace governikus; - -MockActivationContext::MockActivationContext(bool pProcessing, bool pAlreadyActive, bool pErroPage, bool pRedirect, const QString& pSendError) - : ActivationContext() - , mProcessingValue(pProcessing) - , mAlreadyActiveValue(pAlreadyActive) - , mErroPageValue(pErroPage) - , mRedirectValue(pRedirect) - , mErrorMessageOnSend(pSendError) - , mSendProcessingCalled(false) - , mSendAlreadyActiveCalled(false) - , mSendErroPageCalled(false) - , mSendRedirectCalled(false) -{ -} - - -MockActivationContext::~MockActivationContext() -{ -} diff --git a/test/helper/common/MockActivationContext.h b/test/helper/common/MockActivationContext.h deleted file mode 100644 index 34facae68..000000000 --- a/test/helper/common/MockActivationContext.h +++ /dev/null @@ -1,101 +0,0 @@ -/** - * Copyright (c) 2014-2023 Governikus GmbH & Co. KG, Germany - */ - -/*! - * \brief Mocked ActivationContext for unit tests. - */ - -#pragma once - - -#include "context/ActivationContext.h" - - -namespace governikus -{ - -class MockActivationContext - : public ActivationContext -{ - Q_OBJECT - - bool mProcessingValue, mAlreadyActiveValue, mErroPageValue, mRedirectValue; - const QString mErrorMessageOnSend; - bool mSendProcessingCalled, mSendAlreadyActiveCalled, mSendErroPageCalled, mSendRedirectCalled; - - public: - MockActivationContext(bool pProcessing = false, bool pAlreadyActive = false, bool pErroPage = false, bool pRedirect = false, const QString& pSendError = QString()); - ~MockActivationContext() override; - - - [[nodiscard]] QUrl getActivationURL() const override - { - return QUrl(); - } - - - bool sendProcessing() override - { - mSendProcessingCalled = true; - setSendError(mErrorMessageOnSend); - return mProcessingValue; - } - - - bool sendOperationAlreadyActive() override - { - mSendAlreadyActiveCalled = true; - setSendError(mErrorMessageOnSend); - return mAlreadyActiveValue; - } - - - bool sendErrorPage(http_status pStatusCode, const GlobalStatus& pStatus) override - { - Q_UNUSED(pStatusCode) - Q_UNUSED(pStatus) - mSendErroPageCalled = true; - setSendError(mErrorMessageOnSend); - return mErroPageValue; - } - - - bool sendRedirect(const QUrl& pRedirectAddress, const GlobalStatus& pStatus) override - { - Q_UNUSED(pRedirectAddress) - Q_UNUSED(pStatus) - mSendRedirectCalled = true; - setSendError(mErrorMessageOnSend); - return mRedirectValue; - } - - - [[nodiscard]] bool isSendAlreadyActiveCalled() const - { - return mSendAlreadyActiveCalled; - } - - - [[nodiscard]] bool isSendErroPageCalled() const - { - return mSendErroPageCalled; - } - - - [[nodiscard]] bool isSendProcessingCalled() const - { - return mSendProcessingCalled; - } - - - [[nodiscard]] bool isSendRedirectCalled() const - { - return mSendRedirectCalled; - } - - -}; - - -} // namespace governikus diff --git a/test/helper/common/MockDownloader.cpp b/test/helper/common/MockDownloader.cpp index c1daef1cf..e1263850a 100644 --- a/test/helper/common/MockDownloader.cpp +++ b/test/helper/common/MockDownloader.cpp @@ -24,8 +24,7 @@ QDateTime MockDownloader::getTimeStamp() QString MockDownloader::getTimeStampString() { - const QString dateFormat = QStringLiteral("yyyyMMddhhmmss"); - return getTimeStamp().toString(dateFormat); + return getTimeStamp().toString(QStringLiteral("yyyyMMddhhmmsst")); } diff --git a/test/helper/common/MockNetworkReply.cpp b/test/helper/common/MockNetworkReply.cpp index 78973e6d0..2cfcf6303 100644 --- a/test/helper/common/MockNetworkReply.cpp +++ b/test/helper/common/MockNetworkReply.cpp @@ -10,7 +10,6 @@ using namespace governikus; MockNetworkReply::MockNetworkReply(const QByteArray& pData, http_status pStatusCode, QObject* pParent) : QNetworkReply(pParent) , mSocket() - , mFinished(false) { mSocket.mReadBuffer = pData; setOpenMode(QIODevice::ReadOnly); @@ -31,9 +30,9 @@ qint64 MockNetworkReply::readData(char* pDst, qint64 pMaxSize) void MockNetworkReply::fireFinished() { - if (!mFinished) + if (!isFinished()) { - mFinished = true; + setFinished(true); Q_EMIT finished(); } } diff --git a/test/helper/common/MockNetworkReply.h b/test/helper/common/MockNetworkReply.h index 61bd8ab00..fed925ec2 100644 --- a/test/helper/common/MockNetworkReply.h +++ b/test/helper/common/MockNetworkReply.h @@ -24,7 +24,6 @@ class MockNetworkReply private: MockSocket mSocket; - bool mFinished; public: MockNetworkReply(const QByteArray& pData = QByteArray(), http_status pStatusCode = HTTP_STATUS_OK, QObject* pParent = nullptr); diff --git a/test/helper/common/MockReaderManagerPlugIn.cpp b/test/helper/common/MockReaderManagerPlugIn.cpp index a3424e7ca..3cfb27656 100644 --- a/test/helper/common/MockReaderManagerPlugIn.cpp +++ b/test/helper/common/MockReaderManagerPlugIn.cpp @@ -42,6 +42,23 @@ QList MockReaderManagerPlugIn::getReaders() const } +void MockReaderManagerPlugIn::startScan(bool pAutoConnect) +{ + ReaderManagerPlugIn::startScan(pAutoConnect); + for (MockReader* reader : std::as_const(mReaders)) + { + const auto& readerInfo = reader->getReaderInfo(); + if (readerInfo.isInsertable()) + { + Q_EMIT fireReaderPropertiesUpdated(reader->getReaderInfo()); + return; + } + + Q_EMIT fireCardInfoChanged(readerInfo); + } +} + + MockReader* MockReaderManagerPlugIn::addReader(const QString& pReaderName, ReaderManagerPlugInType pType) { MockReader* mockReader = nullptr; diff --git a/test/helper/common/MockReaderManagerPlugIn.h b/test/helper/common/MockReaderManagerPlugIn.h index f08897d11..11794795d 100644 --- a/test/helper/common/MockReaderManagerPlugIn.h +++ b/test/helper/common/MockReaderManagerPlugIn.h @@ -37,9 +37,12 @@ class MockReaderManagerPlugIn void insert(const QString& pReaderName, const QVariant& pData) override; [[nodiscard]] QList getReaders() const override; + void startScan(bool pAutoConnect) override; MockReader* addReader(const QString& pReaderName = QStringLiteral("MockReader"), ReaderManagerPlugInType pType = MockReader::cMOCKED_READERMANAGER_TYPE); void removeReader(const QString& pReaderName); void removeAllReader(); + + using ReaderManagerPlugIn::setPlugInAvailable; }; diff --git a/test/helper/common/MockSocket.cpp b/test/helper/common/MockSocket.cpp index f7318b6ad..605d44709 100644 --- a/test/helper/common/MockSocket.cpp +++ b/test/helper/common/MockSocket.cpp @@ -34,17 +34,13 @@ qint64 MockSocket::readData(char* pDestination, qint64 pMaxSize) { Q_ASSERT(pMaxSize <= INT_MAX); -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) auto chunk = pMaxSize; -#else - auto chunk = static_cast(pMaxSize); -#endif if (mReaderBufferChunk > -1 && mReaderBufferChunk < chunk) { chunk = mReaderBufferChunk; } - const QByteArray data = mReadBuffer.mid(mReaderBufferPosition, chunk); + const QByteArray data = mReadBuffer.mid(static_cast(mReaderBufferPosition), static_cast(chunk)); const auto length = data.length(); if (length >= 0) { diff --git a/test/helper/common/MockSocket.h b/test/helper/common/MockSocket.h index 6a2c6ef32..7dd607dfb 100644 --- a/test/helper/common/MockSocket.h +++ b/test/helper/common/MockSocket.h @@ -22,13 +22,8 @@ class MockSocket public: QByteArray mReadBuffer; -#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) - int mReaderBufferPosition; - int mReaderBufferChunk; -#else qint64 mReaderBufferPosition; qint64 mReaderBufferChunk; -#endif QByteArray mWriteBuffer; MockSocket(); diff --git a/test/helper/common/TestAuthContext.cpp b/test/helper/common/TestAuthContext.cpp index 81fab012c..ccebc8508 100644 --- a/test/helper/common/TestAuthContext.cpp +++ b/test/helper/common/TestAuthContext.cpp @@ -1,6 +1,7 @@ /** * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany */ + #include "TestAuthContext.h" #include "paos/retrieve/DidAuthenticateEac1Parser.h" @@ -12,8 +13,8 @@ using namespace governikus; -TestAuthContext::TestAuthContext(const QSharedPointer& pActivationContext, const QString& pFileName) - : AuthContext(QSharedPointer(pActivationContext)) +TestAuthContext::TestAuthContext(const QString& pFileName) + : AuthContext() , mAcceptedEidTypes({AcceptedEidType::CARD_CERTIFIED, AcceptedEidType::SE_CERTIFIED, AcceptedEidType::SE_ENDORSED}) { if (pFileName.isEmpty()) diff --git a/test/helper/common/TestAuthContext.h b/test/helper/common/TestAuthContext.h index 56b84552e..dd62e0ab1 100644 --- a/test/helper/common/TestAuthContext.h +++ b/test/helper/common/TestAuthContext.h @@ -26,7 +26,7 @@ class TestAuthContext const QSharedPointer getTerminalCvc(QSharedPointer pEac1) const; public: - explicit TestAuthContext(const QSharedPointer& pActivationContext, const QString& pFileName = QString()); + explicit TestAuthContext(const QString& pFileName = QString()); ~TestAuthContext() override; void setRequiredAccessRights(const QSet& pAccessRights); diff --git a/test/helper/common/TestWorkflowController.cpp b/test/helper/common/TestWorkflowController.cpp index bd93b7622..069bebd1c 100644 --- a/test/helper/common/TestWorkflowController.cpp +++ b/test/helper/common/TestWorkflowController.cpp @@ -7,7 +7,7 @@ using namespace governikus; -TestWorkflowController::TestWorkflowController(const QSharedPointer& pContext) +TestWorkflowController::TestWorkflowController(const QSharedPointer& pContext) : WorkflowController(pContext) { } diff --git a/test/helper/common/TestWorkflowController.h b/test/helper/common/TestWorkflowController.h index 4fd2a2958..eca7f0d49 100644 --- a/test/helper/common/TestWorkflowController.h +++ b/test/helper/common/TestWorkflowController.h @@ -21,14 +21,14 @@ class TestWorkflowController Q_OBJECT public: - template + template static QSharedPointer createWorkflowRequest(Args&& ... pArgs) { - return WorkflowRequest::createWorkflowRequest(std::forward(pArgs) ...); + return WorkflowRequest::create(std::forward(pArgs) ...); } - explicit TestWorkflowController(const QSharedPointer& pContext); + explicit TestWorkflowController(const QSharedPointer& pContext); }; diff --git a/test/helper/ui/CMakeLists.txt b/test/helper/ui/CMakeLists.txt index 81e2ae198..3c3a6f250 100644 --- a/test/helper/ui/CMakeLists.txt +++ b/test/helper/ui/CMakeLists.txt @@ -5,3 +5,7 @@ endif() if(TARGET AusweisAppUiWebsocket) add_subdirectory(websocket) endif() + +if(TARGET AusweisAppUiQml) + add_subdirectory(qml) +endif() diff --git a/test/helper/ui/json/MsgHandlerEnterPassword.cpp b/test/helper/ui/json/MsgHandlerEnterPassword.cpp index 90147207a..85a99771e 100644 --- a/test/helper/ui/json/MsgHandlerEnterPassword.cpp +++ b/test/helper/ui/json/MsgHandlerEnterPassword.cpp @@ -62,7 +62,11 @@ void governikus::setValidState(MessageDispatcher& pDispatcher, QByteArray governikus::addReaderData(const char* pData, bool pKeyPad) { const QByteArray data(pData); +#if __has_include("SmartManager.h") + const QByteArray part1(R"(,"reader":{"attached":true,"card":{"deactivated":false,"eidType":"CARD_CERTIFIED","inoperative":false,"retryCounter":-1},"insertable":false,"keypad":)"); +#else const QByteArray part1(R"(,"reader":{"attached":true,"card":{"deactivated":false,"inoperative":false,"retryCounter":-1},"insertable":false,"keypad":)"); +#endif const QByteArray keypad = pKeyPad ? QByteArrayLiteral("true") : QByteArrayLiteral("false"); const QByteArray part2(R"(,"name":"MockReader CARD"})"); return data.mid(0, data.size() - 1) + part1 + keypad + part2 + QByteArrayLiteral("}"); diff --git a/test/helper/ui/qml/CMakeLists.txt b/test/helper/ui/qml/CMakeLists.txt new file mode 100644 index 000000000..1c464a953 --- /dev/null +++ b/test/helper/ui/qml/CMakeLists.txt @@ -0,0 +1,3 @@ +ADD_PLATFORM_LIBRARY(AusweisAppTestHelperUiQml) + +target_link_libraries(AusweisAppTestHelperUiQml AusweisAppUiQml) diff --git a/test/integrated/CMakeLists.txt b/test/integrated/CMakeLists.txt index 582b14bf5..728053418 100644 --- a/test/integrated/CMakeLists.txt +++ b/test/integrated/CMakeLists.txt @@ -1,11 +1,13 @@ set(TESTNAME test_sdk_Integrated) add_executable(${TESTNAME} test_Integrated.cpp) target_link_libraries(${TESTNAME} PRIVATE Threads::Threads) -target_link_libraries(${TESTNAME} PRIVATE AusweisApp AusweisAppUiFunctional AusweisAppTestHelper) +target_link_libraries(${TESTNAME} PRIVATE AusweisAppBinary AusweisAppUiFunctional AusweisAppTestHelper) add_test(NAME ${TESTNAME} COMMAND ${TESTNAME}) set_tests_properties(${TESTNAME} PROPERTIES LABELS "integrated" TIMEOUT 60) +set_tests_properties(${TESTNAME} PROPERTIES FAIL_REGULAR_EXPRESSION "WARNING: QApplication was not created in the main") -if(QT_VENDOR STREQUAL "Governikus") - set_tests_properties(${TESTNAME} PROPERTIES FAIL_REGULAR_EXPRESSION "WARNING: QApplication was not created in the main") +if(NOT QT_VENDOR STREQUAL "Governikus") + list(APPEND ENV "ASAN_OPTIONS=detect_leaks=0") + set_tests_properties(${TESTNAME} PROPERTIES ENVIRONMENT "${ENV}") endif() diff --git a/test/integrated/test_Integrated.cpp b/test/integrated/test_Integrated.cpp index bb75c7f9b..4855b9ab5 100644 --- a/test/integrated/test_Integrated.cpp +++ b/test/integrated/test_Integrated.cpp @@ -71,7 +71,11 @@ int main() { governikus::QtHooks::init(); +#if defined(GOVERNIKUS_QT) start_aa2(nullptr); +#else + start_aa2("--no-proxy"); +#endif const int livingDeadCount = static_cast(governikus::QtHooks::getQObjects().size()); if (livingDeadCount > 0) diff --git a/test/integration/CMakeLists.txt b/test/integration/CMakeLists.txt index 913971398..d1ae2d450 100644 --- a/test/integration/CMakeLists.txt +++ b/test/integration/CMakeLists.txt @@ -10,7 +10,7 @@ function(ADD_INTEGRATION_TEST_EXECUTABLES) add_executable(${TESTNAME} ${sourcefile}) target_link_libraries(${TESTNAME} ${Qt}::Test AusweisAppTestHelper) - target_compile_definitions(${TESTNAME} PUBLIC AUSWEISAPP_BINARY_DIR="$/") + target_compile_definitions(${TESTNAME} PUBLIC AUSWEISAPP_BINARY_DIR="$/") GET_TEST_ENV(TESTENV ${TESTNAME}) diff --git a/test/integration/init/test_CommandLineParser.cpp b/test/integration/init/test_CommandLineParser.cpp index e630dc5f4..973d579ab 100644 --- a/test/integration/init/test_CommandLineParser.cpp +++ b/test/integration/init/test_CommandLineParser.cpp @@ -25,7 +25,7 @@ class test_CommandLineParser #endif const QString& path = QStringLiteral(AUSWEISAPP_BINARY_DIR); - const QString& app = path + "AusweisApp2"; + const QString& app = path + "AusweisApp"; QStringList args; args << "--help"; diff --git a/test/integration/ui/qml/test_UIPlugInQml.cpp b/test/integration/ui/qml/test_Qml.cpp similarity index 83% rename from test/integration/ui/qml/test_UIPlugInQml.cpp rename to test/integration/ui/qml/test_Qml.cpp index 12e550a20..5a2e322a6 100644 --- a/test/integration/ui/qml/test_UIPlugInQml.cpp +++ b/test/integration/ui/qml/test_Qml.cpp @@ -15,7 +15,7 @@ using namespace governikus; -class test_UIPlugInQml +class test_Qml : public QObject { Q_OBJECT @@ -63,27 +63,11 @@ class test_UIPlugInQml const QString logData = getLogData(); bool initContainedAndSuccess = logData.contains(QLatin1String("QML engine initialization finished with 0 warnings.")); - bool noQmlWarning = true; - -#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 1)) - auto iterator = QRegularExpression(QStringLiteral("\n.* W .*\\.qml:.*\n")).globalMatch(logData); - while (iterator.hasNext()) - { - const QRegularExpressionMatch match = iterator.next(); - if (!match.captured(0).contains(QLatin1String("QML Connections: Implicitly defined onFoo properties in Connections are deprecated. Use this syntax instead:"))) - { - noQmlWarning = false; - break; - } - } -#else - noQmlWarning = !logData.contains(QRegularExpression(" W .*\\.qml:")); -#endif - + bool noQmlWarning = !logData.contains(QRegularExpression(" W .*\\.qml:")); bool success = initContainedAndSuccess && noQmlWarning; if (!success) { - qDebug().noquote() << "Error output from AusweisApp2 process:\n" << logData; + qDebug().noquote() << "Error output from AusweisApp process:\n" << logData; } return success; } @@ -106,10 +90,8 @@ class test_UIPlugInQml { QTest::addColumn("platformSelector"); - QTest::newRow("Android") << QString("mobile,android,phone"); - QTest::newRow("Android Tablet") << QString("mobile,android,tablet"); - QTest::newRow("iOS") << QString("mobile,ios,phone"); - QTest::newRow("iOS Tablet") << QString("mobile,ios,tablet"); + QTest::newRow("Android") << QString("mobile,android"); + QTest::newRow("iOS") << QString("mobile,ios"); #ifdef Q_OS_WIN QTest::newRow("Windows") << QString("desktop,win"); #else @@ -123,7 +105,7 @@ class test_UIPlugInQml QFETCH(QString, platformSelector); QString path = QStringLiteral(AUSWEISAPP_BINARY_DIR); - QString app = path + "AusweisApp2"; + QString app = path + "AusweisApp"; #ifdef Q_OS_WIN app += ".exe"; #endif @@ -148,7 +130,7 @@ class test_UIPlugInQml mApp2->start(); QVERIFY(mApp2->waitForStarted(PROCESS_TIMEOUT)); - QFile portInfoFile(PortFile::getPortFilename(QString(), mApp2->processId(), QStringLiteral("AusweisApp2"))); + QFile portInfoFile(PortFile::getPortFilename(QString(), mApp2->processId(), QStringLiteral("AusweisApp"))); QTRY_COMPARE_WITH_TIMEOUT(portInfoFile.exists(), true, PROCESS_TIMEOUT); // clazy:exclude=qstring-allocations QVERIFY(portInfoFile.open(QIODevice::ReadOnly)); @@ -187,20 +169,16 @@ class test_UIPlugInQml QTRY_COMPARE_WITH_TIMEOUT(logSpy.size(), 5, PROCESS_TIMEOUT); QTRY_VERIFY_WITH_TIMEOUT(isShowUiInLog(QStringLiteral("TUTORIAL")), PROCESS_TIMEOUT); - accessManager.get(QNetworkRequest(QUrl(showUiUri.arg("HISTORY")))); - QTRY_COMPARE_WITH_TIMEOUT(logSpy.size(), 6, PROCESS_TIMEOUT); - QTRY_VERIFY_WITH_TIMEOUT(isShowUiInLog(QStringLiteral("HISTORY")), PROCESS_TIMEOUT); - accessManager.get(QNetworkRequest(QUrl(showUiUri.arg("HELP")))); - QTRY_COMPARE_WITH_TIMEOUT(logSpy.size(), 7, PROCESS_TIMEOUT); + QTRY_COMPARE_WITH_TIMEOUT(logSpy.size(), 6, PROCESS_TIMEOUT); QTRY_VERIFY_WITH_TIMEOUT(isShowUiInLog(QStringLiteral("HELP")), PROCESS_TIMEOUT); accessManager.get(QNetworkRequest(QUrl(showUiUri.arg("PROVIDER")))); - QTRY_COMPARE_WITH_TIMEOUT(logSpy.size(), 8, PROCESS_TIMEOUT); + QTRY_COMPARE_WITH_TIMEOUT(logSpy.size(), 7, PROCESS_TIMEOUT); QTRY_VERIFY_WITH_TIMEOUT(isShowUiInLog(QStringLiteral("PROVIDER")), PROCESS_TIMEOUT); accessManager.get(QNetworkRequest(QUrl(showUiUri.arg("SELF_AUTHENTICATION")))); - QTRY_COMPARE_WITH_TIMEOUT(logSpy.size(), 9, PROCESS_TIMEOUT); + QTRY_COMPARE_WITH_TIMEOUT(logSpy.size(), 8, PROCESS_TIMEOUT); QTRY_VERIFY_WITH_TIMEOUT(isShowUiInLog(QStringLiteral("SELF_AUTHENTICATION")), PROCESS_TIMEOUT); QVERIFY(isQmlEngineInitSuccess()); @@ -209,7 +187,7 @@ class test_UIPlugInQml void cleanup() { - const QString portFile = PortFile::getPortFilename(QString(), mApp2->processId(), QStringLiteral("AusweisApp2")); + const QString portFile = PortFile::getPortFilename(QString(), mApp2->processId(), QStringLiteral("AusweisApp")); QVERIFY(QFile::exists(portFile)); mHelper.reset(); @@ -253,5 +231,5 @@ class test_UIPlugInQml }; -QTEST_GUILESS_MAIN(test_UIPlugInQml) -#include "test_UIPlugInQml.moc" +QTEST_GUILESS_MAIN(test_Qml) +#include "test_Qml.moc" diff --git a/test/integration/ui/websocket/test_UIPlugInWebSocket.cpp b/test/integration/ui/websocket/test_UIPlugInWebSocket.cpp index 852958da6..9511d02eb 100644 --- a/test/integration/ui/websocket/test_UIPlugInWebSocket.cpp +++ b/test/integration/ui/websocket/test_UIPlugInWebSocket.cpp @@ -37,7 +37,7 @@ class test_UIPlugInWebSocket void init() { QString path = QStringLiteral(AUSWEISAPP_BINARY_DIR); - QString app = path + "AusweisApp2"; + QString app = path + "AusweisApp"; #ifdef Q_OS_WIN app += ".exe"; #endif @@ -58,7 +58,7 @@ class test_UIPlugInWebSocket mApp2->waitForStarted(PROCESS_TIMEOUT); QCOMPARE(mApp2->state(), QProcess::Running); - QFile portInfoFile(PortFile::getPortFilename(QString(), mApp2->processId(), QStringLiteral("AusweisApp2"))); + QFile portInfoFile(PortFile::getPortFilename(QString(), mApp2->processId(), QStringLiteral("AusweisApp"))); QTRY_COMPARE_WITH_TIMEOUT(portInfoFile.exists(), true, PROCESS_TIMEOUT); // clazy:exclude=qstring-allocations QVERIFY(portInfoFile.open(QIODevice::ReadOnly)); @@ -73,7 +73,7 @@ class test_UIPlugInWebSocket void cleanup() { - const QString portFile = PortFile::getPortFilename(QString(), mApp2->processId(), QStringLiteral("AusweisApp2")); + const QString portFile = PortFile::getPortFilename(QString(), mApp2->processId(), QStringLiteral("AusweisApp")); QVERIFY(QFile::exists(portFile)); mHelper.reset(); @@ -97,7 +97,7 @@ class test_UIPlugInWebSocket // There will never be a clean shutdown on Windows. if (mApp2->exitCode() != 0) { - qDebug().noquote() << "Error output from AusweisApp2 process:\n" << mApp2->readAllStandardError(); + qDebug().noquote() << "Error output from AusweisApp process:\n" << mApp2->readAllStandardError(); } QCOMPARE(mApp2->exitCode(), 0); #endif @@ -119,7 +119,7 @@ class test_UIPlugInWebSocket mHelper->sendMessage("{\"cmd\": \"GET_INFO\"}"); QVERIFY(mHelper->waitForMessage([](const QJsonObject& pMessage){ return pMessage["msg"] == "INFO" && - pMessage["VersionInfo"].toObject()["Name"] == "AusweisApp2"; + pMessage["VersionInfo"].toObject()["Name"] == QLatin1String("AusweisApp2"); })); mHelper->sendMessage("{\"cmd\": \"GET_API_LEVEL\"}"); diff --git a/test/json/CMakeLists.txt b/test/json/CMakeLists.txt index c3253e98c..e3ae0f7d9 100644 --- a/test/json/CMakeLists.txt +++ b/test/json/CMakeLists.txt @@ -10,7 +10,7 @@ if(JSONSCHEMA_BIN) endif() get_filename_component(filename ${file} NAME) - set(schema ${RESOURCES_DIR}/json-schemas/${filename}) + set(schema ${TEST_DIR}/json/${filename}) add_test(NAME ${filename} COMMAND ${JSONSCHEMA_BIN} -i ${file} ${schema}) set_tests_properties(${filename} PROPERTIES LABELS "json" TIMEOUT 10) diff --git a/resources/json-schemas/supported-providers.json b/test/json/supported-providers.json similarity index 97% rename from resources/json-schemas/supported-providers.json rename to test/json/supported-providers.json index 7ae1e6571..dc1604b65 100644 --- a/resources/json-schemas/supported-providers.json +++ b/test/json/supported-providers.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "JSON schema for AusweisApp2's supported-providers.json file", + "title": "JSON schema for AusweisApp's supported-providers.json file", "definitions": { "languageString": { "type": "object", diff --git a/resources/json-schemas/supported-readers.json b/test/json/supported-readers.json similarity index 67% rename from resources/json-schemas/supported-readers.json rename to test/json/supported-readers.json index 43e28032b..d4255a70a 100644 --- a/resources/json-schemas/supported-readers.json +++ b/test/json/supported-readers.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "JSON schema for AusweisApp2's supported-readers.json file", + "title": "JSON schema for AusweisApp's supported-readers.json file", "definitions": { "win_versions": { "type": "string", @@ -8,7 +8,9 @@ "6.1", "6.2", "6.3", - "10.0" + "10", + "10.0.19999", + "10.0.20000" ] }, "mac_versions": { @@ -18,10 +20,12 @@ "10.13", "10.14", "10.15", - "11.0" + "11", + "12", + "13" ] }, - "operating_system": { + "operating_system_drivers": { "oneOf": [ { "type": "object", @@ -75,6 +79,68 @@ "additionalProperties": false } ] + }, + "operating_system_information": { + "oneOf": [ + { + "type": "object", + "properties": { + "DE": { + "type": "string", + "minLength": 5 + }, + "EN": { + "type": "string", + "minLength": 5 + }, + "os": { + "type": "string", + "const": "win" + }, + "min": { + "$ref": "#/definitions/win_versions" + }, + "max": { + "$ref": "#/definitions/win_versions" + } + }, + "required": [ + "DE", + "EN", + "os" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "DE": { + "type": "string", + "minLength": 5 + }, + "EN": { + "type": "string", + "minLength": 5 + }, + "os": { + "type": "string", + "const": "mac" + }, + "min": { + "$ref": "#/definitions/mac_versions" + }, + "max": { + "$ref": "#/definitions/mac_versions" + } + }, + "required": [ + "DE", + "EN", + "os" + ], + "additionalProperties": false + } + ] } }, "type": "object", @@ -96,6 +162,13 @@ "type": "string", "pattern": "^0x[0-9A-F]{4}$" }, + "ProductIds": { + "type": "array", + "items": { + "type": "string", + "pattern": "^0x[0-9A-F]{4}$" + } + }, "Name": { "type": "string", "pattern": "[ \\-0-9a-zA-Z]{8,}" @@ -120,7 +193,7 @@ "Platforms": { "type": "array", "items": { - "$ref": "#/definitions/operating_system" + "$ref": "#/definitions/operating_system_drivers" } }, "URL": { @@ -144,7 +217,7 @@ "Platforms": { "type": "array", "items": { - "$ref": "#/definitions/operating_system" + "$ref": "#/definitions/operating_system_information" } }, "DE": { @@ -171,6 +244,7 @@ "required": [ "VendorId", "ProductId", + "ProductIds", "Name", "Pattern", "Icon", diff --git a/test/qml/test_ProgressView.qml b/test/qml/+desktop/test_ProgressView.qml similarity index 68% rename from test/qml/test_ProgressView.qml rename to test/qml/+desktop/test_ProgressView.qml index 88d6317e9..6b50117bb 100644 --- a/test/qml/test_ProgressView.qml +++ b/test/qml/+desktop/test_ProgressView.qml @@ -1,13 +1,14 @@ /** * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany */ -import QtTest 1.15 +import QtTest TestCase { id: parent + function test_load_ProgressView() { - var item = createTemporaryQmlObject(" - import Governikus.ProgressView 1.0; + let item = createTemporaryQmlObject(" + import Governikus.ProgressView ProgressView {} ", parent); item.destroy(); diff --git a/test/qml/+mobile/test_ProgressView.qml b/test/qml/+mobile/test_ProgressView.qml new file mode 100644 index 000000000..f3821fa77 --- /dev/null +++ b/test/qml/+mobile/test_ProgressView.qml @@ -0,0 +1,18 @@ +/** + * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany + */ +import QtTest + +TestCase { + id: parent + + function test_load_ProgressView() { + let item = createTemporaryQmlObject(" + import Governikus.ProgressView + ProgressView { title: \"ProgessView\" } + ", parent); + item.destroy(); + } + + name: "ModuleImportTest" +} diff --git a/test/qml/AuthView/test_AuthView.qml b/test/qml/AuthView/+desktop/test_AuthView.qml similarity index 66% rename from test/qml/AuthView/test_AuthView.qml rename to test/qml/AuthView/+desktop/test_AuthView.qml index c067a1546..053861c63 100644 --- a/test/qml/AuthView/test_AuthView.qml +++ b/test/qml/AuthView/+desktop/test_AuthView.qml @@ -1,16 +1,18 @@ /** * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 +import QtQuick +import QtTest +import Governikus.Global TestCase { id: testCase + function createTestObject() { return createTemporaryQmlObject(" - import QtQuick 2.15 - import QtQuick.Controls 2.15 - import Governikus.AuthView 1.0 + import QtQuick + import QtQuick.Controls + import Governikus.AuthView ApplicationWindow { menuBar: Item { @@ -22,6 +24,9 @@ TestCase { ", testCase); } function test_load() { + if (hasBindingLoop && Constants.is_desktop) { + skip("Skip test because of QTBUG-110899"); + } let testObject = createTestObject(); verify(testObject, "Object loaded"); } diff --git a/test/qml/Provider/test_ProviderDetailView.qml b/test/qml/AuthView/+desktop/test_ProviderInfoSection.qml similarity index 59% rename from test/qml/Provider/test_ProviderDetailView.qml rename to test/qml/AuthView/+desktop/test_ProviderInfoSection.qml index c3a14a87e..c2485f812 100644 --- a/test/qml/Provider/test_ProviderDetailView.qml +++ b/test/qml/AuthView/+desktop/test_ProviderInfoSection.qml @@ -1,20 +1,21 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 +import QtQuick +import QtTest TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Provider 1.0; ProviderDetailView {}", testCase); + return createTemporaryQmlObject("import \"qrc:/qml/Governikus/AuthView/+desktop/\"; ProviderInfoSection {}", testCase); } function test_load() { let testObject = createTestObject(); verify(testObject, "Object loaded"); } - name: "test_ProviderDetailView" + name: "test_ProviderInfoSection" visible: true when: windowShown } diff --git a/test/qml/AuthView/+mobile/test_AuthView.qml b/test/qml/AuthView/+mobile/test_AuthView.qml new file mode 100644 index 000000000..d2289ccee --- /dev/null +++ b/test/qml/AuthView/+mobile/test_AuthView.qml @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick +import QtTest +import Governikus.Global + +TestCase { + id: testCase + + function createTestObject() { + return createTemporaryQmlObject(" + import QtQuick + import QtQuick.Controls + import Governikus.AuthView + + ApplicationWindow { + menuBar: Item { + function updateActions() {} + } + + AuthView { title: \"AuthView\" } + } + ", testCase); + } + function test_load() { + if (hasBindingLoop && Constants.is_desktop) { + skip("Skip test because of QTBUG-110899"); + } + let testObject = createTestObject(); + verify(testObject, "Object loaded"); + } + + name: "test_AuthView" + visible: true + when: windowShown +} diff --git a/test/qml/Provider/test_ProviderInfoSection.qml b/test/qml/AuthView/+mobile/test_ProviderInfoSection.qml similarity index 66% rename from test/qml/Provider/test_ProviderInfoSection.qml rename to test/qml/AuthView/+mobile/test_ProviderInfoSection.qml index fc7450c3e..2d00a5511 100644 --- a/test/qml/Provider/test_ProviderInfoSection.qml +++ b/test/qml/AuthView/+mobile/test_ProviderInfoSection.qml @@ -1,13 +1,14 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 +import QtQuick +import QtTest TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Provider 1.0; ProviderInfoSection {}", testCase); + return createTemporaryQmlObject("import \"qrc:/qml/Governikus/AuthView/+mobile/\"; ProviderInfoSection {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/CMakeLists.txt b/test/qml/CMakeLists.txt index 0705a2666..5802f8e3c 100644 --- a/test/qml/CMakeLists.txt +++ b/test/qml/CMakeLists.txt @@ -8,7 +8,7 @@ else() endif() target_link_libraries(QmlTestRunner ${Qt}::QuickTest ${Qt}::Gui AusweisAppGlobal AusweisAppUiQml AusweisAppTestHelper) -if(QT6 AND WIN32) +if(WIN32) ADD_SHADERS_TO_TARGET(QmlTestRunner) endif() diff --git a/test/qml/ChangePinView/+desktop/test_ChangePinView.qml b/test/qml/ChangePinView/+desktop/test_ChangePinView.qml index 232423d0f..1017a24b8 100644 --- a/test/qml/ChangePinView/+desktop/test_ChangePinView.qml +++ b/test/qml/ChangePinView/+desktop/test_ChangePinView.qml @@ -1,17 +1,18 @@ /** * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.ChangePinView 1.0 +import QtQuick +import QtTest +import Governikus.ChangePinView TestCase { id: testCase + function createTestObject() { return createTemporaryQmlObject(" - import QtQuick 2.15 - import QtQuick.Controls 2.15 - import Governikus.ChangePinView 1.0 + import QtQuick + import QtQuick.Controls + import Governikus.ChangePinView ApplicationWindow { readonly property alias _d: view._d diff --git a/test/qml/ChangePinView/+mobile/test_ChangePinView.qml b/test/qml/ChangePinView/+mobile/test_ChangePinView.qml index e1c82b5cd..ce28fc9e8 100644 --- a/test/qml/ChangePinView/+mobile/test_ChangePinView.qml +++ b/test/qml/ChangePinView/+mobile/test_ChangePinView.qml @@ -1,13 +1,14 @@ /** * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 +import QtQuick +import QtTest TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.ChangePinView 1.0; ChangePinView {}", testCase); + return createTemporaryQmlObject("import Governikus.ChangePinView; ChangePinView {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/CheckIDCardView/+mobile/test_CheckIDCardView.qml b/test/qml/CheckIDCardView/+mobile/test_CheckIDCardView.qml index 374a5c494..d376f203c 100644 --- a/test/qml/CheckIDCardView/+mobile/test_CheckIDCardView.qml +++ b/test/qml/CheckIDCardView/+mobile/test_CheckIDCardView.qml @@ -1,14 +1,15 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import Governikus.Global TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.CheckIDCardView 1.0; CheckIDCardView {}", testCase); + return createTemporaryQmlObject("import Governikus.CheckIDCardView; CheckIDCardView {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/CheckResultView/+mobile/test_CheckIDCardSuggestionView.qml b/test/qml/CheckResultView/+mobile/test_CheckIDCardSuggestionView.qml new file mode 100644 index 000000000..10b24b039 --- /dev/null +++ b/test/qml/CheckResultView/+mobile/test_CheckIDCardSuggestionView.qml @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick 2.15 +import QtTest 1.15 +import Governikus.Type.CheckIDCardModel 1.0 + +TestCase { + id: testCase + + function createTestObject(result) { + return createTemporaryQmlObject("import \"qrc:/qml/Governikus/CheckIDCardView/+mobile/\"; CheckIDCardSuggestionView { result: %1 }".arg(result), testCase); + } + function test_load(data) { + let testObject = createTestObject(data.result); + verify(testObject, "Object loaded"); + } + function test_load_data() { + return [{ + "result": CheckIDCardModel.NO_NFC + }, { + "result": CheckIDCardModel.UNKNOWN_CARD_DETECTED + }, { + "result": CheckIDCardModel.INSUFFICIENT_APDU_LENGTH + }, { + "result": CheckIDCardModel.CARD_ACCESS_FAILED + }, { + "result": CheckIDCardModel.PIN_DEACTIVATED + }, { + "result": CheckIDCardModel.PIN_SUSPENDED + }, { + "result": CheckIDCardModel.PIN_BLOCKED + }, { + "result": -1 + }]; + } + + name: "test_CheckIDCardSuggestionView" + visible: true + when: windowShown +} diff --git a/test/qml/CheckResultView/+mobile/test_CheckResultSuggestionView.qml b/test/qml/CheckResultView/+mobile/test_CheckResultSuggestionView.qml index 5c9409498..dbf578419 100644 --- a/test/qml/CheckResultView/+mobile/test_CheckResultSuggestionView.qml +++ b/test/qml/CheckResultView/+mobile/test_CheckResultSuggestionView.qml @@ -1,13 +1,14 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 +import QtQuick +import QtTest TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.CheckResultView 1.0; CheckResultSuggestionView {}", testCase); + return createTemporaryQmlObject("import Governikus.CheckResultView; CheckResultSuggestionView { suggestionData: SuggestionData {} }", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/CheckResultView/+mobile/test_CheckResultView.qml b/test/qml/CheckResultView/+mobile/test_CheckResultView.qml index 5abf9b2f3..1ca9a24c0 100644 --- a/test/qml/CheckResultView/+mobile/test_CheckResultView.qml +++ b/test/qml/CheckResultView/+mobile/test_CheckResultView.qml @@ -1,13 +1,14 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 +import QtQuick +import QtTest TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.CheckResultView 1.0; CheckResultView {}", testCase); + return createTemporaryQmlObject("import Governikus.CheckResultView; CheckResultView { title: \"CheckResultView\"; result: 0 }", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/EnterPasswordView/+desktop/test_EnterPasswordView.qml b/test/qml/EnterPasswordView/+desktop/test_EnterPasswordView.qml index d54c3161c..2061977fd 100644 --- a/test/qml/EnterPasswordView/+desktop/test_EnterPasswordView.qml +++ b/test/qml/EnterPasswordView/+desktop/test_EnterPasswordView.qml @@ -1,14 +1,15 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtTest 1.15 -import Governikus.Type.PasswordType 1.0 +import QtTest +import Governikus.Type.PasswordType TestCase { id: parent + function test_load_EnterPasswordView(data) { - var item = createTemporaryQmlObject(" - import Governikus.EnterPasswordView 1.0; + let item = createTemporaryQmlObject(" + import Governikus.EnterPasswordView EnterPasswordView { passwordType: %1 } diff --git a/test/qml/EnterPasswordView/+mobile/test_EnterPasswordView.qml b/test/qml/EnterPasswordView/+mobile/test_EnterPasswordView.qml new file mode 100644 index 000000000..99b79eab8 --- /dev/null +++ b/test/qml/EnterPasswordView/+mobile/test_EnterPasswordView.qml @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany + */ +import QtTest + +TestCase { + id: parent + + function test_load_EnterPasswordView() { + let item = createTemporaryQmlObject(" + import Governikus.EnterPasswordView + import Governikus.Type.PasswordType + EnterPasswordView { + passwordType: PasswordType.PIN + title: \"EnterPasswordView\" + } + ", parent); + item.destroy(); + } + + name: "ModuleImportTest" +} diff --git a/test/qml/EnterPasswordView/test_EnterPasswordView.qml b/test/qml/EnterPasswordView/test_EnterPasswordView.qml deleted file mode 100644 index adf3f1e31..000000000 --- a/test/qml/EnterPasswordView/test_EnterPasswordView.qml +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany - */ -import QtTest 1.15 - -TestCase { - id: parent - function test_load_EnterPasswordView() { - var item = createTemporaryQmlObject(" - import Governikus.EnterPasswordView 1.0; - EnterPasswordView {} - ", parent); - item.destroy(); - } - - name: "ModuleImportTest" -} diff --git a/test/qml/FeedbackView/+desktop/test_DetachedLogView.qml b/test/qml/FeedbackView/+desktop/test_DetachedLogView.qml index 6ee39deb2..67ea00e44 100644 --- a/test/qml/FeedbackView/+desktop/test_DetachedLogView.qml +++ b/test/qml/FeedbackView/+desktop/test_DetachedLogView.qml @@ -1,15 +1,16 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import QtTest +import Governikus.Global +import Governikus.Style TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.FeedbackView 1.0; DetachedLogView {}", testCase); + return createTemporaryQmlObject("import Governikus.FeedbackView; DetachedLogView {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/FeedbackView/+mobile/test_LogView.qml b/test/qml/FeedbackView/+mobile/test_LogView.qml index 0dc8c403d..955831068 100644 --- a/test/qml/FeedbackView/+mobile/test_LogView.qml +++ b/test/qml/FeedbackView/+mobile/test_LogView.qml @@ -1,15 +1,16 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import QtTest +import Governikus.Global +import Governikus.Style TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.FeedbackView 1.0; LogView {}", testCase); + return createTemporaryQmlObject("import Governikus.FeedbackView; LogView {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/FeedbackView/+mobile/test_StoreFeedbackPopup.qml b/test/qml/FeedbackView/+mobile/test_StoreFeedbackPopup.qml index b804bee22..5034b904f 100644 --- a/test/qml/FeedbackView/+mobile/test_StoreFeedbackPopup.qml +++ b/test/qml/FeedbackView/+mobile/test_StoreFeedbackPopup.qml @@ -1,15 +1,16 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import QtTest +import Governikus.Global +import Governikus.Style TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.FeedbackView 1.0; StoreFeedbackPopup {}", testCase); + return createTemporaryQmlObject("import Governikus.FeedbackView; StoreFeedbackPopup {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/Global/+desktop/test_DecisionView.qml b/test/qml/Global/+desktop/test_DecisionView.qml index 5352bf83b..39a2d9c6b 100644 --- a/test/qml/Global/+desktop/test_DecisionView.qml +++ b/test/qml/Global/+desktop/test_DecisionView.qml @@ -1,14 +1,15 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import Governikus.Global TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; DecisionView {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; DecisionView {}", testCase); } function test_agree_button() { let testObject = createTestObject(); @@ -16,34 +17,22 @@ TestCase { testObject.style = DecisionView.ButtonStyle.AgreeButton; verify(testObject.agreeButton.visible, "Agree Button visible"); verify(!testObject.disagreeButton.visible, "Disagree Button invisible"); - verify(!testObject.neutralButton.visible, "Neutral Button invisible"); - } - function test_all_buttons() { - let testObject = createTestObject(); - verify(testObject, "Object loaded"); - testObject.style = DecisionView.ButtonStyle.AllButtons; - verify(testObject.agreeButton.visible, "Agree Button visible"); - verify(testObject.disagreeButton.visible, "Disagree Button visible"); - verify(testObject.neutralButton.visible, "Neutral Button visible"); } function test_combination_buttons() { let testObject = createTestObject(); verify(testObject, "Object loaded"); - testObject.style = DecisionView.ButtonStyle.AgreeButton | DecisionView.ButtonStyle.NeutralButton; + testObject.style = DecisionView.ButtonStyle.AgreeButton; verify(testObject.agreeButton.visible, "Agree Button visible"); verify(!testObject.disagreeButton.visible, "Disagree Button invisible"); - verify(testObject.neutralButton.visible, "Neutral Button visible"); - testObject.style = DecisionView.ButtonStyle.NeutralButton | DecisionView.ButtonStyle.DisagreeButton; + testObject.style = DecisionView.ButtonStyle.DisagreeButton; verify(!testObject.agreeButton.visible, "Agree Button invisible"); verify(testObject.disagreeButton.visible, "Disagree Button visible"); - verify(testObject.neutralButton.visible, "Neutral Button visible"); } function test_default_buttons() { let testObject = createTestObject(); verify(testObject, "Object loaded"); verify(testObject.agreeButton.visible, "Agree Button visible"); verify(testObject.disagreeButton.visible, "Disagree Button visible"); - verify(!testObject.neutralButton.visible, "Neutral Button invisible"); } function test_disagree_button() { let testObject = createTestObject(); @@ -51,27 +40,17 @@ TestCase { testObject.style = DecisionView.ButtonStyle.DisagreeButton; verify(!testObject.agreeButton.visible, "Agree Button invisible"); verify(testObject.disagreeButton.visible, "Disagree Button visible"); - verify(!testObject.neutralButton.visible, "Neutral Button invisible"); } function test_load() { let testObject = createTestObject(); verify(testObject, "Object loaded"); } - function test_neutral_button() { - let testObject = createTestObject(); - verify(testObject, "Object loaded"); - testObject.style = DecisionView.ButtonStyle.NeutralButton; - verify(!testObject.agreeButton.visible, "Agree Button invisible"); - verify(!testObject.disagreeButton.visible, "Disagree Button invisible"); - verify(testObject.neutralButton.visible, "Neutral Button visible"); - } function test_no_buttons() { let testObject = createTestObject(); verify(testObject, "Object loaded"); testObject.style = DecisionView.ButtonStyle.NoButtons; verify(!testObject.agreeButton.visible, "Agree Button invisible"); verify(!testObject.disagreeButton.visible, "Disagree Button invisible"); - verify(!testObject.neutralButton.visible, "Neutral Button invisible"); } name: "test_DecisionView" diff --git a/test/qml/Global/+desktop/test_GFileDialog.qml b/test/qml/Global/+desktop/test_GFileDialog.qml index 9c0ed4871..f9d3da950 100644 --- a/test/qml/Global/+desktop/test_GFileDialog.qml +++ b/test/qml/Global/+desktop/test_GFileDialog.qml @@ -1,13 +1,14 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 +import QtQuick +import QtTest TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; GFileDialog {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; GFileDialog {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/Global/test_LocationButton.qml b/test/qml/Global/+desktop/test_LocationButton.qml similarity index 59% rename from test/qml/Global/test_LocationButton.qml rename to test/qml/Global/+desktop/test_LocationButton.qml index 6a95e4c6c..0adb701be 100644 --- a/test/qml/Global/test_LocationButton.qml +++ b/test/qml/Global/+desktop/test_LocationButton.qml @@ -1,15 +1,16 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 -import Governikus.Type.SettingsModel 1.0 +import QtQuick +import QtTest +import Governikus.Global +import Governikus.Type.SettingsModel TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; LocationButton {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; LocationButton {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/Global/+desktop/test_NavigationButton.qml b/test/qml/Global/+desktop/test_NavigationButton.qml index 81496acea..7aaa066c3 100644 --- a/test/qml/Global/+desktop/test_NavigationButton.qml +++ b/test/qml/Global/+desktop/test_NavigationButton.qml @@ -1,14 +1,15 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import Governikus.Global TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; NavigationButton {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; NavigationButton {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/Global/test_GGridView.qml b/test/qml/Global/+desktop/test_RetryCounter.qml similarity index 58% rename from test/qml/Global/test_GGridView.qml rename to test/qml/Global/+desktop/test_RetryCounter.qml index e27d4c889..6f6fa4d2b 100644 --- a/test/qml/Global/test_GGridView.qml +++ b/test/qml/Global/+desktop/test_RetryCounter.qml @@ -1,21 +1,22 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import Governikus.Global TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; GGridView {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; RetryCounter { width: 64; height: 64 }", testCase); } function test_load() { let testObject = createTestObject(); verify(testObject, "Object loaded"); } - name: "test_GGridView" + name: "test_RetryCounter" visible: true when: windowShown } diff --git a/test/qml/Global/+desktop/test_RoundedRectangle.qml b/test/qml/Global/+desktop/test_RoundedRectangle.qml index 0807eb3a9..f1d2acb21 100644 --- a/test/qml/Global/+desktop/test_RoundedRectangle.qml +++ b/test/qml/Global/+desktop/test_RoundedRectangle.qml @@ -1,14 +1,15 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import Governikus.Global TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; RoundedRectangle {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; RoundedRectangle {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/Global/+desktop/test_ScrollGradients.qml b/test/qml/Global/+desktop/test_ScrollGradients.qml index fad6db09d..9469288b4 100644 --- a/test/qml/Global/+desktop/test_ScrollGradients.qml +++ b/test/qml/Global/+desktop/test_ScrollGradients.qml @@ -1,14 +1,15 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import Governikus.Global TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; ScrollGradients {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; ScrollGradients {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/Global/+desktop/test_ScrollablePane.qml b/test/qml/Global/+desktop/test_ScrollablePane.qml index 229de2939..09e268115 100644 --- a/test/qml/Global/+desktop/test_ScrollablePane.qml +++ b/test/qml/Global/+desktop/test_ScrollablePane.qml @@ -1,14 +1,15 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import Governikus.Global TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; ScrollablePane {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; ScrollablePane {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/Global/+desktop/test_TabbedPane.qml b/test/qml/Global/+desktop/test_TabbedPane.qml index 89352f963..d0194543a 100644 --- a/test/qml/Global/+desktop/test_TabbedPane.qml +++ b/test/qml/Global/+desktop/test_TabbedPane.qml @@ -1,15 +1,16 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import QtQml.Models 2.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import QtQml.Models +import Governikus.Global TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; TabbedPane {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; TabbedPane {}", testCase); } function test_load() { let testObject = createTestObject(); @@ -28,6 +29,7 @@ TestCase { TabbedPane { id: testObject + sectionsModel: ["Item 0", "Item 1", "Item 2"] contentObjectModel: ObjectModel { diff --git a/test/qml/Global/+desktop/test_TitlePane.qml b/test/qml/Global/+desktop/test_TitlePane.qml new file mode 100644 index 000000000..0475e18f0 --- /dev/null +++ b/test/qml/Global/+desktop/test_TitlePane.qml @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ +import QtTest + +TestCase { + id: testCase + + function createTestObject() { + return createTemporaryQmlObject(" + import \"qrc:/qml/Governikus/TitleBar/+desktop/\" + TitlePane {} + ", testCase); + } + function test_load() { + let testObject = createTestObject(); + verify(testObject, "Object loaded"); + } +} diff --git a/test/qml/Global/+mobile/test_GCollapsibleSubButton.qml b/test/qml/Global/+mobile/test_GCollapsibleSubButton.qml new file mode 100644 index 000000000..5c16eab46 --- /dev/null +++ b/test/qml/Global/+mobile/test_GCollapsibleSubButton.qml @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick +import QtTest +import Governikus.Global + +TestCase { + id: testCase + + function createTestObject() { + return createTemporaryQmlObject("import Governikus.Global; GCollapsibleSubButton {}", testCase); + } + function test_image() { + let testObject = createTestObject(); + compare(testObject.image, "", "Initial no image"); + testObject.image = "qrc:///images/material_check.svg"; + compare(testObject.image, "qrc:///images/material_check.svg", "Image: qrc:///images/material_check.svg"); + } + function test_load() { + let testObject = createTestObject(); + verify(testObject, "Object loaded"); + } + function test_text() { + let testObject = createTestObject(); + compare(testObject.text, "", "Initial title: empty"); + testObject.text = "test"; + compare(testObject.text, "test", "text: test"); + } + + name: "test_GCollapsibleSubButton" + visible: true + when: windowShown +} diff --git a/test/qml/Global/+mobile/test_GOptionsContainer.qml b/test/qml/Global/+mobile/test_GOptionsContainer.qml new file mode 100644 index 000000000..9bbb0d14f --- /dev/null +++ b/test/qml/Global/+mobile/test_GOptionsContainer.qml @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick +import QtTest +import Governikus.Global + +TestCase { + id: testCase + + function createTestObject() { + return createTemporaryQmlObject("import Governikus.Global; GOptionsContainer {}", testCase); + } + function test_load() { + let testObject = createTestObject(); + verify(testObject, "Object loaded"); + } + function test_title() { + let testObject = createTestObject(); + compare(testObject.title, "", "Initial title: empty"); + testObject.title = "test"; + compare(testObject.title, "test", "title: test"); + } + + name: "test_GOptionsContainer" + visible: true + when: windowShown +} diff --git a/test/qml/Global/+mobile/test_ListItem.qml b/test/qml/Global/+mobile/test_ListItem.qml index 3a5663efe..94c2cd522 100644 --- a/test/qml/Global/+mobile/test_ListItem.qml +++ b/test/qml/Global/+mobile/test_ListItem.qml @@ -1,14 +1,15 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import Governikus.Global TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; ListItem {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; ListItem {}", testCase); } function test_icon() { let testObject = createTestObject(); diff --git a/test/qml/Global/+mobile/test_PaneTitle.qml b/test/qml/Global/+mobile/test_PaneTitle.qml index e0347944c..b1547421d 100644 --- a/test/qml/Global/+mobile/test_PaneTitle.qml +++ b/test/qml/Global/+mobile/test_PaneTitle.qml @@ -1,14 +1,15 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import Governikus.Global TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; PaneTitle {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; PaneTitle {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/Global/+mobile/test_SwipeActionDelegate.qml b/test/qml/Global/+mobile/test_SwipeActionDelegate.qml index 46e74560c..6b926949d 100644 --- a/test/qml/Global/+mobile/test_SwipeActionDelegate.qml +++ b/test/qml/Global/+mobile/test_SwipeActionDelegate.qml @@ -1,14 +1,15 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import Governikus.Global TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; SwipeActionDelegate {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; SwipeActionDelegate {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/Global/+mobile/test_TitledSeparator.qml b/test/qml/Global/+mobile/test_TitledSeparator.qml index 18ce4a7bc..32ae47431 100644 --- a/test/qml/Global/+mobile/test_TitledSeparator.qml +++ b/test/qml/Global/+mobile/test_TitledSeparator.qml @@ -1,14 +1,15 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import Governikus.Global TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; TitledSeparator {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; TitledSeparator {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/Global/test_Category.qml b/test/qml/Global/test_Category.qml deleted file mode 100644 index 124726482..000000000 --- a/test/qml/Global/test_Category.qml +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 - -TestCase { - id: testCase - function imageFileExists(pImageFilePath) { - var image = createTemporaryQmlObject("import QtQuick 2.15; Image {}", testCase); - if (image === null) { - return false; - } - image.source = pImageFilePath; - return (image.status === Image.Loading || image.status === Image.Ready); - } - function test_categories(data) { - compare(Category.displayString(data.category), data.string); - compare(Category.displayColor(data.category), data.color); - verify(imageFileExists(Category.backgroundImageSource(data.category))); - - // An empty category does not need a button - if (data.category !== "") { - verify(imageFileExists(Category.buttonImageSource(data.category))); - verify(imageFileExists(Category.imageSource(data.category))); - } - } - function test_categories_data() { - return [{ - "category": "", - "color": "#164a8c", - "string": "Provider" - }, { - "category": "all", - "color": "#164a8c", - "string": "All" - }, { - "category": "citizen", - "color": "#851e6b", - "string": "Citizen services" - }, { - "category": "insurance", - "color": "#53428c", - "string": "Insurances" - }, { - "category": "finance", - "color": "#693800", - "string": "Financials" - }, { - "category": "other", - "color": "#00828a", - "string": "Other services" - }]; - } - - name: "test_Category" - visible: true - when: windowShown -} diff --git a/test/qml/Global/test_ConfirmationPopup.qml b/test/qml/Global/test_ConfirmationPopup.qml index 8b37db5f3..3dd0ac4eb 100644 --- a/test/qml/Global/test_ConfirmationPopup.qml +++ b/test/qml/Global/test_ConfirmationPopup.qml @@ -1,15 +1,16 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import QtQuick.Controls +import Governikus.Global TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; ConfirmationPopup {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; ConfirmationPopup {}", testCase); } function test_cancelButtonText() { let testObject = createTestObject(); @@ -67,6 +68,7 @@ TestCase { ConfirmationPopup { id: testObject + width: 1000 onCancelled: text = "cancelled" diff --git a/test/qml/Global/test_Constants.qml b/test/qml/Global/test_Constants.qml index 85ae2a717..420d23cce 100644 --- a/test/qml/Global/test_Constants.qml +++ b/test/qml/Global/test_Constants.qml @@ -1,12 +1,13 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import Governikus.Global TestCase { id: testCase + function test_constantsExist() { compare(Constants.white, "#ffffff", "Constants.white exists"); compare(Constants.black, "#000000", "Constants.black exists"); diff --git a/test/qml/Global/test_GBusyIndicator.qml b/test/qml/Global/test_GBusyIndicator.qml index 1233e8f8a..a685e5179 100644 --- a/test/qml/Global/test_GBusyIndicator.qml +++ b/test/qml/Global/test_GBusyIndicator.qml @@ -1,14 +1,15 @@ /** * Copyright (c) 2022-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import Governikus.Global TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; GBusyIndicator {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; GBusyIndicator {}", testCase); } function test_factor() { let testObject = createTestObject(); diff --git a/test/qml/Global/test_GButton.qml b/test/qml/Global/test_GButton.qml index 48538e0e7..499784680 100644 --- a/test/qml/Global/test_GButton.qml +++ b/test/qml/Global/test_GButton.qml @@ -1,16 +1,20 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQml 2.15 -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQml +import QtQuick +import QtTest +import Governikus.Global +import Governikus.Style TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; GButton {}", testCase); + return createTemporaryQmlObject(" + import Governikus.Global + GButton {} + ", testCase); } function test_enableButton() { let testObject = createTestObject(); @@ -31,50 +35,88 @@ TestCase { verify(testObject, "Object loaded"); } function test_size(data) { - let button = createTemporaryQmlObject("import Governikus.Global 1.0; GButton {icon.source: \"" + data.icon + "\"; text: \"" + data.text + "\"}", testCase); + let button = createTemporaryQmlObject(" + import Governikus.Global + GButton { + icon.source: \"" + data.icon + "\" + text: \"" + data.text + "\" + } + ", testCase); tryCompare(button, "height", data.height); tryCompare(button, "width", data.width); + let buttonInLayout = createTemporaryQmlObject(" + import Governikus.Global + import QtQuick.Layouts + ColumnLayout { + readonly property alias buttonHeight: mybutton.height + readonly property alias buttonWidth: mybutton.width + width: 1000 + GButton { + id: mybutton + icon.source: \"" + data.icon + "\" + text: \"" + data.text + "\" + } + } + ", testCase); + tryCompare(buttonInLayout, "buttonHeight", data.height); + tryCompare(buttonInLayout, "buttonWidth", data.width); + let buttonSmallLayout = createTemporaryQmlObject(" + import Governikus.Global + import QtQuick.Layouts + ColumnLayout { + readonly property alias buttonHeight: mybutton.height + readonly property alias buttonWidth: mybutton.width + width: 75 + GButton { + id: mybutton + icon.source: \"" + data.icon + "\" + text: \"" + data.text + "\" + } + } + ", testCase); + tryCompare(buttonSmallLayout, "buttonHeight", data.height); + tryCompare(buttonSmallLayout, "buttonWidth", Math.min(data.width, Constants.is_desktop ? 120 : 80)); } function test_size_data() { - let text = createTemporaryQmlObject("import Governikus.Global 1.0; import Governikus.Style 1.0; GText {textStyle: Style.text.button; text: \"test test test test test test\"}", testCase); - verify(waitForRendering(text)); - let longTextWidth = Math.ceil(text.width); + let longText = createTemporaryQmlObject("import Governikus.Global; import Governikus.Style; GText {textStyle: Style.text.button; text: \"test test test test test test\"}", testCase); + verify(waitForRendering(longText)); + let longTextWidth = Math.ceil(longText.width); return [{ "tag": "noIconNoText", "icon": "", "text": "", - "height": 12, - "width": 16 + "height": Constants.is_desktop ? 40 : 39, + "width": Constants.is_desktop ? 120 : 80 }, { "tag": "noIconSmallText", "icon": "", "text": "t", - "height": Constants.is_desktop ? 39 : 40, - "width": Constants.is_desktop ? 59 : 112 + "height": Constants.is_desktop ? 40 : 39, + "width": Constants.is_desktop ? 120 : 80 }, { "tag": "noIconLongText", "icon": "", "text": "test test test test test test", - "height": Constants.is_desktop ? 39 : 40, + "height": Constants.is_desktop ? 40 : 39, "width": 16 + longTextWidth }, { "tag": "withIconNoText", - "icon": "qrc:///images/identify.svg", + "icon": "qrc:///images/npa.svg", "text": "", - "height": Constants.is_desktop ? 39 : 40, - "width": Constants.is_desktop ? 43 : 44 + "height": Constants.is_desktop ? 40 : 39, + "width": Constants.is_desktop ? 120 : 80 }, { "tag": "withIconSmallText", - "icon": "qrc:///images/identify.svg", + "icon": "qrc:///images/npa.svg", "text": "t", - "height": Constants.is_desktop ? 39 : 40, - "width": Constants.is_desktop ? (Qt.platform.os === "linux" ? 64 : 59) : 112 + "height": Constants.is_desktop ? 40 : 39, + "width": Constants.is_desktop ? 120 : 80 }, { "tag": "withIconLongText", - "icon": "qrc:///images/identify.svg", + "icon": "qrc:///images/npa.svg", "text": "test test test test test test", - "height": Constants.is_desktop ? 39 : 40, - "width": (Constants.is_desktop ? 49 : 54) + longTextWidth + "height": Constants.is_desktop ? 40 : 39, + "width": (Constants.is_desktop ? 50 : 53) + longTextWidth }]; } function test_text() { @@ -86,8 +128,8 @@ TestCase { function test_textStyle() { let testObject = createTestObject(); compare(testObject.textStyle, Style.text.button, "Initial textStyle: button"); - testObject.textStyle = Style.text.hint_warning; - compare(testObject.textStyle, Style.text.hint_warning, "textStyle: hint_warning"); + testObject.textStyle = Style.text.normal_warning; + compare(testObject.textStyle, Style.text.normal_warning, "textStyle: hint_warning"); } function test_tooltipText() { let testObject = createTestObject(); @@ -106,6 +148,7 @@ TestCase { GButton { id: testObject + icon.source: "qrc:///images/material_check.svg" text: "test" diff --git a/test/qml/Global/test_GCheckBox.qml b/test/qml/Global/test_GCheckBox.qml index fd8211a04..7bffd2432 100644 --- a/test/qml/Global/test_GCheckBox.qml +++ b/test/qml/Global/test_GCheckBox.qml @@ -1,14 +1,15 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import Governikus.Global TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; GCheckBox {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; GCheckBox {}", testCase); } function test_checked() { let testObject = createTestObject(); @@ -34,6 +35,7 @@ TestCase { GCheckBox { id: testObject + TestCase { function test_click() { testObject.checked = false; diff --git a/test/qml/Global/test_GComboBox.qml b/test/qml/Global/test_GComboBox.qml index a782aff60..eaffe6daf 100644 --- a/test/qml/Global/test_GComboBox.qml +++ b/test/qml/Global/test_GComboBox.qml @@ -1,21 +1,22 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import QtTest +import Governikus.Global +import Governikus.Style TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; GComboBox {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; GComboBox {}", testCase); } function test_initial() { let testObject = createTestObject(); compare(testObject.count, 0, "count: -1"); compare(testObject.currentIndex, -1, "currentIndex: -1"); - verify(!testObject.indicator.visible, "Indicator visible: false"); + verify(testObject.indicator.visible, "Indicator visible has to be: true"); } function test_load() { let testObject = createTestObject(); @@ -24,8 +25,8 @@ TestCase { function test_textStyle() { let testObject = createTestObject(); compare(testObject.textStyle, Style.text.normal, "Initial textStyle: normal"); - testObject.textStyle = Style.text.hint_warning; - compare(testObject.textStyle, Style.text.hint_warning, "textStyle: hint_warning"); + testObject.textStyle = Style.text.normal_warning; + compare(testObject.textStyle, Style.text.normal_warning, "textStyle: hint_warning"); } name: "test_GComboBox" @@ -34,8 +35,8 @@ TestCase { GComboBox { id: testObject + model: ["a", "b", "c", "d"] - textStyle: Style.text.hint TestCase { function test_click() { diff --git a/test/qml/Global/test_GFlickable.qml b/test/qml/Global/test_GFlickable.qml index f6ed02785..74f8bd86b 100644 --- a/test/qml/Global/test_GFlickable.qml +++ b/test/qml/Global/test_GFlickable.qml @@ -1,14 +1,15 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import Governikus.Global TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; GFlickable {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; GFlickable {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/Global/test_GFlickableColumnLayout.qml b/test/qml/Global/test_GFlickableColumnLayout.qml index 6324a2d05..80bf13023 100644 --- a/test/qml/Global/test_GFlickableColumnLayout.qml +++ b/test/qml/Global/test_GFlickableColumnLayout.qml @@ -1,14 +1,15 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import Governikus.Global TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; GFlickableColumnLayout {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; GFlickableColumnLayout {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/Global/test_GInformativeButton.qml b/test/qml/Global/test_GInformativeButton.qml index f430e3fcd..44c9601b2 100644 --- a/test/qml/Global/test_GInformativeButton.qml +++ b/test/qml/Global/test_GInformativeButton.qml @@ -1,15 +1,16 @@ /** * Copyright (c) 2022-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import QtTest +import Governikus.Global +import Governikus.Style TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; GInformativeButton {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; GInformativeButton {}", testCase); } function test_description() { let testObject = createTestObject(); @@ -42,8 +43,8 @@ TestCase { function test_textStyle() { let testObject = createTestObject(); compare(testObject.textStyle, Style.text.button, "Initial textStyle: button"); - testObject.textStyle = Style.text.hint_warning; - compare(testObject.textStyle, Style.text.hint_warning, "textStyle: hint_warning"); + testObject.textStyle = Style.text.normal_warning; + compare(testObject.textStyle, Style.text.normal_warning, "textStyle: hint_warning"); } name: "test_GInformativeButton" @@ -52,6 +53,7 @@ TestCase { GInformativeButton { id: testObject + icon.source: "qrc:///images/material_check.svg" scaleIcon: 0.5 text: "test" diff --git a/test/qml/Global/test_GListView.qml b/test/qml/Global/test_GListView.qml index d84c26017..a2eed4192 100644 --- a/test/qml/Global/test_GListView.qml +++ b/test/qml/Global/test_GListView.qml @@ -1,14 +1,15 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import Governikus.Global TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; GListView {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; GListView {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/Global/test_GPane.qml b/test/qml/Global/test_GPane.qml index d361cd324..61456dfb8 100644 --- a/test/qml/Global/test_GPane.qml +++ b/test/qml/Global/test_GPane.qml @@ -1,14 +1,15 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import Governikus.Global TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; GPane {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; GPane {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/Global/test_GPaneBackground.qml b/test/qml/Global/test_GPaneBackground.qml index 3740131a8..3813239cc 100644 --- a/test/qml/Global/test_GPaneBackground.qml +++ b/test/qml/Global/test_GPaneBackground.qml @@ -1,14 +1,15 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import Governikus.Global TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; GPaneBackground {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; GPaneBackground {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/Global/test_SearchBar.qml b/test/qml/Global/test_GPaneBackgroundDelegate.qml similarity index 58% rename from test/qml/Global/test_SearchBar.qml rename to test/qml/Global/test_GPaneBackgroundDelegate.qml index c6cb455d4..edb15aabd 100644 --- a/test/qml/Global/test_SearchBar.qml +++ b/test/qml/Global/test_GPaneBackgroundDelegate.qml @@ -1,21 +1,22 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import Governikus.Global TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; SearchBar {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; GPaneBackgroundDelegate {}", testCase); } function test_load() { let testObject = createTestObject(); verify(testObject, "Object loaded"); } - name: "test_SearchBar" + name: "test_GPaneBackgroundDelegate" visible: true when: windowShown } diff --git a/test/qml/Global/test_GRadioButton.qml b/test/qml/Global/test_GRadioButton.qml index cccb647b4..64c677057 100644 --- a/test/qml/Global/test_GRadioButton.qml +++ b/test/qml/Global/test_GRadioButton.qml @@ -1,15 +1,16 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import QtTest +import Governikus.Global +import Governikus.Style TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; GRadioButton {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; GRadioButton {}", testCase); } function test_icon() { let testObject = createTestObject(); @@ -30,8 +31,8 @@ TestCase { function test_textStyle() { let testObject = createTestObject(); compare(testObject.textStyle, Style.text.normal, "Initial textStyle: normal"); - testObject.textStyle = Style.text.hint_warning; - compare(testObject.textStyle, Style.text.hint_warning, "textStyle: hint_warning"); + testObject.textStyle = Style.text.normal_warning; + compare(testObject.textStyle, Style.text.normal_warning, "textStyle: hint_warning"); } function test_tintIcon() { let testObject = createTestObject(); @@ -47,10 +48,12 @@ TestCase { Item { GRadioButton { id: button_a + checked: true } GRadioButton { id: button_b + } TestCase { function test_selection() { diff --git a/test/qml/Global/test_GRepeater.qml b/test/qml/Global/test_GRepeater.qml index 24a962127..52c3afa1b 100644 --- a/test/qml/Global/test_GRepeater.qml +++ b/test/qml/Global/test_GRepeater.qml @@ -1,15 +1,16 @@ /** * Copyright (c) 2022-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtQml.Models 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtQml.Models +import QtTest +import Governikus.Global TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; GRepeater {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; GRepeater {}", testCase); } function test_load() { let testObject = createTestObject(); @@ -39,9 +40,11 @@ TestCase { Text { id: expected + } ListModel { id: testModel + ListElement { name: "Apple" } @@ -54,6 +57,7 @@ TestCase { } GRepeater { id: testObject1 + model: testModel Text { diff --git a/test/qml/Global/test_GScrollBar.qml b/test/qml/Global/test_GScrollBar.qml index 1a982edcd..7982530ce 100644 --- a/test/qml/Global/test_GScrollBar.qml +++ b/test/qml/Global/test_GScrollBar.qml @@ -1,14 +1,15 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import Governikus.Global TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; GScrollBar {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; GScrollBar {}", testCase); } function test_click() { let testObject = createTestObject(); diff --git a/test/qml/Global/test_GSeparator.qml b/test/qml/Global/test_GSeparator.qml index 9e2396514..9a230532e 100644 --- a/test/qml/Global/test_GSeparator.qml +++ b/test/qml/Global/test_GSeparator.qml @@ -1,14 +1,15 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import Governikus.Global TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; GSeparator {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; GSeparator {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/Global/+mobile/test_GSwitch.qml b/test/qml/Global/test_GSwitch.qml similarity index 78% rename from test/qml/Global/+mobile/test_GSwitch.qml rename to test/qml/Global/test_GSwitch.qml index 988e4e021..b2b39e197 100644 --- a/test/qml/Global/+mobile/test_GSwitch.qml +++ b/test/qml/Global/test_GSwitch.qml @@ -1,14 +1,15 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import Governikus.Global TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; GSwitch {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; GSwitch {}", testCase); } function test_checked() { let testObject = createTestObject(); diff --git a/test/qml/Global/test_GText.qml b/test/qml/Global/test_GText.qml index 1e4260c07..f0602c882 100644 --- a/test/qml/Global/test_GText.qml +++ b/test/qml/Global/test_GText.qml @@ -1,15 +1,16 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import QtTest +import Governikus.Global +import Governikus.Style TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; GText {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; GText {}", testCase); } function test_load() { let testObject = createTestObject(); @@ -24,8 +25,8 @@ TestCase { function test_textStyle() { let testObject = createTestObject(); compare(testObject.textStyle, Style.text.normal, "Initial textStyle: normal"); - testObject.textStyle = Style.text.hint_warning; - compare(testObject.textStyle, Style.text.hint_warning, "textStyle: hint_warning"); + testObject.textStyle = Style.text.normal_warning; + compare(testObject.textStyle, Style.text.normal_warning, "textStyle: hint_warning"); } name: "test_GText" @@ -34,6 +35,9 @@ TestCase { GText { id: testObject + + text: "initial text" + onLinkActivated: testObject.text = "link activated" TestCase { @@ -44,6 +48,50 @@ TestCase { compare(testObject.text, "link activated", "Link activated"); } + when: windowShown + } + } + GText { + id: testObject1 + + maximumLineCount: 3 + text: "initial text" + + TestCase { + function test_effectiveMaxLinesHeight_lineHeight() { + compare(testObject1.effectiveFirstLineHeight, testObject1.height); + compare(testObject1.effectiveMaxLinesHeight, testObject1.maximumLineCount * testObject1.height); + + // textStyle should change lineheights + let height_single = testObject1.effectiveFirstLineHeight; + let height_multi = testObject1.effectiveMaxLinesHeight; + testObject1.textStyle = Style.text.title; + verify(testObject1.effectiveFirstLineHeight !== height_single); + verify(testObject1.effectiveMaxLinesHeight !== height_multi); + + // lineHeight should change lineheights + height_single = testObject1.effectiveFirstLineHeight; + height_multi = testObject1.effectiveMaxLinesHeight; + testObject1.lineHeight = 2; + verify(testObject1.effectiveFirstLineHeight !== height_single); + verify(testObject1.effectiveMaxLinesHeight !== height_multi); + + // textStyle should no longer changelineheights because we + // replaced the binding of lineHeight to textStyle with 2 before + height_single = testObject1.effectiveFirstLineHeight; + height_multi = testObject1.effectiveMaxLinesHeight; + testObject1.textStyle = Style.text.normal; + verify(testObject1.effectiveFirstLineHeight === height_single); + verify(testObject1.effectiveMaxLinesHeight === height_multi); + + // lineHeight should still change lineheights + height_single = testObject1.effectiveFirstLineHeight; + height_multi = testObject1.effectiveMaxLinesHeight; + testObject1.lineHeight = 4; + verify(testObject1.effectiveFirstLineHeight !== height_single); + verify(testObject1.effectiveMaxLinesHeight !== height_multi); + } + when: windowShown } } diff --git a/test/qml/Global/test_GTextField.qml b/test/qml/Global/test_GTextField.qml index 37b06b637..ff639e8b8 100644 --- a/test/qml/Global/test_GTextField.qml +++ b/test/qml/Global/test_GTextField.qml @@ -1,15 +1,16 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import QtTest +import Governikus.Global +import Governikus.Style TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; GTextField {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; GTextField {}", testCase); } function test_enabled() { let testObject = createTestObject(); @@ -36,8 +37,8 @@ TestCase { function test_textStyle() { let testObject = createTestObject(); compare(testObject.textStyle, Style.text.normal, "Initial textStyle: normal"); - testObject.textStyle = Style.text.hint_warning; - compare(testObject.textStyle, Style.text.hint_warning, "textStyle: hint_warning"); + testObject.textStyle = Style.text.normal_warning; + compare(testObject.textStyle, Style.text.normal_warning, "textStyle: hint_warning"); } function test_valid() { let testObject = createTestObject(); diff --git a/test/qml/Global/test_Hint.qml b/test/qml/Global/test_Hint.qml index d1fff1dac..b9f3776db 100644 --- a/test/qml/Global/test_Hint.qml +++ b/test/qml/Global/test_Hint.qml @@ -1,14 +1,15 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import Governikus.Global TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; Hint {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; Hint {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/Global/+mobile/test_LabeledSwitch.qml b/test/qml/Global/test_LabeledSwitch.qml similarity index 80% rename from test/qml/Global/+mobile/test_LabeledSwitch.qml rename to test/qml/Global/test_LabeledSwitch.qml index 975d47579..6c2d41417 100644 --- a/test/qml/Global/+mobile/test_LabeledSwitch.qml +++ b/test/qml/Global/test_LabeledSwitch.qml @@ -1,14 +1,15 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import Governikus.Global TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; LabeledSwitch {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; LabeledSwitch {}", testCase); } function test_checked() { let testObject = createTestObject(); @@ -29,6 +30,9 @@ TestCase { verify(testObject, "Object loaded"); } function test_title() { + if (!Constants.is_desktop) { + skip("Skip test because of flaky behavior for mobile on Linux"); + } let testObject = createTestObject(); compare(testObject.title, "", "Initial title: empty"); testObject.title = "test"; diff --git a/test/qml/Global/test_LabeledText.qml b/test/qml/Global/test_LabeledText.qml index e74cccb23..14f83c9dd 100644 --- a/test/qml/Global/test_LabeledText.qml +++ b/test/qml/Global/test_LabeledText.qml @@ -1,14 +1,15 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import Governikus.Global TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; LabeledText {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; LabeledText {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/Global/test_NumberField.qml b/test/qml/Global/test_NumberField.qml index 119a3cc83..eb3473636 100644 --- a/test/qml/Global/test_NumberField.qml +++ b/test/qml/Global/test_NumberField.qml @@ -1,14 +1,15 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import Governikus.Global TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; NumberField {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; NumberField {}", testCase); } function test_append() { let testObject = createTestObject(); @@ -60,27 +61,6 @@ TestCase { testObject.removeLast(); compare(testObject.number, "", "Empty number"); } - function test_validInput() { - let testObject = createTestObject(); - verify(!testObject.validInput, "Initial validInput: false"); - verify(testObject.confirmedInput, "Initial confirmedInput: true"); - testObject.number = "123456"; - testObject.inputConfirmation = "123456"; - verify(testObject.validInput, "validInput: true"); - verify(testObject.confirmedInput, "confirmedInput: true"); - testObject.number = "12345"; - testObject.inputConfirmation = "123456"; - verify(!testObject.validInput, "short password validInput: false"); - verify(testObject.confirmedInput, "short password confirmedInput: false"); - testObject.number = "1"; - testObject.inputConfirmation = "123456"; - verify(!testObject.validInput, "mismatch password validInput: false"); - verify(testObject.confirmedInput, "mismatch password confirmedInput: false"); - testObject.number = "12345a"; - testObject.inputConfirmation = "123456"; - verify(!testObject.validInput, "invalid character password validInput: false"); - verify(!testObject.confirmedInput, "invalid character confirmedInput: false"); - } name: "test_NumberField" visible: true diff --git a/test/qml/Global/test_PkiSwitch.qml b/test/qml/Global/test_PkiSwitch.qml index 0c7549123..4ecab6045 100644 --- a/test/qml/Global/test_PkiSwitch.qml +++ b/test/qml/Global/test_PkiSwitch.qml @@ -1,14 +1,15 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import Governikus.Global TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; PkiSwitch {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; PkiSwitch { functionName: \"test\" }", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/Global/test_PrivacyStatement.qml b/test/qml/Global/test_PrivacyStatement.qml index f7919db69..b171fb7c5 100644 --- a/test/qml/Global/test_PrivacyStatement.qml +++ b/test/qml/Global/test_PrivacyStatement.qml @@ -1,14 +1,15 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import Governikus.Global TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; PrivacyStatement {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; PrivacyStatement {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/Global/test_ProxyCredentialsPopup.qml b/test/qml/Global/test_ProxyCredentialsPopup.qml index 264c9bd10..5b1bc9493 100644 --- a/test/qml/Global/test_ProxyCredentialsPopup.qml +++ b/test/qml/Global/test_ProxyCredentialsPopup.qml @@ -1,15 +1,16 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import QtQuick.Controls +import Governikus.Global TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; ProxyCredentialsPopup {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; ProxyCredentialsPopup {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/Global/test_StatusIcon.qml b/test/qml/Global/test_StatusIcon.qml deleted file mode 100644 index fc2e940c2..000000000 --- a/test/qml/Global/test_StatusIcon.qml +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 - -TestCase { - id: testCase - function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; StatusIcon { width: 64; height: 64 }", testCase); - } - function test_busy() { - let testObject = createTestObject(); - verify(!testObject.busy, "Initial busy: false"); - testObject.busy = true; - verify(testObject.busy, "Set busy: true"); - } - function test_icon() { - let testObject = createTestObject(); - compare(testObject.source, "", "Initial no image"); - testObject.source = "qrc:///images/material_check.svg"; - compare(testObject.source, "qrc:///images/material_check.svg", "Image: qrc:///images/material_check.svg"); - } - function test_load() { - let testObject = createTestObject(); - verify(testObject, "Object loaded"); - } - function test_text() { - let testObject = createTestObject(); - compare(testObject.text, "", "Initial text empty"); - testObject.text = "test"; - compare(testObject.text, "test", "Set text: test"); - } - - name: "test_StatusIcon" - visible: true - when: windowShown -} diff --git a/test/qml/Global/test_TintableIcon.qml b/test/qml/Global/test_TintableIcon.qml index 62968a711..7844c2c16 100644 --- a/test/qml/Global/test_TintableIcon.qml +++ b/test/qml/Global/test_TintableIcon.qml @@ -1,15 +1,16 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 -import Governikus.Style 1.0 +import QtQuick +import QtTest +import Governikus.Global +import Governikus.Style TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Global 1.0; TintableIcon {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; TintableIcon {}", testCase); } function test_fillMode() { let testObject = createTestObject(); @@ -27,7 +28,7 @@ TestCase { } function test_tintColor() { let testObject = createTestObject(); - compare(testObject.tintColor, Style.color.primary_text, "Initial tintColor: primary_text"); + compare(testObject.tintColor, Style.color.text, "Initial tintColor: text"); testObject.tintColor = "#000000"; compare(testObject.tintColor, "#000000", "Set tintColor"); } diff --git a/test/qml/Global/test_Utils.qml b/test/qml/Global/test_Utils.qml index cc39a2db9..43562a713 100644 --- a/test/qml/Global/test_Utils.qml +++ b/test/qml/Global/test_Utils.qml @@ -1,24 +1,17 @@ /** * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany */ -import QtTest 1.15 -import Governikus.Global 1.0 +import QtTest +import Governikus.Global TestCase { id: testCase + function test_escapeHtml() { compare(Utils.escapeHtml("a&b"), "a&b", "escape &"); compare(Utils.escapeHtml("
    "), "<br/>", "escape < and >"); compare(Utils.escapeHtml("\"Hello\""), ""Hello"", "escape \""); } - function test_helpTopicOf() { - let defaultHelpTopic = "defaultHelp"; - let componentWithoutHelp = createTemporaryQmlObject("import QtQuick 2.15; Item {}", testCase); - let componentWithHelp = createTemporaryQmlObject("import QtQuick 2.15; Item {property string helpTopic: \"dummyHelp\";}", testCase); - compare(Utils.helpTopicOf(null, defaultHelpTopic), defaultHelpTopic, "Get default help topic if component is null"); - compare(Utils.helpTopicOf(componentWithoutHelp, defaultHelpTopic), defaultHelpTopic, "Get default help topic if component got no helpTopic"); - compare(Utils.helpTopicOf(componentWithHelp, defaultHelpTopic), "dummyHelp", "Get component help topic"); - } function test_isSameDate() { let today = new Date; compare(Utils.isSameDate(today, today), true); diff --git a/test/qml/InformationView/+desktop/test_ReleaseNotes.qml b/test/qml/InformationView/+desktop/test_ReleaseNotes.qml index a5f022210..83bf3163b 100644 --- a/test/qml/InformationView/+desktop/test_ReleaseNotes.qml +++ b/test/qml/InformationView/+desktop/test_ReleaseNotes.qml @@ -1,8 +1,8 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 +import QtQuick +import QtTest TestCase { id: testCase @@ -12,7 +12,7 @@ TestCase { } function createTestObject() { - return createTemporaryQmlObject("import Governikus.InformationView 1.0; ReleaseNotes {}", testCase); + return createTemporaryQmlObject("import Governikus.InformationView; ReleaseNotes { width: 500 }", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/InformationView/+mobile/test_ReleaseNotes.qml b/test/qml/InformationView/+mobile/test_ReleaseNotes.qml index 96e265377..f668b32f0 100644 --- a/test/qml/InformationView/+mobile/test_ReleaseNotes.qml +++ b/test/qml/InformationView/+mobile/test_ReleaseNotes.qml @@ -1,12 +1,13 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtTest 1.15 +import QtTest TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.InformationView 1.0; ReleaseNotes {}", testCase); + return createTemporaryQmlObject("import Governikus.InformationView; ReleaseNotes { width: 500 }", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/InformationView/test_LicenseInformation.qml b/test/qml/InformationView/test_LicenseInformation.qml index 878d50415..21aa57c44 100644 --- a/test/qml/InformationView/test_LicenseInformation.qml +++ b/test/qml/InformationView/test_LicenseInformation.qml @@ -1,9 +1,9 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import Governikus.Global TestCase { id: testCase @@ -13,7 +13,7 @@ TestCase { } function createTestObject() { - return createTemporaryQmlObject("import Governikus.InformationView 1.0; LicenseInformation {}", testCase); + return createTemporaryQmlObject("import Governikus.InformationView; LicenseInformation {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/InformationView/test_ReleaseNotesView.qml b/test/qml/InformationView/test_ReleaseNotesView.qml index 06805dada..53607102b 100644 --- a/test/qml/InformationView/test_ReleaseNotesView.qml +++ b/test/qml/InformationView/test_ReleaseNotesView.qml @@ -1,13 +1,14 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtTest 1.15 -import Governikus.Global 1.0 +import QtTest +import Governikus.Global TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.InformationView 1.0; ReleaseNotesView {}", testCase); + return createTemporaryQmlObject("import Governikus.InformationView; ReleaseNotesView {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/Navigation/+mobile/test_Navigation.qml b/test/qml/Navigation/+mobile/test_Navigation.qml index d25b32fff..1198fc073 100644 --- a/test/qml/Navigation/+mobile/test_Navigation.qml +++ b/test/qml/Navigation/+mobile/test_Navigation.qml @@ -1,13 +1,14 @@ /** * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 +import QtQuick +import QtTest TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Navigation 1.0; Navigation {}", testCase); + return createTemporaryQmlObject("import Governikus.Navigation; Navigation {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/PasswordInfoView/+desktop/test_PasswordInfoView.qml b/test/qml/PasswordInfoView/+desktop/test_PasswordInfoView.qml index 27eeb7409..d5b264eb3 100644 --- a/test/qml/PasswordInfoView/+desktop/test_PasswordInfoView.qml +++ b/test/qml/PasswordInfoView/+desktop/test_PasswordInfoView.qml @@ -1,14 +1,15 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtTest 1.15 -import Governikus.PasswordInfoView 1.0 +import QtTest +import Governikus.PasswordInfoView TestCase { id: parent + function test_load_PasswordInfoView(data) { - var item = createTemporaryQmlObject(" - import Governikus.PasswordInfoView 1.0; + let item = createTemporaryQmlObject(" + import Governikus.PasswordInfoView PasswordInfoView { infoContent: PasswordInfoData { contentType: %1 @@ -24,8 +25,6 @@ TestCase { "contentType": PasswordInfoContent.Type.CAN }, { "contentType": PasswordInfoContent.Type.PUK - }, { - "contentType": PasswordInfoContent.Type.SMARTPHONE_AS_CARD_READER }]; } diff --git a/test/qml/Provider/+mobile/+phone/test_ProviderHeader.qml b/test/qml/Provider/+mobile/+phone/test_ProviderHeader.qml deleted file mode 100644 index 5af37b853..000000000 --- a/test/qml/Provider/+mobile/+phone/test_ProviderHeader.qml +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 - -TestCase { - id: testCase - - readonly property var sectionPageFlickable: GFlickable { - } - - function createTestObject() { - return createTemporaryQmlObject("import Governikus.Provider 1.0; ProviderHeader {}", testCase); - } - function test_load() { - let testObject = createTestObject(); - verify(testObject, "Object loaded"); - } - - name: "test_ProviderHeader" - visible: true - when: windowShown -} diff --git a/test/qml/Provider/+mobile/test_ProviderModelItem.qml b/test/qml/Provider/+mobile/test_ProviderModelItem.qml deleted file mode 100644 index 29098b60a..000000000 --- a/test/qml/Provider/+mobile/test_ProviderModelItem.qml +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtTest 1.15 - -TestCase { - id: testCase - function createTestObject() { - return createTemporaryQmlObject("import Governikus.Provider 1.0; ProviderModelItem {}", testCase); - } - function test_load() { - let testObject = createTestObject(); - verify(testObject, "Object loaded"); - } - - name: "test_ProviderModelItem" - visible: true - when: windowShown -} diff --git a/test/qml/QmlTestRunner.cpp b/test/qml/QmlTestRunner.cpp index c8bdc1e70..f5945c6ff 100644 --- a/test/qml/QmlTestRunner.cpp +++ b/test/qml/QmlTestRunner.cpp @@ -34,8 +34,9 @@ class QmlTestRunner Q_PROPERTY(QVariantMap safeAreaMargins MEMBER mSafeAreaMargins CONSTANT) Q_PROPERTY(bool highContrastEnabled MEMBER mFalse CONSTANT) Q_PROPERTY(QString platformStyle MEMBER mPlatformStyle CONSTANT) - Q_PROPERTY(bool isTabletLayout MEMBER isTabletLayout CONSTANT) Q_PROPERTY(QString fixedFontFamily MEMBER mFixedFontFamily CONSTANT) + Q_PROPERTY(qreal scaleFactor MEMBER mScaleFactor CONSTANT) + Q_PROPERTY(qreal fontScaleFactor MEMBER mFontScaleFactor CONSTANT) private: const bool mFalse = false; @@ -44,7 +45,8 @@ class QmlTestRunner }; QString mPlatformStyle; QString mFixedFontFamily; - bool isTabletLayout; + static constexpr qreal mScaleFactor = 0.6; + static constexpr qreal mFontScaleFactor = 1.0; QSharedPointer mMockNetworkManager; @@ -81,17 +83,18 @@ class QmlTestRunner void qmlEngineAvailable(QQmlEngine* pEngine) { pEngine->rootContext()->setContextProperty(QStringLiteral("plugin"), this); +#if (QT_VERSION < QT_VERSION_CHECK(6, 4, 2)) + pEngine->rootContext()->setContextProperty("hasBindingLoop", true); +#else + pEngine->rootContext()->setContextProperty("hasBindingLoop", false); +#endif connect(pEngine, &QQmlEngine::warnings, [](const QList& pWarnings){ bool fail = false; for (auto& warning : pWarnings) { qCritical() << warning; -#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 1)) - fail |= !warning.description().contains("QML Connections: Implicitly defined onFoo properties in Connections are deprecated. Use this syntax instead:"); -#else fail = true; -#endif } if (fail) @@ -103,7 +106,6 @@ class QmlTestRunner const QStringList selectors = QQmlFileSelector(pEngine).selector()->extraSelectors(); mPlatformStyle = selectors.join(QLatin1String(",")); - isTabletLayout = mPlatformStyle.contains("tablet"); mFixedFontFamily = QFontDatabase::systemFont(QFontDatabase::FixedFont).family(); } diff --git a/test/qml/RemoteServiceView/+mobile/test_RemoteServiceView.qml b/test/qml/RemoteServiceView/+mobile/test_RemoteServiceView.qml index 4f3582b88..33833b3af 100644 --- a/test/qml/RemoteServiceView/+mobile/test_RemoteServiceView.qml +++ b/test/qml/RemoteServiceView/+mobile/test_RemoteServiceView.qml @@ -1,8 +1,8 @@ /** * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 +import QtQuick +import QtTest TestCase { id: testCase @@ -12,7 +12,7 @@ TestCase { } function createTestObject() { - return createTemporaryQmlObject("import Governikus.RemoteServiceView 1.0; RemoteServiceView {}", testCase); + return createTemporaryQmlObject("import Governikus.RemoteServiceView; RemoteServiceView { width: 500 }", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/ResultView/+desktop/test_ResultView.qml b/test/qml/ResultView/+desktop/test_ResultView.qml new file mode 100644 index 000000000..b60c74164 --- /dev/null +++ b/test/qml/ResultView/+desktop/test_ResultView.qml @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick +import QtTest +import Governikus.Global +import Governikus.ResultView + +TestCase { + id: testCase + + function createTestObject() { + return createTemporaryQmlObject("import Governikus.ResultView; ResultView {}", testCase); + } + function test_load() { + let testObject = createTestObject(); + verify(testObject, "Object loaded"); + } + + name: "test_ResultView" + visible: true + when: windowShown +} diff --git a/test/qml/ResultView/+mobile/test_ResultErrorView.qml b/test/qml/ResultView/+mobile/test_ResultErrorView.qml index 4b73bbb15..a3ea70386 100644 --- a/test/qml/ResultView/+mobile/test_ResultErrorView.qml +++ b/test/qml/ResultView/+mobile/test_ResultErrorView.qml @@ -1,20 +1,21 @@ /** * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import Governikus.Global TestCase { id: testCase - function createTestObject() { - return createTemporaryQmlObject("import Governikus.ResultView 1.0; ResultErrorView {}", testCase); + + function createTestObject(pErrorCode = "") { + return createTemporaryQmlObject("import Governikus.ResultView; ResultErrorView { title: \"ResultErrorView\"; errorCode: \"%1\"}".arg(pErrorCode), testCase); } function test_hasErrorDetails() { let testObject = createTestObject(); compare(testObject.hasErrorDetails, false); - testObject.errorCode = "SomeErrorCode"; - compare(testObject.hasErrorDetails, true); + let testObjectWithErrorCode = createTestObject("SomeErrorCode"); + compare(testObjectWithErrorCode.hasErrorDetails, true); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/ResultView/+mobile/test_ResultView.qml b/test/qml/ResultView/+mobile/test_ResultView.qml new file mode 100644 index 000000000..0d8ec54a0 --- /dev/null +++ b/test/qml/ResultView/+mobile/test_ResultView.qml @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick +import QtTest +import Governikus.Global +import Governikus.ResultView + +TestCase { + id: testCase + + function createTestObject() { + return createTemporaryQmlObject("import Governikus.ResultView; ResultView { title: \"ResultView\" }", testCase); + } + function test_load() { + let testObject = createTestObject(); + verify(testObject, "Object loaded"); + } + + name: "test_ResultView" + visible: true + when: windowShown +} diff --git a/test/qml/ResultView/test_ResultView.qml b/test/qml/ResultView/test_ResultView.qml deleted file mode 100644 index f6015e07e..000000000 --- a/test/qml/ResultView/test_ResultView.qml +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 -import Governikus.ResultView 1.0 - -TestCase { - id: testCase - function createTestObject() { - return createTemporaryQmlObject("import Governikus.ResultView 1.0; ResultView {}", testCase); - } - function test_load() { - let testObject = createTestObject(); - verify(testObject, "Object loaded"); - } - function test_resultType() { - let testObject = createTestObject(); - compare(testObject.resultType, ResultView.Type.IsSuccess, "Initial resultType: IsSuccess"); - testObject.resultType = ResultView.Type.IsError; - compare(testObject.resultType, ResultView.Type.IsError, "resultType: IsError"); - testObject.resultType = ResultView.Type.IsInfo; - compare(testObject.resultType, ResultView.Type.IsInfo, "resultType: IsInfo"); - } - - name: "test_ResultView" - visible: true - when: windowShown -} diff --git a/test/qml/SettingsView/test_LanguageButtons.qml b/test/qml/SettingsView/+desktop/test_LanguageButtons.qml similarity index 77% rename from test/qml/SettingsView/test_LanguageButtons.qml rename to test/qml/SettingsView/+desktop/test_LanguageButtons.qml index 43667609f..d325c013d 100644 --- a/test/qml/SettingsView/test_LanguageButtons.qml +++ b/test/qml/SettingsView/+desktop/test_LanguageButtons.qml @@ -1,14 +1,15 @@ /** * Copyright (c) 2022-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import Governikus.Global TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.SettingsView 1.0; LanguageButtons {}", testCase); + return createTemporaryQmlObject("import Governikus.SettingsView; LanguageButtons {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/SettingsView/+desktop/test_TabbedReaderView.qml b/test/qml/SettingsView/+desktop/test_TabbedReaderView.qml index 4ee9be342..81d2dc61b 100644 --- a/test/qml/SettingsView/+desktop/test_TabbedReaderView.qml +++ b/test/qml/SettingsView/+desktop/test_TabbedReaderView.qml @@ -1,16 +1,17 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 +import QtQuick +import QtTest TestCase { id: testCase + function createTestObject() { return createTemporaryQmlObject(" - import QtQuick 2.15 - import QtQuick.Controls 2.15 - import Governikus.SettingsView 1.0 + import QtQuick + import QtQuick.Controls + import Governikus.SettingsView ApplicationWindow { menuBar: Item { diff --git a/test/qml/SettingsView/test_DarkModeButtons.qml b/test/qml/SettingsView/test_DarkModeButtons.qml new file mode 100644 index 000000000..65d1c3d1e --- /dev/null +++ b/test/qml/SettingsView/test_DarkModeButtons.qml @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick +import QtTest +import Governikus.Global + +TestCase { + id: testCase + + function createTestObject() { + return createTemporaryQmlObject("import Governikus.SettingsView; DarkModeButtons {}", testCase); + } + function test_load() { + let testObject = createTestObject(); + verify(testObject, "Object loaded"); + } + + name: "test_DarModeButtons" + visible: true + when: windowShown +} diff --git a/test/qml/SettingsView/test_SettingsView.qml b/test/qml/SettingsView/test_SettingsView.qml index e499ba18b..f0dcafb24 100644 --- a/test/qml/SettingsView/test_SettingsView.qml +++ b/test/qml/SettingsView/test_SettingsView.qml @@ -1,16 +1,17 @@ /** * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 +import QtQuick +import QtTest TestCase { id: testCase + function createTestObject() { return createTemporaryQmlObject(" - import QtQuick 2.15 - import QtQuick.Controls 2.15 - import Governikus.SettingsView 1.0 + import QtQuick + import QtQuick.Controls + import Governikus.SettingsView ApplicationWindow { menuBar: Item { diff --git a/test/qml/TutorialView/+desktop/test_TutorialView.qml b/test/qml/SetupAssistantView/+desktop/test_SetupAutostartView.qml similarity index 71% rename from test/qml/TutorialView/+desktop/test_TutorialView.qml rename to test/qml/SetupAssistantView/+desktop/test_SetupAutostartView.qml index a5e9560fd..6cfdbc7d0 100644 --- a/test/qml/TutorialView/+desktop/test_TutorialView.qml +++ b/test/qml/SetupAssistantView/+desktop/test_SetupAutostartView.qml @@ -1,22 +1,23 @@ /** * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany */ -import QtTest 1.15 +import QtTest TestCase { id: testCase + function createTestObject() { return createTemporaryQmlObject(" - import QtQuick 2.15 - import QtQuick.Controls 2.15 - import Governikus.TutorialView 1.0 + import QtQuick + import QtQuick.Controls + import Governikus.SetupAssistantView ApplicationWindow { menuBar: Item { function updateActions() {} } - SetupAssistantView {} + SetupAutostartView {} } ", testCase); } @@ -25,7 +26,7 @@ TestCase { verify(testObject, "Object loaded"); } - name: "test_TutorialView" + name: "test_SetupAutostartView" visible: true when: windowShown } diff --git a/test/qml/SmartView/+mobile/test_CheckSmartResultView.qml b/test/qml/SmartView/+mobile/test_CheckSmartResultView.qml new file mode 100644 index 000000000..cc3a23d6f --- /dev/null +++ b/test/qml/SmartView/+mobile/test_CheckSmartResultView.qml @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick 2.15 +import QtTest 1.15 +import Governikus.Type.SmartModel 1.0 + +TestCase { + id: testCase + + function createTestObject(result) { + return createTemporaryQmlObject("import \"qrc:/qml/Governikus/SmartView/+mobile\"; CheckSmartResultView { result: %1 }".arg(result), testCase); + } + function test_load(data) { + let testObject = createTestObject(data.result); + verify(testObject, "Object loaded"); + } + function test_load_data() { + return [{ + "result": SmartModel.SMART_UPDATING_STATUS + }, { + "result": SmartModel.SMART_UNAVAILABLE + }, { + "result": SmartModel.SMART_UNUSABLE + }, { + "result": SmartModel.SMART_NO_PROVISIONING + }, { + "result": SmartModel.SMART_NO_PERSONALIZATION + }, { + "result": -1 + }]; + } + + name: "test_CheckSmartResultView" + visible: true + when: windowShown +} diff --git a/test/qml/SmartView/+mobile/test_SmartView.qml b/test/qml/SmartView/+mobile/test_SmartView.qml index bd7c06bac..620ec884a 100644 --- a/test/qml/SmartView/+mobile/test_SmartView.qml +++ b/test/qml/SmartView/+mobile/test_SmartView.qml @@ -1,15 +1,16 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 -import Governikus.ResultView 1.0 +import QtQuick +import QtTest +import Governikus.Global +import Governikus.ResultView TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.SmartView 1.0; SmartView {}", testCase); + return createTemporaryQmlObject("import Governikus.SmartView; SmartView {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/TechnologyInfo/+mobile/test_TechnologyInfo.qml b/test/qml/TechnologyInfo/+mobile/test_TechnologyInfo.qml index 77deb1b8e..790da7e2b 100644 --- a/test/qml/TechnologyInfo/+mobile/test_TechnologyInfo.qml +++ b/test/qml/TechnologyInfo/+mobile/test_TechnologyInfo.qml @@ -1,13 +1,14 @@ /** * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 +import QtQuick +import QtTest TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.TechnologyInfo 1.0; TechnologyInfo {}", testCase); + return createTemporaryQmlObject("import Governikus.TechnologyInfo; TechnologyInfo {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/TitleBar/test_TitleBarButton.qml b/test/qml/TitleBar/+desktop/test_TitleBarButton.qml similarity index 68% rename from test/qml/TitleBar/test_TitleBarButton.qml rename to test/qml/TitleBar/+desktop/test_TitleBarButton.qml index 229e45740..30d8ce111 100644 --- a/test/qml/TitleBar/test_TitleBarButton.qml +++ b/test/qml/TitleBar/+desktop/test_TitleBarButton.qml @@ -1,13 +1,14 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 +import QtQuick +import QtTest TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.TitleBar 1.0; TitleBarButton {}", testCase); + return createTemporaryQmlObject("import Governikus.TitleBar; TitleBarButton {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/TitleBar/+desktop/test_CancelAction.qml b/test/qml/TitleBar/test_NavigationAction.qml similarity index 68% rename from test/qml/TitleBar/+desktop/test_CancelAction.qml rename to test/qml/TitleBar/test_NavigationAction.qml index 393c59c63..414554ea9 100644 --- a/test/qml/TitleBar/+desktop/test_CancelAction.qml +++ b/test/qml/TitleBar/test_NavigationAction.qml @@ -1,13 +1,14 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 +import QtQuick +import QtTest TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.TitleBar 1.0; CancelAction {}", testCase); + return createTemporaryQmlObject("import Governikus.TitleBar; NavigationAction {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/TitleBar/test_TitleBar.qml b/test/qml/TitleBar/test_TitleBar.qml index b49e79b85..0caa180a1 100644 --- a/test/qml/TitleBar/test_TitleBar.qml +++ b/test/qml/TitleBar/test_TitleBar.qml @@ -1,13 +1,14 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 +import QtQuick +import QtTest TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.TitleBar 1.0; TitleBar {}", testCase); + return createTemporaryQmlObject("import Governikus.TitleBar; TitleBar {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/View/test_SectionPage.qml b/test/qml/View/+desktop/test_SectionPage.qml similarity index 69% rename from test/qml/View/test_SectionPage.qml rename to test/qml/View/+desktop/test_SectionPage.qml index 321172cc9..917142025 100644 --- a/test/qml/View/test_SectionPage.qml +++ b/test/qml/View/+desktop/test_SectionPage.qml @@ -1,13 +1,14 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 +import QtQuick +import QtTest TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.View 1.0; SectionPage {}", testCase); + return createTemporaryQmlObject("import Governikus.View; SectionPage {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/View/+mobile/test_ContentArea.qml b/test/qml/View/+mobile/test_ContentArea.qml index a90b57579..287d14288 100644 --- a/test/qml/View/+mobile/test_ContentArea.qml +++ b/test/qml/View/+mobile/test_ContentArea.qml @@ -1,13 +1,14 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 +import QtQuick +import QtTest TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.View 1.0; ContentArea {}", testCase); + return createTemporaryQmlObject("import Governikus.View; ContentArea { width: 500 }", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/TutorialView/+mobile/test_TutorialView.qml b/test/qml/View/+mobile/test_SectionPage.qml similarity index 61% rename from test/qml/TutorialView/+mobile/test_TutorialView.qml rename to test/qml/View/+mobile/test_SectionPage.qml index 8dae65143..e3808b8c3 100644 --- a/test/qml/TutorialView/+mobile/test_TutorialView.qml +++ b/test/qml/View/+mobile/test_SectionPage.qml @@ -1,20 +1,21 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 +import QtQuick +import QtTest TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.TutorialView 1.0; TutorialView {}", testCase); + return createTemporaryQmlObject("import Governikus.View; SectionPage { title: \"SectionPage\" }", testCase); } function test_load() { let testObject = createTestObject(); verify(testObject, "Object loaded"); } - name: "test_TutorialView" + name: "test_SectionPage" visible: true when: windowShown } diff --git a/test/qml/View/+mobile/test_TabBarView.qml b/test/qml/View/+mobile/test_TabBarView.qml index c408f77b2..832c2f08a 100644 --- a/test/qml/View/+mobile/test_TabBarView.qml +++ b/test/qml/View/+mobile/test_TabBarView.qml @@ -1,13 +1,14 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 +import QtQuick +import QtTest TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.View 1.0; TabBarView {}", testCase); + return createTemporaryQmlObject("import Governikus.View; TabBarView {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/View/test_Controller.qml b/test/qml/View/test_Controller.qml index ccf65cf92..0f26b0a9e 100644 --- a/test/qml/View/test_Controller.qml +++ b/test/qml/View/test_Controller.qml @@ -1,13 +1,14 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 +import QtQuick +import QtTest TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.View 1.0; Controller {}", testCase); + return createTemporaryQmlObject("import Governikus.View; Controller {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/View/test_FocusFrame.qml b/test/qml/View/test_FocusFrame.qml index 66b4c8e59..c25d48c76 100644 --- a/test/qml/View/test_FocusFrame.qml +++ b/test/qml/View/test_FocusFrame.qml @@ -1,13 +1,14 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 +import QtQuick +import QtTest TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.View 1.0; FocusFrame {}", testCase); + return createTemporaryQmlObject("import Governikus.View; FocusFrame {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/View/test_FocusPoint.qml b/test/qml/View/test_FocusPoint.qml index 9dc859165..5e865bd28 100644 --- a/test/qml/View/test_FocusPoint.qml +++ b/test/qml/View/test_FocusPoint.qml @@ -1,13 +1,14 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 +import QtQuick +import QtTest TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.View 1.0; FocusPoint {}", testCase); + return createTemporaryQmlObject("import Governikus.View; FocusPoint {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/WhiteListClient/+mobile/test_WhiteListSurveyView.qml b/test/qml/WhiteListClient/+mobile/test_WhiteListSurveyView.qml index 89c1a0450..1e4bf21b3 100644 --- a/test/qml/WhiteListClient/+mobile/test_WhiteListSurveyView.qml +++ b/test/qml/WhiteListClient/+mobile/test_WhiteListSurveyView.qml @@ -1,13 +1,14 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 +import QtQuick +import QtTest TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.WhiteListClient 1.0; WhiteListSurveyView {}", testCase); + return createTemporaryQmlObject("import Governikus.WhiteListClient; WhiteListSurveyView {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/Workflow/+desktop/test_GeneralWorkflow.qml b/test/qml/Workflow/+desktop/test_GeneralWorkflow.qml index 8823d5b85..ccd87e2ec 100644 --- a/test/qml/Workflow/+desktop/test_GeneralWorkflow.qml +++ b/test/qml/Workflow/+desktop/test_GeneralWorkflow.qml @@ -1,15 +1,16 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 -import Governikus.Type.ReaderPlugIn 1.0 +import QtQuick +import QtTest +import Governikus.Global +import Governikus.Type.ReaderPlugIn TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Workflow 1.0; GeneralWorkflow {}", testCase); + return createTemporaryQmlObject("import Governikus.Workflow; GeneralWorkflow {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/Workflow/+mobile/test_GeneralWorkflow.qml b/test/qml/Workflow/+mobile/test_GeneralWorkflow.qml index 31fe4099e..ee50222d7 100644 --- a/test/qml/Workflow/+mobile/test_GeneralWorkflow.qml +++ b/test/qml/Workflow/+mobile/test_GeneralWorkflow.qml @@ -1,23 +1,29 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 -import Governikus.Type.ReaderPlugIn 1.0 +import QtQuick +import QtTest +import Governikus.Global +import Governikus.Type.ReaderPlugIn TestCase { id: testCase + function createTestObject() { return createTemporaryQmlObject(" - import QtQuick 2.15 - import Governikus.Workflow 1.0 - import Governikus.Type.ReaderPlugIn 1.0 - GeneralWorkflow { - workflowModel: Item { - property var readerPlugInType: ReaderPlugIn.NFC - property bool isSmartCardAllowed: false - property var supportedPlugInTypes: [ReaderPlugIn.NFC, ReaderPlugIn.REMOTE_IFD, ReaderPlugIn.SMART] + import QtQuick + import QtQuick.Controls + import Governikus.Workflow + import Governikus.Type.ReaderPlugIn + + ApplicationWindow { + menuBar: Item {} + GeneralWorkflow { + workflowModel: Item { + property var readerPlugInType: ReaderPlugIn.NFC + property bool isCurrentSmartCardAllowed: false + property var supportedPlugInTypes: [ReaderPlugIn.NFC, ReaderPlugIn.REMOTE_IFD, ReaderPlugIn.SMART] + } } } ", testCase); diff --git a/test/qml/Workflow/+mobile/test_NfcWorkflow.qml b/test/qml/Workflow/+mobile/test_NfcWorkflow.qml index 74aaf5b5e..f4c830a2a 100644 --- a/test/qml/Workflow/+mobile/test_NfcWorkflow.qml +++ b/test/qml/Workflow/+mobile/test_NfcWorkflow.qml @@ -1,14 +1,21 @@ /** * Copyright (c) 2020-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import Governikus.Global TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Workflow 1.0; NfcWorkflow {}", testCase); + return createTemporaryQmlObject(" + import Governikus.Workflow + NfcWorkflow { + width: 420 + height: 420 + } + ", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/Workflow/+mobile/test_SmartWorkflow.qml b/test/qml/Workflow/+mobile/test_SmartWorkflow.qml index fd1654934..c831e92b2 100644 --- a/test/qml/Workflow/+mobile/test_SmartWorkflow.qml +++ b/test/qml/Workflow/+mobile/test_SmartWorkflow.qml @@ -1,20 +1,23 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import Governikus.Global TestCase { id: testCase + function createTestObject() { return createTemporaryQmlObject(" - import QtQuick 2.15 - import Governikus.Workflow 1.0 + import QtQuick + import Governikus.Workflow SmartWorkflow { workflowModel: Item { - property bool isSmartCardAllowed: false + property bool isCurrentSmartCardAllowed: false } + width: 420 + height: 420 } ", testCase); } diff --git a/test/qml/Workflow/test_Workflow.qml b/test/qml/Workflow/test_Workflow.qml index 2f0bf1aa6..8203f7631 100644 --- a/test/qml/Workflow/test_Workflow.qml +++ b/test/qml/Workflow/test_Workflow.qml @@ -1,14 +1,15 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Global 1.0 +import QtQuick +import QtTest +import Governikus.Global TestCase { id: testCase + function createTestObject() { - return createTemporaryQmlObject("import Governikus.Workflow 1.0; Workflow {}", testCase); + return createTemporaryQmlObject("import Governikus.Workflow; Workflow {}", testCase); } function test_load() { let testObject = createTestObject(); diff --git a/test/qml/test_HistoryView.qml b/test/qml/test_HistoryView.qml deleted file mode 100644 index 7d655a2fb..000000000 --- a/test/qml/test_HistoryView.qml +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany - */ -import QtTest 1.15 - -TestCase { - id: parent - function test_load_HistoryView() { - var item = createTemporaryQmlObject(" - import Governikus.HistoryView 1.0; - HistoryView {} - ", parent); - item.destroy(); - } - - name: "ModuleImportTest" -} diff --git a/test/qml/test_MainView.qml b/test/qml/test_MainView.qml index 3722f9b8b..7a585e39d 100644 --- a/test/qml/test_MainView.qml +++ b/test/qml/test_MainView.qml @@ -1,13 +1,14 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtTest 1.15 +import QtTest TestCase { id: parent + function test_load_MainView() { - var item = createTemporaryQmlObject(" - import Governikus.MainView 1.0; + let item = createTemporaryQmlObject(" + import Governikus.MainView MainView {} ", parent); item.destroy(); diff --git a/test/qml/test_MoreView.qml b/test/qml/test_MoreView.qml index cee71b5f2..8a52f44a2 100644 --- a/test/qml/test_MoreView.qml +++ b/test/qml/test_MoreView.qml @@ -1,13 +1,14 @@ /** * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany */ -import QtTest 1.15 +import QtTest TestCase { id: parent + function test_load_MoreView() { - var item = createTemporaryQmlObject(" - import Governikus.MoreView 1.0; + let item = createTemporaryQmlObject(" + import Governikus.MoreView MoreView {} ", parent); item.destroy(); diff --git a/test/qml/test_ProviderView.qml b/test/qml/test_ProviderView.qml deleted file mode 100644 index 4011ca856..000000000 --- a/test/qml/test_ProviderView.qml +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany - */ -import QtTest 1.15 - -TestCase { - id: parent - function test_load_ProviderView() { - var item = createTemporaryQmlObject(" - import Governikus.ProviderView 1.0; - ProviderView {} - ", parent); - item.destroy(); - } - - name: "ModuleImportTest" -} diff --git a/test/qml/test_SelfAuthenticationView.qml b/test/qml/test_SelfAuthenticationView.qml index 13dbad88c..4c5ebbfa7 100644 --- a/test/qml/test_SelfAuthenticationView.qml +++ b/test/qml/test_SelfAuthenticationView.qml @@ -1,13 +1,14 @@ /** * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ -import QtTest 1.15 +import QtTest TestCase { id: parent + function test_load_SelfAuthenticationView() { - var item = createTemporaryQmlObject(" - import Governikus.SelfAuthenticationView 1.0; + let item = createTemporaryQmlObject(" + import Governikus.SelfAuthenticationView SelfAuthenticationView {} ", parent); item.destroy(); diff --git a/test/qml/test_Style.qml b/test/qml/test_Style.qml index 49c985d48..b4798a1a4 100644 --- a/test/qml/test_Style.qml +++ b/test/qml/test_Style.qml @@ -1,14 +1,15 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtTest 1.15 +import QtTest TestCase { id: parent + function test_load_Style() { - var item = createTemporaryQmlObject(" - import QtQuick 2.15; - import Governikus.Style 1.0; + let item = createTemporaryQmlObject(" + import QtQuick + import Governikus.Style Item {} ", parent); item.destroy(); diff --git a/test/qml/test_UiPluginQml.qml b/test/qml/test_UiPluginQml.qml index 86d03e03a..d41120e2d 100644 --- a/test/qml/test_UiPluginQml.qml +++ b/test/qml/test_UiPluginQml.qml @@ -1,17 +1,18 @@ /** * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import QtTest 1.15 -import Governikus.Type.UiModule 1.0 -import Governikus.Type.SettingsModel 1.0 +import QtQuick +import QtTest +import Governikus.Type.UiModule +import Governikus.Type.SettingsModel TestCase { id: testCase + function createTestObject() { return createTemporaryQmlObject(" - import QtQuick 2.15 - import Governikus.Type.UiModule 1.0 + import QtQuick + import Governikus.Type.UiModule Item { readonly property int v1: UiModule.CURRENT readonly property int v2: UiModule.DEFAULT @@ -19,13 +20,11 @@ TestCase { readonly property int v4: UiModule.PINMANAGEMENT readonly property int v5: UiModule.SETTINGS readonly property int v6: UiModule.HELP - readonly property int v7: UiModule.PROVIDER - readonly property int v8: UiModule.SELF_AUTHENTICATION - readonly property int v9: UiModule.HISTORY - readonly property int v10: UiModule.UPDATEINFORMATION - readonly property int v11: UiModule.REMOTE_SERVICE - readonly property int v12: UiModule.CHECK_ID_CARD - readonly property int v13: UiModule.SMART + readonly property int v7: UiModule.SELF_AUTHENTICATION + readonly property int v8: UiModule.UPDATEINFORMATION + readonly property int v9: UiModule.REMOTE_SERVICE + readonly property int v10: UiModule.CHECK_ID_CARD + readonly property int v11: UiModule.SMART_EID readonly property var testVar: UiModule.DEFAULT readonly property int testInt: UiModule.DEFAULT @@ -49,14 +48,11 @@ TestCase { verify(UiModule.IDENTIFY !== UiModule.PINMANAGEMENT); verify(UiModule.SETTINGS !== UiModule.TUTORIAL); verify(UiModule.TUTORIAL !== UiModule.HELP); - verify(UiModule.HELP !== UiModule.PROVIDER); - verify(UiModule.PROVIDER !== UiModule.SELF_AUTHENTICATION); - verify(UiModule.SELF_AUTHENTICATION !== UiModule.HISTORY); - verify(UiModule.HISTORY !== UiModule.UPDATEINFORMATION); + verify(UiModule.HELP !== UiModule.SELF_AUTHENTICATION); verify(UiModule.UPDATEINFORMATION !== UiModule.REMOTE_SERVICE); verify(UiModule.REMOTE_SERVICE !== UiModule.CHECK_ID_CARD); - verify(UiModule.CHECK_ID_CARD !== UiModule.SMART); - verify(UiModule.SMART !== UiModule.CURRENT); + verify(UiModule.CHECK_ID_CARD !== UiModule.SMART_EID); + verify(UiModule.SMART_EID !== UiModule.CURRENT); } function test_load() { let testObject = createTestObject(); diff --git a/test/qt/card/asn1/test_Asn1IntegerUtil.cpp b/test/qt/card/asn1/test_Asn1IntegerUtil.cpp index be8cb3376..8e1edc731 100644 --- a/test/qt/card/asn1/test_Asn1IntegerUtil.cpp +++ b/test/qt/card/asn1/test_Asn1IntegerUtil.cpp @@ -54,7 +54,7 @@ class test_Asn1IntegerUtil QFETCH(int, number); const uchar* dataPointer = reinterpret_cast(data.data()); - ASN1_INTEGER* asn1Integer = d2i_ASN1_INTEGER(nullptr, &dataPointer, data.length()); + ASN1_INTEGER* asn1Integer = d2i_ASN1_INTEGER(nullptr, &dataPointer, static_cast(data.length())); QCOMPARE(Asn1IntegerUtil::getValue(asn1Integer), number); ASN1_INTEGER_free(asn1Integer); } diff --git a/test/qt/card/asn1/test_Asn1OctetStringUtil.cpp b/test/qt/card/asn1/test_Asn1OctetStringUtil.cpp index 3b8d2e988..95f7c7438 100644 --- a/test/qt/card/asn1/test_Asn1OctetStringUtil.cpp +++ b/test/qt/card/asn1/test_Asn1OctetStringUtil.cpp @@ -40,7 +40,7 @@ class test_Asn1OctetStringUtil const auto guard = qScopeGuard([asn1OctetString] { ASN1_STRING_free(asn1OctetString); }); - ASN1_OCTET_STRING_set(asn1OctetString, reinterpret_cast(bytes.data()), bytes.length()); + ASN1_OCTET_STRING_set(asn1OctetString, reinterpret_cast(bytes.data()), static_cast(bytes.length())); QCOMPARE(Asn1OctetStringUtil::getValue(asn1OctetString), bytes); } diff --git a/test/qt/card/asn1/test_Asn1StringUtil.cpp b/test/qt/card/asn1/test_Asn1StringUtil.cpp index 7363285d1..6af8ba5e5 100644 --- a/test/qt/card/asn1/test_Asn1StringUtil.cpp +++ b/test/qt/card/asn1/test_Asn1StringUtil.cpp @@ -47,7 +47,7 @@ class test_Asn1StringUtil { QString utf8Text("Dieß öst äin UTF8-Đext ɃϢݢૂૂૂ"); ASN1_UTF8STRING* asn1String = ASN1_UTF8STRING_new(); - ASN1_STRING_set(asn1String, utf8Text.toUtf8().data(), utf8Text.toUtf8().length()); + ASN1_STRING_set(asn1String, utf8Text.toUtf8().data(), static_cast(utf8Text.toUtf8().length())); QCOMPARE(Asn1StringUtil::getValue(asn1String), utf8Text); diff --git a/test/qt/card/asn1/test_Asn1TypeUtil.cpp b/test/qt/card/asn1/test_Asn1TypeUtil.cpp index 32cd5ffef..0b315667e 100644 --- a/test/qt/card/asn1/test_Asn1TypeUtil.cpp +++ b/test/qt/card/asn1/test_Asn1TypeUtil.cpp @@ -34,7 +34,7 @@ class test_Asn1TypeUtil ASN1_TYPE* asn1Type = ASN1_TYPE_new(); ASN1_OCTET_STRING* asn1OctetString = ASN1_OCTET_STRING_new(); QByteArray octetBytes = QByteArray::fromHex("0123456789ABCDEF"); - ASN1_OCTET_STRING_set(asn1OctetString, reinterpret_cast(octetBytes.data()), octetBytes.length()); + ASN1_OCTET_STRING_set(asn1OctetString, reinterpret_cast(octetBytes.data()), static_cast(octetBytes.length())); ASN1_TYPE_set(asn1Type, V_ASN1_OCTET_STRING, asn1OctetString); QCOMPARE(Asn1TypeUtil::encode(asn1Type).toHex(), QByteArray("0408").append(octetBytes.toHex())); diff --git a/test/qt/card/asn1/test_CVCertificate.cpp b/test/qt/card/asn1/test_CVCertificate.cpp index a40148198..879bc491f 100644 --- a/test/qt/card/asn1/test_CVCertificate.cpp +++ b/test/qt/card/asn1/test_CVCertificate.cpp @@ -121,15 +121,9 @@ class test_CVCertificate auto cvca1 = CVCertificate::fromHex(TestFileHelper::readFile(":/card/cvca-DETESTeID00001.hex")); auto ecdsaSignature = cvca1->getEcdsaSignature(); - -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) - const BIGNUM* r = ecdsaSignature->r; - const BIGNUM* s = ecdsaSignature->s; -#else const BIGNUM* r = nullptr; const BIGNUM* s = nullptr; ECDSA_SIG_get0(ecdsaSignature, &r, &s); -#endif QCOMPARE(valueOf(r).toHex(), QByteArray("9f25ebfaf4b91e4c60a1683754c5dc076a3179753ef97d9f8cb01fe1dcd3b8c8")); QCOMPARE(valueOf(s).toHex(), QByteArray("3e7a26602ab1f344be5706006d79a9ff6a9716404dc83b9f30e1213b393128a2")); diff --git a/test/qt/card/asn1/test_CertificateDescription.cpp b/test/qt/card/asn1/test_CertificateDescription.cpp index 9d7b51f36..d44906225 100644 --- a/test/qt/card/asn1/test_CertificateDescription.cpp +++ b/test/qt/card/asn1/test_CertificateDescription.cpp @@ -318,7 +318,7 @@ class test_CertificateDescription Asn1StringUtil::setValue("https://www.redirect-test.de", certDescr->mRedirectURL); QByteArray termsOfUsageBytes = QByteArray::fromHex("4E616D652C20416E7363687269667420756E6420452D4D61696C2D4164726573736520646573204469656E737465616E626965746572733A0D0A476573616D7476657262616E64206465722064657574736368656E20566572736963686572756E67737769727473636861667420652E562E0D0A57696C68656C6D73747261C39F652034332F3433670D0A3130313137204265726C696E0D0A6265726C696E406764762E64650D0A0D0A4765736368C3A46674737A7765636B3A0D0A2D52656769737472696572756E6720756E64204C6F67696E20616D204744562D4D616B6C6572706F7274616C2D0D0A0D0A48696E7765697320617566206469652066C3BC722064656E204469656E737465616E626965746572207A757374C3A46E646967656E205374656C6C656E2C20646965206469652045696E68616C74756E672064657220566F7273636872696674656E207A756D20446174656E73636875747A206B6F6E74726F6C6C696572656E3A0D0A4265726C696E6572204265617566747261677465722066C3BC7220446174656E73636875747A20756E6420496E666F726D6174696F6E7366726569686569740D0A416E20646572205572616E696120342D31300D0A3130373837204265726C696E0D0A3033302F3133382038392D300D0A6D61696C626F7840646174656E73636875747A2D6265726C696E2E64650D0A687474703A2F2F7777772E646174656E73636875747A2D6265726C696E2E64650D0A416E737072656368706172746E65723A2044722E20416C6578616E64657220446978"); - ASN1_TYPE_set_octetstring(certDescr->mTermsOfUsage, reinterpret_cast(termsOfUsageBytes.data()), termsOfUsageBytes.length()); + ASN1_TYPE_set_octetstring(certDescr->mTermsOfUsage, reinterpret_cast(termsOfUsageBytes.data()), static_cast(termsOfUsageBytes.length())); { uchar buf[1024]; int buf_len = ASN1_TYPE_get_octetstring(certDescr->mTermsOfUsage, buf, 1024); @@ -330,11 +330,8 @@ class test_CertificateDescription QVERIFY(byteBuf.contains("Name, Anschrift und E-Mail-Adresse des Diensteanbieters:")); } -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) - certDescr->mCommCertificates = SKM_sk_new(ASN1_OCTET_STRING, nullptr); -#else certDescr->mCommCertificates = sk_ASN1_OCTET_STRING_new(nullptr); -#endif + QByteArrayList commCertBytes; commCertBytes.append(QByteArray::fromHex("94B0AA7E8114F3E6DFCD52DA9F43E8B13CCB0589B8957E364728198FB4971AE6")); commCertBytes.append(QByteArray::fromHex("E85E1E8A78864E9246C86CF1C2A3810603EEEE75746C70CD51ACB86B5E2655D8")); @@ -343,12 +340,8 @@ class test_CertificateDescription for (const auto& commCertByte : std::as_const(commCertBytes)) { ASN1_OCTET_STRING* octetString = ASN1_OCTET_STRING_new(); - ASN1_OCTET_STRING_set(octetString, reinterpret_cast(commCertByte.constData()), commCertByte.length()); -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) - SKM_sk_push(ASN1_OCTET_STRING, certDescr->mCommCertificates, octetString); -#else + ASN1_OCTET_STRING_set(octetString, reinterpret_cast(commCertByte.constData()), static_cast(commCertByte.length())); sk_ASN1_OCTET_STRING_push(certDescr->mCommCertificates, octetString); -#endif } { for (int i = 0; i < sk_ASN1_OCTET_STRING_num(certDescr->mCommCertificates); i++) diff --git a/test/qt/card/asn1/test_EcdsaPublicKey.cpp b/test/qt/card/asn1/test_EcdsaPublicKey.cpp index 99f638770..affd7b8e3 100644 --- a/test/qt/card/asn1/test_EcdsaPublicKey.cpp +++ b/test/qt/card/asn1/test_EcdsaPublicKey.cpp @@ -60,12 +60,7 @@ class test_EcdsaPublicKey const EC_GROUP* ecGroup = EC_KEY_get0_group(EVP_PKEY_get0_EC_KEY(pKey.data())); EC_GROUP_get_cofactor(ecGroup, *pCofactor, nullptr); EC_GROUP_get_order(ecGroup, *pOrder, nullptr); - - #if OPENSSL_VERSION_NUMBER < 0x10101000L || defined(LIBRESSL_VERSION_NUMBER) - EC_GROUP_get_curve_GFp(ecGroup, *pP, *pA, *pB, nullptr); - #else EC_GROUP_get_curve(ecGroup, *pP, *pA, *pB, nullptr); - #endif const EC_POINT* generator = EC_GROUP_get0_generator(ecGroup); auto bufLen = EC_POINT_point2oct(ecGroup, generator, point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED, nullptr, 0, nullptr); diff --git a/test/qt/card/asn1/test_efCardSecurity.cpp b/test/qt/card/asn1/test_efCardSecurity.cpp index 2dd8f4a3b..971b6ebcf 100644 --- a/test/qt/card/asn1/test_efCardSecurity.cpp +++ b/test/qt/card/asn1/test_efCardSecurity.cpp @@ -207,7 +207,7 @@ class test_efCardSecurity " 020145"); QSharedPointer bio(BIO_new(BIO_s_mem()), &BIO_free); QVERIFY(bio); - QVERIFY(BIO_write(bio.data(), secInfos.data(), secInfos.size()) > 0); + QVERIFY(BIO_write(bio.data(), secInfos.data(), static_cast(secInfos.size())) > 0); QSharedPointer cms(CMS_sign(cert.data(), key, nullptr, nullptr, CMS_PARTIAL | CMS_NOSMIMECAP), &CMS_ContentInfo_free); QVERIFY(cms); diff --git a/test/qt/card/base/command/test_DidAuthenticateEAC2Command.cpp b/test/qt/card/base/command/test_DidAuthenticateEAC2Command.cpp index d9d486f42..bc8eab2b8 100644 --- a/test/qt/card/base/command/test_DidAuthenticateEAC2Command.cpp +++ b/test/qt/card/base/command/test_DidAuthenticateEAC2Command.cpp @@ -8,6 +8,7 @@ #include "MockCardConnectionWorker.h" #include "TestFileHelper.h" +#include "asn1/ASN1Util.h" #include #include @@ -54,7 +55,7 @@ class test_DidAuthenticateEAC2Command { const auto& data = Asn1Util::encode(V_ASN1_UNIVERSAL, 17, pSecurityInfos.join(), true); QSharedPointer bio(BIO_new(BIO_s_mem()), &BIO_free); - BIO_write(bio.data(), data.data(), data.size()); + BIO_write(bio.data(), data.data(), static_cast(data.size())); QSharedPointer cms(CMS_sign(mCert.data(), mKey.data(), nullptr, nullptr, CMS_PARTIAL | CMS_NOSMIMECAP), &CMS_ContentInfo_free); CMS_set1_eContentType(cms.data(), OBJ_txt2obj("0.4.0.127.0.7.3.2.1", 1)); diff --git a/test/qt/card/base/pinpad/test_EstablishPaceChannelOutput.cpp b/test/qt/card/base/pinpad/test_EstablishPaceChannelOutput.cpp index 224203286..fb3d34cde 100644 --- a/test/qt/card/base/pinpad/test_EstablishPaceChannelOutput.cpp +++ b/test/qt/card/base/pinpad/test_EstablishPaceChannelOutput.cpp @@ -281,6 +281,7 @@ class test_EstablishPaceChannelOutput "9000"); EstablishPaceChannelOutput channelOutput; + QTest::ignoreMessage(QtWarningMsg, "Determine at least PACE return code by regular expression"); QVERIFY(channelOutput.parseFromCcid(QByteArray::fromHex(hexBytes))); QCOMPARE(channelOutput.getPaceReturnCode(), CardReturnCode::INVALID_PASSWORD); @@ -579,6 +580,27 @@ class test_EstablishPaceChannelOutput } + void outputDataWrongSize_data() + { + QTest::addColumn("data"); + + QTest::newRow("efCardAccess") << QByteArray::fromHex("9000020061"); + QTest::newRow("carCurr") << QByteArray::fromHex("900000000261"); + QTest::newRow("carPrev") << QByteArray::fromHex("90000000000261"); + QTest::newRow("idIcc") << QByteArray::fromHex("900000000000020061"); + } + + + void outputDataWrongSize() + { + QFETCH(QByteArray, data); + + EstablishPaceChannelOutput output; + QTest::ignoreMessage(QtDebugMsg, "Decapsulation of command failed. Wrong size."); + QVERIFY(!output.parseOutputData(data)); + } + + }; QTEST_GUILESS_MAIN(test_EstablishPaceChannelOutput) diff --git a/test/qt/card/base/test_CardInfo.cpp b/test/qt/card/base/test_CardInfo.cpp index a840f1f61..4e5d87713 100644 --- a/test/qt/card/base/test_CardInfo.cpp +++ b/test/qt/card/base/test_CardInfo.cpp @@ -2,13 +2,8 @@ * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ -/*! - * \brief Tests for \ref CardInfo. - */ - #include "CardInfo.h" - #include using namespace governikus; @@ -99,51 +94,6 @@ class test_CardInfo } - void test_checkEfCardAccess_data() - { - QTest::addColumn("efCardAccessBytes"); - QTest::addColumn("expectedResult"); - - QTest::newRow("No PACEInfo with domain parameters") - << QByteArray() - << false; - QTest::newRow("PACEInfo With domain parameters ") - << QByteArray("31 14" - " 30 12" - " 06 0A 04007F00070202040202" - " 02 01 02" - " 02 01 08") - << true; - QTest::newRow("Smart-eID without Security Mechanism") - << QByteArray("31 14" - " 30 12" - " 06 0A 04007F00070202040202" - " 02 01 02" - " 02 01 08") - << true; - QTest::newRow("Smart-eID with Security Mechanism") - << QByteArray("31 24" - " 30 12" - " 06 0A 04007F00070202040202" - " 02 01 02" - " 02 01 08" - " 30 0E" - " 06 0A 04007F00070302030201" - " 05 00") - << true; - } - - - void test_checkEfCardAccess() - { - QFETCH(QByteArray, efCardAccessBytes); - QFETCH(bool, expectedResult); - - auto efCardAccess = EFCardAccess::fromHex(efCardAccessBytes); - QCOMPARE(CardInfoFactory::checkEfCardAccess(efCardAccess), expectedResult); - } - - void test_RetryCounterDeterminated() { const CardInfo info1(CardType::EID_CARD); diff --git a/test/qt/card/base/test_CardInfoFactory.cpp b/test/qt/card/base/test_CardInfoFactory.cpp new file mode 100644 index 000000000..e99c18b80 --- /dev/null +++ b/test/qt/card/base/test_CardInfoFactory.cpp @@ -0,0 +1,65 @@ +/** + * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany + */ + +#include "CardInfoFactory.h" + +#include + +using namespace governikus; + +class test_CardInfoFactory + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void test_checkEfCardAccess_data() + { + QTest::addColumn("efCardAccessBytes"); + QTest::addColumn("expectedResult"); + + QTest::newRow("No PACEInfo with domain parameters") + << QByteArray() + << false; + QTest::newRow("PACEInfo With domain parameters ") + << QByteArray("31 14" + " 30 12" + " 06 0A 04007F00070202040202" + " 02 01 02" + " 02 01 08") + << true; + QTest::newRow("Smart-eID without Security Mechanism") + << QByteArray("31 14" + " 30 12" + " 06 0A 04007F00070202040202" + " 02 01 02" + " 02 01 08") + << true; + QTest::newRow("Smart-eID with Security Mechanism") + << QByteArray("31 24" + " 30 12" + " 06 0A 04007F00070202040202" + " 02 01 02" + " 02 01 08" + " 30 0E" + " 06 0A 04007F00070302030201" + " 05 00") + << true; + } + + + void test_checkEfCardAccess() + { + QFETCH(QByteArray, efCardAccessBytes); + QFETCH(bool, expectedResult); + + auto efCardAccess = EFCardAccess::fromHex(efCardAccessBytes); + QCOMPARE(CardInfoFactory::checkEfCardAccess(efCardAccess), expectedResult); + } + + +}; + +QTEST_GUILESS_MAIN(test_CardInfoFactory) +#include "test_CardInfoFactory.moc" diff --git a/test/qt/card/base/test_ReaderInfo.cpp b/test/qt/card/base/test_ReaderInfo.cpp index 7c75f3f8a..63c6ef1f3 100644 --- a/test/qt/card/base/test_ReaderInfo.cpp +++ b/test/qt/card/base/test_ReaderInfo.cpp @@ -31,12 +31,11 @@ class test_ReaderInfo QTest::addColumn("type"); QTest::addColumn("hasCard"); QTest::addColumn("hasEid"); - QTest::addColumn("physicalCard"); - QTest::newRow("none") << CardType::NONE << false << false << false; - QTest::newRow("unknown") << CardType::UNKNOWN << true << false << false; - QTest::newRow("eid-card") << CardType::EID_CARD << true << true << true; - QTest::newRow("smart-eid") << CardType::SMART_EID << true << true << false; + QTest::newRow("none") << CardType::NONE << false << false; + QTest::newRow("unknown") << CardType::UNKNOWN << true << false; + QTest::newRow("eid-card") << CardType::EID_CARD << true << true; + QTest::newRow("smart-eid") << CardType::SMART_EID << true << true; } @@ -45,14 +44,12 @@ class test_ReaderInfo QFETCH(CardType, type); QFETCH(bool, hasCard); QFETCH(bool, hasEid); - QFETCH(bool, physicalCard); const ReaderInfo info(QStringLiteral("Reader"), ReaderManagerPlugInType::UNKNOWN, CardInfo(type, nullptr, 3, false, false)); QCOMPARE(info.getCardType(), type); QCOMPARE(info.hasCard(), hasCard); QCOMPARE(info.hasEid(), hasEid); - QCOMPARE(info.isPhysicalCard(), physicalCard); } diff --git a/test/qt/card/base/test_ReaderManager.cpp b/test/qt/card/base/test_ReaderManager.cpp index aab17dc45..fe048e40e 100644 --- a/test/qt/card/base/test_ReaderManager.cpp +++ b/test/qt/card/base/test_ReaderManager.cpp @@ -46,8 +46,9 @@ class test_ReaderManager void initTestCase() { const auto readerManager = Env::getSingleton(); + QSignalSpy spy(readerManager, &ReaderManager::fireInitialized); readerManager->init(); - readerManager->isScanRunning(); // just to wait until initialization finished + QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations } diff --git a/test/qt/card/base/test_SmartCardDefinitions.cpp b/test/qt/card/base/test_SmartCardDefinitions.cpp new file mode 100644 index 000000000..852250beb --- /dev/null +++ b/test/qt/card/base/test_SmartCardDefinitions.cpp @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ + +#include "SmartCardDefinitions.h" + +#include + + +using namespace governikus; + + +class test_SmartCardDefinitions + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void conversion_data() + { + QTest::addColumn("acceptedType"); + QTest::addColumn("mobileType"); + + QTest::newRow("CARD_CERTIFIED") << AcceptedEidType::CARD_CERTIFIED << MobileEidType::UNKNOWN; + QTest::newRow("SE_CERTIFIED") << AcceptedEidType::SE_CERTIFIED << MobileEidType::SE_CERTIFIED; + QTest::newRow("SE_ENDORSED") << AcceptedEidType::SE_ENDORSED << MobileEidType::SE_ENDORSED; + QTest::newRow("HW_KEYSTORE") << AcceptedEidType::HW_KEYSTORE << MobileEidType::HW_KEYSTORE; + } + + + void conversion() + { + QFETCH(AcceptedEidType, acceptedType); + QFETCH(MobileEidType, mobileType); + + QCOMPARE(Enum::getValue(acceptedType), Enum::getValue(mobileType)); + QCOMPARE(static_cast(acceptedType), mobileType); + QCOMPARE(static_cast(mobileType), acceptedType); + } + + +}; + +QTEST_GUILESS_MAIN(test_SmartCardDefinitions) +#include "test_SmartCardDefinitions.moc" diff --git a/test/qt/card/drivers/test_ReaderDetector.cpp b/test/qt/card/drivers/test_ReaderDetector.cpp index f23631ca6..39abff19d 100644 --- a/test/qt/card/drivers/test_ReaderDetector.cpp +++ b/test/qt/card/drivers/test_ReaderDetector.cpp @@ -37,7 +37,7 @@ class test_ReaderDetector void verify_REINER_cyberJack_RFID_komfort(const ReaderConfigurationInfo& info) { QCOMPARE(info.getVendorId(), static_cast(0x0C4B)); - QCOMPARE(info.getProductId(), static_cast(0x0501)); + QCOMPARE(info.getProductIds(), QSet({static_cast(0x0501)})); QCOMPARE(info.getName(), QStringLiteral("REINER SCT cyberJack RFID komfort")); QCOMPARE(info.getPattern(), QStringLiteral("REINER SCT cyberJack RFID komfort")); QCOMPARE(info.getUrl(), KOMFORT_DRIVER_URL); diff --git a/test/qt/card/pcsc/test_PcscReader.cpp b/test/qt/card/pcsc/test_PcscReader.cpp index f20568661..30c31cc8a 100644 --- a/test/qt/card/pcsc/test_PcscReader.cpp +++ b/test/qt/card/pcsc/test_PcscReader.cpp @@ -37,7 +37,7 @@ class test_PcscReader QTest::ignoreMessage(QtDebugMsg, QStringLiteral("\"%1\"").arg(readerName).toUtf8().data()); reader.reset(new PcscReader(readerName)); - QCOMPARE(reader->init(), PcscUtils::Scard_S_Success); + QCOMPARE(reader->init(), pcsc::Scard_S_Success); QVERIFY(reader->hasFeature(FeatureID::TLV_PROPERTIES)); QCOMPARE(reader->getFeatureValue(FeatureID::TLV_PROPERTIES), 1110638610); diff --git a/test/qt/card/pcsc/test_PcscUtils.cpp b/test/qt/card/pcsc/test_PcscUtils.cpp index 2e1807ef1..350aa996d 100644 --- a/test/qt/card/pcsc/test_PcscUtils.cpp +++ b/test/qt/card/pcsc/test_PcscUtils.cpp @@ -2,10 +2,6 @@ * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany */ -/*! - * \brief Unit tests for \ref PcscUtils - */ - #include "PcscUtils.h" #include @@ -46,7 +42,7 @@ class test_PcscUtils { QFETCH(PCSC_RETURNCODE, code); - QCOMPARE(PcscUtils::toString(code), QString::fromLatin1(QTest::currentDataTag())); + QCOMPARE(pcsc::toString(code), QString::fromLatin1(QTest::currentDataTag())); } @@ -54,16 +50,34 @@ class test_PcscUtils { using uPCSC_RETURNCODE = std::make_unsigned_t; - const auto& getString = [](PcscUtils::PcscReturnCode pCode){ + const auto& getString = [](pcsc::PcscReturnCode pCode){ return QByteArray::fromStdString(std::to_string(static_cast(pCode))); }; const auto& str = QByteArray::fromStdString(std::to_string(static_cast(SCARD_F_INTERNAL_ERROR))); - QCOMPARE(getString(PcscUtils::Scard_F_Internal_Error), str); - QCOMPARE(getString(PcscUtils::Scard_F_Internal_Error), QByteArray("2148532225")); // 80100001 - QCOMPARE(getString(PcscUtils::Scard_E_Timeout), QByteArray("2148532234")); // 8010000a - QCOMPARE(getString(PcscUtils::Scard_S_Success), QByteArray("0")); - QCOMPARE(sizeof(PcscUtils::PcscReturnCode), sizeof(SCARD_F_INTERNAL_ERROR)); + QCOMPARE(getString(pcsc::Scard_F_Internal_Error), str); + QCOMPARE(getString(pcsc::Scard_F_Internal_Error), QByteArray("2148532225")); // 80100001 + QCOMPARE(getString(pcsc::Scard_E_Timeout), QByteArray("2148532234")); // 8010000a + QCOMPARE(getString(pcsc::Scard_S_Success), QByteArray("0")); + QCOMPARE(sizeof(pcsc::PcscReturnCode), sizeof(SCARD_F_INTERNAL_ERROR)); + } + + + void stream() + { + QByteArray data; + { + QDataStream outStream(&data, QIODeviceBase::WriteOnly); + outStream << pcsc::Scard_E_No_Service; + } + + pcsc::PcscReturnCode destination; + { + QDataStream inStream(data); + inStream >> destination; + } + + QCOMPARE(destination, pcsc::Scard_E_No_Service); } diff --git a/test/qt/card/smart/test_SmartManager.cpp b/test/qt/card/smart/test_SmartManager.cpp index aed337154..4560809e7 100644 --- a/test/qt/card/smart/test_SmartManager.cpp +++ b/test/qt/card/smart/test_SmartManager.cpp @@ -27,8 +27,9 @@ class test_SmartManager void initTestCase() { const auto readerManager = Env::getSingleton(); + QSignalSpy spy(readerManager, &ReaderManager::fireInitialized); readerManager->init(); - readerManager->isScanRunning(); // just to wait until initialization finished + QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations } @@ -77,23 +78,23 @@ class test_SmartManager void test_updateInfo_data() { - QTest::addColumn("updateInfo"); + QTest::addColumn("supportInfo"); - QTest::addRow("INTERNAL_ERROR") << EidUpdateInfo::INTERNAL_ERROR; - QTest::addRow("NO_PROVISIONING") << EidUpdateInfo::NO_PROVISIONING; - QTest::addRow("UNAVAILABLE") << EidUpdateInfo::UNAVAILABLE; - QTest::addRow("UPDATE_AVAILABLE") << EidUpdateInfo::UPDATE_AVAILABLE; - QTest::addRow("UP_TO_DATE") << EidUpdateInfo::UP_TO_DATE; + QTest::addRow("INTERNAL_ERROR") << EidSupportStatus::INTERNAL_ERROR; + QTest::addRow("AVAILABLE") << EidSupportStatus::AVAILABLE; + QTest::addRow("UNAVAILABLE") << EidSupportStatus::UNAVAILABLE; + QTest::addRow("UPDATE_AVAILABLE") << EidSupportStatus::UPDATE_AVAILABLE; + QTest::addRow("UP_TO_DATE") << EidSupportStatus::UP_TO_DATE; } void test_updateInfo() { - QFETCH(EidUpdateInfo, updateInfo); + QFETCH(EidSupportStatus, supportInfo); - Env::getSingleton()->callExecute([updateInfo] { - setUpdateInfo(updateInfo); - QCOMPARE(SmartManager::get()->updateInfo(), updateInfo); + Env::getSingleton()->callExecute([supportInfo] { + setSmartEidSupportStatus(supportInfo); + QCOMPARE(SmartManager::get()->updateSupportInfo().mStatus, supportInfo); }); } @@ -103,11 +104,11 @@ class test_SmartManager Env::getSingleton()->callExecute([] { const auto& smartManager = SmartManager::get(); - QVERIFY(!smartManager->deleteSmart()); + QCOMPARE(smartManager->deleteSmart(), EidServiceResult::UNSUPPORTED); setDeleteSmartEidResult(EidServiceResult::SUCCESS); - QVERIFY(smartManager->deleteSmart()); + QCOMPARE(smartManager->deleteSmart(), EidServiceResult::SUCCESS); QVERIFY(smartManager->status() == EidStatus::NO_PROVISIONING); }); } @@ -118,11 +119,11 @@ class test_SmartManager Env::getSingleton()->callExecute([] { const auto& smartManager = SmartManager::get(); - QVERIFY(!smartManager->installSmart()); + QCOMPARE(smartManager->installSmart(), EidServiceResult::UNSUPPORTED); setInstallSmartEidResult(EidServiceResult::SUCCESS); - QVERIFY(smartManager->installSmart()); + QCOMPARE(smartManager->installSmart(), EidServiceResult::SUCCESS); QVERIFY(smartManager->status() == EidStatus::NO_PERSONALIZATION); }); } diff --git a/test/qt/card/smart/test_SmartReader.cpp b/test/qt/card/smart/test_SmartReader.cpp index 979b706db..9f471a879 100644 --- a/test/qt/card/smart/test_SmartReader.cpp +++ b/test/qt/card/smart/test_SmartReader.cpp @@ -21,8 +21,9 @@ class test_SmartReader void initTestCase() { const auto readerManager = Env::getSingleton(); + QSignalSpy spy(readerManager, &ReaderManager::fireInitialized); readerManager->init(); - readerManager->isScanRunning(); // just to wait until initialization finished + QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations } @@ -36,7 +37,7 @@ class test_SmartReader { QTest::addColumn("status"); - QTest::newRow("unavailable") << EidStatus::UNAVAILABLE; + QTest::newRow("internal_error") << EidStatus::INTERNAL_ERROR; QTest::newRow("no_provisioning") << EidStatus::NO_PROVISIONING; QTest::newRow("no_personalization") << EidStatus::NO_PERSONALIZATION; QTest::newRow("personalized") << EidStatus::PERSONALIZED; @@ -50,7 +51,7 @@ class test_SmartReader Env::getSingleton()->callExecute([status] { setSmartEidStatus(status); - SmartReader reader; + SmartReader reader(QStringLiteral("Smart")); QCOMPARE(reader.getCard(), nullptr); QCOMPARE(reader.getReaderInfo().isInsertable(), false); diff --git a/test/qt/card/smart/test_SmartReaderManagerPlugIn.cpp b/test/qt/card/smart/test_SmartReaderManagerPlugIn.cpp index a59f5887d..5a962dd5e 100644 --- a/test/qt/card/smart/test_SmartReaderManagerPlugIn.cpp +++ b/test/qt/card/smart/test_SmartReaderManagerPlugIn.cpp @@ -2,39 +2,94 @@ * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -#include - +#include "AppSettings.h" +#include "ReaderManager.h" #include "SmartReaderManagerPlugIn.h" +#include +#include + using namespace governikus; +Q_DECLARE_METATYPE(ReaderInfo) + + class test_SmartReaderManagerPlugIn : public QObject { Q_OBJECT - private: - SmartReaderManagerPlugIn mPlugin; - private Q_SLOTS: void initTestCase() { - mPlugin.init(); + const auto readerManager = Env::getSingleton(); + QSignalSpy spy(readerManager, &ReaderManager::fireInitialized); + readerManager->init(); + QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations } - void getInfo() + void cleanupTestCase() { - const auto& info = mPlugin.getInfo(); - QCOMPARE(info.isAvailable(), false); + Env::getSingleton()->shutdown(); } - void getReader() + void initialization() { - QCOMPARE(mPlugin.getReaders().size(), 0); + Env::getSingleton()->callExecute([]{ + SmartReaderManagerPlugIn plugin; + plugin.init(); + QCOMPARE(plugin.getInfo().isAvailable(), false); + QCOMPARE(plugin.getReaders().size(), 0); + }); + + } + + + void availableChanged() + { + Env::getSingleton()->callExecute([]{ + SmartReaderManagerPlugIn plugin; + + QSignalSpy readerAddedSpy(&plugin, &SmartReaderManagerPlugIn::fireReaderAdded); + QSignalSpy readerUpdatedSpy(&plugin, &SmartReaderManagerPlugIn::fireReaderPropertiesUpdated); + QSignalSpy readerRemovedSpy(&plugin, &SmartReaderManagerPlugIn::fireReaderRemoved); + auto& settings = Env::getSingleton()->getGeneralSettings(); + + QCOMPARE(plugin.getReaders().size(), 0); + + settings.setSmartAvailable(true); + QCOMPARE(readerAddedSpy.count(), 1); + const auto& readerAddedInfo = readerAddedSpy.at(0).at(0).value(); + QCOMPARE(readerAddedInfo.getName(), QStringLiteral("Smart")); + QCOMPARE(readerAddedInfo.isValid(), true); + QCOMPARE(readerUpdatedSpy.count(), 0); + QCOMPARE(readerRemovedSpy.count(), 0); + QCOMPARE(plugin.getReaders().size(), 1); + QVERIFY(plugin.getReaders().at(0) != nullptr); + + settings.setSmartAvailable(false); + QCOMPARE(readerAddedSpy.count(), 1); + QCOMPARE(readerUpdatedSpy.count(), 1); + const auto& readerUpdatedInfo1 = readerUpdatedSpy.at(0).at(0).value(); + QCOMPARE(readerUpdatedInfo1.getName(), QStringLiteral("Smart")); + QCOMPARE(readerUpdatedInfo1.isValid(), false); + QCOMPARE(readerRemovedSpy.count(), 0); + QCOMPARE(plugin.getReaders().size(), 0); + + settings.setSmartAvailable(true); + QCOMPARE(readerAddedSpy.count(), 1); + QCOMPARE(readerUpdatedSpy.count(), 2); + const auto& readerUpdatedInfo2 = readerUpdatedSpy.at(1).at(0).value(); + QCOMPARE(readerUpdatedInfo2.getName(), QStringLiteral("Smart")); + QCOMPARE(readerUpdatedInfo2.isValid(), true); + QCOMPARE(readerRemovedSpy.count(), 0); + QCOMPARE(plugin.getReaders().size(), 1); + QVERIFY(plugin.getReaders().at(0) != nullptr); + }); } diff --git a/test/qt/card/smart/test_eid_applet_service.cpp b/test/qt/card/smart/test_eid_applet_service.cpp index bee15cb98..25913ab08 100644 --- a/test/qt/card/smart/test_eid_applet_service.cpp +++ b/test/qt/card/smart/test_eid_applet_service.cpp @@ -24,7 +24,7 @@ class test_EidAppletService void getSetSmartEidStatus() { - QCOMPARE(getSmartEidStatus(), EidStatus::UNAVAILABLE); + QCOMPARE(getSmartEidStatus(), EidStatus::INTERNAL_ERROR); setSmartEidStatus(EidStatus::PERSONALIZED); QCOMPARE(getSmartEidStatus(), EidStatus::PERSONALIZED); QCOMPARE(getSmartEidStatus(), EidStatus::PERSONALIZED); diff --git a/test/qt/configuration/test_ProviderConfiguration.cpp b/test/qt/configuration/test_ProviderConfiguration.cpp index 45a15dd50..8d6ccff67 100644 --- a/test/qt/configuration/test_ProviderConfiguration.cpp +++ b/test/qt/configuration/test_ProviderConfiguration.cpp @@ -302,7 +302,7 @@ class test_ProviderConfiguration } } - QCOMPARE(attachedEidCounter, 21); + QCOMPARE(attachedEidCounter, 19); } diff --git a/test/qt/configuration/test_ProviderConfigurationParser.cpp b/test/qt/configuration/test_ProviderConfigurationParser.cpp index ea39abd2d..67f3da3f3 100644 --- a/test/qt/configuration/test_ProviderConfigurationParser.cpp +++ b/test/qt/configuration/test_ProviderConfigurationParser.cpp @@ -224,8 +224,8 @@ class test_ProviderConfigurationParser QTest::addColumn("majorVersion"); QTest::addColumn("count"); - const int all = 120; - const int withEidSupport = 98; + const int all = 122; + const int withEidSupport = 100; QTest::newRow("win") << QOperatingSystemVersion::Windows << -1 << all; QTest::newRow("mac") << QOperatingSystemVersion::MacOS << -1 << all; QTest::newRow("linux") << QOperatingSystemVersion::Unknown << -1 << all; diff --git a/test/qt/configuration/test_ReaderConfiguration.cpp b/test/qt/configuration/test_ReaderConfiguration.cpp index dace0229c..3c8453820 100644 --- a/test/qt/configuration/test_ReaderConfiguration.cpp +++ b/test/qt/configuration/test_ReaderConfiguration.cpp @@ -9,7 +9,6 @@ #include "ReaderConfiguration.h" #include "Env.h" -#include "JsonValueRef.h" #include "MockReaderDetector.h" #include "ResourceLoader.h" #include "TestFileHelper.h" @@ -46,14 +45,14 @@ class test_ReaderConfiguration void checkPlatformsMinMax(const QJsonObject& pObject, const QLatin1String& pValue) { const QJsonArray& array = pObject[pValue].toArray(); - for (JsonValueRef entry : array) + for (const QJsonValueConstRef entry : array) { QVERIFY(entry.isObject()); auto object = entry.toObject(); QVERIFY(object.contains(QLatin1String("Platforms"))); const QJsonArray& platforms = object[QLatin1String("Platforms")].toArray(); - for (JsonValueRef platform : platforms) + for (const QJsonValueConstRef platform : platforms) { QVERIFY(platform.isObject()); auto platformObject = platform.toObject(); @@ -113,7 +112,7 @@ class test_ReaderConfiguration QTest::newRow("REINER SCT cyberJack RFID komfort FON") << UsbId(0x0C4B, 0x2007) << "REINER SCT cyberJack RFID komfort FON" << "REINER SCT cyberJack RFID komfort FON" << "img_Reiner_SCT_cyberjack_RFID_komfort" << "^REINER SCT cyberJack RFID komfort FON"; QTest::newRow("REINER SCT cyberJack RFID standard") << UsbId(0x0C4B, 0x0500) << "REINER SCT cyberJack RFID standard" << "REINER SCT cyberJack RFID standard" << "img_Reiner_SCT_cyberjack_RFID_standard" << "REINER SCT cyberJack RFID standard"; QTest::newRow("REINER SCT cyberJack RFID basis") << UsbId(0x0C4B, 0x9102) << "REINER SCT cyberJack RFID basis" << "REINER SCT cyberJack RFID basis" << "img_Reiner_SCT_cyberjack_RFID_basis" << "REINER SCT cyberJack RFID basis"; - QTest::newRow("REINER SCT cyberJack wave") << UsbId(0x0C4B, 0x0505) << "REINER SCT cyberJack wave" << "REINER SCT cyberJack wave" << "img_cyberjack_wave" << "REINER SCT cyberJack wave( USB 1)?$"; + QTest::newRow("REINER SCT cyberJack wave") << UsbId(0x0C4B, 0x0505) << "REINER SCT cyberJack wave" << "REINER SCT cyberJack wave" << "img_cyberjack_wave" << "REINER SCT cyberJack wave( USB)?( \\d{1,1})?$"; QTest::newRow("KOBIL IDToken") << UsbId(0x0D46, 0x301D) << "KOBIL Systems IDToken" << "KOBIL IDToken" << "img_KOBIL_ID_Token" << "^KOBIL (Systems )?IDToken( \\d{1,1})?$"; @@ -126,7 +125,7 @@ class test_ReaderConfiguration QTest::newRow("HID OMNIKEY 5022") << UsbId(0x076B, 0x5022) << "HID Global OMNIKEY 5022 Smart Card Reader 0" << "HID OMNIKEY 5022-CL" << "img_HID_Omnikey_Mobile_Reader_502X_CL" << "HID Global OMNIKEY 5022 Smart Card Reader( 0)?$"; QTest::newRow("HID OMNIKEY 5321 v2") << UsbId(0x076B, 0x5321) << "OOMNIKEY CardMan 5x21-CL 0" << "HID OMNIKEY 5321 v2" << "img_HID_Global_OMNIKEY_5321_V2" << R"(OMNIKEY CardMan 5x21-CL 0|OMNIKEY CardMan \(076B:5321\) 5321(\(1\)|\(2\)))"; QTest::newRow("HID OMNIKEY 5421") << UsbId(0x076B, 0x5421) << "OMNIKEY CardMan 5x21-CL 0" << "HID OMNIKEY 5421" << "img_HID_Omnikey_542x" << R"(OMNIKEY CardMan 5x21-CL 0|OMNIKEY Smart Card Reader USB 0|OMNIKEY CardMan \(076B:5421\) 5421(\(1\)|\(2\)))"; - QTest::newRow("HID OMNIKEY 5422") << UsbId(0x076B, 0x5422) << "HID Global OMNIKEY 5422CL Smartcard Reader 0" << "HID OMNIKEY 5422" << "img_HID_Omnikey_542x" << R"(HID Global OMNIKEY 5422CL Smartcard Reader 0|HID Global OMNIKEY Smartcard Reader (\(1\)|\(2\)))"; + QTest::newRow("HID OMNIKEY 5422") << UsbId(0x076B, 0x5422) << "HID Global OMNIKEY 5422CL Smartcard Reader 0" << "HID OMNIKEY 5422" << "img_HID_Omnikey_542x" << R"(HID Global OMNIKEY 5422CL Smartcard Reader 0|HID Global OMNIKEY Smartcard Reader ?(\(1\)|\(2\)))"; QTest::newRow("FEIG OBID myAXXESS RFID-Reader") << UsbId(0x0AB1, 0x0003) << "FEIG ELECTRONIC GmbH OBID myAXXESS basic Slot:CL 358334430" << "OBID RFID-Reader" << "img_FEIG_myAXXES_basic" << "FEIG ELECTRONIC GmbH OBID myAXXESS basic Slot:CL 358334430"; @@ -199,9 +198,10 @@ class test_ReaderConfiguration QTest::newRow("REINER SCT cyberJack RFID basis-windows-7-10") << UsbId(0x0C4B, 0x9102) << "REINER SCT cyberJack RFID basis 0" << "REINER SCT cyberJack RFID basis"; QTest::newRow("REINER SCT cyberJack RFID basis-macosx-10.13-11.0") << UsbId(0x0C4B, 0x9102) << "REINER SCT cyberJack RFID basis" << "REINER SCT cyberJack RFID basis"; - QTest::newRow("REINER SCT cyberJack wave-windows-7-10-1") << UsbId(0x0C4B, 0x0505) << "REINER SCT cyberJack wave 0" << "REINER SCT cyberJack wave 0"; - QTest::newRow("REINER SCT cyberJack wave-windows-7-10-2") << UsbId(0x0C4B, 0x0505) << "REINER SCT cyberJack wave USB 1" << "REINER SCT cyberJack wave"; - QTest::newRow("REINER SCT cyberJack wave-macosx-10.13-11.0") << UsbId(0x0C4B, 0x0505) << "REINER SCT cyberJack wave" << "REINER SCT cyberJack wave"; + QTest::newRow("REINER SCT cyberJack wave-windows-10-11-1") << UsbId(0x0C4B, 0x0505) << "REINER SCT cyberJack wave 0" << "REINER SCT cyberJack wave"; + QTest::newRow("REINER SCT cyberJack wave-windows-10-11-1") << UsbId(0x0C4B, 0x0505) << "REINER SCT cyberJack wave 1" << "REINER SCT cyberJack wave"; + QTest::newRow("REINER SCT cyberJack wave-windows-10-11-2") << UsbId(0x0C4B, 0x0505) << "REINER SCT cyberJack wave USB 1" << "REINER SCT cyberJack wave"; + QTest::newRow("REINER SCT cyberJack wave-macosx-11-13") << UsbId(0x0C4B, 0x0505) << "REINER SCT cyberJack wave" << "REINER SCT cyberJack wave"; QTest::newRow("KOBIL IDToken-windows-7-10-1") << UsbId(0x0D46, 0x301D) << "KOBIL IDToken 0" << "KOBIL IDToken"; QTest::newRow("KOBIL IDToken-windows-7-10-2") << UsbId(0x0D46, 0x301D) << "KOBIL IDToken 1" << "KOBIL IDToken"; @@ -211,47 +211,49 @@ class test_ReaderConfiguration QTest::newRow("KOBIL IDToken-macosx-10.13-11.0-2") << UsbId(0x0D46, 0x301D) << "KOBIL Systems IDToken 0" << "KOBIL IDToken"; QTest::newRow("KOBIL IDToken-macosx-10.13-11.0-3") << UsbId(0x0D46, 0x301D) << "KOBIL Systems IDToken 1" << "KOBIL IDToken"; - QTest::newRow("Identiv SDI011-windows-7-10-1") << UsbId(0x04E6, 0x512B) << "SCM Microsystems Inc. SDI011 Contactless Reader 0" << "Identiv SDI011 Dual Interface Smart Card Reader"; - QTest::newRow("Identiv SDI011-windows-7-10-2") << UsbId(0x04E6, 0x512B) << "SCM Microsystems Inc. SDI011 Smart Card Reader 0" << "SCM Microsystems Inc. SDI011 Smart Card Reader 0"; - QTest::newRow("Identiv SDI011-windows-7-10-3") << UsbId(0x04E6, 0x512B) << "SDI011 Contactless Reader" << "Identiv SDI011 Dual Interface Smart Card Reader"; - QTest::newRow("Identiv SDI011-windows-7-10-4") << UsbId(0x04E6, 0x512B) << "SCM Microsystems Inc. SDI011G Contactless Reader 0" << "Identiv SDI011 Dual Interface Smart Card Reader"; - QTest::newRow("Identiv SDI011-windows-7-10-5") << UsbId(0x04E6, 0x512B) << "SCM Microsystems Inc. SDI011G Smart Card Reader 0" << "SCM Microsystems Inc. SDI011G Smart Card Reader 0"; - QTest::newRow("Identiv SDI011-macosx-10.13-11.0") << UsbId(0x04E6, 0x512B) << "SDI011 USB Smart Card Reader(1)" << "Identiv SDI011 Dual Interface Smart Card Reader"; - QTest::newRow("Identiv SDI011-macosx-10.13-11.0") << UsbId(0x04E6, 0x512B) << "SDI011 USB Smart Card Reader(2)" << "Identiv SDI011 Dual Interface Smart Card Reader"; - QTest::newRow("Identiv SDI011-macosx-10.13-10.15-1") << UsbId(0x04E6, 0x512B) << "SCM Microsystems Inc. SDI011 Contactless Reader(1)" << "Identiv SDI011 Dual Interface Smart Card Reader"; - QTest::newRow("Identiv SDI011-macosx-10.13-10.15-2") << UsbId(0x04E6, 0x512B) << "SCM Microsystems Inc. SDI011 Contactless Reader(2)" << "Identiv SDI011 Dual Interface Smart Card Reader"; - - QTest::newRow("Identiv SCL011-windows-7-10-1") << UsbId(0x04E6, 0x5292) << "SCL011 Contactless Reader" << "Identiv SCL01x Contactless Smart Card Reader"; - QTest::newRow("Identiv SCL011-windows-7-10-2") << UsbId(0x04E6, 0x5292) << "SCM Microsystems Inc. SCL010 Contactless Reader" << "SCM Microsystems Inc. SCL010 Contactless Reader"; - QTest::newRow("Identiv SCL011-windows-7-10-3") << UsbId(0x04E6, 0x5292) << "SCM Microsystems Inc. SCL011 Contactless Reader 0" << "Identiv SCL01x Contactless Smart Card Reader"; - QTest::newRow("Identiv SCL011-windows-7-10-4") << UsbId(0x04E6, 0x5292) << "SCM Microsystems Inc. SCL011G Contactless Reader 0" << "Identiv SCL01x Contactless Smart Card Reader"; - QTest::newRow("Identiv SCL011-macosx-10.13-11.0-1") << UsbId(0x04E6, 0x5292) << "SCL011 Contactless Reader" << "Identiv SCL01x Contactless Smart Card Reader"; - QTest::newRow("Identiv SCL011-macosx-10.13-11.0-2") << UsbId(0x04E6, 0x5292) << "SCM Microsystems Inc. SCL011 Contactless Reader" << "Identiv SCL01x Contactless Smart Card Reader"; + QTest::newRow("Identiv SDI011-windows-10-11-1") << UsbId(0x04E6, 0x512B) << "SCM Microsystems Inc. SDI011 Contactless Reader 0" << "Identiv SDI011 Dual Interface Smart Card Reader"; + QTest::newRow("Identiv SDI011-windows-10-11-2") << UsbId(0x04E6, 0x512B) << "SCM Microsystems Inc. SDI011 Smart Card Reader 0" << "SCM Microsystems Inc. SDI011 Smart Card Reader 0"; + QTest::newRow("Identiv SDI011-windows-10-11-3") << UsbId(0x04E6, 0x512B) << "SDI011 Contactless Reader" << "Identiv SDI011 Dual Interface Smart Card Reader"; + QTest::newRow("Identiv SDI011-windows-10-11-4") << UsbId(0x04E6, 0x512B) << "SCM Microsystems Inc. SDI011G Contactless Reader 0" << "Identiv SDI011 Dual Interface Smart Card Reader"; + QTest::newRow("Identiv SDI011-windows-10-11-5") << UsbId(0x04E6, 0x512B) << "SCM Microsystems Inc. SDI011G Smart Card Reader 0" << "SCM Microsystems Inc. SDI011G Smart Card Reader 0"; + QTest::newRow("Identiv SDI011-macosx-11-13") << UsbId(0x04E6, 0x512B) << "SDI011 USB Smart Card Reader(1)" << "Identiv SDI011 Dual Interface Smart Card Reader"; + QTest::newRow("Identiv SDI011-macosx-11-13") << UsbId(0x04E6, 0x512B) << "SDI011 USB Smart Card Reader(2)" << "Identiv SDI011 Dual Interface Smart Card Reader"; + QTest::newRow("Identiv SDI011-macosx-11-13-1") << UsbId(0x04E6, 0x512B) << "SCM Microsystems Inc. SDI011 Contactless Reader(1)" << "Identiv SDI011 Dual Interface Smart Card Reader"; + QTest::newRow("Identiv SDI011-macosx-11-13-2") << UsbId(0x04E6, 0x512B) << "SCM Microsystems Inc. SDI011 Contactless Reader(2)" << "Identiv SDI011 Dual Interface Smart Card Reader"; + + QTest::newRow("Identiv SCL011-windows-10-11-1") << UsbId(0x04E6, 0x5292) << "SCL011 Contactless Reader" << "Identiv SCL01x Contactless Smart Card Reader"; + QTest::newRow("Identiv SCL011-windows-10-11-2") << UsbId(0x04E6, 0x5292) << "SCM Microsystems Inc. SCL010 Contactless Reader" << "SCM Microsystems Inc. SCL010 Contactless Reader"; + QTest::newRow("Identiv SCL011-windows-10-11-3") << UsbId(0x04E6, 0x5292) << "SCM Microsystems Inc. SCL011 Contactless Reader 0" << "Identiv SCL01x Contactless Smart Card Reader"; + QTest::newRow("Identiv SCL011-windows-10-11-4") << UsbId(0x04E6, 0x5292) << "SCM Microsystems Inc. SCL011G Contactless Reader 0" << "Identiv SCL01x Contactless Smart Card Reader"; + QTest::newRow("Identiv SCL011-macosx-11-13-1") << UsbId(0x04E6, 0x5292) << "SCL011 Contactless Reader" << "Identiv SCL01x Contactless Smart Card Reader"; + QTest::newRow("Identiv SCL011-macosx-11-13-2") << UsbId(0x04E6, 0x5292) << "SCM Microsystems Inc. SCL011 Contactless Reader" << "Identiv SCL01x Contactless Smart Card Reader"; QTest::newRow("ACS-ACR1281U-windows-7-10") << UsbId(0x072F, 0x0901) << "ACS ACR1281 PICC Reader 0" << "ACS ACR1281U"; QTest::newRow("ACS-ACR1281U-macosx-10.13-11.0") << UsbId(0x072F, 0x0901) << "ACS ACR1281 PICC Reader" << "ACS ACR1281U"; - QTest::newRow("HID OMNIKEY 5021-windows-7-10") << UsbId(0x076B, 0x5340) << "OMNIKEY CardMan 5x21-CL 0" << "HID OMNIKEY 5021-CL"; - QTest::newRow("HID OMNIKEY 5021-macosx-10.13-11.0") << UsbId(0x076B, 0x5340) << "OMNIKEY CardMan (076B:5340) 5021 CL" << "HID OMNIKEY 5021-CL"; + QTest::newRow("HID OMNIKEY 5021-windows-10-11") << UsbId(0x076B, 0x5340) << "OMNIKEY CardMan 5x21-CL 0" << "HID OMNIKEY 5021-CL"; + QTest::newRow("HID OMNIKEY 5021-macosx-11-13") << UsbId(0x076B, 0x5340) << "OMNIKEY CardMan (076B:5340) 5021 CL" << "HID OMNIKEY 5021-CL"; - QTest::newRow("HID OMNIKEY 5022-windows-7-10") << UsbId(0x076B, 0x5022) << "HID Global OMNIKEY 5022 Smart Card Reader 0" << "HID OMNIKEY 5022-CL"; - QTest::newRow("HID OMNIKEY 5022-macosx-10.13-11.0") << UsbId(0x076B, 0x5022) << "HID Global OMNIKEY 5022 Smart Card Reader" << "HID OMNIKEY 5022-CL"; + QTest::newRow("HID OMNIKEY 5022-windows-10-11") << UsbId(0x076B, 0x5022) << "HID Global OMNIKEY 5022 Smart Card Reader 0" << "HID OMNIKEY 5022-CL"; + QTest::newRow("HID OMNIKEY 5022-macosx-11-13") << UsbId(0x076B, 0x5022) << "HID Global OMNIKEY 5022 Smart Card Reader" << "HID OMNIKEY 5022-CL"; - QTest::newRow("HID OMNIKEY 5321 v2-windows-7-10-1") << UsbId(0x076B, 0x5321) << "OMNIKEY CardMan 5x21 0" << "OMNIKEY CardMan 5x21 0"; - QTest::newRow("HID OMNIKEY 5321 v2-windows-7-10-2") << UsbId(0x076B, 0x5321) << "OMNIKEY CardMan 5x21-CL 0" << "HID OMNIKEY 5321 v2"; - QTest::newRow("HID OMNIKEY 5321 v2-macosx-10.13-11.0-1") << UsbId(0x076B, 0x5321) << "OMNIKEY CardMan (076B:5321) 5321(1)" << "HID OMNIKEY 5321 v2"; - QTest::newRow("HID OMNIKEY 5321 v2-macosx-10.13-11.0-2") << UsbId(0x076B, 0x5321) << "OMNIKEY CardMan (076B:5321) 5321(2)" << "HID OMNIKEY 5321 v2"; + QTest::newRow("HID OMNIKEY 5321 v2-windows-10-11-1") << UsbId(0x076B, 0x5321) << "OMNIKEY CardMan 5x21 0" << "OMNIKEY CardMan 5x21 0"; + QTest::newRow("HID OMNIKEY 5321 v2-windows-10-11-2") << UsbId(0x076B, 0x5321) << "OMNIKEY CardMan 5x21-CL 0" << "HID OMNIKEY 5321 v2"; + QTest::newRow("HID OMNIKEY 5321 v2-macosx-11-14-1") << UsbId(0x076B, 0x5321) << "OMNIKEY CardMan (076B:5321) 5321(1)" << "HID OMNIKEY 5321 v2"; + QTest::newRow("HID OMNIKEY 5321 v2-macosx-11-14-2") << UsbId(0x076B, 0x5321) << "OMNIKEY CardMan (076B:5321) 5321(2)" << "HID OMNIKEY 5321 v2"; - QTest::newRow("HID OMNIKEY 5421-windows-7-10-1") << UsbId(0x076B, 0x5421) << "OMNIKEY CardMan 5x21 0" << "OMNIKEY CardMan 5x21 0"; - QTest::newRow("HID OMNIKEY 5421-windows-7-10-2") << UsbId(0x076B, 0x5421) << "OMNIKEY CardMan 5x21-CL 0" << "HID OMNIKEY 5421"; - QTest::newRow("HID OMNIKEY 5421-windows-7-10-3") << UsbId(0x076B, 0x5421) << "OMNIKEY Smart Card Reader USB 0" << "HID OMNIKEY 5421"; - QTest::newRow("HID OMNIKEY 5421-macosx-10.13-11.0-1") << UsbId(0x076B, 0x5421) << "OMNIKEY CardMan (076B:5421) 5421(1)" << "HID OMNIKEY 5421"; - QTest::newRow("HID OMNIKEY 5421-macosx-10.13-11.0-2") << UsbId(0x076B, 0x5421) << "OMNIKEY CardMan (076B:5421) 5421(2)" << "HID OMNIKEY 5421"; + QTest::newRow("HID OMNIKEY 5421-windows-10-11-1") << UsbId(0x076B, 0x5421) << "OMNIKEY CardMan 5x21 0" << "OMNIKEY CardMan 5x21 0"; + QTest::newRow("HID OMNIKEY 5421-windows-10-11-2") << UsbId(0x076B, 0x5421) << "OMNIKEY CardMan 5x21-CL 0" << "HID OMNIKEY 5421"; + QTest::newRow("HID OMNIKEY 5421-windows-10-11-3") << UsbId(0x076B, 0x5421) << "OMNIKEY Smart Card Reader USB 0" << "HID OMNIKEY 5421"; + QTest::newRow("HID OMNIKEY 5421-macosx-11-13-1") << UsbId(0x076B, 0x5421) << "OMNIKEY CardMan (076B:5421) 5421(1)" << "HID OMNIKEY 5421"; + QTest::newRow("HID OMNIKEY 5421-macosx-11-13-2") << UsbId(0x076B, 0x5421) << "OMNIKEY CardMan (076B:5421) 5421(2)" << "HID OMNIKEY 5421"; - QTest::newRow("HID OMNIKEY 5422-windows-7-10-1") << UsbId(0x076B, 0x5422) << "HID Global OMNIKEY 5422 Smartcard Reader 0" << "HID Global OMNIKEY 5422 Smartcard Reader 0"; - QTest::newRow("HID OMNIKEY 5422-windows-7-10-2") << UsbId(0x076B, 0x5422) << "HID Global OMNIKEY 5422CL Smartcard Reader 0" << "HID OMNIKEY 5422"; - QTest::newRow("HID OMNIKEY 5422-macosx-10.13-11.0-1") << UsbId(0x076B, 0x5422) << "HID Global OMNIKEY Smartcard Reader (1)" << "HID OMNIKEY 5422"; - QTest::newRow("HID OMNIKEY 5422-macosx-10.13-11.0-2") << UsbId(0x076B, 0x5422) << "HID Global OMNIKEY Smartcard Reader (2)" << "HID OMNIKEY 5422"; + QTest::newRow("HID OMNIKEY 5422-windows-10-11-1") << UsbId(0x076B, 0x5422) << "HID Global OMNIKEY 5422 Smartcard Reader 0" << "HID Global OMNIKEY 5422 Smartcard Reader 0"; + QTest::newRow("HID OMNIKEY 5422-windows-10-11-2") << UsbId(0x076B, 0x5422) << "HID Global OMNIKEY 5422CL Smartcard Reader 0" << "HID OMNIKEY 5422"; + QTest::newRow("HID OMNIKEY 5422-macosx-11-13-1") << UsbId(0x076B, 0x5422) << "HID Global OMNIKEY Smartcard Reader (1)" << "HID OMNIKEY 5422"; + QTest::newRow("HID OMNIKEY 5422-macosx-11-13-2") << UsbId(0x076B, 0x5422) << "HID Global OMNIKEY Smartcard Reader (2)" << "HID OMNIKEY 5422"; + QTest::newRow("HID OMNIKEY 5422-macosx-11-13-3") << UsbId(0x076B, 0x5422) << "HID Global OMNIKEY Smartcard Reader(1)" << "HID OMNIKEY 5422"; + QTest::newRow("HID OMNIKEY 5422-macosx-11-13-4") << UsbId(0x076B, 0x5422) << "HID Global OMNIKEY Smartcard Reader(2)" << "HID OMNIKEY 5422"; QTest::newRow("FEIG OBID myAXXESS RFID-Reader-windows-7-10") << UsbId(0x0AB1, 0x0003) << "FEIG ELECTRONIC GmbH OBID myAXXESS basic Slot:CL 358334430" << "OBID RFID-Reader"; @@ -265,20 +267,20 @@ class test_ReaderConfiguration QTest::newRow("Gemalto-Prox-SU-windows-macosx-10.13-11.0-1") << UsbId(0x08E6, 0x5504) << "Gemalto Prox SU USB PC LinkReader(1)" << "Gemalto Prox-SU Contactless"; QTest::newRow("Gemalto-Prox-SU-windows-macosx-10.13-11.0-2") << UsbId(0x08E6, 0x5504) << "Gemalto Prox SU USB PC LinkReader(2)" << "Gemalto Prox-SU Contactless"; - QTest::newRow("Identiv-SCL-3711-windows-7-10") << UsbId(0x04E6, 0x5591) << "SCM Microsystems SCL3711 reader & NFC device 0" << "Identiv SCL3711"; - QTest::newRow("Identiv-SCL-3711--F-macosx-10.12") << UsbId(0x04E6, 0x5591) << "SCL3711 Reader and NFC device" << "Identiv SCL3711"; - QTest::newRow("Identiv-SCL-3711--F-macosx-10.14-11.0") << UsbId(0x04E6, 0x5591) << "SCL3711 Reader and NFC device" << "Identiv SCL3711"; + QTest::newRow("Identiv-SCL-3711-windows-10-11") << UsbId(0x04E6, 0x5591) << "SCM Microsystems SCL3711 reader & NFC device 0" << "Identiv SCL3711"; + QTest::newRow("Identiv-SCL-3711--F-macosx-11-13") << UsbId(0x04E6, 0x5591) << "SCL3711 Reader and NFC device" << "Identiv SCL3711"; + QTest::newRow("Identiv-SCL-3711--F-macosx-11-13") << UsbId(0x04E6, 0x5591) << "SCL3711 Reader and NFC device" << "Identiv SCL3711"; - QTest::newRow("Identiv-3700-F-windows-7-10") << UsbId(0x04E6, 0x5790) << "Identiv CLOUD 3700 F Contactless Reader 0" << "Identiv 3700 F"; - QTest::newRow("Identiv-3700-F-macosx-10.13-11.0") << UsbId(0x04E6, 0x5790) << "Identiv uTrust 3700 F CL Reader" << "Identiv 3700 F"; + QTest::newRow("Identiv-3700-F-windows-10-11") << UsbId(0x04E6, 0x5790) << "Identiv CLOUD 3700 F Contactless Reader 0" << "Identiv 3700 F"; + QTest::newRow("Identiv-3700-F-macosx-11-13") << UsbId(0x04E6, 0x5790) << "Identiv uTrust 3700 F CL Reader" << "Identiv 3700 F"; QTest::newRow("Identiv-3700-F-generic-1") << UsbId(0x04E6, 0x5790) << "Identiv uTrust 3700 F CL Reader 0" << "Identiv 3700 F"; QTest::newRow("Identiv-3700-F-generic-2") << UsbId(0x04E6, 0x5790) << "Identiv cloud 3700 F Contactless Reader 0" << "Identiv 3700 F"; QTest::newRow("Identiv-3700-F-generic-3") << UsbId(0x04E6, 0x5790) << "Identiv uTrust 3700 F Contactless Reader 0" << "Identiv 3700 F"; QTest::newRow("Identiv-3700-F-generic-4") << UsbId(0x04E6, 0x5790) << "Identiv CLOUD 3700 F CL Reader" << "Identiv 3700 F"; QTest::newRow("Identiv-3700-F-generic-5") << UsbId(0x04E6, 0x5790) << "Identiv cloud 3700 F CL Reader" << "Identiv 3700 F"; - QTest::newRow("Identiv-3720-F-windows-7-10.0") << UsbId(0x04E6, 0x5612) << "Identiv uTrust 3720 Contactless Reader 0" << "Identiv 3720 F"; - QTest::newRow("Identiv-3720-F-macosx-10.13-11.0") << UsbId(0x04E6, 0x5612) << "Identiv uTrust 3720 Contactless Reader(1)" << "Identiv 3720 F"; + QTest::newRow("Identiv-3720-F-windows-10-11") << UsbId(0x04E6, 0x5612) << "Identiv uTrust 3720 Contactless Reader 0" << "Identiv 3720 F"; + QTest::newRow("Identiv-3720-F-macosx-11-13") << UsbId(0x04E6, 0x5612) << "Identiv uTrust 3720 Contactless Reader(1)" << "Identiv 3720 F"; QTest::newRow("Identiv-3720-F-generic-1") << UsbId(0x04E6, 0x5612) << "Identiv cloud 3720 Contactless Reader 0" << "Identiv 3720 F"; QTest::newRow("Identiv-3720-F-generic-2") << UsbId(0x04E6, 0x5612) << "Identiv cloud 3720 Contactless Reader(1)" << "Identiv 3720 F"; QTest::newRow("Identiv-3720-F-generic-3") << UsbId(0x04E6, 0x5612) << "Identiv cloud 3720 CL Reader 0" << "Identiv 3720 F"; @@ -290,8 +292,8 @@ class test_ReaderConfiguration QTest::newRow("Identiv-3720-F-generic-9") << UsbId(0x04E6, 0x5612) << "Identiv uTrust 3720 CL Reader 0" << "Identiv 3720 F"; QTest::newRow("Identiv-3720-F-generic-10") << UsbId(0x04E6, 0x5612) << "Identiv uTrust 3720 CL Reader(1)" << "Identiv 3720 F"; - QTest::newRow("Identiv-uTrust-3721-F-windows-7-10.0") << UsbId(0x04E6, 0x5613) << "Identiv uTrust 3721 Contactless Reader 0" << "Identiv 3721 F"; - QTest::newRow("Identiv-uTrust-3721-F-macosx-10.13-11.0") << UsbId(0x04E6, 0x5613) << "Identiv uTrust 3721 Contactless Reader(1)" << "Identiv 3721 F"; + QTest::newRow("Identiv-uTrust-3721-F-windows-10-11") << UsbId(0x04E6, 0x5613) << "Identiv uTrust 3721 Contactless Reader 0" << "Identiv 3721 F"; + QTest::newRow("Identiv-uTrust-3721-F-macosx-11-13") << UsbId(0x04E6, 0x5613) << "Identiv uTrust 3721 Contactless Reader(1)" << "Identiv 3721 F"; QTest::newRow("Identiv-3721-F-generic-1") << UsbId(0x04E6, 0x5613) << "Identiv cloud 3721 Contactless Reader 0" << "Identiv 3721 F"; QTest::newRow("Identiv-3721-F-generic-2") << UsbId(0x04E6, 0x5613) << "Identiv cloud 3721 Contactless Reader(1)" << "Identiv 3721 F"; QTest::newRow("Identiv-3721-F-generic-3") << UsbId(0x04E6, 0x5613) << "Identiv cloud 3721 CL Reader 0" << "Identiv 3721 F"; @@ -303,21 +305,21 @@ class test_ReaderConfiguration QTest::newRow("Identiv-3721-F-generic-9") << UsbId(0x04E6, 0x5613) << "Identiv uTrust 3721 CL Reader 0" << "Identiv 3721 F"; QTest::newRow("Identiv-3721-F-generic-10") << UsbId(0x04E6, 0x5613) << "Identiv uTrust 3721 CL Reader(1)" << "Identiv 3721 F"; - QTest::newRow("Identiv-Cloud-4700-F-windows-7-10-1") << UsbId(0x04E6, 0x5720) << "Identive CLOUD 4700 F Contact Reader 0" << "Identive CLOUD 4700 F Contact Reader 0"; - QTest::newRow("Identiv-Cloud-4700-F-windows-7-10-2") << UsbId(0x04E6, 0x5720) << "Identive CLOUD 4700 F Contactless Reader 0" << "Identiv Cloud 4700 F"; - QTest::newRow("Identiv-Cloud-4700-F-windows-7-10-3") << UsbId(0x04E6, 0x5720) << "Identive CLOUD 4700 F Contactless Reader 1" << "Identiv Cloud 4700 F"; - QTest::newRow("Identiv-Cloud-4700-F-macosx-10.13-11.0-1") << UsbId(0x04E6, 0x5720) << "Identiv uTrust 4700 F Dual Interface Reader(2)" << "Identiv Cloud 4700 F"; - QTest::newRow("Identiv-Cloud-4700-F-macosx-10.13-11.0-2") << UsbId(0x04E6, 0x5720) << "Identiv uTrust 4700 F Dual Interface Reader(1)" << "Identiv uTrust 4700 F Dual Interface Reader(1)"; - - QTest::newRow("Identiv-4701-F-windows-7-10-1") << UsbId(0x04E6, 0x5724) << "Identiv CLOUD 4701 F Contact Reader 0" << "Identiv CLOUD 4701 F Contact Reader 0"; - QTest::newRow("Identiv-4701-F-windows-7-10-2") << UsbId(0x04E6, 0x5724) << "Identiv CLOUD 4701 F Contactless Reader 1" << "Identiv 4701 F"; - QTest::newRow("Identiv-4701-F-windows-7-10-3") << UsbId(0x04E6, 0x5724) << "Identiv CLOUD 4701 F Contactless Reader 0" << "Identiv 4701 F"; - QTest::newRow("Identiv-4701-F-windows-7-10-4") << UsbId(0x04E6, 0x5724) << "Identiv cloud 4701 F Contactless Reader 1" << "Identiv 4701 F"; - QTest::newRow("Identiv-4701-F-windows-7-10-5") << UsbId(0x04E6, 0x5724) << "Identiv cloud 4701 F Contactless Reader 0" << "Identiv 4701 F"; - QTest::newRow("Identiv-4701-F-windows-7-10-6") << UsbId(0x04E6, 0x5724) << "Identiv uTrust 4701 F CL Reader 0" << "Identiv 4701 F"; - QTest::newRow("Identiv-4701-F-macosx-10.13-11.0-1") << UsbId(0x04E6, 0x5724) << "Identiv uTrust 4701 F Dual Interface Reader(1)" << "Identiv 4701 F"; - QTest::newRow("Identiv-4701-F-macosx-10.13-11.0-2") << UsbId(0x04E6, 0x5724) << "Identiv uTrust 4701 F Dual Interface Reader(2)" << "Identiv 4701 F"; - QTest::newRow("Identiv-4701-F-macosx-10.13-11.0-3") << UsbId(0x04E6, 0x5724) << "Identiv uTrust 4701 F Dual Interface Reader" << "Identiv 4701 F"; + QTest::newRow("Identiv-Cloud-4700-F-windows-10-11-1") << UsbId(0x04E6, 0x5720) << "Identive CLOUD 4700 F Contact Reader 0" << "Identive CLOUD 4700 F Contact Reader 0"; + QTest::newRow("Identiv-Cloud-4700-F-windows-10-11-2") << UsbId(0x04E6, 0x5720) << "Identive CLOUD 4700 F Contactless Reader 0" << "Identiv Cloud 4700 F"; + QTest::newRow("Identiv-Cloud-4700-F-windows-10-11-3") << UsbId(0x04E6, 0x5720) << "Identive CLOUD 4700 F Contactless Reader 1" << "Identiv Cloud 4700 F"; + QTest::newRow("Identiv-Cloud-4700-F-macosx-11-13-1") << UsbId(0x04E6, 0x5720) << "Identiv uTrust 4700 F Dual Interface Reader(2)" << "Identiv Cloud 4700 F"; + QTest::newRow("Identiv-Cloud-4700-F-macosx-11-13-2") << UsbId(0x04E6, 0x5720) << "Identiv uTrust 4700 F Dual Interface Reader(1)" << "Identiv uTrust 4700 F Dual Interface Reader(1)"; + + QTest::newRow("Identiv-4701-F-windows-10-11-1") << UsbId(0x04E6, 0x5724) << "Identiv CLOUD 4701 F Contact Reader 0" << "Identiv CLOUD 4701 F Contact Reader 0"; + QTest::newRow("Identiv-4701-F-windows-10-11-2") << UsbId(0x04E6, 0x5724) << "Identiv CLOUD 4701 F Contactless Reader 1" << "Identiv 4701 F"; + QTest::newRow("Identiv-4701-F-windows-10-11-3") << UsbId(0x04E6, 0x5724) << "Identiv CLOUD 4701 F Contactless Reader 0" << "Identiv 4701 F"; + QTest::newRow("Identiv-4701-F-windows-10-11-4") << UsbId(0x04E6, 0x5724) << "Identiv cloud 4701 F Contactless Reader 1" << "Identiv 4701 F"; + QTest::newRow("Identiv-4701-F-windows-10-11-5") << UsbId(0x04E6, 0x5724) << "Identiv cloud 4701 F Contactless Reader 0" << "Identiv 4701 F"; + QTest::newRow("Identiv-4701-F-windows-10-11-6") << UsbId(0x04E6, 0x5724) << "Identiv uTrust 4701 F CL Reader 0" << "Identiv 4701 F"; + QTest::newRow("Identiv-4701-F-macosx-11-13-1") << UsbId(0x04E6, 0x5724) << "Identiv uTrust 4701 F Dual Interface Reader(1)" << "Identiv 4701 F"; + QTest::newRow("Identiv-4701-F-macosx-11-13-2") << UsbId(0x04E6, 0x5724) << "Identiv uTrust 4701 F Dual Interface Reader(2)" << "Identiv 4701 F"; + QTest::newRow("Identiv-4701-F-macosx-11-13-3") << UsbId(0x04E6, 0x5724) << "Identiv uTrust 4701 F Dual Interface Reader" << "Identiv 4701 F"; QTest::newRow("Cherry-TC-1200-windows-7-10-1") << UsbId(0x046A, 0x0091) << "Cherry Smartcard Terminal TC 12xx-CL 0" << "Cherry TC-1200"; QTest::newRow("Cherry-TC-1200-windows-10") << UsbId(0x046A, 0x0091) << "Cherry Smartcard Terminal TC 12xx 0" << "Cherry Smartcard Terminal TC 12xx 0"; @@ -390,7 +392,7 @@ class test_ReaderConfiguration QVERIFY(jsonError.error == QJsonParseError::NoError); QJsonObject doc = json.object(); const QJsonArray& array = doc[QLatin1String("SupportedDevices")].toArray(); - for (JsonValueRef entry : array) + for (const QJsonValueConstRef entry : array) { QVERIFY(entry.isObject()); auto object = entry.toObject(); diff --git a/test/qt/configuration/test_ReaderConfigurationParser.cpp b/test/qt/configuration/test_ReaderConfigurationParser.cpp index 3053fef4d..f2c49ed9a 100644 --- a/test/qt/configuration/test_ReaderConfigurationParser.cpp +++ b/test/qt/configuration/test_ReaderConfigurationParser.cpp @@ -34,7 +34,7 @@ class test_ReaderConfigurationParser void verify_REINER_cyberJack_RFID_komfort(const ReaderConfigurationInfo& info) { QCOMPARE(info.getVendorId(), static_cast(0x0C4B)); - QCOMPARE(info.getProductId(), static_cast(0x0501)); + QCOMPARE(info.getProductIds(), QSet({static_cast(0x0501)})); QCOMPARE(info.getName(), QStringLiteral("REINER SCT cyberJack RFID komfort")); QCOMPARE(info.getPattern(), QStringLiteral("REINER SCT cyberJack RFID komfort")); QCOMPARE(info.getUrl(), KOMFORT_DRIVER_URL); @@ -44,11 +44,11 @@ class test_ReaderConfigurationParser QStringList incompleteKeyValuePairs(int skipIndex, bool skipOnlyValue) { const QStringList keys = { - "ReaderType", "VendorId", "ProductId", "Name", "Drivers" + "VendorId", "ProductIds", "Name", "Drivers" }; const QStringList vals = { - "REINER_cyberJack_RFID_komfort", "0x0C4B", "0x0501", - "REINER SCT cyberJack RFID komfort", + "\"0x0C4B\"", "[\"0x0501\"]", + "\"REINER SCT cyberJack RFID komfort\"", " [\n" " {\n" " \"Platforms\": [{\"os\": \"win\"}],\n" @@ -74,8 +74,8 @@ class test_ReaderConfigurationParser if (index != skipIndex || skipOnlyValue) { const QString key = keys.at(index); - const QString val = index != skipIndex ? vals.at(index) : QString(); - result += QString("\"%1\": \"%2\"\n").arg(key, val); + const QString val = index != skipIndex ? vals.at(index) : QStringLiteral("\"\""); + result += QString("\"%1\": %2\n").arg(key, val); } } @@ -128,9 +128,11 @@ class test_ReaderConfigurationParser " \"SupportedDevices\":\n" " [\n" " {\n" - " \"ReaderType\": \"REINER_cyberJack_RFID_komfort\",\n" " \"VendorId\": \"0x0C4B\",\n" " \"ProductId\": \"0x0501\",\n" + " \"ProductIds\": [\n" + " \"0x0501\"\n" + " ]," " \"Name\": \"REINER SCT cyberJack RFID komfort\",\n" " \"Pattern\": \"REINER SCT cyberJack RFID komfort\",\n" " \"Drivers\":\n" @@ -166,7 +168,7 @@ class test_ReaderConfigurationParser void validJsonDocumentWithOneInvalidEntry_parseErrorAndEmptyDeviceInfo() { // Check that a missing property is reported as a parse error. - for (int skipIndex = 0; skipIndex < 5; skipIndex++) + for (int skipIndex = 0; skipIndex < 4; skipIndex++) { // Key with index skipIndex is not in the test Json data. const QString devicesPair = jsonSingleDeviceString(incompleteKeyValuePairs(skipIndex, @@ -177,7 +179,7 @@ class test_ReaderConfigurationParser } // Check that a property with an empty value is reported as a parse error. - for (int skipIndex = 0; skipIndex < 5; skipIndex++) + for (int skipIndex = 0; skipIndex < 4; skipIndex++) { // Key with index skipIndex is in the test Json data but has the invalid value "" const QString devicesPair = jsonSingleDeviceString(incompleteKeyValuePairs(skipIndex, @@ -195,9 +197,11 @@ class test_ReaderConfigurationParser " \"SupportedDevices\":\n" " [\n" " {\n" - " \"ReaderType\": \"REINER_cyberJack_RFID_komfort\",\n" " \"VendorId\": \"0x0C4B\",\n" " \"ProductId\": \"0x0501\",\n" + " \"ProductIds\": [\n" + " \"0x0501\"\n" + " ]," " \"Name\": \"REINER SCT cyberJack RFID komfort\",\n" " \"Pattern\": \"REINER SCT cyberJack RFID komfort\",\n" " \"Drivers\":\n" @@ -205,9 +209,11 @@ class test_ReaderConfigurationParser " ]\n" " },\n" " {\n" - " \"ReaderType\": \"SCM_SDI011\",\n" " \"VendorId\": \"0x04E6\",\n" " \"ProductId\": \"0x512B\",\n" + " \"ProductIds\": [\n" + " \"0x512B\"\n" + " ]," " \"Name\": \"SDI011 Contactless Reader\",\n" " \"Pattern\": \"SDI011 (USB )?(Smart Card|Contactless) Reader\",\n" " \"Drivers\":\n" @@ -227,9 +233,10 @@ class test_ReaderConfigurationParser " \"SupportedDevices\":\n" " [\n" " {\n" - " \"ReaderType\": \"REINER_cyberJack_RFID_komfort\",\n" " \"VendorId\": \"0x0C4B\",\n" - " \"ProductId\": \"0x0501\",\n" + " \"ProductIds\": [\n" + " \"0x0501\"\n" + " ]," " \"Name\": \"REINER SCT cyberJack RFID komfort\",\n" " \"Pattern\": \"\",\n" " \"Drivers\":\n" @@ -237,9 +244,10 @@ class test_ReaderConfigurationParser " ]\n" " },\n" " {\n" - " \"ReaderType\": \"SCM_SDI011\",\n" " \"VendorId\": \"0x04E6\",\n" - " \"ProductId\": \"0x512B\",\n" + " \"ProductIds\": [\n" + " \"0x512B\"\n" + " ]," " \"Name\": \"SDI011 Contactless Reader\",\n" " \"Pattern\": \"\",\n" " \"Drivers\":\n" @@ -259,9 +267,10 @@ class test_ReaderConfigurationParser " \"SupportedDevices\":\n" " [\n" " {\n" - " \"ReaderType\": \"REINER_cyberJack_RFID_komfort\",\n" " \"VendorId\": \"0x0C4B\",\n" - " \"ProductId\": \"0x0501\",\n" + " \"ProductIds\": [\n" + " \"0x0501\"\n" + " ]," " \"Name\": \"REINER SCT cyberJack RFID komfort\",\n" " \"Pattern\": \"REINER SCT cyberJack RFID komfort\",\n" " \"Drivers\":\n" @@ -269,9 +278,10 @@ class test_ReaderConfigurationParser " ]\n" " },\n" " {\n" - " \"ReaderType\": \"SCM_SDI011\",\n" " \"VendorId\": \"0x0C4B\",\n" - " \"ProductId\": \"0x0501\",\n" + " \"ProductIds\": [\n" + " \"0x0501\"\n" + " ]," " \"Name\": \"SDI011 Contactless Reader\",\n" " \"Pattern\": \"SDI011 (USB )?(Smart Card|Contactless) Reader\",\n" " \"Drivers\":\n" @@ -291,9 +301,10 @@ class test_ReaderConfigurationParser " \"SupportedDevices\":\n" " [\n" " {\n" - " \"ReaderType\": \"REINER_cyberJack_RFID_komfort\",\n" " \"VendorId\": \"0x0C4B\",\n" - " \"ProductId\": \"0x0501\",\n" + " \"ProductIds\": [\n" + " \"0x0501\"\n" + " ]," " \"Name\": \"REINER SCT cyberJack RFID komfort\",\n" " \"Pattern\": \"REINER SCT cyberJack RFID komfort\",\n" " \"Drivers\":\n" @@ -301,9 +312,10 @@ class test_ReaderConfigurationParser " ]\n" " },\n" " {\n" - " \"ReaderType\": \"SCM_SDI011\",\n" " \"VendorId\": \"0x04E6\",\n" - " \"ProductId\": \"0x512B\",\n" + " \"ProductIds\": [\n" + " \"0x512B\"\n" + " ]," " \"Name\": \"REINER SCT cyberJack RFID komfort\",\n" " \"Pattern\": \"SDI011 (USB )?(Smart Card|Contactless) Reader\",\n" " \"Drivers\":\n" @@ -323,9 +335,10 @@ class test_ReaderConfigurationParser " \"SupportedDevices\":\n" " [\n" " {\n" - " \"ReaderType\": \"REINER_cyberJack_RFID_komfort\",\n" " \"VendorId\": \"0x0C4B\",\n" - " \"ProductId\": \"0x0501\",\n" + " \"ProductIds\": [\n" + " \"0x0501\"\n" + " ]," " \"Name\": \"REINER SCT cyberJack RFID komfort\",\n" " \"Pattern\": \"REINER SCT cyberJack RFID komfort\",\n" " \"Drivers\":\n" @@ -333,9 +346,10 @@ class test_ReaderConfigurationParser " ]\n" " },\n" " {\n" - " \"ReaderType\": \"SCM_SDI011\",\n" " \"VendorId\": \"0x04E6\",\n" - " \"ProductId\": \"0x512B\",\n" + " \"ProductIds\": [\n" + " \"0x512B\"\n" + " ]," " \"Name\": \"SDI011 Contactless Reader\",\n" " \"Pattern\": \"REINER SCT cyberJack RFID komfort\",\n" " \"Drivers\":\n" @@ -349,6 +363,93 @@ class test_ReaderConfigurationParser } + void acceptLegacyProductId() + { + const QByteArray data = QByteArrayLiteral("{" + " \"SupportedDevices\":\n" + " [\n" + " {\n" + " \"VendorId\": \"0x0C4B\",\n" + " \"ProductId\": \"0x0501\",\n" + " \"Name\": \"REINER SCT cyberJack RFID komfort\",\n" + " \"Pattern\": \"REINER SCT cyberJack RFID komfort\",\n" + " \"Drivers\":\n" + " [\n" + " ]\n" + " }\n" + " ]\n" + "}"); + const QVector infos = ReaderConfigurationParser::parse(data); + + QCOMPARE(infos.at(0).getProductIds(), QSet({static_cast(0x0501)})); + + } + + + void ignoreProductIdWhenProductIdsPresent() + { + const QByteArray data = QByteArrayLiteral("{" + " \"SupportedDevices\":\n" + " [\n" + " {\n" + " \"VendorId\": \"0x0C4B\",\n" + " \"ProductId\": \"0x0501\",\n" + " \"ProductIds\": [\n" + " \"0x0502\",\n" + " \"0x0503\"\n" + " ]," + " \"Name\": \"REINER SCT cyberJack RFID komfort\",\n" + " \"Pattern\": \"REINER SCT cyberJack RFID komfort\",\n" + " \"Drivers\":\n" + " [\n" + " ]\n" + " }\n" + " ]\n" + "}"); + + const QVector infos = ReaderConfigurationParser::parse(data); + const QSet ids = {static_cast(0x0502), static_cast(0x0503)}; + + QCOMPARE(infos.at(0).getProductIds(), ids); + + } + + + void checkForUniqueProductIds() + { + const QByteArray data = QByteArrayLiteral("{" + " \"SupportedDevices\":\n" + " [\n" + " {\n" + " \"VendorId\": \"0x0C4B\",\n" + " \"ProductIds\": [\n" + " \"0x0502\",\n" + " \"0x0503\"\n" + " ]," + " \"Name\": \"REINER SCT cyberJack RFID komfort\",\n" + " \"Pattern\": \"REINER SCT cyberJack RFID komfort\",\n" + " \"Drivers\":\n" + " [\n" + " ]\n" + " },\n" + " {\n" + " \"VendorId\": \"0x0C4B\",\n" + " \"ProductIds\": [\n" + " \"0x0502\"\n" + " ]," + " \"Name\": \"REINER SCT cyberJack RFID standard\",\n" + " \"Pattern\": \"REINER SCT cyberJack RFID standard\",\n" + " \"Drivers\":\n" + " [\n" + " ]\n" + " }\n" + " ]\n" + "}"); + const QVector infos = ReaderConfigurationParser::parse(data); + QCOMPARE(infos.size(), 0); + } + + }; QTEST_GUILESS_MAIN(test_ReaderConfigurationParser) diff --git a/test/qt/core/test_AppController.cpp b/test/qt/core/test_AppController.cpp index 74c349364..eabc32dea 100644 --- a/test/qt/core/test_AppController.cpp +++ b/test/qt/core/test_AppController.cpp @@ -10,7 +10,6 @@ #include "controller/ChangePinController.h" #include "controller/SelfAuthController.h" -#include "MockActivationContext.h" #include "TestWorkflowController.h" #include @@ -34,8 +33,9 @@ class test_AppController qRegisterMetaType>("QSharedPointer"); const auto readerManager = Env::getSingleton(); + QSignalSpy spy(readerManager, &ReaderManager::fireInitialized); readerManager->init(); - readerManager->isScanRunning(); // just to wait until initialization finished + QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations } @@ -59,16 +59,16 @@ class test_AppController void test_StartNewWorkflow() { - connect(mController.data(), &AppController::fireWorkflowStarted, this, [this](QSharedPointer pContext){ - pContext->claim(this); + connect(mController.data(), &AppController::fireWorkflowStarted, this, [this](const QSharedPointer pRequest){ + pRequest->getContext()->claim(this); }); QSignalSpy spy(mController.data(), &AppController::fireWorkflowStarted); QTest::ignoreMessage(QtInfoMsg, "Started new workflow PIN"); QTest::ignoreMessage(QtDebugMsg, "Start governikus::ChangePinController"); QVERIFY(mController->startNewWorkflow(ChangePinController::createWorkflowRequest())); - QVERIFY(mController->mActiveWorkflow->getController()->getContext()->wasClaimed()); - QCOMPARE(mController->mActiveWorkflow->getController()->getAction(), Action::PIN); + QVERIFY(mController->mActiveWorkflow->getController()->mContext->wasClaimed()); + QCOMPARE(mController->mActiveWorkflow->getController()->mContext->getAction(), Action::PIN); QCOMPARE(spy.count(), 1); QTest::ignoreMessage(QtWarningMsg, "Cannot start new workflow: PIN | Current workflow: PIN"); @@ -114,7 +114,7 @@ class test_AppController QCOMPARE(spyWorkflowFinished.count(), 1); QVERIFY(!mController->mWaitingRequest); QVERIFY(mController->mActiveWorkflow); - QCOMPARE(mController->mActiveWorkflow->getController()->getAction(), Action::PIN); + QCOMPARE(mController->mActiveWorkflow->getController()->mContext->getAction(), Action::PIN); } @@ -123,7 +123,7 @@ class test_AppController QSignalSpy spyWorkflowFinished(mController.data(), &AppController::fireWorkflowFinished); mController->onWorkflowRequested(SelfAuthController::createWorkflowRequest()); - mController->mActiveWorkflow->getController()->getContext()->setWorkflowFinished(true); + mController->mActiveWorkflow->getController()->mContext->setWorkflowFinished(true); mController->onWorkflowRequested(AuthController::createWorkflowRequest(QUrl(QStringLiteral("https://localhost")))); QTest::ignoreMessage(QtDebugMsg, "governikus::SelfAuthController done"); QTest::ignoreMessage(QtInfoMsg, "Finish workflow SELF"); @@ -132,30 +132,46 @@ class test_AppController mController->onWorkflowFinished(); QCOMPARE(spyWorkflowFinished.count(), 1); QVERIFY(!mController->mWaitingRequest); - QCOMPARE(mController->mActiveWorkflow->getController()->getAction(), Action::AUTH); + QCOMPARE(mController->mActiveWorkflow->getController()->mContext->getAction(), Action::AUTH); + } + + + void test_OnWorkflowUnhandled() + { + QSignalSpy spyWorkflowStarted(mController.data(), &AppController::fireWorkflowStarted); + QSignalSpy spyWorkflowUnhandled(mController.data(), &AppController::fireWorkflowUnhandled); + + QTest::ignoreMessage(QtInfoMsg, "Started new workflow AUTH"); + mController->onWorkflowRequested(AuthController::createWorkflowRequest(QUrl())); + QCOMPARE(spyWorkflowUnhandled.count(), 0); + QCOMPARE(spyWorkflowStarted.count(), 1); + + QTest::ignoreMessage(QtWarningMsg, "Skip workflow: AUTH | Current workflow: AUTH"); + mController->onWorkflowRequested(AuthController::createWorkflowRequest(QUrl())); + QCOMPARE(spyWorkflowUnhandled.count(), 1); + QCOMPARE(spyWorkflowStarted.count(), 1); } void test_OnAuthenticationRequestSELF() { - const QSharedPointer context(new MockActivationContext()); - connect(mController.data(), &AppController::fireWorkflowStarted, this, [this](QSharedPointer pContext){ - pContext->claim(this); + connect(mController.data(), &AppController::fireWorkflowStarted, this, [this](const QSharedPointer pRequest){ + pRequest->getContext()->claim(this); }); QTest::ignoreMessage(QtDebugMsg, "New workflow requested: SELF"); QTest::ignoreMessage(QtDebugMsg, "Start governikus::SelfAuthController"); QTest::ignoreMessage(QtInfoMsg, "Started new workflow SELF"); mController->onWorkflowRequested(SelfAuthController::createWorkflowRequest()); - QVERIFY(mController->mActiveWorkflow->getController()->getContext()->wasClaimed()); - mController->mActiveWorkflow->getController()->getContext()->setWorkflowFinished(true); - QVERIFY(!mController->mActiveWorkflow->getController()->getContext()->isStateApproved()); + QVERIFY(mController->mActiveWorkflow->getController()->mContext->wasClaimed()); + mController->mActiveWorkflow->getController()->mContext->setWorkflowFinished(true); + QVERIFY(!mController->mActiveWorkflow->getController()->mContext->isStateApproved()); QTest::ignoreMessage(QtDebugMsg, "New workflow requested: AUTH"); QTest::ignoreMessage(QtDebugMsg, "Auto-approving the current state"); QTest::ignoreMessage(QtDebugMsg, "Enqueue workflow: AUTH"); - mController->onWorkflowRequested(AuthController::createWorkflowRequest(context)); - QVERIFY(mController->mActiveWorkflow->getController()->getContext()->isStateApproved()); + mController->onWorkflowRequested(AuthController::createWorkflowRequest(QUrl())); + QVERIFY(mController->mActiveWorkflow->getController()->mContext->isStateApproved()); QTest::ignoreMessage(QtDebugMsg, "New workflow requested: SELF"); QTest::ignoreMessage(QtWarningMsg, "Cannot start or enqueue workflow: SELF"); @@ -164,18 +180,7 @@ class test_AppController QTest::ignoreMessage(QtDebugMsg, "New workflow requested: AUTH"); QTest::ignoreMessage(QtWarningMsg, "Skip workflow: AUTH | Current workflow: SELF"); QTest::ignoreMessage(QtDebugMsg, "Waiting workflow: AUTH"); - mController->onWorkflowRequested(AuthController::createWorkflowRequest(context)); - } - - - void test_OnAuthenticationRequestCannotSendOperationAlreadyActive() - { - const QString sendError("send error"); - const QSharedPointer context(new MockActivationContext(false, false, false, false, sendError)); - mController->onWorkflowRequested(ChangePinController::createWorkflowRequest()); - QTest::ignoreMessage(QtDebugMsg, "New workflow requested: AUTH"); - QTest::ignoreMessage(QtCriticalMsg, R"(Cannot send "Operation already active" to caller: "send error")"); - mController->onWorkflowRequested(AuthController::createWorkflowRequest(context)); + mController->onWorkflowRequested(AuthController::createWorkflowRequest(QUrl())); } @@ -188,7 +193,7 @@ class test_AppController QTest::ignoreMessage(QtWarningMsg, "Killing the current workflow."); mController->onWorkflowRequested(SelfAuthController::createWorkflowRequest()); - QVERIFY(!mController->mActiveWorkflow->getController()->getContext()->wasClaimed()); + QVERIFY(!mController->mActiveWorkflow->getController()->mContext->wasClaimed()); } @@ -200,7 +205,7 @@ class test_AppController mController->onWorkflowRequested(ChangePinController::createWorkflowRequest()); mController->doShutdown(); QVERIFY(!mController->mWaitingRequest); - QVERIFY(mController->mActiveWorkflow->getController()->getContext()->isWorkflowKilled()); + QVERIFY(mController->mActiveWorkflow->getController()->mContext->isWorkflowKilled()); QCOMPARE(spyHideUi.count(), 1); } diff --git a/test/qt/diagnosis/test_DiagnosisAntivirusDetection.cpp b/test/qt/diagnosis/test_DiagnosisAntivirusDetection.cpp index d7f9c8f37..ee8bd3355 100644 --- a/test/qt/diagnosis/test_DiagnosisAntivirusDetection.cpp +++ b/test/qt/diagnosis/test_DiagnosisAntivirusDetection.cpp @@ -24,9 +24,16 @@ class test_DiagnosisAntivirusDetection const QString mTestFileLocation = QStringLiteral(":/core/diagnosis/"); QString getTestData(const QString& pFilename) { - QString filePath = mTestFileLocation + pFilename; - QByteArray rawData = TestFileHelper::readFile(filePath); - return QString::fromUtf8(rawData); + const QString filePath = QStringLiteral(":/core/diagnosis/") + pFilename; + const QByteArray rawData = TestFileHelper::readFile(filePath); + QString stringData = QString::fromUtf8(rawData); + + Q_ASSERT(stringData.count("\r\n") == 0); + const qsizetype linebreaks = stringData.count('\n'); + stringData.replace('\n', "\r\n"); + Q_ASSERT(stringData.count("\r\n") == linebreaks); + + return stringData; } private Q_SLOTS: diff --git a/test/qt/diagnosis/test_DiagnosisFirewallDetection.cpp b/test/qt/diagnosis/test_DiagnosisFirewallDetection.cpp index 4d00f7af0..9df856a33 100644 --- a/test/qt/diagnosis/test_DiagnosisFirewallDetection.cpp +++ b/test/qt/diagnosis/test_DiagnosisFirewallDetection.cpp @@ -24,9 +24,16 @@ class test_DiagnosisFirewallDetection const QString mTestFileLocation = QStringLiteral(":/core/diagnosis/"); QString getTestData(const QString& pFilename) { - QString filePath = mTestFileLocation + pFilename; - QByteArray rawData = TestFileHelper::readFile(filePath); - return QString::fromUtf8(rawData); + const QString filePath = QStringLiteral(":/core/diagnosis/") + pFilename; + const QByteArray rawData = TestFileHelper::readFile(filePath); + QString stringData = QString::fromUtf8(rawData); + + Q_ASSERT(stringData.count("\r\n") == 0); + const qsizetype linebreaks = stringData.count('\n'); + stringData.replace('\n', "\r\n"); + Q_ASSERT(stringData.count("\r\n") == linebreaks); + + return stringData; } private Q_SLOTS: diff --git a/test/qt/diagnosis/test_DiagnosisModel.cpp b/test/qt/diagnosis/test_DiagnosisModel.cpp index 6ee9c5187..525746c52 100644 --- a/test/qt/diagnosis/test_DiagnosisModel.cpp +++ b/test/qt/diagnosis/test_DiagnosisModel.cpp @@ -18,15 +18,21 @@ class test_DiagnosisModel : public QObject { Q_OBJECT - QSharedPointer mContext; QSharedPointer mModel; private: QString getTestData(const QString& pFilename) { - QString filePath = QStringLiteral(":/core/diagnosis/") + pFilename; - QByteArray rawData = TestFileHelper::readFile(filePath); - return QString::fromUtf8(rawData); + const QString filePath = QStringLiteral(":/core/diagnosis/") + pFilename; + const QByteArray rawData = TestFileHelper::readFile(filePath); + QString stringData = QString::fromUtf8(rawData); + + Q_ASSERT(stringData.count("\r\n") == 0); + const qsizetype linebreaks = stringData.count('\n'); + stringData.replace('\n', "\r\n"); + Q_ASSERT(stringData.count("\r\n") == linebreaks); + + return stringData; } @@ -34,11 +40,7 @@ class test_DiagnosisModel const QVector>& pOrder) { const auto& content = pSection->mContentItems; -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) qsizetype offset = 0; -#else - int offset = 0; -#endif for (const auto& subsection : pOrder) { const auto& slice = content.mid(offset, subsection.size()); @@ -55,22 +57,18 @@ class test_DiagnosisModel private Q_SLOTS: void init() { - mContext.reset(new DiagnosisContext()); - mModel.reset(new DiagnosisModel(mContext)); - mModel->reloadContent(); + mModel.reset(new DiagnosisModel()); } void cleanup() { mModel.clear(); - mContext.clear(); } void test_newDiagnosisModel() { - QCOMPARE(mModel->mContext, mContext); QCOMPARE(mModel->rowCount(), mModel->mSections.size()); QCOMPARE(mModel->getSectionName(DiagnosisModel::Section::GENERAL), QCoreApplication::applicationName()); @@ -79,7 +77,6 @@ class test_DiagnosisModel QCOMPARE(mModel->getSectionName(DiagnosisModel::Section::SECURITY), QString("Antivirus and firewall")); QCOMPARE(mModel->mSections[DiagnosisModel::Section::GENERAL]->mContentItems.last().mTitle, QString("Time of diagnosis")); - QCOMPARE(mModel->mSections[DiagnosisModel::Section::GENERAL]->mContentItems.last().mContent, QString("Initial diagnosis running, please wait.")); QCOMPARE(mModel->mSections[DiagnosisModel::Section::READER]->mContentItems.at(0).mTitle, QString("Paired smartphones")); QCOMPARE(mModel->mSections[DiagnosisModel::Section::READER]->mContentItems.at(1).mContent, QString("No devices paired.")); @@ -108,7 +105,7 @@ class test_DiagnosisModel ReaderInfo comfortReaderInfo(QString("name"), ReaderManagerPlugInType::REMOTE_IFD, CardInfo(CardType::UNKNOWN)); comfortReaderInfo.setBasicReader(false); const QVector readerInfos = {defaultInfo, infoEidCard, comfortReaderInfo}; - mContext->setReaderInfos(readerInfos); + mModel->mContext->setReaderInfos(readerInfos); mModel->onReaderInfosChanged(); QCOMPARE(mModel->mCardReaderSection.size(), 4); @@ -152,7 +149,7 @@ class test_DiagnosisModel const DiagnosisContext::ComponentInfo driver2(QString("/path/to/driver2"), QString("description2"), QString("version2"), QString("vendor2")); QVector components = {component1, component2}; QVector drivers = {driver1, driver2}; - mContext->setPcscInfo(version, components, drivers); + mModel->mContext->setPcscInfo(version, components, drivers); mModel->onPcscInfoChanged(); QCOMPARE(mModel->mPcscSection.size(), 4); @@ -177,12 +174,12 @@ class test_DiagnosisModel const QTime time(12, 0); const QDateTime valid(date, time); - mContext->setTimestamp(invalid); + mModel->mContext->setTimestamp(invalid); mModel->onTimestampChanged(); QCOMPARE(mModel->mTimestampSection.last().mTitle, QString("Time of diagnosis")); QCOMPARE(mModel->mTimestampSection.last().mContent, QString("Failed to retrieve date & time")); - mContext->setTimestamp(valid); + mModel->mContext->setTimestamp(valid); mModel->onTimestampChanged(); QCOMPARE(mModel->mTimestampSection.last().mTitle, QString("Time of diagnosis")); QCOMPARE(mModel->mTimestampSection.last().mContent, QString("12. October 2018, 12:00:00 PM")); @@ -195,7 +192,7 @@ class test_DiagnosisModel const QNetworkInterface interface2; const QNetworkInterface interface3; QList interfaces = {interface1, interface2, interface3}; - mContext->setNetworkInterfaces(interfaces); + mModel->mContext->setNetworkInterfaces(interfaces); mModel->onNetworkInfoChanged(); QCOMPARE(mModel->mNetworkInterfaceSection.size(), 3); @@ -303,6 +300,56 @@ class test_DiagnosisModel } + void test_SavePlainText() + { + static const QRegularExpression re(R"(^Test_diagnosis_DiagnosisModel\r? +Application\r? +Test_diagnosis_DiagnosisModel\r? +Application Version\r? +Organization\r? +Organization Domain\r? +System\r? +.+\r? +Kernel\r? +.+\r? +Architecture\r? +.+\r? +Device\r? +.+\r? +Qt Version\r? +.+\r? +OpenSSL Version\r? +.+\r? +Time of diagnosis\r? +.+\r? +\r? +\r? +Card reader\r? +Paired smartphones\r? +No devices paired\.\r? +Card reader\r? +Diagnosis is running\.\.\.\r? +PC\/SC driver information\r? +Diagnosis is running\.\.\.\r? +\r? +\r? +Network\r? +(?:\N+\r?\n)*\r? +\r? +Antivirus and firewall\r? +Antivirus information\r? +.+\r? +Firewall information\r? +.+)"); + QVERIFY(re.match(mModel->getAsPlaintext()).hasMatch()); + + QTemporaryFile file; + QVERIFY(file.open()); + mModel->saveToFile(QUrl::fromLocalFile(file.fileName())); + QVERIFY(re.match(QString::fromUtf8(file.readAll())).hasMatch()); + } + + }; QTEST_GUILESS_MAIN(test_DiagnosisModel) diff --git a/test/qt/export/test_PdfExporter.cpp b/test/qt/export/test_PdfExporter.cpp deleted file mode 100644 index d8cc4d524..000000000 --- a/test/qt/export/test_PdfExporter.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/** - * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany - */ - -/*! - * \brief Unit tests for \ref PdfExporter - */ - -#include "PdfExporter.h" - -#include "AppSettings.h" -#include "ResourceLoader.h" - -#include -#include - -using namespace governikus; - -Q_DECLARE_METATYPE(QVector) -using Pair = QPair; -Q_DECLARE_METATYPE(QVector) - -class test_PdfExporter - : public QObject -{ - Q_OBJECT - - private Q_SLOTS: - void initTestCase() - { - ResourceLoader::getInstance().init(); - } - - - void history_data() - { - QTest::addColumn("min"); - QTest::addColumn("max"); - QTest::addColumn>("infos"); - - QVector entries; - - QTest::newRow("empty") << 10000 << 100000 << entries; - - for (int i = 0; i < 100; ++i) - { - entries << HistoryInfo("SubjectName", "SubjectUrl", "Usage", QDateTime::currentDateTime(), "TermOfUsage", {"RequestedData"}); - } - QTest::newRow("multiple") << 50000 << 350000 << entries; - } - - - void history() - { - QFETCH(int, min); - QFETCH(int, max); - QFETCH(QVector, infos); - - Env::getSingleton()->getHistorySettings().setHistoryInfos(infos); - - QTemporaryFile file; - QVERIFY(file.open()); - - PdfExporter exporter(file.fileName(), false, false); - QVERIFY(exporter.exportHistory()); - const QFileInfo info(file.fileName()); - qDebug() << info.size(); - QVERIFY(info.size() > min); - QVERIFY(info.size() < max); - } - - - void selfInfo_data() - { - QTest::addColumn("min"); - QTest::addColumn("max"); - QTest::addColumn>("data"); - - QVector> data; - - QTest::newRow("empty") << 10000 << 100000 << data; - - for (int i = 0; i < 100; ++i) - { - data << QPair(QString("key"), QString("value")); - } - QTest::newRow("filled") << 25000 << 150000 << data; - } - - - void selfInfo() - { - QFETCH(int, min); - QFETCH(int, max); - QFETCH(QVector, data); - - const auto& now = QDateTime::currentDateTime(); - - QTemporaryFile file; - QVERIFY(file.open()); - - PdfExporter exporter(file.fileName(), false, false); - QVERIFY(exporter.exportSelfInfo(now, data)); - const QFileInfo info(file.fileName()); - qDebug() << info.size(); - QVERIFY(info.size() > min); - QVERIFY(info.size() < max); - } - - -}; - -QTEST_MAIN(test_PdfExporter) -#include "test_PdfExporter.moc" diff --git a/test/qt/external/smartID/test_eid_applet_interface_mock.cpp b/test/qt/external/smartID/test_eid_applet_interface_mock.cpp index 6669140d8..db3ddec25 100644 --- a/test/qt/external/smartID/test_eid_applet_interface_mock.cpp +++ b/test/qt/external/smartID/test_eid_applet_interface_mock.cpp @@ -10,7 +10,7 @@ using namespace governikus; -Q_DECLARE_METATYPE(EidUpdateInfo) +Q_DECLARE_METATYPE(EidSupportStatus) Q_DECLARE_METATYPE(EidStatus) Q_DECLARE_METATYPE(EidServiceResult) @@ -25,21 +25,21 @@ class test_eid_applet_interface_mock void testInitialReturnValues_data() { QTest::addColumn("restInterfaceEnabled"); - QTest::addColumn("updateInfo"); + QTest::addColumn("supportInfo"); QTest::addColumn("eidStatus"); QTest::addColumn("installResult"); QTest::addColumn("deleteSmartResult"); QTest::addColumn("deletePersonalizationResult"); - QTest::addRow("Rest Enabled") << true << EidUpdateInfo::UP_TO_DATE << EidStatus::NO_PERSONALIZATION << EidServiceResult::SUCCESS << EidServiceResult::SUCCESS << EidServiceResult::SUCCESS; - QTest::addRow("Rest disabled") << false << EidUpdateInfo::UNAVAILABLE << EidStatus::UNAVAILABLE << EidServiceResult::UNSUPPORTED << EidServiceResult::UNSUPPORTED << EidServiceResult::UNSUPPORTED; + QTest::addRow("Rest Enabled") << true << EidSupportStatus::UP_TO_DATE << EidStatus::NO_PERSONALIZATION << EidServiceResult::SUCCESS << EidServiceResult::SUCCESS << EidServiceResult::SUCCESS; + QTest::addRow("Rest disabled") << false << EidSupportStatus::UNAVAILABLE << EidStatus::INTERNAL_ERROR << EidServiceResult::UNSUPPORTED << EidServiceResult::UNSUPPORTED << EidServiceResult::UNSUPPORTED; } void testInitialReturnValues() { QFETCH(bool, restInterfaceEnabled); - QFETCH(EidUpdateInfo, updateInfo); + QFETCH(EidSupportStatus, supportInfo); QFETCH(EidStatus, eidStatus); QFETCH(EidServiceResult, installResult); QFETCH(EidServiceResult, deleteSmartResult); @@ -55,7 +55,7 @@ class test_eid_applet_interface_mock } initMock(); - QCOMPARE(getUpdateInfo(), updateInfo); + QCOMPARE(getSmartEidSupportInfo().mStatus, supportInfo); QCOMPARE(getSmartEidStatus(), eidStatus); QCOMPARE(installSmartEid(ProgressHandler()), installResult); QCOMPARE(deleteSmartEid(ProgressHandler()), deleteSmartResult); diff --git a/test/qt/file_provider/test_UpdatableFile.cpp b/test/qt/file_provider/test_UpdatableFile.cpp index b7ad81333..75d1f9979 100644 --- a/test/qt/file_provider/test_UpdatableFile.cpp +++ b/test/qt/file_provider/test_UpdatableFile.cpp @@ -8,6 +8,7 @@ #include "Env.h" #include "MockDownloader.h" +#include #include using namespace governikus; @@ -18,10 +19,10 @@ class test_UpdatableFile Q_OBJECT private: - const QString mSection; - const QLatin1Char mSep; + static constexpr auto mSection = QLatin1String("reader"); + static constexpr auto mSep = QLatin1Char('/'); - void verifySectionCacheFolder(UpdatableFile& pUpdatableFile) + static void verifySectionCacheFolder(UpdatableFile& pUpdatableFile) { QDir folder(pUpdatableFile.getSectionCachePath()); QVERIFY(folder.exists()); @@ -29,20 +30,27 @@ class test_UpdatableFile } - void touchFileInCache(const QString& pFilename, UpdatableFile& pUpdatableFile) + [[nodiscard]] static auto touchFileInCache(const QString& pFilename, UpdatableFile& pUpdatableFile) { verifySectionCacheFolder(pUpdatableFile); - const QString filePath = pUpdatableFile.getSectionCachePath() + mSep + pFilename; - QFile file(filePath); - QVERIFY(!file.exists()); - QVERIFY(file.open(QIODevice::WriteOnly)); - file.close(); - QVERIFY(file.exists()); + const auto& check = [](const auto& pFilePath){ + QFile file(pFilePath); + QVERIFY(!file.exists()); + QVERIFY(file.open(QIODevice::WriteOnly)); + file.close(); + QVERIFY(file.exists()); + }; + check(pUpdatableFile.getSectionCachePath() + mSep + pFilename); + + return qScopeGuard([pFilename, &pUpdatableFile]{ + removeFileFromCache(pFilename, pUpdatableFile); + }); + } - void removeFileFromCache(const QString& pFilename, UpdatableFile& pUpdatableFile) + static void removeFileFromCache(const QString& pFilename, UpdatableFile& pUpdatableFile) { verifySectionCacheFolder(pUpdatableFile); @@ -63,12 +71,12 @@ class test_UpdatableFile void testFileOnlyInCache() { const QString filename("img_ACS_ACR1252V.png"); - const QString filenameInCache = filename + QStringLiteral("_20170601102132"); + const QString filenameInCache = filename + QStringLiteral("_20170601102132MST"); const QDate timestampDate(2017, 6, 1); const QTime timestampTime(10, 21, 32); - const QDateTime timestamp(timestampDate, timestampTime); + const QDateTime timestamp(timestampDate, timestampTime, QTimeZone("MST")); UpdatableFile updatableFile(mSection, filename); - touchFileInCache(filenameInCache, updatableFile); + const auto guard = touchFileInCache(filenameInCache, updatableFile); QCOMPARE(updatableFile.getName(), filename); QCOMPARE(updatableFile.lookupPath(), updatableFile.getSectionCachePath() + mSep + filenameInCache); @@ -80,8 +88,6 @@ class test_UpdatableFile return true; })); QCOMPARE(paths, QStringList({updatableFile.getSectionCachePath() + mSep + filenameInCache})); - - removeFileFromCache(filenameInCache, updatableFile); } @@ -102,9 +108,9 @@ class test_UpdatableFile { const QString filename("img_ACS_ACR1252U.png"); const QString expectedPath = ":/updatable-files/reader/" + filename; - const QString filenameInCache = filename + QStringLiteral("_20170601102132"); + const QString filenameInCache = filename + QStringLiteral("_20170601102132GMT"); UpdatableFile updatableFile(mSection, filename); - touchFileInCache(filenameInCache, updatableFile); + const auto guard = touchFileInCache(filenameInCache, updatableFile); QCOMPARE(updatableFile.getName(), filename); QCOMPARE(updatableFile.lookupPath(), updatableFile.getSectionCachePath() + mSep + filenameInCache); @@ -115,25 +121,20 @@ class test_UpdatableFile return false; })); QCOMPARE(paths, QStringList({updatableFile.getSectionCachePath() + mSep + filenameInCache, expectedPath})); - - removeFileFromCache(filenameInCache, updatableFile); } void testMoreThanOneVersionInCache() { const QString filename("img_ACS_ACR1252U.png"); - const QString filenameInCache1 = filename + QStringLiteral("_20170710120015"); - const QString filenameInCache2 = filename + QStringLiteral("_20170601102132"); + const QString filenameInCache1 = filename + QStringLiteral("_20170710120015WAST"); + const QString filenameInCache2 = filename + QStringLiteral("_20170601102132UTC"); UpdatableFile updatableFile(mSection, filename); - touchFileInCache(filenameInCache1, updatableFile); - touchFileInCache(filenameInCache2, updatableFile); + const auto guard1 = touchFileInCache(filenameInCache1, updatableFile); + const auto guard2 = touchFileInCache(filenameInCache2, updatableFile); QCOMPARE(updatableFile.getName(), filename); QCOMPARE(updatableFile.lookupPath(), updatableFile.getSectionCachePath() + mSep + filenameInCache1); - - removeFileFromCache(filenameInCache1, updatableFile); - removeFileFromCache(filenameInCache2, updatableFile); } @@ -156,10 +157,11 @@ class test_UpdatableFile QVERIFY(!updatableFile.isDirty()); - touchFileInCache(dirtyFilename, updatableFile); - QVERIFY(updatableFile.isDirty()); + { + const auto guard = touchFileInCache(dirtyFilename, updatableFile); + QVERIFY(updatableFile.isDirty()); + } - removeFileFromCache(dirtyFilename, updatableFile); QVERIFY(!updatableFile.isDirty()); } @@ -186,9 +188,10 @@ class test_UpdatableFile const QString dirtyFilename = filename + QStringLiteral(".dirty"); UpdatableFile updatableFile(mSection, filename); - touchFileInCache(dirtyFilename, updatableFile); + auto guard = touchFileInCache(dirtyFilename, updatableFile); QVERIFY(updatableFile.isDirty()); + guard.dismiss(); updatableFile.clearDirty(); QVERIFY(!updatableFile.isDirty()); } @@ -211,11 +214,12 @@ class test_UpdatableFile QVERIFY(!updatableFile.isDirty()); QCOMPARE(updatableFile.lookupPath(), QStringLiteral("DEFAULT")); - touchFileInCache(dirtyFilename, updatableFile); - QVERIFY(!updatableFile.isDirty()); - QCOMPARE(updatableFile.lookupPath(), QStringLiteral("DEFAULT")); + { + const auto guard = touchFileInCache(dirtyFilename, updatableFile); + QVERIFY(!updatableFile.isDirty()); + QCOMPARE(updatableFile.lookupPath(), QStringLiteral("DEFAULT")); + } - removeFileFromCache(dirtyFilename, updatableFile); QVERIFY(!updatableFile.isDirty()); QCOMPARE(updatableFile.lookupPath(), QStringLiteral("DEFAULT")); } @@ -263,13 +267,14 @@ class test_UpdatableFile QCOMPARE(spy.count(), 1); const QString fileName = updatableFile.getName() + QLatin1Char('_') + downloader.getTimeStampString(); const QString filePath = updatableFile.getSectionCachePath() + "/" + fileName; + const auto guard = qScopeGuard([&fileName, &updatableFile]{ + removeFileFromCache(fileName, updatableFile); + }); QFile testfile(filePath); QVERIFY(testfile.exists()); QVERIFY(testfile.open(QIODevice::ReadOnly)); QCOMPARE(testfile.readAll(), downloader.getTestData(updateUrl)); testfile.close(); - - removeFileFromCache(fileName, updatableFile); } @@ -291,13 +296,6 @@ class test_UpdatableFile QVERIFY(!testfile.exists()); } - public: - test_UpdatableFile() - : mSection("reader") - , mSep('/') - { - } - }; diff --git a/test/qt/global/test_FileDestination.cpp b/test/qt/global/test_FileDestination.cpp index 342ad7c79..6094b9460 100644 --- a/test/qt/global/test_FileDestination.cpp +++ b/test/qt/global/test_FileDestination.cpp @@ -21,7 +21,7 @@ class test_FileDestination private Q_SLOTS: void getPath() { - const auto filename = QStringLiteral("AusweisApp2.rcc"); + const auto filename = QStringLiteral("AusweisApp.rcc"); QString path = FileDestination::getPath(filename); QVERIFY(path.endsWith(filename)); QVERIFY(QFile::exists(path)); diff --git a/test/qt/global/test_GlobalStatus.cpp b/test/qt/global/test_GlobalStatus.cpp index 3b05020bb..b7a63b302 100644 --- a/test/qt/global/test_GlobalStatus.cpp +++ b/test/qt/global/test_GlobalStatus.cpp @@ -63,7 +63,7 @@ class test_GlobalStatus QTest::newRow("incompleteInformation") << GlobalStatus::Code::Workflow_Server_Incomplete_Information_Provided << tr("The server provided no or incomplete information. Your personal data could not be read out."); QTest::newRow("abnormalClose") << GlobalStatus::Code::RemoteReader_CloseCode_AbnormalClose << tr("The smartphone as card reader (SaC) connection was aborted."); QTest::newRow("invalidRequest") << GlobalStatus::Code::IfdConnector_InvalidRequest << tr("Smartphone as card reader (SaC) connection request was invalid."); - QTest::newRow("noSupportedApiLevel") << GlobalStatus::Code::IfdConnector_NoSupportedApiLevel << tr("Your smartphone as card reader (SaC) version is incompatible with the local version. Please install the latest AusweisApp2 version on both your smartphone and your computer."); + QTest::newRow("noSupportedApiLevel") << GlobalStatus::Code::IfdConnector_NoSupportedApiLevel << tr("Your smartphone as card reader (SaC) version is incompatible with the local version. Please install the latest %1 version on both your smartphone and your computer.").arg(QCoreApplication::applicationName()); QTest::newRow("connectionTimeout") << GlobalStatus::Code::IfdConnector_ConnectionTimeout << tr("A timeout occurred while trying to establish a connection to the smartphone as card reader (SaC)."); QTest::newRow("connectionError") << GlobalStatus::Code::IfdConnector_ConnectionError << tr("An error occurred while trying to establish a connection to the smartphone as card reader (SaC)."); QTest::newRow("hostRefused") << GlobalStatus::Code::IfdConnector_RemoteHostRefusedConnection << tr("The smartphone to be paired has rejected the connection. Please check the pairing code. If no pairing code is shown activate the pairing mode."); diff --git a/test/qt/global/test_LogHandler.cpp b/test/qt/global/test_LogHandler.cpp index a003cfecb..4a5d7dc25 100644 --- a/test/qt/global/test_LogHandler.cpp +++ b/test/qt/global/test_LogHandler.cpp @@ -292,20 +292,58 @@ class test_LogHandler } + void handleMessage_data() + { + QTest::addColumn("file"); + QTest::addColumn("line"); + QTest::addColumn("function"); + QTest::addColumn("category"); + QTest::addColumn("msg"); + QTest::addColumn("result"); + + QTest::newRow("normal") << QByteArray("/src/ui/qml/ApplicationModel.cpp") + << 411 + << QByteArray("bool ApplicationModel::isScreenReaderRunning()") + << QByteArray("ui") + << QStringLiteral("testMessage") + << QStringLiteral("ApplicationModel::isScreenReaderRunning(ui/qml/ApplicationModel.cpp:411) : testMessage"); + + QTest::newRow("normal const") << QByteArray("/src/ui/qml/ApplicationModel.cpp") + << 411 + << QByteArray("bool ApplicationModel::isScreenReaderRunning() const") + << QByteArray("ui") + << QStringLiteral("testMessage2") + << QStringLiteral("ApplicationModel::isScreenReaderRunning(ui/qml/ApplicationModel.cpp:411) : testMessage2"); + + QTest::newRow("nullptr") << QByteArray() + << 0 + << QByteArray() + << QByteArray("qt.tlsbackend.ossl") + << QStringLiteral("dummy") + << QStringLiteral("(:0) : dummy"); + } + + void handleMessage() { + QFETCH(QByteArray, file); + QFETCH(int, line); + QFETCH(QByteArray, function); + QFETCH(QByteArray, category); + QFETCH(QString, msg); + QFETCH(QString, result); + + QMessageLogContext ctx; + ctx.category = category.isNull() ? nullptr : category.constData(); + ctx.file = file.isNull() ? nullptr : file.constData(); + ctx.function = function.isNull() ? nullptr : function.constData(); + ctx.line = line; + QSignalSpy logSpy(Env::getSingleton()->getEventHandler(), &LogEventHandler::fireLog); const auto& logger = Env::getSingleton(); - QMessageLogContext logContext1("/src/ui/qml/ApplicationModel.cpp", 411, "bool ApplicationModel::isScreenReaderRunning()", "ui"); - logger->handleMessage(QtMsgType::QtDebugMsg, logContext1, "testMessage"); - QCOMPARE(logSpy.count(), 1); - QVERIFY(logSpy.takeFirst().at(0).toString().contains("ApplicationModel::isScreenReaderRunning(ui/qml/ApplicationModel.cpp:411) : testMessage")); - - QMessageLogContext logContext2("/src/ui/qml/ApplicationModel.cpp", 411, "bool ApplicationModel::isScreenReaderRunning() const", "ui"); - logger->handleMessage(QtMsgType::QtDebugMsg, logContext2, "testMessage2"); - QCOMPARE(logSpy.count(), 1); - QVERIFY(logSpy.takeFirst().at(0).toString().contains("ApplicationModel::isScreenReaderRunning(ui/qml/ApplicationModel.cpp:411) : testMessage2")); + logger->handleMessage(QtMsgType::QtDebugMsg, ctx, msg); + QVERIFY(logSpy.takeFirst().at(0).toString().contains(result)); } diff --git a/test/qt/global/test_VersionInfo.cpp b/test/qt/global/test_VersionInfo.cpp index 9b5c7f2db..67e6f03bc 100644 --- a/test/qt/global/test_VersionInfo.cpp +++ b/test/qt/global/test_VersionInfo.cpp @@ -47,11 +47,11 @@ class test_VersionInfo QCOMPARE(jsonError.error, QJsonParseError::NoError); const auto obj = json.object(); - QCOMPARE(obj["Name"].toString(), QLatin1String("Test_global_VersionInfo")); - QCOMPARE(obj["Specification-Title"].toString(), QLatin1String("TR-03124")); - QCOMPARE(obj["Specification-Version"].toString(), QLatin1String("1.3")); + QCOMPARE(obj["Name"].toString(), QLatin1String("AusweisApp2")); + QCOMPARE(obj["Specification-Title"].toString(), QLatin1String("TR-03124-1")); + QCOMPARE(obj["Specification-Version"].toString(), QLatin1String("1.4")); QCOMPARE(obj["Specification-Vendor"].toString(), QLatin1String("Federal Office for Information Security")); - QCOMPARE(obj["Implementation-Title"].toString(), QLatin1String("Test_global_VersionInfo")); + QCOMPARE(obj["Implementation-Title"].toString(), QLatin1String("AusweisApp2")); QCOMPARE(obj["Implementation-Version"].toString(), QLatin1String("x.y.z")); QCOMPARE(obj["Implementation-Vendor"].toString(), QLatin1String("Governikus GmbH & Co. KG")); } @@ -99,11 +99,11 @@ class test_VersionInfo { auto text = VersionInfo::getInstance().toText(); - QVERIFY(text.contains(QLatin1String("Name: Test_global_VersionInfo"))); - QVERIFY(text.contains(QLatin1String("Specification-Title: TR-03124"))); - QVERIFY(text.contains(QLatin1String("Specification-Version: 1.3"))); + QVERIFY(text.contains(QLatin1String("Name: AusweisApp2"))); + QVERIFY(text.contains(QLatin1String("Specification-Title: TR-03124-1"))); + QVERIFY(text.contains(QLatin1String("Specification-Version: 1.4"))); QVERIFY(text.contains(QLatin1String("Specification-Vendor: Federal Office for Information Security"))); - QVERIFY(text.contains(QLatin1String("Implementation-Title: Test_global_VersionInfo"))); + QVERIFY(text.contains(QLatin1String("Implementation-Title: AusweisApp2"))); QVERIFY(text.contains(QLatin1String("Implementation-Version: x.y.z"))); QVERIFY(text.contains(QLatin1String("Implementation-Vendor: Governikus GmbH & Co. KG"))); } diff --git a/test/qt/global/test_VersionNumber.cpp b/test/qt/global/test_VersionNumber.cpp index ffae6ae20..3e5cccc61 100644 --- a/test/qt/global/test_VersionNumber.cpp +++ b/test/qt/global/test_VersionNumber.cpp @@ -167,18 +167,30 @@ class test_VersionNumber QTest::addColumn("beta"); QTest::newRow("") << true << false; - QTest::newRow("1.5.0+16-default-secret") << true << true; + QTest::newRow("1.5.0+16-default-secret") << true << false; QTest::newRow("1.6.0+1-draft-t34t53+") << true << false; - QTest::newRow("1.5.0") << true << true; + QTest::newRow("1.5.0") << false << false; QTest::newRow("1.6.0") << false << false; - QTest::newRow("1.5.0+0") << true << true; + QTest::newRow("1.5.0+0") << true << false; QTest::newRow("1.6.0+0") << true << false; QTest::newRow("1.6.0+422312-stable-2143eg435") << true << false; - QTest::newRow("1.9.0+422312-stable-2143eg435") << true << true; + QTest::newRow("1.9.0+422312-stable-2143eg435") << true << false; QTest::newRow("3.28.1") << false << false; QTest::newRow("3.28.1+23-default") << true << false; QTest::newRow(" 3.28.1+23-default ") << true << false; QTest::newRow(" 1.10.0 ") << false << false; + QTest::newRow("1.100.0") << true << true; + QTest::newRow("1.100.100") << true << true; + QTest::newRow("1.200.0") << true << true; + QTest::newRow("1.200.199") << true << true; + QTest::newRow("2.99.0") << false << false; + QTest::newRow("2.1.0") << false << false; + QTest::newRow("2.1.100") << true << true; + QTest::newRow("2.1.199") << true << true; + QTest::newRow("2.2.0") << false << false; + QTest::newRow("2.2.100") << true << true; + QTest::newRow("2.2.100+0") << true << true; + QTest::newRow("2.3.0+0") << true << false; } diff --git a/test/qt/ifd/messages/test_Discovery.cpp b/test/qt/ifd/messages/test_Discovery.cpp index abc59e5bf..b615285ad 100644 --- a/test/qt/ifd/messages/test_Discovery.cpp +++ b/test/qt/ifd/messages/test_Discovery.cpp @@ -400,16 +400,16 @@ class test_Discovery QTest::addColumn("incomplete"); QTest::newRow("v0 - fingerprint") << QByteArray(R"("IFDInterface_WebSocket_v0")") << fingerprint << fingerprint << false; - QTest::newRow("v0 - certificate") << QByteArray(R"("IFDInterface_WebSocket_v0")") << certificate << fingerprint << true; - QTest::newRow("v0 - not empty") << QByteArray(R"("IFDInterface_WebSocket_v0")") << QByteArray("0123456789ABCDEF") << QByteArray("0123456789ABCDEF") << true; + QTest::newRow("v0 - certificate") << QByteArray(R"("IFDInterface_WebSocket_v0")") << certificate << fingerprint << false; + QTest::newRow("v0 - not empty") << QByteArray(R"("IFDInterface_WebSocket_v0")") << QByteArray("0123456789ABCDEF") << QByteArray("0123456789ABCDEF") << false; QTest::newRow("v0 - empty") << QByteArray(R"("IFDInterface_WebSocket_v0")") << QByteArray() << QByteArray() << true; - QTest::newRow("v2 - fingerprint") << QByteArray(R"("IFDInterface_WebSocket_v2")") << fingerprint << fingerprint << true; + QTest::newRow("v2 - fingerprint") << QByteArray(R"("IFDInterface_WebSocket_v2")") << fingerprint << fingerprint << false; QTest::newRow("v2 - certificate") << QByteArray(R"("IFDInterface_WebSocket_v2")") << certificate << fingerprint << false; - QTest::newRow("v2 - not empty") << QByteArray(R"("IFDInterface_WebSocket_v2")") << QByteArray("0123456789ABCDEF") << QByteArray("0123456789ABCDEF") << true; + QTest::newRow("v2 - not empty") << QByteArray(R"("IFDInterface_WebSocket_v2")") << QByteArray("0123456789ABCDEF") << QByteArray("0123456789ABCDEF") << false; QTest::newRow("v2 - empty") << QByteArray(R"("IFDInterface_WebSocket_v2")") << QByteArray() << QByteArray() << true; - QTest::newRow("02 - fingerprint") << QByteArray(R"("IFDInterface_WebSocket_v0", "IFDInterface_WebSocket_v2")") << fingerprint << fingerprint << true; + QTest::newRow("02 - fingerprint") << QByteArray(R"("IFDInterface_WebSocket_v0", "IFDInterface_WebSocket_v2")") << fingerprint << fingerprint << false; QTest::newRow("02 - certificate") << QByteArray(R"("IFDInterface_WebSocket_v0", "IFDInterface_WebSocket_v2")") << certificate << fingerprint << false; - QTest::newRow("02 - not empty") << QByteArray(R"("IFDInterface_WebSocket_v0", "IFDInterface_WebSocket_v2")") << QByteArray("0123456789ABCDEF") << QByteArray("0123456789ABCDEF") << true; + QTest::newRow("02 - not empty") << QByteArray(R"("IFDInterface_WebSocket_v0", "IFDInterface_WebSocket_v2")") << QByteArray("0123456789ABCDEF") << QByteArray("0123456789ABCDEF") << false; QTest::newRow("02 - empty") << QByteArray(R"("IFDInterface_WebSocket_v0", "IFDInterface_WebSocket_v2")") << QByteArray() << QByteArray() << true; } @@ -444,14 +444,7 @@ class test_Discovery QCOMPARE(logSpy.count(), incomplete ? 1 : 0); if (incomplete) { - if (discovery.getSupportedApis().contains(IfdVersion::Version::v2)) - { - QVERIFY(TestFileHelper::containsLog(logSpy, QLatin1String("The value of \"IFDID\" should be of type \"X.509 certificate (PEM)\""))); - } - else - { - QVERIFY(TestFileHelper::containsLog(logSpy, QLatin1String("The value of \"IFDID\" should be of type \"certificate fingerprint (SHA256)\""))); - } + QVERIFY(TestFileHelper::containsLog(logSpy, QLatin1String("The value of IFDID should not be emtpy"))); } } diff --git a/test/qt/ifd/messages/test_IfdEstablishPaceChannel.cpp b/test/qt/ifd/messages/test_IfdEstablishPaceChannel.cpp index 629efe742..a014d5cf7 100644 --- a/test/qt/ifd/messages/test_IfdEstablishPaceChannel.cpp +++ b/test/qt/ifd/messages/test_IfdEstablishPaceChannel.cpp @@ -95,16 +95,14 @@ class test_IfdEstablishPaceChannel " \"ContextHandle\": \"TestContext\",\n" "[LENGTH]" " \"InputData\": \"[DATA]\",\n" - "[LENGTH_OLD]" " \"SlotHandle\": \"SlotHandle\",\n" " \"msg\": \"IFDEstablishPACEChannel\"\n" "}\n") .replace("[DATA]", inputApdu) - .replace("[LENGTH]", version >= IfdVersion::Version::v2 ? QByteArray(" \"ExpectedPINLength\": 6,\n") : QByteArray()) - .replace("[LENGTH_OLD]", version >= IfdVersion::Version::v2 ? QByteArray(" \"PreferredPinLength\": 6,\n") : QByteArray())); + .replace("[LENGTH]", version >= IfdVersion::Version::v2 ? QByteArray(" \"ExpectedPINLength\": 6,\n") : QByteArray())); const QJsonObject obj = QJsonDocument::fromJson(byteArray).object(); - QCOMPARE(obj.size(), version >= IfdVersion::Version::v2 ? 6 : 4); + QCOMPARE(obj.size(), version >= IfdVersion::Version::v2 ? 5 : 4); QCOMPARE(obj.value(QLatin1String("msg")).toString(), QStringLiteral("IFDEstablishPACEChannel")); QCOMPARE(obj.value(QLatin1String("ContextHandle")).toString(), QStringLiteral("TestContext")); QCOMPARE(obj.value(QLatin1String("SlotHandle")).toString(), QStringLiteral("SlotHandle")); @@ -337,46 +335,6 @@ class test_IfdEstablishPaceChannel } - void preferredPinLength_data() - { - QTest::addColumn("json"); - QTest::addColumn("preferredPinLength"); - - QTest::newRow("0") << QByteArray(R"("PreferredPinLength": 0,)") << 0; - QTest::newRow("5") << QByteArray(R"("PreferredPinLength": 5,)") << 5; - QTest::newRow("6") << QByteArray(R"("PreferredPinLength": 6,)") << 6; - QTest::newRow("both1") << QByteArray(R"("PreferredPinLength": 5, "ExpectedPINLength": 6,)") << 6; - QTest::newRow("both2") << QByteArray(R"("PreferredPinLength": 6, "ExpectedPINLength": 5,)") << 5; - QTest::newRow("both3") << QByteArray(R"("ExpectedPINLength": 5, "PreferredPinLength": 6,)") << 5; - QTest::newRow("both4") << QByteArray(R"("ExpectedPINLength": 6, "PreferredPinLength": 5,)") << 6; - } - - - void preferredPinLength() - { - QFETCH(QByteArray, json); - QFETCH(int, preferredPinLength); - - QByteArray message(R"({ - "ContextHandle": "TestContext", - "InputData": "0300000000", - [JSON] - "SlotHandle": "SlotHandle", - "msg": "IFDEstablishPACEChannel" - })"); - message.replace("[JSON]", json); - - const QJsonObject& obj = QJsonDocument::fromJson(message).object(); - const IfdEstablishPaceChannel ifdEstablishPaceChannel(obj); - QVERIFY(!ifdEstablishPaceChannel.isIncomplete()); - QCOMPARE(ifdEstablishPaceChannel.getType(), IfdMessageType::IFDEstablishPACEChannel); - QCOMPARE(ifdEstablishPaceChannel.getContextHandle(), QStringLiteral("TestContext")); - QCOMPARE(ifdEstablishPaceChannel.getSlotHandle(), QStringLiteral("SlotHandle")); - QCOMPARE(ifdEstablishPaceChannel.getInputData(), EstablishPaceChannel(PacePasswordId::PACE_PIN)); - QCOMPARE(ifdEstablishPaceChannel.getExpectedPinLength(), preferredPinLength); - } - - }; QTEST_GUILESS_MAIN(test_IfdEstablishPaceChannel) diff --git a/test/qt/ifd/messages/test_IfdStatus.cpp b/test/qt/ifd/messages/test_IfdStatus.cpp index 35659470e..71e63e211 100644 --- a/test/qt/ifd/messages/test_IfdStatus.cpp +++ b/test/qt/ifd/messages/test_IfdStatus.cpp @@ -7,7 +7,7 @@ #include "AppSettings.h" #include "LogHandler.h" #include "TestFileHelper.h" - +#include "VolatileSettings.h" #include @@ -27,6 +27,7 @@ class test_IfdStatus void initTestCase() { Env::getSingleton()->init(); + Env::getSingleton()->setUsedAsSDK(false); } @@ -432,7 +433,8 @@ class test_IfdStatus QCOMPARE(ifdStatus.getType(), IfdMessageType::IFDStatus); QCOMPARE(ifdStatus.getContextHandle(), QString()); QCOMPARE(ifdStatus.getSlotName(), slotName); - QCOMPARE(ifdStatus.hasPinPad(), !isBasicReader || (type == ReaderManagerPlugInType::NFC && pinPadMode)); + const bool isNfcOrSmart = type == ReaderManagerPlugInType::NFC || type == ReaderManagerPlugInType::SMART; + QCOMPARE(ifdStatus.hasPinPad(), !isBasicReader || (isNfcOrSmart && pinPadMode)); QCOMPARE(ifdStatus.getMaxApduLength(), maxApduLength); QCOMPARE(ifdStatus.getConnectedReader(), true); QCOMPARE(ifdStatus.getCardAvailable(), cardAvailable); diff --git a/test/qt/ifd/messages/test_IfdTransmit.cpp b/test/qt/ifd/messages/test_IfdTransmit.cpp index 58421a1a0..02d67d8e2 100644 --- a/test/qt/ifd/messages/test_IfdTransmit.cpp +++ b/test/qt/ifd/messages/test_IfdTransmit.cpp @@ -406,7 +406,7 @@ class test_IfdTransmit QCOMPARE(ifdTransmit.getInputApdu(), QByteArray::fromHex("00A402022F00")); QCOMPARE(logSpy.count(), 1); - QVERIFY(TestFileHelper::containsLog(logSpy, QLatin1String("Only using the first CommandAPDU. Command chaining ist not supported yet"))); + QVERIFY(TestFileHelper::containsLog(logSpy, QLatin1String("Only using the first CommandAPDU. Command chaining is not supported yet"))); } diff --git a/test/qt/ifd/messages/test_IfdTransmitResponse.cpp b/test/qt/ifd/messages/test_IfdTransmitResponse.cpp index b56a436b3..f9f2b3a84 100644 --- a/test/qt/ifd/messages/test_IfdTransmitResponse.cpp +++ b/test/qt/ifd/messages/test_IfdTransmitResponse.cpp @@ -353,7 +353,7 @@ class test_IfdTransmitResponse QCOMPARE(ifdTransmitResponse.getResultMinor(), ECardApiResult::Minor::null); QCOMPARE(logSpy.count(), 1); - QVERIFY(TestFileHelper::containsLog(logSpy, QLatin1String("Only using the first ResponseAPDU. Command chaining ist not supported yet"))); + QVERIFY(TestFileHelper::containsLog(logSpy, QLatin1String("Only using the first ResponseAPDU. Command chaining is not supported yet"))); } diff --git a/test/qt/ifd/remote/test_RemoteIfdReaderManagerPlugin.cpp b/test/qt/ifd/remote/test_RemoteIfdReaderManagerPlugin.cpp index ac743d157..21fde20cc 100644 --- a/test/qt/ifd/remote/test_RemoteIfdReaderManagerPlugin.cpp +++ b/test/qt/ifd/remote/test_RemoteIfdReaderManagerPlugin.cpp @@ -13,6 +13,7 @@ #include "MockIfdDispatcher.h" #include "Reader.h" #include "RemoteIfdClient.h" +#include "VolatileSettings.h" #include "messages/IfdConnect.h" #include "messages/IfdConnect.h" #include "messages/IfdDisconnect.h" @@ -46,11 +47,15 @@ class MockIfdClient MockIfdClient() = default; ~MockIfdClient() override = default; + void populateRemoteDevices(); void startDetection() override; void stopDetection() override; bool isDetecting() override; void establishConnection(const QSharedPointer& pEntry, const QString& pPsk) override; QVector getConnectedDeviceInfos() override; + void requestRemoteDevices() override; + + QVector> mRemoteDevices; }; @@ -83,6 +88,53 @@ QVector MockIfdClient::getConnectedDeviceInfo } +void MockIfdClient::requestRemoteDevices() +{ + Q_EMIT fireRemoteDevicesInfo(mRemoteDevices); +} + + +void MockIfdClient::populateRemoteDevices() +{ + const Discovery discovery("TestIfdName", "3ff02e8dc335f7ebb39299fbc12b66bf378445e59a68880e81464c50874e09cd", 1337, {IfdVersion::Version::latest}); + const IfdDescriptor ifdDescriptor(discovery, QHostAddress("127.0.0.1"), true); + mRemoteDevices = {QSharedPointer::create(ifdDescriptor)}; + auto& remoteServiceSettings = Env::getSingleton()->getRemoteServiceSettings(); + const QByteArray certData = R"(-----BEGIN CERTIFICATE----- + MIIFWDCCA0ACCQD1pPOO77lbczANBgkqhkiG9w0BAQsFADBuMQswCQYDVQQGEwJk + ZTEPMA0GA1UECAwGQnJlbWVuMQ8wDQYDVQQHDAZCcmVtZW4xEzARBgNVBAoMCkdv + dmVybmlrdXMxFDASBgNVBAsMC0F1c3dlaXNBcHAyMRIwEAYDVQQDDAlUZXN0SWZk + SWQwHhcNMjMwMzIxMTA0NzU3WhcNMjQwMzIwMTA0NzU3WjBuMQswCQYDVQQGEwJk + ZTEPMA0GA1UECAwGQnJlbWVuMQ8wDQYDVQQHDAZCcmVtZW4xEzARBgNVBAoMCkdv + dmVybmlrdXMxFDASBgNVBAsMC0F1c3dlaXNBcHAyMRIwEAYDVQQDDAlUZXN0SWZk + SWQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDBctLxnKgZ0JXt/Ylz + rCNV5urbEfOkGmta73yLxa8KS7okeQCWxytNtxaEpoq3pm/x9jHqaE6hmhEt/6iw + 8YeuiZj88+idY/L8iQDmuUGafkXl51BKRYP9LG4VokpZ68xGG2r83x7d0CFnSKpX + jvP8VlXKHtymXm+zCkGiea9urmYl1GvrlKbm92+vn/FKolfEqPL26UKx+Z96B/ld + dA44cq4zEDL3DGOoAtkZXFfdhkgCHr4hedp8+C3kOVTzZgxGpkjQ/Hl1vt0GU0rE + GvRfKKQYHcJqWor43sdtOL8k9h6LcvBKuG91LST0W/CpOKYjyri1rdf2jDpL/ziA + FWnAukwNcHb+Mstxuy6kfcZHQOb6YwTTV4LyFjvwcEaOsEoPIhOrFDvgsWBCz2+J + ILs+4GlN4hGu705cU+4Arg4SkIeuhZd2LiXfk/rZvXUZ+tEvTvVgFUpR3kowMI9i + FuHNHK7Sffp1ekyd139t864M96dyfNrrhYQpMOLaxz0wdgx2es5L3Bv9ZobLdtDh + F3ztfZvDqOF27EWiIOCoZfI/mf2T4dS9D40T9lxLm5F937yC3bG5NpyLA1EVCgbF + NrfTN19Cg0FkuUZLVUlPXs09NgkvsXAuTh3J2ar8bTr9T+aWuErdus7y0+dizz7p + r7MZmVLZfHZjKuIY5hfS33osBwIDAQABMA0GCSqGSIb3DQEBCwUAA4ICAQB0T2PE + f6FrFSjc0TBb+waI4Fr7iOu10IolXDRPZz/INTniHQ5mX6rb2FwMoq/YlVA16QFt + ZD5f2tUXOkYjFFwf7wZOkJAoTDmMrc7IA8HoRAVvNVCK7ub/1IczQrq4lZim7/jI + ZkwjN38j2CXqgMmZbhybkvVs4AAydQuLeATVhdFkgmpghU+9zDnUAuayMgAFOeiO + +mCVRG1fdVrWhxUcOVbn5GFSEZKLCzS+O8ak5FNza61Vm5jl0VVDkX9yFmnjiryz + /s7clpt0N4lAGiLPNWdmWkOdF1iJ23mJLveC/mOurImxqlYVa7djfR8MmJzQw1vM + IlnAGgKYEYjx5+n++EYv2h/GQZv+o+qaOLq8bebak6lVYqS/0jjDQw1tsA2d29SW + y3A92KgkXO8ks+hxTEdCZQrbYIOG+9DvgO9NsZc0qLM2WKTPJhcBfWDg+cRJvw9G + iA4KpHtGJf3SU1fUlQrhxzUcRZhs4LQFugO5VSHPq8fYdrkt/Fm9fgQ8JchG8khj + kXIFNWkrffo2EQDVmYANdKeX3jWdLqDmhNiikZOsmk55HYvC1weve3o3e8gQ6HzA + 2bTkcBAcG6AkIvadj8/nwm6wSp+1r3X+6Sor1Eml2K1p30j4ArEgTZWUwpd6jqy3 + Scj66lxkQJPrpseT8+JcB/ob+qspBKH7zvTTuQ== + -----END CERTIFICATE-----)"; + remoteServiceSettings.addTrustedCertificate(QSslCertificate(certData)); +} + + class test_RemoteIfdReaderManagerPlugIn : public QObject { @@ -102,6 +154,12 @@ class test_RemoteIfdReaderManagerPlugIn } private Q_SLOTS: + void initTestCase() + { + Env::getSingleton()->setUsedAsSDK(false); + } + + void init() { mNetworkThread.setObjectName(QStringLiteral("NetworkThread")); @@ -152,6 +210,46 @@ class test_RemoteIfdReaderManagerPlugIn } + void testDisconnectWithAdvertisedReader() + { + QSignalSpy spySend(mDispatcher1.data(), &MockIfdDispatcher::fireSend); + + Q_EMIT mIfdClient->fireNewDispatcher(mDispatcher1); + QTRY_COMPARE(spySend.count(), 1); // clazy:exclude=qstring-allocations + spySend.clear(); + + QSharedPointer message; + QSignalSpy spyAdded(mPlugin.data(), &ReaderManagerPlugIn::fireReaderAdded); + QSignalSpy spyUpdated(mPlugin.data(), &ReaderManagerPlugIn::fireReaderPropertiesUpdated); + QSignalSpy spyRemoved(mPlugin.data(), &ReaderManagerPlugIn::fireReaderRemoved); + + ReaderInfo info(QStringLiteral("NFC Reader"), ReaderManagerPlugInType::NFC); + info.setBasicReader(true); + info.setMaxApduLength(500); + Env::getSingleton()->getRemoteServiceSettings().setPinPadMode(false); + message.reset(new IfdStatus(info)); + message->mConnectedReader = false; + mDispatcher1->onReceived(message); + QCOMPARE(mPlugin->getReaders().size(), 0); + QCOMPARE(spySend.size(), 0); + QCOMPARE(spyAdded.size(), 1); + QCOMPARE(getReaderInfo(spyAdded).getName(), QStringLiteral("NFC Reader#TestContext")); + QCOMPARE(spyUpdated.size(), 0); + QCOMPARE(spyRemoved.size(), 0); + QCOMPARE(mPlugin->getReaders().size(), 0); + + mDispatcher1->onClosed(); + QCOMPARE(spySend.size(), 0); + QCOMPARE(spyAdded.size(), 0); + QCOMPARE(spyUpdated.size(), 0); + QCOMPARE(spyRemoved.size(), 1); + const auto removedInfo = getReaderInfo(spyRemoved); + QCOMPARE(removedInfo.getName(), QStringLiteral("NFC Reader#TestContext")); + QCOMPARE(removedInfo.isValid(), false); + QCOMPARE(mPlugin->getReaders().size(), 0); + } + + void testSingleDispatcherSingleReaderAddRemoveWithoutCard() { QSignalSpy spySend(mDispatcher1.data(), &MockIfdDispatcher::fireSend); @@ -162,6 +260,7 @@ class test_RemoteIfdReaderManagerPlugIn QSharedPointer message; QSignalSpy spyAdded(mPlugin.data(), &ReaderManagerPlugIn::fireReaderAdded); + QSignalSpy spyUpdated(mPlugin.data(), &ReaderManagerPlugIn::fireReaderPropertiesUpdated); QSignalSpy spyRemoved(mPlugin.data(), &ReaderManagerPlugIn::fireReaderRemoved); ReaderInfo info(QStringLiteral("NFC Reader"), ReaderManagerPlugInType::NFC); @@ -174,8 +273,11 @@ class test_RemoteIfdReaderManagerPlugIn QCOMPARE(spySend.size(), 0); QCOMPARE(spyAdded.size(), 1); QCOMPARE(getReaderInfo(spyAdded).getName(), QStringLiteral("NFC Reader#TestContext")); + QCOMPARE(spyUpdated.size(), 0); + QCOMPARE(spyRemoved.size(), 0); QCOMPARE(mPlugin->getReaders().size(), 1); QCOMPARE(mPlugin->getReaders().at(0)->getName(), QStringLiteral("NFC Reader#TestContext")); + QCOMPARE(mPlugin->getReaders().at(0)->getReaderInfo().isValid(), true); QCOMPARE(mPlugin->getReaders().at(0)->getReaderInfo().isBasicReader(), true); QCOMPARE(mPlugin->getReaders().at(0)->getReaderInfo().getMaxApduLength(), 500); @@ -185,21 +287,33 @@ class test_RemoteIfdReaderManagerPlugIn QCOMPARE(mPlugin->getReaders().size(), 0); QCOMPARE(spySend.size(), 0); QCOMPARE(spyAdded.size(), 0); - QCOMPARE(spyRemoved.size(), 1); - QCOMPARE(getReaderInfo(spyRemoved).getName(), QStringLiteral("NFC Reader#TestContext")); + QCOMPARE(spyUpdated.size(), 1); + const auto updateInfo1 = getReaderInfo(spyUpdated); + QCOMPARE(updateInfo1.getName(), QStringLiteral("NFC Reader#TestContext")); + QCOMPARE(updateInfo1.isValid(), false); + QCOMPARE(spyRemoved.size(), 0); + QCOMPARE(mPlugin->getReaders().size(), 0); message.reset(new IfdStatus(info)); message->mConnectedReader = true; mDispatcher1->onReceived(message); + QCOMPARE(spyAdded.size(), 0); + QCOMPARE(spyUpdated.size(), 1); + const auto updateInfo2 = getReaderInfo(spyUpdated); + QCOMPARE(updateInfo2.getName(), QStringLiteral("NFC Reader#TestContext")); + QCOMPARE(updateInfo2.isValid(), true); + QCOMPARE(spyRemoved.size(), 0); QCOMPARE(mPlugin->getReaders().size(), 1); QCOMPARE(mPlugin->getReaders().at(0)->getName(), QStringLiteral("NFC Reader#TestContext")); - spyAdded.clear(); mDispatcher1->onClosed(); QCOMPARE(spySend.size(), 0); QCOMPARE(spyAdded.size(), 0); + QCOMPARE(spyUpdated.size(), 0); QCOMPARE(spyRemoved.size(), 1); - QCOMPARE(getReaderInfo(spyRemoved).getName(), QStringLiteral("NFC Reader#TestContext")); + const auto removedInfo = getReaderInfo(spyRemoved); + QCOMPARE(removedInfo.getName(), QStringLiteral("NFC Reader#TestContext")); + QCOMPARE(removedInfo.isValid(), true); QCOMPARE(mPlugin->getReaders().size(), 0); } @@ -248,6 +362,7 @@ class test_RemoteIfdReaderManagerPlugIn QSharedPointer message; QSignalSpy spyAdded(mPlugin.data(), &ReaderManagerPlugIn::fireReaderAdded); + QSignalSpy spyUpdated(mPlugin.data(), &ReaderManagerPlugIn::fireReaderPropertiesUpdated); QSignalSpy spyRemoved(mPlugin.data(), &ReaderManagerPlugIn::fireReaderRemoved); ReaderInfo info1(QStringLiteral("NFC Reader 1"), ReaderManagerPlugInType::NFC); @@ -268,6 +383,7 @@ class test_RemoteIfdReaderManagerPlugIn QCOMPARE(spyAdded.size(), 2); QCOMPARE(getReaderInfo(spyAdded).getName(), QStringLiteral("NFC Reader 1#TestContext")); QCOMPARE(getReaderInfo(spyAdded).getName(), QStringLiteral("NFC Reader 2#TestContext")); + QCOMPARE(spyUpdated.size(), 0); QCOMPARE(spyRemoved.size(), 0); QCOMPARE(mPlugin->getReaders().size(), 2); QCOMPARE(mPlugin->getReaders().at(0)->getName(), QStringLiteral("NFC Reader 1#TestContext")); @@ -280,8 +396,11 @@ class test_RemoteIfdReaderManagerPlugIn QCOMPARE(spySend1.size(), 0); QCOMPARE(spySend2.size(), 0); QCOMPARE(spyAdded.size(), 0); - QCOMPARE(spyRemoved.size(), 1); - QCOMPARE(getReaderInfo(spyRemoved).getName(), QStringLiteral("NFC Reader 1#TestContext")); + QCOMPARE(spyUpdated.size(), 1); + const auto updateInfo1 = getReaderInfo(spyUpdated); + QCOMPARE(updateInfo1.getName(), QStringLiteral("NFC Reader 1#TestContext")); + QCOMPARE(updateInfo1.isValid(), false); + QCOMPARE(spyRemoved.size(), 0); QCOMPARE(mPlugin->getReaders().size(), 1); QCOMPARE(mPlugin->getReaders().at(0)->getName(), QStringLiteral("NFC Reader 2#TestContext")); @@ -291,8 +410,11 @@ class test_RemoteIfdReaderManagerPlugIn QCOMPARE(spySend1.size(), 0); QCOMPARE(spySend2.size(), 0); - QCOMPARE(spyAdded.size(), 1); - QCOMPARE(getReaderInfo(spyAdded).getName(), QStringLiteral("NFC Reader 1#TestContext")); + QCOMPARE(spyAdded.size(), 0); + QCOMPARE(spyUpdated.size(), 1); + const auto updateInfo2 = getReaderInfo(spyUpdated); + QCOMPARE(updateInfo2.getName(), QStringLiteral("NFC Reader 1#TestContext")); + QCOMPARE(updateInfo2.isValid(), true); QCOMPARE(spyRemoved.size(), 0); QCOMPARE(mPlugin->getReaders().size(), 2); QCOMPARE(mPlugin->getReaders().at(0)->getName(), QStringLiteral("NFC Reader 1#TestContext")); @@ -302,8 +424,11 @@ class test_RemoteIfdReaderManagerPlugIn QCOMPARE(spySend1.size(), 0); QCOMPARE(spySend2.size(), 0); QCOMPARE(spyAdded.size(), 0); + QCOMPARE(spyUpdated.size(), 0); QCOMPARE(spyRemoved.size(), 1); - QCOMPARE(getReaderInfo(spyRemoved).getName(), QStringLiteral("NFC Reader 1#TestContext")); + const auto removedInfo1 = getReaderInfo(spyRemoved); + QCOMPARE(removedInfo1.getName(), QStringLiteral("NFC Reader 1#TestContext")); + QCOMPARE(removedInfo1.isValid(), true); QCOMPARE(mPlugin->getReaders().size(), 1); QCOMPARE(mPlugin->getReaders().at(0)->getName(), QStringLiteral("NFC Reader 2#TestContext")); @@ -311,8 +436,11 @@ class test_RemoteIfdReaderManagerPlugIn QCOMPARE(spySend1.size(), 0); QCOMPARE(spySend2.size(), 0); QCOMPARE(spyAdded.size(), 0); + QCOMPARE(spyUpdated.size(), 0); QCOMPARE(spyRemoved.size(), 1); - QCOMPARE(getReaderInfo(spyRemoved).getName(), QStringLiteral("NFC Reader 2#TestContext")); + const auto removedInfo2 = getReaderInfo(spyRemoved); + QCOMPARE(removedInfo2.getName(), QStringLiteral("NFC Reader 2#TestContext")); + QCOMPARE(removedInfo2.isValid(), true); QCOMPARE(mPlugin->getReaders().size(), 0); } @@ -527,6 +655,44 @@ class test_RemoteIfdReaderManagerPlugIn } + void testConnectionAttemptConnectionNeverFinished() + { + mIfdClient->populateRemoteDevices(); + + mPlugin->connectToPairedReaders(); + QTRY_COMPARE(mPlugin->mConnectionAttempts.size(), 1); // clazy:exclude=qstring-allocations + + mPlugin->connectToPairedReaders(); + QTRY_COMPARE(mPlugin->mConnectionAttempts.size(), 1); // clazy:exclude=qstring-allocations + } + + + void testConnectionAttemptDeviceVanished() + { + mIfdClient->populateRemoteDevices(); + + mPlugin->connectToPairedReaders(); + QTRY_COMPARE(mPlugin->mConnectionAttempts.size(), 1); // clazy:exclude=qstring-allocations + + QTest::ignoreMessage(QtInfoMsg, "Removing \"3ff02e8dc335f7ebb39299fbc12b66bf378445e59a68880e81464c50874e09cd\" from connection attempt list as it has vanished"); + Q_EMIT mIfdClient->fireDeviceVanished(mIfdClient->mRemoteDevices.first()); + QTRY_COMPARE(mPlugin->mConnectionAttempts.size(), 0); // clazy:exclude=qstring-allocations + } + + + void testConnectionAttemptConnectionDone() + { + mIfdClient->populateRemoteDevices(); + + mPlugin->connectToPairedReaders(); + QTRY_COMPARE(mPlugin->mConnectionAttempts.size(), 1); // clazy:exclude=qstring-allocations + + QTest::ignoreMessage(QtInfoMsg, "Removing \"3ff02e8dc335f7ebb39299fbc12b66bf378445e59a68880e81464c50874e09cd\" from connection attempt list as the request finished with No_Error | \"No error occurred.\""); + Q_EMIT mIfdClient->fireEstablishConnectionDone(mIfdClient->mRemoteDevices.first(), GlobalStatus::Code::No_Error); + QTRY_COMPARE(mPlugin->mConnectionAttempts.size(), 0); // clazy:exclude=qstring-allocations + } + + void testKeepNormalConnection() { QSignalSpy spySend(mDispatcher1.data(), &MockIfdDispatcher::fireSend); diff --git a/test/qt/ifd/remote/test_RemoteTlsServer.cpp b/test/qt/ifd/remote/test_RemoteTlsServer.cpp index d8ad1eb2c..616794c3d 100644 --- a/test/qt/ifd/remote/test_RemoteTlsServer.cpp +++ b/test/qt/ifd/remote/test_RemoteTlsServer.cpp @@ -73,11 +73,7 @@ class test_RemoteTlsServer client.connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort()); QTRY_COMPARE(clientErrors.count(), 1); // clazy:exclude=qstring-allocations -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) QCOMPARE(clientErrors.takeFirst().at(0).value(), QAbstractSocket::SocketError::SslHandshakeFailedError); -#else - QCOMPARE(clientErrors.takeFirst().at(0).value(), QAbstractSocket::SocketError::RemoteHostClosedError); -#endif QCOMPARE(clientEncrypted.count(), 0); QCOMPARE(clientPsk.count(), 0); } diff --git a/test/qt/ifd/test_IfdListImpl.cpp b/test/qt/ifd/test_IfdListImpl.cpp index de9f26501..772893ed4 100644 --- a/test/qt/ifd/test_IfdListImpl.cpp +++ b/test/qt/ifd/test_IfdListImpl.cpp @@ -2,7 +2,7 @@ * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany */ -#include "IfdList.h" +#include "IfdListImpl.h" #include "messages/Discovery.h" diff --git a/test/qt/ifd/test_ServerMessageHandler.cpp b/test/qt/ifd/test_ServerMessageHandler.cpp index cb9f07ddf..c1d236f2b 100644 --- a/test/qt/ifd/test_ServerMessageHandler.cpp +++ b/test/qt/ifd/test_ServerMessageHandler.cpp @@ -116,8 +116,9 @@ class test_ServerMessageHandler { Env::getSingleton()->init(); const auto readerManager = Env::getSingleton(); + QSignalSpy spy(readerManager, &ReaderManager::fireInitialized); readerManager->init(); - readerManager->isScanRunning(); // just to wait until initialization finished + QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations Env::setCreator(std::function& pDataChannel)>([this](const QSharedPointer){ mDispatcher = new MockIfdMessageDispatcherServer(mDataChannel); diff --git a/test/qt/network/test_HttpResponse.cpp b/test/qt/network/test_HttpResponse.cpp index 0b7266d28..a9a7481c7 100644 --- a/test/qt/network/test_HttpResponse.cpp +++ b/test/qt/network/test_HttpResponse.cpp @@ -34,8 +34,8 @@ class test_HttpResponse QVERIFY(msg.contains("HTTP/1.0 203 Non-Authoritative Information")); QVERIFY(msg.contains("Content-Length: 0")); QVERIFY(msg.contains("Date: ")); - QVERIFY(msg.contains("Server: Test_network_HttpResponse/1.2 (TR-03124-1/1.3)")); - QCOMPARE(msg.size(), 158); + QVERIFY(msg.contains("Server: AusweisApp2/1.2 (TR-03124-1/1.4)")); + QCOMPARE(msg.size(), 144); } @@ -48,7 +48,7 @@ class test_HttpResponse QVERIFY(msg.contains("HTTP/1.0 200 OK")); QVERIFY(msg.contains("Content-Length: 21")); QVERIFY(msg.contains("Content-Type: text/plain")); - QVERIFY(msg.contains("Server: Test_network_HttpResponse/1.2 (TR-03124-1/1.3)")); + QVERIFY(msg.contains("Server: AusweisApp2/1.2 (TR-03124-1/1.4)")); QVERIFY(msg.contains("\r\n\r\nthis is dummy content")); } diff --git a/test/qt/network/test_NetworkManager.cpp b/test/qt/network/test_NetworkManager.cpp index a7c8f016d..417f24870 100644 --- a/test/qt/network/test_NetworkManager.cpp +++ b/test/qt/network/test_NetworkManager.cpp @@ -39,8 +39,9 @@ class test_NetworkManager Env::getSingleton()->init(); const auto readerManager = Env::getSingleton(); + QSignalSpy spy(readerManager, &ReaderManager::fireInitialized); readerManager->init(); - readerManager->isScanRunning(); // just to wait until initialization finished + QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations } diff --git a/test/qt/network/test_TlsChecker.cpp b/test/qt/network/test_TlsChecker.cpp index bb23f6b0c..d06ab8406 100644 --- a/test/qt/network/test_TlsChecker.cpp +++ b/test/qt/network/test_TlsChecker.cpp @@ -34,7 +34,7 @@ class test_TlsChecker static QSslKey createQSslKeyWithHandle(const QByteArray& pPemEncodedEvpPKey) { BIO* bio = BIO_new(BIO_s_mem()); - BIO_write(bio, pPemEncodedEvpPKey.constData(), pPemEncodedEvpPKey.length()); + BIO_write(bio, pPemEncodedEvpPKey.constData(), static_cast(pPemEncodedEvpPKey.length())); QSslKey key(PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr), QSsl::PublicKey); BIO_free(bio); return key; @@ -306,7 +306,11 @@ class test_TlsChecker QVERIFY(logSpy.at(0).at(0).toString().contains("Used session cipher QSslCipher(name=, bits=0, proto=)")); QVERIFY(logSpy.at(1).at(0).toString().contains("Used session protocol: \"UnknownProtocol\"")); QVERIFY(logSpy.at(2).at(0).toString().contains("Used ephemeral server key:")); +#if (QT_VERSION < QT_VERSION_CHECK(6, 5, 0)) QVERIFY(logSpy.at(3).at(0).toString().contains("Used peer certificate: QSslCertificate(\"\", \"\", \"1B2M2Y8AsgTpgAmY7PhCfg==\"")); +#else + QVERIFY(logSpy.at(3).at(0).toString().contains(R"(Used peer certificate: QSslCertificate(Version="", SerialNumber="", Digest="1B2M2Y8AsgTpgAmY7PhCfg==", Issuer="", Subject="", AlternativeSubjectNames=QMultiMap(), EffectiveDate=QDateTime(Invalid), ExpiryDate=QDateTime(Invalid))")); +#endif QVERIFY(logSpy.at(4).at(0).toString().contains("Used ssl session: \"\"")); QVERIFY(logSpy.at(5).at(0).toString().contains("Handshake of tls connection done!")); } diff --git a/test/qt/secure_storage/test_SecureStorage.cpp b/test/qt/secure_storage/test_SecureStorage.cpp index 2e8e81a3c..43d70fc74 100644 --- a/test/qt/secure_storage/test_SecureStorage.cpp +++ b/test/qt/secure_storage/test_SecureStorage.cpp @@ -8,7 +8,6 @@ #include "SecureStorage.h" -#include "JsonValueRef.h" #include "ResourceLoader.h" #include "asn1/CVCertificate.h" @@ -48,7 +47,7 @@ class test_SecureStorage QStringList comments; const auto& commentValueArray = commentValues.toArray(); - for (JsonValueRef comment : commentValueArray) + for (const QJsonValueConstRef comment : commentValueArray) { if (comment.isString()) { @@ -74,7 +73,7 @@ class test_SecureStorage void testGetCVRootCertificatesUnique() { const auto secureStorage = Env::getSingleton(); - static const int EXPECTED_CERTIFICATE_COUNT = 16; + static const int EXPECTED_CERTIFICATE_COUNT = 17; QVector> cvcs = CVCertificate::fromRaw(secureStorage->getCVRootCertificates(true)) + CVCertificate::fromRaw(secureStorage->getCVRootCertificates(false)); @@ -115,7 +114,7 @@ class test_SecureStorage QTest::addColumn("commentName"); QTest::newRow("production") << 5 << true << "_comment_2"; - QTest::newRow("test") << 11 << false << "_comment_4"; + QTest::newRow("test") << 12 << false << "_comment_4"; } @@ -220,6 +219,7 @@ class test_SecureStorage QFETCH(QString, expiryDate); QFETCH(int, length); QFETCH(QSsl::KeyAlgorithm, algorithm); + QFETCH(QString, ocsp); QVERIFY(certificates.count() - index > 0); @@ -232,18 +232,12 @@ class test_SecureStorage QCOMPARE(cert.publicKey().algorithm(), algorithm); QCOMPARE(cert.publicKey().type(), QSsl::PublicKey); - // Disable check on older Qt versions, since it leads to a memory leak. -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) - QFETCH(QString, ocsp); - const auto& ext = cert.extensions(); - const bool foundOcspResponder = std::any_of(ext.cbegin(), ext.cend(), [&ocsp](const auto& entry){ return entry.name() == QLatin1String("authorityInfoAccess") && entry.value().toMap().value(QStringLiteral("OCSP")).toString() == ocsp; }); QCOMPARE(foundOcspResponder, !ocsp.isEmpty()); -#endif } @@ -293,13 +287,11 @@ class test_SecureStorage if (secureStorage->getVendor().contains(QLatin1String("Governikus"))) { QVERIFY(!secureStorage->getSmartServiceId().isEmpty()); - QVERIFY(!secureStorage->getSmartVersionTag().isEmpty()); QVERIFY(!secureStorage->getSmartSsdAid().isEmpty()); } else { QVERIFY(secureStorage->getSmartServiceId().isEmpty()); - QVERIFY(secureStorage->getSmartVersionTag().isEmpty()); QVERIFY(secureStorage->getSmartSsdAid().isEmpty()); } } @@ -313,8 +305,9 @@ class test_SecureStorage QCOMPARE(secureStorage->getLocalIfdMinPskSize(), 256); const auto& certificateHashes = secureStorage->getLocalIfdAllowedCertificateHashes(); - QCOMPARE(certificateHashes.size(), 2); + QCOMPARE(certificateHashes.size(), 3); QVERIFY(certificateHashes.contains(QByteArray::fromHex(QByteArrayLiteral("B02AC76B50A497AE810AEAC22598187B3D4290277D0851A7FA8E1AEA5A979870")))); + QVERIFY(certificateHashes.contains(QByteArray::fromHex(QByteArrayLiteral("F4A4D85A22103EBB5F4D35AEDE5117F40E591AB5DDF43DF39C953D08E3895138")))); QVERIFY(certificateHashes.contains(QByteArray::fromHex(QByteArrayLiteral("F96FD6BBA899845E06D3E6522F0843217681D473B6B09F1E313DEA1A21D6B8E7")))); } diff --git a/test/qt/settings/test_GeneralSettings.cpp b/test/qt/settings/test_GeneralSettings.cpp index 8e2be1abf..3e0c732d6 100644 --- a/test/qt/settings/test_GeneralSettings.cpp +++ b/test/qt/settings/test_GeneralSettings.cpp @@ -9,9 +9,11 @@ #include "GeneralSettings.h" #include "AppSettings.h" -#include "AutoStart.h" #include "Env.h" #include "VolatileSettings.h" +#ifdef Q_OS_WIN + #include "AutoStart.h" +#endif #include #include @@ -263,6 +265,8 @@ class test_GeneralSettings QCOMPARE(settings.getPersistentSettingsVersion(), QString()); QCOMPARE(settings.isNewAppVersion(), false); QCOMPARE(settings.getLastReaderPluginType(), QString()); + QCOMPARE(settings.isUseSystemFont(), false); + QCOMPARE(settings.getDarkMode(), QString()); } @@ -474,6 +478,89 @@ class test_GeneralSettings } + void testSmartUpdate() + { + auto& settings = Env::getSingleton()->getGeneralSettings(); + QSignalSpy smartSpy(&settings, &GeneralSettings::fireSmartAvailableChanged); + + QCOMPARE(smartSpy.count(), 0); + QCOMPARE(settings.doSmartUpdate(), true); + QCOMPARE(settings.isSmartAvailable(), false); + + settings.setSmartAvailable(false); + QCOMPARE(smartSpy.count(), 0); + QCOMPARE(settings.doSmartUpdate(), false); + QCOMPARE(settings.isSmartAvailable(), false); + + settings.setSmartAvailable(true); + QCOMPARE(smartSpy.count(), 1); + QCOMPARE(smartSpy.at(0).at(0), true); + QCOMPARE(settings.doSmartUpdate(), false); + QCOMPARE(settings.isSmartAvailable(), true); + + settings.setSmartAvailable(true); + QCOMPARE(smartSpy.count(), 1); + QCOMPARE(settings.doSmartUpdate(), false); + QCOMPARE(settings.isSmartAvailable(), true); + + settings.setSmartAvailable(false); + QCOMPARE(smartSpy.count(), 2); + QCOMPARE(smartSpy.at(1).at(0), false); + QCOMPARE(settings.doSmartUpdate(), false); + QCOMPARE(settings.isSmartAvailable(), false); + } + + + void testUseSystemFont() + { + auto& settings = Env::getSingleton()->getGeneralSettings(); + QSignalSpy fontSpy(&settings, &GeneralSettings::fireUseSystemFontChanged); + + QCOMPARE(fontSpy.count(), 0); + QCOMPARE(settings.isUseSystemFont(), false); + + settings.setUseSystemFont(true); + QCOMPARE(fontSpy.count(), 1); + QCOMPARE(settings.isUseSystemFont(), true); + + settings.setUseSystemFont(false); + QCOMPARE(fontSpy.count(), 2); + QCOMPARE(settings.isUseSystemFont(), false); + } + + + void testDarkMode() + { + auto& settings = Env::getSingleton()->getGeneralSettings(); + QSignalSpy darkSpy(&settings, &GeneralSettings::fireDarkModeChanged); + QCOMPARE(darkSpy.count(), 0); + + const auto initialMode = settings.getDarkMode(); + + const auto systemMode = QStringLiteral("AUTO"); + settings.setDarkMode(systemMode); + QCOMPARE(darkSpy.count(), 1); + QCOMPARE(settings.getDarkMode(), systemMode); + + settings.setDarkMode(initialMode); + QCOMPARE(darkSpy.count(), 2); + QCOMPARE(settings.getDarkMode(), initialMode); + } + + + void testShowTrayIcon() + { + auto& settings = Env::getSingleton()->getGeneralSettings(); +#if defined(Q_OS_WIN) || defined(Q_OS_MACOS) + QCOMPARE(settings.showTrayIcon(), settings.isAutoStart()); + settings.setAutoStart(!settings.isAutoStart()); + QCOMPARE(settings.showTrayIcon(), settings.isAutoStart()); +#else + QCOMPARE(settings.showTrayIcon(), true); +#endif + } + + }; QTEST_GUILESS_MAIN(test_GeneralSettings) diff --git a/test/qt/settings/test_HistorySettings.cpp b/test/qt/settings/test_HistorySettings.cpp deleted file mode 100644 index e103a9efc..000000000 --- a/test/qt/settings/test_HistorySettings.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/** - * Copyright (c) 2014-2023 Governikus GmbH & Co. KG, Germany - */ - -/*! - * \brief Unit tests for History. - * - * All tests end with _QTEST to be able to identify them later. - * All original history entry from AusweisApp2 do not have this. - */ - -#include "HistorySettings.h" - -#include "AppSettings.h" -#include "Env.h" -#include "VolatileSettings.h" - -#include "TestFileHelper.h" - -#include -#include - -using namespace governikus; - -class test_HistorySettings - : public QObject -{ - Q_OBJECT - - private Q_SLOTS: - void init() - { - QCoreApplication::setOrganizationName(QStringLiteral("dummy")); - Env::getSingleton()->getHistorySettings().deleteSettings(); - } - - - void testEnabled() - { - auto& settings = Env::getSingleton()->getHistorySettings(); - bool initial = settings.isEnabled(); - - settings.setEnabled(!initial); - QCOMPARE(settings.isEnabled(), !initial); - - settings.setEnabled(initial); - QCOMPARE(settings.isEnabled(), initial); - } - - - void testHistoryEntries() - { - SDK_MODE(false); - auto& settings = Env::getSingleton()->getHistorySettings(); - QVector initial = settings.getHistoryInfos(); - HistoryInfo info("pSubjectName", "pSubjectUrl", "pUsage", QDateTime(), "pTermOfUsage", {"pRequestedData"}); - QVector newValue(initial); - newValue.prepend(info); // new values will be prepended, so that it appears on top - - settings.addHistoryInfo(info); - QCOMPARE(settings.getHistoryInfos(), newValue); - } - - - void testDeleteHistory() - { - SDK_MODE(false); - auto& settings = Env::getSingleton()->getHistorySettings(); - HistoryInfo info("pSubjectName", "pSubjectUrl", "pUsage", QDateTime(), "pTermOfUsage", {"pRequestedData"}); - settings.addHistoryInfo(info); - - QCOMPARE(settings.getHistoryInfos().size(), 1); - - settings.deleteSettings(); - - QCOMPARE(settings.getHistoryInfos().size(), 0); - } - - - void testDeleteHistoryFromFile() - { - SDK_MODE(false); - auto& settings = Env::getSingleton()->getHistorySettings(); - const auto file = AbstractSettings::mTestDir->path() + QStringLiteral("/dummy/Test_settings_HistorySettings.ini"); - - HistoryInfo info("pSubjectXYZ", "pSubjectUrlXYZ", "pUsageXYZ", QDateTime(), "pTermOfUsageXYZ", {"pRequestedDataXYZ"}); - settings.addHistoryInfo(info); - settings.addHistoryInfo(info); - settings.addHistoryInfo(info); - QVERIFY(QFile::exists(file)); - - auto content = TestFileHelper::readFile(file); - QVERIFY(content.contains("pSubjectXYZ")); - QVERIFY(content.contains("pSubjectUrlXYZ")); - QVERIFY(content.contains("pUsageXYZ")); - QVERIFY(content.contains("pTermOfUsageXYZ")); - QVERIFY(content.contains("pRequestedDataXYZ")); - - settings.deleteSettings(); - - content = TestFileHelper::readFile(file); - QVERIFY(!content.contains("pSubjectXYZ")); - QVERIFY(!content.contains("pSubjectUrlXYZ")); - QVERIFY(!content.contains("pUsageXYZ")); - QVERIFY(!content.contains("pTermOfUsageXYZ")); - QVERIFY(!content.contains("pRequestedDataXYZ")); - } - - -}; - -QTEST_GUILESS_MAIN(test_HistorySettings) -#include "test_HistorySettings.moc" diff --git a/test/qt/settings/test_KeyPair.cpp b/test/qt/settings/test_KeyPair.cpp index 570330d22..c850652a7 100644 --- a/test/qt/settings/test_KeyPair.cpp +++ b/test/qt/settings/test_KeyPair.cpp @@ -26,13 +26,31 @@ class test_KeyPair KeyPair pair2 = KeyPair::generate(); private Q_SLOTS: + void validKey_data() + { + QTest::addColumn("algorithm"); + QTest::addColumn("size"); + QTest::addColumn("curve"); + + QTest::newRow("RSA") << QSsl::Rsa << 2048 << QLatin1String(); + QTest::newRow("prime256v1") << QSsl::Ec << 256 << QLatin1String("prime256v1"); + QTest::newRow("secp384r1") << QSsl::Ec << 384 << QLatin1String("secp384r1"); + QTest::newRow("brainpoolP512r1") << QSsl::Ec << 512 << QLatin1String("brainpoolP512r1"); + } + + void validKey() { - QVERIFY(pair1.isValid()); - const auto& key = pair1.getKey(); + QFETCH(QSsl::KeyAlgorithm, algorithm); + QFETCH(int, size); + QFETCH(QLatin1String, curve); + + KeyPair pair = KeyPair::generate(curve.data()); + QVERIFY(pair.isValid()); + const auto& key = pair.getKey(); QVERIFY(!key.isNull()); - QCOMPARE(key.length(), 2048); - QCOMPARE(key.algorithm(), QSsl::Rsa); + QCOMPARE(key.length(), size); + QCOMPARE(key.algorithm(), algorithm); QCOMPARE(key.type(), QSsl::PrivateKey); } @@ -47,10 +65,28 @@ class test_KeyPair } + void validCertificate_data() + { + QTest::addColumn("algorithm"); + QTest::addColumn("size"); + QTest::addColumn("curve"); + + QTest::newRow("RSA") << QSsl::Rsa << 2048 << QLatin1String(); + QTest::newRow("prime256v1") << QSsl::Ec << 256 << QLatin1String("prime256v1"); + QTest::newRow("secp384r1") << QSsl::Ec << 384 << QLatin1String("secp384r1"); + QTest::newRow("brainpoolP512r1") << QSsl::Ec << 512 << QLatin1String("brainpoolP512r1"); + } + + void validCertificate() { - QVERIFY(pair1.isValid()); - const auto& cert = pair1.getCertificate(); + QFETCH(QSsl::KeyAlgorithm, algorithm); + QFETCH(int, size); + QFETCH(QLatin1String, curve); + + KeyPair pair = KeyPair::generate(curve.data()); + QVERIFY(pair.isValid()); + const auto& cert = pair.getCertificate(); QVERIFY(!cert.isNull()); QCOMPARE(cert.issuerInfo(QSslCertificate::CommonName).size(), 1); QCOMPARE(cert.issuerInfo(QSslCertificate::CommonName).at(0), QCoreApplication::applicationName()); @@ -66,8 +102,8 @@ class test_KeyPair QVERIFY(QByteArray::number(serialNumberValue).size() < 21); const auto& key = cert.publicKey(); - QCOMPARE(key.length(), 2048); - QCOMPARE(key.algorithm(), QSsl::Rsa); + QCOMPARE(key.length(), size); + QCOMPARE(key.algorithm(), algorithm); QCOMPARE(key.type(), QSsl::PublicKey); QVERIFY(TlsChecker::hasValidCertificateKeyLength(cert)); diff --git a/test/qt/ui/automatic/test_UIPlugInAutomatic.cpp b/test/qt/ui/automatic/test_UIPlugInAutomatic.cpp index 0713d2f36..d3e81e82c 100644 --- a/test/qt/ui/automatic/test_UIPlugInAutomatic.cpp +++ b/test/qt/ui/automatic/test_UIPlugInAutomatic.cpp @@ -10,6 +10,7 @@ #include "ReaderManager.h" #include "VolatileSettings.h" +#include "WorkflowRequest.h" #include "states/StateEnterPacePassword.h" #include "states/StateSelectReader.h" @@ -17,6 +18,7 @@ #include "MockReaderManagerPlugIn.h" #include "TestAuthContext.h" #include "TestWorkflowContext.h" +#include "TestWorkflowController.h" #include #include @@ -34,8 +36,8 @@ class DummyUI public: void doShutdown() override; - void onWorkflowStarted(QSharedPointer pContext) override; - void onWorkflowFinished(QSharedPointer pContext) override; + void onWorkflowStarted(const QSharedPointer& pRequest) override; + void onWorkflowFinished(const QSharedPointer& pRequest) override; }; void DummyUI::doShutdown() @@ -43,15 +45,15 @@ void DummyUI::doShutdown() } -void DummyUI::onWorkflowStarted(QSharedPointer pContext) +void DummyUI::onWorkflowStarted(const QSharedPointer& pRequest) { - Q_UNUSED(pContext) + Q_UNUSED(pRequest) } -void DummyUI::onWorkflowFinished(QSharedPointer pContext) +void DummyUI::onWorkflowFinished(const QSharedPointer& pRequest) { - Q_UNUSED(pContext) + Q_UNUSED(pRequest) } @@ -64,8 +66,9 @@ class test_UIPlugInAutomatic void initTestCase() { const auto readerManager = Env::getSingleton(); + QSignalSpy spy(readerManager, &ReaderManager::fireInitialized); readerManager->init(); - readerManager->isScanRunning(); // just to wait until initialization finished + QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations } @@ -84,11 +87,7 @@ class test_UIPlugInAutomatic void startUpShutDown() { UIPlugInAutomatic ui; - -#if (QT_VERSION >= QT_VERSION_CHECK(6, 3, 0)) QTest::failOnWarning(QRegularExpression(".*")); -#endif - ui.onApplicationStarted(); ui.doShutdown(); } @@ -128,13 +127,16 @@ class test_UIPlugInAutomatic ui.onUiDomination(&dummy, QString(), true); QVERIFY(ui.isDominated()); - const auto& context = QSharedPointer::create(); - ui.onWorkflowStarted(context); + const auto& request = TestWorkflowController::createWorkflowRequest(); + const auto& context = request->getContext(); + QVERIFY(context); + + ui.onWorkflowStarted(request); QVERIFY(!context->wasClaimed()); QVERIFY(ui.mContext.isNull()); ui.mContext = context; - ui.onWorkflowFinished(context); + ui.onWorkflowFinished(request); QVERIFY(!ui.mContext.isNull()); // should be cleared if not dominated } @@ -142,12 +144,13 @@ class test_UIPlugInAutomatic void workflowKilled() { UIPlugInAutomatic ui; - const auto& context = QSharedPointer::create(); + const auto& request = TestWorkflowController::createWorkflowRequest(); + const auto& context = request->getContext(); QTest::ignoreMessage(QtDebugMsg, R"(Claim workflow by "governikus::UIPlugInAutomatic")"); QTest::ignoreMessage(QtWarningMsg, "Cannot handle context... abort automatic workflow"); QTest::ignoreMessage(QtWarningMsg, "Killing the current workflow."); - ui.onWorkflowStarted(context); + ui.onWorkflowStarted(request); QVERIFY(context->wasClaimed()); QVERIFY(context->isWorkflowKilled()); } @@ -158,20 +161,21 @@ class test_UIPlugInAutomatic Env::getSingleton()->setUsedAsSDK(false); UIPlugInAutomatic ui; - const auto& context = QSharedPointer::create(nullptr); + const auto& request = TestWorkflowController::createWorkflowRequest(); + const auto& context = request->getContext(); QVERIFY(ui.mContext.isNull()); QVERIFY(!Env::getSingleton()->isUsedAsSDK()); QTest::ignoreMessage(QtDebugMsg, R"(Claim workflow by "governikus::UIPlugInAutomatic")"); QTest::ignoreMessage(QtDebugMsg, "Fallback to full automatic UI"); - ui.onWorkflowStarted(context); + ui.onWorkflowStarted(request); QVERIFY(!ui.mContext.isNull()); QVERIFY(context->wasClaimed()); QVERIFY(!context->isWorkflowKilled()); QVERIFY(Env::getSingleton()->isUsedAsSDK()); QVERIFY(!ui.mPrevUsedAsSDK); - ui.onWorkflowFinished(context); + ui.onWorkflowFinished(request); QVERIFY(!Env::getSingleton()->isUsedAsSDK()); QVERIFY(!ui.mPrevUsedAsSDK); QVERIFY(ui.mContext.isNull()); @@ -182,10 +186,11 @@ class test_UIPlugInAutomatic { UIPlugInAutomatic ui; ui.onStateChanged(QStringLiteral("do nothing")); - const auto& context = QSharedPointer::create(nullptr); + const auto& request = TestWorkflowController::createWorkflowRequest(); + const auto& context = request->getContext(); QVERIFY(!context->isStateApproved()); - ui.onWorkflowStarted(context); + ui.onWorkflowStarted(request); QVERIFY(!context->isStateApproved()); context->setCurrentState(QStringLiteral("approve me")); @@ -196,13 +201,14 @@ class test_UIPlugInAutomatic void insertNoCard() { UIPlugInAutomatic ui; - const auto& context = QSharedPointer::create(nullptr); + const auto& request = TestWorkflowController::createWorkflowRequest(); + const auto& context = request->getContext(); - ui.onWorkflowStarted(context); + ui.onWorkflowStarted(request); QTest::ignoreMessage(QtWarningMsg, "Cannot insert card... abort automatic workflow"); QTest::ignoreMessage(QtWarningMsg, "Killing the current workflow."); - context->setCurrentState(AbstractState::getClassName()); + context->setCurrentState(StateBuilder::generateStateName()); QVERIFY(context->isWorkflowKilled()); } @@ -215,12 +221,13 @@ class test_UIPlugInAutomatic QVERIFY(!reader->getReaderInfo().isInsertable()); UIPlugInAutomatic ui; - const auto& context = QSharedPointer::create(nullptr); + const auto& request = TestWorkflowController::createWorkflowRequest(); + const auto& context = request->getContext(); - ui.onWorkflowStarted(context); + ui.onWorkflowStarted(request); QVERIFY(!context->isStateApproved()); QTest::ignoreMessage(QtDebugMsg, "Use existing card..."); - context->setCurrentState(AbstractState::getClassName()); + context->setCurrentState(StateBuilder::generateStateName()); QVERIFY(!context->isWorkflowKilled()); QVERIFY(context->isStateApproved()); } @@ -247,13 +254,14 @@ class test_UIPlugInAutomatic QVERIFY(readerInfo.wasShelved()); UIPlugInAutomatic ui; - const auto& context = QSharedPointer::create(nullptr); + const auto& request = TestWorkflowController::createWorkflowRequest(); + const auto& context = request->getContext(); QSignalSpy spyCard(Env::getSingleton(), &ReaderManager::fireCardInserted); - ui.onWorkflowStarted(context); + ui.onWorkflowStarted(request); QVERIFY(!context->isStateApproved()); QTest::ignoreMessage(QtDebugMsg, R"(Automatically insert card into: "MockReader2")"); - context->setCurrentState(AbstractState::getClassName()); + context->setCurrentState(StateBuilder::generateStateName()); QVERIFY(!context->isWorkflowKilled()); QVERIFY(context->isStateApproved()); @@ -266,13 +274,14 @@ class test_UIPlugInAutomatic { UIPlugInAutomatic ui; - const auto& context = QSharedPointer::create(nullptr); + const auto& request = TestWorkflowController::createWorkflowRequest(); + const auto& context = request->getContext(); context->setLastPaceResult(CardReturnCode::PROTOCOL_ERROR); - ui.onWorkflowStarted(context); + ui.onWorkflowStarted(request); QTest::ignoreMessage(QtWarningMsg, "Previous PACE failed... abort automatic workflow"); QTest::ignoreMessage(QtWarningMsg, "Killing the current workflow."); - context->setCurrentState(AbstractState::getClassName()); + context->setCurrentState(StateBuilder::generateStateName()); QVERIFY(context->isWorkflowKilled()); } @@ -295,12 +304,13 @@ class test_UIPlugInAutomatic reader->setInfoBasicReader(false); UIPlugInAutomatic ui; - const auto& context = QSharedPointer::create(nullptr); + const auto& request = TestWorkflowController::createWorkflowRequest(); + const auto& context = request->getContext(); context->setLastPaceResult(returnCode); context->setCardConnection(QSharedPointer::create(reader->getReaderInfo())); - ui.onWorkflowStarted(context); - context->setCurrentState(AbstractState::getClassName()); + ui.onWorkflowStarted(request); + context->setCurrentState(StateBuilder::generateStateName()); QVERIFY(!context->isWorkflowKilled()); QVERIFY(context->isStateApproved()); } @@ -313,14 +323,15 @@ class test_UIPlugInAutomatic reader->setInfoBasicReader(false); UIPlugInAutomatic ui; - const auto& context = QSharedPointer::create(nullptr); + const auto& request = TestWorkflowController::createWorkflowRequest(); + const auto& context = request->getContext(); context->setLastPaceResult(CardReturnCode::OK); context->setCardConnection(QSharedPointer::create(reader->getReaderInfo())); - ui.onWorkflowStarted(context); + ui.onWorkflowStarted(request); QTest::ignoreMessage(QtWarningMsg, "Cannot handle password... abort automatic workflow"); QTest::ignoreMessage(QtWarningMsg, "Killing the current workflow."); - context->setCurrentState(AbstractState::getClassName()); + context->setCurrentState(StateBuilder::generateStateName()); QVERIFY(context->isWorkflowKilled()); } @@ -386,18 +397,19 @@ class test_UIPlugInAutomatic reader->setInfoBasicReader(true); UIPlugInAutomatic ui; - const auto& context = QSharedPointer::create(nullptr); + const auto& request = TestWorkflowController::createWorkflowRequest(); + const auto& context = request->getContext(); context->setLastPaceResult(CardReturnCode::OK); context->setEstablishPaceChannelType(passwordId); context->setCardConnection(QSharedPointer::create(reader->getReaderInfo())); - ui.onWorkflowStarted(context); + ui.onWorkflowStarted(request); if (killWorkflow) { QTest::ignoreMessage(QtWarningMsg, "Cannot handle password... abort automatic workflow"); QTest::ignoreMessage(QtWarningMsg, "Killing the current workflow."); } - context->setCurrentState(AbstractState::getClassName()); + context->setCurrentState(StateBuilder::generateStateName()); QCOMPARE(context->isWorkflowKilled(), killWorkflow); QVERIFY(context->isStateApproved()); diff --git a/test/qt/ui/json/test_Message.cpp b/test/qt/ui/json/test_Message.cpp index f75adfff5..b68b57be7 100644 --- a/test/qt/ui/json/test_Message.cpp +++ b/test/qt/ui/json/test_Message.cpp @@ -10,7 +10,6 @@ #include "ReaderManager.h" #include "context/AuthContext.h" -#include "context/InternalActivationContext.h" #include "states/StateEnterPacePassword.h" #include "TestWorkflowContext.h" @@ -112,7 +111,7 @@ class test_Message QCOMPARE(dispatcher.init(context), MsgType::VOID); dispatcher.mContext.getContext()->setEstablishPaceChannelType(PacePasswordId::PACE_PIN); - const auto& msg = dispatcher.processStateChange(AbstractState::getClassName()); + const auto& msg = dispatcher.processStateChange(StateBuilder::generateStateName()); QCOMPARE(msg, QByteArray("{\"msg\":\"ENTER_PIN\"}")); } @@ -146,7 +145,7 @@ class test_Message QCOMPARE(dispatcher.processCommand(msg), expectedBadState); dispatcher.mContext.getContext()->setEstablishPaceChannelType(PacePasswordId::PACE_CAN); - QVERIFY(!QByteArray(dispatcher.processStateChange(AbstractState::getClassName())).isEmpty()); + QVERIFY(!QByteArray(dispatcher.processStateChange(StateBuilder::generateStateName())).isEmpty()); QVERIFY(!context->isStateApproved()); auto expectedEnterCan = QByteArray(R"({"error":"You must provide 6 digits","msg":"ENTER_CAN"})"); @@ -225,7 +224,7 @@ class test_Message void finishAuthContext() { - const QSharedPointer context(new AuthContext(QSharedPointer::create(QUrl("http://dummy")))); + const QSharedPointer context(new AuthContext(true, QUrl("http://dummy"))); context->setStatus(GlobalStatus::Code::No_Error); context->setRefreshUrl(QUrl("http://dummy")); MessageDispatcher dispatcher; diff --git a/test/qt/ui/json/test_MsgContext.cpp b/test/qt/ui/json/test_MsgContext.cpp index 2dadd8259..1f6623463 100644 --- a/test/qt/ui/json/test_MsgContext.cpp +++ b/test/qt/ui/json/test_MsgContext.cpp @@ -10,7 +10,6 @@ #include "ReaderManager.h" #include "context/AuthContext.h" -#include "context/InternalActivationContext.h" #include "messages/MsgHandler.h" #include "messages/MsgHandlerEnterPin.h" #include "messages/MsgHandlerInsertCard.h" @@ -30,8 +29,9 @@ class test_MsgContext void initTestCase() { const auto readerManager = Env::getSingleton(); + QSignalSpy spy(readerManager, &ReaderManager::fireInitialized); readerManager->init(); - readerManager->isScanRunning(); // just to wait until initialization finished + QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations } @@ -94,7 +94,7 @@ class test_MsgContext QVERIFY(!ctx.getContext()); QVERIFY(!readOnly.getContext()); - ctx.setWorkflowContext(QSharedPointer(new AuthContext(QSharedPointer::create(QUrl("http://www.bla.de"))))); + ctx.setWorkflowContext(QSharedPointer(new AuthContext(true, QUrl("http://www.bla.de")))); QVERIFY(readOnly.isActiveWorkflow()); QVERIFY(readOnly.getContext()); QVERIFY(ctx.getContext()); diff --git a/test/qt/ui/json/test_MsgHandlerAccessRights.cpp b/test/qt/ui/json/test_MsgHandlerAccessRights.cpp index ce6a6682c..37826473c 100644 --- a/test/qt/ui/json/test_MsgHandlerAccessRights.cpp +++ b/test/qt/ui/json/test_MsgHandlerAccessRights.cpp @@ -11,19 +11,26 @@ #include "AppSettings.h" #include "MessageDispatcher.h" #include "VolatileSettings.h" -#include "context/InternalActivationContext.h" #include "states/StateEditAccessRights.h" #include "TestAuthContext.h" #include + using namespace governikus; + class test_MsgHandlerAccessRights : public QObject { Q_OBJECT +#if __has_include("SmartManager.h") + const QByteArray mJsonHeader = QByteArray(R"({"acceptedEidTypes":["CARD_CERTIFIED","SE_CERTIFIED","SE_ENDORSED"],)"); +#else + const QByteArray mJsonHeader = QByteArray("{"); +#endif + QSharedPointer getChat(const std::initializer_list& pList) { auto chat = newObject(); @@ -35,8 +42,7 @@ class test_MsgHandlerAccessRights QSharedPointer getContextWithChat(bool pCanAllowed = false) { Env::getSingleton()->getGeneralSettings().setEnableCanAllowed(pCanAllowed); - QSharedPointer activationContext(new InternalActivationContext(QUrl("http://dummy"))); - QSharedPointer context(new TestAuthContext(activationContext, ":/paos/DIDAuthenticateEAC1.xml")); + auto context = QSharedPointer::create(":/paos/DIDAuthenticateEAC1.xml"); context->setRequiredAccessRights({AccessRight::READ_DG01, AccessRight::READ_DG04, AccessRight::READ_DG17}); context->setOptionalAccessRights({AccessRight::AGE_VERIFICATION, AccessRight::READ_DG05}); Env::getSingleton()->getGeneralSettings().setEnableCanAllowed(false); @@ -54,7 +60,7 @@ class test_MsgHandlerAccessRights ? QByteArray::number(today.year() - ageVerificationDate.year()) : QByteArray::number(today.year() - ageVerificationDate.year() - 1); - QByteArray aux(R"({"aux":{"ageVerificationDate":"%1","communityId":"02760400110000","requiredAge":"%2","validityDate":"2013-12-06"},)"); + QByteArray aux(R"("aux":{"ageVerificationDate":"%1","communityId":"02760400110000","requiredAge":"%2","validityDate":"2013-12-06"},)"); aux.replace(QByteArrayLiteral("%1"), ageVerificationDate.toString(Qt::ISODate).toLatin1()); aux.replace(QByteArrayLiteral("%2"), age); return aux; @@ -69,13 +75,12 @@ class test_MsgHandlerAccessRights void nonExistingTransactionInfo() { - QSharedPointer activationContext(new InternalActivationContext(QUrl("http://dummy"))); - QSharedPointer context(new TestAuthContext(activationContext, ":/paos/DIDAuthenticateEAC1_2.xml")); + const auto& context = QSharedPointer::create(":/paos/DIDAuthenticateEAC1_2.xml"); MessageDispatcher dispatcher; QCOMPARE(dispatcher.init(context), MsgType::AUTH); - QCOMPARE(dispatcher.processStateChange(AbstractState::getClassName()), - QByteArray(R"({"chat":{"effective":["WriteAddress","WriteCommunityID","WriteResidencePermitI","WriteResidencePermitII","ResidencePermitII","ResidencePermitI","CommunityID","Address","BirthName","Nationality","PlaceOfBirth","DateOfBirth","DoctoralDegree","ArtisticName","FamilyName","GivenNames","ValidUntil","IssuingCountry","DocumentType","PinManagement","CanAllowed","Pseudonym"],"optional":["WriteAddress","WriteCommunityID","WriteResidencePermitI","WriteResidencePermitII","ResidencePermitII","ResidencePermitI","CommunityID","Address","BirthName","Nationality","PlaceOfBirth","DateOfBirth","DoctoralDegree","ArtisticName","FamilyName","GivenNames","ValidUntil","IssuingCountry","DocumentType","PinManagement","CanAllowed","Pseudonym"],"required":[]},"msg":"ACCESS_RIGHTS"})")); + QCOMPARE(dispatcher.processStateChange(StateBuilder::generateStateName()), + mJsonHeader + QByteArray(R"("chat":{"effective":["WriteAddress","WriteCommunityID","WriteResidencePermitI","WriteResidencePermitII","ResidencePermitII","ResidencePermitI","CommunityID","Address","BirthName","Nationality","PlaceOfBirth","DateOfBirth","DoctoralDegree","ArtisticName","FamilyName","GivenNames","ValidUntil","IssuingCountry","DocumentType","PinManagement","CanAllowed","Pseudonym"],"optional":["WriteAddress","WriteCommunityID","WriteResidencePermitI","WriteResidencePermitII","ResidencePermitII","ResidencePermitI","CommunityID","Address","BirthName","Nationality","PlaceOfBirth","DateOfBirth","DoctoralDegree","ArtisticName","FamilyName","GivenNames","ValidUntil","IssuingCountry","DocumentType","PinManagement","CanAllowed","Pseudonym"],"required":[]},"msg":"ACCESS_RIGHTS"})")); } @@ -84,8 +89,8 @@ class test_MsgHandlerAccessRights MessageDispatcher dispatcher; QCOMPARE(dispatcher.init(getContextWithChat()), MsgType::AUTH); - QCOMPARE(dispatcher.processStateChange(AbstractState::getClassName()), - getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); + QCOMPARE(dispatcher.processStateChange(StateBuilder::generateStateName()), + mJsonHeader + getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); } @@ -108,11 +113,11 @@ class test_MsgHandlerAccessRights QCOMPARE(dispatcher.init(context), MsgType::AUTH); QVERIFY(!context->isStateApproved()); - QVERIFY(!QByteArray(dispatcher.processStateChange(AbstractState::getClassName())).isEmpty()); + QVERIFY(!QByteArray(dispatcher.processStateChange(StateBuilder::generateStateName())).isEmpty()); QVERIFY(!context->isStateApproved()); QCOMPARE(dispatcher.processCommand(QByteArray(R"( {"cmd": "GET_ACCESS_RIGHTS"} )")), - getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); + mJsonHeader + getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); QCOMPARE(dispatcher.processCommand(QByteArray(R"( {"cmd": "ACCEPT"} )")), QByteArray()); QVERIFY(context->isStateApproved()); @@ -124,9 +129,9 @@ class test_MsgHandlerAccessRights MessageDispatcher dispatcher; QCOMPARE(dispatcher.init(getContextWithChat()), MsgType::AUTH); - QVERIFY(!QByteArray(dispatcher.processStateChange(AbstractState::getClassName())).isEmpty()); + QVERIFY(!QByteArray(dispatcher.processStateChange(StateBuilder::generateStateName())).isEmpty()); QCOMPARE(dispatcher.processCommand(QByteArray(R"( {"cmd": "GET_ACCESS_RIGHTS"} )")), - getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); + mJsonHeader + getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); } @@ -136,15 +141,15 @@ class test_MsgHandlerAccessRights auto context = getContextWithChat(true); QCOMPARE(dispatcher.init(context), MsgType::AUTH); - QVERIFY(!QByteArray(dispatcher.processStateChange(AbstractState::getClassName())).isEmpty()); + QVERIFY(!QByteArray(dispatcher.processStateChange(StateBuilder::generateStateName())).isEmpty()); QCOMPARE(dispatcher.processCommand(QByteArray(R"( {"cmd": "GET_ACCESS_RIGHTS"} )")), - getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","CanAllowed","AgeVerification"],"optional":["FamilyName","CanAllowed","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); + mJsonHeader + getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","CanAllowed","AgeVerification"],"optional":["FamilyName","CanAllowed","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); QCOMPARE(dispatcher.processCommand(QByteArray(R"( {"cmd": "SET_ACCESS_RIGHTS", "chat": ["FamilyName","AgeVerification"]} )")), - getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","CanAllowed","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); + mJsonHeader + getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","CanAllowed","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); QCOMPARE(dispatcher.processCommand(QByteArray(R"( {"cmd": "SET_ACCESS_RIGHTS", "chat": ["FamilyName","AgeVerification", "CanAllowed"]} )")), - getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","CanAllowed","AgeVerification"],"optional":["FamilyName","CanAllowed","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); + mJsonHeader + getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","CanAllowed","AgeVerification"],"optional":["FamilyName","CanAllowed","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); } @@ -154,31 +159,31 @@ class test_MsgHandlerAccessRights QTest::addColumn("msg"); QTest::newRow("chat_invalid") << QByteArray(R"( {"cmd": "SET_ACCESS_RIGHTS", "chat": ["8",11]} )") - << getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"error":"Entry in 'chat' data is invalid","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); + << mJsonHeader + getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"error":"Entry in 'chat' data is invalid","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); QTest::newRow("chat_needs_be_string") << QByteArray(R"( {"cmd": "SET_ACCESS_RIGHTS", "chat": [8,"11"]} )") - << getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"error":"Entry in 'chat' data needs to be string","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); + << mJsonHeader + getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"error":"Entry in 'chat' data needs to be string","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); QTest::newRow("chat_unknown_id") << QByteArray(R"( {"cmd": "SET_ACCESS_RIGHTS", "chat": ["y", "123"]} )") - << getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"error":"Entry in 'chat' data is invalid","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); + << mJsonHeader + getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"error":"Entry in 'chat' data is invalid","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); QTest::newRow("chat_invalid_and_needs_be_string") << QByteArray(R"( {"cmd": "SET_ACCESS_RIGHTS", "chat": ["y", 123]} )") - << getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"error":"Entry in 'chat' data is invalid","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); + << mJsonHeader + getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"error":"Entry in 'chat' data is invalid","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); QTest::newRow("chat_set_optional") << QByteArray(R"( {"cmd": "SET_ACCESS_RIGHTS", "chat": ["FamilyName"]} )") - << getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); + << mJsonHeader + getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); QTest::newRow("chat_mixed_valid_and_required") << QByteArray(R"( {"cmd": "SET_ACCESS_RIGHTS", "chat": ["AgeVerification", "GivenNames"]} )") - << getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"error":"Entry in 'chat' data is not available","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); + << mJsonHeader + getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"error":"Entry in 'chat' data is not available","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); QTest::newRow("chat_both_optional") << QByteArray(R"( {"cmd": "SET_ACCESS_RIGHTS", "chat": ["AgeVerification", "FamilyName"]} )") - << getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); + << mJsonHeader + getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); QTest::newRow("chat_single_optional") << QByteArray(R"( {"cmd": "SET_ACCESS_RIGHTS", "chat": ["AgeVerification"]} )") - << getAux() + QByteArray(R"("chat":{"effective":["Address","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); + << mJsonHeader + getAux() + QByteArray(R"("chat":{"effective":["Address","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); QTest::newRow("chat_disable_optional") << QByteArray(R"( {"cmd": "SET_ACCESS_RIGHTS", "chat": []} )") - << getAux() + QByteArray(R"("chat":{"effective":["Address","GivenNames","DocumentType"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); + << mJsonHeader + getAux() + QByteArray(R"("chat":{"effective":["Address","GivenNames","DocumentType"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); } @@ -189,11 +194,11 @@ class test_MsgHandlerAccessRights MessageDispatcher dispatcher; QCOMPARE(dispatcher.init(getContextWithChat()), MsgType::AUTH); - QVERIFY(!QByteArray(dispatcher.processStateChange(AbstractState::getClassName())).isEmpty()); + QVERIFY(!QByteArray(dispatcher.processStateChange(StateBuilder::generateStateName())).isEmpty()); // check original state QCOMPARE(dispatcher.processCommand(QByteArray(R"( {"cmd": "GET_ACCESS_RIGHTS"} )")), - getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); + mJsonHeader + getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); // check cmd QCOMPARE(dispatcher.processCommand(cmd), msg); @@ -204,19 +209,19 @@ class test_MsgHandlerAccessRights { MessageDispatcher dispatcher; QCOMPARE(dispatcher.init(getContextWithChat()), MsgType::AUTH); - QVERIFY(!QByteArray(dispatcher.processStateChange(AbstractState::getClassName())).isEmpty()); + QVERIFY(!QByteArray(dispatcher.processStateChange(StateBuilder::generateStateName())).isEmpty()); // check original state QCOMPARE(dispatcher.processCommand(QByteArray(R"( {"cmd": "GET_ACCESS_RIGHTS"} )")), - getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); + mJsonHeader + getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); // check cmds QCOMPARE(dispatcher.processCommand(QByteArray(R"( {"cmd": "SET_ACCESS_RIGHTS", "chat": ["FamilyName"]} )")), - getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); + mJsonHeader + getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); // 11 is not valid, 0 is valid ... we do not accept partial valid values! QCOMPARE(dispatcher.processCommand(QByteArray(R"( {"cmd": "SET_ACCESS_RIGHTS", "chat": ["AgeVerification", "GivenNames"]} )")), - getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"error":"Entry in 'chat' data is not available","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); + mJsonHeader + getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"error":"Entry in 'chat' data is not available","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); } @@ -227,19 +232,19 @@ class test_MsgHandlerAccessRights MessageDispatcher dispatcher; QCOMPARE(dispatcher.init(context), MsgType::AUTH); - QVERIFY(!QByteArray(dispatcher.processStateChange(AbstractState::getClassName())).isEmpty()); + QVERIFY(!QByteArray(dispatcher.processStateChange(StateBuilder::generateStateName())).isEmpty()); QCOMPARE(dispatcher.processCommand(QByteArray(R"( {"cmd": "SET_ACCESS_RIGHTS", "chat": ["AgeVerification"]} )")), - getAux() + QByteArray(R"("chat":{"effective":["Address","GivenNames","DocumentType"],"optional":[],"required":["Address","GivenNames","DocumentType"]},"error":"No optional access rights available","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); + mJsonHeader + getAux() + QByteArray(R"("chat":{"effective":["Address","GivenNames","DocumentType"],"optional":[],"required":["Address","GivenNames","DocumentType"]},"error":"No optional access rights available","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); context->setOptionalAccessRights({AccessRight::AGE_VERIFICATION}); QCOMPARE(dispatcher.processCommand(QByteArray(R"( {"cmd": "SET_ACCESS_RIGHTS", "chat": ["AgeVerification"]} )")), - getAux() + QByteArray(R"("chat":{"effective":["Address","GivenNames","DocumentType","AgeVerification"],"optional":["AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); + mJsonHeader + getAux() + QByteArray(R"("chat":{"effective":["Address","GivenNames","DocumentType","AgeVerification"],"optional":["AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); context->setRequiredAccessRights({AccessRight::AGE_VERIFICATION, AccessRight::READ_DG17}); context->setOptionalAccessRights({}); QCOMPARE(dispatcher.processCommand(QByteArray(R"( {"cmd": "SET_ACCESS_RIGHTS", "chat": ["AgeVerification"]} )")), - getAux() + QByteArray(R"("chat":{"effective":["Address","AgeVerification"],"optional":[],"required":["Address","AgeVerification"]},"error":"No optional access rights available","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); + mJsonHeader + getAux() + QByteArray(R"("chat":{"effective":["Address","AgeVerification"],"optional":[],"required":["Address","AgeVerification"]},"error":"No optional access rights available","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); } @@ -248,14 +253,19 @@ class test_MsgHandlerAccessRights const auto& context = getContextWithChat(); MessageDispatcher dispatcher; QCOMPARE(dispatcher.init(context), MsgType::AUTH); - QVERIFY(!QByteArray(dispatcher.processStateChange(AbstractState::getClassName())).isEmpty()); + QVERIFY(!QByteArray(dispatcher.processStateChange(StateBuilder::generateStateName())).isEmpty()); QCOMPARE(dispatcher.processCommand(QByteArray(R"( {"cmd": "GET_ACCESS_RIGHTS"} )")), - getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); + mJsonHeader + getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); +#if __has_include("SmartManager.h") + const QByteArray cardOnly(R"({"acceptedEidTypes":["CARD_CERTIFIED"],)"); +#else + const QByteArray cardOnly = QByteArray("{"); +#endif context->setAcceptedEidTypes({AcceptedEidType::CARD_CERTIFIED}); QCOMPARE(dispatcher.processCommand(QByteArray(R"( {"cmd": "GET_ACCESS_RIGHTS"} )")), - getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); + cardOnly + getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); } @@ -265,10 +275,10 @@ class test_MsgHandlerAccessRights QTest::addColumn("msg"); QTest::newRow("chat_null") << QByteArray(R"( {"cmd": "SET_ACCESS_RIGHTS", "chat": null} )") - << getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"error":"Invalid 'chat' data","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); + << mJsonHeader + getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"error":"Invalid 'chat' data","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); QTest::newRow("CHAT") << QByteArray(R"( {"cmd": "SET_ACCESS_RIGHTS", "CHAT": []} )") - << getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"error":"'chat' cannot be undefined","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); + << mJsonHeader + getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"error":"'chat' cannot be undefined","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); } @@ -279,7 +289,7 @@ class test_MsgHandlerAccessRights MessageDispatcher dispatcher; QCOMPARE(dispatcher.init(getContextWithChat()), MsgType::AUTH); - QVERIFY(!QByteArray(dispatcher.processStateChange(AbstractState::getClassName())).isEmpty()); + QVERIFY(!QByteArray(dispatcher.processStateChange(StateBuilder::generateStateName())).isEmpty()); QCOMPARE(dispatcher.processCommand(cmd), msg); } diff --git a/test/qt/ui/json/test_MsgHandlerAuth.cpp b/test/qt/ui/json/test_MsgHandlerAuth.cpp index 62c7f877f..4e878e804 100644 --- a/test/qt/ui/json/test_MsgHandlerAuth.cpp +++ b/test/qt/ui/json/test_MsgHandlerAuth.cpp @@ -15,7 +15,6 @@ #include "UIPlugInJson.h" #include "VolatileSettings.h" #include "WorkflowRequest.h" -#include "context/InternalActivationContext.h" #include "controller/AppController.h" #include "states/StateGetTcToken.h" @@ -128,7 +127,7 @@ class test_MsgHandlerAuth auto request = param.at(0).value>(); QCOMPARE(request->getAction(), Action::AUTH); QVERIFY(request->getContext().objectCast()); - QCOMPARE(request->getContext().objectCast()->getActivationContext()->getActivationURL(), + QCOMPARE(request->getContext().objectCast()->getActivationUrl(), QUrl("http://localhost/?tcTokenURL=https%3A%2F%2Fwww.governikus.de%2Ftoken%3Fsession%3D123abc")); } @@ -140,7 +139,7 @@ class test_MsgHandlerAuth QCOMPARE(dispatcher.init(context), QByteArray()); QCOMPARE(dispatcher.finish(), QByteArray()); - const QSharedPointer authContext(new AuthContext(QSharedPointer::create(QUrl("http://dummy")))); + const QSharedPointer authContext(new AuthContext(true, QUrl("http://dummy"))); QCOMPARE(dispatcher.init(authContext), QByteArray("{\"msg\":\"AUTH\"}")); } @@ -151,7 +150,7 @@ class test_MsgHandlerAuth QTest::addColumn("statusMessages"); QTest::newRow("noStatus") << QVariant(false) << 0; - QTest::newRow("Status") << QVariant(true) << 3; // StateGetTcToken, StateCheckRefreshAddress, StateWriteHistory + QTest::newRow("Status") << QVariant(true) << 2; // StateGetTcToken, StateCheckRefreshAddress } @@ -170,18 +169,19 @@ class test_MsgHandlerAuth QVERIFY(ui); ui->setEnabled(true); ui->mMessageDispatcher.setSkipStateApprovedHook([](const QString& pState){ - return AbstractState::isState(pState); + return StateBuilder::isState(pState); }); QSignalSpy spyUi(ui, &UIPlugIn::fireWorkflowRequested); QSignalSpy spyStarted(&controller, &AppController::fireWorkflowStarted); QSignalSpy spyFinished(&controller, &AppController::fireWorkflowFinished); static int firedStatusCount = 0; - connect(&controller, &AppController::fireWorkflowStarted, this, [this, ui](QSharedPointer pContext){ - pContext->claim(this); // UIPlugInJson is internal API and does not claim by itself - connect(pContext.data(), &WorkflowContext::fireStateChanged, this, [ui](const QString& pState) + connect(&controller, &AppController::fireWorkflowStarted, this, [this, ui](const QSharedPointer& pRequest){ + const auto& context = pRequest->getContext(); + context->claim(this); // UIPlugInJson is internal API and does not claim by itself + connect(context.data(), &WorkflowContext::fireStateChanged, this, [ui](const QString& pState) { // do not CANCEL to early to get all STATUS messages and avoid flaky unit test - if (AbstractState::isState(pState)) + if (StateBuilder::isState(pState)) { const QByteArray msgCancel(R"({"cmd": "CANCEL"})"); ui->doMessageProcessing(msgCancel); @@ -230,7 +230,7 @@ class test_MsgHandlerAuth auto request = param.at(0).value>(); QCOMPARE(request->getAction(), Action::AUTH); QVERIFY(request->getContext().objectCast()); - QCOMPARE(request->getContext().objectCast()->getActivationContext()->getActivationURL(), + QCOMPARE(request->getContext().objectCast()->getActivationUrl(), QUrl("http://localhost/?tcTokenURL=https%3A%2F%2Ftest.governikus-eid.de%2Fgov_autent%2Fasync%3FSAMLRequest%3DnVbZsppIGH4Vi7m0lEURsI4nBbIcV1TA7SbF0myy0wj49NMeTXIySWYyueTvf%252FuWrublUxNHnSsoyiBNJhjZJ7AOSOzUCRJvghm63GOxT68vpRlHVDbmK%252BgnO5BXoIQdVJiU48fJBKuKZJyaZVCOEzMG5RjaY41fLcdUnxhnRQpTO42wDl%252BWoIBo1DRNyioGhQaKa2ADY7ecYD6EWTnG8bqu3X50jfsOwJPMvA%252FFgZ3Gn9HHPYAXoMxQPcA6IlokSMx7x2%252F1EAX7XopAJcGlKnsgcO6tUOSzWUGQQNws28TGOjNxgjG2NaBphu3RnEX1hiQDepwzGvVIa8S6nM3ZBHBRZllWYJaU0EzgBKMIctQj2B7J6iQ1HpBjiukTLHPGOpsivQYOKNaIg58Cwjr7L1wjZrAns%252BP3%252FsVHSv%252BdUfMLj9jrT1h7wd9VeXb9qp7UIPB3ncvXF8TJWErsos0gcD7K%252BjXpuQxKfABBwlhl0Leq5J1NMBNxtH6DzPKtkWhC81l3P%252FhaiBTt14N%252BWng4RRAkTgxx5B6U8RfW0dvsSdVD%252Bl8kShGIkXT%252FGInArAD0U6fDR15aBNCPf2OoCUqSYnu2hTzwcPHvbou%252FvjjleAHaWeKmz1qn%252FMVIAie4O06nDLy%252FfuAKNfmfw79n%252B8%252BgF6XZIz%252FTGALyLt00yHxQ3HX7LrA3owq8nqchd%252FChs84FcV%252F7K2XeNSNam7c1zXHmaE01PIgXcC8dVEkwOF9cgKS6Gjw7z%252Fcm301Gy4G2U3ldYZNjokPNXknswARRE1X1eWSDZvgGGUNwzhS6g1yrGsui1cBFSMJwF8Do1rihPLyZPH%252B7haovT4eaFrDbAcB3ah6G24xiVGFr5%252BUlOxlvuORmrFaQuzIHyvE257rT0Qpe9xqlVeAYWIGhioZiWWcoRnVIadR5YbORNmUAawRruznL%252FsUN8GCjjEA7mpmLnAqrZRU5i22Sd91An2blxp2R7IY6VLcisRwhJslgyKjEleEbMO9yF4m4bQapCs8jnWblM6WpFru02fDCevopWnteylL1ZPKCf%252BD%252BQfV3oYccj6SvlxT5BcW%252Bue8HAf%252FMTQ8DPJYQZXuh7SMTD8zuydusrZJf86WxyozjgobSkWfDkMn5S3d7mFJTXKWEkXuKdWKGFnXOQrbYJwodtcXONjyt686N5T4ZCOtpO4PeJiLo0PDieXdIzt11lzLndd4KjLqkY3kqH287U2svdeN6852480LvYm4vTEUXbN0FOKMUtroeXtdRGHOncHqMtZTJcvEircycDWNFy89VumWnqsTBvT7jo60ypUYbLTkt97nbGOvGJm1wahNDk5q3Q93qNVgufWV6s66GlTnbzDVxejiq7ThcNUqs3FyfVmVCYbeOElnXzU0JL7wtIefm1Wwv4%252FQZF%252Bp0mCa6tiVO8qI2Z7kx8KKteIipPN7dToNqFzCU7s9xRStX25wkV3SVpjK1sXTeL%252FRmPuAovBL5dsaTDCFJSnwaDfNhxXXdZq%252BLZ1fGU8GxBHxJweVVONRvvnySDkyOV0P1EOf8fHAEx5vPnzPLSvnB4dJGAhzGbJAJFJnvDFGo9gBuzduaetsf4PHmOJc6APybfPkzDz6N%252Bd%252BPB3Lq85fh46PzJfbxvXn9Gw%253D%253D%26RelayState%3Dfc4b5fad-76fd-49d2-841b-b5cd39568029%26SigAlg%3Dhttp%253A%252F%252Fwww.w3.org%252F2001%252F04%252Fxmldsig-more%2523rsa-sha256%26Signature%3DjEVAVmY1XMMuNt2GJ%252BoaN6FaGj6ACZokOfme1OmkBiCPJyr%252B4rsg%252BrajIyMtSoUbtOoOaH63g1JP%250AqT7Wc%252Bucd%252FLcEYf7qU%252FJKN2uTMvssQblsSKuPHOWLJQUKPZHiSPA67%252F9JZhov8FXYM9uBYSs1Far%250AMRBpM49o1m1pRzwOKx3%252FcwOqc%252BT5mOWM78tNOj37mFFzwDTGuoB9iE2cZCUu1wfBbTPIvRZ2ND8Y%250AVYEO5FdR8W0sLR9LNOVjm64D%252Fl9u%252FjFJXntW4CPRPXiOiCr7TLlnFWVxXOTwywF5LTyLYQR5OjwB%250AK3cWmRPkN6OAejN%252F3Su3nWHDlGttrZuZBYzfag%253D%253D")); } @@ -249,7 +249,7 @@ class test_MsgHandlerAuth void result() { - const QSharedPointer context(new AuthContext(QSharedPointer(new InternalActivationContext(QUrl())))); + const QSharedPointer context(new AuthContext()); context->setStatus(GlobalStatus::Code::No_Error); MsgHandlerAuth msg(context); QCOMPARE(msg.toJson(), QByteArray("{\"msg\":\"AUTH\",\"result\":{\"major\":\"http://www.bsi.bund.de/ecard/api/1.1/resultmajor#ok\"}}")); @@ -258,7 +258,7 @@ class test_MsgHandlerAuth void resultWithUrl() { - const QSharedPointer context(new AuthContext(QSharedPointer(new InternalActivationContext(QUrl())))); + const QSharedPointer context(new AuthContext()); context->setStatus(GlobalStatus::Code::No_Error); context->setRefreshUrl(QUrl("http://www.governikus.de")); MsgHandlerAuth msg(context); @@ -279,7 +279,7 @@ class test_MsgHandlerAuth " \n" ""))); - const QSharedPointer context(new AuthContext(QSharedPointer(new InternalActivationContext(QUrl())))); + const QSharedPointer context(new AuthContext()); context->setStatus(GlobalStatus::Code::Workflow_Reader_Became_Inaccessible); context->setTcToken(token); MsgHandlerAuth msg(context); @@ -302,8 +302,8 @@ class test_MsgHandlerAuth UILoader::setUserRequest({QStringLiteral("json")}); AppController controller; controller.start(); - connect(&controller, &AppController::fireWorkflowStarted, this, [this](QSharedPointer pContext){ - pContext->claim(this); // UIPlugInJson is internal API and does not claim by itself + connect(&controller, &AppController::fireWorkflowStarted, this, [this](const QSharedPointer& pRequest){ + pRequest->getContext()->claim(this); // UIPlugInJson is internal API and does not claim by itself }); const auto& initialMessages = Env::getSingleton()->getMessages(); @@ -317,7 +317,7 @@ class test_MsgHandlerAuth QVERIFY(ui); ui->setEnabled(true); ui->mMessageDispatcher.setSkipStateApprovedHook([&reachedStateGetTcToken](const QString& pState){ - if (AbstractState::isState(pState)) + if (StateBuilder::isState(pState)) { reachedStateGetTcToken = true; return true; @@ -349,7 +349,7 @@ class test_MsgHandlerAuth auto request = param.at(0).value>(); QCOMPARE(request->getAction(), Action::AUTH); QVERIFY(request->getContext().objectCast()); - QCOMPARE(request->getContext().objectCast()->getActivationContext()->getActivationURL(), + QCOMPARE(request->getContext().objectCast()->getActivationUrl(), QUrl("http://localhost/?tcTokenURL=https%3A%2F%2Flocalhost%2Ftoken%3Fsession%3D123abc")); QTRY_COMPARE(spyStarted.count(), 1); // clazy:exclude=qstring-allocations @@ -399,8 +399,8 @@ class test_MsgHandlerAuth UILoader::setUserRequest({QStringLiteral("json")}); AppController controller; controller.start(); - connect(&controller, &AppController::fireWorkflowStarted, this, [this](QSharedPointer pContext){ - pContext->claim(this); // UIPlugInJson is internal API and does not claim by itself + connect(&controller, &AppController::fireWorkflowStarted, this, [this](const QSharedPointer& pRequest){ + pRequest->getContext()->claim(this); // UIPlugInJson is internal API and does not claim by itself }); QCOMPARE(Env::getSingleton()->handleInterrupt(), false); // default @@ -409,7 +409,7 @@ class test_MsgHandlerAuth QVERIFY(ui); ui->setEnabled(true); ui->mMessageDispatcher.setSkipStateApprovedHook([&reachedStateGetTcToken](const QString& pState){ - if (AbstractState::isState(pState)) + if (StateBuilder::isState(pState)) { reachedStateGetTcToken = true; return true; @@ -441,7 +441,7 @@ class test_MsgHandlerAuth auto request = param.at(0).value>(); QCOMPARE(request->getAction(), Action::AUTH); QVERIFY(request->getContext().objectCast()); - QCOMPARE(request->getContext().objectCast()->getActivationContext()->getActivationURL(), + QCOMPARE(request->getContext().objectCast()->getActivationUrl(), QUrl("http://localhost/?tcTokenURL=https%3A%2F%2Flocalhost%2Ftoken%3Fsession%3D123abc")); QTRY_COMPARE(spyStarted.count(), 1); // clazy:exclude=qstring-allocations @@ -478,8 +478,8 @@ class test_MsgHandlerAuth UILoader::setUserRequest({QStringLiteral("json")}); AppController controller; controller.start(); - connect(&controller, &AppController::fireWorkflowStarted, this, [this](QSharedPointer pContext){ - pContext->claim(this); // UIPlugInJson is internal API and does not claim by itself + connect(&controller, &AppController::fireWorkflowStarted, this, [this](const QSharedPointer& pRequest){ + pRequest->getContext()->claim(this); // UIPlugInJson is internal API and does not claim by itself }); QCOMPARE(Env::getSingleton()->handleInterrupt(), false); // default @@ -488,7 +488,7 @@ class test_MsgHandlerAuth QVERIFY(ui); ui->setEnabled(true); ui->mMessageDispatcher.setSkipStateApprovedHook([&reachedStateGetTcToken](const QString& pState){ - if (AbstractState::isState(pState)) + if (StateBuilder::isState(pState)) { reachedStateGetTcToken = true; return true; @@ -546,8 +546,8 @@ class test_MsgHandlerAuth UILoader::setUserRequest({QStringLiteral("json")}); AppController controller; controller.start(); - connect(&controller, &AppController::fireWorkflowStarted, this, [this](QSharedPointer pContext){ - pContext->claim(this); // UIPlugInJson is internal API and does not claim by itself + connect(&controller, &AppController::fireWorkflowStarted, this, [this](const QSharedPointer& pRequest){ + pRequest->getContext()->claim(this); // UIPlugInJson is internal API and does not claim by itself }); QCOMPARE(Env::getSingleton()->isDeveloperMode(), false); // default @@ -557,7 +557,7 @@ class test_MsgHandlerAuth QVERIFY(ui); ui->setEnabled(true); ui->mMessageDispatcher.setSkipStateApprovedHook([&reachedStateGetTcToken](const QString& pState){ - if (AbstractState::isState(pState)) + if (StateBuilder::isState(pState)) { reachedStateGetTcToken = true; return true; @@ -587,7 +587,7 @@ class test_MsgHandlerAuth QVERIFY(workFlowRequest); QCOMPARE(workFlowRequest->getAction(), Action::AUTH); auto authContext = workFlowRequest->getContext().objectCast(); - auto url = authContext->getActivationContext()->getActivationURL(); + auto url = authContext->getActivationUrl(); QCOMPARE(url, QUrl("http://localhost/?tcTokenURL=https%3A%2F%2Flocalhost%2Ftoken%3Fsession%3D123abc")); QTRY_COMPARE(spyStarted.count(), 1); // clazy:exclude=qstring-allocations diff --git a/test/qt/ui/json/test_MsgHandlerCertificate.cpp b/test/qt/ui/json/test_MsgHandlerCertificate.cpp index 71b0948f3..9a9531290 100644 --- a/test/qt/ui/json/test_MsgHandlerCertificate.cpp +++ b/test/qt/ui/json/test_MsgHandlerCertificate.cpp @@ -9,7 +9,6 @@ #include "messages/MsgHandlerCertificate.h" #include "MessageDispatcher.h" -#include "context/InternalActivationContext.h" #include "states/StateEditAccessRights.h" #include "TestAuthContext.h" @@ -24,8 +23,7 @@ class test_MsgHandlerCertificate QSharedPointer getContext() { - QSharedPointer activationContext(new InternalActivationContext(QUrl("http://dummy"))); - QSharedPointer context(new TestAuthContext(activationContext, ":/paos/DIDAuthenticateEAC1.xml")); + QSharedPointer context(new TestAuthContext(":/paos/DIDAuthenticateEAC1.xml")); context->setRequiredAccessRights({AccessRight::READ_DG01}); context->setOptionalAccessRights({AccessRight::AGE_VERIFICATION}); return context; @@ -51,7 +49,7 @@ class test_MsgHandlerCertificate MessageDispatcher dispatcher; QCOMPARE(dispatcher.init(context), MsgType::AUTH); - QVERIFY(!QByteArray(dispatcher.processStateChange(AbstractState::getClassName())).isEmpty()); + QVERIFY(!QByteArray(dispatcher.processStateChange(StateBuilder::generateStateName())).isEmpty()); QByteArray msg = R"({"cmd": "GET_CERTIFICATE"})"; QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"description\":{\"issuerName\":\"Governikus Test DVCA\",\"issuerUrl\":\"http://www.governikus.de\",\"purpose\":\"\",\"subjectName\":\"Governikus GmbH & Co. KG\",\"subjectUrl\":\"https://test.governikus-eid.de\",\"termsOfUsage\":\"Name, Anschrift und E-Mail-Adresse des Diensteanbieters:\\r\\nGovernikus GmbH & Co. KG\\r\\nHochschulring 4\\r\\n28359 Bremen\\r\\nE-Mail: kontakt@governikus.de\\t\"},\"msg\":\"CERTIFICATE\",\"validity\":{\"effectiveDate\":\"2020-05-21\",\"expirationDate\":\"2020-06-20\"}}")); } diff --git a/test/qt/ui/json/test_MsgHandlerChangePin.cpp b/test/qt/ui/json/test_MsgHandlerChangePin.cpp index 61fcb353c..0c4a61da2 100644 --- a/test/qt/ui/json/test_MsgHandlerChangePin.cpp +++ b/test/qt/ui/json/test_MsgHandlerChangePin.cpp @@ -155,8 +155,8 @@ class test_MsgHandlerChangePin QSignalSpy spyUi(ui, &UIPlugIn::fireWorkflowRequested); QSignalSpy spyStarted(&controller, &AppController::fireWorkflowStarted); QSignalSpy spyFinished(&controller, &AppController::fireWorkflowFinished); - connect(&controller, &AppController::fireWorkflowStarted, this, [this](QSharedPointer pContext){ - pContext->claim(this); // UIPlugInJson is internal API and does not claim by itself + connect(&controller, &AppController::fireWorkflowStarted, this, [this](const QSharedPointer& pRequest){ + pRequest->getContext()->claim(this); // UIPlugInJson is internal API and does not claim by itself }); const QByteArray msg("{" @@ -226,8 +226,8 @@ class test_MsgHandlerChangePin QSignalSpy spyUi(ui, &UIPlugIn::fireWorkflowRequested); QSignalSpy spyStarted(&controller, &AppController::fireWorkflowStarted); QSignalSpy spyFinished(&controller, &AppController::fireWorkflowFinished); - connect(&controller, &AppController::fireWorkflowStarted, this, [this](QSharedPointer pContext){ - pContext->claim(this); // UIPlugInJson is internal API and does not claim by itself + connect(&controller, &AppController::fireWorkflowStarted, this, [this](const QSharedPointer& pRequest){ + pRequest->getContext()->claim(this); // UIPlugInJson is internal API and does not claim by itself }); QByteArray msgApiLevel = R"({"cmd": "SET_API_LEVEL", "level": *})"; @@ -286,8 +286,8 @@ class test_MsgHandlerChangePin QSignalSpy spyUi(ui, &UIPlugIn::fireWorkflowRequested); QSignalSpy spyStarted(&controller, &AppController::fireWorkflowStarted); QSignalSpy spyFinished(&controller, &AppController::fireWorkflowFinished); - connect(&controller, &AppController::fireWorkflowStarted, this, [this](QSharedPointer pContext){ - pContext->claim(this); // UIPlugInJson is internal API and does not claim by itself + connect(&controller, &AppController::fireWorkflowStarted, this, [this](const QSharedPointer& pRequest){ + pRequest->getContext()->claim(this); // UIPlugInJson is internal API and does not claim by itself }); QByteArray msgApiLevel = R"({"cmd": "SET_API_LEVEL", "level": *})"; diff --git a/test/qt/ui/json/test_MsgHandlerEnterCan.cpp b/test/qt/ui/json/test_MsgHandlerEnterCan.cpp index 899329bf2..feaf03b21 100644 --- a/test/qt/ui/json/test_MsgHandlerEnterCan.cpp +++ b/test/qt/ui/json/test_MsgHandlerEnterCan.cpp @@ -39,8 +39,9 @@ class test_MsgHandlerEnterCan void initTestCase() { const auto readerManager = Env::getSingleton(); + QSignalSpy spy(readerManager, &ReaderManager::fireInitialized); readerManager->init(); - readerManager->isScanRunning(); // just to wait until initialization finished + QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations } diff --git a/test/qt/ui/json/test_MsgHandlerEnterNewPin.cpp b/test/qt/ui/json/test_MsgHandlerEnterNewPin.cpp index 938770ac5..033a3ef1d 100644 --- a/test/qt/ui/json/test_MsgHandlerEnterNewPin.cpp +++ b/test/qt/ui/json/test_MsgHandlerEnterNewPin.cpp @@ -49,8 +49,9 @@ class test_MsgHandlerEnterNewPin void initTestCase() { const auto readerManager = Env::getSingleton(); + QSignalSpy spy(readerManager, &ReaderManager::fireInitialized); readerManager->init(); - readerManager->isScanRunning(); // just to wait until initialization finished + QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations } diff --git a/test/qt/ui/json/test_MsgHandlerEnterPin.cpp b/test/qt/ui/json/test_MsgHandlerEnterPin.cpp index e8fec98fd..a920d0712 100644 --- a/test/qt/ui/json/test_MsgHandlerEnterPin.cpp +++ b/test/qt/ui/json/test_MsgHandlerEnterPin.cpp @@ -40,8 +40,9 @@ class test_MsgHandlerEnterPin void initTestCase() { const auto readerManager = Env::getSingleton(); + QSignalSpy spy(readerManager, &ReaderManager::fireInitialized); readerManager->init(); - readerManager->isScanRunning(); // just to wait until initialization finished + QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations } diff --git a/test/qt/ui/json/test_MsgHandlerEnterPuk.cpp b/test/qt/ui/json/test_MsgHandlerEnterPuk.cpp index c801c7b14..151559a15 100644 --- a/test/qt/ui/json/test_MsgHandlerEnterPuk.cpp +++ b/test/qt/ui/json/test_MsgHandlerEnterPuk.cpp @@ -39,8 +39,9 @@ class test_MsgHandlerEnterPuk void initTestCase() { const auto readerManager = Env::getSingleton(); + QSignalSpy spy(readerManager, &ReaderManager::fireInitialized); readerManager->init(); - readerManager->isScanRunning(); // just to wait until initialization finished + QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations } diff --git a/test/qt/ui/json/test_MsgHandlerInfo.cpp b/test/qt/ui/json/test_MsgHandlerInfo.cpp index cb7ea4239..5769ad479 100644 --- a/test/qt/ui/json/test_MsgHandlerInfo.cpp +++ b/test/qt/ui/json/test_MsgHandlerInfo.cpp @@ -30,8 +30,9 @@ class test_MsgHandlerInfo void initTestCase() { const auto readerManager = Env::getSingleton(); + QSignalSpy spy(readerManager, &ReaderManager::fireInitialized); readerManager->init(); - readerManager->isScanRunning(); // just to wait until initialization finished + QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations } @@ -56,6 +57,21 @@ class test_MsgHandlerInfo } + void localIfd() + { + const QByteArray msg(R"({"cmd": "GET_INFO"})"); + MessageDispatcher dispatcher; + auto versionInfo = VersionInfo::getInstance().toJson(QJsonDocument::Compact); + + const auto& result = dispatcher.processCommand(msg); + QCOMPARE(result, MsgType::INFO); + const QByteArray data = result; + QVERIFY(data.contains(versionInfo)); + QVERIFY(data.contains(R"("msg":"INFO")")); + QVERIFY(data.contains(R"("AusweisApp")")); + } + + }; QTEST_GUILESS_MAIN(test_MsgHandlerInfo) diff --git a/test/qt/ui/json/test_MsgHandlerInsertCard.cpp b/test/qt/ui/json/test_MsgHandlerInsertCard.cpp index 3b7c7f60b..62e4bea0c 100644 --- a/test/qt/ui/json/test_MsgHandlerInsertCard.cpp +++ b/test/qt/ui/json/test_MsgHandlerInsertCard.cpp @@ -15,6 +15,7 @@ #include "TestWorkflowContext.h" +#include #include #include @@ -37,8 +38,9 @@ class test_MsgHandlerInsertCard void initTestCase() { const auto readerManager = Env::getSingleton(); + QSignalSpy spy(readerManager, &ReaderManager::fireInitialized); readerManager->init(); - readerManager->isScanRunning(); // just to wait until initialization finished + QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations } @@ -73,7 +75,7 @@ class test_MsgHandlerInsertCard MessageDispatcher dispatcher; setContext(dispatcher); - QCOMPARE(dispatcher.processStateChange(AbstractState::getClassName()), QByteArray("{\"msg\":\"INSERT_CARD\"}")); + QCOMPARE(dispatcher.processStateChange(StateBuilder::generateStateName()), QByteArray("{\"msg\":\"INSERT_CARD\"}")); } @@ -86,7 +88,7 @@ class test_MsgHandlerInsertCard MessageDispatcher dispatcher; setContext(dispatcher); - QCOMPARE(dispatcher.processStateChange(AbstractState::getClassName()), QByteArray("{\"msg\":\"INSERT_CARD\"}")); + QCOMPARE(dispatcher.processStateChange(StateBuilder::generateStateName()), QByteArray("{\"msg\":\"INSERT_CARD\"}")); } @@ -99,7 +101,7 @@ class test_MsgHandlerInsertCard MessageDispatcher dispatcher; setContext(dispatcher); - QCOMPARE(dispatcher.processStateChange(AbstractState::getClassName()), QByteArray()); + QCOMPARE(dispatcher.processStateChange(StateBuilder::generateStateName()), QByteArray()); } @@ -107,7 +109,7 @@ class test_MsgHandlerInsertCard { MessageDispatcher dispatcher; setContext(dispatcher); - QCOMPARE(dispatcher.processStateChange(AbstractState::getClassName()), QByteArray(R"({"msg":"INSERT_CARD"})")); + QCOMPARE(dispatcher.processStateChange(StateBuilder::generateStateName()), QByteArray(R"({"msg":"INSERT_CARD"})")); QByteArray msg(R"({"cmd": "SET_API_LEVEL", "level": 1})"); QCOMPARE(dispatcher.processCommand(msg), QByteArray(R"({"current":1,"msg":"API_LEVEL"})")); @@ -147,7 +149,7 @@ class test_MsgHandlerInsertCard { MessageDispatcher dispatcher; setContext(dispatcher); - QCOMPARE(dispatcher.processStateChange(AbstractState::getClassName()), QByteArray(R"({"msg":"INSERT_CARD"})")); + QCOMPARE(dispatcher.processStateChange(StateBuilder::generateStateName()), QByteArray(R"({"msg":"INSERT_CARD"})")); MockReader* reader = MockReaderManagerPlugIn::getInstance().addReader("MockReaderSimulator", ReaderManagerPlugInType::SIMULATOR); auto info = reader->getReaderInfo(); diff --git a/test/qt/ui/json/test_MsgHandlerPersonalization.cpp b/test/qt/ui/json/test_MsgHandlerPersonalization.cpp index 1d606743c..e0d135ccf 100644 --- a/test/qt/ui/json/test_MsgHandlerPersonalization.cpp +++ b/test/qt/ui/json/test_MsgHandlerPersonalization.cpp @@ -46,7 +46,7 @@ class test_MsgHandlerPersonalization private Q_SLOTS: void initTestCase() { - setUpdateInfo(EidUpdateInfo::UP_TO_DATE); + setSmartEidSupportStatus(EidSupportStatus::UP_TO_DATE); setSmartEidStatus(EidStatus::NO_PERSONALIZATION); qRegisterMetaType>("QSharedPointer"); @@ -236,8 +236,8 @@ class test_MsgHandlerPersonalization UILoader::setUserRequest({QStringLiteral("json")}); AppController controller; controller.start(); - connect(&controller, &AppController::fireWorkflowStarted, this, [this](QSharedPointer pContext){ - pContext->claim(this); // UIPlugInJson is internal API and does not claim by itself + connect(&controller, &AppController::fireWorkflowStarted, this, [this](const QSharedPointer& pRequest){ + pRequest->getContext()->claim(this); // UIPlugInJson is internal API and does not claim by itself }); QTRY_VERIFY(mSmartAvailable); // clazy:exclude=qstring-allocations @@ -253,7 +253,7 @@ class test_MsgHandlerPersonalization QVERIFY(ui); ui->setEnabled(true); ui->mMessageDispatcher.setSkipStateApprovedHook([&reachedStateGetTcToken](const QString& pState){ - if (AbstractState::isState(pState)) + if (StateBuilder::isState(pState)) { reachedStateGetTcToken = true; return true; @@ -337,8 +337,8 @@ class test_MsgHandlerPersonalization UILoader::setUserRequest({QStringLiteral("json")}); AppController controller; controller.start(); - connect(&controller, &AppController::fireWorkflowStarted, this, [this](QSharedPointer pContext){ - pContext->claim(this); // UIPlugInJson is internal API and does not claim by itself + connect(&controller, &AppController::fireWorkflowStarted, this, [this](const QSharedPointer& pRequest){ + pRequest->getContext()->claim(this); // UIPlugInJson is internal API and does not claim by itself }); QTRY_VERIFY(mSmartAvailable); // clazy:exclude=qstring-allocations @@ -349,7 +349,7 @@ class test_MsgHandlerPersonalization QVERIFY(ui); ui->setEnabled(true); ui->mMessageDispatcher.setSkipStateApprovedHook([&reachedStateGetTcToken](const QString& pState){ - if (AbstractState::isState(pState)) + if (StateBuilder::isState(pState)) { reachedStateGetTcToken = true; return true; @@ -420,8 +420,8 @@ class test_MsgHandlerPersonalization UILoader::setUserRequest({QStringLiteral("json")}); AppController controller; controller.start(); - connect(&controller, &AppController::fireWorkflowStarted, this, [this](QSharedPointer pContext){ - pContext->claim(this); // UIPlugInJson is internal API and does not claim by itself + connect(&controller, &AppController::fireWorkflowStarted, this, [this](const QSharedPointer& pRequest){ + pRequest->getContext()->claim(this); // UIPlugInJson is internal API and does not claim by itself }); QTRY_VERIFY(mSmartAvailable); // clazy:exclude=qstring-allocations @@ -432,7 +432,7 @@ class test_MsgHandlerPersonalization QVERIFY(ui); ui->setEnabled(true); ui->mMessageDispatcher.setSkipStateApprovedHook([&reachedStateGetTcToken](const QString& pState){ - if (AbstractState::isState(pState)) + if (StateBuilder::isState(pState)) { reachedStateGetTcToken = true; return true; @@ -494,8 +494,8 @@ class test_MsgHandlerPersonalization UILoader::setUserRequest({QStringLiteral("json")}); AppController controller; controller.start(); - connect(&controller, &AppController::fireWorkflowStarted, this, [this](QSharedPointer pContext){ - pContext->claim(this); // UIPlugInJson is internal API and does not claim by itself + connect(&controller, &AppController::fireWorkflowStarted, this, [this](const QSharedPointer& pRequest){ + pRequest->getContext()->claim(this); // UIPlugInJson is internal API and does not claim by itself }); QTRY_VERIFY(mSmartAvailable); // clazy:exclude=qstring-allocations @@ -507,7 +507,7 @@ class test_MsgHandlerPersonalization QVERIFY(ui); ui->setEnabled(true); ui->mMessageDispatcher.setSkipStateApprovedHook([&reachedStateGetTcToken](const QString& pState){ - if (AbstractState::isState(pState)) + if (StateBuilder::isState(pState)) { reachedStateGetTcToken = true; return true; diff --git a/test/qt/ui/json/test_MsgHandlerReader.cpp b/test/qt/ui/json/test_MsgHandlerReader.cpp index da5a597b8..b1b0c0b0e 100644 --- a/test/qt/ui/json/test_MsgHandlerReader.cpp +++ b/test/qt/ui/json/test_MsgHandlerReader.cpp @@ -11,6 +11,7 @@ #include "MessageDispatcher.h" #include "MockReaderManagerPlugIn.h" #include "ReaderManager.h" +#include "TestFileHelper.h" #include @@ -25,12 +26,19 @@ class test_MsgHandlerReader { Q_OBJECT +#if __has_include("SmartManager.h") + const QByteArray mEidType = QByteArray(R"("eidType":"CARD_CERTIFIED",)"); +#else + const QByteArray mEidType; +#endif + private Q_SLOTS: void initTestCase() { const auto readerManager = Env::getSingleton(); + QSignalSpy spy(readerManager, &ReaderManager::fireInitialized); readerManager->init(); - readerManager->isScanRunning(); // just to wait until initialization finished + QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations } @@ -90,7 +98,7 @@ class test_MsgHandlerReader MessageDispatcher dispatcher; QByteArray msg(R"({"cmd": "GET_READER", "name": "MockReader 0815"})"); - QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"attached\":true,\"card\":{\"deactivated\":false,\"inoperative\":false,\"retryCounter\":-1},\"insertable\":false,\"keypad\":false,\"msg\":\"READER\",\"name\":\"MockReader 0815\"}")); + QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"attached\":true,\"card\":{\"deactivated\":false," + mEidType + "\"inoperative\":false,\"retryCounter\":-1},\"insertable\":false,\"keypad\":false,\"msg\":\"READER\",\"name\":\"MockReader 0815\"}")); } @@ -117,10 +125,10 @@ class test_MsgHandlerReader MessageDispatcher dispatcher; QByteArray msg(R"({"cmd": "GET_READER", "name": "MockReader 0815"})"); - QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"attached\":true,\"card\":{\"deactivated\":false,\"inoperative\":false,\"retryCounter\":-1},\"insertable\":false,\"keypad\":false,\"msg\":\"READER\",\"name\":\"MockReader 0815\"}")); + QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"attached\":true,\"card\":{\"deactivated\":false," + mEidType + "\"inoperative\":false,\"retryCounter\":-1},\"insertable\":false,\"keypad\":false,\"msg\":\"READER\",\"name\":\"MockReader 0815\"}")); msg = R"({"cmd": "GET_READER", "name": "ReaderMock"})"; - QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"attached\":true,\"card\":{\"deactivated\":false,\"inoperative\":false,\"retryCounter\":-1},\"insertable\":false,\"keypad\":false,\"msg\":\"READER\",\"name\":\"ReaderMock\"}")); + QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"attached\":true,\"card\":{\"deactivated\":false," + mEidType + "\"inoperative\":false,\"retryCounter\":-1},\"insertable\":false,\"keypad\":false,\"msg\":\"READER\",\"name\":\"ReaderMock\"}")); msg = R"({"cmd": "GET_READER", "name": "ReaderMockXYZ"})"; QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"attached\":true,\"card\":null,\"insertable\":false,\"keypad\":false,\"msg\":\"READER\",\"name\":\"ReaderMockXYZ\"}")); @@ -129,10 +137,37 @@ class test_MsgHandlerReader QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"attached\":true,\"card\":null,\"insertable\":false,\"keypad\":false,\"msg\":\"READER\",\"name\":\"SpecialMock\"}")); msg = R"({"cmd": "GET_READER", "name": "SpecialMockWithGermanCard"})"; - QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"attached\":true,\"card\":{\"deactivated\":true,\"inoperative\":false,\"retryCounter\":3},\"insertable\":false,\"keypad\":false,\"msg\":\"READER\",\"name\":\"SpecialMockWithGermanCard\"}")); + QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"attached\":true,\"card\":{\"deactivated\":true," + mEidType + "\"inoperative\":false,\"retryCounter\":3},\"insertable\":false,\"keypad\":false,\"msg\":\"READER\",\"name\":\"SpecialMockWithGermanCard\"}")); + } + + +#if __has_include("SmartManager.h") + void eidType_data() + { + QTest::addColumn("efCardAccess"); + QTest::addColumn("eidType"); + + QTest::newRow("CARD_CERTIFIED") << TestFileHelper::readFile(":/card/efCardAccess.hex") << QByteArray("CARD_CERTIFIED"); + QTest::newRow("SE_ENDORSED") << TestFileHelper::readFile(":/card/smartEfCardAccess.hex") << QByteArray("SE_ENDORSED"); + } + + + void eidType() + { + QFETCH(QByteArray, efCardAccess); + QFETCH(QByteArray, eidType); + + MockReader* reader = MockReaderManagerPlugIn::getInstance().addReader("MockReader 0815"); + reader->setCard(MockCardConfig(), EFCardAccess::decode(QByteArray::fromHex(efCardAccess)), CardType::SMART_EID); + MessageDispatcher dispatcher; + + QByteArray msg(R"({"cmd": "GET_READER", "name": "MockReader 0815"})"); + QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"attached\":true,\"card\":{\"deactivated\":false,\"eidType\":\"\",\"inoperative\":false,\"retryCounter\":-1},\"insertable\":false,\"keypad\":false,\"msg\":\"READER\",\"name\":\"MockReader 0815\"}").replace("", eidType)); } +#endif + }; QTEST_GUILESS_MAIN(test_MsgHandlerReader) diff --git a/test/qt/ui/json/test_MsgHandlerReaderList.cpp b/test/qt/ui/json/test_MsgHandlerReaderList.cpp index d05a5cbce..f13bad455 100644 --- a/test/qt/ui/json/test_MsgHandlerReaderList.cpp +++ b/test/qt/ui/json/test_MsgHandlerReaderList.cpp @@ -22,12 +22,19 @@ class test_MsgHandlerReaderList { Q_OBJECT +#if __has_include("SmartManager.h") + const QByteArray mEidType = QByteArray(R"("eidType":"CARD_CERTIFIED",)"); +#else + const QByteArray mEidType; +#endif + private Q_SLOTS: void initTestCase() { const auto readerManager = Env::getSingleton(); + QSignalSpy spy(readerManager, &ReaderManager::fireInitialized); readerManager->init(); - readerManager->isScanRunning(); // just to wait until initialization finished + QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations } @@ -74,7 +81,7 @@ class test_MsgHandlerReaderList MessageDispatcher dispatcher; QByteArray msg(R"({"cmd": "GET_READER_LIST"})"); - QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"msg\":\"READER_LIST\",\"readers\":[{\"attached\":true,\"card\":{\"deactivated\":false,\"inoperative\":false,\"retryCounter\":-1},\"insertable\":false,\"keypad\":false,\"name\":\"MockReader 0815\"}]}")); + QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"msg\":\"READER_LIST\",\"readers\":[{\"attached\":true,\"card\":{\"deactivated\":false," + mEidType + "\"inoperative\":false,\"retryCounter\":-1},\"insertable\":false,\"keypad\":false,\"name\":\"MockReader 0815\"}]}")); } @@ -103,12 +110,13 @@ class test_MsgHandlerReaderList QByteArray msg(R"({"cmd": "GET_READER_LIST"})"); QByteArray expected("{\"msg\":\"READER_LIST\",\"readers\":[" - "{\"attached\":true,\"card\":{\"deactivated\":false,\"inoperative\":false,\"retryCounter\":-1},\"insertable\":false,\"keypad\":false,\"name\":\"MockReader 0815\"}," - "{\"attached\":true,\"card\":{\"deactivated\":false,\"inoperative\":false,\"retryCounter\":-1},\"insertable\":false,\"keypad\":false,\"name\":\"ReaderMock\"}," + "{\"attached\":true,\"card\":{\"deactivated\":false,\"inoperative\":false,\"retryCounter\":-1},\"insertable\":false,\"keypad\":false,\"name\":\"MockReader 0815\"}," + "{\"attached\":true,\"card\":{\"deactivated\":false,\"inoperative\":false,\"retryCounter\":-1},\"insertable\":false,\"keypad\":false,\"name\":\"ReaderMock\"}," "{\"attached\":true,\"card\":null,\"insertable\":false,\"keypad\":false,\"name\":\"ReaderMockXYZ\"}," "{\"attached\":true,\"card\":null,\"insertable\":false,\"keypad\":false,\"name\":\"SpecialMock\"}," - "{\"attached\":true,\"card\":{\"deactivated\":true,\"inoperative\":false,\"retryCounter\":3},\"insertable\":false,\"keypad\":false,\"name\":\"SpecialMockWithGermanCard\"}" + "{\"attached\":true,\"card\":{\"deactivated\":true,\"inoperative\":false,\"retryCounter\":3},\"insertable\":false,\"keypad\":false,\"name\":\"SpecialMockWithGermanCard\"}" "]}"); + expected.replace("", mEidType); QCOMPARE(dispatcher.processCommand(msg), expected); } diff --git a/test/qt/ui/json/test_MsgHandlerStatus.cpp b/test/qt/ui/json/test_MsgHandlerStatus.cpp index f7dd8a21b..206398f4e 100644 --- a/test/qt/ui/json/test_MsgHandlerStatus.cpp +++ b/test/qt/ui/json/test_MsgHandlerStatus.cpp @@ -11,7 +11,6 @@ #include "MessageDispatcher.h" #include "ReaderManager.h" #include "context/ChangePinContext.h" -#include "context/InternalActivationContext.h" #include "context/SelfAuthContext.h" #include "states/StateConnectCard.h" #include "states/StateEditAccessRights.h" @@ -48,8 +47,9 @@ class test_MsgHandlerStatus void initTestCase() { const auto readerManager = Env::getSingleton(); + QSignalSpy spy(readerManager, &ReaderManager::fireInitialized); readerManager->init(); - readerManager->isScanRunning(); // just to wait until initialization finished + QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations } @@ -148,13 +148,12 @@ class test_MsgHandlerStatus void stateAccessRights() { - const QSharedPointer activationContext(new InternalActivationContext(QUrl("http://dummy"))); - const QSharedPointer context(new TestAuthContext(activationContext, ":/paos/DIDAuthenticateEAC1.xml")); + const QSharedPointer context(new TestAuthContext(":/paos/DIDAuthenticateEAC1.xml")); MessageDispatcher dispatcher; QCOMPARE(dispatcher.init(context), MsgType::AUTH); - QVERIFY(QByteArray(dispatcher.processStateChange(AbstractState::getClassName())).contains(QByteArray(R"("msg":"ACCESS_RIGHTS")"))); + QVERIFY(QByteArray(dispatcher.processStateChange(StateBuilder::generateStateName())).contains(QByteArray(R"("msg":"ACCESS_RIGHTS")"))); QCOMPARE(dispatcher.processCommand(cmd), QByteArray(R"({"msg":"STATUS","progress":0,"state":"ACCESS_RIGHTS","workflow":"AUTH"})")); } @@ -166,7 +165,7 @@ class test_MsgHandlerStatus MessageDispatcher dispatcher; QCOMPARE(dispatcher.init(context), MsgType::VOID); - QCOMPARE(dispatcher.processStateChange(AbstractState::getClassName()), QByteArray(R"({"msg":"ENTER_PIN"})")); + QCOMPARE(dispatcher.processStateChange(StateBuilder::generateStateName()), QByteArray(R"({"msg":"ENTER_PIN"})")); QCOMPARE(dispatcher.processCommand(cmd), QByteArray(R"({"msg":"STATUS","progress":0,"state":"ENTER_PIN","workflow":"AUTH"})")); } @@ -177,7 +176,7 @@ class test_MsgHandlerStatus MessageDispatcher dispatcher; QCOMPARE(dispatcher.init(context), MsgType::CHANGE_PIN); - QCOMPARE(dispatcher.processStateChange(AbstractState::getClassName()), QByteArray(R"({"msg":"ENTER_NEW_PIN"})")); + QCOMPARE(dispatcher.processStateChange(StateBuilder::generateStateName()), QByteArray(R"({"msg":"ENTER_NEW_PIN"})")); QCOMPARE(dispatcher.processCommand(cmd), QByteArray(R"({"msg":"STATUS","progress":0,"state":"ENTER_NEW_PIN","workflow":"CHANGE_PIN"})")); } @@ -189,7 +188,7 @@ class test_MsgHandlerStatus MessageDispatcher dispatcher; QCOMPARE(dispatcher.init(context), MsgType::VOID); - QCOMPARE(dispatcher.processStateChange(AbstractState::getClassName()), QByteArray(R"({"msg":"ENTER_CAN"})")); + QCOMPARE(dispatcher.processStateChange(StateBuilder::generateStateName()), QByteArray(R"({"msg":"ENTER_CAN"})")); QCOMPARE(dispatcher.processCommand(cmd), QByteArray(R"({"msg":"STATUS","progress":0,"state":"ENTER_CAN","workflow":"AUTH"})")); } @@ -201,7 +200,7 @@ class test_MsgHandlerStatus MessageDispatcher dispatcher; QCOMPARE(dispatcher.init(context), MsgType::VOID); - QCOMPARE(dispatcher.processStateChange(AbstractState::getClassName()), QByteArray(R"({"msg":"ENTER_PUK"})")); + QCOMPARE(dispatcher.processStateChange(StateBuilder::generateStateName()), QByteArray(R"({"msg":"ENTER_PUK"})")); QCOMPARE(dispatcher.processCommand(cmd), QByteArray(R"({"msg":"STATUS","progress":0,"state":"ENTER_PUK","workflow":"AUTH"})")); } @@ -211,10 +210,10 @@ class test_MsgHandlerStatus MessageDispatcher dispatcher; setContext(dispatcher); - QCOMPARE(dispatcher.processStateChange(AbstractState::getClassName()), QByteArray(R"({"msg":"INSERT_CARD"})")); + QCOMPARE(dispatcher.processStateChange(StateBuilder::generateStateName()), QByteArray(R"({"msg":"INSERT_CARD"})")); QCOMPARE(dispatcher.processCommand(cmd), QByteArray(R"({"msg":"STATUS","progress":0,"state":"INSERT_CARD","workflow":"AUTH"})")); - QCOMPARE(dispatcher.processStateChange(AbstractState::getClassName()), QByteArray()); + QCOMPARE(dispatcher.processStateChange(StateBuilder::generateStateName()), QByteArray()); QCOMPARE(dispatcher.processCommand(cmd), QByteArray(R"({"msg":"STATUS","progress":0,"state":null,"workflow":"AUTH"})")); } diff --git a/test/qt/ui/json/test_UILoader.cpp b/test/qt/ui/json/test_UILoader.cpp index d82f9a1b2..8c43f2fe8 100644 --- a/test/qt/ui/json/test_UILoader.cpp +++ b/test/qt/ui/json/test_UILoader.cpp @@ -44,11 +44,7 @@ class test_UILoader QCOMPARE(ui->property("userInteractive"), QVariant()); QCOMPARE(ui->property("readerManager"), QVariant()); -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) QTest::ignoreMessage(QtDebugMsg, R"(Shutdown UILoader: QList("json"))"); -#else - QTest::ignoreMessage(QtDebugMsg, R"(Shutdown UILoader: ("json"))"); -#endif } @@ -63,12 +59,7 @@ class test_UILoader QVERIFY(!loader.load()); QVERIFY(!loader.isLoaded()); -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) QTest::ignoreMessage(QtDebugMsg, "Shutdown UILoader: QList()"); -#else - QTest::ignoreMessage(QtDebugMsg, "Shutdown UILoader: ()"); -#endif - loader.shutdown(); } @@ -86,11 +77,7 @@ class test_UILoader QCOMPARE(spyLoaded.count(), 1); QVERIFY(loader.getLoaded()); -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) QTest::ignoreMessage(QtDebugMsg, R"(Shutdown UILoader: QList("json"))"); -#else - QTest::ignoreMessage(QtDebugMsg, R"(Shutdown UILoader: ("json"))"); -#endif } @@ -105,12 +92,7 @@ class test_UILoader QVERIFY(loader.initialize()); // empty list is ok QCOMPARE(spyLoaded.count(), 0); -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) QTest::ignoreMessage(QtDebugMsg, "Shutdown UILoader: QList()"); -#else - QTest::ignoreMessage(QtDebugMsg, "Shutdown UILoader: ()"); -#endif - loader.shutdown(); } @@ -124,12 +106,7 @@ class test_UILoader QVERIFY(!loader.isLoaded()); QCOMPARE(spyLoaded.count(), 0); -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) QTest::ignoreMessage(QtDebugMsg, "Shutdown UILoader: QList()"); -#else - QTest::ignoreMessage(QtDebugMsg, "Shutdown UILoader: ()"); -#endif - loader.shutdown(); } @@ -139,11 +116,7 @@ class test_UILoader auto loader = QSharedPointer::create(); QSignalSpy spyShutdown(loader.get(), &UILoader::fireRemovedAllPlugins); -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) QTest::ignoreMessage(QtDebugMsg, "Shutdown UILoader: QList()"); -#else - QTest::ignoreMessage(QtDebugMsg, "Shutdown UILoader: ()"); -#endif loader->shutdown(); QCoreApplication::processEvents(); // cannot use QTRY_COMPARE here QCOMPARE(spyShutdown.count(), 0); @@ -158,11 +131,7 @@ class test_UILoader QTest::ignoreMessage(QtDebugMsg, R"(Try to load UI plugin: "json")"); QVERIFY(loader->load()); -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) QTest::ignoreMessage(QtDebugMsg, R"(Shutdown UILoader: QList("json"))"); -#else - QTest::ignoreMessage(QtDebugMsg, R"(Shutdown UILoader: ("json"))"); -#endif QTest::ignoreMessage(QtDebugMsg, R"(Shutdown UI: "json")"); loader->shutdown(); QTRY_COMPARE(spyShutdown.count(), 1); // clazy:exclude=qstring-allocations diff --git a/test/qt/ui/proxy/test_UILoader.cpp b/test/qt/ui/proxy/test_UILoader.cpp index 34f6855cc..6b2f1c5cc 100644 --- a/test/qt/ui/proxy/test_UILoader.cpp +++ b/test/qt/ui/proxy/test_UILoader.cpp @@ -41,11 +41,7 @@ class test_UILoader QCOMPARE(ui->property("passive"), QVariant()); QCOMPARE(ui->property("readerManager"), QVariant(false)); -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) QTest::ignoreMessage(QtDebugMsg, R"(Shutdown UILoader: QList("proxy"))"); -#else - QTest::ignoreMessage(QtDebugMsg, R"(Shutdown UILoader: ("proxy"))"); -#endif } diff --git a/test/qt/ui/qml/smart/test_SmartModel.cpp b/test/qt/ui/qml/smart/test_SmartModel.cpp index 0c70d1587..ca044c977 100644 --- a/test/qt/ui/qml/smart/test_SmartModel.cpp +++ b/test/qt/ui/qml/smart/test_SmartModel.cpp @@ -11,16 +11,23 @@ #include "Env.h" #include "MockReaderManagerPlugIn.h" #include "ReaderManager.h" -#include "SmartManager.h" #include "mock/eid_applet_interface_mock.h" +#include #include + Q_IMPORT_PLUGIN(MockReaderManagerPlugIn) + using namespace governikus; +Q_DECLARE_METATYPE(EidStatus) +Q_DECLARE_METATYPE(EidSupportStatus) +Q_DECLARE_METATYPE(EidServiceResult) + + class test_SmartModel : public QObject { @@ -43,8 +50,9 @@ class test_SmartModel { MockReader::cMOCKED_READERMANAGER_TYPE = ReaderManagerPlugInType::SMART; const auto readerManager = Env::getSingleton(); + QSignalSpy spy(readerManager, &ReaderManager::fireInitialized); readerManager->init(); - readerManager->isScanRunning(); // just to wait until initialization finished + QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations setSmartEidStatus(EidStatus::PERSONALIZED); mSmartReader = MockReaderManagerPlugIn::getInstance().addReader("SmartReader"); @@ -56,6 +64,15 @@ class test_SmartModel } + void cleanup() + { + setupSmartReader(false, 3); + setSmartEidSupportStatusResult({EidServiceResult::SUCCESS, EidSupportStatus::AVAILABLE}); + setSmartEidStatus(EidStatus::PERSONALIZED); + Env::getSingleton()->mStatus = SmartModel::QmlSmartState::SMART_READY; + } + + void cleanupTestCase() { MockReaderManagerPlugIn::getInstance().removeAllReader(); @@ -70,12 +87,12 @@ class test_SmartModel QTest::addColumn("retryCounter"); QTest::addColumn("smartState"); - QTest::newRow("Unusable") << EidStatus::APPLET_UNUSABLE << false << 3 << SmartModel::QmlSmartState::SMART_UNUSABLE; + QTest::newRow("Unusable") << EidStatus::UNUSABLE << false << 3 << SmartModel::QmlSmartState::SMART_UNUSABLE; QTest::newRow("Internal error") << EidStatus::INTERNAL_ERROR << false << 3 << SmartModel::QmlSmartState::SMART_UNAVAILABLE; QTest::newRow("No personalization") << EidStatus::NO_PERSONALIZATION << false << 3 << SmartModel::QmlSmartState::SMART_NO_PERSONALIZATION; QTest::newRow("No provisioning") << EidStatus::NO_PROVISIONING << false << 3 << SmartModel::QmlSmartState::SMART_NO_PROVISIONING; QTest::newRow("Personalized") << EidStatus::PERSONALIZED << false << 3 << SmartModel::QmlSmartState::SMART_READY; - QTest::newRow("Unavailable") << EidStatus::UNAVAILABLE << false << 3 << SmartModel::QmlSmartState::SMART_UNAVAILABLE; + QTest::newRow("cert_expired") << EidStatus::CERT_EXPIRED << false << 3 << SmartModel::QmlSmartState::SMART_UNUSABLE; QTest::newRow("Personalized - Retry Counter 0") << EidStatus::PERSONALIZED << false << 0 << SmartModel::QmlSmartState::SMART_UNUSABLE; QTest::newRow("Personalized - Retry Counter -1") << EidStatus::PERSONALIZED << false << -1 << SmartModel::QmlSmartState::SMART_UNUSABLE; @@ -148,7 +165,7 @@ class test_SmartModel int signalCount = 0; - connect(smartModel, &SmartModel::fireSmartStateChanged, [&signalCount, smartModel](){ + const auto connection = connect(smartModel, &SmartModel::fireSmartStateChanged, [&signalCount, smartModel](){ signalCount++; switch (signalCount) @@ -165,6 +182,9 @@ class test_SmartModel QFAIL("Expected only two signals"); } }); + const auto guard = qScopeGuard([connection] { + disconnect(connection); + }); smartModel->updateStatus(); QTRY_COMPARE(signalCount, 2); @@ -197,7 +217,111 @@ class test_SmartModel } + void test_updateSupportInfo_data() + { + QTest::addColumn("eidSupportStatus"); + QTest::addColumn("eidStatus"); + QTest::addColumn("smartState"); + + QTest::newRow("Unavailable1") << EidSupportStatus::UNAVAILABLE << EidStatus::NO_PROVISIONING << SmartModel::QmlSmartState::SMART_UNAVAILABLE; + QTest::newRow("Unavailable2") << EidSupportStatus::UNAVAILABLE << EidStatus::NO_PERSONALIZATION << SmartModel::QmlSmartState::SMART_UNAVAILABLE; + QTest::newRow("Unavailable3") << EidSupportStatus::UNAVAILABLE << EidStatus::PERSONALIZED << SmartModel::QmlSmartState::SMART_UNAVAILABLE; + QTest::newRow("Unavailable4") << EidSupportStatus::UNAVAILABLE << EidStatus::UNUSABLE << SmartModel::QmlSmartState::SMART_UNAVAILABLE; + QTest::newRow("Available1") << EidSupportStatus::AVAILABLE << EidStatus::NO_PROVISIONING << SmartModel::QmlSmartState::SMART_NO_PROVISIONING; + QTest::newRow("Available2") << EidSupportStatus::AVAILABLE << EidStatus::NO_PERSONALIZATION << SmartModel::QmlSmartState::SMART_NO_PERSONALIZATION; + QTest::newRow("Available3") << EidSupportStatus::AVAILABLE << EidStatus::PERSONALIZED << SmartModel::QmlSmartState::SMART_READY; + QTest::newRow("Available4") << EidSupportStatus::AVAILABLE << EidStatus::UNUSABLE << SmartModel::QmlSmartState::SMART_UNUSABLE; + QTest::newRow("UpToDate1") << EidSupportStatus::UP_TO_DATE << EidStatus::NO_PROVISIONING << SmartModel::QmlSmartState::SMART_NO_PROVISIONING; + QTest::newRow("UpToDate2") << EidSupportStatus::UP_TO_DATE << EidStatus::NO_PERSONALIZATION << SmartModel::QmlSmartState::SMART_NO_PERSONALIZATION; + QTest::newRow("UpToDate3") << EidSupportStatus::UP_TO_DATE << EidStatus::PERSONALIZED << SmartModel::QmlSmartState::SMART_READY; + QTest::newRow("UpToDate4") << EidSupportStatus::UP_TO_DATE << EidStatus::UNUSABLE << SmartModel::QmlSmartState::SMART_UNUSABLE; + QTest::newRow("UpdateAvailable1") << EidSupportStatus::UPDATE_AVAILABLE << EidStatus::NO_PROVISIONING << SmartModel::QmlSmartState::SMART_NO_PROVISIONING; + QTest::newRow("UpdateAvailable2") << EidSupportStatus::UPDATE_AVAILABLE << EidStatus::NO_PERSONALIZATION << SmartModel::QmlSmartState::SMART_NO_PERSONALIZATION; + QTest::newRow("UpdateAvailable3") << EidSupportStatus::UPDATE_AVAILABLE << EidStatus::PERSONALIZED << SmartModel::QmlSmartState::SMART_READY; + QTest::newRow("UpdateAvailable4") << EidSupportStatus::UPDATE_AVAILABLE << EidStatus::UNUSABLE << SmartModel::QmlSmartState::SMART_UNUSABLE; + QTest::newRow("InternalError1") << EidSupportStatus::INTERNAL_ERROR << EidStatus::NO_PROVISIONING << SmartModel::QmlSmartState::SMART_UNAVAILABLE; + QTest::newRow("InternalError2") << EidSupportStatus::INTERNAL_ERROR << EidStatus::NO_PERSONALIZATION << SmartModel::QmlSmartState::SMART_UNAVAILABLE; + QTest::newRow("InternalError3") << EidSupportStatus::INTERNAL_ERROR << EidStatus::PERSONALIZED << SmartModel::QmlSmartState::SMART_UNAVAILABLE; + QTest::newRow("InternalError4") << EidSupportStatus::INTERNAL_ERROR << EidStatus::UNUSABLE << SmartModel::QmlSmartState::SMART_UNAVAILABLE; + } + + + void test_updateSupportInfo() + { + QFETCH(EidSupportStatus, eidSupportStatus); + QFETCH(EidStatus, eidStatus); + QFETCH(SmartModel::QmlSmartState, smartState); + + const auto& smartModel = Env::getSingleton(); + smartModel->mStatus = SmartModel::QmlSmartState::SMART_NO_PROVISIONING; + + setSmartEidSupportStatus(eidSupportStatus); + setSmartEidStatus(eidStatus); + smartModel->updateSupportInfo(); + QCOMPARE(smartModel->getSmartState(), SmartModel::QmlSmartState::SMART_UPDATING_STATUS); + QTRY_COMPARE(smartModel->getSmartState(), smartState); + } + + + void test_errorStringUpdateSupportInfo_data() + { + QTest::addColumn("serviceResult"); + + QTest::addRow("Success") << EidServiceResult::SUCCESS; + QTest::addRow("Unsupported") << EidServiceResult::UNSUPPORTED; + QTest::addRow("Error") << EidServiceResult::ERROR; + QTest::addRow("Info") << EidServiceResult::INFO; + QTest::addRow("NFC not activated") << EidServiceResult::NFC_NOT_ACTIVATED; + QTest::addRow("Overload protection") << EidServiceResult::OVERLOAD_PROTECTION; + QTest::addRow("Undefined") << EidServiceResult::UNDEFINED; + QTest::addRow("Warn") << EidServiceResult::WARN; + QTest::addRow("Under maintenance") << EidServiceResult::UNDER_MAINTENANCE; + } + + + void test_errorStringUpdateSupportInfo() + { + QFETCH(EidServiceResult, serviceResult); + + setSmartEidSupportStatusResult({serviceResult, EidSupportStatus::AVAILABLE}); + auto* smartModel = Env::getSingleton(); + smartModel->mStatus = SmartModel::QmlSmartState::SMART_NO_PROVISIONING; + smartModel->updateSupportInfo(); + QTRY_VERIFY(smartModel->getSmartState() != SmartModel::QmlSmartState::SMART_UPDATING_STATUS); + QCOMPARE(smartModel->getErrorString().isEmpty(), serviceResult == EidServiceResult::SUCCESS); + } + + + void test_errorStringDeleteSmart_data() + { + QTest::addColumn("serviceResult"); + + QTest::addRow("Success") << EidServiceResult::SUCCESS; + QTest::addRow("Unsupported") << EidServiceResult::UNSUPPORTED; + QTest::addRow("Error") << EidServiceResult::ERROR; + QTest::addRow("Info") << EidServiceResult::INFO; + QTest::addRow("NFC not activated") << EidServiceResult::NFC_NOT_ACTIVATED; + QTest::addRow("Overload protection") << EidServiceResult::OVERLOAD_PROTECTION; + QTest::addRow("Undefined") << EidServiceResult::UNDEFINED; + QTest::addRow("Warn") << EidServiceResult::WARN; + QTest::addRow("Under maintenance") << EidServiceResult::UNDER_MAINTENANCE; + } + + + void test_errorStringDeleteSmart() + { + QFETCH(EidServiceResult, serviceResult); + + setDeleteSmartEidResult(serviceResult); + auto* smartModel = Env::getSingleton(); + QSignalSpy spyDeleteDone(smartModel, &SmartModel::fireDeleteSmartDone); + smartModel->deleteSmart(); + QTRY_COMPARE(spyDeleteDone.count(), 1); + QCOMPARE(smartModel->getErrorString().isEmpty(), serviceResult == EidServiceResult::SUCCESS); + } + + }; -QTEST_GUILESS_MAIN(test_SmartModel) +QTEST_MAIN(test_SmartModel) #include "test_SmartModel.moc" diff --git a/test/qt/ui/qml/test_ApplicationModel.cpp b/test/qt/ui/qml/test_ApplicationModel.cpp index 530822245..daf89c637 100644 --- a/test/qt/ui/qml/test_ApplicationModel.cpp +++ b/test/qt/ui/qml/test_ApplicationModel.cpp @@ -8,7 +8,6 @@ #include "ApplicationModel.h" -#include "MockActivationContext.h" #include "MockIfdServer.h" #include "context/AuthContext.h" #include "context/ChangePinContext.h" @@ -58,7 +57,7 @@ class test_ApplicationModel QTest::addColumn("workflow"); QTest::addRow("No Context") << QSharedPointer() << ApplicationModel::Workflow::WORKFLOW_NONE; - QTest::addRow("AuthContext") << QSharedPointer(new AuthContext(QSharedPointer::create())) << ApplicationModel::Workflow::WORKFLOW_AUTHENTICATION; + QTest::addRow("AuthContext") << QSharedPointer(new AuthContext()) << ApplicationModel::Workflow::WORKFLOW_AUTHENTICATION; QTest::addRow("ChangePinContext") << QSharedPointer(new ChangePinContext()) << ApplicationModel::Workflow::WORKFLOW_CHANGE_PIN; QTest::addRow("IfdServiceContext") << QSharedPointer(new IfdServiceContext(QSharedPointer::create())) << ApplicationModel::Workflow::WORKFLOW_REMOTE_SERVICE; QTest::addRow("SelfAuthContext") << QSharedPointer(new SelfAuthContext()) << ApplicationModel::Workflow::WORKFLOW_SELF_AUTHENTICATION; diff --git a/test/qt/ui/qml/test_AuthModel.cpp b/test/qt/ui/qml/test_AuthModel.cpp index 7dfbcac7b..01ba1fd41 100644 --- a/test/qt/ui/qml/test_AuthModel.cpp +++ b/test/qt/ui/qml/test_AuthModel.cpp @@ -30,13 +30,17 @@ class test_AuthModel void test_ResetContext() { const auto model = Env::getSingleton(); - const QSharedPointer context(new AuthContext(nullptr)); + const QSharedPointer context(new AuthContext()); + QSignalSpy spyWorkflowStarted(model, &WorkflowModel::fireWorkflowStarted); QSignalSpy spyCurrentStateChanged(model, &WorkflowModel::fireCurrentStateChanged); + QSignalSpy spyStateEntered(model, &WorkflowModel::fireStateEntered); QSignalSpy spyTransactionInfoChanged(model, &AuthModel::fireTransactionInfoChanged); model->resetAuthContext(context); + QCOMPARE(spyWorkflowStarted.count(), 1); QCOMPARE(spyCurrentStateChanged.count(), 1); + QCOMPARE(spyStateEntered.count(), 0); QCOMPARE(spyTransactionInfoChanged.count(), 0); QByteArray content = TestFileHelper::readFile(":/paos/DIDAuthenticateEAC1.xml"); @@ -47,7 +51,9 @@ class test_AuthModel QVERIFY(model->getTransactionInfo().isEmpty()); Q_EMIT context->fireDidAuthenticateEac1Changed(); QCOMPARE(model->getTransactionInfo(), QString("this is a test for TransactionInfo")); + QCOMPARE(spyWorkflowStarted.count(), 2); QCOMPARE(spyCurrentStateChanged.count(), 2); + QCOMPARE(spyStateEntered.count(), 0); QCOMPARE(spyTransactionInfoChanged.count(), 3); } diff --git a/test/qt/ui/qml/test_CertificateDescriptionModel.cpp b/test/qt/ui/qml/test_CertificateDescriptionModel.cpp index 44281f789..61fe4298d 100644 --- a/test/qt/ui/qml/test_CertificateDescriptionModel.cpp +++ b/test/qt/ui/qml/test_CertificateDescriptionModel.cpp @@ -45,7 +45,7 @@ class test_CertificateDescriptionModel private Q_SLOTS: void init() { - mContext.reset(new TestAuthContext(nullptr, ":/paos/DIDAuthenticateEAC1.xml")); + mContext.reset(new TestAuthContext(":/paos/DIDAuthenticateEAC1.xml")); mModel = Env::getSingleton(); } @@ -96,7 +96,7 @@ class test_CertificateDescriptionModel void test_Validity() { - mContext.reset(new TestAuthContext(nullptr, ":/paos/DIDAuthenticateEAC1_ordered_certificates.xml")); + mContext.reset(new TestAuthContext(":/paos/DIDAuthenticateEAC1_ordered_certificates.xml")); mContext->initAccessRightManager(mContext->getDidAuthenticateEac1()->getCvCertificates().last()); mModel->resetContext(mContext); diff --git a/test/qt/ui/qml/test_ChangePinModel.cpp b/test/qt/ui/qml/test_ChangePinModel.cpp index 88f48964d..183e68105 100644 --- a/test/qt/ui/qml/test_ChangePinModel.cpp +++ b/test/qt/ui/qml/test_ChangePinModel.cpp @@ -26,18 +26,15 @@ class test_ChangePinModel QSharedPointer context(new ChangePinContext()); QSignalSpy resultChanged(model, &ChangePinModel::fireResultChanged); - QSignalSpy newContextSet(model, &ChangePinModel::fireNewContextSet); model->resetChangePinContext(); QCOMPARE(resultChanged.count(), 1); - QCOMPARE(newContextSet.count(), 0); Q_EMIT context->fireSuccessMessageChanged(); QCOMPARE(resultChanged.count(), 1); model->resetChangePinContext(context); QCOMPARE(resultChanged.count(), 2); - QCOMPARE(newContextSet.count(), 1); Q_EMIT context->fireSuccessMessageChanged(); QCOMPARE(resultChanged.count(), 3); diff --git a/test/qt/ui/qml/test_ChatModel.cpp b/test/qt/ui/qml/test_ChatModel.cpp index db6acd875..8bceabbf5 100644 --- a/test/qt/ui/qml/test_ChatModel.cpp +++ b/test/qt/ui/qml/test_ChatModel.cpp @@ -11,7 +11,6 @@ #include "context/SelfAuthContext.h" #include "paos/retrieve/DidAuthenticateEac1Parser.h" -#include "MockActivationContext.h" #include "TestAuthContext.h" #include "TestFileHelper.h" @@ -28,7 +27,6 @@ class test_ChatModel { Q_OBJECT QPointer mModel; - QSharedPointer mActContext; QSharedPointer mAuthContext; private Q_SLOTS: @@ -36,15 +34,13 @@ class test_ChatModel { Q_ASSERT(mModel.isNull()); mModel = new ChatModel(); - mActContext.reset(new MockActivationContext()); - mAuthContext.reset(new TestAuthContext(mActContext)); + mAuthContext.reset(new TestAuthContext()); } void cleanup() { delete mModel.data(); - mActContext.clear(); mAuthContext.clear(); } diff --git a/test/qt/ui/qml/test_ConnectivityManager.cpp b/test/qt/ui/qml/test_ConnectivityManager.cpp index ad5a1dca5..2ede50bb3 100644 --- a/test/qt/ui/qml/test_ConnectivityManager.cpp +++ b/test/qt/ui/qml/test_ConnectivityManager.cpp @@ -38,15 +38,25 @@ class test_ConnectivityManager QVERIFY(!manager.isNetworkInterfaceActive()); - manager.setActive(true, name); + manager.setActive(true); QCOMPARE(logSpy.count(), 1); - QVERIFY(logSpy.takeFirst().at(0).toString().contains("Found active network interface")); + QVERIFY(logSpy.takeFirst().at(0).toString().contains("A network interface is now available")); QCOMPARE(signalSpy.count(), 1); QVERIFY(manager.isNetworkInterfaceActive()); - manager.setActive(false, name); + manager.setActive(true); + QCOMPARE(logSpy.count(), 0); + QCOMPARE(signalSpy.count(), 1); + QVERIFY(manager.isNetworkInterfaceActive()); + + manager.setActive(false); QCOMPARE(logSpy.count(), 1); - QVERIFY(logSpy.takeFirst().at(0).toString().contains("Found no active network interface")); + QVERIFY(logSpy.takeFirst().at(0).toString().contains("An active network interface is no longer available")); + QCOMPARE(signalSpy.count(), 2); + QVERIFY(!manager.isNetworkInterfaceActive()); + + manager.setActive(false); + QCOMPARE(logSpy.count(), 0); QCOMPARE(signalSpy.count(), 2); QVERIFY(!manager.isNetworkInterfaceActive()); } @@ -55,22 +65,23 @@ class test_ConnectivityManager void test_Watching() { ConnectivityManager manager; - QSignalSpy logSpy(Env::getSingleton()->getEventHandler(), &LogEventHandler::fireLog); + QSignalSpy signalSpy(&manager, &ConnectivityManager::fireWatchingChanged); - manager.startWatching(); + manager.setWatching(true); QVERIFY(manager.mTimerId != 0); - QCOMPARE(logSpy.count(), 1); + QCOMPARE(signalSpy.count(), 1); - manager.startWatching(); - QCOMPARE(logSpy.count(), 2); - QVERIFY(logSpy.at(1).at(0).toString().contains("Already started, skip")); + manager.setWatching(true); + QVERIFY(manager.mTimerId != 0); + QCOMPARE(signalSpy.count(), 1); - manager.stopWatching(); + manager.setWatching(false); QCOMPARE(manager.mTimerId, 0); + QCOMPARE(signalSpy.count(), 2); - manager.stopWatching(); - QCOMPARE(logSpy.count(), 3); - QVERIFY(logSpy.at(2).at(0).toString().contains("Already stopped, skip")); + manager.setWatching(false); + QCOMPARE(manager.mTimerId, 0); + QCOMPARE(signalSpy.count(), 2); } diff --git a/test/qt/ui/qml/test_HelpAction.cpp b/test/qt/ui/qml/test_HelpAction.cpp deleted file mode 100644 index 236a636f8..000000000 --- a/test/qt/ui/qml/test_HelpAction.cpp +++ /dev/null @@ -1,162 +0,0 @@ -/** - * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany - */ - -/*! - * \brief Unit tests for \ref HelpAction - */ - -#include "TestFileHelper.h" - -#include - -#include "HelpAction.h" -#include "LanguageLoader.h" - -using namespace governikus; - -class test_HelpAction - : public QObject -{ - Q_OBJECT - - QDir helpDir = QCoreApplication::applicationDirPath() + QStringLiteral("/help/"); - QTemporaryDir mTranslationDir; - - void loadLanguage(QLocale::Language pLang) - { - if (LanguageLoader::getInstance().isLoaded()) - { - LanguageLoader::getInstance().unload(); - } - - LanguageLoader::getInstance().load(pLang); - QCOMPARE(LanguageLoader::getInstance().getUsedLocale().language(), pLang); - } - - - QString toWebUrl(const QString& pLang = QStringLiteral("en")) - { -#ifdef Q_OS_MACOS - const QString sys = "macOS"; -#else - const QString sys = "Windows"; -#endif - - return QStringLiteral("https://www.ausweisapp.bund.de/ausweisapp2/help/1.16/%1/%2/index.html").arg(pLang, sys); - } - - - QString toUrl(const char* pStr) - { - return QUrl::fromLocalFile(helpDir.path()).toString() + QString::fromLatin1(pStr); - } - - private Q_SLOTS: - void init() - { - QCoreApplication::setApplicationVersion(QStringLiteral("1.16")); - QVERIFY(!helpDir.exists()); - } - - - void initTestCase() - { - TestFileHelper::createTranslations(mTranslationDir.path()); - LanguageLoader::getInstance().setPath(mTranslationDir.path()); - } - - - void cleanup() - { - QVERIFY(helpDir.removeRecursively()); - if (LanguageLoader::getInstance().isLoaded()) - { - LanguageLoader::getInstance().unload(); - } - } - - - void escapedMapping() - { - QVERIFY(helpDir.mkpath(helpDir.path())); - - QVERIFY(helpDir.mkdir("de")); - loadLanguage(QLocale::German); - - QString padding; - if (QSysInfo::prettyProductName().startsWith(QLatin1String("Windows"))) - { - padding = '/'; - } - - QCOMPARE(HelpAction::getInstance().getHelpUrl("provider"), "file://" + padding + helpDir.path() + "/de/provider.html"); - } - - - void nonExistingHelpDir() - { - QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toWebUrl()); - - loadLanguage(QLocale::English); - QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toWebUrl()); - - loadLanguage(QLocale::German); - QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toWebUrl("de")); - - loadLanguage(QLocale::Italian); - QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toWebUrl("it")); - } - - - void existingHelpDir() - { - QVERIFY(helpDir.mkpath(helpDir.path())); - - QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toWebUrl()); - - loadLanguage(QLocale::English); - QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toWebUrl()); - - loadLanguage(QLocale::German); - QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toWebUrl("de")); - - loadLanguage(QLocale::Italian); - QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toWebUrl("it")); - } - - - void existingLanguageHelpDir() - { - QVERIFY(helpDir.mkpath(helpDir.path())); - - QVERIFY(helpDir.mkdir("en")); - QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toUrl("/en/index.html")); - - QVERIFY(helpDir.mkdir("de")); - QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toUrl("/en/index.html")); - - loadLanguage(QLocale::German); - QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toUrl("/de/index.html")); - - loadLanguage(QLocale::Italian); - QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toUrl("/en/index.html")); - - LanguageLoader::getInstance().unload(); - QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toUrl("/en/index.html")); - } - - - void contextMap() - { - QCOMPARE(HelpAction::getInstance().getContextMapping(""), QString("index.html")); - - QCOMPARE(HelpAction::getInstance().getContextMapping("pinManagement"), QString("pin-management.html")); - QCOMPARE(HelpAction::getInstance().getContextMapping("unknown"), QString("index.html")); - } - - -}; - -QTEST_GUILESS_MAIN(test_HelpAction) -#include "test_HelpAction.moc" diff --git a/test/qt/ui/qml/test_HistoryModel.cpp b/test/qt/ui/qml/test_HistoryModel.cpp deleted file mode 100644 index 1372808c1..000000000 --- a/test/qt/ui/qml/test_HistoryModel.cpp +++ /dev/null @@ -1,231 +0,0 @@ -/** - * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany - */ - -/*! - * \brief Unit tests for \ref HistoryModel - */ - -#include "HistoryModel.h" - -#include "AppSettings.h" -#include "Env.h" -#include "ProviderConfiguration.h" - -#include -#include - - -using namespace governikus; - -Q_DECLARE_METATYPE(HistoryModel::HistoryRoles) - -class test_HistoryModel - : public QObject -{ - Q_OBJECT - QSharedPointer mModel; - - static ProviderConfigurationInfo createProviderInfo(const QStringList& subjectUrls) - { - if (subjectUrls.isEmpty()) - { - return ProviderConfigurationInfo(); - } - return ProviderConfigurationInfo( - /* short name */ QStringLiteral("Provider 1"), - /* long name */ QStringLiteral("Provider 1 - long name"), - /* long description */ QStringLiteral("Provider description long"), - /* address */ QStringLiteral("https://www.homepage.com/"), - /* homepage */ QStringLiteral("https://www.homepage.com/"), - /* category */ QStringLiteral("CategoryA"), - /* phone */ QStringLiteral("0421 123456"), - /* email */ QStringLiteral("abc@def.de"), - /* postal address */ QStringLiteral("Am Fallturm 9\n28359 Bremen"), - /* icon */ QString(), - /* image */ QString(), - /* subjectUrls */ subjectUrls); - } - - - static QVector setTestProviders(int size) - { - - QStringList subjectUrls1({QStringLiteral("https://test.test/"), QStringLiteral("https://abc.abc/"), QStringLiteral("abc.abc")}); - QStringList subjectUrls2({QStringLiteral("abc.abc")}); - QStringList subjectUrls3({QStringLiteral("https://www.autentapp.de/bla1"), QStringLiteral("https://www.autentapp.de/bla1")}); - - auto& infos = Env::getSingleton()->mProviderConfigurationInfos; - infos.clear(); - - switch (size) - { - case 1: - infos.append(createProviderInfo(subjectUrls1)); - break; - - case 3: - infos.append(createProviderInfo(subjectUrls1)); - infos.append(createProviderInfo(subjectUrls2)); - infos.append(createProviderInfo(subjectUrls3)); - } - return infos; - } - - private Q_SLOTS: - void init() - { - mModel.reset(new HistoryModel()); - } - - - void cleanup() - { - mModel.clear(); - } - - - void test_updateConnections_data() - { - QTest::addColumn("entriesSize"); - QTest::addColumn("size"); - - QTest::newRow("empty") << 0 << 0; - QTest::newRow("2") << 2 << 4; - QTest::newRow("10") << 10 << 20; - } - - - void test_updateConnections() - { - QFETCH(int, entriesSize); - QFETCH(int, size); - - HistoryInfo info("SubjectName", "SubjectUrl", "Usage", QDateTime::currentDateTime(), "TermOfUsage", {"RequestedData"}); - QVector entries(entriesSize); - entries.fill(info); - - Env::getSingleton()->getHistorySettings().setHistoryInfos(entries); - - mModel->updateConnections(); - QCOMPARE(mModel->mConnections.size(), size); - } - - - void test_DeterminateProviderForEmptyProviderList() - { - HistoryInfo info("SubjectName", "SubjectUrl", "Usage", QDateTime::currentDateTime(), "TermOfUsage", {"RequestedData"}); - QCOMPARE(mModel->determineProviderFor(info), ProviderConfigurationInfo()); - } - - - void test_DeterminateProviderForProviderListSize1() - { - const auto providers = setTestProviders(1); - - HistoryInfo historyInfo1("SubjectName", "", "Usage", QDateTime::currentDateTime(), "TermOfUsage", {"RequestedData"}); - QCOMPARE(mModel->determineProviderFor(historyInfo1), ProviderConfigurationInfo()); - - HistoryInfo historyInfo2("SubjectName", QString("https://test.test/"), "Usage", QDateTime::currentDateTime(), "TermOfUsage", {"RequestedData"}); - QCOMPARE(mModel->determineProviderFor(historyInfo2), providers.at(0)); - } - - - void test_DeterminateProviderForProviderListSize3() - { - const auto providers = setTestProviders(3); - - HistoryInfo historyInfo1("SubjectName", QString("https://test/"), "Usage", QDateTime::currentDateTime(), "TermOfUsage", {"RequestedData"}); - HistoryInfo historyInfo2("SubjectName", QString("https://test.test/"), "Usage", QDateTime::currentDateTime(), "TermOfUsage", {"RequestedData"}); - HistoryInfo historyInfo3("SubjectName", QString("https://abc.abc/"), "Usage", QDateTime::currentDateTime(), "TermOfUsage", {"RequestedData"}); - HistoryInfo historyInfo4("SubjectName", QString("test.test"), "Usage", QDateTime::currentDateTime(), "TermOfUsage", {"RequestedData"}); - - QCOMPARE(mModel->determineProviderFor(historyInfo1), ProviderConfigurationInfo()); - QCOMPARE(mModel->determineProviderFor(historyInfo2), providers.at(0)); - QCOMPARE(mModel->determineProviderFor(historyInfo3), providers.at(0)); - QCOMPARE(mModel->determineProviderFor(historyInfo4), ProviderConfigurationInfo()); - } - - - void test_Data_data() - { - QTest::addColumn("role"); - QTest::addColumn("result"); - - QTest::newRow("subject") << HistoryModel::HistoryRoles::SUBJECT << "SubjectName"; - QTest::newRow("purpose") << HistoryModel::HistoryRoles::PURPOSE << "Usage"; - QTest::newRow("termOfUsage") << HistoryModel::HistoryRoles::TERMSOFUSAGE << "TermOfUsage"; - QTest::newRow("requestedData") << HistoryModel::HistoryRoles::REQUESTEDDATA << "Doctoral degree"; - QTest::newRow("writtenData") << HistoryModel::HistoryRoles::WRITTENDATA << "Address"; - QTest::newRow("providerCategory") << HistoryModel::HistoryRoles::PROVIDER_CATEGORY << "CategoryA"; - QTest::newRow("providerShortname") << HistoryModel::HistoryRoles::PROVIDER_SHORTNAME << "Provider 1"; - QTest::newRow("providerLongname") << HistoryModel::HistoryRoles::PROVIDER_LONGNAME << "Provider 1 - long name"; - QTest::newRow("providerLongdescription") << HistoryModel::HistoryRoles::PROVIDER_LONGDESCRIPTION << "Provider description long"; - QTest::newRow("providerAddress") << HistoryModel::HistoryRoles::PROVIDER_ADDRESS << "https://www.homepage.com/"; - QTest::newRow("providerAddressDomain") << HistoryModel::HistoryRoles::PROVIDER_ADDRESS_DOMAIN << "www.homepage.com"; - QTest::newRow("providerHomepage") << HistoryModel::HistoryRoles::PROVIDER_HOMEPAGE << "https://www.homepage.com/"; - QTest::newRow("providerHomepageBase") << HistoryModel::HistoryRoles::PROVIDER_HOMEPAGE_BASE << "www.homepage.com"; - QTest::newRow("providerPhone") << HistoryModel::HistoryRoles::PROVIDER_PHONE << "0421 123456"; - QTest::newRow("providerPhoneCost") << HistoryModel::HistoryRoles::PROVIDER_PHONE_COST << QString(); - QTest::newRow("providerPostalAddress") << HistoryModel::HistoryRoles::PROVIDER_POSTALADDRESS << "Am Fallturm 9\n28359 Bremen"; - } - - - void test_Data() - { - QFETCH(HistoryModel::HistoryRoles, role); - QFETCH(QString, result); - - HistoryInfo historyInfo("SubjectName", "https://test.test/", "Usage", QDateTime::currentDateTime(), "TermOfUsage", {"DoctoralDegree", "WriteAddress"}); - QVector infos = {historyInfo}; - - setTestProviders(1); - - Env::getSingleton()->getHistorySettings().setHistoryInfos(infos); - QModelIndex index = mModel->createIndex(0, 0); - - QCOMPARE(mModel->data(index, role).toString(), result); - } - - - void test_RemoveRows_data() - { - QTest::addColumn("oldSize"); - QTest::addColumn("row"); - QTest::addColumn("count"); - QTest::addColumn("newSize"); - - QTest::newRow("size5") << 5 << 0 << 5 << 0; - QTest::newRow("size10") << 10 << 1 << 3 << 7; - QTest::newRow("size15") << 15 << 8 << 0 << 15; - } - - - void test_RemoveRows() - { - QFETCH(int, oldSize); - QFETCH(int, row); - QFETCH(int, count); - QFETCH(int, newSize); - - HistoryInfo historyInfo("SubjectName", "https://www.autentapp.de/bla1", "Usage", QDateTime::currentDateTime(), "TermOfUsage", {"RequestedData"}); - QVector infos(oldSize); - infos.fill(historyInfo); - - QSignalSpy spyRemove(mModel.data(), &HistoryModel::rowsAboutToBeRemoved); - - Env::getSingleton()->getHistorySettings().setHistoryInfos(infos); - if (mModel->removeRows(row, count)) - { - QCOMPARE(Env::getSingleton()->getHistorySettings().getHistoryInfos().size(), newSize); - QList argumentsRemove = spyRemove.takeFirst(); - QCOMPARE(argumentsRemove.at(1).toInt(), row); - QCOMPARE(argumentsRemove.at(2).toInt(), row + count - 1); - } - } - - -}; - -QTEST_GUILESS_MAIN(test_HistoryModel) -#include "test_HistoryModel.moc" diff --git a/test/qt/ui/qml/test_NumberModel.cpp b/test/qt/ui/qml/test_NumberModel.cpp index cfb3f0f8d..fa3333d25 100644 --- a/test/qt/ui/qml/test_NumberModel.cpp +++ b/test/qt/ui/qml/test_NumberModel.cpp @@ -167,24 +167,57 @@ class test_NumberModel void test_NewPin() { - const QSharedPointer context(new TestWorkflowContext()); const QSharedPointer changePinContext(new ChangePinContext()); - const QSharedPointer remoteServiceContext(new IfdServiceContext(QSharedPointer(new RemoteIfdServer()))); const QString pin = QStringLiteral("111111"); - mModel->resetContext(context); mModel->setNewPin(pin); QCOMPARE(mModel->getNewPin(), QString()); mModel->resetContext(changePinContext); + QCOMPARE(mModel->getNewPin(), QString()); mModel->setNewPin(pin); - QCOMPARE(changePinContext->getNewPin(), pin); QCOMPARE(mModel->getNewPin(), pin); + QCOMPARE(changePinContext->getNewPin(), QString()); + } - mModel->resetContext(remoteServiceContext); - mModel->setNewPin(pin); - QCOMPARE(remoteServiceContext->getNewPin(), pin); - QCOMPARE(mModel->getNewPin(), QString()); + + void test_NewPinConfirmation_data() + { + QTest::addColumn("newPin"); + QTest::addColumn("newPinConfirmation"); + + QTest::newRow("Mismatch") << QStringLiteral("111111") << QStringLiteral("222222"); + QTest::newRow("Match") << QStringLiteral("111111") << QStringLiteral("111111"); + + } + + + void test_NewPinConfirmation() + { + QFETCH(QString, newPin); + QFETCH(QString, newPinConfirmation); + const bool pinConfirmed = newPin == newPinConfirmation; + + const QSharedPointer changePinContext(new ChangePinContext()); + QSignalSpy inputErrorSpy(mModel, &NumberModel::fireInputErrorChanged); + + mModel->resetContext(changePinContext); + mModel->setNewPin(newPin); + mModel->setNewPinConfirmation(newPinConfirmation); + + QCOMPARE(mModel->getNewPin(), newPin); + QCOMPARE(mModel->getNewPinConfirmation(), newPinConfirmation); + + QCOMPARE(mModel->commitNewPin(), pinConfirmed); + + if (pinConfirmed) + { + QCOMPARE(changePinContext->getNewPin(), newPin); + } + else + { + QCOMPARE(inputErrorSpy.count(), 2); + } } @@ -283,30 +316,21 @@ class test_NumberModel QCOMPARE(mModel->getInputError(), QStringLiteral("%1 %3.").arg( tr("A protocol error occurred. Please make sure that your ID card is placed correctly on the card reader and try again. If the problem occurs again, please contact our support at"), LanguageLoader::getLocaleCode(), - tr("AusweisApp2 Support"))); + tr("%1 Support").arg(QCoreApplication::applicationName()))); context.reset(new ChangePinContext(true)); mModel->resetContext(context); context->setCardConnection(connection); context->setLastPaceResult(CardReturnCode::INVALID_PIN); QCOMPARE(mModel->getInputError(), tr("You have entered an incorrect, five-digit Transport PIN. " - "You have two further attempts to enter the correct Transport PIN." - "

    " - "Please note that you may use the five-digit Transport PIN only once to change to a six-digit ID card PIN. " - "If you already set a six-digit ID card PIN, the five-digit Transport PIN is no longer valid.")); + "You have two further attempts to enter the correct Transport PIN.")); context->setLastPaceResult(CardReturnCode::INVALID_PIN_2); QCOMPARE(mModel->getInputError(), tr("You have entered an incorrect, five-digit Transport PIN twice. " "For a third attempt, the six-digit Card Access Number (CAN) must be entered first. " - "You can find your CAN in the bottom right on the front of your ID card." - "

    " - "Please note that you may use the five-digit Transport PIN only once to change to a six-digit ID card PIN. " - "If you already set a six-digit ID card PIN, the five-digit Transport PIN is no longer valid.")); + "You can find your CAN in the bottom right on the front of your ID card.")); context->setLastPaceResult(CardReturnCode::INVALID_PIN_3); QCOMPARE(mModel->getInputError(), tr("You have entered an incorrect, five-digit Transport PIN thrice, your Transport PIN is now blocked. " - "To remove the block, the ten-digit PUK must be entered first." - "

    " - "Please note that you may use the five-digit Transport PIN only once to change to a six-digit ID card PIN. " - "If you already set a six-digit ID card PIN, the five-digit Transport PIN is no longer valid.")); + "To remove the block, the ten-digit PUK must be entered first.")); connectionThread.quit(); connectionThread.wait(); @@ -404,13 +428,21 @@ class test_NumberModel void test_GetPasswordTypeNewPin() { const QSharedPointer context(new ChangePinContext()); + const QString pin = QStringLiteral("123456"); + mModel->resetContext(context); context->setEstablishPaceChannelType(PacePasswordId::PACE_PIN); QCOMPARE(mModel->getPasswordType(), PasswordType::PIN); - context->setPin(QStringLiteral("123456")); + context->setPin(pin); QCOMPARE(mModel->getPasswordType(), PasswordType::NEW_PIN); + + mModel->setNewPin(pin); + QCOMPARE(mModel->getPasswordType(), PasswordType::NEW_PIN_CONFIRMATION); + + mModel->setNewPinConfirmation(pin); + QCOMPARE(mModel->getPasswordType(), PasswordType::NEW_PIN_CONFIRMATION); } @@ -425,6 +457,8 @@ class test_NumberModel QVERIFY(personalizationContext); personalizationContext->setSessionIdentifier(QUuid::createUuid()); QCOMPARE(mModel->getPasswordType(), PasswordType::NEW_SMART_PIN); + mModel->setNewPin(QStringLiteral("123456")); + QCOMPARE(mModel->getPasswordType(), PasswordType::NEW_SMART_PIN_CONFIRMATION); #endif } diff --git a/test/qt/ui/qml/test_ProviderCategoryFilterModel.cpp b/test/qt/ui/qml/test_ProviderCategoryFilterModel.cpp deleted file mode 100644 index 8b13be3c4..000000000 --- a/test/qt/ui/qml/test_ProviderCategoryFilterModel.cpp +++ /dev/null @@ -1,214 +0,0 @@ -/** - * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany - */ - -/*! - * \brief Unit tests for \ref ProviderCategoryFilterModel - */ - -#include "ProviderCategoryFilterModel.h" - -#include - -using namespace governikus; - -class MockProviderModel - : public QAbstractListModel -{ - Q_OBJECT - QMap mData; - - public: - explicit MockProviderModel() - : mData() - { - } - - - [[nodiscard]] int rowCount(const QModelIndex& parent) const override - { - Q_UNUSED(parent) - return 1; - } - - - [[nodiscard]] QVariant data(const QModelIndex& index, int role) const override - { - Q_UNUSED(index) - return mData.value(role); - } - - - [[nodiscard]] QModelIndex index(int row, int column, const QModelIndex& parent) const override - { - Q_UNUSED(parent) - QModelIndex index = createIndex(row, column); - return index; - } - - - [[nodiscard]] QModelIndex parent(const QModelIndex& pIndex) const override - { - return pIndex.parent(); - } - - - [[nodiscard]] int columnCount(const QModelIndex& parent) const override - { - Q_UNUSED(parent) - return 1; - } - - - void addData(int pRole, const QVariant& pValue) - { - mData.insert(pRole, pValue); - } - - -}; - - -class test_ProviderCategoryFilterModel - : public QObject -{ - Q_OBJECT - QSharedPointer mModel; - - private Q_SLOTS: - void init() - { - mModel.reset(new ProviderCategoryFilterModel()); - } - - - void cleanup() - { - mModel.reset(); - } - - - void test_UpdateSearchString() - { - QSignalSpy spy(mModel.data(), &ProviderCategoryFilterModel::fireCriteriaChanged); - const QString search = QStringLiteral("search"); - - mModel->updateSearchString(search); - QCOMPARE(mModel->getSearchString(), search); - QCOMPARE(spy.count(), 1); - } - - - void test_CategorySelection() - { - QSignalSpy spy(mModel.data(), &ProviderCategoryFilterModel::fireCriteriaChanged); - const QString category1 = QStringLiteral("CATEGORY"); - const QString category2 = QStringLiteral("testCATEGORY"); - - mModel->setCategorySelection(QString()); - QVERIFY(mModel->mSelectedCategories.isEmpty()); - QCOMPARE(spy.count(), 1); - - mModel->setCategorySelection(category1); - QVERIFY(mModel->mSelectedCategories.contains("category")); - QCOMPARE(spy.count(), 2); - - mModel->updateCategorySelection(category2, true); - QVERIFY(mModel->mSelectedCategories.contains("testcategory")); - QCOMPARE(spy.count(), 3); - - mModel->updateCategorySelection(category2, true); - QVERIFY(mModel->mSelectedCategories.contains("testcategory")); - QCOMPARE(spy.count(), 3); - - mModel->updateCategorySelection(category1, false); - QVERIFY(mModel->mSelectedCategories.contains("testcategory")); - QVERIFY(!mModel->mSelectedCategories.contains("category")); - QCOMPARE(spy.count(), 4); - } - - - void test_SortByCategoryFirst() - { - mModel->sortByCategoryFirst(true); - QCOMPARE(mModel->sortRole(), ProviderModel::SORT_ROLE); - - mModel->sortByCategoryFirst(false); - QCOMPARE(mModel->sortRole(), ProviderModel::SHORTNAME); - } - - - void test_AddAdditionalResultCategories() - { - QSignalSpy spy(mModel.data(), &ProviderCategoryFilterModel::fireCriteriaChanged); - - mModel->addAdditionalResultCategories(); - QVERIFY(mModel->getSelectedCategories().isEmpty()); - QCOMPARE(spy.count(), 0); - - const QString category("citizen"); - const QString selected("other"); - const QString searchString("provider1"); - mModel->setCategorySelection(selected); - mModel->updateSearchString(searchString); - MockProviderModel model; - model.addData(Qt::DisplayRole, searchString); - model.addData(ProviderModel::CATEGORY, category); - mModel->setSourceModel(&model); - - mModel->addAdditionalResultCategories(); - QVERIFY(mModel->getSelectedCategories().contains(category)); - QCOMPARE(spy.count(), 3); - } - - - void test_ResultCountForFilter() - { - const QStringList categories({"citizen"}); - const QString selected("other"); - const QString searchString("provider1"); - - QCOMPARE(mModel->resultCountForFilter(categories, searchString), 0); - - mModel->setCategorySelection(selected); - mModel->updateSearchString(searchString); - MockProviderModel model; - model.addData(Qt::DisplayRole, searchString); - model.addData(ProviderModel::CATEGORY, "citizen"); - mModel->setSourceModel(&model); - QCOMPARE(mModel->resultCountForFilter(categories, searchString), 1); - - const QStringList unknownCategories({"test category"}); - QCOMPARE(mModel->resultCountForFilter(unknownCategories, searchString), 0); - } - - - void test_FilterAcceptsRow() - { - QVERIFY(mModel->filterAcceptsRow(0, QModelIndex())); - - const QString all("all"); - mModel->setCategorySelection(all); - QVERIFY(mModel->filterAcceptsRow(0, QModelIndex())); - - const QString citizen("citizen"); - mModel->setCategorySelection(citizen); - MockProviderModel model; - model.addData(ProviderModel::CATEGORY, citizen); - mModel->setSourceModel(&model); - QVERIFY(mModel->filterAcceptsRow(0, QModelIndex())); - - const QString unknownCategory("test category"); - mModel->setCategorySelection(unknownCategory); - QVERIFY(!mModel->filterAcceptsRow(0, QModelIndex())); - - const QString searchString("search"); - mModel->updateSearchString(searchString); - QVERIFY(!mModel->filterAcceptsRow(0, QModelIndex())); - } - - -}; - -QTEST_GUILESS_MAIN(test_ProviderCategoryFilterModel) -#include "test_ProviderCategoryFilterModel.moc" diff --git a/test/qt/ui/qml/test_ProviderModel.cpp b/test/qt/ui/qml/test_ProviderModel.cpp deleted file mode 100644 index bd139c358..000000000 --- a/test/qt/ui/qml/test_ProviderModel.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/** - * Copyright (c) 2016-2023 Governikus GmbH & Co. KG, Germany - */ - -/*! - * \brief Unit tests for \ref ProviderModel - */ - -#include "ProviderModel.h" - -#include -#include - - -using namespace governikus; - - -class test_ProviderModel - : public QObject -{ - Q_OBJECT - - private Q_SLOTS: - void createCostStringNullCost() - { - const auto& msg = ProviderModel::createCostString(CallCost()); - QVERIFY(msg.isNull()); - } - - - void createCostString_data() - { - QTest::addColumn("freeSeconds"); - QTest::addColumn("lLineCentsPMin"); - QTest::addColumn("lLineCentsPCall"); - QTest::addColumn("mobCentsPMin"); - QTest::addColumn("mobCentsPCall"); - QTest::addColumn("msg"); - - const QString msg1 = QStringLiteral("10 seconds free, afterwards landline costs 0.5 ct/min; mobile costs may vary."); - const QString msg2 = QStringLiteral("landline costs 20 ct/call; mobile costs may vary."); - const QString msg3 = QStringLiteral("landline costs 15 ct/min; mobile costs 25 ct/min"); - const QString msg4 = QStringLiteral("20 seconds free, afterwards landline costs 15 ct/min; mobile costs 1.01 EUR/call"); - const QString msg5 = QStringLiteral("60 seconds free, afterwards landline costs 2 EUR/call; mobile costs 55 ct/call"); - - QTest::newRow("landlineProMin") << 10 << 0.5 << 2.4 << 0.0 << 0.0 << msg1; - QTest::newRow("landlineProCall") << 0 << 0.0 << 20.0 << 0.0 << 0.0 << msg2; - QTest::newRow("landlineAndMobProMin") << 0 << 15.0 << 30.0 << 25.0 << 0.0 << msg3; - QTest::newRow("landlineProMinMobProCall") << 20 << 15.0 << 30.0 << 0.0 << 101.0 << msg4; - QTest::newRow("landlineAndMobProCall") << 60 << 0.0 << 200.0 << 0.0 << 55.0 << msg5; - } - - - void createCostString() - { - QFETCH(int, freeSeconds); - QFETCH(double, lLineCentsPMin); - QFETCH(double, lLineCentsPCall); - QFETCH(double, mobCentsPMin); - QFETCH(double, mobCentsPCall); - QFETCH(QString, msg); - - const CallCost cost(freeSeconds, lLineCentsPMin, lLineCentsPCall, mobCentsPMin, mobCentsPCall); - QCOMPARE(ProviderModel::createCostString(cost), msg); - } - - -}; - -QTEST_GUILESS_MAIN(test_ProviderModel) -#include "test_ProviderModel.moc" diff --git a/test/qt/ui/qml/test_ProviderNameFilterModel.cpp b/test/qt/ui/qml/test_ProviderNameFilterModel.cpp deleted file mode 100644 index 013f8e24d..000000000 --- a/test/qt/ui/qml/test_ProviderNameFilterModel.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/** - * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany - */ - -/*! - * \brief Unit tests for \ref ProviderNameFilterModel - */ - -#include "ProviderNameFilterModel.h" - -#include "AppSettings.h" -#include "HistoryModel.h" -#include "ProviderConfiguration.h" -#include "ResourceLoader.h" -#include "VolatileSettings.h" - -#include - - -using namespace governikus; - - -class test_ProviderNameFilterModel - : public QObject -{ - Q_OBJECT - QSharedPointer mModel; - - private Q_SLOTS: - void initTestCase() - { - ResourceLoader::getInstance().init(); - } - - - void init() - { - mModel.reset(new ProviderNameFilterModel()); - } - - - void cleanup() - { - mModel.clear(); - } - - - void test_FilterAcceptsRow() - { - SDK_MODE(false); - QVERIFY(!mModel->filterAcceptsRow(0, QModelIndex())); - - HistoryModel model; - mModel->setSourceModel(&model); - - HistoryInfo historyInfo1("SubjectName", QString("https://www.ausweisapp.bund.de/aa2/download"), "Usage", QDateTime::currentDateTime(), "TermOfUsage", {"RequestedData"}); - HistoryInfo historyInfo2("SubjectName", QString("https://test.de"), "Usage", QDateTime::currentDateTime(), "TermOfUsage", {"RequestedData"}); - Env::getSingleton()->getHistorySettings().addHistoryInfo(historyInfo1); - Env::getSingleton()->getHistorySettings().addHistoryInfo(historyInfo2); - const QString providerAddress("https://www.ausweisapp.bund.de/aa2/download"); - mModel->setProviderAddress(providerAddress); - - QVERIFY(!mModel->filterAcceptsRow(0, QModelIndex())); - QVERIFY(mModel->filterAcceptsRow(1, QModelIndex())); - } - - - void test_SetProviderAddress() - { - const QString invalidProviderAddress("https://test.de/"); - QTest::ignoreMessage(QtWarningMsg, "Cannot select provider with address \"https://test.de/\""); - mModel->setProviderAddress(invalidProviderAddress); - QCOMPARE(mModel->mProvider.getAddress(), QString()); - - const QString validProviderAddress("https://www.ausweisapp.bund.de/aa2/download"); - mModel->setProviderAddress(validProviderAddress); - QCOMPARE(mModel->mProvider.getAddress(), validProviderAddress); - } - - -}; - -QTEST_GUILESS_MAIN(test_ProviderNameFilterModel) -#include "test_ProviderNameFilterModel.moc" diff --git a/test/qt/ui/qml/test_QmlFileStructure.cpp b/test/qt/ui/qml/test_QmlFileStructure.cpp index 76ebb616d..ea39fd3ec 100644 --- a/test/qt/ui/qml/test_QmlFileStructure.cpp +++ b/test/qt/ui/qml/test_QmlFileStructure.cpp @@ -61,45 +61,6 @@ class test_QmlFileStructure } - void avoidMultipleDeviceFiles_data() - { - QTest::addColumn("qmlFile"); - - for (const QString& file : std::as_const(mQmlFiles)) - { - if (file.contains(QLatin1String("+phone")) || file.contains(QLatin1String("+tablet"))) - { - const QFileInfo info(file); - QTest::newRow(info.fileName().toLatin1().data()) << info; - } - } - } - - - void avoidMultipleDeviceFiles() - { - QFETCH(QFileInfo, qmlFile); - - QDir dir = qmlFile.dir(); - const auto& device = dir.dirName(); - dir.cdUp(); - - const auto& parentFolder = dir.dirName(); - if (parentFolder == QLatin1String("+android") || parentFolder == QLatin1String("+ios")) - { - dir.cdUp(); - dir.cd(device); - const QString fileInParentFolder = dir.path() + QDir::separator() + qmlFile.fileName(); - QVERIFY(!mQmlFiles.contains(fileInParentFolder)); - return; - } - - const QString file = QDir::separator() + device + QDir::separator() + qmlFile.fileName(); - QVERIFY(!mQmlFiles.contains(dir.path() + QDir::separator() + QStringLiteral("+android") + file)); - QVERIFY(!mQmlFiles.contains(dir.path() + QDir::separator() + QStringLiteral("+ios") + file)); - } - - }; QTEST_GUILESS_MAIN(test_QmlFileStructure) diff --git a/test/qt/ui/qml/test_ReaderScanEnabler.cpp b/test/qt/ui/qml/test_ReaderScanEnabler.cpp index 965280c35..01ee1a08e 100644 --- a/test/qt/ui/qml/test_ReaderScanEnabler.cpp +++ b/test/qt/ui/qml/test_ReaderScanEnabler.cpp @@ -25,18 +25,22 @@ class test_ReaderScanEnabler { Q_OBJECT - QSharedPointer mEnabler; + QScopedPointer mParent; + QPointer mEnabler; private Q_SLOTS: void init() { const auto readerManager = Env::getSingleton(); + QSignalSpy spy(readerManager, &ReaderManager::fireInitialized); readerManager->init(); - readerManager->isScanRunning(); // just to wait until initialization finished + QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations + + mParent.reset(new QQuickItem()); auto& mockPlugin = MockReaderManagerPlugIn::getInstance(); mockPlugin.addReader(); - mEnabler.reset(new ReaderScanEnabler()); + mEnabler = new ReaderScanEnabler(mParent.data()); mEnabler->setPlugInType(mockPlugin.getInfo().getPlugInType()); mEnabler->setVisible(false); QCoreApplication::processEvents(); // Make sure to process things from itemChange @@ -55,21 +59,21 @@ class test_ReaderScanEnabler const auto& pluginType = mEnabler->getPlugInType(); const auto* readerManager = Env::getSingleton(); - QCOMPARE(readerManager->isScanRunning(pluginType), false); + QCOMPARE(readerManager->getPlugInInfo(pluginType).isScanRunning(), false); mEnabler->enableScan(true); - QCOMPARE(readerManager->isScanRunning(pluginType), true); + QTRY_COMPARE(readerManager->getPlugInInfo(pluginType).isScanRunning(), true); QTRY_COMPARE(scanRunningChanged.size(), 1); mEnabler->enableScan(true); // Call a second time to ensure the state does not change - QCOMPARE(readerManager->isScanRunning(pluginType), true); + QCOMPARE(readerManager->getPlugInInfo(pluginType).isScanRunning(), true); QTRY_COMPARE(scanRunningChanged.size(), 1); mEnabler->enableScan(false); - QCOMPARE(readerManager->isScanRunning(pluginType), false); + QTRY_COMPARE(readerManager->getPlugInInfo(pluginType).isScanRunning(), false); QTRY_COMPARE(scanRunningChanged.size(), 2); mEnabler->enableScan(false); // Call a second time to ensure the state does not change - QCOMPARE(readerManager->isScanRunning(pluginType), false); + QCOMPARE(readerManager->getPlugInInfo(pluginType).isScanRunning(), false); QTRY_COMPARE(scanRunningChanged.size(), 2); } @@ -95,11 +99,13 @@ class test_ReaderScanEnabler initialScanState ? readerManager->startScan(pluginType) : readerManager->stopScan(pluginType); - QCOMPARE(readerManager->isScanRunning(pluginType), initialScanState); + QTRY_COMPARE(readerManager->getPlugInInfo(pluginType).isScanRunning(), initialScanState); mEnabler->setVisible(true); - QTRY_COMPARE(readerManager->isScanRunning(pluginType), true); + QVERIFY(mEnabler->isVisible()); + QTRY_COMPARE(readerManager->getPlugInInfo(pluginType).isScanRunning(), true); mEnabler->setVisible(false); - QTRY_COMPARE(readerManager->isScanRunning(pluginType), finalScanState); + QVERIFY(!mEnabler->isVisible()); + QTRY_COMPARE(readerManager->getPlugInInfo(pluginType).isScanRunning(), finalScanState); } @@ -122,11 +128,13 @@ class test_ReaderScanEnabler QFETCH(bool, finalScanState); Env::getSingleton()->resetContext(workflowContext); - QCOMPARE(readerManager->isScanRunning(pluginType), false); + QCOMPARE(readerManager->getPlugInInfo(pluginType).isScanRunning(), false); mEnabler->setVisible(true); - QTRY_COMPARE(readerManager->isScanRunning(pluginType), true); + QVERIFY(mEnabler->isVisible()); + QTRY_COMPARE(readerManager->getPlugInInfo(pluginType).isScanRunning(), true); mEnabler->setVisible(false); - QTRY_COMPARE(readerManager->isScanRunning(pluginType), finalScanState); + QVERIFY(!mEnabler->isVisible()); + QTRY_COMPARE(readerManager->getPlugInInfo(pluginType).isScanRunning(), finalScanState); } diff --git a/test/qt/ui/qml/test_RemoteServiceModel.cpp b/test/qt/ui/qml/test_RemoteServiceModel.cpp index c3673bed1..f06ab49b2 100644 --- a/test/qt/ui/qml/test_RemoteServiceModel.cpp +++ b/test/qt/ui/qml/test_RemoteServiceModel.cpp @@ -3,12 +3,13 @@ */ /*! - * \brief Unit tests for \ref ProviderModel + * \brief Unit tests for \ref RemoteServiceModel */ #include "RemoteServiceModel.h" #include "MockIfdServer.h" +#include "ReaderManager.h" #include "context/IfdServiceContext.h" #include @@ -50,6 +51,11 @@ class test_RemoteServiceModel void test_ReaderPlugInType() { + const auto readerManager = Env::getSingleton(); + QSignalSpy spy(readerManager, &ReaderManager::fireInitialized); + readerManager->init(); + QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations + const ReaderManagerPlugInType input1 = ReaderManagerPlugInType::NFC; const ReaderManagerPlugInType input2 = ReaderManagerPlugInType::UNKNOWN; @@ -106,16 +112,22 @@ class test_RemoteServiceModel void test_ResetContext() { QSignalSpy spyConnectedChanged(mModel, &RemoteServiceModel::fireConnectedChanged); + QSignalSpy spyWorkflowStarted(mModel, &WorkflowModel::fireWorkflowStarted); QSignalSpy spyCurrentStateChanged(mModel, &WorkflowModel::fireCurrentStateChanged); + QSignalSpy spyStateEntered(mModel, &WorkflowModel::fireStateEntered); QSignalSpy spyIsRunningChanged(mModel, &RemoteServiceModel::fireIsRunningChanged); QSignalSpy spyPskChanged(mModel, &RemoteServiceModel::firePskChanged); QSignalSpy spyConnectedClientDeviceNameChanged(mModel, &RemoteServiceModel::fireConnectionInfoChanged); mModel->resetRemoteServiceContext(mContext); + QCOMPARE(spyWorkflowStarted.count(), 1); QCOMPARE(spyCurrentStateChanged.count(), 1); + QCOMPARE(spyStateEntered.count(), 0); QCOMPARE(spyConnectedChanged.count(), 1); Q_EMIT mContext->fireStateChanged(QString()); + QCOMPARE(spyCurrentStateChanged.count(), 2); + QCOMPARE(spyStateEntered.count(), 1); QCOMPARE(spyIsRunningChanged.count(), 1); Q_EMIT mContext->getIfdServer()->firePskChanged(QByteArray()); @@ -140,13 +152,6 @@ class test_RemoteServiceModel } - void test_TransactionInfo() - { - mModel->resetRemoteServiceContext(mContext); - QCOMPARE(mModel->getTransactionInfo(), QString()); - } - - void test_getSupportedReaderPlugInTypes() { QVector supportedPlugIns {ReaderManagerPlugInType::NFC}; @@ -157,6 +162,13 @@ class test_RemoteServiceModel } + void test_TransactionInfo() + { + mModel->resetRemoteServiceContext(mContext); + QCOMPARE(mModel->getTransactionInfo(), QString()); + } + + void test_DisplayText_data() { QTest::addColumn("inputText"); diff --git a/test/qt/ui/qml/test_SelfAuthModel.cpp b/test/qt/ui/qml/test_SelfAuthModel.cpp index b9932a81c..fb00dc3a6 100644 --- a/test/qt/ui/qml/test_SelfAuthModel.cpp +++ b/test/qt/ui/qml/test_SelfAuthModel.cpp @@ -117,6 +117,18 @@ class test_SelfAuthModel } + void test_WorkflowCancelled() + { + QSignalSpy spy(mModel, &SelfAuthModel::fireCancelWorkflow); + + mModel->resetContext(mContext); + QCOMPARE(mModel->isWorkflowCancelled(), false); + mModel->cancelWorkflow(); + QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations + QCOMPARE(mModel->isWorkflowCancelled(), true); + } + + }; QTEST_GUILESS_MAIN(test_SelfAuthModel) diff --git a/test/qt/ui/qml/test_SortedReaderModel.cpp b/test/qt/ui/qml/test_SortedReaderModel.cpp index 4e609a31e..84cd915b5 100644 --- a/test/qt/ui/qml/test_SortedReaderModel.cpp +++ b/test/qt/ui/qml/test_SortedReaderModel.cpp @@ -46,7 +46,7 @@ MockReaderModel::MockReaderModel(const QVector& readers) int MockReaderModel::rowCount(const QModelIndex& parent) const { Q_UNUSED(parent) - return mReaders.count(); + return static_cast(mReaders.count()); } diff --git a/test/qt/ui/qml/test_UILoader.cpp b/test/qt/ui/qml/test_UILoader.cpp index f6ef6cda4..66e2f98da 100644 --- a/test/qt/ui/qml/test_UILoader.cpp +++ b/test/qt/ui/qml/test_UILoader.cpp @@ -38,12 +38,7 @@ class test_UILoader QVERIFY(!loader.getLoaded()); QCOMPARE(spyLoaded.count(), 0); -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) QTest::ignoreMessage(QtDebugMsg, "Shutdown UILoader: QList()"); -#else - QTest::ignoreMessage(QtDebugMsg, "Shutdown UILoader: ()"); -#endif - loader.shutdown(); } @@ -71,11 +66,7 @@ class test_UILoader QCOMPARE(ui->property("passive"), QVariant()); QCOMPARE(ui->property("readerManager"), QVariant()); -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) QTest::ignoreMessage(QtDebugMsg, R"(Shutdown UILoader: QList("websocket"))"); -#else - QTest::ignoreMessage(QtDebugMsg, R"(Shutdown UILoader: ("websocket"))"); -#endif } @@ -91,11 +82,7 @@ class test_UILoader QVERIFY(loader.getLoaded()); QCOMPARE(spyLoaded.count(), 1); -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) QTest::ignoreMessage(QtDebugMsg, R"(Shutdown UILoader: QList("websocket"))"); -#else - QTest::ignoreMessage(QtDebugMsg, R"(Shutdown UILoader: ("websocket"))"); -#endif } diff --git a/test/qt/ui/qml/test_UIPlugInQml.cpp b/test/qt/ui/qml/test_UIPlugInQml.cpp new file mode 100644 index 000000000..8f5aaa603 --- /dev/null +++ b/test/qt/ui/qml/test_UIPlugInQml.cpp @@ -0,0 +1,171 @@ +/** + * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany + */ + +#include "UIPlugInQml.h" + +#include "context/AuthContext.h" +#include "context/ChangePinContext.h" +#include "context/IfdServiceContext.h" +#include "context/SelfAuthContext.h" +#if __has_include("context/PersonalizationContext.h") + #include "PersonalizationModel.h" + #include "context/PersonalizationContext.h" +#endif +#include "AppSettings.h" +#include "ApplicationModel.h" +#include "AuthModel.h" +#include "CertificateDescriptionModel.h" +#include "ChangePinModel.h" +#include "ChatModel.h" +#include "MockIfdServer.h" +#include "NumberModel.h" +#include "RemoteServiceModel.h" +#include "ResourceLoader.h" +#include "SelfAuthModel.h" +#include "VolatileSettings.h" + +#include "TestWorkflowController.h" + +#include +#include + + +using namespace governikus; + +Q_DECLARE_METATYPE(QSharedPointer) + +class test_UIPlugInQml + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void test_onWorkflowChanged_data() + { + QTest::addColumn>("request"); + + QTest::newRow("AuthContext") << TestWorkflowController::createWorkflowRequest(); + QTest::newRow("SelfAuthContext") << TestWorkflowController::createWorkflowRequest(); + QTest::newRow("ChangePinContext") << TestWorkflowController::createWorkflowRequest(); + QTest::newRow("IfdServiceContext") << TestWorkflowController::createWorkflowRequest(QSharedPointer(new MockIfdServer())); +#if __has_include("context/PersonalizationContext.h") + QTest::newRow("PersonalizationContext") << TestWorkflowController::createWorkflowRequest(QString()); +#endif + } + + + void test_onWorkflowChanged() + { + QFETCH(QSharedPointer, request); + const auto& context = request->getContext(); + + const bool isAuth = !context.objectCast().isNull(); + const bool isSelfAuth = !context.objectCast().isNull(); + const bool isPinChange = !context.objectCast().isNull(); + const bool isIfdService = !context.objectCast().isNull(); +#if __has_include("context/PersonalizationContext.h") + const bool isPersonalization = !context.objectCast().isNull(); +#else + const bool isPersonalization = false; +#endif + + QCOMPARE(Env::getSingleton()->getDelay(), 0); + QVERIFY(!Env::getSingleton()->mContext); + QVERIFY(!Env::getSingleton()->mContext); + QVERIFY(!Env::getSingleton()->mContext); +#if __has_include("context/PersonalizationContext.h") + QVERIFY(!Env::getSingleton()->mContext); +#endif + QVERIFY(!Env::getSingleton()->mContext); + QVERIFY(!Env::getSingleton()->mContext); + QVERIFY(!Env::getSingleton()->mContext); + QVERIFY(!Env::getSingleton()->mContext); + QVERIFY(!Env::getSingleton()->mContext); + + UIPlugInQml plugin; + plugin.onWorkflowStarted(request); + QCOMPARE(Env::getSingleton()->getDelay(), 1000); + QVERIFY(Env::getSingleton()->mContext); + QVERIFY(Env::getSingleton()->mContext); + QCOMPARE(!Env::getSingleton()->mContext.isNull(), isPinChange); +#if __has_include("context/PersonalizationContext.h") + QCOMPARE(!Env::getSingleton()->mContext.isNull(), isPersonalization); +#endif + QCOMPARE(!Env::getSingleton()->mContext.isNull(), isAuth || isIfdService || isPersonalization); + QCOMPARE(!Env::getSingleton()->mContext.isNull(), isAuth || isIfdService || isPersonalization); + QCOMPARE(!Env::getSingleton()->mContext.isNull(), isAuth && !isPersonalization); + QCOMPARE(!Env::getSingleton()->mContext.isNull(), isSelfAuth); + QCOMPARE(!Env::getSingleton()->mContext.isNull(), isIfdService); + + plugin.onWorkflowFinished(request); + QCOMPARE(Env::getSingleton()->getDelay(), 0); + QVERIFY(!Env::getSingleton()->mContext); + QVERIFY(!Env::getSingleton()->mContext); + QVERIFY(!Env::getSingleton()->mContext); +#if __has_include("context/PersonalizationContext.h") + QVERIFY(!Env::getSingleton()->mContext); +#endif + QVERIFY(!Env::getSingleton()->mContext); + QVERIFY(!Env::getSingleton()->mContext); + QVERIFY(!Env::getSingleton()->mContext); + QVERIFY(!Env::getSingleton()->mContext); + QVERIFY(!Env::getSingleton()->mContext); + } + + + void test_useSystemFontChanged() + { + ResourceLoader::getInstance().init(); + UIPlugInQml plugin; + + auto& generalSettings = Env::getSingleton()->getGeneralSettings(); + QVERIFY(!generalSettings.isUseSystemFont()); + QTRY_VERIFY(QGuiApplication::font().family().contains(QStringLiteral("roboto"), Qt::CaseInsensitive)); + + generalSettings.setUseSystemFont(true); + //We call this manually, because the signal-connection is tied to an application window being present. + plugin.onUseSystemFontChanged(); + QTRY_VERIFY(!QGuiApplication::font().family().contains(QStringLiteral("roboto"), Qt::CaseInsensitive)); + ResourceLoader::getInstance().shutdown(); + } + + + void test_setFontScaleFactor() + { + UIPlugInQml plugin; + QSignalSpy spy(&plugin, &UIPlugInQml::fireFontScaleFactorChanged); + + const auto initialValue = plugin.getFontScaleFactor(); + + plugin.setFontScaleFactor(initialValue); + QTRY_COMPARE(spy.count(), 0); + + const auto newValue = 42; + plugin.setFontScaleFactor(newValue); + QTRY_COMPARE(spy.count(), 1); + QCOMPARE(plugin.getFontScaleFactor(), newValue); + } + + + void test_setDarkMode() + { + UIPlugInQml plugin; + QSignalSpy spy(&plugin, &UIPlugInQml::fireOsDarkModeChanged); + + const auto initialValue = plugin.isOsDarkModeEnabled(); + + plugin.setOsDarkMode(initialValue); + QTRY_COMPARE(spy.count(), 0); + + const auto newValue = !initialValue; + plugin.setOsDarkMode(newValue); + QTRY_COMPARE(spy.count(), 1); + QCOMPARE(plugin.isOsDarkModeEnabled(), newValue); + } + + +}; + +QTEST_MAIN(test_UIPlugInQml) +#include "test_UIPlugInQml.moc" diff --git a/test/qt/ui/qml/test_WorkflowModel.cpp b/test/qt/ui/qml/test_WorkflowModel.cpp index dfee3571a..7e78fa693 100644 --- a/test/qt/ui/qml/test_WorkflowModel.cpp +++ b/test/qt/ui/qml/test_WorkflowModel.cpp @@ -12,11 +12,14 @@ #include "MockCardConnectionWorker.h" #include "MockReaderManagerPlugIn.h" #include "ReaderManager.h" +#include "ResourceLoader.h" #include "TestWorkflowContext.h" #include +#include #include + Q_IMPORT_PLUGIN(MockReaderManagerPlugIn) using namespace governikus; @@ -28,26 +31,53 @@ class test_WorkflowModel Q_OBJECT private Q_SLOTS: + void initTestCase() + { + const auto readerManager = Env::getSingleton(); + QSignalSpy spy(readerManager, &ReaderManager::fireInitialized); + readerManager->init(); + QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations + + ResourceLoader::getInstance().init(); + } + + + void cleanupTestCase() + { + Env::getSingleton()->shutdown(); + } + + void test_ResetContext() { WorkflowModel model; QSharedPointer context(new TestWorkflowContext()); + QSignalSpy spyWorkflowStarted(&model, &WorkflowModel::fireWorkflowStarted); QSignalSpy spyCurrentStateChanged(&model, &WorkflowModel::fireCurrentStateChanged); + QSignalSpy spyStateEntered(&model, &WorkflowModel::fireStateEntered); QSignalSpy spyResultChanged(&model, &WorkflowModel::fireResultChanged); QSignalSpy spyReaderPlugInTypeChanged(&model, &WorkflowModel::fireReaderPlugInTypeChanged); QSignalSpy spySelectedReaderChanged(&model, &WorkflowModel::fireSelectedReaderChanged); + QSignalSpy spyWorkflowFinished(&model, &WorkflowModel::fireWorkflowFinished); model.resetWorkflowContext(); + QCOMPARE(spyWorkflowStarted.count(), 0); QCOMPARE(spyCurrentStateChanged.count(), 1); + QCOMPARE(spyStateEntered.count(), 0); QCOMPARE(spyResultChanged.count(), 1); + QCOMPARE(spyWorkflowFinished.count(), 1); model.resetWorkflowContext(context); + QCOMPARE(spyWorkflowStarted.count(), 1); QCOMPARE(spyCurrentStateChanged.count(), 2); + QCOMPARE(spyStateEntered.count(), 0); QCOMPARE(spyResultChanged.count(), 2); + QCOMPARE(spyWorkflowFinished.count(), 1); Q_EMIT context->fireStateChanged(QString("state")); QCOMPARE(spyCurrentStateChanged.count(), 3); + QCOMPARE(spyStateEntered.count(), 1); Q_EMIT context->fireResultChanged(); QCOMPARE(spyResultChanged.count(), 3); @@ -107,18 +137,15 @@ class test_WorkflowModel } - void test_isSmartCardAllowed() + void test_isCurrentSmartCardAllowed() { - QVERIFY(true); + WorkflowModel workflowModel; + QVERIFY2(!workflowModel.isCurrentSmartCardAllowed(), "Ensure that this will not crash when the model has no WorkflowContext."); } void test_startScanExplicitly() { - const auto readerManager = Env::getSingleton(); - readerManager->init(); - readerManager->isScanRunning(); // just to wait until initialization finished - QSharedPointer context(new TestWorkflowContext()); QSignalSpy spy(context.data(), &WorkflowContext::fireReaderPlugInTypesChanged); @@ -133,10 +160,6 @@ class test_WorkflowModel void test_hasCard() { - const auto readerManager = Env::getSingleton(); - readerManager->init(); - readerManager->isScanRunning(); // just to wait until initialization finished - WorkflowModel model; QCOMPARE(model.hasCard(), false); @@ -153,6 +176,56 @@ class test_WorkflowModel } + void test_statusCodeImage_data() + { + QTest::addColumn("statusCode"); + + QMetaEnum e = QMetaEnum::fromType(); + + for (int k = 0; k < e.keyCount(); k++) + { + QTest::addRow("%s", e.key(k)) << GlobalStatus::Code(e.value(k)); + } + } + + + void test_statusCodeImage() + { + QSharedPointer context(new TestWorkflowContext()); + QSignalSpy spy(context.data(), &WorkflowContext::fireReaderPlugInTypesChanged); + + QFETCH(GlobalStatus::Code, statusCode); + context->setStatus(statusCode); + + WorkflowModel model; + model.resetWorkflowContext(context); + + auto image = model.getStatusCodeImage(); + image = image.replace("qrc://", ":"); + if (image.isEmpty()) + { + return; + } + + if (image.contains("%1")) + { + QStringList themes; + themes << QStringLiteral("darkmode") << QStringLiteral("lightmode") << QStringLiteral("highcontrast"); + + for (const auto& theme : themes) + { + const auto fileName = image.arg(theme); + QVERIFY2(QFile(fileName).exists(), qPrintable(QString("%1 not found").arg(fileName))); + } + } + else + { + QVERIFY(QFile::exists(image)); + } + + } + + }; QTEST_MAIN(test_WorkflowModel) diff --git a/test/qt/ui/scheme/test_CustomSchemeActivationContext.cpp b/test/qt/ui/scheme/test_CustomSchemeActivationContext.cpp deleted file mode 100644 index 38f349b30..000000000 --- a/test/qt/ui/scheme/test_CustomSchemeActivationContext.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/** - * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany - */ - -/*! - * \brief Unit tests for \ref CustomSchemeActivationContext - */ - -#include "CustomSchemeActivationContext.h" - -#include -#include - - -using namespace governikus; - - -class test_CustomSchemeActivationContext - : public QObject -{ - Q_OBJECT - - private: - QUrl mReceivedUrl; - - private Q_SLOTS: - void onCustomUrl(const QUrl& pUrl) - { - mReceivedUrl = pUrl; - } - - - void test_GetActivationUrl() - { - const QUrl testUrl("http://localhost:24727/eID-Client?tctokenURL=bla"); - CustomSchemeActivationContext context(testUrl, QString("ref")); - QCOMPARE(context.getActivationURL(), testUrl); - } - - - void test_SendProcessing() - { - const QUrl testUrl("http://localhost:24727/eID-Client?tctokenURL=bla"); - CustomSchemeActivationContext context(testUrl, QString("ref")); - QVERIFY(context.sendProcessing()); - } - - - void test_SendActivationAlreadyActive() - { - const QUrl testUrl("http://localhost:24727/eID-Client?tctokenURL=bla"); - CustomSchemeActivationContext context(testUrl, QString("ref")); - - QSignalSpy spy(&context, &CustomSchemeActivationContext::fireShowUserInformation); - QVERIFY(context.sendOperationAlreadyActive()); - QCOMPARE(spy.count(), 1); - - QVERIFY(context.sendOperationAlreadyActive()); - QCOMPARE(spy.count(), 2); - } - - - void test_SendErrorPage() - { - const QUrl testUrl("http://localhost:24727/eID-Client?tctokenURL=bla"); - CustomSchemeActivationContext context(testUrl, QString("ref")); - QVERIFY(context.sendErrorPage(HTTP_STATUS_BAD_REQUEST, GlobalStatus::Code::Unknown_Error)); - } - - - void test_SendRedirect() - { - mReceivedUrl = QUrl(); - QDesktopServices::setUrlHandler(QStringLiteral("https"), this, "onCustomUrl"); - - { - const QUrl testUrl("http://localhost:24727/eID-Client?tctokenURL=bla"); - CustomSchemeActivationContext context(testUrl, QString("ref")); - - QTest::ignoreMessage(QtDebugMsg, "Determined redirect URL QUrl(\"https://www.example.com?ResultMajor=ok\")"); - QVERIFY(context.sendRedirect(QUrl("https://www.example.com"), GlobalStatus::Code::No_Error)); - } - - QCOMPARE(mReceivedUrl, QUrl("https://www.example.com?ResultMajor=ok")); - QDesktopServices::unsetUrlHandler(QStringLiteral("https")); - } - - -}; - -QTEST_GUILESS_MAIN(test_CustomSchemeActivationContext) -#include "test_CustomSchemeActivationContext.moc" diff --git a/test/qt/ui/scheme/test_UIPlugInScheme.cpp b/test/qt/ui/scheme/test_UIPlugInScheme.cpp index 8352f2973..0e3551c97 100644 --- a/test/qt/ui/scheme/test_UIPlugInScheme.cpp +++ b/test/qt/ui/scheme/test_UIPlugInScheme.cpp @@ -9,13 +9,11 @@ #include "UIPlugInScheme.h" #include "WorkflowRequest.h" -#include "context/ActivationContext.h" #include "context/AuthContext.h" #include #include - using namespace governikus; Q_DECLARE_METATYPE(QSharedPointer) @@ -25,6 +23,9 @@ class test_UIPlugInScheme { Q_OBJECT + private: + QUrl mReceivedUrl; + private Q_SLOTS: void authentication_data() { @@ -56,7 +57,7 @@ class test_UIPlugInScheme QCOMPARE(spy.count(), 1); const auto request = spy.at(0).at(0).value>(); - QCOMPARE(request->getContext().objectCast()->getActivationContext()->getActivationURL(), url); + QCOMPARE(request->getContext().objectCast()->getActivationUrl(), url); } @@ -167,6 +168,74 @@ class test_UIPlugInScheme } + void onCustomUrl() + { + UIPlugInScheme ui; + + QUrl url; + QSignalSpy spy(&ui, &UIPlugIn::fireWorkflowRequested); + connect(&ui, &UIPlugIn::fireWorkflowRequested, this, [&url](const QSharedPointer& pRequest){ + url = pRequest->getContext().objectCast()->getActivationUrl(); + }); + + QTest::ignoreMessage(QtDebugMsg, "Got new request"); + QTest::ignoreMessage(QtDebugMsg, "Request URL: QUrl(\"http://crap\")"); + QTest::ignoreMessage(QtDebugMsg, "Not our business. Using the appropriate mechanism for the user's desktop environment."); + ui.onCustomUrl(QUrl("http://crap")); + QCOMPARE(spy.count(), 0); + + const QUrl testUrl("http://localhost:24727/eID-Client?tcTokenURL=http://bla"); + QTest::ignoreMessage(QtDebugMsg, "Got new request"); + QTest::ignoreMessage(QtDebugMsg, "Request type: authentication"); + ui.onCustomUrl(testUrl); + QCOMPARE(spy.count(), 1); + QCOMPARE(url, testUrl); + + QSignalSpy spyShowUi(&ui, &UIPlugIn::fireShowUiRequested); + QTest::ignoreMessage(QtDebugMsg, "Got new request"); + QTest::ignoreMessage(QtDebugMsg, "Request type: showui"); + ui.onCustomUrl(QUrl("http://localhost:24727/eID-Client?showUi")); + QCOMPARE(spy.count(), 1); + QCOMPARE(spyShowUi.count(), 1); + } + + + void sendRedirectOnCustomUrl(const QUrl& pUrl) + { + mReceivedUrl = pUrl; + } + + + void sendRedirect() + { + UIPlugInScheme ui; + + QSharedPointer request; + QSignalSpy spy(&ui, &UIPlugIn::fireWorkflowRequested); + connect(&ui, &UIPlugIn::fireWorkflowRequested, this, [&request](const QSharedPointer& pRequest){ + request = pRequest; + }); + + QTest::ignoreMessage(QtDebugMsg, "Got new request"); + QTest::ignoreMessage(QtDebugMsg, "Request type: authentication"); + ui.onCustomUrl(QUrl("http://localhost:24727/eID-Client?tcTokenURL=https://bla")); + QVERIFY(request); + QVERIFY(request->getData().value()); + + auto authContext = request->getContext().objectCast(); + QVERIFY(authContext); + authContext->setRefreshUrl(QUrl("https://www.example.com")); + authContext->setStatus(GlobalStatus::Code::No_Error); + + QDesktopServices::setUrlHandler(QStringLiteral("https"), this, "sendRedirectOnCustomUrl"); + QTest::ignoreMessage(QtDebugMsg, "Determined redirect URL QUrl(\"https://www.example.com?ResultMajor=ok\")"); + ui.onWorkflowFinished(request); + + QTRY_COMPARE(mReceivedUrl, QUrl("https://www.example.com?ResultMajor=ok")); // clazy:exclude=qstring-allocations + QDesktopServices::unsetUrlHandler(QStringLiteral("https")); + } + + }; QTEST_GUILESS_MAIN(test_UIPlugInScheme) diff --git a/test/qt/ui/webservice/test_UIPlugInWebService.cpp b/test/qt/ui/webservice/test_UIPlugInWebService.cpp index 69d17b60d..733a8b022 100644 --- a/test/qt/ui/webservice/test_UIPlugInWebService.cpp +++ b/test/qt/ui/webservice/test_UIPlugInWebService.cpp @@ -9,14 +9,16 @@ #include "UIPlugInWebService.h" #include "HttpServerRequestor.h" +#include "MockNetworkManager.h" #include "ResourceLoader.h" +#include "VersionInfo.h" #include "WorkflowRequest.h" -#include "context/ActivationContext.h" -#include "context/AuthContext.h" +#include #include #include + using namespace governikus; @@ -36,7 +38,7 @@ class test_UIPlugInWebService QString getUserAgentVersion(const QString& pVersion) { - return QStringLiteral("%1/%2 (TR-03124-1/1.3)").arg(QCoreApplication::applicationName(), pVersion); + return QStringLiteral("%1/%2 (TR-03124-1/1.4)").arg(VersionInfo::getInstance().getImplementationTitle(), pVersion); } private Q_SLOTS: @@ -77,10 +79,11 @@ class test_UIPlugInWebService QTest::newRow("Settings") << QString("/eID-Client?ShowUI=SETTINGS") << UiModule::SETTINGS; QTest::newRow("Tutorial") << QString("/eID-Client?ShowUI=TUTORIAL") << UiModule::TUTORIAL; - QTest::newRow("History") << QString("/eID-Client?ShowUI=HISTORY") << UiModule::HISTORY; QTest::newRow("Help") << QString("/eID-Client?ShowUI=HELP") << UiModule::HELP; - QTest::newRow("Provider") << QString("/eID-Client?ShowUI=PROVIDER") << UiModule::PROVIDER; QTest::newRow("Self AUth") << QString("/eID-Client?ShowUI=SELF_AUTHENTICATION") << UiModule::SELF_AUTHENTICATION; + + QTest::newRow("SMART_EID") << QString("/eID-Client?ShowUI=SMART_EID") << UiModule::SMART_EID; + QTest::newRow("Smart-eID") << QString("/eID-Client?ShowUI=Smart-eID") << UiModule::SMART_EID; } @@ -146,7 +149,7 @@ class test_UIPlugInWebService QTest::addColumn("error"); QTest::newRow("favicon") << QString("/favicon.ico") << QString("image/x-icon") << 94921 << QNetworkReply::NoError; - QTest::newRow("logo") << QString("/images/html_templates/Logo_AusweisApp2.png") << QString("image/png") << 3291 << QNetworkReply::NoError; + QTest::newRow("smallicon") << QString("/images/html_templates/icon_attention.svg") << QString("image/svg+xml") << 957 << QNetworkReply::NoError; QTest::newRow("nothing") << QString("/images/html_templates/nothing.gif") << QString() << 0 << QNetworkReply::ContentNotFoundError; } @@ -170,14 +173,36 @@ class test_UIPlugInWebService void authentication() + { + connect(mUi.data(), &UIPlugIn::fireWorkflowRequested, mUi.data(), &UIPlugIn::onWorkflowStarted); // fake AppController + + QTest::ignoreMessage(QtDebugMsg, "Request type: authentication"); + HttpServerRequestor requestor; + QSharedPointer reply = requestor.getRequest(getUrl("/eID-Client?tctokenURL=bla")); + QVERIFY(reply); + QCOMPARE(reply->error(), QNetworkReply::NoError); + + QCOMPARE(mShowUiSpy->count(), 0); + QCOMPARE(mShowUserInfoSpy->count(), 0); + QCOMPARE(mAuthenticationSpy->count(), 1); + } + + + void authenticationConnectionLost() { QTest::ignoreMessage(QtDebugMsg, "Request type: authentication"); - connect(mUi.data(), &UIPlugIn::fireWorkflowRequested, this, [](const QSharedPointer& pRequest) + connect(mUi.data(), &UIPlugIn::fireWorkflowRequested, this, [this](const QSharedPointer& pRequest) { - pRequest->getContext().objectCast()->getActivationContext()->sendProcessing(); + const auto request = pRequest->getData().value>(); + request->send(HTTP_STATUS_NO_CONTENT); // send something to avoid retry of Qt + auto* socket = request->take(); + socket->close(); + socket->deleteLater(); + mUi->onWorkflowStarted(pRequest); }); + QTest::ignoreMessage(QtCriticalMsg, "Cannot send 'Processing' to caller as connection is lost"); HttpServerRequestor requestor; QSharedPointer reply = requestor.getRequest(getUrl("/eID-Client?tctokenURL=bla")); QVERIFY(reply); @@ -189,6 +214,22 @@ class test_UIPlugInWebService } + void authenticationAlreadyActive() + { + connect(mUi.data(), &UIPlugIn::fireWorkflowRequested, mUi.data(), &UIPlugIn::onWorkflowUnhandled); + + QTest::ignoreMessage(QtDebugMsg, "Request type: authentication"); + HttpServerRequestor requestor; + QSharedPointer reply = requestor.getRequest(getUrl("/eID-Client?tctokenURL=bla")); + QVERIFY(reply); + QCOMPARE(reply->error(), QNetworkReply::ContentConflictError); + + QCOMPARE(mShowUiSpy->count(), 0); + QCOMPARE(mShowUserInfoSpy->count(), 0); + QCOMPARE(mAuthenticationSpy->count(), 1); + } + + void unknownRequest() { HttpServerRequestor requestor; @@ -252,6 +293,51 @@ class test_UIPlugInWebService } + void proxyDetection_data() + { + QTest::addColumn("httpStatusCode"); + QTest::addColumn("existingAppResult"); + + QTest::newRow("timeout") << 0 << static_cast(UIPlugInWebService::ExistingAppResult::SHOWUI_TIMEOUT); + QTest::newRow("no-proxy") << 200 << static_cast(UIPlugInWebService::ExistingAppResult::SHOWUI_SUCCEED); + QTest::newRow("proxy-failed") << 502 << static_cast(UIPlugInWebService::ExistingAppResult::REBIND_FAILED); + QTest::newRow("proxy-succedd") << 502 << static_cast(UIPlugInWebService::ExistingAppResult::REBIND_SUCCEED); + } + + + void proxyDetection() + { + QFETCH(int, httpStatusCode); + QFETCH(int, existingAppResult); + const auto existingAppResultType = static_cast(existingAppResult); + + const auto testAddress = HttpServer::cAddresses.constFirst(); + QScopedValueRollback guard(HttpServer::cAddresses); + + MockNetworkManager networkManager; + Env::set(NetworkManager::staticMetaObject, &networkManager); + + if (existingAppResultType == UIPlugInWebService::ExistingAppResult::SHOWUI_TIMEOUT) + { + QTest::ignoreMessage(QtWarningMsg, "ShowUI request timed out"); + } + else + { + auto reply = new MockNetworkReply(); + reply->setAttribute(QNetworkRequest::Attribute::HttpStatusCodeAttribute, httpStatusCode); + reply->fireFinished(); + networkManager.setNextReply(reply); + + if (existingAppResultType == UIPlugInWebService::ExistingAppResult::REBIND_FAILED) + { + HttpServer::cAddresses.clear(); + } + } + + QCOMPARE(mUi->handleExistingApp(HttpServer::cPort, testAddress), existingAppResultType); + } + + void test_GuessImageContentType_data() { QTest::addColumn("fileName"); diff --git a/test/qt/ui/webservice/test_UIPlugInWebServiceBrowserHandler.cpp b/test/qt/ui/webservice/test_UIPlugInWebServiceBrowserHandler.cpp new file mode 100644 index 000000000..065eb5270 --- /dev/null +++ b/test/qt/ui/webservice/test_UIPlugInWebServiceBrowserHandler.cpp @@ -0,0 +1,181 @@ +/** + * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany + */ + +#include "UIPlugInWebService.h" + +#include "MockSocket.h" +#include "ResourceLoader.h" +#include "WorkflowRequest.h" +#include "context/AuthContext.h" + +#include +#include + +using namespace governikus; + +class test_UIPlugInWebServiceBrowserHandler + : public QObject +{ + Q_OBJECT + QPointer mSocket; + QSharedPointer mRequest; + QSharedPointer mAuthContext; + + QByteArray split(const QByteArray& pData) + { + return pData.split('\r').at(0); + } + + private Q_SLOTS: + void initTestCase() + { + //QCoreApplication::setApplicationVersion("1.0.0"); + HttpServer::cPort = 0; + } + + + void init() + { + mSocket = new MockSocket(); + mSocket->setSocketState(QAbstractSocket::ConnectedState); + mRequest.reset(new HttpRequest(mSocket)); + mAuthContext.reset(new AuthContext(true, QUrl("http://activationUrl"))); + + ResourceLoader::getInstance().init(); // html templates + } + + + void getActivationUrl() + { + mSocket->mReadBuffer = QByteArray("GET /testUrl HTTP/1.1\r\n" + "\r\n\r\n"); + Q_EMIT mSocket->readyRead(); + QCOMPARE(mRequest->getUrl().toEncoded(), QByteArray("/testUrl")); + + UIPlugInWebService ui; + + QUrl url; + connect(&ui, &UIPlugIn::fireWorkflowRequested, this, [&url](const QSharedPointer& pRequest){ + url = pRequest->getContext().objectCast()->getActivationUrl(); + }); + + ui.handleWorkflowRequest(mRequest); + QCOMPARE(url.toEncoded(), QByteArray("/testUrl")); + } + + + void connectionLost() + { + mSocket->setSocketState(QAbstractSocket::UnconnectedState); + UIPlugInWebService ui; + + // lost for error page + QCOMPARE(ui.sendRedirect(mRequest, mAuthContext), QLatin1String("The browser connection was lost.")); + + // lost for correct redirect + mAuthContext->setTcTokenNotFound(false); + mAuthContext->setRefreshUrl(QUrl("http://dummy")); + QCOMPARE(ui.sendRedirect(mRequest, mAuthContext), QLatin1String("The connection to the browser was lost. No forwarding was executed. Please try to call the URL again manually: dummy")); + } + + + void tcTokenNotFound() + { + UIPlugInWebService ui; + mAuthContext->setTcTokenNotFound(true); + + QTest::ignoreMessage(QtDebugMsg, "Send error page to browser, error code 404"); + QCOMPARE(ui.sendRedirect(mRequest, mAuthContext), QString()); + QCOMPARE(split(mSocket->mWriteBuffer), "HTTP/1.0 404 Not Found"); + } + + + void internalErrorBeforeTcToken() + { + UIPlugInWebService ui; + mAuthContext->setStatus(GlobalStatus::Code::Workflow_InternalError_BeforeTcToken); + + QTest::ignoreMessage(QtDebugMsg, "Send error page to browser, error code 500"); + QCOMPARE(ui.sendRedirect(mRequest, mAuthContext), QString()); + QCOMPARE(split(mSocket->mWriteBuffer), "HTTP/1.0 500 Internal Server Error"); + } + + + void emptyRefreshUrlNoTcToken() + { + UIPlugInWebService ui; + mAuthContext->setTcTokenNotFound(false); + + QTest::ignoreMessage(QtDebugMsg, "Send error page to browser, error code 400"); + QCOMPARE(ui.sendRedirect(mRequest, mAuthContext), QString()); + QCOMPARE(split(mSocket->mWriteBuffer), "HTTP/1.0 400 Bad Request"); + } + + + void emptyRefreshUrlNoCommunicationErrorAddress() + { + const QByteArray tokenData("" + "" + " https://eid-server.example.de/entrypoint" + " 1A2BB129" + " https://service.example.de/loggedin?7eb39f62" + " urn:liberty:paos:2006-08 " + " urn:ietf:rfc:4279 " + " " + " 4BC1A0B5 " + " " + ""); + + UIPlugInWebService ui; + mAuthContext->setTcTokenNotFound(false); + mAuthContext->setTcToken(QSharedPointer::create(tokenData)); + + QTest::ignoreMessage(QtDebugMsg, "Send error page to browser, error code 400"); + QCOMPARE(ui.sendRedirect(mRequest, mAuthContext), QString()); + QCOMPARE(split(mSocket->mWriteBuffer), "HTTP/1.0 400 Bad Request"); + } + + + void emptyRefreshUrl() + { + const QByteArray tokenData("" + "" + " https://eid-server.example.de/entrypoint" + " 1A2BB129" + " https://service.example.de/loggedin?7eb39f62" + " https://flupp" + " urn:liberty:paos:2006-08 " + " urn:ietf:rfc:4279 " + " " + " 4BC1A0B5 " + " " + ""); + + UIPlugInWebService ui; + mAuthContext->setTcTokenNotFound(false); + mAuthContext->setTcToken(QSharedPointer::create(tokenData)); + + QCOMPARE(ui.sendRedirect(mRequest, mAuthContext), QString()); + QCOMPARE(split(mSocket->mWriteBuffer), "HTTP/1.0 303 See Other"); + QVERIFY(mSocket->mWriteBuffer.contains("Location: https://flupp")); + } + + + void sendRefreshUrl() + { + UIPlugInWebService ui; + mAuthContext->setTcTokenNotFound(false); + mAuthContext->setRefreshUrl(QUrl("http://dummy")); + + QTest::ignoreMessage(QtDebugMsg, "Redirect URL: QUrl(\"http://dummy?ResultMajor=ok\")"); + QCOMPARE(ui.sendRedirect(mRequest, mAuthContext), QString()); + QCOMPARE(split(mSocket->mWriteBuffer), "HTTP/1.0 303 See Other"); + QVERIFY(mSocket->mWriteBuffer.contains("Location: http://dummy?ResultMajor=ok")); + } + + +}; + +QTEST_GUILESS_MAIN(test_UIPlugInWebServiceBrowserHandler) +#include "test_UIPlugInWebServiceBrowserHandler.moc" diff --git a/test/qt/ui/webservice/test_WebserviceActivationContext.cpp b/test/qt/ui/webservice/test_WebserviceActivationContext.cpp deleted file mode 100644 index 38ca95c34..000000000 --- a/test/qt/ui/webservice/test_WebserviceActivationContext.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/** - * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany - */ - -/*! - * \brief Unit tests for \ref WebserviceActivationContext - */ - -#include "WebserviceActivationContext.h" - -#include "MockSocket.h" -#include "ResourceLoader.h" - -#include -#include - -using namespace governikus; - -class test_WebserviceActivationContext - : public QObject -{ - Q_OBJECT - QPointer mSocket; - QSharedPointer mRequest; - - private Q_SLOTS: - void initTestCase() - { - mSocket = new MockSocket(); - mRequest.reset(new HttpRequest(mSocket)); - - ResourceLoader::getInstance().init(); - } - - - void test_GetActivationUrl() - { - mSocket->mReadBuffer = QByteArray("GET /testUrl HTTP/1.1\r\n" - "\r\n\r\n"); - Q_EMIT mSocket->readyRead(); - WebserviceActivationContext context(mRequest); - QCOMPARE(context.getActivationURL().toEncoded(), QByteArray("/testUrl")); - } - - - void test_SendProcessing() - { - WebserviceActivationContext context(mRequest); - QVERIFY(!context.sendProcessing()); - QCOMPARE(context.getSendError(), QString("The browser connection was lost.")); - - mSocket->setSocketState(QAbstractSocket::ConnectedState); - QVERIFY(context.sendProcessing()); - } - - - void test_SendActivationAlreadyActive() - { - WebserviceActivationContext context(mRequest); - - mSocket->setSocketState(QAbstractSocket::UnconnectedState); - QVERIFY(!context.sendOperationAlreadyActive()); - QCOMPARE(context.getSendError(), QString("The browser connection was lost.")); - - mSocket->setSocketState(QAbstractSocket::ConnectedState); - QVERIFY(context.sendOperationAlreadyActive()); - } - - - void test_SendRedirect() - { - WebserviceActivationContext context(mRequest); - - mSocket->setSocketState(QAbstractSocket::UnconnectedState); - QTest::ignoreMessage(QtDebugMsg, "Redirect URL: QUrl(\"?ResultMajor=ok\")"); - QVERIFY(!context.sendRedirect(QUrl(), GlobalStatus::Code::No_Error)); - QCOMPARE(context.getSendError(), QString("The connection to the browser was lost. No forwarding was executed. Please try to call the URL again manually: ")); - - mSocket->setSocketState(QAbstractSocket::ConnectedState); - QVERIFY(context.sendRedirect(QUrl(), GlobalStatus::Code::No_Error)); - } - - - void test_SendErrorPage() - { - WebserviceActivationContext context(mRequest); - - QTest::ignoreMessage(QtDebugMsg, "Send error page to browser, error code 400"); - QVERIFY(context.sendErrorPage(HTTP_STATUS_BAD_REQUEST, GlobalStatus::Code::Unknown_Error)); - const auto buffer = mSocket->mWriteBuffer; - QVERIFY(buffer.contains("Connection: close")); - QVERIFY(buffer.contains("Cache-Control: no-cache, no-store")); - QVERIFY(buffer.contains("Pragma: no-cache")); - - mSocket->setSocketState(QAbstractSocket::UnconnectedState); - QVERIFY(!context.sendErrorPage(HTTP_STATUS_BAD_REQUEST, GlobalStatus::Code::Unknown_Error)); - } - - -}; - -QTEST_GUILESS_MAIN(test_WebserviceActivationContext) -#include "test_WebserviceActivationContext.moc" diff --git a/test/qt/workflows/context/test_AccessRightManager.cpp b/test/qt/workflows/context/test_AccessRightManager.cpp index b55b0b42d..1bb132eca 100644 --- a/test/qt/workflows/context/test_AccessRightManager.cpp +++ b/test/qt/workflows/context/test_AccessRightManager.cpp @@ -66,7 +66,7 @@ class test_AccessRightManager { Env::getSingleton()->setUsedAsSDK(false); - mTestAuthContext.reset(new TestAuthContext(nullptr, ":/paos/DIDAuthenticateEAC1_accessRightsEmpty.xml")); + mTestAuthContext.reset(new TestAuthContext(":/paos/DIDAuthenticateEAC1_accessRightsEmpty.xml")); mEac1Changed.reset(new QSignalSpy(mTestAuthContext.data(), &AuthContext::fireDidAuthenticateEac1Changed)); mARMCreated.reset(new QSignalSpy(mTestAuthContext.data(), &AuthContext::fireAccessRightManagerCreated)); } @@ -81,7 +81,7 @@ class test_AccessRightManager void test_AuthContext_00() { - TestAuthContext context(nullptr, ":/paos/DIDAuthenticateEAC1_accessRightsMissing.xml"); + TestAuthContext context(":/paos/DIDAuthenticateEAC1_accessRightsMissing.xml"); QCOMPARE(context.getAccessRightManager()->getRequiredAccessRights().size(), 0); QCOMPARE(context.getAccessRightManager()->getOptionalAccessRights().size(), 16); QCOMPARE(context.getAccessRightManager()->getEffectiveAccessRights().size(), 16); @@ -211,7 +211,7 @@ class test_AccessRightManager void test_Testbed_C2_01() { - TestAuthContext context(nullptr, ":/testbed/DIDAuthenticateEAC1_C2_01.xml"); + TestAuthContext context(":/testbed/DIDAuthenticateEAC1_C2_01.xml"); *context.getAccessRightManager() -= AccessRight::CAN_ALLOWED; QVERIFY(context.encodeEffectiveChat().toHex().endsWith("3c0f13ffe4")); } @@ -219,7 +219,7 @@ class test_AccessRightManager void test_Testbed_C2_02() { - TestAuthContext context(nullptr, ":/testbed/DIDAuthenticateEAC1_C2_02.xml"); + TestAuthContext context(":/testbed/DIDAuthenticateEAC1_C2_02.xml"); *context.getAccessRightManager() = {}; QVERIFY(context.encodeEffectiveChat().toHex().endsWith("0000000000")); } diff --git a/test/qt/workflows/context/test_AuthContext.cpp b/test/qt/workflows/context/test_AuthContext.cpp index 43f8b68a9..4245e262b 100644 --- a/test/qt/workflows/context/test_AuthContext.cpp +++ b/test/qt/workflows/context/test_AuthContext.cpp @@ -46,7 +46,7 @@ class test_AuthContext Env::getSingleton()->setUsedAsSDK(usedAsSdk); Env::getSingleton()->getGeneralSettings().setEnableCanAllowed(enabled); - TestAuthContext context(nullptr, ":/paos/DIDAuthenticateEAC1.xml"); + TestAuthContext context(":/paos/DIDAuthenticateEAC1.xml"); Env::getSingleton()->getGeneralSettings().setEnableCanAllowed(false); Env::getSingleton()->setUsedAsSDK(false); QSignalSpy spy(&context, &TestAuthContext::fireCanAllowedModeChanged); @@ -68,7 +68,7 @@ class test_AuthContext void test_ErrorReportedToServer() { - AuthContext context(nullptr); + AuthContext context; QVERIFY(!context.isErrorReportedToServer()); @@ -82,7 +82,7 @@ class test_AuthContext void test_DidAuthenticateEacResponse1() { - AuthContext context(nullptr); + AuthContext context; const QSharedPointer eac(new DIDAuthenticateResponseEAC1()); QCOMPARE(context.getDidAuthenticateResponseEac1(), nullptr); @@ -94,7 +94,7 @@ class test_AuthContext void test_DidAuthenticateResponseEacAdditionalInputType() { - AuthContext context(nullptr); + AuthContext context; const QSharedPointer eac(new DIDAuthenticateResponseEAC2()); QCOMPARE(context.getDidAuthenticateResponseEacAdditionalInputType(), nullptr); @@ -106,7 +106,7 @@ class test_AuthContext void test_DidAuthenticateEacAdditional() { - AuthContext context(nullptr); + AuthContext context; const QSharedPointer eac(new DIDAuthenticateEACAdditional()); QCOMPARE(context.getDidAuthenticateEacAdditional(), nullptr); @@ -118,7 +118,7 @@ class test_AuthContext void test_DidAuthenticateResponseEac2() { - AuthContext context(nullptr); + AuthContext context; const QSharedPointer eac(new DIDAuthenticateResponseEAC2()); QCOMPARE(context.getDidAuthenticateResponseEac2(), nullptr); @@ -130,7 +130,7 @@ class test_AuthContext void test_TransmitResponse() { - AuthContext context(nullptr); + AuthContext context; QSharedPointer response(new TransmitResponse()); QCOMPARE(context.getTransmitResponse(), nullptr); @@ -142,7 +142,7 @@ class test_AuthContext void test_Transmit() { - AuthContext context(nullptr); + AuthContext context; const QSharedPointer transmit(new Transmit()); QCOMPARE(context.getTransmit(), nullptr); @@ -154,7 +154,7 @@ class test_AuthContext void test_StartPaos() { - AuthContext context(nullptr); + AuthContext context; const QByteArray data("paos"); const QSharedPointer paos(new StartPaos(data)); @@ -167,7 +167,7 @@ class test_AuthContext void test_SslSession() { - AuthContext context(nullptr); + AuthContext context; const QByteArray session("session"); context.setSslSession(session); @@ -177,7 +177,7 @@ class test_AuthContext void test_MultiCertificatesUrl() { - AuthContext context(nullptr); + AuthContext context; QCOMPARE(context.getCertificateList().size(), 0); context.addCertificateData(QUrl("https://governikus.de"), QSslCertificate()); diff --git a/test/qt/workflows/context/test_ChangePinContext.cpp b/test/qt/workflows/context/test_ChangePinContext.cpp index 4c986c4ed..1a59ba0a0 100644 --- a/test/qt/workflows/context/test_ChangePinContext.cpp +++ b/test/qt/workflows/context/test_ChangePinContext.cpp @@ -81,19 +81,28 @@ class test_ChangePinContext } - void test_isPhysicalCardRequired() + void test_AcceptedEidTypes() { { ChangePinContext context; - QVERIFY(!context.isPhysicalCardRequired()); + QVERIFY(context.getAcceptedEidTypes().contains(AcceptedEidType::CARD_CERTIFIED)); + QVERIFY(context.getAcceptedEidTypes().contains(AcceptedEidType::SE_CERTIFIED)); + QVERIFY(context.getAcceptedEidTypes().contains(AcceptedEidType::SE_ENDORSED)); + QVERIFY(context.getAcceptedEidTypes().contains(AcceptedEidType::HW_KEYSTORE)); } { ChangePinContext context(false); - QVERIFY(!context.isPhysicalCardRequired()); + QVERIFY(context.getAcceptedEidTypes().contains(AcceptedEidType::CARD_CERTIFIED)); + QVERIFY(context.getAcceptedEidTypes().contains(AcceptedEidType::SE_CERTIFIED)); + QVERIFY(context.getAcceptedEidTypes().contains(AcceptedEidType::SE_ENDORSED)); + QVERIFY(context.getAcceptedEidTypes().contains(AcceptedEidType::HW_KEYSTORE)); } { ChangePinContext context(true); - QVERIFY(context.isPhysicalCardRequired()); + QVERIFY(context.getAcceptedEidTypes().contains(AcceptedEidType::CARD_CERTIFIED)); + QVERIFY(!context.getAcceptedEidTypes().contains(AcceptedEidType::SE_CERTIFIED)); + QVERIFY(!context.getAcceptedEidTypes().contains(AcceptedEidType::SE_ENDORSED)); + QVERIFY(!context.getAcceptedEidTypes().contains(AcceptedEidType::HW_KEYSTORE)); } } diff --git a/test/qt/workflows/context/test_WorkflowContext.cpp b/test/qt/workflows/context/test_WorkflowContext.cpp index 7d9344a49..c442272b3 100644 --- a/test/qt/workflows/context/test_WorkflowContext.cpp +++ b/test/qt/workflows/context/test_WorkflowContext.cpp @@ -18,7 +18,34 @@ class test_WorkflowContext : public QObject { Q_OBJECT - QSharedPointer mContext; + QSharedPointer mContext; + + private: + QVector allow_all_types() + { + return QVector({AcceptedEidType::CARD_CERTIFIED, AcceptedEidType::HW_KEYSTORE, AcceptedEidType::SE_CERTIFIED, AcceptedEidType::SE_ENDORSED}); + } + + + QVector allow_all_types_but(const AcceptedEidType& pType) + { + auto types = allow_all_types(); + types.removeOne(pType); + return types; + } + + + QVector allow_only(std::initializer_list pTypes) + { + return QVector(pTypes); + } + + + QSharedPointer createCardConnection(CardType pCardType) + { + auto readerInfo = ReaderInfo("reader", ReaderManagerPlugInType::UNKNOWN, CardInfo(pCardType)); + return QSharedPointer(new MockCardConnection(readerInfo)); + } private Q_SLOTS: void init() @@ -273,15 +300,69 @@ class test_WorkflowContext } - void test_setInterruptRequested() + void test_eidTypeMismatch_data() + { + QTest::addColumn>("cardConnection"); + QTest::addColumn>("acceptedTypes"); + QTest::addColumn("result"); + + QTest::addRow("No error when no cardconnection 1") << QSharedPointer() << QVector() << false; + QTest::addRow("No error when no cardconnection 2") << QSharedPointer() << allow_all_types() << false; + + QTest::addRow("No error when no card") << createCardConnection(CardType::NONE) << QVector() << false; + + QTest::addRow("ID card allowed") << createCardConnection(CardType::EID_CARD) << allow_all_types() << false; + QTest::addRow("ID card not allowed") << createCardConnection(CardType::EID_CARD) << allow_all_types_but(AcceptedEidType::CARD_CERTIFIED) << true; + + QTest::addRow("Smart-eID with unknown EidType not allowed") << createCardConnection(CardType::SMART_EID) << allow_only({AcceptedEidType::CARD_CERTIFIED, AcceptedEidType::SE_CERTIFIED}) << true; + } + + + void test_eidTypeMismatch() + { + QFETCH(QSharedPointer, cardConnection); + QFETCH(QVector, acceptedTypes); + QFETCH(bool, result); + + mContext->setAcceptedEidTypes(acceptedTypes); + mContext->setCardConnection(cardConnection); + + QCOMPARE(mContext->eidTypeMismatch(), result); + } + + + void test_isMobileEidTypeAllowed_data() + { + QTest::addColumn("mobileEidType"); + QTest::addColumn>("acceptedTypes"); + QTest::addColumn("result"); + + QTest::addRow("UNKNOWN not allowed") << MobileEidType::UNKNOWN << allow_all_types() << false; + QTest::addRow("All allowed 1") << MobileEidType::HW_KEYSTORE << allow_all_types() << true; + QTest::addRow("All allowed 2") << MobileEidType::SE_CERTIFIED << allow_all_types() << true; + QTest::addRow("All allowed 3") << MobileEidType::SE_ENDORSED << allow_all_types() << true; + + QTest::addRow("Only id card allowed 1") << MobileEidType::HW_KEYSTORE << allow_only({AcceptedEidType::CARD_CERTIFIED}) << false; + QTest::addRow("Only id card allowed 2") << MobileEidType::SE_CERTIFIED << allow_only({AcceptedEidType::CARD_CERTIFIED}) << false; + QTest::addRow("Only id card allowed 3") << MobileEidType::SE_ENDORSED << allow_only({AcceptedEidType::CARD_CERTIFIED}) << false; + + QTest::addRow("Specific type not allowed") << MobileEidType::SE_ENDORSED << allow_all_types_but(AcceptedEidType::SE_ENDORSED) << false; + + QTest::addRow("Specific type allowed 1") << MobileEidType::HW_KEYSTORE << allow_only({AcceptedEidType::HW_KEYSTORE}) << true; + QTest::addRow("Specific type allowed 2") << MobileEidType::SE_CERTIFIED << allow_only({AcceptedEidType::SE_CERTIFIED}) << true; + QTest::addRow("Specific type allowed 3") << MobileEidType::SE_ENDORSED << allow_only({AcceptedEidType::SE_ENDORSED}) << true; + } + + + void test_isMobileEidTypeAllowed() { - QVERIFY(!mContext->interruptRequested()); + QFETCH(MobileEidType, mobileEidType); + QFETCH(QVector, acceptedTypes); + QFETCH(bool, result); - mContext->setInterruptRequested(true); - QVERIFY(mContext->interruptRequested()); + mContext->setAcceptedEidTypes(acceptedTypes); - mContext->setInterruptRequested(false); - QVERIFY(!mContext->interruptRequested()); + QCOMPARE(mContext->isMobileEidTypeAllowed(mobileEidType), result); } diff --git a/test/qt/workflows/ifd/test_IfdServiceContext.cpp b/test/qt/workflows/ifd/test_IfdServiceContext.cpp index 6ab80c053..398df8514 100644 --- a/test/qt/workflows/ifd/test_IfdServiceContext.cpp +++ b/test/qt/workflows/ifd/test_IfdServiceContext.cpp @@ -80,6 +80,7 @@ class test_IfdServiceContext { IfdServiceContext context(mIfdServer); context.reset(); + QCOMPARE(context.getDisplayText(), QString()); QCOMPARE(context.getCardConnection(), QSharedPointer()); QCOMPARE(context.getCan(), QString()); QCOMPARE(context.getPin(), QString()); diff --git a/test/qt/workflows/ifd/test_StateProcessIfdMessages.cpp b/test/qt/workflows/ifd/test_StateProcessIfdMessages.cpp index dba2e1cd3..9265c6baa 100644 --- a/test/qt/workflows/ifd/test_StateProcessIfdMessages.cpp +++ b/test/qt/workflows/ifd/test_StateProcessIfdMessages.cpp @@ -35,7 +35,7 @@ class test_StateProcessIfdMessages const QSharedPointer context(new IfdServiceContext(mIfdServer)); StateProcessIfdMessages state(context); state.run(); - QCOMPARE(state.mConnections.size(), 1); + QCOMPARE(state.mConnections.size(), 3); QCOMPARE(state.mMessageConnections.size(), 7); } diff --git a/test/qt/workflows/ifd/test_StateStopIfdService.cpp b/test/qt/workflows/ifd/test_StateStopIfdService.cpp index b2fa31e89..471e104c0 100644 --- a/test/qt/workflows/ifd/test_StateStopIfdService.cpp +++ b/test/qt/workflows/ifd/test_StateStopIfdService.cpp @@ -48,8 +48,6 @@ class test_StateStopIfdService void test_OnExit() { - const QString name("name"); - mState->setStateName(name); Q_EMIT mContext->fireCancelWorkflow(); QVERIFY(!mContext->getIfdServer()->isRunning()); } diff --git a/test/qt/workflows/paos/retrieve/test_StartPAOSResponse.cpp b/test/qt/workflows/paos/retrieve/test_StartPAOSResponse.cpp index 6403efdc8..ce7635376 100644 --- a/test/qt/workflows/paos/retrieve/test_StartPAOSResponse.cpp +++ b/test/qt/workflows/paos/retrieve/test_StartPAOSResponse.cpp @@ -27,14 +27,10 @@ class test_StartPAOSResponse QTest::addColumn("major"); QTest::addColumn("minor"); QTest::addColumn("message"); - QTest::addColumn("mRemainingDays"); - QTest::addColumn("mRemainingAttempts"); - QTest::addColumn("mBlockingCode"); - QTest::newRow("Major") << ":paos/StartPAOSResponse1.xml" << ECardApiResult::Major::Ok << ECardApiResult::Minor::null << QString() << -1 << -1 << QString(); - QTest::newRow("MajorMinor") << ":paos/StartPAOSResponse2.xml" << ECardApiResult::Major::Error << ECardApiResult::Minor::DP_Timeout_Error << QString() << -1 << -1 << QString(); - QTest::newRow("MajorMinorMessage") << ":paos/StartPAOSResponse3.xml" << ECardApiResult::Major::Error << ECardApiResult::Minor::DP_Timeout_Error << QString("Detail message") << -1 << -1 << QString(); - QTest::newRow("AdditionalInformation") << ":paos/StartPAOSResponse4.xml" << ECardApiResult::Major::Ok << ECardApiResult::Minor::null << QString() << 30 << 9 << QString("LASTWAGEN"); + QTest::newRow("Major") << ":paos/StartPAOSResponse1.xml" << ECardApiResult::Major::Ok << ECardApiResult::Minor::null << QString(); + QTest::newRow("MajorMinor") << ":paos/StartPAOSResponse2.xml" << ECardApiResult::Major::Error << ECardApiResult::Minor::DP_Timeout_Error << QString(); + QTest::newRow("MajorMinorMessage") << ":paos/StartPAOSResponse3.xml" << ECardApiResult::Major::Error << ECardApiResult::Minor::DP_Timeout_Error << QString("Detail message"); } @@ -44,18 +40,12 @@ class test_StartPAOSResponse QFETCH(ECardApiResult::Major, major); QFETCH(ECardApiResult::Minor, minor); QFETCH(QString, message); - QFETCH(int, mRemainingDays); - QFETCH(int, mRemainingAttempts); - QFETCH(QString, mBlockingCode); QByteArray content = TestFileHelper::readFile(filename); StartPaosResponse startPaosResponse(content); QCOMPARE(startPaosResponse.getResult().getMajor(), major); QCOMPARE(startPaosResponse.getResult().getMinor(), minor); QCOMPARE(startPaosResponse.getResult().getMessage(), message); - QCOMPARE(startPaosResponse.getRemainingDays(), mRemainingDays); - QCOMPARE(startPaosResponse.getRemainingAttempts(), mRemainingAttempts); - QCOMPARE(startPaosResponse.getBlockingCode(), mBlockingCode); } diff --git a/test/qt/workflows/paos/test_UserAgent.cpp b/test/qt/workflows/paos/test_UserAgent.cpp index f6db5b079..862e568dd 100644 --- a/test/qt/workflows/paos/test_UserAgent.cpp +++ b/test/qt/workflows/paos/test_UserAgent.cpp @@ -24,7 +24,7 @@ class test_UserAgent QCoreApplication::setApplicationVersion("1.32.4"); UserAgent obj; - QCOMPARE(obj.getName(), QString("Test_workflows_paos_UserAgent")); + QCOMPARE(obj.getName(), QString("AusweisApp2")); QCOMPARE(obj.getVersionMajor(), QString("1")); QCOMPARE(obj.getVersionMinor(), QString("32")); QCOMPARE(obj.getVersionSubminor(), QString("4")); diff --git a/test/qt/workflows/personalization/test_PersonalizationContext.cpp b/test/qt/workflows/personalization/test_PersonalizationContext.cpp index 5c6ab8584..4d33b5d8d 100644 --- a/test/qt/workflows/personalization/test_PersonalizationContext.cpp +++ b/test/qt/workflows/personalization/test_PersonalizationContext.cpp @@ -49,6 +49,46 @@ class test_PersonalizationContext } + void progress_data() + { + QTest::addColumn("initial"); + QTest::addColumn("max"); + QTest::addColumn("progress"); + QTest::addColumn("expected"); + + QTest::newRow("full_10") << 0 << 100 << 10 << 10; + QTest::newRow("full_50") << 0 << 100 << 50 << 50; + QTest::newRow("full_99") << 0 << 100 << 99 << 99; + QTest::newRow("full_100") << 0 << 100 << 100 << 100; + + QTest::newRow("first_half_10") << 0 << 50 << 10 << 5; + QTest::newRow("first_half_50") << 0 << 50 << 50 << 25; + QTest::newRow("first_half_90") << 0 << 50 << 90 << 45; + QTest::newRow("first_half_100") << 0 << 50 << 100 << 50; + + QTest::newRow("second_half_10") << 50 << 100 << 10 << 55; + QTest::newRow("second_half_50") << 50 << 100 << 50 << 75; + QTest::newRow("second_half_90") << 50 << 100 << 90 << 95; + QTest::newRow("second_half_100") << 50 << 100 << 100 << 100; + } + + + void progress() + { + QFETCH(int, initial); + QFETCH(int, max); + QFETCH(int, progress); + QFETCH(int, expected); + + auto context = QSharedPointer::create(QString()); + QSignalSpy spy(context.get(), &WorkflowContext::fireProgressChanged); + + context->setProgress(progress, QStringLiteral("dummy"), initial, max); + QCOMPARE(spy.count(), 1); + QCOMPARE(context->getProgressValue(), expected); + } + + }; QTEST_GUILESS_MAIN(test_PersonalizationContext) diff --git a/test/qt/workflows/personalization/test_StateChangeSmartPin.cpp b/test/qt/workflows/personalization/test_StateChangeSmartPin.cpp index 72bb49d32..9aff5e280 100644 --- a/test/qt/workflows/personalization/test_StateChangeSmartPin.cpp +++ b/test/qt/workflows/personalization/test_StateChangeSmartPin.cpp @@ -10,11 +10,14 @@ #include "MockCardConnection.h" #include "MockCardConnectionWorker.h" +#include "VolatileSettings.h" #include + using namespace governikus; + class MockEstablishPaceChannelCommand : public BaseCardCommand { @@ -43,6 +46,12 @@ class test_StateChangeSmartPin Q_OBJECT private Q_SLOTS: + void initTestCase() + { + Env::getSingleton()->setUsedAsSDK(false); + } + + void test_RunWithNewPin() { QThread workerThread; diff --git a/test/qt/workflows/personalization/test_StateCheckApplet.cpp b/test/qt/workflows/personalization/test_StateCheckApplet.cpp index de2847e0a..cbe349133 100644 --- a/test/qt/workflows/personalization/test_StateCheckApplet.cpp +++ b/test/qt/workflows/personalization/test_StateCheckApplet.cpp @@ -5,15 +5,11 @@ #include "states/StateCheckApplet.h" #include "ReaderManager.h" -#include "SmartManager.h" #include "context/PersonalizationContext.h" -#include "paos/retrieve/TransmitParser.h" -#include "TestFileHelper.h" #include "mock/eid_applet_interface_mock.h" #include - #include @@ -23,6 +19,9 @@ Q_DECLARE_LOGGING_CATEGORY(network) using namespace governikus; +Q_DECLARE_METATYPE(EidStatus) + + class test_StateCheckApplet : public QObject { @@ -32,8 +31,9 @@ class test_StateCheckApplet void initTestCase() { const auto readerManager = Env::getSingleton(); + QSignalSpy spy(readerManager, &ReaderManager::fireInitialized); readerManager->init(); - readerManager->isScanRunning(); // just to wait until initialization finished + QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations } @@ -46,63 +46,31 @@ class test_StateCheckApplet void run_data() { QTest::addColumn("status"); - QTest::addColumn("code"); - - QTest::newRow("internal_error") << EidStatus::INTERNAL_ERROR << GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed; - QTest::newRow("unavailable") << EidStatus::UNAVAILABLE << GlobalStatus::Code::Workflow_Smart_eID_Unavailable; - QTest::newRow("no_provisioning") << EidStatus::NO_PROVISIONING << GlobalStatus::Code::No_Error; - QTest::newRow("no_personalization") << EidStatus::NO_PERSONALIZATION << GlobalStatus::Code::No_Error; - QTest::newRow("applet_unusable") << EidStatus::APPLET_UNUSABLE << GlobalStatus::Code::No_Error; - QTest::newRow("personalized") << EidStatus::PERSONALIZED << GlobalStatus::Code::No_Error; + QTest::addColumn("signal"); + + QTest::newRow("internal_error") << EidStatus::INTERNAL_ERROR << SIGNAL(fireAbort(const FailureCode&)); + QTest::newRow("cert_expired") << EidStatus::CERT_EXPIRED << SIGNAL(fireDeletePersonalization()); + QTest::newRow("no_provisioning") << EidStatus::NO_PROVISIONING << SIGNAL(fireInstallApplet()); + QTest::newRow("no_personalization") << EidStatus::NO_PERSONALIZATION << SIGNAL(fireContinue()); + QTest::newRow("unusable") << EidStatus::UNUSABLE << SIGNAL(fireDeleteApplet()); + QTest::newRow("personalized") << EidStatus::PERSONALIZED << SIGNAL(fireDeletePersonalization()); } void run() { QFETCH(EidStatus, status); - QFETCH(GlobalStatus::Code, code); + QFETCH(QString, signal); setSmartEidStatus(status); auto context = QSharedPointer::create(QString()); StateCheckApplet state(context); - QSignalSpy spyAbort(&state, &StateCheckApplet::fireAbort); - QSignalSpy spyContinue(&state, &StateCheckApplet::fireContinue); - QSignalSpy spyFurtherStepRequired(&state, &StateCheckApplet::fireFurtherStepRequired); + QSignalSpy spy(&state, qPrintable(signal)); + QVERIFY(spy.isValid()); state.run(); - - switch (code) - { - case GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed: - QTRY_COMPARE(spyAbort.size(), 1); // clazy:exclude=qstring-allocations - QCOMPARE(spyContinue.size(), 0); - QCOMPARE(spyFurtherStepRequired.size(), 0); - QCOMPARE(context->getFailureCode(), FailureCode::Reason::Check_Applet_Error); - break; - - case GlobalStatus::Code::Workflow_Smart_eID_Unavailable: - QTRY_COMPARE(spyAbort.size(), 1); // clazy:exclude=qstring-allocations - QCOMPARE(spyContinue.size(), 0); - QCOMPARE(spyFurtherStepRequired.size(), 0); - QCOMPARE(context->getFailureCode(), FailureCode::Reason::Check_Applet_Unavailable); - break; - - default: - if (status == EidStatus::NO_PERSONALIZATION) - { - QCOMPARE(spyAbort.size(), 0); - QTRY_COMPARE(spyContinue.size(), 1); // clazy:exclude=qstring-allocations - QCOMPARE(spyFurtherStepRequired.size(), 0); - } - else - { - QCOMPARE(spyAbort.size(), 0); - QCOMPARE(spyContinue.size(), 0); - QTRY_COMPARE(spyFurtherStepRequired.size(), 1); // clazy:exclude=qstring-allocations - } - } - QCOMPARE(context->getStatus(), code); + QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations } diff --git a/test/qt/workflows/personalization/test_StateDeleteApplet.cpp b/test/qt/workflows/personalization/test_StateDeleteApplet.cpp new file mode 100644 index 000000000..a56595dae --- /dev/null +++ b/test/qt/workflows/personalization/test_StateDeleteApplet.cpp @@ -0,0 +1,142 @@ +/** + * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany + */ + +#include "states/StateDeleteApplet.h" + +#include "ReaderManager.h" +#include "context/PersonalizationContext.h" + +#include "mock/eid_applet_interface_mock.h" + +#include +#include + + +Q_DECLARE_LOGGING_CATEGORY(network) + + +using namespace governikus; + + +Q_DECLARE_METATYPE(EidServiceResult) +Q_DECLARE_METATYPE(std::optional) + + +class test_StateDeleteApplet + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void initTestCase() + { + const auto readerManager = Env::getSingleton(); + QSignalSpy spy(readerManager, &ReaderManager::fireInitialized); + readerManager->init(); + QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations + } + + + void cleanupTestCase() + { + Env::getSingleton()->shutdown(); + } + + + void init() + { + initMock(); + } + + + void run_data() + { + QTest::addColumn("deleteSmartResult"); + QTest::addColumn("logEntries"); + QTest::addColumn("statusCode"); + QTest::addColumn>("failureCode"); + + QTest::addRow("SUCCESS") + << EidServiceResult::SUCCESS + << QStringList {"Successfully deleted Smart-eID"} + << GlobalStatus::Code::No_Error + << std::optional(); + QTest::addRow("ERROR") + << EidServiceResult::ERROR + << QStringList {"Deletion of Smart-eID failed"} + << GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed + << std::optional(FailureCode::Reason::Delete_Smart_Service_Response_Fail); + QTest::addRow("UNSUPPORTED") + << EidServiceResult::UNSUPPORTED + << QStringList {"Deletion of Smart-eID failed"} + << GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed + << std::optional(FailureCode::Reason::Delete_Smart_Service_Response_Unsupported); + QTest::addRow("NFC_NOT_ACTIVATED") + << EidServiceResult::NFC_NOT_ACTIVATED + << QStringList {"Deletion of Smart-eID failed"} + << GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed + << std::optional(FailureCode::Reason::Delete_Smart_Service_Response_Nfc_Disabled); + QTest::addRow("OVERLOAD_PROTECTION") + << EidServiceResult::OVERLOAD_PROTECTION + << QStringList {"Deletion of Smart-eID failed"} + << GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed + << std::optional(FailureCode::Reason::Delete_Smart_Service_Response_Overload); + QTest::addRow("UNDER_MAINTENANCE") + << EidServiceResult::UNDER_MAINTENANCE + << QStringList {"Deletion of Smart-eID failed"} + << GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed + << std::optional(FailureCode::Reason::Delete_Smart_Service_Response_Maintenance); + QTest::addRow("INTEGRITY_CHECK_FAILED") + << EidServiceResult::INTEGRITY_CHECK_FAILED + << QStringList {"Deletion of Smart-eID failed"} + << GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed + << std::optional(FailureCode::Reason::Delete_Smart_Service_Response_Integrity_Check_Failed); + QTest::addRow("NOT_AUTHENTICATED") + << EidServiceResult::NOT_AUTHENTICATED + << QStringList {"Deletion of Smart-eID failed"} + << GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed + << std::optional(FailureCode::Reason::Delete_Smart_Service_Response_Not_Authenticated); + } + + + void run() + { + QFETCH(EidServiceResult, deleteSmartResult); + QFETCH(QStringList, logEntries); + QFETCH(GlobalStatus::Code, statusCode); + QFETCH(std::optional, failureCode); + + setDeleteSmartEidResult(deleteSmartResult); + + auto context = QSharedPointer::create(QString()); + + StateDeleteApplet state(context); + QSignalSpy spyAbort(&state, &StateDeleteApplet::fireAbort); + QSignalSpy spyContinue(&state, &StateDeleteApplet::fireContinue); + + for (const auto& log : std::as_const(logEntries)) + { + QTest::ignoreMessage(QtDebugMsg, log.toUtf8().data()); + } + state.run(); + + if (statusCode == GlobalStatus::Code::No_Error) + { + QTRY_COMPARE(spyContinue.size(), 1); // clazy:exclude=qstring-allocations + QCOMPARE(spyAbort.size(), 0); + } + else + { + QTRY_COMPARE(spyAbort.size(), 1); // clazy:exclude=qstring-allocations + QCOMPARE(spyContinue.size(), 0); + } + QCOMPARE(context->getStatus(), statusCode); + QCOMPARE(context->getFailureCode(), failureCode); + } + + +}; + +QTEST_GUILESS_MAIN(test_StateDeleteApplet) +#include "test_StateDeleteApplet.moc" diff --git a/test/qt/workflows/personalization/test_StateDeletePersonalization.cpp b/test/qt/workflows/personalization/test_StateDeletePersonalization.cpp new file mode 100644 index 000000000..eb417b194 --- /dev/null +++ b/test/qt/workflows/personalization/test_StateDeletePersonalization.cpp @@ -0,0 +1,139 @@ +/** + * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany + */ + +#include "states/StateDeletePersonalization.h" + +#include "ReaderManager.h" +#include "context/PersonalizationContext.h" + +#include "mock/eid_applet_interface_mock.h" + +#include +#include + + +using namespace governikus; + + +Q_DECLARE_METATYPE(EidServiceResult) +Q_DECLARE_METATYPE(std::optional) + + +class test_StateDeletePersonalization + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void initTestCase() + { + const auto readerManager = Env::getSingleton(); + QSignalSpy spy(readerManager, &ReaderManager::fireInitialized); + readerManager->init(); + QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations + } + + + void cleanupTestCase() + { + Env::getSingleton()->shutdown(); + } + + + void init() + { + initMock(); + } + + + void run_data() + { + QTest::addColumn("deletePersonalizationResult"); + QTest::addColumn("logEntries"); + QTest::addColumn("statusCode"); + QTest::addColumn>("failureCode"); + + QTest::addRow("SUCCESS") + << EidServiceResult::SUCCESS + << QStringList {"Successfully deleted the Smart-eID personalization"} + << GlobalStatus::Code::No_Error + << std::optional(); + QTest::addRow("ERROR") + << EidServiceResult::ERROR + << QStringList {"Deletion of Smart-eID personalization failed"} + << GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed + << std::optional(FailureCode::Reason::Delete_Personalization_Failed); + QTest::addRow("UNSUPPORTED") + << EidServiceResult::UNSUPPORTED + << QStringList {"Deletion of Smart-eID personalization failed"} + << GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed + << std::optional(FailureCode::Reason::Delete_Personalization_Failed); + QTest::addRow("OVERLOAD_PROTECTION") + << EidServiceResult::OVERLOAD_PROTECTION + << QStringList {"Deletion of Smart-eID personalization failed"} + << GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed + << std::optional(FailureCode::Reason::Delete_Personalization_Failed); + QTest::addRow("UNDER_MAINTENANCE") + << EidServiceResult::UNDER_MAINTENANCE + << QStringList {"Deletion of Smart-eID personalization failed"} + << GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed + << std::optional(FailureCode::Reason::Delete_Personalization_Failed); + QTest::addRow("NFC_NOT_ACTIVATED") + << EidServiceResult::NFC_NOT_ACTIVATED + << QStringList {"Deletion of Smart-eID personalization failed"} + << GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed + << std::optional(FailureCode::Reason::Delete_Personalization_Failed); + QTest::addRow("INTEGRITY_CHECK_FAILED") + << EidServiceResult::INTEGRITY_CHECK_FAILED + << QStringList {"Deletion of Smart-eID personalization failed"} + << GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed + << std::optional(FailureCode::Reason::Delete_Personalization_Failed); + QTest::addRow("NOT_AUTHENTICATED") + << EidServiceResult::NOT_AUTHENTICATED + << QStringList {"Deletion of Smart-eID personalization failed"} + << GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed + << std::optional(FailureCode::Reason::Delete_Personalization_Failed); + } + + + void run() + { + QFETCH(EidServiceResult, deletePersonalizationResult); + QFETCH(QStringList, logEntries); + QFETCH(GlobalStatus::Code, statusCode); + QFETCH(std::optional, failureCode); + + setDeletePersonalizationResult(deletePersonalizationResult); + + auto context = QSharedPointer::create(QString()); + + StateDeletePersonalization state(context); + QSignalSpy spyAbort(&state, &StateDeletePersonalization::fireAbort); + QSignalSpy spyContinue(&state, &StateDeletePersonalization::fireContinue); + + for (const auto& log : std::as_const(logEntries)) + { + QTest::ignoreMessage(QtDebugMsg, log.toUtf8().data()); + } + state.run(); + + if (statusCode == GlobalStatus::Code::No_Error) + { + QTRY_COMPARE(spyContinue.size(), 1); // clazy:exclude=qstring-allocations + QCOMPARE(spyAbort.size(), 0); + } + else + { + QTRY_COMPARE(spyAbort.size(), 1); // clazy:exclude=qstring-allocations + QCOMPARE(spyContinue.size(), 0); + } + QCOMPARE(context->getStatus(), statusCode); + QCOMPARE(context->getFailureCode(), failureCode); + } + + +}; + +QTEST_GUILESS_MAIN(test_StateDeletePersonalization) +#include "test_StateDeletePersonalization.moc" diff --git a/test/qt/workflows/personalization/test_StateFinalizePersonalization.cpp b/test/qt/workflows/personalization/test_StateFinalizePersonalization.cpp index b707ffd22..a165b38d5 100644 --- a/test/qt/workflows/personalization/test_StateFinalizePersonalization.cpp +++ b/test/qt/workflows/personalization/test_StateFinalizePersonalization.cpp @@ -30,8 +30,9 @@ class test_StateFinalizePersonalization void initTestCase() { const auto readerManager = Env::getSingleton(); + QSignalSpy spy(readerManager, &ReaderManager::fireInitialized); readerManager->init(); - readerManager->isScanRunning(); // just to wait until initialization finished + QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations } diff --git a/test/qt/workflows/personalization/test_StateGetChallenge.cpp b/test/qt/workflows/personalization/test_StateGetChallenge.cpp index f3cd84375..0c51ed6cc 100644 --- a/test/qt/workflows/personalization/test_StateGetChallenge.cpp +++ b/test/qt/workflows/personalization/test_StateGetChallenge.cpp @@ -35,8 +35,7 @@ class test_StateGetChallenge void init() { mContext.reset(new PersonalizationContext(QStringLiteral("https://dummy/v1/%1"))); - mState.reset(new StateGetChallenge(mContext)); - mState->setStateName("StateGetChallenge"); + mState.reset(StateBuilder::createState(mContext)); QVERIFY(mContext->getChallenge().isEmpty()); } @@ -60,6 +59,7 @@ class test_StateGetChallenge void test_CheckPayload() { mContext->setSessionIdentifier(QUuid("135a32d8-ccfa-11eb-b8bc-0242ac130003")); + mContext->setServiceInformation(SmartEidType::APPLET, QStringLiteral("FooBar"), QString()); const auto& payload = mState->getPayload(); QJsonParseError jsonError {}; @@ -69,7 +69,7 @@ class test_StateGetChallenge const auto obj = json.object(); QCOMPARE(obj.size(), 2); QCOMPARE(obj.value(QLatin1String("sessionID")).toString(), QString("135a32d8-ccfa-11eb-b8bc-0242ac130003")); - QCOMPARE(obj.value(QLatin1String("osType")).toString(), QString("Unknown")); + QCOMPARE(obj.value(QLatin1String("challengeType")).toString(), QString("FooBar")); } @@ -107,22 +107,22 @@ class test_StateGetChallenge auto reply = new MockNetworkReply(); mState->mReply.reset(reply, &QObject::deleteLater); reply->setAttribute(QNetworkRequest::Attribute::HttpStatusCodeAttribute, 500); + reply->setError(QNetworkReply::NetworkError::InternalServerError, QString()); QSignalSpy spyAbort(mState.data(), &StateGetChallenge::fireAbort); - QTest::ignoreMessage(QtDebugMsg, "Network request failed"); mState->onNetworkReply(); QCOMPARE(spyAbort.count(), 1); - QCOMPARE(mState->getContext()->getStatus(), GlobalStatus::Code::Workflow_Server_Incomplete_Information_Provided); + QCOMPARE(mState->getContext()->getStatus().getStatusCode(), GlobalStatus::Code::Workflow_TrustedChannel_Server_Error); const FailureCode::FailureInfoMap infoMap { {FailureCode::Info::State_Name, "StateGetChallenge"}, {FailureCode::Info::Http_Status_Code, QString::number(500)}, {FailureCode::Info::Network_Error, "Unknown error"} }; - const FailureCode failureCode(FailureCode::Reason::Generic_Provider_Communication_Network_Error, infoMap); - QCOMPARE(mState->getContext()->getFailureCode() == failureCode, true); - QVERIFY(mState->getContext()->getFailureCode()->getFailureInfoMap() == infoMap); + const FailureCode failureCode(FailureCode::Reason::Generic_Provider_Communication_Server_Error, infoMap); + QCOMPARE(mState->getContext()->getFailureCode(), failureCode); + QCOMPARE(mState->getContext()->getFailureCode()->getFailureInfoMap(), infoMap); QVERIFY(mContext->getChallenge().isEmpty()); } diff --git a/test/qt/workflows/personalization/test_StateGetServiceInformation.cpp b/test/qt/workflows/personalization/test_StateGetServiceInformation.cpp new file mode 100644 index 000000000..a3f89e4a7 --- /dev/null +++ b/test/qt/workflows/personalization/test_StateGetServiceInformation.cpp @@ -0,0 +1,95 @@ +/** + * Copyright (c) 2022-2023 Governikus GmbH & Co. KG, Germany + */ + +#include "states/StateGetServiceInformation.h" + +#include "LogHandler.h" +#include "ReaderManager.h" +#include "context/PersonalizationContext.h" + +#include "mock/eid_applet_interface_mock.h" + +#include + +#include + + +Q_DECLARE_LOGGING_CATEGORY(network) + + +using namespace governikus; + + +class test_StateGetServiceInformation + : public QObject +{ + Q_OBJECT + + QSharedPointer mContext; + + private Q_SLOTS: + void initTestCase() + { + const auto readerManager = Env::getSingleton(); + QSignalSpy spy(readerManager, &ReaderManager::fireInitialized); + readerManager->init(); + QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations + } + + + void cleanupTestCase() + { + Env::getSingleton()->shutdown(); + } + + + void init() + { + Env::getSingleton()->init(); + mContext = QSharedPointer::create(QString()); + } + + + void fail() + { + StateGetServiceInformation state(mContext); + QSignalSpy spyAbort(&state, &StateGetServiceInformation::fireAbort); + QSignalSpy spyContinue(&state, &StateGetServiceInformation::fireContinue); + + setServiceInformation({EidServiceResult::ERROR}); + QTest::ignoreMessage(QtWarningMsg, QRegularExpression("ServiceInformation query failed")); + state.run(); + + QTRY_COMPARE(spyAbort.size(), 1); // clazy:exclude=qstring-allocations + QCOMPARE(spyContinue.size(), 0); + QCOMPARE(mContext->getStatus(), GlobalStatus::Code::Workflow_Smart_eID_ServiceInformation_Query_Failed); + QCOMPARE(mContext->getSmartEidType(), SmartEidType::UNKNOWN); + QCOMPARE(mContext->getChallengeType(), QString()); + } + + + void success() + { + setSmartEidStatus(EidStatus::NO_PERSONALIZATION); + setServiceInformation({EidServiceResult::SUCCESS, SmartEidType::APPLET, std::string("UUID")}); + + StateGetServiceInformation state(mContext); + QSignalSpy spyAbort(&state, &StateGetServiceInformation::fireAbort); + QSignalSpy spyContinue(&state, &StateGetServiceInformation::fireContinue); + QSignalSpy logSpy(Env::getSingleton()->getEventHandler(), &LogEventHandler::fireLog); + + state.run(); + + QTRY_COMPARE(spyContinue.size(), 1); // clazy:exclude=qstring-allocations + QCOMPARE(spyAbort.size(), 0); + QCOMPARE(mContext->getStatus(), GlobalStatus::Code::No_Error); + QCOMPARE(mContext->getSmartEidType(), SmartEidType::APPLET); + QCOMPARE(mContext->getChallengeType(), QString("UUID")); + } + + +}; + +QTEST_GUILESS_MAIN(test_StateGetServiceInformation) +#include "test_StateGetServiceInformation.moc" diff --git a/test/qt/workflows/personalization/test_StateGetSessionId.cpp b/test/qt/workflows/personalization/test_StateGetSessionId.cpp index afa33a93b..1237d28ee 100644 --- a/test/qt/workflows/personalization/test_StateGetSessionId.cpp +++ b/test/qt/workflows/personalization/test_StateGetSessionId.cpp @@ -28,8 +28,7 @@ class test_StateGetSessionId void init() { mContext = QSharedPointer::create(QString()); - mState.reset(new StateGetSessionId(mContext)); - mState->setStateName("StateGetSessionId"); + mState.reset(StateBuilder::createState(mContext)); QVERIFY(mContext->getSessionIdentifier().isNull()); } @@ -53,31 +52,34 @@ class test_StateGetSessionId void test_OnNetworkReplyNoValidData_data() { QTest::addColumn("data"); + QTest::addColumn("logMsg"); - QTest::newRow("empty") << QByteArray(); + QTest::newRow("empty") << QByteArray() << QString("JSON parsing failed: \"illegal value\""); QTest::newRow("empty object") << QByteArray(R"({ - })"); + })") << QString("No valid sessionID to prepare personalization"); QTest::newRow("wrong sessionID type") << QByteArray(R"({ "sessionID": 0 - })"); + })") << QString("No valid sessionID to prepare personalization"); QTest::newRow("wrong sessionID value") << QByteArray(R"({ "sessionID": "HelloWorld!" - })"); + })") << QString("No valid sessionID to prepare personalization"); } void test_OnNetworkReplyNoValidData() { QFETCH(QByteArray, data); + QFETCH(QString, logMsg); mState->mReply.reset(new MockNetworkReply(data), &QObject::deleteLater); QSignalSpy spyAbort(mState.data(), &StateGetSessionId::fireAbort); - QTest::ignoreMessage(QtDebugMsg, "No valid sessionID to prepare personalization"); + const auto bytes = logMsg.toUtf8(); + QTest::ignoreMessage(QtDebugMsg, bytes.data()); mState->onNetworkReply(); QCOMPARE(spyAbort.count(), 1); - QCOMPARE(mState->getContext()->getStatus(), GlobalStatus::Code::Workflow_Server_Incomplete_Information_Provided); + QCOMPARE(mState->getContext()->getStatus(), GlobalStatus::Code::Workflow_Smart_eID_Authentication_Failed); QCOMPARE(mState->getContext()->getFailureCode(), FailureCode::Reason::Get_Session_Id_Invalid); QVERIFY(mContext->getSessionIdentifier().isNull()); } @@ -93,6 +95,10 @@ class test_StateGetSessionId QTest::newRow("without curly braces") << QByteArray(R"({ "sessionID": "135a32d8-ccfa-11eb-b8bc-0242ac130003" })"); + QTest::newRow("additional data") << QByteArray(R"({ + "statusCode": 0, + "sessionID": "{135a32d8-ccfa-11eb-b8bc-0242ac130003}" + })"); } @@ -101,6 +107,7 @@ class test_StateGetSessionId QFETCH(QByteArray, data); mState->mReply.reset(new MockNetworkReply(data), &QObject::deleteLater); + QSignalSpy logSpy(Env::getSingleton()->getEventHandler(), &LogEventHandler::fireLog); QSignalSpy spyContinue(mState.data(), &StateGetSessionId::fireContinue); mState->onNetworkReply(); @@ -114,21 +121,21 @@ class test_StateGetSessionId auto reply = new MockNetworkReply(); mState->mReply.reset(reply, &QObject::deleteLater); reply->setAttribute(QNetworkRequest::Attribute::HttpStatusCodeAttribute, 500); + reply->setError(QNetworkReply::NetworkError::InternalServerError, QString()); QSignalSpy spyAbort(mState.data(), &StateGetSessionId::fireAbort); - QTest::ignoreMessage(QtDebugMsg, "Network request failed"); mState->onNetworkReply(); QCOMPARE(spyAbort.count(), 1); - QCOMPARE(mState->getContext()->getStatus(), GlobalStatus::Code::Workflow_Server_Incomplete_Information_Provided); + QCOMPARE(mState->getContext()->getStatus().getStatusCode(), GlobalStatus::Code::Workflow_TrustedChannel_Server_Error); const FailureCode::FailureInfoMap infoMap { {FailureCode::Info::State_Name, "StateGetSessionId"}, {FailureCode::Info::Http_Status_Code, QString::number(500)}, {FailureCode::Info::Network_Error, "Unknown error"} }; - const FailureCode failureCode(FailureCode::Reason::Generic_Provider_Communication_Network_Error, infoMap); - QCOMPARE(mState->getContext()->getFailureCode() == failureCode, true); - QVERIFY(mState->getContext()->getFailureCode()->getFailureInfoMap() == infoMap); + const FailureCode failureCode(FailureCode::Reason::Generic_Provider_Communication_Server_Error, infoMap); + QCOMPARE(mState->getContext()->getFailureCode(), failureCode); + QCOMPARE(mState->getContext()->getFailureCode()->getFailureInfoMap(), infoMap); QVERIFY(mContext->getSessionIdentifier().isNull()); } diff --git a/test/qt/workflows/personalization/test_StateInitializePersonalization.cpp b/test/qt/workflows/personalization/test_StateInitializePersonalization.cpp index c3fc09103..c161192a6 100644 --- a/test/qt/workflows/personalization/test_StateInitializePersonalization.cpp +++ b/test/qt/workflows/personalization/test_StateInitializePersonalization.cpp @@ -6,6 +6,7 @@ #include "LogHandler.h" #include "ReaderManager.h" +#include "SmartManager.h" #include "context/PersonalizationContext.h" #include "mock/eid_applet_interface_mock.h" @@ -32,8 +33,9 @@ class test_StateInitializePersonalization void initTestCase() { const auto readerManager = Env::getSingleton(); + QSignalSpy spy(readerManager, &ReaderManager::fireInitialized); readerManager->init(); - readerManager->isScanRunning(); // just to wait until initialization finished + QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations } @@ -50,6 +52,12 @@ class test_StateInitializePersonalization } + void cleanup() + { + SmartManager::releaseConnection(); + } + + void fail() { StateInitializePersonalization state(mContext); @@ -64,13 +72,33 @@ class test_StateInitializePersonalization QCOMPARE(spyContinue.size(), 0); QCOMPARE(mContext->getStatus(), GlobalStatus::Code::Workflow_Smart_eID_PrePersonalization_Failed); QCOMPARE(mContext->getFailureCode(), FailureCode::Reason::Initialize_Personalization_Failed); + + QCOMPARE(dequeueReceivedParameter(), QString()); + QCOMPARE(dequeueReceivedParameter(), QString()); + } + + + void success_data() + { + QTest::addColumn("type"); + QTest::addColumn("pin"); + + QTest::newRow("UNKNOWN") << SmartEidType::UNKNOWN << QString(); + QTest::newRow("APPLET") << SmartEidType::APPLET << QString(); + QTest::newRow("NON_APPLET") << SmartEidType::NON_APPLET << QString("123456"); } void success() { + QFETCH(SmartEidType, type); + QFETCH(QString, pin); + setSmartEidStatus(EidStatus::NO_PERSONALIZATION); setInitializePersonalizationResult({EidServiceResult::SUCCESS, std::string("data containing the PIN when Smart-eID is of type HWKeyStore")}); + mContext->setServiceInformation(type, QString(), QString()); + mContext->setNewPin(QString("123456")); + mContext->setChallenge(QString("FooBar")); StateInitializePersonalization state(mContext); QSignalSpy spyAbort(&state, &StateInitializePersonalization::fireAbort); @@ -88,6 +116,9 @@ class test_StateInitializePersonalization { QVERIFY(!entry.at(0).toString().contains(QLatin1String("data containing the PIN"))); } + + QCOMPARE(dequeueReceivedParameter(), QString("FooBar")); + QCOMPARE(dequeueReceivedParameter(), pin); } diff --git a/test/qt/workflows/personalization/test_StateInstallApplet.cpp b/test/qt/workflows/personalization/test_StateInstallApplet.cpp new file mode 100644 index 000000000..a53b6f6ac --- /dev/null +++ b/test/qt/workflows/personalization/test_StateInstallApplet.cpp @@ -0,0 +1,139 @@ +/** + * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany + */ + +#include "states/StateInstallApplet.h" + +#include "ReaderManager.h" +#include "context/PersonalizationContext.h" + +#include "mock/eid_applet_interface_mock.h" + +#include +#include + + +using namespace governikus; + + +Q_DECLARE_METATYPE(EidServiceResult) +Q_DECLARE_METATYPE(std::optional) + + +class test_StateInstallApplet + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void initTestCase() + { + const auto readerManager = Env::getSingleton(); + QSignalSpy spy(readerManager, &ReaderManager::fireInitialized); + readerManager->init(); + QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations + } + + + void cleanupTestCase() + { + Env::getSingleton()->shutdown(); + } + + + void init() + { + initMock(); + } + + + void run_data() + { + QTest::addColumn("installResult"); + QTest::addColumn("logEntries"); + QTest::addColumn("statusCode"); + QTest::addColumn>("failureCode"); + + QTest::addRow("SUCCESS") + << EidServiceResult::SUCCESS + << QStringList {"Successfully installed Smart-eID"} + << GlobalStatus::Code::No_Error + << std::optional(); + QTest::addRow("ERROR") + << EidServiceResult::ERROR + << QStringList {"Installation of Smart-eID failed"} + << GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed + << std::optional(FailureCode::Reason::Install_Smart_Service_Response_Fail); + QTest::addRow("UNSUPPORTED") + << EidServiceResult::UNSUPPORTED + << QStringList {"Installation of Smart-eID failed"} + << GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed + << std::optional(FailureCode::Reason::Install_Smart_Service_Response_Unsupported); + QTest::addRow("NFC_NOT_ACTIVATED") + << EidServiceResult::NFC_NOT_ACTIVATED + << QStringList {"Installation of Smart-eID failed"} + << GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed + << std::optional(FailureCode::Reason::Install_Smart_Service_Response_Nfc_Disabled); + QTest::addRow("OVERLOAD_PROTECTION") + << EidServiceResult::OVERLOAD_PROTECTION + << QStringList {"Installation of Smart-eID failed"} + << GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed + << std::optional(FailureCode::Reason::Install_Smart_Service_Response_Overload); + QTest::addRow("UNDER_MAINTENANCE") + << EidServiceResult::UNDER_MAINTENANCE + << QStringList {"Installation of Smart-eID failed"} + << GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed + << std::optional(FailureCode::Reason::Install_Smart_Service_Response_Maintenance); + QTest::addRow("INTEGRITY_CHECK_FAILED") + << EidServiceResult::INTEGRITY_CHECK_FAILED + << QStringList {"Installation of Smart-eID failed"} + << GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed + << std::optional(FailureCode::Reason::Install_Smart_Service_Response_Integrity_Check_Failed); + QTest::addRow("NOT_AUTHENTICATED") + << EidServiceResult::NOT_AUTHENTICATED + << QStringList {"Installation of Smart-eID failed"} + << GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed + << std::optional(FailureCode::Reason::Install_Smart_Service_Response_Not_Authenticated); + } + + + void run() + { + QFETCH(EidServiceResult, installResult); + QFETCH(QStringList, logEntries); + QFETCH(GlobalStatus::Code, statusCode); + QFETCH(std::optional, failureCode); + + setInstallSmartEidResult(installResult); + + auto context = QSharedPointer::create(QString()); + + StateInstallApplet state(context); + QSignalSpy spyAbort(&state, &StateInstallApplet::fireAbort); + QSignalSpy spyContinue(&state, &StateInstallApplet::fireContinue); + + for (const auto& log : std::as_const(logEntries)) + { + QTest::ignoreMessage(QtDebugMsg, log.toUtf8().data()); + } + state.run(); + + if (statusCode == GlobalStatus::Code::No_Error) + { + QTRY_COMPARE(spyContinue.size(), 1); // clazy:exclude=qstring-allocations + QCOMPARE(spyAbort.size(), 0); + } + else + { + QTRY_COMPARE(spyAbort.size(), 1); // clazy:exclude=qstring-allocations + QCOMPARE(spyContinue.size(), 0); + } + QCOMPARE(context->getStatus(), statusCode); + QCOMPARE(context->getFailureCode(), failureCode); + } + + +}; + +QTEST_GUILESS_MAIN(test_StateInstallApplet) +#include "test_StateInstallApplet.moc" diff --git a/test/qt/workflows/personalization/test_StatePrepareApplet.cpp b/test/qt/workflows/personalization/test_StatePrepareApplet.cpp deleted file mode 100644 index 0427ded71..000000000 --- a/test/qt/workflows/personalization/test_StatePrepareApplet.cpp +++ /dev/null @@ -1,202 +0,0 @@ -/** - * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany - */ - -#include "states/StatePrepareApplet.h" - -#include "ReaderManager.h" -#include "SmartManager.h" -#include "context/PersonalizationContext.h" -#include "paos/retrieve/TransmitParser.h" - -#include "TestFileHelper.h" -#include "mock/eid_applet_interface_mock.h" - -#include - -#include - - -Q_DECLARE_LOGGING_CATEGORY(network) - - -using namespace governikus; - - -class test_StatePrepareApplet - : public QObject -{ - Q_OBJECT - - private Q_SLOTS: - void initTestCase() - { - const auto readerManager = Env::getSingleton(); - readerManager->init(); - readerManager->isScanRunning(); // just to wait until initialization finished - } - - - void cleanupTestCase() - { - Env::getSingleton()->shutdown(); - } - - - void run_data() - { - QTest::addColumn("status"); - QTest::addColumn("updateInfo"); - QTest::addColumn("result"); - QTest::addColumn("logEntries"); - QTest::addColumn>("failureCode"); - - QTest::newRow("unavailable") - << EidStatus::UNAVAILABLE << EidUpdateInfo::UP_TO_DATE << EidServiceResult::SUCCESS - << QStringList("Smart-eID is not available on this device") << std::optional(FailureCode::Reason::Prepare_Applet_Unavailable); - - QTest::newRow("no_provisioning - success") - << EidStatus::NO_PROVISIONING << EidUpdateInfo::UP_TO_DATE << EidServiceResult::SUCCESS - << QStringList("Successfully installed Smart-eID") << std::optional(); - QTest::newRow("no_provisioning - fail") - << EidStatus::NO_PROVISIONING << EidUpdateInfo::UP_TO_DATE << EidServiceResult::ERROR - << QStringList("Installation of Smart-eID failed") << std::optional(FailureCode::Reason::Prepare_Applet_Installation_Failed); - - QTest::newRow("no_personalization - internal_error") - << EidStatus::NO_PERSONALIZATION << EidUpdateInfo::INTERNAL_ERROR << EidServiceResult::SUCCESS - << QStringList("updateInfo() failed") << std::optional(FailureCode::Reason::Prepare_Applet_UpdateInfo_Call_Failed); - QTest::newRow("no_personalization - up_to_data") - << EidStatus::NO_PERSONALIZATION << EidUpdateInfo::UP_TO_DATE << EidServiceResult::SUCCESS - << QStringList("No update available") << std::optional(); - QTest::newRow("no_personalization - unavailable") - << EidStatus::NO_PERSONALIZATION << EidUpdateInfo::UNAVAILABLE << EidServiceResult::SUCCESS - << QStringList("No update available") << std::optional(); - QTest::newRow("no_personalization - no_provisioning") - << EidStatus::NO_PERSONALIZATION << EidUpdateInfo::NO_PROVISIONING << EidServiceResult::SUCCESS - << QStringList("No update available") << std::optional(); - QTest::newRow("no_personalization - update_available - success") - << EidStatus::NO_PERSONALIZATION << EidUpdateInfo::UPDATE_AVAILABLE << EidServiceResult::SUCCESS - << QStringList({"Update available, delete the Smart-eID first", "Successfully deleted Smart-eID"}) << std::optional(); - QTest::newRow("no_personalization - update_available - fail") - << EidStatus::NO_PERSONALIZATION << EidUpdateInfo::UPDATE_AVAILABLE << EidServiceResult::ERROR - << QStringList({"Update available, delete the Smart-eID first", "Deletion of Smart-eID failed"}) << std::optional(FailureCode::Reason::Prepare_Applet_Delete_Smart_Failed); - - QTest::newRow("applet_unusable - success") - << EidStatus::APPLET_UNUSABLE << EidUpdateInfo::UP_TO_DATE << EidServiceResult::SUCCESS - << QStringList("Successfully deleted Smart-eID") << std::optional(); - QTest::newRow("applet_unusable - fail") - << EidStatus::APPLET_UNUSABLE << EidUpdateInfo::UP_TO_DATE << EidServiceResult::ERROR - << QStringList("Deletion of Smart-eID failed") << std::optional(FailureCode::Reason::Prepare_Applet_Delete_Smart_Failed); - - QTest::newRow("personalized - fail") - << EidStatus::PERSONALIZED << EidUpdateInfo::UP_TO_DATE << EidServiceResult::ERROR - << QStringList("Deletion of Smart-eID personalization failed") << std::optional(FailureCode::Reason::Prepare_Applet_Delete_Personalization_Failed); - QTest::newRow("personalized - internal_error") - << EidStatus::PERSONALIZED << EidUpdateInfo::INTERNAL_ERROR << EidServiceResult::SUCCESS - << QStringList({"Successfully deleted the Smart-eID personalization", "updateInfo() failed"}) << std::optional(FailureCode::Reason::Prepare_Applet_UpdateInfo_Call_Failed); - QTest::newRow("personalized - up_to_data") - << EidStatus::PERSONALIZED << EidUpdateInfo::UP_TO_DATE << EidServiceResult::SUCCESS - << QStringList({"Successfully deleted the Smart-eID personalization", "No update available"}) << std::optional(); - QTest::newRow("personalized - unavailable") - << EidStatus::PERSONALIZED << EidUpdateInfo::UNAVAILABLE << EidServiceResult::SUCCESS - << QStringList({"Successfully deleted the Smart-eID personalization", "No update available"}) << std::optional(); - QTest::newRow("personalized - no_provisioning") - << EidStatus::PERSONALIZED << EidUpdateInfo::NO_PROVISIONING << EidServiceResult::SUCCESS - << QStringList({"Successfully deleted the Smart-eID personalization", "No update available"}) << std::optional(); - QTest::newRow("personalized - update_available") - << EidStatus::PERSONALIZED << EidUpdateInfo::UPDATE_AVAILABLE << EidServiceResult::SUCCESS - << QStringList({"Successfully deleted the Smart-eID personalization", "Update available, delete the Smart-eID first", "Successfully deleted Smart-eID"}) << std::optional(); - - QTest::newRow("internal_error") - << EidStatus::INTERNAL_ERROR << EidUpdateInfo::UP_TO_DATE << EidServiceResult::SUCCESS - << QStringList("getSmartEidStatus() failed") << std::optional(FailureCode::Reason::Prepare_Applet_Status_Call_Failed); - } - - - void run() - { - QFETCH(EidStatus, status); - QFETCH(EidUpdateInfo, updateInfo); - QFETCH(EidServiceResult, result); - QFETCH(QStringList, logEntries); - QFETCH(std::optional, failureCode); - - setSmartEidStatus(status); - setUpdateInfo(updateInfo); - setInstallSmartEidResult(result); - setDeletePersonalizationResult(result); - setDeleteSmartEidResult(result); - - auto context = QSharedPointer::create(QString()); - - StatePrepareApplet state(context); - QSignalSpy spyAbort(&state, &StatePrepareApplet::fireAbort); - QSignalSpy spyContinue(&state, &StatePrepareApplet::fireContinue); - - for (const auto& log : std::as_const(logEntries)) - { - QTest::ignoreMessage(QtDebugMsg, log.toUtf8().data()); - } - state.run(); - - if (failureCode.has_value()) - { - QTRY_COMPARE(spyAbort.size(), 1); // clazy:exclude=qstring-allocations - QCOMPARE(spyContinue.size(), 0); - QCOMPARE(context->getStatus(), GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed); - QCOMPARE(context->getFailureCode(), failureCode); - } - else - { - QTRY_COMPARE(spyContinue.size(), 1); // clazy:exclude=qstring-allocations - QCOMPARE(spyAbort.size(), 0); - QCOMPARE(context->getStatus(), GlobalStatus::Code::No_Error); - } - } - - - void progress_data() - { - QTest::addColumn("initial"); - QTest::addColumn("max"); - QTest::addColumn("progress"); - QTest::addColumn("expected"); - - QTest::newRow("full_10") << 0 << 100 << 10 << 10; - QTest::newRow("full_50") << 0 << 100 << 50 << 50; - QTest::newRow("full_99") << 0 << 100 << 99 << 99; - QTest::newRow("full_100") << 0 << 100 << 100 << 100; - - QTest::newRow("first_half_10") << 0 << 50 << 10 << 5; - QTest::newRow("first_half_50") << 0 << 50 << 50 << 25; - QTest::newRow("first_half_90") << 0 << 50 << 90 << 45; - QTest::newRow("first_half_100") << 0 << 50 << 100 << 50; - - QTest::newRow("second_half_10") << 50 << 100 << 10 << 55; - QTest::newRow("second_half_50") << 50 << 100 << 50 << 75; - QTest::newRow("second_half_90") << 50 << 100 << 90 << 95; - QTest::newRow("second_half_100") << 50 << 100 << 100 << 100; - } - - - void progress() - { - QFETCH(int, initial); - QFETCH(int, max); - QFETCH(int, progress); - QFETCH(int, expected); - - auto context = QSharedPointer::create(QString()); - QSignalSpy spy(context.get(), &WorkflowContext::fireProgressChanged); - - StatePrepareApplet state(context); - state.setProgress(progress, QStringLiteral("dummy"), initial, max); - QCOMPARE(spy.count(), 1); - QCOMPARE(context->getProgressValue(), expected); - } - - -}; - -QTEST_GUILESS_MAIN(test_StatePrepareApplet) -#include "test_StatePrepareApplet.moc" diff --git a/test/qt/workflows/personalization/test_StatePreparePersonalization.cpp b/test/qt/workflows/personalization/test_StatePreparePersonalization.cpp index e85692b01..c71f7184a 100644 --- a/test/qt/workflows/personalization/test_StatePreparePersonalization.cpp +++ b/test/qt/workflows/personalization/test_StatePreparePersonalization.cpp @@ -38,8 +38,7 @@ class test_StatePreparePersonalization { Env::getSingleton()->init(); mContext.reset(new PersonalizationContext(QStringLiteral("https://dummy/%1"))); - mState.reset(new StatePreparePersonalization(mContext)); - mState->setStateName("StatePreparePersonalization"); + mState.reset(StateBuilder::createState(mContext)); mNetworkManager.reset(new MockNetworkManager()); Env::set(NetworkManager::staticMetaObject, mNetworkManager.data()); @@ -78,14 +77,80 @@ class test_StatePreparePersonalization } - void test_OnNetworkReplySuccess() + void test_OnNetworkReplyNoValidData() { - mState->mReply.reset(new MockNetworkReply(), &QObject::deleteLater); + const QByteArray data("."); + mState->mReply.reset(new MockNetworkReply(data), &QObject::deleteLater); + + QSignalSpy spyAbort(mState.data(), &StatePreparePersonalization::fireAbort); + + QTest::ignoreMessage(QtDebugMsg, QRegularExpression("No valid network response")); + mState->onNetworkReply(); + QCOMPARE(spyAbort.count(), 1); + QCOMPARE(mState->getContext()->getStatus(), GlobalStatus::Code::Workflow_Server_Incomplete_Information_Provided); + QCOMPARE(mContext->getFinalizeStatus(), 0); + } + + + void test_OnNetworkReplyValidDataFail() + { + const QByteArray data(R"({ "statusCode": -1 })"); + mState->mReply.reset(new MockNetworkReply(data), &QObject::deleteLater); + + QSignalSpy spyAbort(mState.data(), &StatePreparePersonalization::fireAbort); + + QTest::ignoreMessage(QtWarningMsg, QRegularExpression("preparePersonalization failed with statusCode -1")); + mState->onNetworkReply(); + QCOMPARE(spyAbort.count(), 1); + QCOMPARE(mContext->getFinalizeStatus(), -1); + } + + + void test_OnNetworkReplyValidData() + { + const QByteArray data(R"({ "statusCode": 1 })"); + mState->mReply.reset(new MockNetworkReply(data), &QObject::deleteLater); + + QSignalSpy logSpy(Env::getSingleton()->getEventHandler(), &LogEventHandler::fireLog); QSignalSpy spyContinue(mState.data(), &StatePreparePersonalization::fireContinue); mState->onNetworkReply(); + const QString logMsg(logSpy.takeLast().at(0).toString()); + QVERIFY(logMsg.contains("preparePersonalization finished with statusCode 1")); QCOMPARE(spyContinue.count(), 1); - QCOMPARE(mState->getContext()->getStatus(), GlobalStatus::Code::No_Error); + QCOMPARE(mContext->getFinalizeStatus(), 1); + } + + + void test_OnNetworkReplyWrongStatusCode() + { + const QByteArray data(R"({ "statusCode": -2 })"); + mState->mReply.reset(new MockNetworkReply(data), &QObject::deleteLater); + + QSignalSpy spyAbort(mState.data(), &StatePreparePersonalization::fireAbort); + + QTest::ignoreMessage(QtWarningMsg, QRegularExpression("preparePersonalization failed with statusCode -2")); + mState->onNetworkReply(); + QCOMPARE(spyAbort.count(), 1); + QCOMPARE(mState->getContext()->getStatus(), GlobalStatus::Code::Workflow_Smart_eID_PrePersonalization_Failed); + QCOMPARE(mState->getContext()->getFailureCode(), FailureCode::Reason::Smart_PrePersonalization_Wrong_Status); + QCOMPARE(mContext->getFinalizeStatus(), -2); + } + + + void test_OnNetworkReplyWrongContent() + { + const QByteArray data(R"({ "fooBar": 1 })"); + mState->mReply.reset(new MockNetworkReply(data), &QObject::deleteLater); + + QSignalSpy spyAbort(mState.data(), &StatePreparePersonalization::fireAbort); + + QTest::ignoreMessage(QtDebugMsg, QRegularExpression("JSON parsing failed: statusCode is missing")); + mState->onNetworkReply(); + QCOMPARE(spyAbort.count(), 1); + QCOMPARE(mState->getContext()->getStatus(), GlobalStatus::Code::Workflow_Server_Incomplete_Information_Provided); + QCOMPARE(mState->getContext()->getFailureCode(), FailureCode::Reason::Smart_PrePersonalization_Incomplete_Information); + QCOMPARE(mContext->getFinalizeStatus(), 0); } @@ -94,21 +159,22 @@ class test_StatePreparePersonalization auto reply = new MockNetworkReply(); mState->mReply.reset(reply, &QObject::deleteLater); reply->setAttribute(QNetworkRequest::Attribute::HttpStatusCodeAttribute, 500); + reply->setError(QNetworkReply::NetworkError::InternalServerError, QString()); QSignalSpy spyAbort(mState.data(), &StatePreparePersonalization::fireAbort); - QTest::ignoreMessage(QtDebugMsg, QRegularExpression("Network request failed")); mState->onNetworkReply(); QCOMPARE(spyAbort.count(), 1); - QCOMPARE(mState->getContext()->getStatus(), GlobalStatus::Code::Workflow_Server_Incomplete_Information_Provided); + QCOMPARE(mState->getContext()->getStatus().getStatusCode(), GlobalStatus::Code::Workflow_TrustedChannel_Server_Error); const FailureCode::FailureInfoMap infoMap { {FailureCode::Info::State_Name, "StatePreparePersonalization"}, {FailureCode::Info::Http_Status_Code, QString::number(500)}, {FailureCode::Info::Network_Error, "Unknown error"} }; - const FailureCode failureCode(FailureCode::Reason::Generic_Provider_Communication_Network_Error, infoMap); - QCOMPARE(mState->getContext()->getFailureCode() == failureCode, true); - QVERIFY(mState->getContext()->getFailureCode()->getFailureInfoMap() == infoMap); + const FailureCode failureCode(FailureCode::Reason::Generic_Provider_Communication_Server_Error, infoMap); + QCOMPARE(mState->getContext()->getFailureCode(), failureCode); + QCOMPARE(mState->getContext()->getFailureCode()->getFailureInfoMap(), infoMap); + QCOMPARE(mContext->getFinalizeStatus(), 0); } @@ -116,9 +182,8 @@ class test_StatePreparePersonalization { mContext->setSessionIdentifier(QUuid("135a32d8-ccfa-11eb-b8bc-0242ac130003")); mContext->setPreparePersonalizationData(QString("data containing the PIN when Smart-eID is of type HWKeyStore")); - mState->setStateName(QStringLiteral("StatePreparePersonalization")); mState->onEntry(nullptr); - mNetworkManager->setNextReply(new MockNetworkReply(QByteArrayLiteral("TEST"))); + mNetworkManager->setNextReply(new MockNetworkReply(QByteArrayLiteral(R"({ "statusCode": 1 })"))); QSignalSpy logSpy(Env::getSingleton()->getEventHandler(), &LogEventHandler::fireLog); diff --git a/test/qt/workflows/personalization/test_StateStartPaosPersonalizationResponse.cpp b/test/qt/workflows/personalization/test_StateStartPaosPersonalizationResponse.cpp new file mode 100644 index 000000000..c375d67b7 --- /dev/null +++ b/test/qt/workflows/personalization/test_StateStartPaosPersonalizationResponse.cpp @@ -0,0 +1,161 @@ +/** + * Copyright (c) 2022-2023 Governikus GmbH & Co. KG, Germany + */ + +#include "TestFileHelper.h" +#include "context/PersonalizationContext.h" +#include "states/StateStartPaosPersonalizationResponse.h" + +#include +#include + + +using namespace governikus; + + +Q_DECLARE_METATYPE(std::optional) + + +class test_StateStartPaosPersonalizationResponse + : public QObject +{ + Q_OBJECT + + private: + QByteArray createResult(const QByteArray& pMajor, const QByteArray& pMinor = QByteArray()) + { + const QByteArray resultMajor = "http://www.bsi.bund.de/ecard/api/1.1/resultmajor#" + pMajor + ""; + QByteArray resultMinor; + + if (!pMinor.isEmpty()) + { + resultMinor = "http://www.bsi.bund.de/ecard/api/1.1/resultminor/" + pMinor + ""; + } + + return "" + resultMajor + resultMinor + ""; + } + + + QByteArray createOutputs(int pFinalizeStatus, const QByteArray& pRemainingDays, const QByteArray& pRemainingAttempts = QByteArray(), const QByteArray& pBlockingCode = QByteArray()) + { + QByteArray outputs = "" + QByteArray::number(pFinalizeStatus) + ""; + outputs += "" + pRemainingDays + ""; + + if (!pRemainingAttempts.isEmpty()) + { + outputs += "" + pRemainingAttempts + ""; + } + + if (!pBlockingCode.isEmpty()) + { + outputs += "" + pBlockingCode + ""; + } + + return R"( + + + )" + outputs + R"( + + + )"; + } + + private Q_SLOTS: + void noPaosResponse() + { + auto context = QSharedPointer::create(QString()); + StateStartPaosPersonalizationResponse state(context); + + QSignalSpy spy(&state, &StateStartPaosPersonalizationResponse::fireAbort); + state.run(); + QCOMPARE(context->getFailureCode(), FailureCode::Reason::Start_Paos_Response_Personalization_Empty); + QCOMPARE(spy.count(), 1); + } + + + void testPersonalization_data() + { + const auto& dateFormat = "d. MMMM yyyy"; + + QTest::addColumn("finalizeStatus"); + QTest::addColumn("restrictionDate"); + QTest::addColumn("remainingAttempts"); + QTest::addColumn("blockingCode"); + QTest::addColumn("resultMajor"); + QTest::addColumn("resultMinor"); + QTest::addColumn("statusCode"); + QTest::addColumn>("failureCode"); + QTest::addColumn("resultContent"); + QTest::addColumn("outputsContent"); + + QTest::addRow("Success") << 1 << QDate::currentDate().addDays(30).toString(dateFormat) << 9 << "LASTWAGEN" + << ECardApiResult::Major::Ok << ECardApiResult::Minor::null + << GlobalStatus::Code::No_Error + << std::optional() + << createResult("ok") << createOutputs(1, "30", "9", "LASTWAGEN"); + QTest::addRow("Failure - resultMinor missing") << 2 << QDate::currentDate().addDays(13).toString(dateFormat) << -1 << "" + << ECardApiResult::Major::Error << ECardApiResult::Minor::null + << GlobalStatus::Code::Paos_Error_AL_Unknown_Error + << std::optional(FailureCode::Reason::Start_Paos_Response_Personalization_Invalid) + << createResult("error") << createOutputs(2, "-13"); + QTest::addRow("No Permission") << -3 << QDate::currentDate().addDays(13).toString(dateFormat) << -1 << "" + << ECardApiResult::Major::Error << ECardApiResult::Minor::AL_No_Permission + << GlobalStatus::Code::Workflow_Smart_eID_Personalization_Denied + << std::optional(FailureCode::Reason::Start_Paos_Response_Personalization_Invalid) + << createResult("error", "al/common#noPermission") << createOutputs(-3, "-13"); + QTest::addRow("No OptionalOutputs") << 0 << QDate::currentDate().addDays(1).toString(dateFormat) << -1 << "" + << ECardApiResult::Major::Error << ECardApiResult::Minor::null + << GlobalStatus::Code::Paos_Error_AL_Unknown_Error + << std::optional(FailureCode::Reason::Start_Paos_Response_Personalization_Invalid) + << createResult("error", "al#noPermission") << QByteArray(); + } + + + void testPersonalization() + { + QFETCH(int, finalizeStatus); + QFETCH(QString, restrictionDate); + QFETCH(int, remainingAttempts); + QFETCH(QString, blockingCode); + QFETCH(ECardApiResult::Major, resultMajor); + QFETCH(ECardApiResult::Minor, resultMinor); + QFETCH(GlobalStatus::Code, statusCode); + QFETCH(std::optional, failureCode); + QFETCH(QByteArray, resultContent); + QFETCH(QByteArray, outputsContent); + + QByteArray content = TestFileHelper::readFile(":/paos/StartPAOSResponse_template.xml"); + content.replace("", resultContent); + content.replace("", outputsContent); + + auto context = QSharedPointer::create(QString()); + context->setStartPaosResponse(QSharedPointer::create(content)); + + StateStartPaosPersonalizationResponse state(context); + QSignalSpy spyAbort(&state, &StateStartPaosPersonalizationResponse::fireAbort); + QSignalSpy spyContinue(&state, &StateStartPaosPersonalizationResponse::fireContinue); + state.run(); + + QCOMPARE(context->getFinalizeStatus(), finalizeStatus); + QCOMPARE(context->getRestrictionDate(), restrictionDate); + QCOMPARE(context->getRemainingAttempts(), remainingAttempts); + QCOMPARE(context->getBlockingCode(), blockingCode); + QCOMPARE(context->getStartPaosResult().getMajor(), resultMajor); + QCOMPARE(context->getStartPaosResult().getMinor(), resultMinor); + QCOMPARE(context->getStatus().getStatusCode(), statusCode); + QCOMPARE(context->getFailureCode(), failureCode); + if (resultMajor == ECardApiResult::Major::Ok) + { + QCOMPARE(spyContinue.count(), 1); + } + else + { + QCOMPARE(spyAbort.count(), 1); + } + } + + +}; + +QTEST_GUILESS_MAIN(test_StateStartPaosPersonalizationResponse) +#include "test_StateStartPaosPersonalizationResponse.moc" diff --git a/test/qt/workflows/personalization/test_StateTransmitPersonalization.cpp b/test/qt/workflows/personalization/test_StateTransmitPersonalization.cpp index 3ffd51655..3e5208fac 100644 --- a/test/qt/workflows/personalization/test_StateTransmitPersonalization.cpp +++ b/test/qt/workflows/personalization/test_StateTransmitPersonalization.cpp @@ -33,8 +33,9 @@ class test_StateTransmitPersonalization void initTestCase() { const auto readerManager = Env::getSingleton(); + QSignalSpy spy(readerManager, &ReaderManager::fireInitialized); readerManager->init(); - readerManager->isScanRunning(); // just to wait until initialization finished + QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations } @@ -101,11 +102,7 @@ class test_StateTransmitPersonalization QSignalSpy spyAbort(&state, &StateTransmitPersonalization::fireAbort); QSignalSpy spyContinue(&state, &StateTransmitPersonalization::fireContinue); -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) QTest::ignoreMessage(QtWarningMsg, "Transmit unsuccessful. StatusCode does not start with acceptable status code QList(\"9001\")"); -#else - QTest::ignoreMessage(QtWarningMsg, "Transmit unsuccessful. StatusCode does not start with acceptable status code (\"9001\")"); -#endif state.run(); QTRY_COMPARE(spyAbort.size(), 1); // clazy:exclude=qstring-allocations diff --git a/test/qt/workflows/personalization/test_StateUpdateSupportInfo.cpp b/test/qt/workflows/personalization/test_StateUpdateSupportInfo.cpp new file mode 100644 index 000000000..c020c7e67 --- /dev/null +++ b/test/qt/workflows/personalization/test_StateUpdateSupportInfo.cpp @@ -0,0 +1,163 @@ +/** + * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany + */ + +#include "states/StateUpdateSupportInfo.h" + +#include "ReaderManager.h" +#include "context/PersonalizationContext.h" + +#include "mock/eid_applet_interface_mock.h" + +#include +#include + + +using namespace governikus; + + +Q_DECLARE_METATYPE(EidSupportStatusResult) +Q_DECLARE_METATYPE(std::optional) + + +class test_StateUpdateSupportInfo + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void initTestCase() + { + const auto readerManager = Env::getSingleton(); + QSignalSpy spy(readerManager, &ReaderManager::fireInitialized); + readerManager->init(); + QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations + } + + + void cleanupTestCase() + { + Env::getSingleton()->shutdown(); + } + + + void init() + { + initMock(); + } + + + void run_data() + { + QTest::addColumn("updateSupportInfo"); + QTest::addColumn("logEntry"); + QTest::addColumn("statusCode"); + QTest::addColumn>("failureCode"); + QTest::addColumn("signal"); + + // EidServiceResult tests + QTest::addRow("ERROR") + << EidSupportStatusResult {EidServiceResult::ERROR, EidSupportStatus::AVAILABLE} + << QString("updateSupportInfo() failed with \"ERROR\" 0x33000000") + << GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed + << std::optional(FailureCode::Reason::Update_Support_Info_Service_Response_Fail) + << SIGNAL(fireAbort(const FailureCode&)); + QTest::addRow("UNSUPPORTED") + << EidSupportStatusResult {EidServiceResult::UNSUPPORTED, EidSupportStatus::AVAILABLE} + << QString("updateSupportInfo() failed with \"UNSUPPORTED\" 0x34000000") + << GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed + << std::optional(FailureCode::Reason::Update_Support_Info_Service_Response_Unsupported) + << SIGNAL(fireAbort(const FailureCode&)); + QTest::addRow("OVERLOAD_PROTECTION") + << EidSupportStatusResult {EidServiceResult::OVERLOAD_PROTECTION, EidSupportStatus::AVAILABLE} + << QString("updateSupportInfo() failed with \"OVERLOAD_PROTECTION\" 0x35000000") + << GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed + << std::optional(FailureCode::Reason::Update_Support_Info_Service_Response_Overload) + << SIGNAL(fireAbort(const FailureCode&)); + QTest::addRow("UNDER_MAINTENANCE") + << EidSupportStatusResult {EidServiceResult::UNDER_MAINTENANCE, EidSupportStatus::AVAILABLE} + << QString("updateSupportInfo() failed with \"UNDER_MAINTENANCE\" 0x36000000") + << GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed + << std::optional(FailureCode::Reason::Update_Support_Info_Service_Response_Maintenance) + << SIGNAL(fireAbort(const FailureCode&)); + QTest::addRow("NFC_NOT_ACTIVATED") + << EidSupportStatusResult {EidServiceResult::NFC_NOT_ACTIVATED, EidSupportStatus::AVAILABLE} + << QString("updateSupportInfo() failed with \"NFC_NOT_ACTIVATED\" 0x37000000") + << GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed + << std::optional(FailureCode::Reason::Update_Support_Info_Service_Response_Nfc_Disabled) + << SIGNAL(fireAbort(const FailureCode&)); + QTest::addRow("INTEGRITY_CHECK_FAILED") + << EidSupportStatusResult {EidServiceResult::INTEGRITY_CHECK_FAILED, EidSupportStatus::AVAILABLE} + << QString("updateSupportInfo() failed with \"INTEGRITY_CHECK_FAILED\" 0x38000000") + << GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed + << std::optional(FailureCode::Reason::Update_Support_Info_Service_Response_Integrity_Check_Failed) + << SIGNAL(fireAbort(const FailureCode&)); + QTest::addRow("NOT_AUTHENTICATED") + << EidSupportStatusResult {EidServiceResult::NOT_AUTHENTICATED, EidSupportStatus::AVAILABLE} + << QString("updateSupportInfo() failed with \"NOT_AUTHENTICATED\" 0x39000000") + << GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed + << std::optional(FailureCode::Reason::Update_Support_Info_Service_Response_Not_Authenticated) + << SIGNAL(fireAbort(const FailureCode&)); + + // EidSupportStatus tests + QTest::addRow("UNAVAILABLE") + << EidSupportStatusResult {EidServiceResult::SUCCESS, EidSupportStatus::UNAVAILABLE} + << QString("getSmartEidSupportInfo() finished with result \"SUCCESS\" 0x0 and status \"UNAVAILABLE\" 0x400010") + << GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed + << std::optional(FailureCode::Reason::Update_Support_Info_Call_Failed) + << SIGNAL(fireAbort(const FailureCode&)); + QTest::addRow("AVAILABLE") + << EidSupportStatusResult {EidServiceResult::SUCCESS, EidSupportStatus::AVAILABLE} + << QString("getSmartEidSupportInfo() finished with result \"SUCCESS\" 0x0 and status \"AVAILABLE\" 0x400020") + << GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed + << std::optional(FailureCode::Reason::Update_Support_Info_Call_Failed) + << SIGNAL(fireAbort(const FailureCode&)); + QTest::addRow("UP_TO_DATE") + << EidSupportStatusResult {EidServiceResult::SUCCESS, EidSupportStatus::UP_TO_DATE} + << QString("getSmartEidSupportInfo() finished with result \"SUCCESS\" 0x0 and status \"UP_TO_DATE\" 0x400040") + << GlobalStatus::Code::No_Error + << std::optional() + << SIGNAL(fireContinue()); + QTest::addRow("UPDATE_AVAILABLE") + << EidSupportStatusResult {EidServiceResult::SUCCESS, EidSupportStatus::UPDATE_AVAILABLE} + << QString("getSmartEidSupportInfo() finished with result \"SUCCESS\" 0x0 and status \"UPDATE_AVAILABLE\" 0x400030") + << GlobalStatus::Code::No_Error + << std::optional() + << SIGNAL(fireUpdateAvailable()); + QTest::addRow("INTERNAL_ERROR") + << EidSupportStatusResult {EidServiceResult::SUCCESS, EidSupportStatus::INTERNAL_ERROR} + << QString("getSmartEidSupportInfo() finished with result \"SUCCESS\" 0x0 and status \"INTERNAL_ERROR\" 0x2100000") + << GlobalStatus::Code::Workflow_Smart_eID_Applet_Preparation_Failed + << std::optional(FailureCode::Reason::Update_Support_Info_Call_Failed) + << SIGNAL(fireAbort(const FailureCode&)); + } + + + void run() + { + QFETCH(EidSupportStatusResult, updateSupportInfo); + QFETCH(QString, logEntry); + QFETCH(GlobalStatus::Code, statusCode); + QFETCH(std::optional, failureCode); + QFETCH(QString, signal); + + setSmartEidSupportStatusResult(updateSupportInfo); + + auto context = QSharedPointer::create(QString()); + + StateUpdateSupportInfo state(context); + QSignalSpy spy(&state, qPrintable(signal)); + + QTest::ignoreMessage(QtDebugMsg, logEntry.toUtf8().data()); + state.run(); + + QTRY_COMPARE(spy.size(), 1); // clazy:exclude=qstring-allocations + QCOMPARE(context->getStatus(), statusCode); + QCOMPARE(context->getFailureCode(), failureCode); + } + + +}; + +QTEST_GUILESS_MAIN(test_StateUpdateSupportInfo) +#include "test_StateUpdateSupportInfo.moc" diff --git a/test/qt/workflows/states/test_StateCertificateDescriptionCheck.cpp b/test/qt/workflows/states/test_StateCertificateDescriptionCheck.cpp index 5462d1328..8dd8296ca 100644 --- a/test/qt/workflows/states/test_StateCertificateDescriptionCheck.cpp +++ b/test/qt/workflows/states/test_StateCertificateDescriptionCheck.cpp @@ -29,11 +29,10 @@ class test_StateCertificateDescriptionCheck private Q_SLOTS: void init() { - mAuthContext.reset(new TestAuthContext(nullptr, ":/paos/DIDAuthenticateEAC1.xml")); + mAuthContext.reset(new TestAuthContext(":/paos/DIDAuthenticateEAC1.xml")); mAuthContext->setTcTokenUrl(QUrl("https://test.governikus-eid.de:443/Autent-DemoApplication/RequestServlet?provider=demo_epa_can&redirect=true")); mState.reset(StateBuilder::createState(mAuthContext)); - mState->setStateName("StateCertificateDescriptionCheck"); mState->onEntry(nullptr); } diff --git a/test/qt/workflows/states/test_StateCheckRefreshAddress.cpp b/test/qt/workflows/states/test_StateCheckRefreshAddress.cpp index 04f8c15dc..671bce082 100644 --- a/test/qt/workflows/states/test_StateCheckRefreshAddress.cpp +++ b/test/qt/workflows/states/test_StateCheckRefreshAddress.cpp @@ -52,7 +52,7 @@ class test_StateCheckRefreshAddress mMockNetworkManager.reset(new MockNetworkManager()); Env::set(NetworkManager::staticMetaObject, mMockNetworkManager.data()); - mAuthContext.reset(new AuthContext(nullptr)); + mAuthContext.reset(new AuthContext()); mState.reset(StateBuilder::createState(mAuthContext)); mState->onEntry(nullptr); } @@ -260,20 +260,24 @@ class test_StateCheckRefreshAddress { QTest::addColumn("networkError"); QTest::addColumn("status"); + QTest::addColumn("failureCode"); QTest::addColumn("statusCode"); QTest::addColumn("redirectUrl"); QTest::addColumn("developerMode"); - QTest::newRow("service unavailable") << QNetworkReply::NetworkError::ServiceUnavailableError << GlobalStatus::Code::Network_ServiceUnavailable << 1 << QUrl("http://governikus.com/") << false; - QTest::newRow("timeout") << QNetworkReply::NetworkError::TimeoutError << GlobalStatus::Code::Network_TimeOut << 2 << QUrl() << false; - QTest::newRow("proxy error") << QNetworkReply::NetworkError::ProxyNotFoundError << GlobalStatus::Code::Network_Proxy_Error << 0 << QUrl("test") << false; - QTest::newRow("ssl error") << QNetworkReply::NetworkError::SslHandshakeFailedError << GlobalStatus::Code::Network_Ssl_Establishment_Error << 1 << QUrl("https://governikus.com/") << false; - QTest::newRow("other error") << QNetworkReply::NetworkError::OperationCanceledError << GlobalStatus::Code::Network_Other_Error << 2 << QUrl("https://governikus.com/") << false; - QTest::newRow("no error unexpected status") << QNetworkReply::NetworkError::NoError << GlobalStatus::Code::Workflow_Network_Expected_Redirect << 2 << QUrl("https://governikus.com/") << false; - QTest::newRow("no error empty url") << QNetworkReply::NetworkError::NoError << GlobalStatus::Code::Workflow_Network_Empty_Redirect_Url << 302 << QUrl() << false; - QTest::newRow("no error invalid url") << QNetworkReply::NetworkError::NoError << GlobalStatus::Code::Workflow_Network_Malformed_Redirect_Url << 302 << QUrl("://://") << false; - QTest::newRow("no error http") << QNetworkReply::NetworkError::NoError << GlobalStatus::Code::Workflow_Network_Invalid_Scheme << 302 << QUrl("http://governikus.com/") << false; - QTest::newRow("no error http developer mode") << QNetworkReply::NetworkError::NoError << GlobalStatus::Code::No_Error << 302 << QUrl("http://governikus.com/") << true; + QTest::newRow("http service unavailable") << QNetworkReply::NetworkError::ServiceUnavailableError << GlobalStatus::Code::Network_ServiceUnavailable << FailureCode::Reason::Check_Refresh_Address_Service_Unavailable << 503 << QUrl("http://governikus.com/") << false; + QTest::newRow("http internal server error") << QNetworkReply::NetworkError::InternalServerError << GlobalStatus::Code::Network_ServerError << FailureCode::Reason::Check_Refresh_Address_Server_Error << 500 << QUrl("http://governikus.com/") << false; + QTest::newRow("http not found") << QNetworkReply::NetworkError::ContentNotFoundError << GlobalStatus::Code::Network_ClientError << FailureCode::Reason::Check_Refresh_Address_Client_Error << 404 << QUrl("https://governikus.com/") << false; + QTest::newRow("http other error") << QNetworkReply::NetworkError::ProtocolUnknownError << GlobalStatus::Code::Network_Other_Error << FailureCode::Reason::Check_Refresh_Address_Unknown_Network_Error << 304 << QUrl("http://governikus.com/") << false; + QTest::newRow("timeout") << QNetworkReply::NetworkError::TimeoutError << GlobalStatus::Code::Network_TimeOut << FailureCode::Reason::Check_Refresh_Address_Service_Timeout << 2 << QUrl() << false; + QTest::newRow("proxy error") << QNetworkReply::NetworkError::ProxyNotFoundError << GlobalStatus::Code::Network_Proxy_Error << FailureCode::Reason::Check_Refresh_Address_Proxy_Error << 0 << QUrl("test") << false; + QTest::newRow("ssl error") << QNetworkReply::NetworkError::SslHandshakeFailedError << GlobalStatus::Code::Network_Ssl_Establishment_Error << FailureCode::Reason::Check_Refresh_Address_Fatal_Tls_Error_After_Reply << 1 << QUrl("https://governikus.com/") << false; + QTest::newRow("other error") << QNetworkReply::NetworkError::OperationCanceledError << GlobalStatus::Code::Network_Other_Error << FailureCode::Reason::Check_Refresh_Address_Unknown_Network_Error << 2 << QUrl("https://governikus.com/") << false; + QTest::newRow("no error unexpected status") << QNetworkReply::NetworkError::NoError << GlobalStatus::Code::Workflow_Network_Expected_Redirect << FailureCode::Reason::Check_Refresh_Address_Invalid_Http_Response << 2 << QUrl("https://governikus.com/") << false; + QTest::newRow("no error empty url") << QNetworkReply::NetworkError::NoError << GlobalStatus::Code::Workflow_Network_Empty_Redirect_Url << FailureCode::Reason::Check_Refresh_Address_Empty << 302 << QUrl() << false; + QTest::newRow("no error invalid url") << QNetworkReply::NetworkError::NoError << GlobalStatus::Code::Workflow_Network_Malformed_Redirect_Url << FailureCode::Reason::Check_Refresh_Address_Invalid_Url << 302 << QUrl("://://") << false; + QTest::newRow("no error http") << QNetworkReply::NetworkError::NoError << GlobalStatus::Code::Workflow_Network_Invalid_Scheme << FailureCode::Reason::Check_Refresh_Address_No_Https_Scheme << 302 << QUrl("http://governikus.com/") << false; + QTest::newRow("no error http developer mode") << QNetworkReply::NetworkError::NoError << GlobalStatus::Code::No_Error << FailureCode::Reason::Check_Refresh_Address_No_Https_Scheme << 302 << QUrl("http://governikus.com/") << true; } @@ -281,6 +285,7 @@ class test_StateCheckRefreshAddress { QFETCH(QNetworkReply::NetworkError, networkError); QFETCH(GlobalStatus::Code, status); + QFETCH(FailureCode::Reason, failureCode); QFETCH(int, statusCode); QFETCH(QUrl, redirectUrl); QFETCH(bool, developerMode); @@ -303,6 +308,7 @@ class test_StateCheckRefreshAddress if (!developerMode) { QCOMPARE(mAuthContext->getStatus().getStatusCode(), status); + QCOMPARE(mAuthContext->getFailureCode(), failureCode); } } diff --git a/test/qt/workflows/states/test_StateConnectCard.cpp b/test/qt/workflows/states/test_StateConnectCard.cpp index e2bb26285..40b0037e0 100644 --- a/test/qt/workflows/states/test_StateConnectCard.cpp +++ b/test/qt/workflows/states/test_StateConnectCard.cpp @@ -26,6 +26,27 @@ class test_StateConnectCard QSharedPointer mContext; ReaderInfo mReaderInfo; + private: + QSharedPointer createCardConnection(QThread& workerThread) + { + QSharedPointer connectionWorker(new MockCardConnectionWorker()); + connectionWorker->moveToThread(&workerThread); + return QSharedPointer(new CardConnection(connectionWorker)); + } + + + QSharedPointer createCardConnectionCommand(const QString& readerName, QSharedPointer cardConnection = nullptr) + { + const QSharedPointer command(new CreateCardConnectionCommand(readerName, QPointer())); + + if (cardConnection) + { + command->mCardConnection = cardConnection; + } + + return command; + } + private Q_SLOTS: void initTestCase() { @@ -61,25 +82,20 @@ class test_StateConnectCard workerThread.start(); const QString rName("reader name"); - const QSharedPointer command(new CreateCardConnectionCommand(rName, QPointer())); QSignalSpy spyContinue(mState.data(), &StateConnectCard::fireContinue); QSignalSpy spyAbort(mState.data(), &StateConnectCard::fireAbort); QTest::ignoreMessage(QtDebugMsg, "Card connection command completed"); QTest::ignoreMessage(QtDebugMsg, "Card connection failed"); - mState->onCommandDone(command); + mState->onCommandDone(createCardConnectionCommand(rName)); QCOMPARE(spyAbort.count(), 1); QCOMPARE(mState->getContext()->getFailureCode(), FailureCode::Reason::Connect_Card_Connection_Failed); - QSharedPointer connectionWorker(new MockCardConnectionWorker()); - connectionWorker->moveToThread(&workerThread); - QSharedPointer cardConnection(new CardConnection(connectionWorker)); - command->mCardConnection = cardConnection; - QTest::ignoreMessage(QtDebugMsg, "Card connection command completed"); QTest::ignoreMessage(QtDebugMsg, "Card connection was successful"); - mState->onCommandDone(command); + const auto& cardConnection = createCardConnection(workerThread); + mState->onCommandDone(createCardConnectionCommand(rName, cardConnection)); QCOMPARE(mContext->getCardConnection(), cardConnection); QCOMPARE(spyContinue.count(), 1); @@ -88,25 +104,40 @@ class test_StateConnectCard } - void test_OnReaderRemoved() + void test_onUnusableCardConnectionLost() { + QThread workerThread; + workerThread.start(); + const auto info = ReaderInfo(QStringLiteral("name")); + const auto cardConnection = createCardConnection(workerThread); QSignalSpy spy(mState.data(), &StateConnectCard::fireRetry); - mState->onReaderRemoved(info); + mState->onUnusableCardConnectionLost(info); QCOMPARE(spy.count(), 0); mContext->setReaderName(info.getName()); - mState->onReaderRemoved(info); + mContext->setCardConnection(cardConnection); + + mState->onUnusableCardConnectionLost(ReaderInfo(QStringLiteral("anotherReader"))); + QCOMPARE(spy.count(), 0); + QCOMPARE(mContext->getReaderName(), info.getName()); + QCOMPARE(mContext->getCardConnection(), cardConnection); + + mState->onUnusableCardConnectionLost(info); QCOMPARE(spy.count(), 1); + QVERIFY(mContext->getReaderName().isEmpty()); + QVERIFY(mContext->getCardConnection().isNull()); + + workerThread.quit(); + workerThread.wait(); } void test_OnEntry() { - const QString stateName("name"); - mState->setStateName(stateName); + mState->setObjectName(QStringLiteral("dummyStateName")); QSignalSpy spyRetry(mState.data(), &StateConnectCard::fireRetry); diff --git a/test/qt/workflows/states/test_StateDidAuthenticateEac1.cpp b/test/qt/workflows/states/test_StateDidAuthenticateEac1.cpp index 9b0dd3668..c13098bc0 100644 --- a/test/qt/workflows/states/test_StateDidAuthenticateEac1.cpp +++ b/test/qt/workflows/states/test_StateDidAuthenticateEac1.cpp @@ -46,7 +46,7 @@ class test_StateDidAuthenticateEac1 private Q_SLOTS: void init() { - mAuthContext.reset(new TestAuthContext(nullptr, ":/paos/DIDAuthenticateEAC1.xml")); + mAuthContext.reset(new TestAuthContext(":/paos/DIDAuthenticateEAC1.xml")); } diff --git a/test/qt/workflows/states/test_StateDidAuthenticateEac2.cpp b/test/qt/workflows/states/test_StateDidAuthenticateEac2.cpp index dbf065222..814cd8dc2 100644 --- a/test/qt/workflows/states/test_StateDidAuthenticateEac2.cpp +++ b/test/qt/workflows/states/test_StateDidAuthenticateEac2.cpp @@ -50,7 +50,7 @@ class test_StateDidAuthenticateEac2 private Q_SLOTS: void init() { - mAuthContext.reset(new TestAuthContext(nullptr, ":/paos/DIDAuthenticateEAC1.xml")); + mAuthContext.reset(new TestAuthContext(":/paos/DIDAuthenticateEAC1.xml")); mState.reset(new StateDidAuthenticateEac2(mAuthContext)); workerThread.start(); } diff --git a/test/qt/workflows/states/test_StateEnterPacePassword.cpp b/test/qt/workflows/states/test_StateEnterPacePassword.cpp index 1d0d43b94..3d7b922d2 100644 --- a/test/qt/workflows/states/test_StateEnterPacePassword.cpp +++ b/test/qt/workflows/states/test_StateEnterPacePassword.cpp @@ -21,7 +21,7 @@ class test_StateEnterPacePassword private Q_SLOTS: void init() { - mAuthContext.reset(new TestAuthContext(nullptr, ":/paos/DIDAuthenticateEAC1.xml")); + mAuthContext.reset(new TestAuthContext(":/paos/DIDAuthenticateEAC1.xml")); mState.reset(new StateEnterPacePassword(mAuthContext)); } diff --git a/test/qt/workflows/states/test_StateEstablishPaceChannel.cpp b/test/qt/workflows/states/test_StateEstablishPaceChannel.cpp index 270835dac..5cbb88be3 100644 --- a/test/qt/workflows/states/test_StateEstablishPaceChannel.cpp +++ b/test/qt/workflows/states/test_StateEstablishPaceChannel.cpp @@ -60,9 +60,8 @@ class test_StateEstablishPaceChannel void init() { mWorkerThread.start(); - mAuthContext.reset(new TestAuthContext(nullptr, ":/paos/DIDAuthenticateEAC1.xml")); - mState.reset(new StateEstablishPaceChannel(mAuthContext)); - mState->setStateName("StateEstablishPaceChannel"); + mAuthContext.reset(new TestAuthContext(":/paos/DIDAuthenticateEAC1.xml")); + mState.reset(StateBuilder::createState(mAuthContext)); } @@ -87,23 +86,40 @@ class test_StateEstablishPaceChannel } + void test_Run_data() + { + QTest::addColumn("initialProgress"); + + QTest::newRow("0") << 0; + QTest::newRow("42") << 42; + QTest::newRow("50") << 42; + QTest::newRow("90") << 90; + QTest::newRow("100") << 100; + } + + void test_Run() { + QFETCH(int, initialProgress); + const QSharedPointer worker(new MockCardConnectionWorker()); worker->moveToThread(&mWorkerThread); const QSharedPointer connection(new CardConnection(worker)); const QString password("0000000"); + mAuthContext->setPin(password); mAuthContext->setCardConnection(connection); mAuthContext->setEstablishPaceChannelType(PacePasswordId::PACE_PIN); - QCOMPARE(mAuthContext->getProgressValue(), 0); + mAuthContext->setProgress(initialProgress, QString()); + QCOMPARE(mAuthContext->getProgressValue(), initialProgress); QCOMPARE(mAuthContext->getProgressMessage(), QString()); + QTest::ignoreMessage(QtDebugMsg, "Establish connection using PACE_PIN"); mState->run(); QCOMPARE(mAuthContext->getEstablishPaceChannelType(), PacePasswordId::PACE_PIN); QCOMPARE(mState->mPasswordId, PacePasswordId::PACE_PIN); - QCOMPARE(mAuthContext->getProgressValue(), 0); + QCOMPARE(mAuthContext->getProgressValue(), initialProgress); QCOMPARE(mAuthContext->getProgressMessage(), tr("The secure channel is opened")); } @@ -124,7 +140,6 @@ class test_StateEstablishPaceChannel { QSignalSpy spyAbort(mState.data(), &AbstractState::fireAbort); QSignalSpy spyPaceChannelFailed(mState.data(), &StateEstablishPaceChannel::firePaceChannelFailed); - mState->setStateName("StateEstablishPaceChannel"); mState->onEntry(nullptr); QCOMPARE(spyAbort.count(), 0); QCOMPARE(spyPaceChannelFailed.count(), 0); diff --git a/test/qt/workflows/states/test_StateExtractCvcsFromEac1InputType.cpp b/test/qt/workflows/states/test_StateExtractCvcsFromEac1InputType.cpp index e0c5958dc..5680d6c22 100644 --- a/test/qt/workflows/states/test_StateExtractCvcsFromEac1InputType.cpp +++ b/test/qt/workflows/states/test_StateExtractCvcsFromEac1InputType.cpp @@ -46,10 +46,9 @@ class test_StateExtractCvcsFromEac1InputType void init() { - mAuthContext.reset(new TestAuthContext(nullptr, ":/paos/DIDAuthenticateEAC1_3.xml")); + mAuthContext.reset(new TestAuthContext(":/paos/DIDAuthenticateEAC1_3.xml")); mState.reset(StateBuilder::createState(mAuthContext)); - mState->setStateName("StateExtractCvcsFromEac1InputType"); mAuthContext->clearCvCertificates(); mState->onEntry(nullptr); diff --git a/test/qt/workflows/states/test_StateGenericProviderCommunication.cpp b/test/qt/workflows/states/test_StateGenericProviderCommunication.cpp index dfed18a54..f75e9618d 100644 --- a/test/qt/workflows/states/test_StateGenericProviderCommunication.cpp +++ b/test/qt/workflows/states/test_StateGenericProviderCommunication.cpp @@ -63,9 +63,8 @@ class test_StateGenericProviderCommunication private Q_SLOTS: void init() { - mContext.reset(new AuthContext(QSharedPointer())); - mState.reset(new StateGenericProviderCommunicationImpl(mContext)); - mState->setStateName("StateGenericProviderCommunicationImpl"); + mContext.reset(new AuthContext()); + mState.reset(StateBuilder::createState(mContext)); mState->onEntry(nullptr); mNetworkManager.reset(new MockNetworkManager()); @@ -209,6 +208,57 @@ class test_StateGenericProviderCommunication } + void test_OnNetworkReplyWrongHttpStatus_data() + { + QTest::addColumn("networkError"); + QTest::addColumn("httpStatus"); + QTest::addColumn("globalStatusCode"); + QTest::addColumn("failureCodeReason"); + + QTest::addRow("503") << QNetworkReply::NetworkError::ServiceUnavailableError << 503 << GlobalStatus::Code::Workflow_TrustedChannel_ServiceUnavailable << FailureCode::Reason::Generic_Provider_Communication_ServiceUnavailable; + QTest::addRow("500") << QNetworkReply::NetworkError::InternalServerError << 500 << GlobalStatus::Code::Workflow_TrustedChannel_Server_Error << FailureCode::Reason::Generic_Provider_Communication_Server_Error; + QTest::addRow("400") << QNetworkReply::NetworkError::ProtocolInvalidOperationError << 400 << GlobalStatus::Code::Workflow_TrustedChannel_Client_Error << FailureCode::Reason::Generic_Provider_Communication_Client_Error; + QTest::addRow("404") << QNetworkReply::NetworkError::ContentNotFoundError << 404 << GlobalStatus::Code::Workflow_TrustedChannel_Client_Error << FailureCode::Reason::Generic_Provider_Communication_Client_Error; + QTest::addRow("302") << QNetworkReply::NetworkError::ProtocolUnknownError << 302 << GlobalStatus::Code::Workflow_TrustedChannel_Other_Network_Error << FailureCode::Reason::Generic_Provider_Communication_Network_Error; + QTest::addRow("200") << QNetworkReply::NetworkError::NoError << 200 << GlobalStatus::Code::No_Error << FailureCode::Reason::Generic_Provider_Communication_Network_Error; + } + + + void test_OnNetworkReplyWrongHttpStatus() + { + QFETCH(QNetworkReply::NetworkError, networkError); + QFETCH(int, httpStatus); + QFETCH(GlobalStatus::Code, globalStatusCode); + QFETCH(FailureCode::Reason, failureCodeReason); + + auto reply = new MockNetworkReply(); + mState->mReply.reset(reply, &QObject::deleteLater); + reply->setAttribute(QNetworkRequest::Attribute::HttpStatusCodeAttribute, httpStatus); + reply->setError(networkError, QString()); + + QSignalSpy spyAbort(mState.data(), &StateGetSelfAuthenticationData::fireAbort); + + mState->onNetworkReply(); + + if (networkError == QNetworkReply::NetworkError::NoError) + { + QCOMPARE(spyAbort.count(), 0); + QCOMPARE(mState->getContext()->getStatus().getStatusCode(), globalStatusCode); + return; + } + QCOMPARE(spyAbort.count(), 1); + QCOMPARE(mState->getContext()->getStatus().getStatusCode(), globalStatusCode); + const FailureCode::FailureInfoMap infoMap { + {FailureCode::Info::State_Name, "StateGenericProviderCommunicationImpl"}, + {FailureCode::Info::Http_Status_Code, QString::number(httpStatus)}, + {FailureCode::Info::Network_Error, "Unknown error"} + }; + const FailureCode failureCode(failureCodeReason, infoMap); + QCOMPARE(mState->getContext()->getFailureCode(), failureCode); + QVERIFY(mState->getContext()->getFailureCode()->getFailureInfoMap() == infoMap); + } + + }; QTEST_GUILESS_MAIN(test_StateGenericProviderCommunication) diff --git a/test/qt/workflows/states/test_StateGenericSendReceive.cpp b/test/qt/workflows/states/test_StateGenericSendReceive.cpp index 8e63c08ab..0cc30342b 100644 --- a/test/qt/workflows/states/test_StateGenericSendReceive.cpp +++ b/test/qt/workflows/states/test_StateGenericSendReceive.cpp @@ -36,7 +36,7 @@ class test_StateGenericSendReceive private Q_SLOTS: void init() { - mAuthContext.reset(new TestAuthContext(nullptr, ":/paos/DIDAuthenticateEAC1.xml")); + mAuthContext.reset(new TestAuthContext(":/paos/DIDAuthenticateEAC1.xml")); QSharedPointer tcToken(new TcToken(TestFileHelper::readFile(":/tctoken/ok.xml"))); mAuthContext->setTcToken(tcToken); @@ -44,7 +44,6 @@ class test_StateGenericSendReceive Env::set(NetworkManager::staticMetaObject, mNetworkManager.data()); mState.reset(StateBuilder::createState(mAuthContext)); - mState->setStateName("StateSendInitializeFrameworkResponse"); mState->onEntry(nullptr); } @@ -253,7 +252,7 @@ class test_StateGenericSendReceive { const QVector states = QVector() << GlobalStatus::Code::Workflow_TrustedChannel_Establishment_Error - << GlobalStatus::Code::Workflow_TrustedChannel_Error_From_Server + << GlobalStatus::Code::Workflow_TrustedChannel_Server_Error << GlobalStatus::Code::Workflow_TrustedChannel_Hash_Not_In_Description << GlobalStatus::Code::Workflow_TrustedChannel_No_Data_Received << GlobalStatus::Code::Workflow_TrustedChannel_Ssl_Certificate_Unsupported_Algorithm_Or_Length @@ -346,6 +345,40 @@ class test_StateGenericSendReceive } + void onReplyFinishedError_data() + { + QTest::addColumn("networkError"); + QTest::addColumn("globalStatus"); + QTest::addColumn("failureCode"); + QTest::addColumn("httpCode"); + + QTest::addRow("http service unavailable") << QNetworkReply::ServiceUnavailableError << GlobalStatus::Code::Workflow_TrustedChannel_ServiceUnavailable << FailureCode::Reason::Generic_Send_Receive_Service_Unavailable << 503; + QTest::addRow("http server error") << QNetworkReply::InternalServerError << GlobalStatus::Code::Workflow_TrustedChannel_Server_Error << FailureCode::Reason::Generic_Send_Receive_Server_Error << 500; + QTest::addRow("http not found") << QNetworkReply::ContentNotFoundError << GlobalStatus::Code::Workflow_TrustedChannel_Client_Error << FailureCode::Reason::Generic_Send_Receive_Client_Error << 404; + QTest::addRow("http other error") << QNetworkReply::ProtocolUnknownError << GlobalStatus::Code::Workflow_TrustedChannel_Other_Network_Error << FailureCode::Reason::Generic_Send_Receive_Network_Error << 301; + } + + + void onReplyFinishedError() + { + QFETCH(QNetworkReply::NetworkError, networkError); + QFETCH(GlobalStatus::Code, globalStatus); + QFETCH(FailureCode::Reason, failureCode); + QFETCH(int, httpCode); + + auto reply = QSharedPointer::create(); + reply->setAttribute(QNetworkRequest::HttpStatusCodeAttribute, QVariant(httpCode)); + reply->setError(networkError, QString()); + mState->mReply = reply; + + mState->onReplyFinished(); + + QCOMPARE(mAuthContext->getStatus().getStatusCode(), globalStatus); + QVERIFY(mAuthContext->getFailureCode().has_value()); + QCOMPARE(mAuthContext->getFailureCode().value().getReason(), failureCode); + } + + }; QTEST_GUILESS_MAIN(test_StateGenericSendReceive) diff --git a/test/qt/workflows/states/test_StateGetSelfAuthenticationData.cpp b/test/qt/workflows/states/test_StateGetSelfAuthenticationData.cpp index b39b6b754..d58a1cc25 100644 --- a/test/qt/workflows/states/test_StateGetSelfAuthenticationData.cpp +++ b/test/qt/workflows/states/test_StateGetSelfAuthenticationData.cpp @@ -29,8 +29,7 @@ class test_StateGetSelfAuthenticationData void init() { mContext.reset(new SelfAuthContext()); - mState.reset(new StateGetSelfAuthenticationData(mContext)); - mState->setStateName("StateGetSelfAuthenticationData"); + mState.reset(StateBuilder::createState(mContext)); } @@ -66,26 +65,51 @@ class test_StateGetSelfAuthenticationData } + void test_OnNetworkReplyWrongHttpStatus_data() + { + QTest::addColumn("networkError"); + QTest::addColumn("httpStatus"); + QTest::addColumn("globalStatusCode"); + QTest::addColumn("failureCodeReason"); + + QTest::addRow("503") << QNetworkReply::NetworkError::ServiceUnavailableError << 503 << GlobalStatus::Code::Workflow_TrustedChannel_ServiceUnavailable << FailureCode::Reason::Generic_Provider_Communication_ServiceUnavailable; + QTest::addRow("500") << QNetworkReply::NetworkError::InternalServerError << 500 << GlobalStatus::Code::Workflow_TrustedChannel_Server_Error << FailureCode::Reason::Generic_Provider_Communication_Server_Error; + QTest::addRow("400") << QNetworkReply::NetworkError::ProtocolInvalidOperationError << 400 << GlobalStatus::Code::Workflow_TrustedChannel_Client_Error << FailureCode::Reason::Generic_Provider_Communication_Client_Error; + QTest::addRow("404") << QNetworkReply::NetworkError::ContentNotFoundError << 404 << GlobalStatus::Code::Workflow_TrustedChannel_Client_Error << FailureCode::Reason::Generic_Provider_Communication_Client_Error; + QTest::addRow("302") << QNetworkReply::NetworkError::ProtocolUnknownError << 302 << GlobalStatus::Code::Workflow_TrustedChannel_Other_Network_Error << FailureCode::Reason::Generic_Provider_Communication_Network_Error; + QTest::addRow("200") << QNetworkReply::NetworkError::NoError << 200 << GlobalStatus::Code::Workflow_Server_Incomplete_Information_Provided << FailureCode::Reason::Get_SelfAuthData_Invalid_Or_Empty; + } + + void test_OnNetworkReplyWrongHttpStatus() { + QFETCH(QNetworkReply::NetworkError, networkError); + QFETCH(int, httpStatus); + QFETCH(GlobalStatus::Code, globalStatusCode); + QFETCH(FailureCode::Reason, failureCodeReason); + auto reply = new MockNetworkReply(); mState->mReply.reset(reply, &QObject::deleteLater); - reply->setAttribute(QNetworkRequest::Attribute::HttpStatusCodeAttribute, 500); + reply->setAttribute(QNetworkRequest::Attribute::HttpStatusCodeAttribute, httpStatus); + reply->setError(networkError, QString()); QSignalSpy spyAbort(mState.data(), &StateGetSelfAuthenticationData::fireAbort); - QTest::ignoreMessage(QtDebugMsg, "Network request failed"); mState->onNetworkReply(); + QCOMPARE(spyAbort.count(), 1); - QCOMPARE(mState->getContext()->getStatus(), GlobalStatus::Code::Workflow_Server_Incomplete_Information_Provided); + QCOMPARE(mState->getContext()->getStatus().getStatusCode(), globalStatusCode); const FailureCode::FailureInfoMap infoMap { {FailureCode::Info::State_Name, "StateGetSelfAuthenticationData"}, - {FailureCode::Info::Http_Status_Code, QString::number(500)}, + {FailureCode::Info::Http_Status_Code, QString::number(httpStatus)}, {FailureCode::Info::Network_Error, "Unknown error"} }; - const FailureCode failureCode(FailureCode::Reason::Generic_Provider_Communication_Network_Error, infoMap); + const FailureCode failureCode(failureCodeReason, infoMap); QCOMPARE(mState->getContext()->getFailureCode(), failureCode); - QVERIFY(mState->getContext()->getFailureCode()->getFailureInfoMap() == infoMap); + if (httpStatus != 200) + { + QVERIFY(mState->getContext()->getFailureCode()->getFailureInfoMap() == infoMap); + } } diff --git a/test/qt/workflows/states/test_StateGetTcToken.cpp b/test/qt/workflows/states/test_StateGetTcToken.cpp index 68e467c0d..7bd1100d7 100644 --- a/test/qt/workflows/states/test_StateGetTcToken.cpp +++ b/test/qt/workflows/states/test_StateGetTcToken.cpp @@ -33,7 +33,7 @@ class test_StateGetTcToken void test_Run() { - const QSharedPointer context(new AuthContext(nullptr)); + const QSharedPointer context(new AuthContext()); StateGetTcToken state(context); const QUrl validUrl(QString("https://a.not.existing.valid.test.url.com")); const QUrl invalidUrl(QString("test")); @@ -54,7 +54,7 @@ class test_StateGetTcToken void test_IsValidRedirectUrl() { - const QSharedPointer context(new AuthContext(nullptr)); + const QSharedPointer context(new AuthContext()); StateGetTcToken state(context); QTest::ignoreMessage(QtCriticalMsg, "Error while connecting to the provider. The server returns an invalid or empty redirect URL."); @@ -71,7 +71,7 @@ class test_StateGetTcToken void test_SendRequest() { - const QSharedPointer context(new AuthContext(nullptr)); + const QSharedPointer context(new AuthContext()); StateGetTcToken state(context); QSignalSpy spyAbort(&state, &StateGetTcToken::fireAbort); @@ -86,7 +86,7 @@ class test_StateGetTcToken void test_ParseTcTokenNoData() { - const QSharedPointer context(new AuthContext(nullptr)); + const QSharedPointer context(new AuthContext()); StateGetTcToken state(context); state.mReply.reset(new MockNetworkReply(), &QObject::deleteLater); QSignalSpy spyAbort(&state, &StateGetTcToken::fireAbort); @@ -113,7 +113,7 @@ class test_StateGetTcToken "
    " ""); - const QSharedPointer context(new AuthContext(nullptr)); + const QSharedPointer context(new AuthContext()); StateGetTcToken state(context); state.mReply.reset(new MockNetworkReply(data), &QObject::deleteLater); QSignalSpy spyContinue(&state, &StateGetTcToken::fireContinue); @@ -129,7 +129,7 @@ class test_StateGetTcToken void test_ParseTcTokenWithDataNoPsk() { const QByteArray data("invalid data"); - const QSharedPointer context(new AuthContext(nullptr)); + const QSharedPointer context(new AuthContext()); StateGetTcToken state(context); state.mReply.reset(new MockNetworkReply(data), &QObject::deleteLater); QSignalSpy spyAbort(&state, &StateGetTcToken::fireAbort); diff --git a/test/qt/workflows/states/test_StateInitializeFramework.cpp b/test/qt/workflows/states/test_StateInitializeFramework.cpp index b02338ee4..fbf121d00 100644 --- a/test/qt/workflows/states/test_StateInitializeFramework.cpp +++ b/test/qt/workflows/states/test_StateInitializeFramework.cpp @@ -29,7 +29,7 @@ class test_StateInitializeFramework private Q_SLOTS: void initTestCase() { - mAuthContext.reset(new AuthContext(nullptr)); + mAuthContext.reset(new AuthContext()); auto fileContent = TestFileHelper::readFile(":/paos/InitializeFramework.xml"); mAuthContext->setInitializeFramework(QSharedPointer(new InitializeFramework(fileContent))); diff --git a/test/qt/workflows/states/test_StatePreVerification.cpp b/test/qt/workflows/states/test_StatePreVerification.cpp index 9e4da35fc..fdf1053aa 100644 --- a/test/qt/workflows/states/test_StatePreVerification.cpp +++ b/test/qt/workflows/states/test_StatePreVerification.cpp @@ -42,12 +42,11 @@ class test_StatePreVerification void init() { AbstractSettings::mTestDir.clear(); - mAuthContext.reset(new TestAuthContext(nullptr, ":/paos/DIDAuthenticateEAC1.xml")); + mAuthContext.reset(new TestAuthContext(":/paos/DIDAuthenticateEAC1.xml")); mAuthContext->initCvcChainBuilder(); - mState.reset(new StatePreVerification(mAuthContext)); - mState->setStateName("StatePreVerification"); + mState.reset(StateBuilder::createState(mAuthContext)); mState->onEntry(nullptr); } @@ -124,12 +123,9 @@ class test_StatePreVerification { const_cast(&mState->mValidationDateTime)->setDate(QDate(2020, 05, 25)); auto signature = mAuthContext->getDidAuthenticateEac1()->getCvCertificates().at(0)->getEcdsaSignature(); -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) - BIGNUM* signaturePart = signature->r; -#else + const BIGNUM* signaturePart = nullptr; ECDSA_SIG_get0(signature, &signaturePart, nullptr); -#endif BN_rand(const_cast(signaturePart), BN_num_bits(signaturePart), 0, 0); QSignalSpy spy(mState.data(), &StatePreVerification::fireAbort); @@ -185,7 +181,7 @@ class test_StatePreVerification settings.removeLinkCertificate(cvc); } - const int expectedCvcaSize = 16; + const int expectedCvcaSize = 17; QCOMPARE(mState->mTrustedCvcas.size(), expectedCvcaSize); const_cast(&mState->mValidationDateTime)->setDate(QDate(2020, 05, 25)); auto& trustedCvcas = const_cast>&>(mState->mTrustedCvcas); diff --git a/test/qt/workflows/states/test_StateProcessCertificatesFromEac2.cpp b/test/qt/workflows/states/test_StateProcessCertificatesFromEac2.cpp index 8768b3b71..593ceb78f 100644 --- a/test/qt/workflows/states/test_StateProcessCertificatesFromEac2.cpp +++ b/test/qt/workflows/states/test_StateProcessCertificatesFromEac2.cpp @@ -43,7 +43,7 @@ class test_StateProcessCertificatesFromEac2 void init() { - mAuthContext.reset(new TestAuthContext(nullptr, ":/paos/DIDAuthenticateEAC1.xml")); + mAuthContext.reset(new TestAuthContext(":/paos/DIDAuthenticateEAC1.xml")); QSharedPointer didAuthEac2(static_cast(DidAuthenticateEac2Parser().parse(TestFileHelper::readFile(":/paos/DIDAuthenticateEAC2.xml")))); mAuthContext->setDidAuthenticateEac2(didAuthEac2); @@ -59,7 +59,6 @@ class test_StateProcessCertificatesFromEac2 mAuthContext->setPaceOutputData(paceOutput); mState.reset(StateBuilder::createState(mAuthContext)); - mState->setStateName("StateProcessCertificatesFromEac2"); mState->onEntry(nullptr); } diff --git a/test/qt/workflows/states/test_StateRedirectBrowser.cpp b/test/qt/workflows/states/test_StateRedirectBrowser.cpp index 2382a2e48..1612608dd 100644 --- a/test/qt/workflows/states/test_StateRedirectBrowser.cpp +++ b/test/qt/workflows/states/test_StateRedirectBrowser.cpp @@ -4,7 +4,6 @@ #include "states/StateRedirectBrowser.h" -#include "MockActivationContext.h" #include "TestFileHelper.h" #include "states/StateBuilder.h" @@ -18,168 +17,44 @@ class test_StateRedirectBrowser : public QObject { Q_OBJECT - QScopedPointer mState; - QSharedPointer mAuthContext; - Q_SIGNALS: - void fireStateStart(QEvent* pEvent); + QSharedPointer getStateRedirectBrowser(AuthContext::BrowserHandler pHandler = AuthContext::BrowserHandler()) + { + const auto& context = QSharedPointer::create(true, QUrl(), pHandler); + QSharedPointer state(StateBuilder::createState(context)); + state->onEntry(nullptr); + return state; + } private Q_SLOTS: - void init() + void noError() { - mAuthContext.reset(new AuthContext(nullptr)); - mState.reset(StateBuilder::createState(mAuthContext)); - mState->onEntry(nullptr); + auto state = getStateRedirectBrowser(); + QSignalSpy spyAbort(state.data(), &StateRedirectBrowser::fireAbort); + QSignalSpy spyContinue(state.data(), &StateRedirectBrowser::fireContinue); + + state->run(); + QCOMPARE(state->getContext()->getStatus(), GlobalStatus::Code::No_Error); + QCOMPARE(spyAbort.count(), 0); + QCOMPARE(spyContinue.count(), 1); } - void cleanup() + void error() { - mAuthContext.clear(); - mState.reset(); - } - - - void tcTokenNotFound_sendErrorPageSuccess() - { - mAuthContext->setTcTokenNotFound(true); - mAuthContext->mActivationContext.reset(new MockActivationContext(true, true, true, true)); - QSignalSpy spy(mState.data(), &StateRedirectBrowser::fireContinue); - - mAuthContext->setStateApproved(); - - QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations - QVERIFY(qobject_cast(mAuthContext->getActivationContext())->isSendErroPageCalled()); - } - - - void tcTokenNotFound_sendErrorPageFailure() - { - mAuthContext->setTcTokenNotFound(true); - mAuthContext->mActivationContext.reset(new MockActivationContext(true, true, false, true, "send error")); - QSignalSpy spy(mState.data(), &StateRedirectBrowser::fireAbort); - - mAuthContext->setStateApproved(); - - QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations - QVERIFY(qobject_cast(mAuthContext->getActivationContext())->isSendErroPageCalled()); - QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Redirect_Browser_Send_Error_Page_Failed); - } - - - void noRefreshUrl_noTcToken_sendErrorPageErrorSuccess() - { - mAuthContext->setTcTokenNotFound(false); - mAuthContext->mActivationContext.reset(new MockActivationContext(true, true, true, true)); - QSignalSpy spy(mState.data(), &StateRedirectBrowser::fireContinue); - - mAuthContext->setStateApproved(); - - QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations - QVERIFY(qobject_cast(mAuthContext->getActivationContext())->isSendErroPageCalled()); - } - - - void noRefreshUrl_noTcToken_sendErrorPageErrorFailure() - { - mAuthContext->setTcTokenNotFound(false); - mAuthContext->mActivationContext.reset(new MockActivationContext(true, true, false, true)); - QSignalSpy spy(mState.data(), &StateRedirectBrowser::fireAbort); - - mAuthContext->setStateApproved(); - - QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations - QVERIFY(qobject_cast(mAuthContext->getActivationContext())->isSendErroPageCalled()); - QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Redirect_Browser_Send_Error_Page_Failed); - } - - - void noRefreshUrl_tcTokenWithoutCommunicationErrorAddress_sendErrorPageErrorSuccess() - { - mAuthContext->setTcTokenNotFound(false); - mAuthContext->setTcToken(QSharedPointer(new TcToken(TestFileHelper::readFile(":/tctoken/withoutCommunicationErrorAddress.xml")))); - mAuthContext->mActivationContext.reset(new MockActivationContext(true, true, true, true)); - QSignalSpy spy(mState.data(), &StateRedirectBrowser::fireContinue); - - mAuthContext->setStateApproved(); - - QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations - QVERIFY(qobject_cast(mAuthContext->getActivationContext())->isSendErroPageCalled()); - } - - - void noRefreshUrl_tcTokenWithoutCommunicationErrorAddress_sendErrorPageErrorFailure() - { - mAuthContext->setTcTokenNotFound(false); - mAuthContext->setTcToken(QSharedPointer(new TcToken(TestFileHelper::readFile(":/tctoken/withoutCommunicationErrorAddress.xml")))); - mAuthContext->mActivationContext.reset(new MockActivationContext(true, true, false, true)); - QSignalSpy spy(mState.data(), &StateRedirectBrowser::fireAbort); - - mAuthContext->setStateApproved(); - - QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations - QVERIFY(qobject_cast(mAuthContext->getActivationContext())->isSendErroPageCalled()); - QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Redirect_Browser_Send_Error_Page_Failed); - } - - - void noRefreshUrl_sendRedirectSuccess() - { - mAuthContext->setTcTokenNotFound(false); - mAuthContext->setTcToken(QSharedPointer(new TcToken(TestFileHelper::readFile(":/tctoken/ok.xml")))); - mAuthContext->mActivationContext.reset(new MockActivationContext(true, true, true, true)); - QSignalSpy spy(mState.data(), &StateRedirectBrowser::fireContinue); - - mAuthContext->setStateApproved(); - - QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations - QVERIFY(qobject_cast(mAuthContext->getActivationContext())->isSendRedirectCalled()); - } - - - void noRefreshUrl_sendRedirectFailure() - { - mAuthContext->setTcTokenNotFound(false); - mAuthContext->setTcToken(QSharedPointer(new TcToken(TestFileHelper::readFile(":/tctoken/ok.xml")))); - mAuthContext->mActivationContext.reset(new MockActivationContext(true, true, true, false)); - QSignalSpy spy(mState.data(), &StateRedirectBrowser::fireAbort); - - mAuthContext->setStateApproved(); - - QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations - QVERIFY(qobject_cast(mAuthContext->getActivationContext())->isSendRedirectCalled()); - QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Redirect_Browser_Send_Redirect_Failed); - } - - - void refreshUrl_sendRedirectSuccess() - { - mAuthContext->setTcTokenNotFound(false); - mAuthContext->setTcToken(QSharedPointer(new TcToken(TestFileHelper::readFile(":/tctoken/ok.xml")))); - mAuthContext->setRefreshUrl(QUrl("https://bla.de")); - mAuthContext->mActivationContext.reset(new MockActivationContext(true, true, true, true)); - QSignalSpy spy(mState.data(), &StateRedirectBrowser::fireContinue); - - mAuthContext->setStateApproved(); - - QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations - QVERIFY(qobject_cast(mAuthContext->getActivationContext())->isSendRedirectCalled()); - } - - - void refreshUrl_sendRedirectFailure() - { - mAuthContext->setTcTokenNotFound(false); - mAuthContext->setTcToken(QSharedPointer(new TcToken(TestFileHelper::readFile(":/tctoken/ok.xml")))); - mAuthContext->setRefreshUrl(QUrl("https://bla.de")); - mAuthContext->mActivationContext.reset(new MockActivationContext(true, true, true, false)); - QSignalSpy spy(mState.data(), &StateRedirectBrowser::fireAbort); - - mAuthContext->setStateApproved(); - - QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations - QVERIFY(qobject_cast(mAuthContext->getActivationContext())->isSendRedirectCalled()); - QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Redirect_Browser_Send_Redirect_Failed); + auto state = getStateRedirectBrowser([](const QSharedPointer&){ + return QStringLiteral("failing"); + }); + + QSignalSpy spyAbort(state.data(), &StateRedirectBrowser::fireAbort); + QSignalSpy spyContinue(state.data(), &StateRedirectBrowser::fireContinue); + + QTest::ignoreMessage(QtCriticalMsg, "Cannot send page to caller: \"failing\""); + state->run(); + QCOMPARE(state->getContext()->getStatus().getStatusCode(), GlobalStatus::Code::Workflow_Browser_Transmission_Error); + QCOMPARE(state->getContext()->getStatus().getExternalInfo(), QLatin1String("failing")); + QCOMPARE(spyAbort.count(), 1); + QCOMPARE(spyContinue.count(), 0); } diff --git a/test/qt/workflows/states/test_StateSelectReader.cpp b/test/qt/workflows/states/test_StateSelectReader.cpp index 1037fd7af..e6bb7c9ae 100644 --- a/test/qt/workflows/states/test_StateSelectReader.cpp +++ b/test/qt/workflows/states/test_StateSelectReader.cpp @@ -31,8 +31,9 @@ class test_StateSelectReader void initTestCase() { const auto readerManager = Env::getSingleton(); + QSignalSpy spy(readerManager, &ReaderManager::fireInitialized); readerManager->init(); - readerManager->isScanRunning(); // just to wait until initialization finished + QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations } diff --git a/test/qt/workflows/states/test_StateSendWhitelistSurvey.cpp b/test/qt/workflows/states/test_StateSendWhitelistSurvey.cpp index fd5ac87b0..afbf14b26 100644 --- a/test/qt/workflows/states/test_StateSendWhitelistSurvey.cpp +++ b/test/qt/workflows/states/test_StateSendWhitelistSurvey.cpp @@ -46,7 +46,7 @@ class test_StateSendWhitelistSurvey private Q_SLOTS: void init() { - mContext.reset(new TestAuthContext(nullptr, ":/paos/DIDAuthenticateEAC1.xml")); + mContext.reset(new TestAuthContext(":/paos/DIDAuthenticateEAC1.xml")); mState.reset(StateBuilder::createState(mContext)); mState->onEntry(nullptr); } diff --git a/test/qt/workflows/states/test_StateStartPaosResponse.cpp b/test/qt/workflows/states/test_StateStartPaosResponse.cpp index 127513971..d53e8d05e 100644 --- a/test/qt/workflows/states/test_StateStartPaosResponse.cpp +++ b/test/qt/workflows/states/test_StateStartPaosResponse.cpp @@ -26,7 +26,7 @@ class test_StateStartPaosResponse private Q_SLOTS: void init() { - mAuthContext.reset(new AuthContext(nullptr)); + mAuthContext.reset(new AuthContext()); mState.reset(StateBuilder::createState(mAuthContext)); mState->onEntry(nullptr); } diff --git a/test/qt/workflows/states/test_StateTransmit.cpp b/test/qt/workflows/states/test_StateTransmit.cpp index a64e6bce0..5c1295a70 100644 --- a/test/qt/workflows/states/test_StateTransmit.cpp +++ b/test/qt/workflows/states/test_StateTransmit.cpp @@ -59,7 +59,7 @@ class test_StateTransmit const QSharedPointer worker(new MockCardConnectionWorker()); worker->moveToThread(&workerThread); const QSharedPointer connection(new CardConnection(worker)); - const QSharedPointer context(new AuthContext(nullptr)); + const QSharedPointer context(new AuthContext()); context->setCardConnection(connection); StateTransmit stateTransmit(context); @@ -87,7 +87,7 @@ class test_StateTransmit void test_OnCardCommandDone() { - const QSharedPointer context(new AuthContext(nullptr)); + const QSharedPointer context(new AuthContext()); const QSharedPointer response(new TransmitResponse()); context->setTransmitResponse(response); StateTransmit stateTransmit(context); diff --git a/test/qt/workflows/states/test_StateUpdRetryCounter.cpp b/test/qt/workflows/states/test_StateUpdRetryCounter.cpp index d7c6bee9f..a4ff192bf 100644 --- a/test/qt/workflows/states/test_StateUpdRetryCounter.cpp +++ b/test/qt/workflows/states/test_StateUpdRetryCounter.cpp @@ -77,7 +77,7 @@ class test_StateUpdateRetryCounter QSignalSpy spyNoCardConnection(&counter, &StateUpdateRetryCounter::fireNoCardConnection); QTest::ignoreMessage(QtDebugMsg, "StateUpdateRetryCounter::onUpdateRetryCounterDone()"); - QTest::ignoreMessage(QtCriticalMsg, "An error ( UNKNOWN ) occurred while communicating with the card reader, cannot determine retry counter, abort state"); + QTest::ignoreMessage(QtCriticalMsg, "An error (UNKNOWN) occurred while communicating with the card reader, cannot determine retry counter, abort state"); counter.onUpdateRetryCounterDone(command); QCOMPARE(spyAbort.count(), 0); QCOMPARE(spyNoCardConnection.count(), 1); diff --git a/test/qt/workflows/states/test_StateWriteHistory.cpp b/test/qt/workflows/states/test_StateWriteHistory.cpp deleted file mode 100644 index 78a6c70e2..000000000 --- a/test/qt/workflows/states/test_StateWriteHistory.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/** - * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany - */ - -/*! - * \brief Unit tests for \ref StateWriteHistory - */ - -#include "states/StateWriteHistory.h" - -#include "AppSettings.h" -#include "Env.h" -#include "LanguageLoader.h" -#include "VolatileSettings.h" -#include "states/StateBuilder.h" - -#include "MockCardConnectionWorker.h" -#include "TestAuthContext.h" - -#include -#include - - -using namespace governikus; - -class test_StateWriteHistory - : public QObject -{ - Q_OBJECT - QSharedPointer mContext; - QSharedPointer mState; - - private Q_SLOTS: - void init() - { - mContext.reset(new TestAuthContext(nullptr, ":/paos/DIDAuthenticateEAC1_2.xml")); - mState.reset(StateBuilder::createState(mContext)); - mState->onEntry(nullptr); - } - - - void cleanup() - { - mContext.clear(); - mState.clear(); - } - - - void test_RunHistoryDisabled() - { - QSignalSpy spyContinue(mState.data(), &StateWriteHistory::fireContinue); - Env::getSingleton()->getHistorySettings().setEnabled(false); - - QTest::ignoreMessage(QtDebugMsg, "History disabled"); - mContext->setStateApproved(); - QTRY_COMPARE(spyContinue.count(), 1); // clazy:exclude=qstring-allocations - } - - - void test_RunNoError() - { - SDK_MODE(false); - auto& historySettings = Env::getSingleton()->getHistorySettings(); - QSignalSpy spyContinue(mState.data(), &StateWriteHistory::fireContinue); - historySettings.setEnabled(true); - *mContext->getAccessRightManager() = {AccessRight::READ_DG01, AccessRight::READ_DG02}; - - mContext->setStatus(GlobalStatus::Code::No_Error); - mContext->setStateApproved(); - QTRY_COMPARE(spyContinue.count(), 1); // clazy:exclude=qstring-allocations - QVERIFY(historySettings.getHistoryInfos().size() > 0); - const auto historyInfo = historySettings.getHistoryInfos().at(0); - QCOMPARE(historyInfo.getSubjectName(), mState->getContext()->getDidAuthenticateEac1()->getCertificateDescription()->getSubjectName()); - QCOMPARE(historyInfo.getSubjectUrl(), mState->getContext()->getDidAuthenticateEac1()->getCertificateDescription()->getSubjectUrl()); - QCOMPARE(historyInfo.getPurpose(), mState->getContext()->getDidAuthenticateEac1()->getCertificateDescription()->getPurpose()); - QVERIFY(historyInfo.getTermOfUsage().contains(mState->getContext()->getDidAuthenticateEac1()->getCertificateDescription()->getTermsOfUsage())); - qDebug() << historyInfo.getTermOfUsage(); - const auto locale = LanguageLoader::getInstance().getUsedLocale(); - const auto effectiveDate = locale.toString(QDate(2014, 4, 7), QLocale::ShortFormat); - const auto expirationDate = locale.toString(QDate(2014, 7, 6), QLocale::ShortFormat); - QVERIFY(historyInfo.getTermOfUsage().endsWith(tr("Validity:\n%1 - %2").arg(effectiveDate, expirationDate))); - QStringList list = {"DocumentType", "IssuingCountry"}; - qDebug() << historyInfo.getRequestedData(); - QCOMPARE(historyInfo.getRequestedData(), list); - QCOMPARE(spyContinue.count(), 1); - } - - - void test_SetProgress() - { - mState->onEntry(nullptr); - QCOMPARE(mContext->getProgressValue(), 100); - QCOMPARE(mContext->getProgressMessage(), tr("Preparing results")); - - mContext->setStatus(GlobalStatus::Code::Workflow_Cancellation_By_User); - mState->onEntry(nullptr); - QCOMPARE(mContext->getProgressValue(), 100); - QCOMPARE(mContext->getProgressMessage(), QString()); - } - - - void test_RunCertificateValidity() - { - mContext.reset(new TestAuthContext(nullptr, ":/paos/DIDAuthenticateEAC1_ordered_certificates.xml")); - mState.reset(StateBuilder::createState(mContext)); - mState->onEntry(nullptr); - - SDK_MODE(false); - auto& historySettings = Env::getSingleton()->getHistorySettings(); - QSignalSpy spyContinue(mState.data(), &StateWriteHistory::fireContinue); - historySettings.setEnabled(true); - - mContext->setStatus(GlobalStatus::Code::No_Error); - mContext->setStateApproved(); - QTRY_COMPARE(spyContinue.count(), 1); // clazy:exclude=qstring-allocations - QVERIFY(historySettings.getHistoryInfos().size() > 0); - const auto historyInfo = historySettings.getHistoryInfos().at(0); - QCOMPARE(historyInfo.getSubjectName(), mState->getContext()->getDidAuthenticateEac1()->getCertificateDescription()->getSubjectName()); - QCOMPARE(historyInfo.getSubjectUrl(), mState->getContext()->getDidAuthenticateEac1()->getCertificateDescription()->getSubjectUrl()); - QCOMPARE(historyInfo.getPurpose(), mState->getContext()->getDidAuthenticateEac1()->getCertificateDescription()->getPurpose()); - QVERIFY(historyInfo.getTermOfUsage().contains(mState->getContext()->getDidAuthenticateEac1()->getCertificateDescription()->getTermsOfUsage())); - qDebug() << historyInfo.getTermOfUsage(); - const auto locale = LanguageLoader::getInstance().getUsedLocale(); - const auto effectiveDate = locale.toString(QDate(2020, 5, 21), QLocale::ShortFormat); - const auto expirationDate = locale.toString(QDate(2020, 6, 20), QLocale::ShortFormat); - QVERIFY(historyInfo.getTermOfUsage().endsWith(tr("Validity:\n%1 - %2").arg(effectiveDate, expirationDate))); - QCOMPARE(spyContinue.count(), 1); - } - - -}; - -QTEST_GUILESS_MAIN(test_StateWriteHistory) -#include "test_StateWriteHistory.moc" diff --git a/test/qt/workflows/test_CertificateChecker.cpp b/test/qt/workflows/test_CertificateChecker.cpp index 5ce59cf74..bbfe0fba4 100644 --- a/test/qt/workflows/test_CertificateChecker.cpp +++ b/test/qt/workflows/test_CertificateChecker.cpp @@ -12,8 +12,6 @@ #include "SecureStorage.h" #include "context/AuthContext.h" -#include "MockActivationContext.h" - #include using namespace governikus; @@ -36,7 +34,7 @@ class test_CertificateChecker void validUpdateCert() { - const QSharedPointer context(new AuthContext(QSharedPointer::create())); + const QSharedPointer context(new AuthContext()); QCOMPARE(context->getCertificateList().size(), 0); QCOMPARE(CertificateChecker::checkAndSaveCertificate(certs.at(0), QUrl("dummy"), context), CertificateChecker::CertificateStatus::Good); diff --git a/test/qt/workflows/test_ChangePinController.cpp b/test/qt/workflows/test_ChangePinController.cpp index 594b6c001..8afe576f8 100644 --- a/test/qt/workflows/test_ChangePinController.cpp +++ b/test/qt/workflows/test_ChangePinController.cpp @@ -34,24 +34,6 @@ class test_ChangePinController bool mRetryCounterUpdated = false; - void onCardInfoChanged(const ReaderInfo& pInfo) - { - if (pInfo.isInsertable()) - { - Env::getSingleton()->insert(pInfo); - } - } - - - void onCardInserted(const ReaderInfo& pInfo) - { - if (pInfo.hasEid()) - { - Q_EMIT fireEidCardInserted(); - } - } - - void onStateChanged(const QString& pNextState) { if (mRetryCounterUpdated) @@ -65,7 +47,7 @@ class test_ChangePinController } } - if (AbstractState::isState(pNextState)) + if (StateBuilder::isState(pNextState)) { mRetryCounterUpdated = true; } @@ -76,21 +58,25 @@ class test_ChangePinController private Q_SLOTS: void initTestCase() { - QSignalSpy eidCardDetected(this, &test_ChangePinController::fireEidCardInserted); - const auto readerManager = Env::getSingleton(); - connect(readerManager, &ReaderManager::fireReaderPropertiesUpdated, this, &test_ChangePinController::onCardInfoChanged); - connect(readerManager, &ReaderManager::fireCardInserted, this, &test_ChangePinController::onCardInserted); + QSignalSpy spy(readerManager, &ReaderManager::fireInitialized); + connect(readerManager, &ReaderManager::fireReaderPropertiesUpdated, this, [] (const ReaderInfo& pInfo){ + if (pInfo.isInsertable()) + { + Env::getSingleton()->insert(pInfo); + } + }); + readerManager->init(); + QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations } void cleanupTestCase() { const auto readerManager = Env::getSingleton(); + readerManager->disconnect(this); readerManager->shutdown(); - disconnect(readerManager, &ReaderManager::fireCardInserted, this, &test_ChangePinController::onCardInserted); - disconnect(readerManager, &ReaderManager::fireReaderPropertiesUpdated, this, &test_ChangePinController::onCardInfoChanged); } @@ -108,8 +94,7 @@ class test_ChangePinController void cleanup() { - disconnect(mChangePinContext.data(), &WorkflowContext::fireStateChanged, this, &test_ChangePinController::onStateChanged); - + mChangePinContext->disconnect(this); mChangePinController.reset(); mChangePinContext.reset(); } @@ -117,19 +102,14 @@ class test_ChangePinController void testSuccess() { - qDebug() << "START: testSuccess"; - QSignalSpy controllerFinishedSpy(mChangePinController.data(), &ChangePinController::fireComplete); mChangePinController->run(); - QVERIFY(controllerFinishedSpy.wait()); - QCOMPARE(mChangePinContext->getStatus().getStatusCode(), GlobalStatus::Code::No_Error); } - Q_SIGNALS: - void fireEidCardInserted(); + }; QTEST_GUILESS_MAIN(test_ChangePinController) diff --git a/test/qt/workflows/test_WorkflowRequest.cpp b/test/qt/workflows/test_WorkflowRequest.cpp index 4ce9eb2a2..bc676e51b 100644 --- a/test/qt/workflows/test_WorkflowRequest.cpp +++ b/test/qt/workflows/test_WorkflowRequest.cpp @@ -27,8 +27,9 @@ class test_WorkflowRequest void initTestCase() { const auto readerManager = Env::getSingleton(); + QSignalSpy spy(readerManager, &ReaderManager::fireInitialized); readerManager->init(); - readerManager->isScanRunning(); // just to wait until initialization finished + QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations } @@ -40,7 +41,7 @@ class test_WorkflowRequest void initialize() { - auto request = WorkflowRequest::createWorkflowRequest(); + auto request = WorkflowRequest::create(); QVERIFY(!request->isInitialized()); QCOMPARE(request->getAction(), Action::AUTH);