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/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 7c977bf34..c1de2b2a0 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -33,7 +33,7 @@ jobs: queries: +security-and-quality - name: Install dependencies - run: sudo apt install -y cmake pkg-config libssl-dev libudev-dev libhttp-parser-dev libpcsclite-dev libqt6svg6-dev libqt6websockets6-dev qt6-base-dev qt6-base-private-dev qt6-declarative-dev qt6-scxml-dev qt6-tools-dev qt6-tools-dev-tools libqt6opengl6-dev libqt6shadertools6-dev libgl1-mesa-dev qt6-l10n-tools + run: sudo apt update -qq && sudo apt install -y cmake pkg-config libssl-dev libudev-dev libhttp-parser-dev libpcsclite-dev libqt6svg6-dev libqt6websockets6-dev qt6-base-dev qt6-base-private-dev qt6-declarative-dev qt6-connectivity-dev qt6-scxml-dev qt6-tools-dev qt6-tools-dev-tools libqt6opengl6-dev libqt6shadertools6-dev libgl1-mesa-dev qt6-l10n-tools - name: Autobuild uses: github/codeql-action/autobuild@v2 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 7c6cce40c..a379e35df 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() - -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() +cmake_minimum_required(VERSION 3.19.0) -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.3 LANGUAGES ${LANGUAGES}) +project(AusweisApp VERSION 2.0.3 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") @@ -182,6 +138,7 @@ endif() option(USE_SMARTEID "Enable Smart-eID" OFF) include(Libraries) +include(Tools.Libraries) include(CompilerFlags) if(LINUX OR BSD) @@ -200,3 +157,6 @@ if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/utils") endif() include(Packaging) + +include(FeatureSummary) +FEATURE_SUMMARY(WHAT ALL) 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 932b38267..afc3c56df 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -ARG ALPINE_VERSION=3.17 +ARG ALPINE_VERSION=3.18 FROM alpine:$ALPINE_VERSION as builder # Install development stuff @@ -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 d81a69119..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.8 + 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 8bae541de..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.8 + 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 3845159be..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() @@ -150,7 +140,6 @@ else() endif() endif() - if(CMAKE_COMPILE_WARNING_AS_ERROR AND CMAKE_VERSION VERSION_LESS "3.24") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") endif() @@ -189,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 ceb09a6a6..a294f343c 100644 --- a/cmake/DVCS.cmake +++ b/cmake/DVCS.cmake @@ -45,8 +45,6 @@ endfunction() macro(CHECK_DVCS) - set(VERSION_DVCS ${PROJECT_VERSION}) - if(HG_FOUND) DVCS_CALL("tag" "" id -t) elseif(GIT_FOUND) @@ -96,7 +94,7 @@ macro(GET_DVCS_INFO) endif() endmacro() - +set(VERSION_DVCS ${PROJECT_VERSION}) FIND_DVCS(${PROJECT_SOURCE_DIR}) if(DVCS_FOUND) option(ENABLE_DVCS "Check consistency of version/tag and get additional revision data" true) @@ -106,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 8d7fdd88c..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,33 +80,22 @@ if(WIN32) endif() endif() - if (QT6) - # 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") - 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}) @@ -131,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}) @@ -156,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) @@ -210,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() @@ -226,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}") @@ -247,7 +227,7 @@ elseif(ANDROID) foreach(entry ldpi mdpi hdpi xhdpi xxhdpi xxxhdpi) 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}/${ANDROID_LAUNCHER_ICON} DESTINATION ${ANDROID_PACKAGE_SRC_DIR}/res/mipmap-${entry} COMPONENT Runtime RENAME npa.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_SPLASH_SCREEN_ICON_NAME} DESTINATION ${ANDROID_PACKAGE_SRC_DIR}/res/drawable-${entry} COMPONENT Runtime RENAME splash_npa.png) endforeach() @@ -260,11 +240,7 @@ elseif(ANDROID) install(FILES ${PACKAGING_DIR}/android/IAusweisApp2Sdk.aidl DESTINATION ${ANDROID_PACKAGE_SRC_DIR}/src/com/governikus/ausweisapp2/ COMPONENT Runtime) install(FILES ${PACKAGING_DIR}/android/IAusweisApp2SdkCallback.aidl DESTINATION ${ANDROID_PACKAGE_SRC_DIR}/src/com/governikus/ausweisapp2/ COMPONENT Runtime) - if(VERSION_DVCS) - set(ANDROID_VERSION_NAME ${VERSION_DVCS}) - else() - set(ANDROID_VERSION_NAME ${PROJECT_VERSION}) - endif() + set(ANDROID_VERSION_NAME ${VERSION_DVCS}) configure_file(${PACKAGING_DIR}/android/${ANDROID_MANIFEST} ${ANDROID_PACKAGE_SRC_DIR}/AndroidManifest.xml @ONLY) if(INTEGRATED_SDK) set(QML_ROOT_PATH []) @@ -273,9 +249,11 @@ elseif(ANDROID) set(QML_ROOT_PATH [\"${RESOURCES_DIR}/qml\"]) set(ANDROID_ROOT_LOGGER "") configure_file(${PACKAGING_DIR}/android/fileprovider.xml ${ANDROID_PACKAGE_SRC_DIR}/res/xml/fileprovider.xml COPYONLY) + configure_file(${PACKAGING_DIR}/android/full_backup_content.xml ${ANDROID_PACKAGE_SRC_DIR}/res/xml/full_backup_content.xml COPYONLY) + 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}") @@ -286,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) @@ -297,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 6ece9e5d5..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,44 +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) - - if(QT_VERSION VERSION_GREATER_EQUAL "5.14") - list(APPEND QT_COMPONENTS QmlWorkerScript) - endif() - 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() @@ -101,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/Messages.cmake b/cmake/Messages.cmake index 0a5e4ecab..e3c63199d 100644 --- a/cmake/Messages.cmake +++ b/cmake/Messages.cmake @@ -25,7 +25,6 @@ if(ANDROID) message(STATUS "ANDROID_BUILD_TOOLS_REVISION: ${ANDROID_BUILD_TOOLS_REVISION}") message(STATUS "ANDROID_NDK_REVISION: ${ANDROID_NDK_REVISION}") - message(STATUS "ANDROID_SDK_REVISION: ${ANDROID_SDK_REVISION}") endif() diff --git a/cmake/Notarization.cmake b/cmake/Notarization.cmake index 9edd74d62..7b4040913 100644 --- a/cmake/Notarization.cmake +++ b/cmake/Notarization.cmake @@ -25,14 +25,11 @@ if(NOT DMG_FILE_LEN EQUAL 1) endif() message(STATUS "Using DMG: ${DMG_FILE}") -if(NOT USER) - set(USER ausweisapp@governikus.com) -endif() -execute_process(COMMAND ${XCRUN} altool -t osx --notarize-app --verbose -u ${USER} -p @env:PASSWORD --primary-bundle-id com.governikus.ausweisapp2 -f ${DMG_FILE} - OUTPUT_VARIABLE UUID_OUTPUT) +set(keychain --keychain-profile "AC_PASSWORD") +execute_process(COMMAND ${XCRUN} notarytool submit ${keychain} ${DMG_FILE} OUTPUT_VARIABLE UUID_OUTPUT) -set(regex_uuid "RequestUUID = ([-|0-9|a-z]+)") +set(regex_uuid "id: ([-|0-9|a-z]+)") FETCH_REGEX(UUID "${regex_uuid}" "${UUID_OUTPUT}") if(UUID) message(STATUS "Fetched UUID: ${UUID}") @@ -40,26 +37,21 @@ else() message(FATAL_ERROR "Cannot fetch UUID: ${UUID_OUTPUT}") endif() -set(regex_status "Status: ([a-z| ]+)") -while(TRUE) - message(STATUS "Wait 30 seconds...") - execute_process(COMMAND ${CMAKE_COMMAND} -E sleep 30) +message(STATUS "Wait...") +execute_process(COMMAND ${XCRUN} notarytool wait ${UUID} ${keychain}) - execute_process(COMMAND ${XCRUN} altool -u ${USER} -p @env:PASSWORD --notarization-info ${UUID} - OUTPUT_VARIABLE STATUS_OUTPUT) +execute_process(COMMAND ${XCRUN} notarytool info ${UUID} ${keychain} OUTPUT_VARIABLE STATUS_OUTPUT) - FETCH_REGEX(STATUS "${regex_status}" "${STATUS_OUTPUT}") +set(regex_status "status: ([a-zA-Z| ]+)") +FETCH_REGEX(STATUS "${regex_status}" "${STATUS_OUTPUT}") - if(STATUS STREQUAL "success") - message(STATUS "Notarization succeeded...") - break() - elseif(STATUS STREQUAL "in progress") - message(STATUS "Waiting...\n${STATUS_OUTPUT}") - else() - message(STATUS "Fetched Status: ${STATUS}") - message(FATAL_ERROR "Notarization failed:\n${STATUS_OUTPUT}") - endif() -endwhile() +if(STATUS STREQUAL "Accepted") + message(STATUS "Notarization succeeded...") +else() + message(STATUS "Fetched Status: ${STATUS}") + execute_process(COMMAND ${XCRUN} notarytool log ${UUID} ${keychain}) + message(FATAL_ERROR "Notarization failed:\n${STATUS_OUTPUT}") +endif() execute_process(COMMAND ${XCRUN} stapler staple -v ${DMG_FILE}) execute_process(COMMAND ${XCRUN} stapler validate -v ${DMG_FILE}) diff --git a/cmake/Packaging.cmake b/cmake/Packaging.cmake index 461c3b285..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) @@ -171,7 +170,11 @@ elseif(ANDROID) file(READ "${BUILD_GRADLE_APPEND}" BUILD_GRADLE) file(APPEND "${CMAKE_INSTALL_PREFIX}/build.gradle" "${BUILD_GRADLE}") - if(USE_SMARTEID AND NOT INTEGRATED_SDK) + if(INTEGRATED_SDK) + set(BUILD_GRADLE_APPEND "${PACKAGING_DIR}/android/build.gradle.append.aar") + file(READ "${BUILD_GRADLE_APPEND}" BUILD_GRADLE) + file(APPEND "${CMAKE_INSTALL_PREFIX}/build.gradle" "${BUILD_GRADLE}") + elseif(USE_SMARTEID) set(BUILD_GRADLE_APPEND "${PACKAGING_DIR}/android/build.gradle.append.smarteid") file(READ "${BUILD_GRADLE_APPEND}" BUILD_GRADLE) file(APPEND "${CMAKE_INSTALL_PREFIX}/build.gradle" "${BUILD_GRADLE}") @@ -214,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) @@ -222,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/Sphinx.cmake b/cmake/Sphinx.cmake index 92aef00ed..608802ba5 100644 --- a/cmake/Sphinx.cmake +++ b/cmake/Sphinx.cmake @@ -13,13 +13,11 @@ if(SPHINX_BIN) list(APPEND _LOCALES ${_defaultLang}) set(_TMP_DIR "${CMAKE_BINARY_DIR}/_tmp/${_target}/${_builder}") - set(_CONFIG_DIR "${_TMP_DIR}/config") set(SPHINX_CONF_PY_IN "${SPHINX_DOCS_DIR}/${_builder}.conf.py.in") if(NOT EXISTS "${SPHINX_CONF_PY_IN}") set(SPHINX_CONF_PY_IN "${SPHINX_DOCS_DIR}/conf.py.in") endif() - configure_file("${SPHINX_CONF_PY_IN}" "${_CONFIG_DIR}/conf.py" @ONLY) # Use @SPHINX_DOCS_DIR@ here file(GLOB_RECURSE _FILES "${SPHINX_DOCS_DIR}/*.rst" @@ -28,14 +26,17 @@ if(SPHINX_BIN) "${SPHINX_DOCS_DIR}/*.jpg" "${SPHINX_DOCS_DIR}/*.svg") - foreach(lang ${_LOCALES}) - get_filename_component(lang "${lang}" NAME) - message(STATUS "Generate (${_builder}) ${_target}: ${lang}") + foreach(SPHINX_LANG ${_LOCALES}) + get_filename_component(SPHINX_LANG "${SPHINX_LANG}" NAME) + message(STATUS "Generate (${_builder}) ${_target}: ${SPHINX_LANG}") - set(target_dir "${_output}/${_target}/${_builder}/${lang}") - set(TARGET_CMD ${SPHINX_BIN} -c "${_CONFIG_DIR}" -Dlanguage=${lang} ${_options} -d "${_TMP_DIR}/${lang}" -b ${_builder} "${SPHINX_DOCS_DIR}" "${target_dir}") + set(_CONFIG_DIR "${_TMP_DIR}/config/${SPHINX_LANG}") + configure_file("${SPHINX_CONF_PY_IN}" "${_CONFIG_DIR}/conf.py" @ONLY) # Use @SPHINX_DOCS_DIR@ / @SPHINX_LANG@ here + + set(target_dir "${_output}/${_target}/${_builder}/${SPHINX_LANG}") + set(TARGET_CMD ${SPHINX_BIN} -c "${_CONFIG_DIR}" ${_options} -d "${_TMP_DIR}/${SPHINX_LANG}" -b ${_builder} "${SPHINX_DOCS_DIR}" "${target_dir}") add_custom_command(OUTPUT ${target_dir} COMMAND ${TARGET_CMD} DEPENDS ${_FILES}) - set(subtarget ${_target}.${_builder}.${lang}) + set(subtarget ${_target}.${_builder}.${SPHINX_LANG}) add_custom_target(${subtarget} DEPENDS ${target_dir} SOURCES ${_FILES}) list(APPEND target_list ${subtarget}) diff --git a/cmake/Tools.Libraries.cmake b/cmake/Tools.Libraries.cmake new file mode 100644 index 000000000..9237c91ca --- /dev/null +++ b/cmake/Tools.Libraries.cmake @@ -0,0 +1,42 @@ +# This file will be included in Tools.cmake AND after Libraries.cmake +# So this file will be called two times and the check needs to respect that +# with a "VALIDATOR function" or "if(NOT VARIABLE)". + +if(NOT TARGET format.qml) + set(QMLFORMAT_MIN_VERSION 6) + function(qmlformat_validator validator_result binary) + execute_process(COMMAND ${binary} --version OUTPUT_VARIABLE QMLFORMAT_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) + string(REPLACE "qmlformat " "" QMLFORMAT_VERSION "${QMLFORMAT_VERSION}") + + if("${QMLFORMAT_VERSION}" VERSION_LESS "${QMLFORMAT_MIN_VERSION}") + set(${validator_result} FALSE PARENT_SCOPE) + endif() + endfunction() + + if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.25") + set(VALIDATOR VALIDATOR qmlformat_validator) + endif() + + find_program(QMLFORMAT qmlformat HINTS "${QT_INSTALL_ARCHDATA}/bin" ${VALIDATOR} CMAKE_FIND_ROOT_PATH_BOTH) + if(QMLFORMAT) + execute_process(COMMAND ${QMLFORMAT} --version OUTPUT_VARIABLE QMLFORMAT_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) + string(REPLACE "qmlformat " "" QMLFORMAT_VERSION "${QMLFORMAT_VERSION}") + + if("${QMLFORMAT_VERSION}" VERSION_LESS "${QMLFORMAT_MIN_VERSION}") + unset(QMLFORMAT CACHE) # let's retry later + else() + file(GLOB_RECURSE FILES_QML ${PROJECT_SOURCE_DIR}/*.qml) + set(QMLFORMAT_CMD ${QMLFORMAT} -i -n -l unix -t -w 4) + + set(FORMATTING_FILE ${PROJECT_BINARY_DIR}/formatting.files.qml) + file(WRITE ${FORMATTING_FILE} "") + foreach(file ${FILES_QML}) + file(APPEND ${FORMATTING_FILE} ${file}) + file(APPEND ${FORMATTING_FILE} "\n") + endforeach() + + add_custom_target(format.qml COMMAND ${QMLFORMAT_CMD} -F ${FORMATTING_FILE} SOURCES ${FILES_QML}) + add_dependencies(format format.qml) + endif() + endif() +endif() diff --git a/cmake/Tools.cmake b/cmake/Tools.cmake index 0667652d5..135ea668f 100644 --- a/cmake/Tools.cmake +++ b/cmake/Tools.cmake @@ -115,33 +115,10 @@ if(UNCRUSTIFY) endif() endif() -find_program(QMLFORMAT qmlformat HINTS "${QT_INSTALL_ARCHDATA}/bin" CMAKE_FIND_ROOT_PATH_BOTH) -if(QMLFORMAT) - execute_process(COMMAND ${QMLFORMAT} --version OUTPUT_VARIABLE QMLFORMAT_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) - string(REPLACE "qmlformat " "" QMLFORMAT_VERSION "${QMLFORMAT_VERSION}") - - if("${QMLFORMAT_VERSION}" VERSION_LESS "6") - message(WARNING "qmlformat is too old: ${QMLFORMAT_VERSION}") - else() - file(GLOB_RECURSE FILES_QML ${PROJECT_SOURCE_DIR}/*.qml) - set(QMLFORMAT_CMD ${QMLFORMAT} -i -n -l unix -t -w 4) - - set(FORMATTING_FILE ${PROJECT_BINARY_DIR}/formatting.files.qml) - file(WRITE ${FORMATTING_FILE} "") - foreach(file ${FILES_QML}) - file(APPEND ${FORMATTING_FILE} ${file}) - file(APPEND ${FORMATTING_FILE} "\n") - endforeach() - - add_custom_target(format.qml COMMAND ${QMLFORMAT_CMD} -F ${FORMATTING_FILE} SOURCES ${FILES_QML}) - add_dependencies(format format.qml) - endif() -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}) @@ -177,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 @@ -188,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 @@ -251,6 +201,33 @@ if(INKSCAPE) COMMAND ${INKSCAPE} adaptive_foreground_preview.svg -d 640 -y 0 -o xxxhdpi/foreground_npa_preview.png WORKING_DIRECTORY ${RESOURCES_DIR}/images/android) + add_custom_target(npaicons.android.adaptive.monochrome + COMMAND ${INKSCAPE} adaptive_monochrome_release.svg -d 120 -y 0 -o ldpi/monochrome_npa.png + COMMAND ${INKSCAPE} adaptive_monochrome_release.svg -d 160 -y 0 -o mdpi/monochrome_npa.png + COMMAND ${INKSCAPE} adaptive_monochrome_release.svg -d 240 -y 0 -o hdpi/monochrome_npa.png + COMMAND ${INKSCAPE} adaptive_monochrome_release.svg -d 320 -y 0 -o xhdpi/monochrome_npa.png + COMMAND ${INKSCAPE} adaptive_monochrome_release.svg -d 480 -y 0 -o xxhdpi/monochrome_npa.png + COMMAND ${INKSCAPE} adaptive_monochrome_release.svg -d 640 -y 0 -o xxxhdpi/monochrome_npa.png + WORKING_DIRECTORY ${RESOURCES_DIR}/images/android) + + add_custom_target(npaicons.android.adaptive.monochrome.beta + COMMAND ${INKSCAPE} adaptive_monochrome_beta.svg -d 120 -y 0 -o ldpi/monochrome_npa_beta.png + COMMAND ${INKSCAPE} adaptive_monochrome_beta.svg -d 160 -y 0 -o mdpi/monochrome_npa_beta.png + COMMAND ${INKSCAPE} adaptive_monochrome_beta.svg -d 240 -y 0 -o hdpi/monochrome_npa_beta.png + COMMAND ${INKSCAPE} adaptive_monochrome_beta.svg -d 320 -y 0 -o xhdpi/monochrome_npa_beta.png + COMMAND ${INKSCAPE} adaptive_monochrome_beta.svg -d 480 -y 0 -o xxhdpi/monochrome_npa_beta.png + COMMAND ${INKSCAPE} adaptive_monochrome_beta.svg -d 640 -y 0 -o xxxhdpi/monochrome_npa_beta.png + WORKING_DIRECTORY ${RESOURCES_DIR}/images/android) + + add_custom_target(npaicons.android.adaptive.monochrome.preview + COMMAND ${INKSCAPE} adaptive_monochrome_preview.svg -d 120 -y 0 -o ldpi/monochrome_npa_preview.png + COMMAND ${INKSCAPE} adaptive_monochrome_preview.svg -d 160 -y 0 -o mdpi/monochrome_npa_preview.png + COMMAND ${INKSCAPE} adaptive_monochrome_preview.svg -d 240 -y 0 -o hdpi/monochrome_npa_preview.png + COMMAND ${INKSCAPE} adaptive_monochrome_preview.svg -d 320 -y 0 -o xhdpi/monochrome_npa_preview.png + COMMAND ${INKSCAPE} adaptive_monochrome_preview.svg -d 480 -y 0 -o xxhdpi/monochrome_npa_preview.png + COMMAND ${INKSCAPE} adaptive_monochrome_preview.svg -d 640 -y 0 -o xxxhdpi/monochrome_npa_preview.png + WORKING_DIRECTORY ${RESOURCES_DIR}/images/android) + add_custom_target(npaicons.android.launchimage COMMAND ${INKSCAPE} npa_release.svg -w 120 -h 120 -y 0 -o android/ldpi/splash_npa.png COMMAND ${INKSCAPE} npa_release.svg -w 180 -h 180 -y 0 -o android/mdpi/splash_npa.png @@ -329,13 +306,13 @@ 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 npaicons.android.adaptive.foreground.preview + npaicons.android.adaptive.monochrome + npaicons.android.adaptive.monochrome.beta + npaicons.android.adaptive.monochrome.preview npaicons.android.launchimage npaicons.android.launchimage.beta npaicons.android.launchimage.preview @@ -352,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) @@ -367,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 @@ -430,6 +375,33 @@ if(PNGQUANT) COMMAND ${PNGQUANT_CMD} xxxhdpi/foreground_npa_preview.png -- xxxhdpi/foreground_npa_preview.png WORKING_DIRECTORY ${RESOURCES_DIR}/images/android) + add_custom_target(pngquant.android.adaptive.monochrome + COMMAND ${PNGQUANT_CMD} ldpi/monochrome_npa.png -- ldpi/monochrome_npa.png + COMMAND ${PNGQUANT_CMD} mdpi/monochrome_npa.png -- mdpi/monochrome_npa.png + COMMAND ${PNGQUANT_CMD} hdpi/monochrome_npa.png -- hdpi/monochrome_npa.png + COMMAND ${PNGQUANT_CMD} xhdpi/monochrome_npa.png -- xhdpi/monochrome_npa.png + COMMAND ${PNGQUANT_CMD} xxhdpi/monochrome_npa.png -- xxhdpi/monochrome_npa.png + COMMAND ${PNGQUANT_CMD} xxxhdpi/monochrome_npa.png -- xxxhdpi/monochrome_npa.png + WORKING_DIRECTORY ${RESOURCES_DIR}/images/android) + + add_custom_target(pngquant.android.adaptive.monochrome.beta + COMMAND ${PNGQUANT_CMD} ldpi/monochrome_npa_beta.png -- ldpi/monochrome_npa_beta.png + COMMAND ${PNGQUANT_CMD} mdpi/monochrome_npa_beta.png -- mdpi/monochrome_npa_beta.png + COMMAND ${PNGQUANT_CMD} hdpi/monochrome_npa_beta.png -- hdpi/monochrome_npa_beta.png + COMMAND ${PNGQUANT_CMD} xhdpi/monochrome_npa_beta.png -- xhdpi/monochrome_npa_beta.png + COMMAND ${PNGQUANT_CMD} xxhdpi/monochrome_npa_beta.png -- xxhdpi/monochrome_npa_beta.png + COMMAND ${PNGQUANT_CMD} xxxhdpi/monochrome_npa_beta.png -- xxxhdpi/monochrome_npa_beta.png + WORKING_DIRECTORY ${RESOURCES_DIR}/images/android) + + add_custom_target(pngquant.android.adaptive.monochrome.preview + COMMAND ${PNGQUANT_CMD} ldpi/monochrome_npa_preview.png -- ldpi/monochrome_npa_preview.png + COMMAND ${PNGQUANT_CMD} mdpi/monochrome_npa_preview.png -- mdpi/monochrome_npa_preview.png + COMMAND ${PNGQUANT_CMD} hdpi/monochrome_npa_preview.png -- hdpi/monochrome_npa_preview.png + COMMAND ${PNGQUANT_CMD} xhdpi/monochrome_npa_preview.png -- xhdpi/monochrome_npa_preview.png + COMMAND ${PNGQUANT_CMD} xxhdpi/monochrome_npa_preview.png -- xxhdpi/monochrome_npa_preview.png + COMMAND ${PNGQUANT_CMD} xxxhdpi/monochrome_npa_preview.png -- xxxhdpi/monochrome_npa_preview.png + WORKING_DIRECTORY ${RESOURCES_DIR}/images/android) + add_custom_target(pngquant.android.launchimage COMMAND ${PNGQUANT_CMD} ldpi/splash_npa.png -- ldpi/splash_npa.png COMMAND ${PNGQUANT_CMD} mdpi/splash_npa.png -- mdpi/splash_npa.png @@ -507,13 +479,13 @@ 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 pngquant.android.adaptive.foreground.preview + pngquant.android.adaptive.monochrome + pngquant.android.adaptive.monochrome.beta + pngquant.android.adaptive.monochrome.preview pngquant.android.launchimage pngquant.android.launchimage.beta pngquant.android.launchimage.preview @@ -530,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) @@ -621,3 +588,4 @@ if(DOT) endif() include(Sphinx) +include(Tools.Libraries) 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 c21ea168a..51635da33 100644 --- a/cmake/android.toolchain.cmake +++ b/cmake/android.toolchain.cmake @@ -52,12 +52,11 @@ if(NOT ANDROID_BUILD_TOOLS_REVISION) endif() READ_REVISION(ANDROID_NDK_REVISION ".*Revision = ([0-9|\\.]+)" "${CMAKE_ANDROID_NDK}/source.properties") -READ_REVISION(ANDROID_SDK_REVISION ".*Revision=([0-9|\\.]+)" "${ANDROID_SDK}/cmdline-tools/latest/source.properties;${ANDROID_SDK}/tools/source.properties") 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) @@ -73,10 +72,6 @@ if(CMAKE_ANDROID_ARCH_ABI STREQUAL "armeabi-v7a") set(CMAKE_ANDROID_ARM_NEON ON) endif() -# Emulate NDK CMake-Variable as Qt 5.14 needs this (Multi-ABI) -set(ANDROID_ABI ${CMAKE_ANDROID_ARCH_ABI}) - - set(CMAKE_FIND_ROOT_PATH ${CMAKE_PREFIX_PATH} CACHE STRING "android find search path root") set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/cmake/cmd.cmake b/cmake/cmd.cmake index d2f666c43..d9fb3e648 100644 --- a/cmake/cmd.cmake +++ b/cmake/cmd.cmake @@ -1,4 +1,5 @@ -cmake_minimum_required(VERSION 3.1.0) +cmake_minimum_required(VERSION 3.13.0) +cmake_policy(SET CMP0057 NEW) ########################################### #### Usage: cmake -DCMD= -P cmake/cmd.cmake @@ -184,8 +185,29 @@ function(CHECK_FAILURE_CODES) string(REGEX REPLACE "/\\*[^(\\*/)]*\\*/" "" SINGLE_LINE ${SINGLE_LINE}) string(REGEX MATCHALL "([a-zA-Z0-9_]+)" FAILURE_CODES ${SINGLE_LINE}) + file(STRINGS "docs/failurecodes/failurecodes.rst" LINES_RST) + foreach(line_rst ${LINES_RST}) + #match this pattern: " - | **Card_Removed**" with spaces or tabs as whitespaces. + string(REGEX MATCH "[ \\t]+-[ \\t]+\\|[ \\t]+\\*\\*([A-Za-z0-9_]+)\\*\\*" MATCH ${line_rst}) + if(MATCH) + list(APPEND FAILURE_CODES_RST ${CMAKE_MATCH_1}) + endif() + endforeach() + + list(LENGTH FAILURE_CODES ENUM_CODE_COUNT) + list(LENGTH FAILURE_CODES_RST RST_CODE_COUNT) + if(NOT ENUM_CODE_COUNT EQUAL RST_CODE_COUNT) + message(FATAL_ERROR + "The failure code count in FailureCode.h (${ENUM_CODE_COUNT}) does not match the count in failurecodes.rst (${RST_CODE_COUNT})!") + endif() + file(GLOB_RECURSE SOURCE_FILES src/*.cpp) foreach(code ${FAILURE_CODES}) + if(NOT code IN_LIST FAILURE_CODES_RST) + message(FATAL_ERROR + "The failure code [${code}] is not part of failurecodes.rst. This hints a missing, duplicated or incorrectly spelled code in failurecodes.rst.") + endif() + set(COUNTER 0) foreach(file ${SOURCE_FILES}) file(READ ${file} CONTENT) @@ -194,7 +216,7 @@ function(CHECK_FAILURE_CODES) math(EXPR COUNTER ${COUNTER}+${OCCURRENCES}) endforeach() if(NOT COUNTER EQUAL 1) - message(FATAL_ERROR "${code} is not used excatly one time. Found ${COUNTER}") + message(FATAL_ERROR "${code} is not used exactly one time. Found ${COUNTER}") endif() endforeach() endfunction() 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 30bc1adb0..c9b41e12c 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -3,9 +3,9 @@ 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}/installation" "installation_integration" BUILDER changes html latex) - SPHINX_GEN("${CMAKE_CURRENT_SOURCE_DIR}/integration" "inte" BUILDER changes html latex) + SPHINX_GEN("${CMAKE_CURRENT_SOURCE_DIR}/failurecodes" "failurecodes" BUILDER changes html latex DEFAULT_LANG en) else() message(STATUS "No documentation will be generated") endif() diff --git a/docs/integration/conf.py.in b/docs/failurecodes/conf.py.in similarity index 89% rename from docs/integration/conf.py.in rename to docs/failurecodes/conf.py.in index d729e5e6b..cf14817dd 100644 --- a/docs/integration/conf.py.in +++ b/docs/failurecodes/conf.py.in @@ -41,8 +41,8 @@ source_suffix = '.rst' master_doc = 'index' # General information about the project. -project = 'AusweisApp2 Integration' -copyright = '2019-2023, Governikus GmbH & Co. KG' +project = '@PROJECT_NAME@ Failure Codes' +copyright = '2023, Governikus GmbH & Co. KG' author = 'Governikus GmbH & Co. KG' # The version info for the project you're documenting, acts as replacement for @@ -54,14 +54,12 @@ 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 = 'en' +language = '@SPHINX_LANG@' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. @@ -98,7 +96,7 @@ html_show_copyright = True html_scaled_image_link = False # Output file base name for HTML help builder. -htmlhelp_basename = 'AusweisApp2Integration' +htmlhelp_basename = '@PROJECT_NAME@ReleaseNotes' html_context = { 'display_github': False, @@ -120,11 +118,10 @@ latex_elements = { # Additional stuff for the LaTeX preamble. 'preamble': ''' -\\usepackage{lscape} -\\hypersetup{pdfauthor={Governikus GmbH \& Co. KG}, - pdftitle={AusweisApp2}, - pdfsubject={Integration}, - pdfkeywords={Integration}, +\hypersetup{pdfauthor={Governikus GmbH \& Co. KG}, + pdftitle={@PROJECT_NAME@}, + pdfsubject={Failure_Codes}, + pdfkeywords={failure, codes, sdk, api}, pdfproducer={LaTeX}, pdfcreator={Sphinx} } @@ -146,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@-Integration.tex', 'AusweisApp2 Integration', + (master_doc, '@PROJECT_NAME@-@VERSION_DVCS@-Failure-Codes-' + language + '.tex', '@PROJECT_NAME@ Failure Codes', 'Governikus GmbH \& Co. KG', 'howto'), ] @@ -169,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 new file mode 100644 index 000000000..01d68899a --- /dev/null +++ b/docs/failurecodes/failurecodes.rst @@ -0,0 +1,659 @@ +Failure Codes +============= +The |AppName| will send failure codes indicating what went wrong and where it happened as well as +how to solve it. + +Helpful tips +------------ +The following tips will help you to prevent many of the failures mentioned in the next section. +Also they assist you in receiving further guidance and help. + +.. _failure_code_card_position: + +Check ID card position +^^^^^^^^^^^^^^^^^^^^^^ +Check the position of your ID card on the smartphone or card reader. Especially with smartphones, +the field strength for the power supply of the ID card is not always sufficient. If you place your +smartphone on your ID card, please also ensure that your surface is not electrically conductive, +as this can then disrupt or prevent communication with the ID card. If all of the above does not +work, please see :ref:`failure_code_replace_card_or_card_reader`. + +.. _failure_code_contact_support: + +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 +|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 service provider contact information are available on the website on +which you have started the authentication. + +.. _failure_code_fix_connections_problems: + +Fix connection problems +^^^^^^^^^^^^^^^^^^^^^^^ +For any failure code that mentions connection issues in its cause, it is recommended to check your +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 |AppName|, the diagnosis, which is located in +the help section, may assist you in finding issues. + +.. _failure_code_replace_card_or_card_reader: + +Replace ID card of card reader +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +It cannot be ruled out that your ID card is defective or, due to necessary updates, initially +requires more power than your current smartphone or card reader can supply. If possible, try other +card readers or smartphones. +If the ID card still does not work you might need to replace it with a new one at your responsible +authority. + + +.. _failure_codes: + +Codes +----- + + - | **User_Cancelled** + | The user canceled the workflow. In the SDK case, the user can also be a third-party + application that has disconnected from the SDK. + | **Possible Solutions:** Complete the workflow without canceling. + + - | **Card_Removed** + | Possible causes for this failure are: + | 1 Unstable NFC connection + | 2 Removal of the ID card + | 3 Removal of the card reader + | 4 Cancellation of the remote access + | **Possible Solutions:** + | 1 :ref:`failure_code_card_position` + | 2 The ID card has to be present on the reader during the whole workflow + | 3 The card reader has to be attached during the whole workflow + | 4 You must not cancel the remote access during the whole workflow + + - | **Parse_TcToken_Invalid_Url** + | An authentication was started according to TR-03124-1 section 2.2.1.1. However, no valid + tcTokenURL was transmitted. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **Parse_TcToken_Missing_Url** + | An authentication was started according to TR-03124-1 section 2.2.1.1. However, the query + "tcTokenURL" is missing. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **Get_TcToken_Invalid_Url** + | An authentication was started according to TR-03124-1 section 2.2.1.1. However, no valid + tcTokenURL using the https scheme was transmitted. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **Get_TcToken_Invalid_Redirect_Url** + | The tcTokenURL call was answered with a redirect. The URL provided there is invalid or does + not use the https scheme. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **Get_TcToken_Invalid_Certificate_Key_Length** + | The TLS certificate transmitted by the server when retrieving the tcToken uses an insufficient + key length. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **Get_TcToken_Invalid_Ephemeral_Key_Length** + | The ephemeral key length generated by the TLS handshake to get the tcToken is insufficient. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **Get_TcToken_Invalid_Server_Reply** + | The server responded to the request for the tcToken neither with content nor with a + 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`. + + - | **Get_TcToken_Invalid_Data** + | The server responded to the request for the tcToken with content that does not comply + with TR-03124-1 section 2.6. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **Get_TcToken_Network_Error** + | A network error occurred while retrieving the tcToken. + | **Possible Solutions:** :ref:`failure_code_fix_connections_problems`. + + - | **Certificate_Check_Failed_No_Description** + | TR-03112-7 section 3.6.4.1 requires a description of the service provider certificate. + However, this was not transmitted by the service provider in the EAC1InputType. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **Certificate_Check_Failed_No_SubjectUrl_In_Description** + | TR-03124-1 section 2.7.3 requires that the service provider's URL is included in the + description of the certificate. The URL does not exist. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **Certificate_Check_Failed_Hash_Mismatch** + | TR-03124-1 section 2.7.3 requires that the hash of the certificate description matches that + stored in the certificate. These don't match. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **Certificate_Check_Failed_Same_Origin_Policy_Violation** + | TR-03124-1 section 2.7.3 requires that the tcTokenUrl has the same origin as the service + provider's URL from the certificate description. This condition is not met. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **Certificate_Check_Failed_Hash_Missing_In_Description** + | TR-03124-1 Section 2.7.3 requires that the hashes of all TLS certificates used are included in + the description of the service provider certificate. This condition is not met. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **Pre_Verification_No_Test_Environment** + | 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 |AppName|. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **Pre_Verification_Invalid_Certificate_Signature** + | At least one signature in the certificate chain used by the server is incorrect. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **Pre_Verification_Certificate_Expired** + | The certificate chain used by the server is currently not valid. + | **Possible Solutions:** Make sure your system time is set correctly. If the problem persists, + see :ref:`failure_code_inform_service_provider`. + + - | **Extract_Cvcs_From_Eac1_No_Unique_At** + | The server submitted a certificate chain that contained more than one terminal certificate. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **Extract_Cvcs_From_Eac1_No_Unique_Dv** + | The server transmitted a certificate chain containing more than one DV certificate. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **Extract_Cvcs_From_Eac1_At_Missing** + | The server transmitted a certificate chain that does not contain a terminal certificate. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **Extract_Cvcs_From_Eac1_Dv_Missing** + | The server transmitted a certificate chain that does not contain a DV certificate. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **Connect_Card_Connection_Failed** + | In order to communicate with the ID card, a connection must first be established. This process + failed. + | **Possible Solutions:** :ref:`failure_code_card_position`. + + - | **Connect_Card_Eid_Inactive** + | The PIN of the card is deactivated. The card can currently only be used with the CAN for + on-site reading. + | **Possible Solutions:** When your ID card was issued, the online ID card function (the PIN) was not + activated or you had the function deactivated afterwards. You can have the function activated + at the citizens' office (Bürgeramt) or activate it with the CAN at + https://www.pin-ruecksetzbrief-bestellen.de. + + - | **Prepace_Pace_Smart_Eid_Invalidated** + | The attempt to establish a connection with a PIN to a Smart-eID failed, because all + PIN-attempts have been used. + | **Possible Solutions:** The PIN is permanently disabled after 3 failed attempts. Please set up + your Smart-eID again. + + - | **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. + | **Possible Solutions:** :ref:`failure_code_contact_support`. + + - | **Establish_Pace_Channel_Puk_Inoperative** + | An attempt was made to set up a PACE channel with the PUK to unlock the PIN. However, the PUK + can no longer be used because it has already been used 10 times. + | **Possible Solutions:** The PIN can be unlocked with the PUK after three incorrect entries. + However, this is only possible ten times and you have reached that limit. However you can set + a new PIN at the citizens' office (Bürgeramt) or let it be set with the CAN at + https://www.pin-ruecksetzbrief-bestellen.de. + + - | **Establish_Pace_Channel_User_Cancelled** + | The user canceled the workflow on a comfort USB reader or a smartphone as a card reader + with keyboard mode enabled. + | **Possible Solutions:** Complete the workflow without canceling. + + - | **Maintain_Card_Connection_Pace_Unrecoverable** + | An error occurred while setting up the PACE channel that was not due to user error. + | **Possible Solutions:** The connection to the ID card could not be established with the PIN, + CAN, or PUK. The entered passwords have no influence on this. Please note + :ref:`failure_code_card_position`. + + - | **Did_Authenticate_Eac1_Card_Command_Failed** + | The 4th card command of the terminal authentication according to TR-0110-3 section B.3 failed. + | **Possible Solutions:** :ref:`failure_code_card_position`. + + - | **Process_Certificates_From_Eac2_Cvc_Chain_Missing** + | When setting up the PACE channel with PIN or CAN, the ID card communicated which certificate it + knew. However, the server sent a certificate chain that does not contain this certificate. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **Did_Authenticate_Eac2_Invalid_Cvc_Chain** + | When setting up the PACE channel with PIN or CAN, the ID card communicated which certificate it + knew. However, the server sent a certificate chain that does not contain this certificate. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **Did_Authenticate_Eac2_Card_Command_Failed** + | A terminal or chip authentication card command according to TR-0110-3 sections B.2 and B.3 + failed. + | **Possible Solutions:** :ref:`failure_code_card_position`. + + - | **Generic_Send_Receive_Paos_Unhandled** + | A message was sent by the server in the PAOS communication during authentication, that + could not be completely processed. + | **Possible Solutions:** :ref:`failure_code_contact_support`. + + - | **Generic_Send_Receive_Network_Error** + | A network error has occurred in the PAOS communication during authentication. + | **Possible Solutions:** :ref:`failure_code_fix_connections_problems`. + + - | **Generic_Send_Receive_Tls_Error** + | An authentication error occurred in the PAOS communication during the TLS handshake. The TLS + 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`. + + - | **Generic_Send_Receive_Client_Error** + | A client error 4xx occurred in the PAOS communication during authentication. + | **Possible Solutions:** :ref:`failure_code_contact_support`. + + - | **Generic_Send_Receive_Paos_Unknown** + | An unknown message was sent by the server in the PAOS communication during authentication. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **Generic_Send_Receive_Paos_Unexpected** + | An unexpected message was sent by the server in the PAOS communication during authentication. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **Generic_Send_Receive_Invalid_Ephemeral_Key_Length** + | The symmetric key generated by the TLS handshake for PAOS communication is not long enough. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **Generic_Send_Receive_Certificate_Error** + | The TLS certificate for PAOS communication uses key lengths that are too small or is not + included in the description of the service provider certificate. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **Generic_Send_Receive_Session_Resumption_Failed** + | Failed to resume TLS session during PAOS communication. + | **Possible Solutions:** :ref:`failure_code_contact_support`. + + - | **Transmit_Card_Command_Failed** + | During authentication, card commands transmitted in PAOS communication could not be correctly + transmitted to the card. + | **Possible Solutions:** :ref:`failure_code_card_position`. + + - | **Start_Paos_Response_Missing** + | The message "StartPaosResponse" from the server could not be evaluated because it does not + exist. + | **Possible Solutions:** :ref:`failure_code_contact_support`. + + - | **Start_Paos_Response_Error** + | 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`. + + - | **Check_Refresh_Address_Fatal_Tls_Error_Before_Reply** + | An error occurred during the TLS handshake when checking the return address after a successful + authentication. The TLS certificate is incorrect. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **Check_Refresh_Address_Invalid_Ephemeral_Key_Length** + | The symmetric key generated by the TLS handshake when calling the return address is not long + enough. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **Check_Refresh_Address_Service_Unavailable** + | 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 |AppName|. This + didn't work for checking the return address. + | **Possible Solutions:** :ref:`failure_code_fix_connections_problems`. + + - | **Check_Refresh_Address_Fatal_Tls_Error_After_Reply** + | When checking the return address after successful authentication, the TLS handshake could not + be completed successfully. + | **Possible Solutions:** :ref:`failure_code_fix_connections_problems`. + + - | **Check_Refresh_Address_Unknown_Network_Error** + | A unknown error occurred when checking the return address after successful authentication. + | **Possible Solutions:** :ref:`failure_code_fix_connections_problems`. + + - | **Check_Refresh_Address_Invalid_Http_Response** + | The call to the return address did not result in forwarding. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **Check_Refresh_Address_Empty** + | The call to the return address led to a redirect but no URL was supplied. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **Check_Refresh_Address_Invalid_Url** + | The call to the return address led to a redirect, but no correct URL was supplied. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **Check_Refresh_Address_No_Https_Scheme** + | The call to the return address led to a redirect, but delivered an URL without https scheme. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **Check_Refresh_Address_Fetch_Certificate_Error** + | The server certificate could not be obtained after tracing all redirects. + | **Possible Solutions:** :ref:`failure_code_fix_connections_problems`. + + - | **Check_Refresh_Address_Unsupported_Certificate** + | The check of the return address after a successful authentication was interrupted because the + server uses a TLS certificate with unsupported algorithms or key lengths. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **Check_Refresh_Address_Hash_Missing_In_Certificate** + | The server certificate of the return address is not included in the description of the service + provider certificate. + | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. + + - | **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 |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 |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 |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 |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 |AppName| sent a PIN change command to its core, but received an answer for a + different command. + | **Possible Solutions:** :ref:`failure_code_contact_support`. + + - | **Change_Pin_Input_Timeout** + | When changing a PIN, the user took too long to set the new PIN. Timeouts are currently only + known from card readers with a PIN pad, which also affects smartphones as card readers with + activated keyboard mode. + | **Possible Solutions:** Enter the PIN within 60 seconds. + + - | **Change_Pin_User_Cancelled** + | The user canceled the PIN change after entering the current valid PIN. Can only occur with + card readers with a PIN pad, which also affects smartphones as card readers with activated + keyboard mode. + | **Possible Solutions:** Carry out the PIN change without abortion. + + - | **Change_Pin_New_Pin_Mismatch** + | When changing a PIN, the user entered an incorrect confirmation of the new PIN. Can only occur + with USB card readers with a PIN pad. Smartphone as a card reader with activated keyboard mode + does not allow this behavior. + | **Possible Solutions:** Confirm the new PIN correctly. + + - | **Change_Pin_New_Pin_Invalid_Length** + | When changing a PIN, the user entered a new PIN with an incorrect length. Can only occur with + USB card readers with a PIN pad. However, there is no known device/case that allows this + possibility. Smartphone as a card reader with activated keyboard mode does not allow this + behavior. + | **Possible Solutions:** :ref:`failure_code_contact_support`. + + - | **Change_Pin_Unexpected_Transmit_Status** + | The command to change the PIN has been transmitted and answered. However, the answer is blank, + unknown, or unexpected. + | **Possible Solutions:** :ref:`failure_code_card_position`. + + - | **Change_Pin_Card_New_Pin_Mismatch** + | Like Change_Pin_New_Pin_Mismatch but at a higher protocol level. + | **Possible Solutions:** Confirm the new PIN correctly. + + - | **Change_Pin_Card_User_Cancelled** + | Like Change_Pin_User_Cancelled but at a higher log level. + | **Possible Solutions:** Carry out the PIN change without abortion. + + - | **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 |AppName| on Android that is used + through the SDK. + | **Possible Solutions:** :ref:`failure_code_contact_support`. + + - | **Prepare_Pace_Ifd_Unknown** + | The establishment of a PACE channel was requested by the client on a smartphone as a card + reader with activated keyboard mode. However, an unsupported password type was requested (PIN, + CAN, PUK are supported). + | **Possible Solutions:** :ref:`failure_code_contact_support`. + + - | **Establish_Pace_Ifd_Unknown** + | The establishment of a PACE channel was requested by the client on a smartphone as a card + reader with activated keyboard mode. However, an unsupported password type was requested (PIN, + CAN, PUK are supported). + | **Possible Solutions:** :ref:`failure_code_contact_support`. + + - | **Enter_Pace_Password_Ifd_User_Cancelled** + | Occurs when the user canceled entering the PIN, CAN, or PUK on a smartphone acting as a card + reader with keyboard mode enabled. + | **Possible Solutions:** :ref:`failure_code_contact_support`. + + - | **Enter_New_Pace_Pin_Ifd_User_Cancelled** + | Occurs when the user has canceled entering the new PIN during a PIN change on a smartphone + acting as a card reader with keyboard mode enabled. + | **Possible Solutions:** :ref:`failure_code_contact_support`. + + - | **Check_Status_Unavailable** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Check_Applet_Internal_Error** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Install_Smart_User_Cancelled** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Delete_Smart_User_Cancelled** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Delete_Personalization_User_Cancelled** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Update_Support_Info_User_Cancelled** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Install_Smart_Service_Response_Fail** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Install_Smart_Service_Response_Unsupported** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Install_Smart_Service_Response_Overload** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Install_Smart_Service_Response_Maintenance** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Install_Smart_Service_Response_Nfc_Disabled** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Install_Smart_Service_Response_Integrity_Check_Failed** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Install_Smart_Service_Response_Not_Authenticated** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Install_Smart_Service_Response_Network_Connection_Error** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Update_Support_Info_Call_Failed** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Update_Support_Info_Service_Response_Fail** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Update_Support_Info_Service_Response_Unsupported** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **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. + + - | **Insert_Card_No_SmartReader** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Insert_Card_Multiple_SmartReader** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **Insert_Card_Unknown_Eid_Type** + | Is not yet included in the product and will only be relevant with version 2.0.0. + + - | **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 new file mode 100644 index 000000000..2a5b880a0 --- /dev/null +++ b/docs/failurecodes/index.rst @@ -0,0 +1,23 @@ +.. only:: html + + .. image:: ../sdk/AusweisApp_Logo.svg + :alt: AusweisApp + :align: center + :width: 200pt + + | + + + + + +Table of contents +----------------- + +.. toctree:: + :maxdepth: 2 + + intro + failurecodes + + diff --git a/docs/failurecodes/intro.rst b/docs/failurecodes/intro.rst new file mode 100644 index 000000000..8667a88d2 --- /dev/null +++ b/docs/failurecodes/intro.rst @@ -0,0 +1,7 @@ +Introduction +============ +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 new file mode 100644 index 000000000..4f0782622 --- /dev/null +++ b/docs/failurecodes/locales/de/LC_MESSAGES/failurecodes.po @@ -0,0 +1,1337 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) 2023, Governikus GmbH & Co. KG +# This file is distributed under the same license as the AusweisApp2 Failure +# Codes package. +# FIRST AUTHOR , 2023. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: AusweisApp2 Failure Codes 1.26.3\n" +"Report-Msgid-Bugs-To: \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" +"Language-Team: de \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.12.1\n" + +msgid "Failure Codes" +msgstr "Fehlercodes" + +msgid "" +"The |AppName| will send failure codes indicating what went wrong and " +"where it happened as well as how to solve it." +msgstr "" +"Die |AppName| sendet Fehlercodes, um mitzuteilen, welche Fehler an " +"welcher Stelle aufgetreten sind und wie sie behoben werden können." + +msgid "Helpful tips" +msgstr "Hilfreiche Tipps" + +msgid "" +"The following tips will help you to prevent many of the failures " +"mentioned in the next section. Also they assist you in receiving further " +"guidance and help." +msgstr "" +"Die folgenden Tipps helfen, eine Vielzahl der im Nachfolgenden " +"beschriebenen Fehlersituationen zu verhindern oder an weiterführende " +"Hilfestellung zu gelangen." + +msgid "Check ID card position" +msgstr "Ausweis-Position überprüfen" + +msgid "" +"Check the position of your ID card on the smartphone or card reader. " +"Especially with smartphones, the field strength for the power supply of " +"the ID card is not always sufficient. If you place your smartphone on " +"your ID card, please also ensure that your surface is not electrically " +"conductive, as this can then disrupt or prevent communication with the ID" +" card. If all of the above does not work, please see " +":ref:`failure_code_replace_card_or_card_reader`." +msgstr "" +"Überprüfen Sie die Position Ihres Ausweises auf dem Smartphone oder " +"Kartenleser. Speziell bei Smartphones ist die Feldstärke für die " +"Stromversorgung des Ausweises nicht immer ausreichend. Sollten Sie Ihr " +"Smartphone auf Ihren Ausweis legen, achten Sie bitte auch darauf, dass " +"die Oberfläche nicht elektrisch leitend ist, da diese dann die " +"Kommunikation mit dem Ausweis stört bzw. verhindern kann. Falls keiner " +"der genannten Tipps hilft, lesen Sie bitte " +":ref:`failure_code_replace_card_or_card_reader`." + +msgid "Contact support" +msgstr "Support kontaktieren" + +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 |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 |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 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." + +msgid "Fix connection problems" +msgstr "Verbindungsprobleme beheben" + +msgid "" +"For any failure code that mentions connection issues in its cause, it is " +"recommended to check your 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 |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 |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" + +msgid "" +"It cannot be ruled out that your ID card is defective or, due to " +"necessary updates, initially requires more power than your current " +"smartphone or card reader can supply. If possible, try other card readers" +" or smartphones. If the ID card still does not work you might need to " +"replace it with a new one at your responsible authority." +msgstr "" +"Es kann nicht ausgeschlossen werden, dass Ihr Ausweis defekt ist oder " +"aufgrund notwendiger Updates zunächst mehr Strom benötigt, als Ihr " +"aktuelles Smartphone oder Kartenleser liefern kann. Probieren Sie nach " +"Möglichkeit weitere Kartenleser oder Smartphones. Falls Ihr Ausweis dann " +"immer noch nicht funktioniert, müssen Sie ihn möglicherweise bei Ihrer " +"zuständigen Behörde ersetzen." + +msgid "Codes" +msgstr "" + +msgid "**User_Cancelled**" +msgstr "" + +msgid "" +"The user canceled the workflow. In the SDK case, the user can also be a " +"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." + +msgid "**Possible Solutions:** Complete the workflow without canceling." +msgstr "**Mögliche Lösungen:** Den Vorgang ohne Abbruch durchführen." + +msgid "**Card_Removed**" +msgstr "" + +msgid "Possible causes for this failure are:" +msgstr "Mögliche Ursachen für diesen Fehler sind:" + +msgid "1 Unstable NFC connection" +msgstr "1 Instabile NFC-Verbindung" + +msgid "2 Removal of the ID card" +msgstr "2 Die Karte wurde entfernt" + +msgid "3 Removal of the card reader" +msgstr "3 Der Kartenleser wurde entfernt" + +msgid "4 Cancellation of the remote access" +msgstr "4 Der Fernzugriff wurde gestoppt" + +msgid "**Possible Solutions:**" +msgstr "**Mögliche Lösungen:**" + +msgid "1 :ref:`failure_code_card_position`" +msgstr "1 :ref:`failure_code_card_position`" + +msgid "2 The ID card has to be present on the reader during the whole workflow" +msgstr "2 Die Karte muss während des gesamten Vorgangs verfügbar sein" + +msgid "3 The card reader has to be attached during the whole workflow" +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 "**Parse_TcToken_Invalid_Url**" +msgstr "" + +msgid "" +"An authentication was started according to TR-03124-1 section 2.2.1.1. " +"However, no valid tcTokenURL was transmitted." +msgstr "" +"Eine Authentisierung wurde gemäß TR-03124-1 Abschnitt 2.2.1.1 gestartet. " +"Es wurde aber keine gültige tcTokenURL übermittelt." + +msgid "**Possible Solutions:** :ref:`failure_code_inform_service_provider`." +msgstr "**Mögliche Lösungen:** :ref:`failure_code_inform_service_provider`." + +msgid "**Parse_TcToken_Missing_Url**" +msgstr "" + +msgid "" +"An authentication was started according to TR-03124-1 section 2.2.1.1. " +"However, the query \"tcTokenURL\" is missing." +msgstr "" +"Eine Authentisierung wurde gemäß TR-03124-1 Abschnitt 2.2.1.1 gestartet. " +"Es fehlt jedoch der Query „tcTokenURL“." + +msgid "**Get_TcToken_Invalid_Url**" +msgstr "" + +msgid "" +"An authentication was started according to TR-03124-1 section 2.2.1.1. " +"However, no valid tcTokenURL using the https scheme was transmitted." +msgstr "" +"Eine Authentisierung wurde gemäß TR-03124-1 Abschnitt 2.2.1.1 gestartet. " +"Es wurde aber keine gültige tcTokenURL übermittelt, die das https-Schema " +"benutzt." + +msgid "**Get_TcToken_Invalid_Redirect_Url**" +msgstr "" + +msgid "" +"The tcTokenURL call was answered with a redirect. The URL provided there " +"is invalid or does not use the https scheme." +msgstr "" +"Der Aufruf der tcTokenURL wurde mit einer Weiterleitung beantwortet. Die " +"dort gelieferte URL ist ungültig oder nutzt kein https-Schema." + +msgid "**Get_TcToken_Invalid_Certificate_Key_Length**" +msgstr "" + +msgid "" +"The TLS certificate transmitted by the server when retrieving the tcToken" +" uses an insufficient key length." +msgstr "" +"Das vom Server übermittelte TLS-Zertifikat beim Abruf des tcToken nutzt " +"eine unzureichende Schlüssellänge." + +msgid "**Get_TcToken_Invalid_Ephemeral_Key_Length**" +msgstr "" + +msgid "" +"The ephemeral key length generated by the TLS handshake to get the " +"tcToken is insufficient." +msgstr "" +"Die durch den TLS-Handshake generierte Schlüssellänge für den Abruf des " +"tcToken ist unzureichend." + +msgid "**Get_TcToken_Invalid_Server_Reply**" +msgstr "" + +msgid "" +"The server responded to the request for the tcToken neither with content " +"nor with a forwarding." +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 "" + +msgid "The server responded to the request for the tcToken with empty content." +msgstr "" +"Der Server hat auf die Anfrage nach dem tcToken mit leerem Inhalt " +"reagiert." + +msgid "**Get_TcToken_Invalid_Data**" +msgstr "" + +msgid "" +"The server responded to the request for the tcToken with content that " +"does not comply with TR-03124-1 section 2.6." +msgstr "" +"Der Server hat auf die Anfrage nach dem tcToken mit Inhalt geantwortet, " +"der nicht TR-03124-1 Abschnitt 2.6 entspricht." + +msgid "**Get_TcToken_Network_Error**" +msgstr "" + +msgid "A network error occurred while retrieving the tcToken." +msgstr "Bei dem Abruf des tcToken ist ein Netzwerkfehler aufgetreten." + +msgid "**Possible Solutions:** :ref:`failure_code_fix_connections_problems`." +msgstr "**Mögliche Lösungen:** :ref:`failure_code_fix_connections_problems`." + +msgid "**Certificate_Check_Failed_No_Description**" +msgstr "" + +msgid "" +"TR-03112-7 section 3.6.4.1 requires a description of the service provider" +" certificate. However, this was not transmitted by the service provider " +"in the EAC1InputType." +msgstr "" +"TR-03112-7 Abschnitt 3.6.4.1 erfordert eine Beschreibung des " +"Diensteanbieter-Zertifikats. Diese wurde im EAC1InputType jedoch vom " +"Diensteanbieter nicht übermittelt." + +msgid "**Certificate_Check_Failed_No_SubjectUrl_In_Description**" +msgstr "" + +msgid "" +"TR-03124-1 section 2.7.3 requires that the service provider's URL is " +"included in the description of the certificate. The URL does not exist." +msgstr "" +"TR-03124-1 Abschnitt 2.7.3 erfordert, dass die URL des Diensteanbieters " +"in der Beschreibung des Zertifikats enthalten ist. Die URL ist nicht " +"vorhanden." + +msgid "**Certificate_Check_Failed_Hash_Mismatch**" +msgstr "" + +msgid "" +"TR-03124-1 section 2.7.3 requires that the hash of the certificate " +"description matches that stored in the certificate. These don't match." +msgstr "" +"TR-03124-1 Abschnitt 2.7.3 erfordert, dass der Hash der " +"Zertifikatsbeschreibung dem entspricht, der im Zertifikat hinterlegt " +"wurde. Diese stimmen nicht überein." + +msgid "**Certificate_Check_Failed_Same_Origin_Policy_Violation**" +msgstr "" + +msgid "" +"TR-03124-1 section 2.7.3 requires that the tcTokenUrl has the same origin" +" as the service provider's URL from the certificate description. This " +"condition is not met." +msgstr "" +"TR-03124-1 Abschnitt 2.7.3 erfordert, dass die tcTokenUrl den selben " +"Ursprung hat wie die URL des Diensteanbieters aus der Beschreibung des " +"Zertifikats. Diese Bedingung ist nicht erfüllt." + +msgid "**Certificate_Check_Failed_Hash_Missing_In_Description**" +msgstr "" + +msgid "" +"TR-03124-1 Section 2.7.3 requires that the hashes of all TLS certificates" +" used are included in the description of the service provider " +"certificate. This condition is not met." +msgstr "" +"TR-03124-1 Abschnitt 2.7.3 erfordert, dass die Hashes aller verwendeten " +"TLS-Zertifikate in der Beschreibung des Diensteanbieterzertifikats " +"enthalten sind. Diese Bedingung ist nicht erfüllt." + +msgid "**Pre_Verification_No_Test_Environment**" +msgstr "" + +msgid "" +"Occurs when the development mode of |AppName| is activated and a " +"genuine ID card is used." +msgstr "" +"Tritt auf, wenn der Entwicklermodus der |AppName| aktiviert ist und ein" +" Echtausweis verwendet wird." + +msgid "" +"**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." +msgstr "" +"**Mögliche Lösungen:** Deaktivieren des Entwicklermodus. Die Nutzung von " +"Echtausweisen ist mit aktiviertem Entwicklermodus nicht gestattet, da " +"dieser nur die Inbetriebnahme von Diensten mit Testausweisen erleichtern " +"soll." + +msgid "**Pre_Verification_Invalid_Certificate_Chain**" +msgstr "" + +msgid "" +"A certificate chain was sent from the server that is unknown to " +"|AppName|." +msgstr "" +"Vom Server wurde eine Zertifikatskette gesendet, die der |AppName| " +"nicht bekannt ist." + +msgid "**Pre_Verification_Invalid_Certificate_Signature**" +msgstr "" + +msgid "" +"At least one signature in the certificate chain used by the server is " +"incorrect." +msgstr "" +"Mindestens eine Signatur in der vom Server genutzten Zertifikatskette ist" +" nicht korrekt." + +msgid "**Pre_Verification_Certificate_Expired**" +msgstr "" + +msgid "The certificate chain used by the server is currently not valid." +msgstr "" +"Die vom Server genutzte Zertifikatskette ist zum aktuellen Zeitpunkt " +"nicht gültig." + +msgid "" +"**Possible Solutions:** Make sure your system time is set correctly. If " +"the problem persists, see :ref:`failure_code_inform_service_provider`." +msgstr "" +"**Mögliche Lösungen:** Stellen Sie sicher, dass Ihre Systemzeit korrekt " +"eingestellt ist. Falls das Problem weiterhin auftritt, beachten Sie auch " +":ref:`failure_code_inform_service_provider`." + +msgid "**Extract_Cvcs_From_Eac1_No_Unique_At**" +msgstr "" + +msgid "" +"The server submitted a certificate chain that contained more than one " +"terminal certificate." +msgstr "" +"Der Server hat eine Zertifikatskette übermittelt, in der mehr als ein " +"Terminal-Zertifikat enthalten ist." + +msgid "**Extract_Cvcs_From_Eac1_No_Unique_Dv**" +msgstr "" + +msgid "" +"The server transmitted a certificate chain containing more than one DV " +"certificate." +msgstr "" +"Der Server hat eine Zertifikatskette übermittelt, in der mehr als ein DV-" +"Zertifikat enthalten ist." + +msgid "**Extract_Cvcs_From_Eac1_At_Missing**" +msgstr "" + +msgid "" +"The server transmitted a certificate chain that does not contain a " +"terminal certificate." +msgstr "" +"Der Server hat eine Zertifikatskette übermittelt, in der kein Terminal-" +"Zertifikat enthalten ist." + +msgid "**Extract_Cvcs_From_Eac1_Dv_Missing**" +msgstr "" + +msgid "" +"The server transmitted a certificate chain that does not contain a DV " +"certificate." +msgstr "" +"Der Server hat eine Zertifikatskette übermittelt, in der kein DV-" +"Zertifikat enthalten ist." + +msgid "**Connect_Card_Connection_Failed**" +msgstr "" + +msgid "" +"In order to communicate with the ID card, a connection must first be " +"established. This process failed." +msgstr "" +"Für die Kommunikation mit der Karte muss zunächst eine Verbindung " +"hergestellt werden. Dieser Prozess ist fehlgeschlagen." + +msgid "**Possible Solutions:** :ref:`failure_code_card_position`." +msgstr "**Mögliche Lösungen:** :ref:`failure_code_card_position`." + +msgid "**Connect_Card_Eid_Inactive**" +msgstr "" + +msgid "" +"The PIN of the card is deactivated. The card can currently only be used " +"with the CAN for on-site reading." +msgstr "" +"Die PIN der Karte ist deaktiviert. Die Karte kann derzeit nur mit der CAN" +" beim Vor-Ort-Auslesen verwendet werden." + +msgid "" +"**Possible Solutions:** When your ID card was issued, the online ID card " +"function (the PIN) was not activated or you had the function deactivated " +"afterwards. You can have the function activated at the citizens' office " +"(Bürgeramt) or activate it with the CAN at https://www.pin-" +"ruecksetzbrief-bestellen.de." +msgstr "" +"**Mögliche Lösungen:** Bei der Ausgabe Ihres Ausweises wurde die Online-" +"Ausweisfunktion (die PIN) nicht aktiviert oder Sie haben die Funktion im " +"Nachhinein deaktivieren lassen. Sie können die Funktion im Bürgeramt " +"aktivieren lassen oder auf https://www.pin-ruecksetzbrief-bestellen.de " +"mit der CAN aktivieren." + +msgid "**Prepace_Pace_Smart_Eid_Invalidated**" +msgstr "" + +msgid "" +"The attempt to establish a connection with a PIN to a Smart-eID failed, " +"because all PIN-attempts have been used." +msgstr "" +"Der Versuch eine Verbindung mit der PIN zu einer Smart-eID aufzubauen ist" +" gescheitert, da bereits alle verfügbaren PIN-Versuche aufgebraucht " +"wurden." + +msgid "" +"**Possible Solutions:** The PIN is permanently disabled after 3 failed " +"attempts. Please set up your Smart-eID again." +msgstr "" +"**Mögliche Lösungen:** Im Gegensatz zu einem Ausweis kann die PIN nach 3 " +"Fehlversuchen nicht freigeschaltet werden. Bitte richten Sie Ihre Smart-" +"eID erneut ein." + +msgid "" +"**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 |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." + +msgid "**Establish_Pace_Channel_Basic_Reader_No_Pin**" +msgstr "" + +msgid "" +"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." +msgstr "" +"Bei der Verwendung eines Basislesers wurde versucht ein PACE-Kanal " +"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`." + +msgid "**Establish_Pace_Channel_Puk_Inoperative**" +msgstr "" + +msgid "" +"An attempt was made to set up a PACE channel with the PUK to unlock the " +"PIN. However, the PUK can no longer be used because it has already been " +"used 10 times." +msgstr "" +"Es wurde versucht ein PACE-Kanal mit der PUK aufzubauen um die PIN zu " +"entsperren. Die PUK ist jedoch nicht mehr nutzbar, da sie bereits zehn " +"Mal verwendet wurde." + +msgid "" +"**Possible Solutions:** The PIN can be unlocked with the PUK after three " +"incorrect entries. However, this is only possible ten times and you have " +"reached that limit. However you can set a new PIN at the citizens' office" +" (Bürgeramt) or let it be set with the CAN at https://www.pin-" +"ruecksetzbrief-bestellen.de." +msgstr "" +"**Mögliche Lösungen:** Die PIN kann nach dreimaliger Falscheingabe mit " +"der PUK freigeschaltet werden. Dies ist jedoch nur zehn Mal möglich und " +"Sie haben diese Grenze erreicht. Sie können dennoch im Bürgeramt eine " +"neue PIN setzen oder auf https://www.pin-ruecksetzbrief-bestellen.de mit " +"der CAN setzen lassen." + +msgid "**Establish_Pace_Channel_User_Cancelled**" +msgstr "" + +msgid "" +"The user canceled the workflow on a comfort USB reader or a smartphone as" +" a card reader with keyboard mode enabled." +msgstr "" +"Der Benutzer hat den Arbeitsablauf auf einem USB-Komfortleser oder einem " +"Smartphone als Kartenleser mit aktiviertem Tastaturmodus abgebrochen." + +msgid "**Maintain_Card_Connection_Pace_Unrecoverable**" +msgstr "" + +msgid "" +"An error occurred while setting up the PACE channel that was not due to " +"user error." +msgstr "" +"Beim Aufbau des PACE-Kanals ist ein Fehler aufgetreten, der nicht auf " +"Benutzerfehler zurückzuführen ist." + +msgid "" +"**Possible Solutions:** The connection to the ID card could not be " +"established with the PIN, CAN, or PUK. The entered passwords have no " +"influence on this. Please note :ref:`failure_code_card_position`." +msgstr "" +"**Mögliche Lösungen:** Die Verbindung zum Ausweis konnte mit der PIN, CAN" +" oder PUK nicht hergestellt werden. Die eingegebenen Passwörter haben " +"darauf keinen Einfluss. Bitte beachten Sie " +":ref:`failure_code_card_position`." + +msgid "**Did_Authenticate_Eac1_Card_Command_Failed**" +msgstr "" + +msgid "" +"The 4th card command of the terminal authentication according to " +"TR-0110-3 section B.3 failed." +msgstr "" +"Das 4. Kartenkommando der Terminal-Authentisierung gemäß TR-0110-3 " +"Abschnitt B.3 ist fehlgeschlagen." + +msgid "**Process_Certificates_From_Eac2_Cvc_Chain_Missing**" +msgstr "" + +msgid "" +"When setting up the PACE channel with PIN or CAN, the ID card " +"communicated which certificate it knew. However, the server sent a " +"certificate chain that does not contain this certificate." +msgstr "" +"Beim Aufbau des PACE-Kanals mit PIN oder CAN hat die Karte mitgeteilt, " +"welches Zertifikat ihr bekannt ist. Der Server hat aber eine " +"Zertifikatskette gesendet, in der dieses Zertifikat nicht enthalten ist." + +msgid "**Did_Authenticate_Eac2_Invalid_Cvc_Chain**" +msgstr "" + +msgid "**Did_Authenticate_Eac2_Card_Command_Failed**" +msgstr "" + +msgid "" +"A terminal or chip authentication card command according to TR-0110-3 " +"sections B.2 and B.3 failed." +msgstr "" +"Ein Kartenkommando der Terminal- oder Chip-Authentisierung gemäß " +"TR-0110-3 Abschnitt B.2 und B.3 ist fehlgeschlagen." + +msgid "**Generic_Send_Receive_Paos_Unhandled**" +msgstr "" + +msgid "" +"A message was sent by the server in the PAOS communication during " +"authentication, that could not be completely processed." +msgstr "" +"Bei einer Authentisierung ist eine Nachricht vom Server in der PAOS-" +"Kommunikation gesendet worden, die nicht vollständig verarbeitet werden " +"konnte." + +msgid "**Generic_Send_Receive_Network_Error**" +msgstr "" + +msgid "" +"A network error has occurred in the PAOS communication during " +"authentication." +msgstr "" +"Bei einer Authentisierung ist ein Netzwerkfehler in der PAOS-" +"Kommunikation aufgetreten." + +msgid "**Generic_Send_Receive_Tls_Error**" +msgstr "" + +msgid "" +"An authentication error occurred in the PAOS communication during the TLS" +" handshake. The TLS certificate is incorrect." +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 "" + +msgid "" +"A server error 5xx occurred in the PAOS communication during " +"authentication." +msgstr "" +"Bei einer Authentisierung ist ein Serverfehler 5xx in der PAOS-" +"Kommunikation aufgetreten." + +msgid "**Generic_Send_Receive_Client_Error**" +msgstr "" + +msgid "" +"A client error 4xx occurred in the PAOS communication during " +"authentication." +msgstr "" +"Bei einer Authentisierung ist ein Clientfehler 4xx in der PAOS-" +"Kommunikation aufgetreten." + +msgid "**Generic_Send_Receive_Paos_Unknown**" +msgstr "" + +msgid "" +"An unknown message was sent by the server in the PAOS communication " +"during authentication." +msgstr "" +"Bei einer Authentisierung ist vom Server eine unbekannte Nachricht in der" +" PAOS-Kommunikation gesendet worden." + +msgid "**Generic_Send_Receive_Paos_Unexpected**" +msgstr "" + +msgid "" +"An unexpected message was sent by the server in the PAOS communication " +"during authentication." +msgstr "" +"Bei einer Authentisierung ist eine unerwartete Nachricht vom Server in " +"der PAOS-Kommunikation gesendet worden." + +msgid "**Generic_Send_Receive_Invalid_Ephemeral_Key_Length**" +msgstr "" + +msgid "" +"The symmetric key generated by the TLS handshake for PAOS communication " +"is not long enough." +msgstr "" +"Der durch den TLS-Handshake generierte symmetrische Schlüssel für die " +"PAOS-Kommunikation ist nicht lang genug." + +msgid "**Generic_Send_Receive_Certificate_Error**" +msgstr "" + +msgid "" +"The TLS certificate for PAOS communication uses key lengths that are too " +"small or is not included in the description of the service provider " +"certificate." +msgstr "" +"Das TLS-Zertifikat für die PAOS-Kommunikation verwendet zu kleine " +"Schlüssellängen oder ist nicht in der Beschreibung des " +"Diensteanbieterzertifikats enthalten." + +msgid "**Generic_Send_Receive_Session_Resumption_Failed**" +msgstr "" + +msgid "Failed to resume TLS session during PAOS communication." +msgstr "" +"Die Wiederaufnahme der TLS-Session während der PAOS-Kommunikation ist " +"fehlgeschlagen." + +msgid "**Transmit_Card_Command_Failed**" +msgstr "" + +msgid "" +"During authentication, card commands transmitted in PAOS communication " +"could not be correctly transmitted to the card." +msgstr "" +"Bei der Authentisierung konnten in der PAOS-Kommunikation übertragene " +"Kartenkommandos nicht korrekt an die Karte übermittelt werden." + +msgid "**Start_Paos_Response_Missing**" +msgstr "" + +msgid "" +"The message \"StartPaosResponse\" from the server could not be evaluated " +"because it does not exist." +msgstr "" +"Die Nachricht \"StartPaosResponse\" vom Server konnte nicht ausgewertet " +"werden, da sie nicht vorhanden ist." + +msgid "**Start_Paos_Response_Error**" +msgstr "" + +msgid "" +"The \"StartPaosResponse\" message from the server returned an error. The " +"|AppName| or the ID card did not behave as expected by the server." +msgstr "" +"Die Nachricht \"StartPaosResponse\" vom Server hat einen Fehler " +"geliefert. Die |AppName| oder die Karte hat sich nicht entsprechend der" +" Erwartung des Servers verhalten." + +msgid "**Check_Refresh_Address_Fatal_Tls_Error_Before_Reply**" +msgstr "" + +msgid "" +"An error occurred during the TLS handshake when checking the return " +"address after a successful authentication. The TLS certificate is " +"incorrect." +msgstr "" +"Bei der Überprüfung der Rücksprungadresse nach einer erfolgreichen " +"Authentisierung ist während des TLS-Handshakes ein Fehler aufgetreten. " +"Das TLS-Zertifikat ist fehlerhaft." + +msgid "**Check_Refresh_Address_Invalid_Ephemeral_Key_Length**" +msgstr "" + +msgid "" +"The symmetric key generated by the TLS handshake when calling the return " +"address is not long enough." +msgstr "" +"Der durch den TLS-Handshake generierte symmetrische Schlüssel beim Aufruf" +" der Rücksprungadresse ist nicht lang genug." + +msgid "**Check_Refresh_Address_Service_Unavailable**" +msgstr "" + +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 "" + +msgid "" +"The call to the return address did not provide an answer within 30 " +"seconds." +msgstr "" +"Der Aufruf der Rücksprungadresse hat keine Antwort innerhalb von 30 " +"Sekunden geliefert." + +msgid "**Check_Refresh_Address_Proxy_Error**" +msgstr "" + +msgid "" +"A proxy server was configured by the operating system or the settings of " +"|AppName|. This didn't work for checking the return address." +msgstr "" +"Durch das Betriebssystem oder die Einstellungen der |AppName| wurde ein" +" Proxyserver konfiguriert. Dieser hat für die Überprüfung der " +"Rücksprungadresse nicht funktioniert." + +msgid "**Check_Refresh_Address_Fatal_Tls_Error_After_Reply**" +msgstr "" + +msgid "" +"When checking the return address after successful authentication, the TLS" +" handshake could not be completed successfully." +msgstr "" +"Bei der Überprüfung der Rücksprungadresse nach einer erfolgreichen " +"Authentisierung konnte der TLS-Handshake nicht erfolgreich beendet " +"werden." + +msgid "**Check_Refresh_Address_Unknown_Network_Error**" +msgstr "" + +msgid "" +"A unknown error occurred when checking the return address after " +"successful authentication." +msgstr "" +"Bei der Überprüfung der Rücksprungadresse nach einer erfolgreichen " +"Authentisierung ist ein nicht erwarteter Fehler aufgetreten." + +msgid "**Check_Refresh_Address_Invalid_Http_Response**" +msgstr "" + +msgid "The call to the return address did not result in forwarding." +msgstr "Der Aufruf der Rücksprungadresse hat nicht zu einer Weiterleitung geführt." + +msgid "**Check_Refresh_Address_Empty**" +msgstr "" + +msgid "The call to the return address led to a redirect but no URL was supplied." +msgstr "" +"Der Aufruf der Rücksprungadresse hat zu einer Weiterleitung geführt aber " +"keine URL mitgeliefert." + +msgid "**Check_Refresh_Address_Invalid_Url**" +msgstr "" + +msgid "" +"The call to the return address led to a redirect, but no correct URL was " +"supplied." +msgstr "" +"Der Aufruf der Rücksprungadresse hat zu einer Weiterleitung geführt aber " +"keine korrekte URL mitgeliefert." + +msgid "**Check_Refresh_Address_No_Https_Scheme**" +msgstr "" + +msgid "" +"The call to the return address led to a redirect, but delivered an URL " +"without https scheme." +msgstr "" +"Der Aufruf der Rücksprungadresse hat zu einer Weiterleitung geführt aber " +"eine URL ohne https-Schema mitgeliefert." + +msgid "**Check_Refresh_Address_Fetch_Certificate_Error**" +msgstr "" + +msgid "The server certificate could not be obtained after tracing all redirects." +msgstr "" +"Das Server-Zertifikat konnte nach Verfolgung aller Weiterleitungen nicht " +"abgerufen werden." + +msgid "**Check_Refresh_Address_Unsupported_Certificate**" +msgstr "" + +msgid "" +"The check of the return address after a successful authentication was " +"interrupted because the server uses a TLS certificate with unsupported " +"algorithms or key lengths." +msgstr "" +"Die Überprüfung der Rücksprungadresse nach einer erfolgreichen " +"Authentisierung wurde unterbrochen, da der Server ein TLS-Zertifikat mit " +"nicht unterstützten Algorithmen oder Schlüssellängen nutzt." + +msgid "**Check_Refresh_Address_Hash_Missing_In_Certificate**" +msgstr "" + +msgid "" +"The server certificate of the return address is not included in the " +"description of the service provider certificate." +msgstr "" +"Das Server-Zertifikat der Rücksprungadresse ist nicht in der Beschreibung" +" des Diensteanbieterzertifikats enthalten." + +msgid "" +"**Possible Solutions:** If the problem occurs repeatedly and changing the" +" browser does not help, please :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 "**Browser_Send_Failed**" +msgstr "" + +msgid "" +"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 |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 |AppName|, such as " +"self-authentication." +msgstr "" +"Bei der Kommunikation mit einem Diensteanbieter ist ein Netzwerkfehler " +"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**" +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 |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 |AppName| heraus gestartet werden, " +"wie zum Beispiel die Selbstauskunft." + +msgid "**Generic_Provider_Communication_Certificate_Error**" +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 |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 |AppName| heraus gestartet werden, wie zum Beispiel die " +"Selbstauskunft." + +msgid "**Generic_Provider_Communication_Tls_Error**" +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 |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 |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 "" + +msgid "" +"The authentication for the self-authentication was completed " +"successfully, but the server then did not transmit the read data " +"correctly." +msgstr "" +"Die Authentisierung für die Selbstauskunft wurde erfolgreich durchlaufen," +" der Server hat die ausgelesenen Daten im Anschluss aber nicht korrekt " +"übermittelt." + +msgid "**Change_Pin_No_SetEidPinCommand_Response**" +msgstr "" + +msgid "" +"The |AppName| sent a PIN change command to its core, but received an " +"answer for a different command." +msgstr "" +"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**" +msgstr "" + +msgid "" +"When changing a PIN, the user took too long to set the new PIN. Timeouts " +"are currently only known from card readers with a PIN pad, which also " +"affects smartphones as card readers with activated keyboard mode." +msgstr "" +"Der Benutzer hat bei einer PIN-Änderung zu lange gebraucht, um die neue " +"PIN festzulegen. Timeouts sind aktuell nur von Kartenlesern mit PIN-Pad " +"bekannt, was auch ein Smartphone als Kartenleser mit aktiviertem " +"Tastaturmodus betrifft." + +msgid "**Possible Solutions:** Enter the PIN within 60 seconds." +msgstr "**Mögliche Lösungen:** Die PIN innerhalb von 60 Sekunden eingeben." + +msgid "**Change_Pin_User_Cancelled**" +msgstr "" + +msgid "" +"The user canceled the PIN change after entering the current valid PIN. " +"Can only occur with card readers with a PIN pad, which also affects " +"smartphones as card readers with activated keyboard mode." +msgstr "" +"Der Benutzer hat die PIN-Änderung nach Eingabe der aktuellen gültigen PIN" +" abgebrochen. Kann nur bei Kartenlesern mit PIN-Pad auftreten, was auch " +"ein Smartphone als Kartenleser mit aktiviertem Tastaturmodus betrifft." + +msgid "**Possible Solutions:** Carry out the PIN change without abortion." +msgstr "**Mögliche Lösungen:** Die PIN-Änderung ohne Abbruch durchführen." + +msgid "**Change_Pin_New_Pin_Mismatch**" +msgstr "" + +msgid "" +"When changing a PIN, the user entered an incorrect confirmation of the " +"new PIN. Can only occur with USB card readers with a PIN pad. Smartphone " +"as a card reader with activated keyboard mode does not allow this " +"behavior." +msgstr "" +"Der Benutzer hat bei einer PIN-Änderung eine falsche Bestätigung der " +"neuen PIN eingegeben. Kann nur bei USB-Kartenlesern mit PIN-Pad " +"auftreten. Ein Smartphone als Kartenleser mit aktiviertem Tastaturmodus " +"lässt dieses Verhalten nicht zu." + +msgid "**Possible Solutions:** Confirm the new PIN correctly." +msgstr "**Mögliche Lösungen:** Die neue PIN korrekt bestätigen." + +msgid "**Change_Pin_New_Pin_Invalid_Length**" +msgstr "" + +msgid "" +"When changing a PIN, the user entered a new PIN with an incorrect length." +" Can only occur with USB card readers with a PIN pad. However, there is " +"no known device/case that allows this possibility. Smartphone as a card " +"reader with activated keyboard mode does not allow this behavior." +msgstr "" +"Der Benutzer hat bei einer PIN-Änderung eine neue PIN mit einer falschen " +"Länge eingegeben. Kann nur bei USB-Kartenlesern mit PIN-Pad auftreten. Es" +" ist jedoch kein Gerät/Fall bekannt, das diese Möglichkeit zulässt. Ein " +"Smartphone als Kartenleser mit aktiviertem Tastaturmodus lässt dieses " +"Verhalten nicht zu." + +msgid "**Change_Pin_Unexpected_Transmit_Status**" +msgstr "" + +msgid "" +"The command to change the PIN has been transmitted and answered. However," +" the answer is blank, unknown, or unexpected." +msgstr "" +"Das Kommando zur Änderung der PIN wurde übertragen und beantwortet. Die " +"Antwort ist jedoch leer, unbekannt oder unerwartet." + +msgid "**Change_Pin_Card_New_Pin_Mismatch**" +msgstr "" + +msgid "Like Change_Pin_New_Pin_Mismatch but at a higher protocol level." +msgstr "Wie Change_Pin_New_Pin_Mismatch aber auf einer höheren Protokollebene." + +msgid "**Change_Pin_Card_User_Cancelled**" +msgstr "" + +msgid "Like Change_Pin_User_Cancelled but at a higher log level." +msgstr "Wie Change_Pin_User_Cancelled aber auf einer höheren Protokollebene." + +msgid "**Start_Ifd_Service_Failed**" +msgstr "" + +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 |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 |AppName| auf Android, der durch das SDK genutzt wird." + +msgid "**Prepare_Pace_Ifd_Unknown**" +msgstr "" + +msgid "" +"The establishment of a PACE channel was requested by the client on a " +"smartphone as a card reader with activated keyboard mode. However, an " +"unsupported password type was requested (PIN, CAN, PUK are supported)." +msgstr "" +"Auf einem Smartphone als Kartenleser mit aktiviertem Tastaturmodus wurde " +"der Aufbau eines PACE-Kanals durch den Client angefordert. Dabei wurde " +"jedoch ein nicht unterstützter Passworttyp angefragt (Unterstützt werden " +"PIN, CAN, PUK)." + +msgid "**Establish_Pace_Ifd_Unknown**" +msgstr "" + +msgid "**Enter_Pace_Password_Ifd_User_Cancelled**" +msgstr "" + +msgid "" +"Occurs when the user canceled entering the PIN, CAN, or PUK on a " +"smartphone acting as a card reader with keyboard mode enabled." +msgstr "" +"Tritt auf, wenn der Benutzer die Eingabe der PIN, CAN oder PUK auf einem " +"Smartphone als Kartenleser mit aktiviertem Tastaturmodus abgebrochen hat." + +msgid "**Enter_New_Pace_Pin_Ifd_User_Cancelled**" +msgstr "" + +msgid "" +"Occurs when the user has canceled entering the new PIN during a PIN " +"change on a smartphone acting as a card reader with keyboard mode " +"enabled." +msgstr "" +"Tritt auf, wenn der Benutzer die Eingabe der neuen PIN bei einer PIN-" +"Änderung auf einem Smartphone als Kartenleser mit aktiviertem " +"Tastaturmodus abgebrochen hat." + +msgid "**Check_Status_Unavailable**" +msgstr "" + +msgid "" +"Is not yet included in the product and will only be relevant with version" +" 2.0.0." +msgstr "" +"Ist noch nicht im Produkt enthalten und wird erst mit der Version 2.0.0 " +"relevant." + +msgid "**Check_Applet_Internal_Error**" +msgstr "" + +msgid "**Install_Smart_User_Cancelled**" +msgstr "" + +msgid "**Delete_Smart_User_Cancelled**" +msgstr "" + +msgid "**Delete_Personalization_User_Cancelled**" +msgstr "" + +msgid "**Update_Support_Info_User_Cancelled**" +msgstr "" + +msgid "**Install_Smart_Service_Response_Fail**" +msgstr "" + +msgid "**Install_Smart_Service_Response_Unsupported**" +msgstr "" + +msgid "**Install_Smart_Service_Response_Overload**" +msgstr "" + +msgid "**Install_Smart_Service_Response_Maintenance**" +msgstr "" + +msgid "**Install_Smart_Service_Response_Nfc_Disabled**" +msgstr "" + +msgid "**Install_Smart_Service_Response_Integrity_Check_Failed**" +msgstr "" + +msgid "**Install_Smart_Service_Response_Not_Authenticated**" +msgstr "" + +msgid "**Install_Smart_Service_Response_Network_Connection_Error**" +msgstr "" + +msgid "**Update_Support_Info_Call_Failed**" +msgstr "" + +msgid "**Update_Support_Info_Service_Response_Fail**" +msgstr "" + +msgid "**Update_Support_Info_Service_Response_Unsupported**" +msgstr "" + +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 "**Insert_Card_No_SmartReader**" +msgstr "" + +msgid "**Insert_Card_Multiple_SmartReader**" +msgstr "" + +msgid "**Insert_Card_Unknown_Eid_Type**" +msgstr "" + +msgid "**Insert_Card_Invalid_SmartReader**" +msgstr "" + +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 new file mode 100644 index 000000000..d791ceeec --- /dev/null +++ b/docs/failurecodes/locales/de/LC_MESSAGES/index.po @@ -0,0 +1,31 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) 2023, Governikus GmbH & Co. KG +# This file is distributed under the same license as the AusweisApp2 Failure +# Codes package. +# FIRST AUTHOR , 2023. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: AusweisApp2 Failure Codes 1.26.3\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-03-21 12:25+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language: de\n" +"Language-Team: de \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.12.1\n" + +msgid "AusweisApp" +msgstr "" + +msgid ".. image:: ../sdk/AusweisApp_Logo.svg" +msgstr "" + +msgid "Table of contents" +msgstr "Inhaltsverzeichnis" + diff --git a/docs/failurecodes/locales/de/LC_MESSAGES/intro.po b/docs/failurecodes/locales/de/LC_MESSAGES/intro.po new file mode 100644 index 000000000..39fe7796e --- /dev/null +++ b/docs/failurecodes/locales/de/LC_MESSAGES/intro.po @@ -0,0 +1,38 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) 2023, Governikus GmbH & Co. KG +# This file is distributed under the same license as the AusweisApp2 Failure +# Codes package. +# FIRST AUTHOR , 2023. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: AusweisApp2 Failure Codes 1.26.3\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-03-27 13:03+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language: de\n" +"Language-Team: de \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.12.1\n" + +msgid "Introduction" +msgstr "Einführung" + +msgid "" +"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." +msgstr "" +"Diese Dokumentation listet alle Fehlercodes auf, die beim Verwenden der " +"|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 a1aea8ea2..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: @@ -173,8 +169,8 @@ dargestellt: remindToClose - showSetupAssistant - + uiStartupModule + DEFAULT transportPinReminder customProxyType @@ -183,16 +179,12 @@ dargestellt: proxy.example.org customProxyPort 1337 - autoUpdateCheck - keylessPassword shuffleScreenKeyboard visualPrivacy - history.enable - enableCanAllowed skipRightsOnCanAllowed @@ -209,16 +201,14 @@ macOS Windows ======================= ======================= autoCloseWindow AUTOHIDE remindToClose REMINDTOCLOSE -showSetupAssistant ASSISTANT +uiStartupModule ASSISTANT transportPinReminder TRANSPORTPINREMINDER customProxyType CUSTOMPROXYTYPE customProxyPort CUSTOMPROXYPORT customProxyHost CUSTOMPROXYHOST -autoUpdateCheck UPDATECHECK keylessPassword ONSCREENKEYBOARD shuffleScreenKeyboard SHUFFLESCREENKEYBOARD visualPrivacy SECURESCREENKEYBOARD -history.enable HISTORY enableCanAllowed ENABLECANALLOWED skipRightsOnCanAllowed SKIPRIGHTSONCANALLOWED ======================= ======================= @@ -238,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. @@ -275,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. @@ -297,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. @@ -307,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 @@ -317,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 @@ -327,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 2f03af350..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 @@ -160,8 +157,8 @@ the file must be "com.governikus.AusweisApp2.plist". The content is shown below: remindToClose - showSetupAssistant - + uiStartupModule + DEFAULT transportPinReminder customProxyType @@ -170,16 +167,12 @@ the file must be "com.governikus.AusweisApp2.plist". The content is shown below: proxy.example.org customProxyPort 1337 - autoUpdateCheck - keylessPassword shuffleScreenKeyboard visualPrivacy - history.enable - enableCanAllowed skipRightsOnCanAllowed @@ -195,16 +188,14 @@ macOS Windows ======================= ======================= autoCloseWindow AUTOHIDE remindToClose REMINDTOCLOSE -showSetupAssistant ASSISTANT +uiStartupModule ASSISTANT transportPinReminder TRANSPORTPINREMINDER customProxyType CUSTOMPROXYTYPE customProxyPort CUSTOMPROXYPORT customProxyHost CUSTOMPROXYHOST -autoUpdateCheck UPDATECHECK keylessPassword ONSCREENKEYBOARD shuffleScreenKeyboard SHUFFLESCREENKEYBOARD visualPrivacy SECURESCREENKEYBOARD -history.enable HISTORY enableCanAllowed ENABLECANALLOWED skipRightsOnCanAllowed SKIPRIGHTSONCANALLOWED ======================= ======================= @@ -223,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. -It may be necessary to deactive AP isolation on your router. +|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. @@ -277,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 @@ -285,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 @@ -295,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 384604b72..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' @@ -61,7 +61,7 @@ today = ' ' # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = 'en' +language = '@SPHINX_LANG@' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. @@ -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/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/1.26.4.rst b/docs/releasenotes/1.26.4.rst new file mode 100644 index 000000000..97bc1c2e0 --- /dev/null +++ b/docs/releasenotes/1.26.4.rst @@ -0,0 +1,31 @@ +AusweisApp2 1.26.4 +^^^^^^^^^^^^^^^^^^ + +**Releasedatum:** 28. April 2023 + + +Anwender +"""""""" +- Unter macOS wurde das Fensterverhalten korrigiert. + +- Kleinere Fehlerbehebungen und Optimierungen. + + +Entwickler +"""""""""" +- INTERRUPT zeigt nun nicht immer ein Fehlersymbol an. + +- Der Header "Access-Control-Allow-Private-Network" ist + nun beim Status-Request gesetzt. + +- CHANGE_PIN liefert nun auch einen FailureCode. + +- Ein Absturz bei AirPlay im iOS-SDK wurde behoben. + +- Private Symbole im iOS-SDK wurden korrigiert. + +- Der Simulator unterstützt nun auch explizite + private Schlüssel als Parameter. + +- Der Abbruch-Button im iOS-Scan-Dialog des SDK bricht + nun wieder den Workflow ab. diff --git a/docs/releasenotes/1.26.5.rst b/docs/releasenotes/1.26.5.rst new file mode 100644 index 000000000..450f414bb --- /dev/null +++ b/docs/releasenotes/1.26.5.rst @@ -0,0 +1,36 @@ +AusweisApp2 1.26.5 +^^^^^^^^^^^^^^^^^^ + +**Releasedatum:** 25. Juli 2023 + + +Anwender +"""""""" +- Überarbeitung des Kopplungsprozesses der Funktion Smartphone als Kartenleser. + Beide an der Kopplung beteiligten Geräte müssen auf Version 1.26.5 aktualisiert werden. + Versionen kleiner als 1.26.5 lassen sich nicht mit einer AusweisApp2 1.26.5 koppeln. + +- Die Anzeige des Fortschritts erfolgt jetzt auch auf einem Smartphone als Kartenleser. + +- Der Tastaturmodus auf einem Smartphone als Kartenleser ist jetzt standardmäßig aktiviert. + +- Bei Nutzung des Tastaturmodus auf einem Smartphone als Kartenleser kann in den Einstellungen eine + erneute Anzeige der Berechtigungen aktiviert werden. + +- Ergänzung eines monochromen Icons unter Android. + +- Berücksichtigung von Command + W unter macOS. + +- Entfernung der Updatefunktion auf macOS zugunsten des Mac App Store. + +- Kleinere Fehlerbehebungen und Optimierungen. + + +Entwickler +"""""""""" +- Die Dokumentation für die Installation in Firmennetzwerken unter macOS für die Einstellung zum + Einrichtungsassistenten wurde korrigiert. + +- Optimierung der Größe des Android SDK. + +- Aktualisierung von OpenSSL auf die Version 3.0.9. diff --git a/docs/releasenotes/1.26.6.rst b/docs/releasenotes/1.26.6.rst new file mode 100644 index 000000000..58ecd2cad --- /dev/null +++ b/docs/releasenotes/1.26.6.rst @@ -0,0 +1,13 @@ +AusweisApp2 1.26.6 +^^^^^^^^^^^^^^^^^^ + +**Releasedatum:** 27. Juli 2023 + + +Anwender +"""""""" +- Ein möglicher Absturz beim Start unter Android wurde behoben. + + +Entwickler +"""""""""" diff --git a/docs/releasenotes/1.26.7.rst b/docs/releasenotes/1.26.7.rst new file mode 100644 index 000000000..b66cb0c64 --- /dev/null +++ b/docs/releasenotes/1.26.7.rst @@ -0,0 +1,13 @@ +AusweisApp2 1.26.7 +^^^^^^^^^^^^^^^^^^ + +**Releasedatum:** 28. Juli 2023 + + +Anwender +"""""""" +- Ein möglicher Absturz beim Start unter Android wurde behoben. + + +Entwickler +"""""""""" 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/2.0.1.rst b/docs/releasenotes/2.0.1.rst new file mode 100644 index 000000000..a1ff893c6 --- /dev/null +++ b/docs/releasenotes/2.0.1.rst @@ -0,0 +1,14 @@ +AusweisApp 2.0.1 +^^^^^^^^^^^^^^^^ + +**Releasedatum:** 8. November 2023 + + +Anwender +"""""""" +- Vermeidung des Verlusts der Einstellungen auf iOS und macOS. + + +Entwickler +"""""""""" +- Entitlements unter macOS korrigiert. diff --git a/docs/releasenotes/2.0.2.rst b/docs/releasenotes/2.0.2.rst new file mode 100644 index 000000000..60d0cae94 --- /dev/null +++ b/docs/releasenotes/2.0.2.rst @@ -0,0 +1,13 @@ +AusweisApp 2.0.2 +^^^^^^^^^^^^^^^^ + +**Releasedatum:** 12. Januar 2024 + + +Anwender +"""""""" +- Vermeidung von Verweisen auf den PIN-Rücksetzdienst. + + +Entwickler +"""""""""" diff --git a/docs/releasenotes/2.0.3.rst b/docs/releasenotes/2.0.3.rst new file mode 100644 index 000000000..c507235d3 --- /dev/null +++ b/docs/releasenotes/2.0.3.rst @@ -0,0 +1,17 @@ +AusweisApp 2.0.3 +^^^^^^^^^^^^^^^^ + +**Releasedatum:** 19. Januar 2024 + + +Anwender +"""""""" +- Absturz unter macOS 11 korrigiert. + +- Fehlende deutsche Übersetzung ergänzt. + +- Anzeige der Release Notes korrigiert. + + +Entwickler +"""""""""" 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 da295dfe8..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. @@ -359,6 +359,9 @@ in a :ref:`reader` message. .. versionadded:: 1.24.0 This command was introduced in :ref:`api_level` **2**. +.. versionadded:: 1.26.4 + Parameter **keys** added. + - **name**: Name of the :ref:`reader`. @@ -366,6 +369,8 @@ in a :ref:`reader` message. - **files**: Content of card :ref:`filesystem`. + - **keys**: Keys of card :ref:`filesystem`. + .. code-block:: json { @@ -373,12 +378,13 @@ in a :ref:`reader` message. "name": "reader name", "simulator": { - "files": [] + "files": [], + "keys": [] } } .. 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. @@ -391,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 @@ -399,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. @@ -412,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. @@ -422,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. @@ -435,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. @@ -443,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. @@ -452,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. @@ -482,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. @@ -495,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**. @@ -528,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. @@ -541,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 @@ -560,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. @@ -573,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 @@ -596,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. @@ -609,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`. @@ -634,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 db8bab719..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' @@ -59,7 +59,7 @@ release = '@VERSION_DVCS@' # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = 'en' +language = '@SPHINX_LANG@' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. @@ -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/failurecodes.rst b/docs/sdk/failurecodes.rst new file mode 100644 index 000000000..607356254 --- /dev/null +++ b/docs/sdk/failurecodes.rst @@ -0,0 +1 @@ +.. include:: ../failurecodes/failurecodes.rst diff --git a/docs/sdk/index.rst b/docs/sdk/index.rst index 5c38161b4..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 @@ -55,6 +55,7 @@ Table of contents commands messages workflow + failurecodes .. raw:: latex 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 716fea368..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 @@ -243,9 +244,9 @@ a result and an url parameter to indicate the end of an authentication. - **message**: The error message. - - **reason**: Unique error code. + - **reason**: Unique :doc:`failurecodes`. - - **url**: Refresh url or communication error address. + - **url**: Refresh url or an optional communication error address. .. code-block:: json @@ -269,7 +270,8 @@ a result and an url parameter to indicate the end of an authentication. "minor": "http://www.bsi.bund.de/ecard/api/1.1/resultminor/al/common#internalError", "language": "en", "description": "An internal error has occurred during processing.", - "message": "The connection to the ID card has been lost. The process was aborted." + "message": "The connection to the ID card has been lost. The process was aborted.", + "reason": "Card_Removed" }, "url": "https://test.governikus-eid.de/gov_autent/async?refID=_abcdefgh" } @@ -357,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** @@ -370,9 +372,15 @@ command if the connection to the card failed. Also the parameter Support of CHANGE_PIN message. +.. versionadded:: 1.26.4 + Parameter **reason** added. + + - **success**: Indicates with true that the PIN was successfully changed, otherwise false. + - **reason**: Unique :doc:`failurecodes`. + .. code-block:: json { @@ -381,6 +389,15 @@ command if the connection to the card failed. Also the parameter } +.. code-block:: json + + { + "msg": "CHANGE_PIN", + "success": false, + "reason": "Card_Removed" + } + + .. _enter_can: @@ -389,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 @@ -402,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 @@ -451,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. @@ -459,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` @@ -511,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`. @@ -555,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 @@ -610,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. @@ -625,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 @@ -651,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 { @@ -660,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" } @@ -674,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. @@ -687,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. @@ -736,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! @@ -760,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. @@ -794,6 +826,8 @@ until a card with enabled eID function is inserted. to unblock the PIN. - **deactivated**: True if eID function is deactivated, otherwise false. + The scan dialog on iOS won't be closed if this is True. You need to + send :ref:`interrupt` yourself to show an error message. - **retryCounter**: Count of possible retries for the PIN. If you enter a PIN with command :ref:`set_pin` it will be decreased if PIN was incorrect. @@ -868,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` @@ -907,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/simulator.rst b/docs/sdk/simulator.rst index 0856ead09..8fcee9e75 100644 --- a/docs/sdk/simulator.rst +++ b/docs/sdk/simulator.rst @@ -6,7 +6,7 @@ message with the parameter **name** being `Simulator`. This virtual card can be inserted by :ref:`set_card` or can be automatically used in :ref:`automatic` mode. The default values of that virtual card are hardcoded and can only be changed -by the **files** parameter in the **simulator** parameter. +by the **files** and **keys** parameter in the **simulator** parameter. .. note:: @@ -19,21 +19,17 @@ by the **files** parameter in the **simulator** parameter. Filesystem ---------- The content of the filesystem can be provided as a JSON array of objects. -The ``fileId`` and ``shortFileId`` are specified on the corresponding -technical guideline of the BSI and ISO. The ``content`` is an ASN.1 structure -in DER encoding. All fields are hex encoded. +The ``fileId`` and ``shortFileId`` are specified in `TR-03110_part4`_. The +``content`` is an ASN.1 structure in DER encoding. All fields are hex encoded. These are the default values if your application does not provide other values -as **files** parameter in :ref:`set_card` or if you use the :ref:`automatic` mode -of :doc:`desktop` or the :doc:`container` variant. +as **simulator** parameter in :ref:`set_card` or if you use the :ref:`automatic` +mode of :doc:`desktop` or the :doc:`container` variant. .. code-block:: json "files": [ - {"fileId": "2f00", "shortFileId": "1e", "content": "61324f0fe828bd080fa000000167455349474e500f434941207a752044462e655369676e5100730c4f0aa000000167455349474e61094f07a0000002471001610b4f09e80704007f00070302610c4f0aa000000167455349474e"}, - {"fileId": "011c", "shortFileId": "1c", "content": "3181c13012060a04007f0007020204020202010202010d300d060804007f00070202020201023012060a04007f00070202030202020102020129301c060904007f000702020302300c060704007f0007010202010d020129303e060804007f000702020831323012060a04007f0007020203020202010202012d301c060904007f000702020302300c060704007f0007010202010d02012d302a060804007f0007020206161e687474703a2f2f6273692e62756e642e64652f6369662f6e70612e786d6c"}, - {"fileId": "011d", "shortFileId": "1d", "content": "308209f606092a864886f70d010702a08209e7308209e3020103310f300d06096086480165030402030500308203e0060804007f0007030201a08203d2048203ce318203ca3012060a04007f0007020204020202010202010d300d060804007f00070202020201023017060a04007f0007020205020330090201010201010101003021060904007f000702020502301406072a8648ce3d020106092b24030302080101073017060a04007f0007020205020330090201010201020101ff3012060a04007f00070202030202020102020129301c060904007f000702020302300c060704007f0007010202010d0201293062060904007f0007020201023052300c060704007f0007010202010d0342000419d4b7447788b0e1993db35500999627e739a4e5e35f02d8fb07d6122e76567f17758d7a3aa6943ef23e5e2909b3e8b31bfaa4544c2cbf1fb487f31ff239c8f80201293081a3060804007f00070202083181963012060a04007f0007020203020202010202012d301c060904007f000702020302300c060704007f0007010202010d02012d3062060904007f0007020201023052300c060704007f0007010202010d034200041ac6cae884a6c2b8461404150f54cd1150b21e862a4e5f21ce34290c741104bd1bf31ed91e085d7c630e8b4d10a8ae22bbb2898b44b52ea0f4cdadcf57cfba2502012d302a060804007f0007020206161e687474703a2f2f6273692e62756e642e64652f6369662f6e70612e786d6c308201e6060804007f0007020207308201d8300b0609608648016503040204308201c73021020101041c2ff0247f59dd3c646e314f03abb33ee91a586577ebdf48d3864ec34d3021020102041c37823963b71af0bf5698d1fdc30da2b7f9ece57cfa4959bee9d6d9943021020103041ce8b2a171dc1290a765f124aafe33061c08c918a1069dff5caf4c62b53021020104041cad81d20dbd4f5687fdb05e5037ec267609fde28c6036fdbdf2c8b4333021020105041ca90f28eb7a0fa0de83abf3293d14e0838b9c85fc7277cbb97737a32b3021020106041c712b8550e49a13c64dced4457e9a0f5a85dc26cd6a321596723005d63021020107041c42a8fa36b60887ed022cd3b6ecc255220fbe8cb3f607e416601fcaa63021020108041c6446e0a909967462b5c1117634f8a1b557ef74be3f606c1e94efae433021020109041c635d1017f4abc656b9fdddd7e0fbb1e992b7686e89485e6ab51b638b302102010d041c04db93544a64bc1245b10aab266386f08f8e89f72e1db178c172624d3021020111041caadee20557d41ab9969e962282caf25904475148d329d2f6b2f43e343021020112041c57ce396ca707b96fa37c580f693230e4d4aebb97293f0909489d95cb302102010a041c1880a259cdb497c15a7fdd1c9ac9490d7dc0d18743378603d43d1d4fa082049f3082049b308203fea003020102020204d5300a06082a8648ce3d0403043046310b3009060355040613024445310d300b060355040a0c0462756e64310c300a060355040b0c03627369311a301806035504030c115445535420637363612d6765726d616e79301e170d3230303132313036333630345a170d3330303832313233353935395a305c310b3009060355040613024445310c300a060355040a0c03425349310d300b06035504051304303039393130302e06035504030c275445535420446f63756d656e74205369676e6572204964656e7469747920446f63756d656e7473308201b53082014d06072a8648ce3d020130820140020101303c06072a8648ce3d01010231008cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b412b1da197fb71123acd3a729901d1a71874700133107ec53306404307bc382c63d8c150c3c72080ace05afa0c2bea28e4fb22787139165efba91f90f8aa5814a503ad4eb04a8c7dd22ce2826043004a8c7dd22ce28268b39b55416f0447c2fb77de107dcd2a62e880ea53eeb62d57cb4390295dbc9943ab78696fa504c110461041d1c64f068cf45ffa2a63a81b7c13f6b8847a3e77ef14fe3db7fcafe0cbd10e8e826e03436d646aaef87b2e247d4af1e8abe1d7520f9c2a45cb1eb8e95cfd55262b70b29feec5864e19c054ff99129280e4646217791811142820341263c53150231008cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e90465650201010362000401b434b9555974f51934687c520dae338032f5046999e1595d85b89a4cbdb90888b8dcab2d6588cf73e8e43db78ab40a0fdb710d971f1c0205b9243e1f769a9e0681c01d1b298c4d7de7f3f7e6ce9f16657907b79328bec8166f5fc035e26ee3a382016630820162301f0603551d23041830168014539db1872aac9193d76392ee80d9e5996cf99b3b301d0603551d0e0416041472571e58fc52ead9641412875c615e8090508cfa300e0603551d0f0101ff040403020780302b0603551d1004243022800f32303230303132313036333630345a810f32303230303832313233353935395a30160603551d20040f300d300b060904007f00070301010130260603551d11041f301d820b6273692e62756e642e6465a40e300c310a300806035504070c014430510603551d12044a30488118637363612d6765726d616e79406273692e62756e642e6465861c68747470733a2f2f7777772e6273692e62756e642e64652f63736361a40e300c310a300806035504070c01443019060767810801010602040e300c02010031071301411302494430350603551d1f042e302c302aa028a0268624687474703a2f2f7777772e6273692e62756e642e64652f746573745f637363615f63726c300a06082a8648ce3d04030403818a00308186024100a348c5e7948535c9ecb5043d62fa1f56f16886af76c434c870d988d345175fd51e60a89c0e9d06a94d35078853397d7c8403e32053df6bdfc16cc1b3a5e7d1cb0241008506dc6aca4f202b4bdf7957263010886d38d4991d101374f6a7b8f4bc1ce51cb278e9f8851951f6af0aba7d4773f42762fd8f840a01f2d526cc80682dca08103182014430820140020101304c3046310b3009060355040613024445310d300b060355040a0c0462756e64310c300a060355040b0c03627369311a301806035504030c115445535420637363612d6765726d616e79020204d5300d06096086480165030402030500a06a301706092a864886f70d010903310a060804007f0007030201304f06092a864886f70d0109043142044066927654d73a84cccd931e2c44a9b34ef3b848ee85b7f4a92699ea7bf5262fe73b101f31f580180c96ea642569e5e6db8469a4c7e4cb47dfe9c5d95b0939125e300a06082a8648ce3d040304046630640230582364c74d9c694d3c8f99acbf82a7a847141248b015aed8bee3c395e82788426f032978d196303a6b81d9fa8b8dbc8e02305bf169de97b344a4b03e862c48a76226f044c6da1ea78e380c2c6479b79526415735345764d7b6e738ee83931aabe840"}, {"fileId": "0101", "shortFileId": "01", "content": "610413024944"}, {"fileId": "0102", "shortFileId": "02", "content": "6203130144"}, {"fileId": "0103", "shortFileId": "03", "content": "630a12083230323931303331"}, @@ -54,6 +50,56 @@ of :doc:`desktop` or the :doc:`container` variant. {"fileId": "0114", "shortFileId": "14", "content": "7416a1140c125245534944454e4345205045524d49542032"}, {"fileId": "0115", "shortFileId": "15", "content": "7515131374656c3a2b34392d3033302d31323334353637"}, {"fileId": "0116", "shortFileId": "16", "content": "761516136572696b61406d75737465726d616e6e2e6465"} + ], + "keys": + [ + {"id": 1, "private": "0353859c2ec67780ba39015de8c682af2326d43de9ce1e07737087bd1e17cb22"}, + {"id": 2, "private": "9ad0ad7f4dfaaa06988339fc31d3a111f4c7964ac7f377373a2454327c43e2ff"} + ] + + + +All keys and also the files from :ref:`advanced` will always be present and +can be overwritten as they are required for successful authentication. The +other files will not exist until they are specified so it is possible to +simulate a missing piece of personal data. + +The keys are used to calculate the pseudonym. Key ``1`` is used to check the +blacklist while key ``2`` is used to calculate the pseudonym for the service +provider. + +New keys can be generated with OpenSSL. + +.. code-block:: console + + openssl ecparam -name brainpoolP256r1 -genkey -out riKey.pem + openssl ec -in riKey.pem -text -noout + + + +.. _TR-03110_part4: https://www.bsi.bund.de/SharedDocs/Downloads/EN/BSI/Publications/TechGuidelines/TR03110/BSI_TR-03110_Part-4_V2-2.pdf + + + +.. _advanced: + +Advanced +-------- +In addition the following files and keys can be overridden to change the +technical behavior of the virtual card. This does not affect the personal +data and is only required for eID-Client or eID-Server development. + +.. code-block:: json + + "files": + [ + {"fileId": "2f00", "shortFileId": "1e", "content": "61324f0fe828bd080fa000000167455349474e500f434941207a752044462e655369676e5100730c4f0aa000000167455349474e61094f07a0000002471001610b4f09e80704007f00070302610c4f0aa000000167455349474e"}, + {"fileId": "011c", "shortFileId": "1c", "content": "3181c13012060a04007f0007020204020202010202010d300d060804007f00070202020201023012060a04007f00070202030202020102020129301c060904007f000702020302300c060704007f0007010202010d020129303e060804007f000702020831323012060a04007f0007020203020202010202012d301c060904007f000702020302300c060704007f0007010202010d02012d302a060804007f0007020206161e687474703a2f2f6273692e62756e642e64652f6369662f6e70612e786d6c"}, + {"fileId": "011d", "shortFileId": "1d", "content": "308209f606092a864886f70d010702a08209e7308209e3020103310f300d06096086480165030402030500308203e0060804007f0007030201a08203d2048203ce318203ca3012060a04007f0007020204020202010202010d300d060804007f00070202020201023017060a04007f0007020205020330090201010201010101003021060904007f000702020502301406072a8648ce3d020106092b24030302080101073017060a04007f0007020205020330090201010201020101ff3012060a04007f00070202030202020102020129301c060904007f000702020302300c060704007f0007010202010d0201293062060904007f0007020201023052300c060704007f0007010202010d0342000419d4b7447788b0e1993db35500999627e739a4e5e35f02d8fb07d6122e76567f17758d7a3aa6943ef23e5e2909b3e8b31bfaa4544c2cbf1fb487f31ff239c8f80201293081a3060804007f00070202083181963012060a04007f0007020203020202010202012d301c060904007f000702020302300c060704007f0007010202010d02012d3062060904007f0007020201023052300c060704007f0007010202010d034200041ac6cae884a6c2b8461404150f54cd1150b21e862a4e5f21ce34290c741104bd1bf31ed91e085d7c630e8b4d10a8ae22bbb2898b44b52ea0f4cdadcf57cfba2502012d302a060804007f0007020206161e687474703a2f2f6273692e62756e642e64652f6369662f6e70612e786d6c308201e6060804007f0007020207308201d8300b0609608648016503040204308201c73021020101041c2ff0247f59dd3c646e314f03abb33ee91a586577ebdf48d3864ec34d3021020102041c37823963b71af0bf5698d1fdc30da2b7f9ece57cfa4959bee9d6d9943021020103041ce8b2a171dc1290a765f124aafe33061c08c918a1069dff5caf4c62b53021020104041cad81d20dbd4f5687fdb05e5037ec267609fde28c6036fdbdf2c8b4333021020105041ca90f28eb7a0fa0de83abf3293d14e0838b9c85fc7277cbb97737a32b3021020106041c712b8550e49a13c64dced4457e9a0f5a85dc26cd6a321596723005d63021020107041c42a8fa36b60887ed022cd3b6ecc255220fbe8cb3f607e416601fcaa63021020108041c6446e0a909967462b5c1117634f8a1b557ef74be3f606c1e94efae433021020109041c635d1017f4abc656b9fdddd7e0fbb1e992b7686e89485e6ab51b638b302102010d041c04db93544a64bc1245b10aab266386f08f8e89f72e1db178c172624d3021020111041caadee20557d41ab9969e962282caf25904475148d329d2f6b2f43e343021020112041c57ce396ca707b96fa37c580f693230e4d4aebb97293f0909489d95cb302102010a041c1880a259cdb497c15a7fdd1c9ac9490d7dc0d18743378603d43d1d4fa082049f3082049b308203fea003020102020204d5300a06082a8648ce3d0403043046310b3009060355040613024445310d300b060355040a0c0462756e64310c300a060355040b0c03627369311a301806035504030c115445535420637363612d6765726d616e79301e170d3230303132313036333630345a170d3330303832313233353935395a305c310b3009060355040613024445310c300a060355040a0c03425349310d300b06035504051304303039393130302e06035504030c275445535420446f63756d656e74205369676e6572204964656e7469747920446f63756d656e7473308201b53082014d06072a8648ce3d020130820140020101303c06072a8648ce3d01010231008cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b412b1da197fb71123acd3a729901d1a71874700133107ec53306404307bc382c63d8c150c3c72080ace05afa0c2bea28e4fb22787139165efba91f90f8aa5814a503ad4eb04a8c7dd22ce2826043004a8c7dd22ce28268b39b55416f0447c2fb77de107dcd2a62e880ea53eeb62d57cb4390295dbc9943ab78696fa504c110461041d1c64f068cf45ffa2a63a81b7c13f6b8847a3e77ef14fe3db7fcafe0cbd10e8e826e03436d646aaef87b2e247d4af1e8abe1d7520f9c2a45cb1eb8e95cfd55262b70b29feec5864e19c054ff99129280e4646217791811142820341263c53150231008cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e90465650201010362000401b434b9555974f51934687c520dae338032f5046999e1595d85b89a4cbdb90888b8dcab2d6588cf73e8e43db78ab40a0fdb710d971f1c0205b9243e1f769a9e0681c01d1b298c4d7de7f3f7e6ce9f16657907b79328bec8166f5fc035e26ee3a382016630820162301f0603551d23041830168014539db1872aac9193d76392ee80d9e5996cf99b3b301d0603551d0e0416041472571e58fc52ead9641412875c615e8090508cfa300e0603551d0f0101ff040403020780302b0603551d1004243022800f32303230303132313036333630345a810f32303230303832313233353935395a30160603551d20040f300d300b060904007f00070301010130260603551d11041f301d820b6273692e62756e642e6465a40e300c310a300806035504070c014430510603551d12044a30488118637363612d6765726d616e79406273692e62756e642e6465861c68747470733a2f2f7777772e6273692e62756e642e64652f63736361a40e300c310a300806035504070c01443019060767810801010602040e300c02010031071301411302494430350603551d1f042e302c302aa028a0268624687474703a2f2f7777772e6273692e62756e642e64652f746573745f637363615f63726c300a06082a8648ce3d04030403818a00308186024100a348c5e7948535c9ecb5043d62fa1f56f16886af76c434c870d988d345175fd51e60a89c0e9d06a94d35078853397d7c8403e32053df6bdfc16cc1b3a5e7d1cb0241008506dc6aca4f202b4bdf7957263010886d38d4991d101374f6a7b8f4bc1ce51cb278e9f8851951f6af0aba7d4773f42762fd8f840a01f2d526cc80682dca08103182014430820140020101304c3046310b3009060355040613024445310d300b060355040a0c0462756e64310c300a060355040b0c03627369311a301806035504030c115445535420637363612d6765726d616e79020204d5300d06096086480165030402030500a06a301706092a864886f70d010903310a060804007f0007030201304f06092a864886f70d0109043142044066927654d73a84cccd931e2c44a9b34ef3b848ee85b7f4a92699ea7bf5262fe73b101f31f580180c96ea642569e5e6db8469a4c7e4cb47dfe9c5d95b0939125e300a06082a8648ce3d040304046630640230582364c74d9c694d3c8f99acbf82a7a847141248b015aed8bee3c395e82788426f032978d196303a6b81d9fa8b8dbc8e02305bf169de97b344a4b03e862c48a76226f044c6da1ea78e380c2c6479b79526415735345764d7b6e738ee83931aabe840"} + ], + "keys": + [ + {"id": 41, "private": "a07eb62e891daa84643e0afcc1af006891b669b8f51e379477dbeab8c987a610"} ] @@ -63,7 +109,4 @@ of :doc:`desktop` or the :doc:`container` variant. `TR-03110_part3`_, part 3: Section A.1.2. Storage on the Chip - `TR-03110_part4`_, part 4: Applications and Document Profiles - .. _TR-03110_part3: https://www.bsi.bund.de/SharedDocs/Downloads/EN/BSI/Publications/TechGuidelines/TR03110/BSI_TR-03110_Part-3-V2_2.pdf - .. _TR-03110_part4: https://www.bsi.bund.de/SharedDocs/Downloads/EN/BSI/Publications/TechGuidelines/TR03110/BSI_TR-03110_Part-4_V2-2.pdf diff --git a/docs/sdk/workflow.rst b/docs/sdk/workflow.rst index b5cc87807..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|. @@ -24,7 +24,7 @@ into the connected card reader. .. code-block:: json - {"cmd": "RUN_AUTH", "tcTokenURL": "https://test.governikus-eid.de/DEMO"} + {"cmd": "RUN_AUTH", "tcTokenURL": "https://test.governikus-eid.de/AusweisAuskunft/WebServiceRequesterServlet"} {"msg": "AUTH"} diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt index 1e9fc145f..201bcf8a3 100644 --- a/libs/CMakeLists.txt +++ b/libs/CMakeLists.txt @@ -109,11 +109,7 @@ if(NOT CMAKE_HOST_SYSTEM_NAME STREQUAL CMAKE_SYSTEM_NAME) endif() ################################## Versions -set(QT 6.4.1) -set(QT_HASH e20b850b6134098a7f2e7701cfddfb213c6cf394b9e848e6fbc5b0e89dcfcc09) - -set(OPENSSL 3.0.8) -set(OPENSSL_HASH 6c13d2bf38fdf31eac3ce2a347073673f5d63263398f1f69d0df4a41253e4b3e) +include(Versions.cmake) ################################## Files set(QT_FILE qt-everywhere-src-${QT}.tar.xz) @@ -151,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}) @@ -178,9 +174,9 @@ else() endif() if(IOS) + set(OPENSSL_CONFIGURE_FLAGS ${OPENSSL_CONFIGURE_FLAGS} no-asm) if(CMAKE_OSX_SYSROOT MATCHES "iphonesimulator") set(OPENSSL_ARCH iossimulator-xcrun) - set(OPENSSL_CONFIGURE_FLAGS ${OPENSSL_CONFIGURE_FLAGS} no-asm) if (CMAKE_OSX_ARCHITECTURES STREQUAL "arm64") set(OPENSSL_CONFIGURE_FLAGS ${OPENSSL_CONFIGURE_FLAGS} "-arch arm64") endif() @@ -189,12 +185,14 @@ if(IOS) string(REGEX REPLACE "/SDKs/.*" "" CROSS_TOP_DEV_ROOT "${CMAKE_OSX_SYSROOT}") set(OPENSSL_ENV CROSS_TOP=${CROSS_TOP_DEV_ROOT} CROSS_SDK=iPhoneOS.sdk) endif() + set(OPENSSL_COMPILER_FLAGS ${OPENSSL_COMPILER_FLAGS} -fvisibility=hidden) elseif(APPLE) if(NOT CMAKE_OSX_ARCHITECTURES AND CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm64") set(CMAKE_OSX_ARCHITECTURES arm64) endif() if(CMAKE_OSX_ARCHITECTURES STREQUAL "arm64") + set(OPENSSL_CONFIGURE_FLAGS ${OPENSSL_CONFIGURE_FLAGS} no-asm) set(OPENSSL_ARCH darwin64-arm64-cc) set(OPENSSL_COMPILER_FLAGS ${OPENSSL_COMPILER_FLAGS} -mmacosx-version-min=11.0) else() @@ -222,12 +220,17 @@ elseif(ANDROID) if(CMAKE_ANDROID_ARCH_ABI STREQUAL "armeabi-v7a") set(OPENSSL_ARCH android-arm) set(OPENSSL_COMPILER_FLAGS ${OPENSSL_COMPILER_FLAGS} -mfloat-abi=softfp) + set(OPENSSL_NDK_PREFIX armv7a) + set(OPENSSL_NDK_INFIX eabi) elseif(CMAKE_ANDROID_ARCH_ABI STREQUAL "x86_64") set(OPENSSL_ARCH android-x86_64) + set(OPENSSL_NDK_PREFIX x86_64) elseif(CMAKE_ANDROID_ARCH_ABI STREQUAL "x86") set(OPENSSL_ARCH android-x86) + set(OPENSSL_NDK_PREFIX i686) elseif(CMAKE_ANDROID_ARCH_ABI STREQUAL "arm64-v8a") set(OPENSSL_ARCH android-arm64) + set(OPENSSL_NDK_PREFIX aarch64) else() message(FATAL_ERROR "CMAKE_ANDROID_ARCH_ABI not supported by openssl") endif() @@ -239,6 +242,7 @@ elseif(ANDROID) if(ANDROID_NDK_REVISION VERSION_LESS "23") set(OPENSSL_COMPILER_FLAGS ${OPENSSL_COMPILER_FLAGS} -D__ANDROID_API__=${CMAKE_SYSTEM_VERSION}) endif() + set(OPENSSL_COMPILER_FLAGS ${OPENSSL_COMPILER_FLAGS} --target=${OPENSSL_NDK_PREFIX}-linux-android${OPENSSL_NDK_INFIX}${CMAKE_SYSTEM_VERSION}) elseif(BSD) set(OPENSSL_ARCH BSD-x86_64) elseif(LINUX) @@ -276,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) @@ -341,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}) @@ -359,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) @@ -466,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 6496dcf2f..7193034e1 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. @@ -86,6 +86,9 @@ Es wird der von Apple ausgelieferte clang compiler verwendet. $ cmake -DCMAKE_BUILD_TYPE=release ../AusweisApp2/libs $ make +======= +Beispiel: Innerhalb von /Users/governikus/AusweisApp befindet sich der Quellcode. + Linux / Unix ^^^^^^^^^^^^ @@ -102,7 +105,7 @@ Die Einrichtung unter Linux/Unix ist einfach und erfordert nur die oben genannte $ cd /home/governikus $ mkdir build $ cd build - $ cmake -DCMAKE_BUILD_TYPE=release ../AusweisApp2/libs + $ cmake -DCMAKE_BUILD_TYPE=release ../AusweisApp/libs $ make @@ -265,7 +268,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") @@ -294,7 +297,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 @@ -308,14 +311,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 @@ -357,14 +360,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 new file mode 100644 index 000000000..644bd3303 --- /dev/null +++ b/libs/Versions.cmake @@ -0,0 +1,5 @@ +set(QT 6.5.3) +set(QT_HASH 7cda4d119aad27a3887329cfc285f2aba5da85601212bcb0aea27bd6b7b544cb) + +set(OPENSSL 3.1.4) +set(OPENSSL_HASH 840af5366ab9b522bde525826be3ef0fb0af81c6a9ebd84caa600fea1731eee3) diff --git a/libs/patch.cmake.in b/libs/patch.cmake.in index 6f5ded14a..adec3a60a 100644 --- a/libs/patch.cmake.in +++ b/libs/patch.cmake.in @@ -15,11 +15,11 @@ endfunction() function(PATCH_SOURCES _component) set(PATCHES_DIR @PROJECT_SOURCE_DIR@/patches) - file(GLOB PATCHES "${PATCHES_DIR}/${_component}-*.patch") + file(GLOB PATCHES "${PATCHES_DIR}/${_component}*.patch") PATCH_SOURCES_EXECUTE("${PATCHES}") if("@CMAKE_BUILD_TYPE@" STREQUAL "DEBUG") - file(GLOB PATCHES_DEBUG "${PATCHES_DIR}/debug/${_component}-*.patch") + file(GLOB PATCHES_DEBUG "${PATCHES_DIR}/debug/${_component}*.patch") PATCH_SOURCES_EXECUTE("${PATCHES_DEBUG}") endif() endfunction() diff --git a/libs/patches.cmake b/libs/patches.cmake new file mode 100644 index 000000000..64dd98b24 --- /dev/null +++ b/libs/patches.cmake @@ -0,0 +1,227 @@ +cmake_minimum_required(VERSION 3.19.0) + +# How to use +# +# Create an empty directory and provide it by -DREPOSITORY_DIR or set +# REPOSITORY_DIR as environment variable. +# +# - Apply existing patches +# $ cmake -DCMD=apply -P libs/patches.cmake +# 1. This will clone all repositores to REPOSITORY_DIR. +# 2. Checkout git tag from Versions.cmake to a new ausweisap_ branch. +# It will delete that branch if it exist. +# 3. Apply all patches to the new branch. +# +# - Generate patches from repositories +# $ cmake -DCMD=generate -P libs/patches.cmake +# 1. All existing patches in "patches" directory will be deleted. +# 2. Branch of current Version on all repositories in REPOSITORY_DIR will be scanned. +# 3. All changesets from the latest tag will be exported to "patches" dir. +# +# If you need a new repository you can clone it into REPOSITORY_DIR. +# Checkout the release tag of used Version.cmake and cherry-pick or add +# changesets to it. It will be exported with "generate". +# If you need to remove patches, just delete the changesets or the whole clone. +# +# - 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 +# 3. git rebase --onto v6.6.0 v6.4.3 HEAD +# 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") +endif() + +find_package(Git REQUIRED) + +if(NOT REPOSITORY_DIR) + set(REPOSITORY_DIR $ENV{REPOSITORY_DIR}) + if(NOT REPOSITORY_DIR) + message(FATAL_ERROR "Define REPOSITORY_DIR for local repositories") + endif() + if(NOT EXISTS "${REPOSITORY_DIR}") + message(FATAL_ERROR "REPOSITORY_DIR ${REPOSITORY_DIR} does not exist") + endif() +endif() + +get_filename_component(libs_dir "${CMAKE_SCRIPT_MODE_FILE}" DIRECTORY) +set(patch_dir "${libs_dir}/patches") +set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/../cmake;${libs_dir}") +include(Versions) + +function(execute_dir dir) + execute_process(COMMAND ${GIT_EXECUTABLE} ${ARGN} + WORKING_DIRECTORY "${REPOSITORY_DIR}/${dir}" + RESULT_VARIABLE _result) + + if(NOT "${_result}" EQUAL 0) + message(FATAL_ERROR "git failed: ${_result}") + endif() +endfunction() + +function(execute) + execute_dir("" ${ARGN}) +endfunction() + +function(git_clone prefix) + if(NOT EXISTS "${REPOSITORY_DIR}/${prefix}") + message(STATUS "Repository not found: ${prefix}") + if(prefix STREQUAL "openssl") + execute(clone "https://github.com/openssl/openssl" "${prefix}") + elseif(prefix MATCHES "qt") + execute(clone "https://code.qt.io/qt/${prefix}.git" "${prefix}") + endif() + endif() +endfunction() + +function(git_checkout prefix) + get_version_branch("${prefix}" version tmp_branch) + execute_dir("${prefix}" fetch) + execute_dir("${prefix}" checkout -q ${version}) + execute_process(COMMAND ${GIT_EXECUTABLE} branch -D ${tmp_branch} WORKING_DIRECTORY ${REPOSITORY_DIR}/${prefix}) + execute_process(COMMAND ${GIT_EXECUTABLE} am --abort WORKING_DIRECTORY ${REPOSITORY_DIR}/${prefix} OUTPUT_QUIET ERROR_QUIET) + execute_dir("${prefix}" checkout ${version} -b ${tmp_branch}) +endfunction() + +function(get_version_branch prefix _version _branch) + set(tmp_branch ausweisapp) + if(prefix STREQUAL "openssl") + set(version openssl-${OPENSSL}) + 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() + + set(${_version} "${version}" PARENT_SCOPE) + set(${_branch} "${tmp_branch}" PARENT_SCOPE) +endfunction() + +function(apply_patches) + file(GLOB PATCHES "${patch_dir}/*.patch") + foreach(patch ${PATCHES}) + get_filename_component(filename "${patch}" NAME) + string(REGEX MATCH "([a-z|-]+)-[0-9]+.+" _unused "${filename}") + set(prefix ${CMAKE_MATCH_1}) + + list(APPEND prefixes "${prefix}") + list(APPEND "${prefix}" "${patch}") + + if(NOT (prefix STREQUAL "openssl" OR prefix MATCHES "qt")) + message(FATAL_ERROR "Prefix unknown: ${prefix}") + endif() + endforeach() + + list(REMOVE_DUPLICATES prefixes) + foreach(prefix ${prefixes}) + message(STATUS "Apply component: ${prefix}") + git_clone(${prefix}) + git_checkout(${prefix}) + + foreach(patch ${${prefix}}) + if(prefix STREQUAL "openssl") + set(p 1) + elseif(prefix MATCHES "qt") + set(p 2) + endif() + + execute_process(COMMAND ${CMAKE_COMMAND} -E env GIT_COMMITTER_NAME="Governikus" GIT_COMMITTER_EMAIL="" -- + ${GIT_EXECUTABLE} am --whitespace=fix --no-gpg-sign --committer-date-is-author-date -p${p} "${patch}" + WORKING_DIRECTORY "${REPOSITORY_DIR}/${prefix}" + RESULT_VARIABLE _result) + + if(NOT "${_result}" EQUAL 0) + message(FATAL_ERROR "cannot apply patch: ${_result}") + endif() + endforeach() + endforeach() +endfunction() + + +function(get_latest_tag _out repo) + execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags --abbrev=0 + WORKING_DIRECTORY ${repo} + OUTPUT_VARIABLE _output + RESULT_VARIABLE _result + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + + if(${_result} EQUAL 0) + set(${_out} "${_output}" PARENT_SCOPE) + endif() +endfunction() + +function(get_current_branch _out repo) + execute_process(COMMAND ${GIT_EXECUTABLE} branch --show-current + WORKING_DIRECTORY ${repo} + OUTPUT_VARIABLE _output + RESULT_VARIABLE _result + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + + if(NOT "${_result}" EQUAL 0) + message(FATAL_ERROR "git failed: ${_result}") + endif() + set(${_out} "${_output}" PARENT_SCOPE) +endfunction() + +function(rename_patches component) + file(GLOB PATCHES "${patch_dir}/*.patch") + foreach(patch ${PATCHES}) + get_filename_component(filename "${patch}" NAME) + if(filename MATCHES "^[0-9]+.*") + file(RENAME "${patch}" "${patch_dir}/${component}-${filename}") + endif() + endforeach() +endfunction() + +function(generate_patches) + file(GLOB PATCHES "${patch_dir}/*.patch") + if(PATCHES) + file(REMOVE ${PATCHES}) + endif() + + list(APPEND prefixes openssl qt) + foreach(prefix ${prefixes}) + file(GLOB REPOS "${REPOSITORY_DIR}/${prefix}*") + foreach(repo ${REPOS}) + get_filename_component(dirname "${repo}" NAME) + get_version_branch("${prefix}" version tmp_branch) + execute_process(COMMAND ${GIT_EXECUTABLE} checkout -q ${tmp_branch} WORKING_DIRECTORY ${repo} OUTPUT_QUIET ERROR_QUIET) + get_current_branch(current_branch "${repo}") + if(current_branch STREQUAL tmp_branch) + get_latest_tag(latesttag "${repo}") + message(STATUS "Generate patches of ${dirname} since tag ${latesttag}") + + if(dirname STREQUAL "openssl") + set(component "") + else() + set(component "${dirname}/") + endif() + + execute_dir("${dirname}" format-patch --no-signature --no-renames --no-binary --src-prefix=x/${component} --dst-prefix=y/${component} -k ${latesttag}..HEAD -o "${patch_dir}") + rename_patches(${dirname}) + else() + message(STATUS "Skip patches of ${dirname} and branch ${current_branch}") + endif() + endforeach() + endforeach() +endfunction() + + + +if(CMD STREQUAL "generate") + message(STATUS "Generate patches!") + generate_patches() +elseif(CMD STREQUAL "apply") + message(STATUS "Apply patches!") + apply_patches() +else() + message(FATAL_ERROR "Unknown CMD: ${CMD}") +endif() diff --git a/libs/patches/openssl-0001-Adjust-iOS-target.patch b/libs/patches/openssl-0001-Adjust-iOS-target.patch index c2345ef24..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 a16972bcfd33b694fd27d19e85754be74daa4430 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 @@ -8,7 +8,7 @@ Subject: Adjust iOS target 1 file changed, 1 insertion(+), 1 deletion(-) diff --git x/Configurations/15-ios.conf y/Configurations/15-ios.conf -index 54d37f63f4..a4ade8d209 100644 +index 54d37f63f4..7e411b2e3a 100644 --- x/Configurations/15-ios.conf +++ y/Configurations/15-ios.conf @@ -25,7 +25,7 @@ my %targets = ( @@ -20,5 +20,3 @@ index 54d37f63f4..a4ade8d209 100644 bn_ops => "SIXTY_FOUR_BIT_LONG RC4_CHAR", asm_arch => 'aarch64', perlasm_scheme => "ios64", --- -2.35.1 diff --git a/libs/patches/openssl-0002-android-shlib_variant.patch b/libs/patches/openssl-0002-android-shlib_variant.patch index 24f251fda..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 8e011194bf8b4e4275f51f76b75a1b22e45e9564 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 @@ -41,6 +41,3 @@ index 41ad9223e0..f804aeb11b 100644 }, #################################################################### --- -2.35.1 - diff --git a/libs/patches/qt-base-0002-Revert-Android-Fix-QSettings-when-using-content-URL.patch b/libs/patches/qt-base-0002-Revert-Android-Fix-QSettings-when-using-content-URL.patch deleted file mode 100644 index 86f8eb005..000000000 --- a/libs/patches/qt-base-0002-Revert-Android-Fix-QSettings-when-using-content-URL.patch +++ /dev/null @@ -1,66 +0,0 @@ -From c6818d0c25f067bc13198b9aa2ca82776a40ad3b Mon Sep 17 00:00:00 2001 -From: Lars Schmertmann -Date: Wed, 14 Dec 2022 11:52:12 +0100 -Subject: Revert "Android: Fix QSettings when using content URL" - -This reverts commit 140ca89a3c2b8d78889d27217f977cd4de10041b. ---- - src/corelib/io/qsettings.cpp | 21 +++------------------ - 1 file changed, 3 insertions(+), 18 deletions(-) - -diff --git x/qtbase/src/corelib/io/qsettings.cpp y/qtbase/src/corelib/io/qsettings.cpp -index 60622e3aaa..a999aa6996 100644 ---- x/qtbase/src/corelib/io/qsettings.cpp -+++ y/qtbase/src/corelib/io/qsettings.cpp -@@ -48,9 +48,8 @@ - #define Q_XDG_PLATFORM - #endif - --#if !defined(QT_NO_STANDARDPATHS) \ -- && (defined(Q_XDG_PLATFORM) || defined(QT_PLATFORM_UIKIT) || defined(Q_OS_ANDROID)) --# define QSETTINGS_USE_QSTANDARDPATHS -+#if !defined(QT_NO_STANDARDPATHS) && (defined(Q_XDG_PLATFORM) || defined(QT_PLATFORM_UIKIT)) -+#define QSETTINGS_USE_QSTANDARDPATHS - #endif - - // ************************************************************************ -@@ -1332,15 +1331,6 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile) - } - - #ifndef QT_BOOTSTRAPPED -- QString lockFileName = confFile->name + ".lock"_L1; -- --# if defined(Q_OS_ANDROID) && defined(QSETTINGS_USE_QSTANDARDPATHS) -- // 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(); --# endif - /* - Use a lockfile in order to protect us against other QSettings instances - trying to write the same settings at the same time. -@@ -1348,7 +1338,7 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile) - We only need to lock if we are actually writing as only concurrent writes are a problem. - Concurrent read and write are not a problem because the writing operation is atomic. - */ -- QLockFile lockFile(lockFileName); -+ QLockFile lockFile(confFile->name + ".lock"_L1); - if (!readOnly && !lockFile.lock() && atomicSyncOnly) { - setStatus(QSettings::AccessError); - return; -@@ -1426,11 +1416,6 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile) - #if !defined(QT_BOOTSTRAPPED) && QT_CONFIG(temporaryfile) - QSaveFile sf(confFile->name); - sf.setDirectWriteFallback(!atomicSyncOnly); --# ifdef Q_OS_ANDROID -- // QSaveFile requires direct write when using content scheme URL in Android -- if (confFile->name.startsWith("content:"_L1)) -- sf.setDirectWriteFallback(true); --# endif - #else - QFile sf(confFile->name); - #endif --- -2.39.0 - diff --git a/libs/patches/qt-base-0003-Android-A11Y-Only-access-the-main-thread-when-it-is-.patch b/libs/patches/qt-base-0003-Android-A11Y-Only-access-the-main-thread-when-it-is-.patch deleted file mode 100644 index ea17cb1c6..000000000 --- a/libs/patches/qt-base-0003-Android-A11Y-Only-access-the-main-thread-when-it-is-.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 97d4394f85f120724a9cbe518ba2233b87e48c68 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); --- -2.39.0 - diff --git a/libs/patches/qt-connectivity-0001-iOS-NFC-Always-ensure-timeout-after-session-invalida.patch b/libs/patches/qt-connectivity-0001-iOS-NFC-Always-ensure-timeout-after-session-invalida.patch deleted file mode 100644 index f7da165bc..000000000 --- a/libs/patches/qt-connectivity-0001-iOS-NFC-Always-ensure-timeout-after-session-invalida.patch +++ /dev/null @@ -1,140 +0,0 @@ -From 720768b715d432aa084c9c15b994a396a89968a8 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(); - }; - - --- -2.39.1 - diff --git a/libs/patches/qt-declarative-0001-qmlformat-fix-omitting-some-comments-while-reformatt.patch b/libs/patches/qt-declarative-0001-qmlformat-fix-omitting-some-comments-while-reformatt.patch deleted file mode 100644 index 7ad14c863..000000000 --- a/libs/patches/qt-declarative-0001-qmlformat-fix-omitting-some-comments-while-reformatt.patch +++ /dev/null @@ -1,102 +0,0 @@ -From f5b5a974f6ad854008c587c9494ae46785e21899 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() --- -2.39.1 - diff --git a/libs/patches/qt-scxml-0001-Make-qtdeclarative-optional-for-CONTAINER_SDK.patch b/libs/patches/qt-scxml-0001-Make-qtdeclarative-optional-for-CONTAINER_SDK.patch deleted file mode 100644 index d345633b1..000000000 --- a/libs/patches/qt-scxml-0001-Make-qtdeclarative-optional-for-CONTAINER_SDK.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 5a844a0c1b5e9c1b9fb94831afc0724f5deaa7dd 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 ee6f92e..7375551 100644 ---- x/qtscxml/dependencies.yaml -+++ y/qtscxml/dependencies.yaml -@@ -4,4 +4,4 @@ dependencies: - required: true - ../qtdeclarative: - ref: a514640b2a38391fceaaac3ca01b390ad3d62f31 -- required: true -+ required: false --- -2.38.1 - diff --git a/libs/patches/qt-tools-0002-Revert-Move-UiTools-and-UiPlugin-modules-to-a-upper-.patch b/libs/patches/qt-tools-0002-Revert-Move-UiTools-and-UiPlugin-modules-to-a-upper-.patch deleted file mode 100644 index ef7852d63..000000000 --- a/libs/patches/qt-tools-0002-Revert-Move-UiTools-and-UiPlugin-modules-to-a-upper-.patch +++ /dev/null @@ -1,3235 +0,0 @@ -From d6c550d3ef01a50e100acd4fa44a2d6fbd376cbb 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 | 47 + - src/designer/src/uitools/qtuitoolsglobal.h | 24 + - 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, 1511 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..5306fcbd5 ---- /dev/null -+++ y/qttools/src/designer/src/uitools/CMakeLists.txt -@@ -0,0 +1,47 @@ -+# 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..a2f967dee ---- /dev/null -+++ y/qttools/src/designer/src/uitools/qtuitoolsglobal.h -@@ -0,0 +1,24 @@ -+// 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", - ); --- -2.38.1 - diff --git a/libs/patches/qt-webengine-0001-Fix-Linux-build-with-CMake-versions-3.25.patch b/libs/patches/qt-webengine-0001-Fix-Linux-build-with-CMake-versions-3.25.patch deleted file mode 100644 index 0ded83d28..000000000 --- a/libs/patches/qt-webengine-0001-Fix-Linux-build-with-CMake-versions-3.25.patch +++ /dev/null @@ -1,39 +0,0 @@ -From dfc2918f8d635edf9300512fc5c1a067a89707d1 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) --- -2.38.1 - diff --git a/libs/patches/qt-base-0001-Revert-Fix-usage-of-logging-category-on-Android.patch b/libs/patches/qtbase-0001-Revert-Fix-usage-of-logging-category-on-Android.patch similarity index 87% rename from libs/patches/qt-base-0001-Revert-Fix-usage-of-logging-category-on-Android.patch rename to libs/patches/qtbase-0001-Revert-Fix-usage-of-logging-category-on-Android.patch index 23f53c9c0..a4b9447bb 100644 --- a/libs/patches/qt-base-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 ca3a694221c62131a384cbabd7dc34f91add9eae 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; }; @@ -38,6 +38,3 @@ index 9ac70b3340..737a91dc6e 100644 return true; // Prevent further output to stderr } --- -2.38.1 - diff --git a/libs/patches/qt-base-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 95% rename from libs/patches/qt-base-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 29a703777..26a28e62b 100644 --- a/libs/patches/qt-base-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 bc1b984a5b1a53c0c9eccc44763aaf0c94294fb7 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; @@ -44,6 +44,3 @@ index 69dc2d2446..88e8ab08d2 100644 { while (first != last) { if (std::invoke(pred, std::invoke(proj, *first))) --- -2.39.0 - 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-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-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/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/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-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/qt-scxml-0002-Disable-qtscxml-library.patch b/libs/patches/qtscxml-0001-Build-statemachine-only.patch similarity index 55% rename from libs/patches/qt-scxml-0002-Disable-qtscxml-library.patch rename to libs/patches/qtscxml-0001-Build-statemachine-only.patch index c311a71a1..7476d8b75 100644 --- a/libs/patches/qt-scxml-0002-Disable-qtscxml-library.patch +++ b/libs/patches/qtscxml-0001-Build-statemachine-only.patch @@ -1,38 +1,40 @@ -From ee68d7d67358f92c87720c2f740322fb03ad8299 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 f1b7c2b..7e28acc 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 9726a78..956f904 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) + #add_subdirectory(qscxmlc) endif() --- -2.38.1 - diff --git a/libs/patches/qt-tools-0001-Disable-linguist-but-keep-translation-tools.patch b/libs/patches/qttools-0001-Disable-linguist-but-keep-translation-tools.patch similarity index 83% rename from libs/patches/qt-tools-0001-Disable-linguist-but-keep-translation-tools.patch rename to libs/patches/qttools-0001-Disable-linguist-but-keep-translation-tools.patch index 54eda298c..3715343c9 100644 --- a/libs/patches/qt-tools-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 125584904a64497ae50b227ef326e0fc12683a4b 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,8 +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 --- -2.38.1 - + 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/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 e8a5f7821..000000000 --- a/resources/ausweisapp_android.qrc +++ /dev/null @@ -1,6 +0,0 @@ - - - images/android/material_phone_android.svg - images/android/material_share.svg - - diff --git a/resources/ausweisapp_desktop.qrc b/resources/ausweisapp_desktop.qrc index 02422ee37..7d3f1351a 100644 --- a/resources/ausweisapp_desktop.qrc +++ b/resources/ausweisapp_desktop.qrc @@ -1,22 +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_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 182741824..000000000 --- a/resources/ausweisapp_ios.qrc +++ /dev/null @@ -1,6 +0,0 @@ - - - images/ios/material_phone_iphone.svg - images/ios/share.svg - - diff --git a/resources/ausweisapp_mobile.qrc b/resources/ausweisapp_mobile.qrc index a6ba90344..e690f309d 100644 --- a/resources/ausweisapp_mobile.qrc +++ b/resources/ausweisapp_mobile.qrc @@ -1,224 +1,40 @@ - qtquickcontrols2.conf + 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_smart.svg images/mobile/icon_remote.svg images/mobile/icon_simulator.svg - images/mobile/material_arrow_right.svg - images/mobile/material_arrow_back.svg + images/mobile/icon_smart.svg + images/mobile/share.svg + images/mobile/material_arrow_left.svg images/mobile/material_backspace.svg images/mobile/material_view_headline.svg - images/mobile/material_home.svg - images/mobile/phone_smart.svg + images/mobile/phone_card_reader.svg images/mobile/phone_nfc.svg images/mobile/phone_nfc_with_card.svg images/mobile/phone_remote.svg images/mobile/phone_simulator.svg - images/mobile/generic_id_card.svg - 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/provider/ios/general.svg - images/provider/ios/citizen.svg - images/provider/ios/finance.svg - images/provider/ios/insurance.svg - images/provider/ios/other.svg - images/provider/default_bg.svg - images/provider/citizen_button.svg - images/provider/finance_button.svg - images/provider/general_button.svg - images/provider/insurance_button.svg - images/provider/other_button.svg - images/provider/citizen_bg.svg - images/provider/finance_bg.svg - images/provider/general_bg.svg - images/provider/insurance_bg.svg - images/provider/other_bg.svg - images/tutorial/main_menu_what_caret.svg - images/tutorial/main_menu_where_caret.svg - images/tutorial/main_menu_how_caret.svg - images/tutorial/main_menu_important_caret.svg - images/tutorial/background_icon_how.svg - images/tutorial/background_icon_where.svg - images/tutorial/background_icon_important.svg - images/tutorial/icon_box.svg - images/tutorial/icon_circle.svg - images/tutorial/icon_diamond.svg - images/tutorial/icon_star.svg - images/tutorial/arrow_blue.svg - images/tutorial/arrows.svg - images/tutorial/button_de.png - images/tutorial/button_en.png - images/tutorial/identify.svg - images/tutorial/questionmark.svg - images/tutorial/hint.svg - images/tutorial/thumb_up.svg - images/tutorial/hand.svg - images/tutorial/check.svg - images/tutorial/cross.svg - images/tutorial/click.svg - images/tutorial/save.svg - images/tutorial/bva.svg - images/tutorial/provider_home.svg - images/tutorial/rectangles.svg - images/tutorial/laptop.svg - images/tutorial/tablet.svg - images/tutorial/tablet-nfc.svg - images/tutorial/tablet-no-nfc.svg - images/tutorial/reader.svg - images/tutorial/desktop.svg - images/tutorial/phone.svg - images/tutorial/phone_border.svg - images/tutorial/phone_list.svg - images/tutorial/phone_screen.svg - images/tutorial/nfc.svg - images/tutorial/no-nfc.svg - images/tutorial/wifi.svg - images/tutorial/letters.svg - images/tutorial/usb.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.svg - images/tutorial/circle-lock-2.svg - images/tutorial/up_icon.svg - images/tutorial/phone_screen_de.png - images/tutorial/phone_screen_en.png - images/tutorial/pin-5@2x.png - images/tutorial/pin-6@2x.png - images/tutorial/user-tine@3x.png - images/tutorial/providericons.png - images/tutorial/play_movie.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_ios_de.png - images/tutorial/screenshot_check_id_card_ios_en.png - images/tutorial/screenshot_cert_android_de.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_providerlist_android_de.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_remoteservice_android_de.png - images/tutorial/screenshot_remoteservice_android_en.png - images/tutorial/screenshot_remoteservice_ios_en.png - images/tutorial/screenshot_remoteservice_ios_de.png - images/tutorial/screenshot_pairing_de.png - images/tutorial/screenshot_pairing_en.png - images/tutorial/screenshot_choose_reader_android_de.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_pin_management_menu_android_en.png - images/tutorial/screenshot_pin_management_menu_android_de.png - images/tutorial/screenshot_pin_management_menu_ios_en.png - images/tutorial/screenshot_pin_management_menu_ios_de.png - images/tutorial/screenshot_start_android_en.png - images/tutorial/screenshot_start_android_de.png - images/tutorial/screenshot_start_ios_en.png - images/tutorial/screenshot_start_ios_de.png - images/tutorial/screenshot_selfauthentication_android_de.png - images/tutorial/screenshot_selfauthentication_android_en.png - images/tutorial/screenshot_selfauthentication_ios_de.png - images/tutorial/screenshot_selfauthentication_ios_en.png - images/tutorial/section_seperator_what.svg - images/tutorial/section_seperator_where.svg - images/tutorial/section_seperator_how.svg - images/tutorial/section_seperator_important.svg - images/tutorial/where_overview_question.svg - images/tutorial/where_identify_now_de.svg - images/tutorial/where_identify_now_en.svg - images/tutorial/where_userdata_example_de.svg - images/tutorial/where_userdata_example_en.svg - images/tutorial/where_lay_down_id.svg - images/tutorial/where_pin6.svg - images/tutorial/how_questions_everywhere.svg - images/tutorial/how_device_lineup.svg - images/tutorial/how_method_nfc.svg - images/tutorial/how_method_sac_desktop.svg - images/tutorial/how_method_sac_mobile.svg - images/tutorial/how_form_no_fun.svg - images/tutorial/how_desktop.svg - images/tutorial/important_pin5.svg - images/tutorial/important_pin6.svg - images/tutorial/important_lets_go.svg - images/tutorial/important_space_questionmark.svg - images/tutorial/reader_nfc_provider_on_smartphone.svg - images/tutorial/reader_nfc_npa_on_smartphone.svg - images/tutorial/reader_nfc_smartphone_nfc_position.svg - images/tutorial/reader_nfc_finished.svg - images/tutorial/reader_nfc_pin6.svg - images/tutorial/reader_nfc_userdata_example_de.svg - images/tutorial/reader_nfc_userdata_example_en.svg - images/tutorial/reader_sac_provider_on_laptop.svg - images/tutorial/reader_sac_npa_on_laptop.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_ios_de.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/button_en.png - images/tutorial/phone_screen_en.png - images/tutorial/screenshot_cert_android_en.png - images/tutorial/screenshot_cert_ios_en.png - images/tutorial/screenshot_check_id_card_android_en.png - images/tutorial/screenshot_check_id_card_ios_en.png - images/tutorial/screenshot_choose_reader_android_en.png - images/tutorial/screenshot_choose_reader_ios_en.png - images/tutorial/screenshot_pairing_en.png - images/tutorial/screenshot_pin_management_menu_android_en.png - images/tutorial/screenshot_pin_management_menu_ios_en.png - images/tutorial/screenshot_providerlist_android_en.png - images/tutorial/screenshot_providerlist_ios_en.png - images/tutorial/screenshot_remoteservice_android_en.png - images/tutorial/screenshot_remoteservice_ios_en.png - images/tutorial/screenshot_selfauthentication_android_en.png - images/tutorial/screenshot_selfauthentication_ios_en.png - images/tutorial/screenshot_start_android_en.png - images/tutorial/screenshot_start_ios_en.png - images/tutorial/reader_nfc_userdata_example_en.svg - images/tutorial/reader_sac_menu_android_en.svg - images/tutorial/reader_sac_menu_ios_en.svg - images/tutorial/src/phone_screen_en.svg - images/tutorial/where_identify_now_en.svg - images/tutorial/where_userdata_example_en.svg - - - images/tutorial/button_en.png - images/tutorial/phone_screen_en.png - images/tutorial/screenshot_cert_android_en.png - images/tutorial/screenshot_cert_ios_en.png - images/tutorial/screenshot_check_id_card_android_en.png - images/tutorial/screenshot_check_id_card_ios_en.png - images/tutorial/screenshot_choose_reader_android_en.png - images/tutorial/screenshot_choose_reader_ios_en.png - images/tutorial/screenshot_pairing_en.png - images/tutorial/screenshot_pin_management_menu_android_en.png - images/tutorial/screenshot_pin_management_menu_ios_en.png - images/tutorial/screenshot_providerlist_android_en.png - images/tutorial/screenshot_providerlist_ios_en.png - images/tutorial/screenshot_remoteservice_android_en.png - images/tutorial/screenshot_remoteservice_ios_en.png - images/tutorial/screenshot_selfauthentication_android_en.png - images/tutorial/screenshot_selfauthentication_ios_en.png - images/tutorial/screenshot_start_android_en.png - images/tutorial/screenshot_start_ios_en.png - images/tutorial/reader_nfc_userdata_example_en.svg - images/tutorial/reader_sac_menu_android_en.svg - images/tutorial/reader_sac_menu_ios_en.svg - images/tutorial/src/phone_screen_en.svg - images/tutorial/where_identify_now_en.svg - images/tutorial/where_userdata_example_en.svg + images/mobile/phone_smart.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/adaptive_monochrome_beta.svg b/resources/images/android/adaptive_monochrome_beta.svg new file mode 100644 index 000000000..148445eef --- /dev/null +++ b/resources/images/android/adaptive_monochrome_beta.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/resources/images/android/adaptive_monochrome_preview.svg b/resources/images/android/adaptive_monochrome_preview.svg new file mode 100644 index 000000000..de08bb3cd --- /dev/null +++ b/resources/images/android/adaptive_monochrome_preview.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/resources/images/android/adaptive_monochrome_release.svg b/resources/images/android/adaptive_monochrome_release.svg new file mode 100644 index 000000000..6e8057b1f --- /dev/null +++ b/resources/images/android/adaptive_monochrome_release.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + diff --git a/resources/images/android/hdpi/monochrome_npa.png b/resources/images/android/hdpi/monochrome_npa.png new file mode 100644 index 000000000..a1f62c6f5 Binary files /dev/null and b/resources/images/android/hdpi/monochrome_npa.png differ diff --git a/resources/images/android/hdpi/monochrome_npa_beta.png b/resources/images/android/hdpi/monochrome_npa_beta.png new file mode 100644 index 000000000..0b02ef3eb Binary files /dev/null and b/resources/images/android/hdpi/monochrome_npa_beta.png differ diff --git a/resources/images/android/hdpi/monochrome_npa_preview.png b/resources/images/android/hdpi/monochrome_npa_preview.png new file mode 100644 index 000000000..26762f855 Binary files /dev/null and b/resources/images/android/hdpi/monochrome_npa_preview.png 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/monochrome_npa.png b/resources/images/android/ldpi/monochrome_npa.png new file mode 100644 index 000000000..21d31857a Binary files /dev/null and b/resources/images/android/ldpi/monochrome_npa.png differ diff --git a/resources/images/android/ldpi/monochrome_npa_beta.png b/resources/images/android/ldpi/monochrome_npa_beta.png new file mode 100644 index 000000000..cfe226711 Binary files /dev/null and b/resources/images/android/ldpi/monochrome_npa_beta.png differ diff --git a/resources/images/android/ldpi/monochrome_npa_preview.png b/resources/images/android/ldpi/monochrome_npa_preview.png new file mode 100644 index 000000000..6f7b4c17d Binary files /dev/null and b/resources/images/android/ldpi/monochrome_npa_preview.png 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_phone_android.svg b/resources/images/android/material_phone_android.svg deleted file mode 100644 index b7a256bcb..000000000 --- a/resources/images/android/material_phone_android.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file 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/monochrome_npa.png b/resources/images/android/mdpi/monochrome_npa.png new file mode 100644 index 000000000..1e08f0def Binary files /dev/null and b/resources/images/android/mdpi/monochrome_npa.png differ diff --git a/resources/images/android/mdpi/monochrome_npa_beta.png b/resources/images/android/mdpi/monochrome_npa_beta.png new file mode 100644 index 000000000..cf03b597e Binary files /dev/null and b/resources/images/android/mdpi/monochrome_npa_beta.png differ diff --git a/resources/images/android/mdpi/monochrome_npa_preview.png b/resources/images/android/mdpi/monochrome_npa_preview.png new file mode 100644 index 000000000..38a2f986e Binary files /dev/null and b/resources/images/android/mdpi/monochrome_npa_preview.png differ 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/monochrome_npa.png b/resources/images/android/xhdpi/monochrome_npa.png new file mode 100644 index 000000000..e8acb1170 Binary files /dev/null and b/resources/images/android/xhdpi/monochrome_npa.png differ diff --git a/resources/images/android/xhdpi/monochrome_npa_beta.png b/resources/images/android/xhdpi/monochrome_npa_beta.png new file mode 100644 index 000000000..5cb637325 Binary files /dev/null and b/resources/images/android/xhdpi/monochrome_npa_beta.png differ diff --git a/resources/images/android/xhdpi/monochrome_npa_preview.png b/resources/images/android/xhdpi/monochrome_npa_preview.png new file mode 100644 index 000000000..ac7309a88 Binary files /dev/null and b/resources/images/android/xhdpi/monochrome_npa_preview.png differ 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/monochrome_npa.png b/resources/images/android/xxhdpi/monochrome_npa.png new file mode 100644 index 000000000..fd700d694 Binary files /dev/null and b/resources/images/android/xxhdpi/monochrome_npa.png differ diff --git a/resources/images/android/xxhdpi/monochrome_npa_beta.png b/resources/images/android/xxhdpi/monochrome_npa_beta.png new file mode 100644 index 000000000..c7647f0ce Binary files /dev/null and b/resources/images/android/xxhdpi/monochrome_npa_beta.png differ diff --git a/resources/images/android/xxhdpi/monochrome_npa_preview.png b/resources/images/android/xxhdpi/monochrome_npa_preview.png new file mode 100644 index 000000000..6866745a8 Binary files /dev/null and b/resources/images/android/xxhdpi/monochrome_npa_preview.png 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/monochrome_npa.png b/resources/images/android/xxxhdpi/monochrome_npa.png new file mode 100644 index 000000000..812653d7e Binary files /dev/null and b/resources/images/android/xxxhdpi/monochrome_npa.png differ diff --git a/resources/images/android/xxxhdpi/monochrome_npa_beta.png b/resources/images/android/xxxhdpi/monochrome_npa_beta.png new file mode 100644 index 000000000..76abeeb9d Binary files /dev/null and b/resources/images/android/xxxhdpi/monochrome_npa_beta.png differ diff --git a/resources/images/android/xxxhdpi/monochrome_npa_preview.png b/resources/images/android/xxxhdpi/monochrome_npa_preview.png new file mode 100644 index 000000000..fc43da6c3 Binary files /dev/null and b/resources/images/android/xxxhdpi/monochrome_npa_preview.png 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/info_white.svg b/resources/images/desktop/info_white.svg new file mode 100644 index 000000000..6725deeef --- /dev/null +++ b/resources/images/desktop/info_white.svg @@ -0,0 +1,21 @@ + + + + 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 a87416f2f..000000000 --- a/resources/images/desktop/material_a11y.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/resources/images/desktop/material_assistant.svg b/resources/images/desktop/material_assistant.svg index a70334532..fbfd819c1 100644 --- a/resources/images/desktop/material_assistant.svg +++ b/resources/images/desktop/material_assistant.svg @@ -1 +1 @@ - + diff --git a/resources/images/desktop/material_bug_report.svg b/resources/images/desktop/material_bug_report.svg deleted file mode 100644 index 718f6b36b..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 ae7443060..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 0a9ef46da..000000000 --- a/resources/images/desktop/material_menu_book.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 209018412..000000000 --- a/resources/images/desktop/material_privacy.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file 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/material_settings.svg b/resources/images/desktop/material_settings_white.svg similarity index 100% rename from resources/images/material_settings.svg rename to resources/images/desktop/material_settings_white.svg diff --git a/resources/images/desktop/material_video.svg b/resources/images/desktop/material_video.svg deleted file mode 100644 index 1d5a32eca..000000000 --- a/resources/images/desktop/material_video.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/resources/images/desktop/material_view_list.svg b/resources/images/desktop/material_view_list.svg deleted file mode 100644 index 550b676c0..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 6725deeef..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/material_phone_iphone.svg b/resources/images/ios/material_phone_iphone.svg deleted file mode 100644 index 91ad0e071..000000000 --- a/resources/images/ios/material_phone_iphone.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_add.svg b/resources/images/material_add.svg new file mode 100644 index 000000000..70898c171 --- /dev/null +++ b/resources/images/material_add.svg @@ -0,0 +1 @@ + \ No newline at end of file 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 7677f0ed9..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 6975ecef2..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 06255c48d..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 cfc8a0c3f..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_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 new file mode 100644 index 000000000..7b68f72b9 --- /dev/null +++ b/resources/images/mobile/phone_card_reader.svg @@ -0,0 +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 4988d8537..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 e7d8a8f8d..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 0e420450e..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 61d600c42..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 9d78bf09b..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 098254a62..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 4766d7ae1..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 6d66ec2fb..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 bdd8e2a0a..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 7e3de5cd6..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 5779a2a47..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 3bc2ca409..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 d2baa9b49..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 5e11871b1..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 9ef8bd93a..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 6fa8d3bf3..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 6d070268f..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 af038b892..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 43658c34f..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 b60a71c1f..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 9bab8dcc4..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 5140f7e64..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 b2a0e782a..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 c61df8c65..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 a99803c52..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 abcb8cbfd..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 edce7768c..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 f146014be..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 5b589703b..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 1fd47167c..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 ceb8f6d19..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 bd2678cac..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 07b186c52..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 f2bc875ac..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 428c5d66c..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 a4df6dba8..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 a46e038f2..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 26e3ff9b6..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/common/Dockerfile b/resources/jenkins/docker/alpine-common/Dockerfile similarity index 91% rename from resources/jenkins/docker/common/Dockerfile rename to resources/jenkins/docker/alpine-common/Dockerfile index be1511a71..68fa974db 100644 --- a/resources/jenkins/docker/common/Dockerfile +++ b/resources/jenkins/docker/alpine-common/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:swarm +FROM dev-docker.governikus.de/ausweisapp2/alpine:swarm MAINTAINER Governikus KG ARG UNCRUSTIFY=0.74.0 diff --git a/resources/jenkins/docker/docs/Dockerfile b/resources/jenkins/docker/alpine-docs/Dockerfile similarity index 62% rename from resources/jenkins/docker/docs/Dockerfile rename to resources/jenkins/docker/alpine-docs/Dockerfile index 2d54decfe..054b6cb2c 100644 --- a/resources/jenkins/docker/docs/Dockerfile +++ b/resources/jenkins/docker/alpine-docs/Dockerfile @@ -1,9 +1,9 @@ -FROM alpine:swarm +FROM dev-docker.governikus.de/ausweisapp2/alpine:swarm MAINTAINER Governikus KG ENV NAME=Docs LABELS=Docs -RUN apk --no-cache add py3-setuptools icu poppler zziplib enscript ghostscript texlive-full py3-sphinx py3-sphinx_rtd_theme && \ +RUN apk --no-cache add py3-setuptools icu poppler zziplib enscript ghostscript texlive-full py3-sphinx py3-sphinx_rtd_theme py3-sphinx-copybutton && \ pip3 install doc8 USER governikus diff --git a/resources/jenkins/docker/linux/Dockerfile b/resources/jenkins/docker/alpine-linux/Dockerfile similarity index 92% rename from resources/jenkins/docker/linux/Dockerfile rename to resources/jenkins/docker/alpine-linux/Dockerfile index e7e427a85..8077d7f64 100644 --- a/resources/jenkins/docker/linux/Dockerfile +++ b/resources/jenkins/docker/alpine-linux/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:swarm +FROM dev-docker.governikus.de/ausweisapp2/alpine:swarm MAINTAINER Governikus KG ENV NAME=Linux LABELS="Linux g++ clang++" PACKAGES_DIR=/home/governikus/packages diff --git a/resources/jenkins/docker/swarm/Dockerfile b/resources/jenkins/docker/alpine-swarm/Dockerfile similarity index 90% rename from resources/jenkins/docker/swarm/Dockerfile rename to resources/jenkins/docker/alpine-swarm/Dockerfile index 527175dac..5c75ef601 100644 --- a/resources/jenkins/docker/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/swarm-ubuntu/swarm.sh b/resources/jenkins/docker/alpine-swarm/swarm.sh similarity index 82% rename from resources/jenkins/docker/swarm-ubuntu/swarm.sh rename to resources/jenkins/docker/alpine-swarm/swarm.sh index 65504707c..9de004a53 100755 --- a/resources/jenkins/docker/swarm-ubuntu/swarm.sh +++ b/resources/jenkins/docker/alpine-swarm/swarm.sh @@ -7,10 +7,11 @@ labels=${LABELS:-undefined} mode=${MODE:-exclusive} master=${MASTER:-https://ausweisapp-ci.govkg.de/} user=${USER:-jenkins-swarm} -fingerprints=${FINGERPRINTS:-40:DD:0E:F9:8D:A1:DA:39:D4:B9:B6:31:C3:F8:E5:8B:45:76:C5:BB:68:61:4A:F3:DD:14:16:85:D9:03:C2:02} +fingerprints=${FINGERPRINTS:-FA:B8:35:6B:4F:1F:AF:68:9F:CC:B9:63:71:BC:1F:DA:6E:DB:61:F6:C7:E4:64:F6:41:8F:51:09:4C:A9:A0:A9} /usr/bin/java \ -jar /swarm-client.jar \ + -webSocket \ -name $name-$HOSTNAME \ -mode $mode \ -executors $executor \ diff --git a/resources/jenkins/docker/trigger/Dockerfile b/resources/jenkins/docker/alpine-trigger/Dockerfile similarity index 73% rename from resources/jenkins/docker/trigger/Dockerfile rename to resources/jenkins/docker/alpine-trigger/Dockerfile index 60a4eff59..4271630d7 100644 --- a/resources/jenkins/docker/trigger/Dockerfile +++ b/resources/jenkins/docker/alpine-trigger/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:swarm +FROM dev-docker.governikus.de/ausweisapp2/alpine:swarm MAINTAINER Governikus KG ENV NAME=Trigger LABELS="Trigger Seeder" diff --git a/resources/jenkins/docker/generate.py b/resources/jenkins/docker/generate.py index 4d6eea439..8ed942edd 100755 --- a/resources/jenkins/docker/generate.py +++ b/resources/jenkins/docker/generate.py @@ -10,12 +10,29 @@ print("python version >=3.5 required") sys.exit(1) +args = str(sys.argv) + # Alpine -images = ["swarm", "trigger", "common", "docs", "linux"] -for image in images: - print("Building %s ..." % (image)) - proc_args = ["docker", "build", "-t", "alpine:%s" % (image), image] - subprocess.run(proc_args).check_returncode() - proc_args = ["docker", "tag", "alpine:%s" % (image), - "dev-docker.govkg.de/ausweisapp2/alpine:%s" % image] - subprocess.run(proc_args).check_returncode() +alpine = ['alpine:swarm', 'alpine:trigger', + 'alpine:common', 'alpine:docs', 'alpine:linux'] + +# Ubuntu +ubuntu = ['ubuntu:swarm', 'ubuntu:android', 'ubuntu:vanilla'] + +images = alpine + ubuntu + +if 'build' in args: + for image in images: + dir = image.replace(':', '-') + print('Building %s in directory %s' % (image, dir)) + proc_args = ['docker', 'build', '-t', + 'dev-docker.governikus.de/ausweisapp2/%s' % (image), dir] + subprocess.run(proc_args).check_returncode() + + +if 'push' in args: + for image in images: + print('Push %s' % image) + proc_args = ['docker', 'push', + 'dev-docker.governikus.de/ausweisapp2/%s' % (image)] + subprocess.run(proc_args).check_returncode() diff --git a/resources/jenkins/docker/android/Dockerfile b/resources/jenkins/docker/ubuntu-android/Dockerfile similarity index 72% rename from resources/jenkins/docker/android/Dockerfile rename to resources/jenkins/docker/ubuntu-android/Dockerfile index da95d2aee..921bb14eb 100644 --- a/resources/jenkins/docker/android/Dockerfile +++ b/resources/jenkins/docker/ubuntu-android/Dockerfile @@ -1,28 +1,24 @@ -FROM ubuntu:swarm +FROM dev-docker.governikus.de/ausweisapp2/ubuntu:swarm MAINTAINER Governikus KG -ARG ANDROID_CMDLINE_TOOLS=8092744 -ARG ANDROID_NDK_VERSION=21.4.7075529 -ARG CMAKE=3.22.2 +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 -# Remove this later: https://github.com/openssl/openssl/pull/11206 -ENV ANDROID_NDK $ANDROID_NDK_ROOT - 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;6.0" "build-tools;30.0.3" "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/swarm-ubuntu/Dockerfile b/resources/jenkins/docker/ubuntu-swarm/Dockerfile similarity index 57% rename from resources/jenkins/docker/swarm-ubuntu/Dockerfile rename to resources/jenkins/docker/ubuntu-swarm/Dockerfile index caaab8a96..ae4298168 100644 --- a/resources/jenkins/docker/swarm-ubuntu/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/swarm/swarm.sh b/resources/jenkins/docker/ubuntu-swarm/swarm.sh similarity index 82% rename from resources/jenkins/docker/swarm/swarm.sh rename to resources/jenkins/docker/ubuntu-swarm/swarm.sh index 65504707c..9de004a53 100755 --- a/resources/jenkins/docker/swarm/swarm.sh +++ b/resources/jenkins/docker/ubuntu-swarm/swarm.sh @@ -7,10 +7,11 @@ labels=${LABELS:-undefined} mode=${MODE:-exclusive} master=${MASTER:-https://ausweisapp-ci.govkg.de/} user=${USER:-jenkins-swarm} -fingerprints=${FINGERPRINTS:-40:DD:0E:F9:8D:A1:DA:39:D4:B9:B6:31:C3:F8:E5:8B:45:76:C5:BB:68:61:4A:F3:DD:14:16:85:D9:03:C2:02} +fingerprints=${FINGERPRINTS:-FA:B8:35:6B:4F:1F:AF:68:9F:CC:B9:63:71:BC:1F:DA:6E:DB:61:F6:C7:E4:64:F6:41:8F:51:09:4C:A9:A0:A9} /usr/bin/java \ -jar /swarm-client.jar \ + -webSocket \ -name $name-$HOSTNAME \ -mode $mode \ -executors $executor \ diff --git a/resources/jenkins/docker/ubuntu-vanilla/Dockerfile b/resources/jenkins/docker/ubuntu-vanilla/Dockerfile new file mode 100644 index 000000000..1822ac91e --- /dev/null +++ b/resources/jenkins/docker/ubuntu-vanilla/Dockerfile @@ -0,0 +1,43 @@ +FROM dev-docker.governikus.de/ausweisapp2/ubuntu:swarm +MAINTAINER Governikus KG + +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 \ + \ + 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 +RUN mkdir -p /home/governikus/.ccache && mkdir -p /home/governikus/workspace && mkdir -p /home/governikus/packages + +ENTRYPOINT ["/usr/bin/tini", "--"] +CMD /swarm.sh diff --git a/resources/jenkins/docker/vanilla/Dockerfile b/resources/jenkins/docker/vanilla/Dockerfile deleted file mode 100644 index 61829d2bd..000000000 --- a/resources/jenkins/docker/vanilla/Dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -FROM ubuntu:swarm -MAINTAINER Governikus KG - -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 && \ - rm -rf /var/lib/apt/lists/* - -USER governikus -RUN mkdir -p /home/governikus/.ccache && mkdir -p /home/governikus/workspace && mkdir -p /home/governikus/packages - -ENTRYPOINT ["/usr/bin/tini", "--"] -CMD /swarm.sh 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 53d982da9..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) @@ -21,15 +21,17 @@ j.with steps { + shell('docker container prune -f') + 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 3ce81067d..19dac6f00 100644 --- a/resources/jenkins/dsl/Builds/Build_Docs.groovy +++ b/resources/jenkins/dsl/Builds/Build_Docs.groovy @@ -16,15 +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 inst.latex.pdf') + shell('cmake --build build --target failurecodes') + shell('cmake --build build --target failurecodes.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 43513609a..f7c7d7b22 100644 --- a/resources/jenkins/dsl/Releases/Release_Docs.groovy +++ b/resources/jenkins/dsl/Releases/Release_Docs.groovy @@ -21,15 +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 inst.latex.pdf') + shell('cmake --build build --target failurecodes') + shell('cmake --build build --target failurecodes.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 73de84eb5..37667a586 100644 --- a/resources/jenkins/dsl/Reviews/Review_Docs.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Docs.groovy @@ -20,15 +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 inst.latex.pdf') + shell('cmake --build build --target failurecodes') + shell('cmake --build build --target failurecodes.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 98d1e5a12..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@"> - + @@ -38,7 +38,9 @@ android:name="org.qtproject.qt.android.bindings.QtApplication" android:allowBackup="false" android:allowNativeHeapPointerTagging="false" + android:dataExtractionRules="@xml/data_extraction_rules" android:extractNativeLibs="true" + android:fullBackupContent="@xml/full_backup_content" android:hardwareAccelerated="true" android:icon="@mipmap/npa" android:label="@string/app_name" @@ -71,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"> @@ -82,16 +86,11 @@ - - + + + + + diff --git a/resources/packaging/android/build.gradle.append b/resources/packaging/android/build.gradle.append index 91ba06e33..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 { @@ -37,6 +36,14 @@ android { exclude 'META-INF/native-image/**' exclude 'META-INF/native/**' exclude 'META-INF/license/**' + exclude '**/libplugins_tls_qcertonlybackend_*.so' + exclude '**/libplugins_networkinformation_*.so' + exclude '**/libplugins_imageformats_qgif_*.so' + exclude '**/libplugins_imageformats_qicns_*.so' + exclude '**/libplugins_imageformats_qico_*.so' + exclude '**/libplugins_imageformats_qtga_*.so' + exclude '**/libplugins_imageformats_qtiff_*.so' + exclude '**/libplugins_imageformats_qwbmp_*.so' jniLibs { useLegacyPackaging = true diff --git a/resources/packaging/android/build.gradle.append.aar b/resources/packaging/android/build.gradle.append.aar new file mode 100644 index 000000000..6557c1109 --- /dev/null +++ b/resources/packaging/android/build.gradle.append.aar @@ -0,0 +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/data_extraction_rules.xml b/resources/packaging/android/data_extraction_rules.xml new file mode 100644 index 000000000..224515d8b --- /dev/null +++ b/resources/packaging/android/data_extraction_rules.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/resources/packaging/android/full_backup_content.xml b/resources/packaging/android/full_backup_content.xml new file mode 100644 index 000000000..a06f20d18 --- /dev/null +++ b/resources/packaging/android/full_backup_content.xml @@ -0,0 +1,8 @@ + + + + + + + + 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 db3ee1060..a2ccff2f4 100644 --- a/resources/packaging/android/lint.aar.xml +++ b/resources/packaging/android/lint.aar.xml @@ -1,57 +1,12 @@ - - - - - - - - - - - - - - - - - diff --git a/resources/packaging/android/lint.apk.xml b/resources/packaging/android/lint.apk.xml index 599146f0b..90d197def 100644 --- a/resources/packaging/android/lint.apk.xml +++ b/resources/packaging/android/lint.apk.xml @@ -1,57 +1,12 @@ - - - - - - - - - - - - - - - - - @@ -71,60 +26,6 @@ - - - - - - - - - - - - - - - - - - - - - - + + 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 80% rename from resources/packaging/android/res/mipmap-anydpi-v26/npa.xml rename to resources/packaging/android/res/mipmap-anydpi/npa.xml index 4c7b81f35..065d6d9e0 100644 --- a/resources/packaging/android/res/mipmap-anydpi-v26/npa.xml +++ b/resources/packaging/android/res/mipmap-anydpi/npa.xml @@ -2,4 +2,5 @@ + 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 73% rename from resources/packaging/macos/AusweisApp2.entitlements rename to resources/packaging/macos/AusweisApp.entitlements index 97f3c17ac..b1b705cea 100644 --- a/resources/packaging/macos/AusweisApp2.entitlements +++ b/resources/packaging/macos/AusweisApp.entitlements @@ -12,9 +12,5 @@ com.apple.security.network.server - com.apple.security.temporary-exception.shared-preference.read-only - - /Library/Preferences/com.governikus.AusweisApp2.plist - 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 45944769f..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 { @@ -52,20 +66,21 @@ ApplicationWindow { Component.onCompleted: menuBar.forceActiveFocus(Qt.MouseFocusReason) onClosing: close => { - if (ApplicationModel.currentWorkflow !== ApplicationModel.WORKFLOW_NONE) { + if (ApplicationModel.currentWorkflow !== ApplicationModel.WORKFLOW_NONE && !d.suppressAbortWarning) { abortWorkflowWarning.open(); close.accepted = false; return; } - if (Qt.platform.os === "osx" && !SettingsModel.autoStartApp) { - close.accepted = true; + if (d.detachedLogView !== null) { + visibility = ApplicationWindow.Minimized; + close.accepted = false; return; } - if (SettingsModel.remindUserToClose) { - closeWarning.open(); + if (SettingsModel.remindUserToClose && !d.suppressAbortWarning) { + closingPopup().open(); close.accepted = false; } else { - d.hideUiAndTaskbarEntry(); + handleClosing(); } } onHeightChanged: d.setScaleFactor() @@ -75,12 +90,27 @@ ApplicationWindow { } onWidthChanged: d.setScaleFactor() + Item { + Component.onCompleted: { + Style.software_renderer = GraphicsInfo.api === GraphicsInfo.Software; + } + } QtObject { id: d property int activeView: UiModule.DEFAULT property ApplicationWindow detachedLogView: null + readonly property string hideToTrayText: { + if (Qt.platform.os === "osx") { + //: 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. + return qsTr("The program remains available via the icon in the menu bar. Click on the %1 icon to reopen the user interface.").arg(Qt.application.name); + } + + //: 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); + } property int lastVisibility: ApplicationWindow.Windowed + property bool suppressAbortWarning: false function abortCurrentWorkflow() { if (ApplicationModel.currentWorkflow === ApplicationModel.WORKFLOW_AUTHENTICATION) { @@ -101,13 +131,19 @@ 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) { + d.detachedLogView.show(); + } } function showMainWindow() { + d.suppressAbortWarning = false; 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; @@ -122,31 +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 - //: INFO DESKTOP Content of the popup that is shown when the AA2 is closed for the first time. - text: 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) + 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 } @@ -154,29 +210,48 @@ 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) - //: INFO DESKTOP Content of the popup that is shown when the AA2 is closed and a workflow is still active and the close/minimize info was not disabled. - readonly property string hideToTrayText: 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 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 ? "

%1".arg(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") onCancelled: close() onConfirmed: { d.abortCurrentWorkflow(); - d.hideUiAndTaskbarEntry(); + d.suppressAbortWarning = true; + appWindow.close(); } } 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(); } function onFireShowRequest(pModule) { d.showMainWindow(); d.closeOpenDialogs(); + d.showDetachedLogViewIfPresent(); switch (pModule) { case UiModule.CURRENT: break; @@ -222,9 +297,10 @@ ApplicationWindow { target: SettingsModel } Shortcut { - sequence: StandardKey.HelpContents + enabled: Qt.platform.os === "osx" + sequence: "Ctrl+W" - onActivated: ApplicationModel.openOnlineHelp(menuBar.rightMostAction.helpTopic) + onActivated: close() } Image { anchors.centerIn: parent @@ -237,6 +313,7 @@ ApplicationWindow { } Loader { id: contentLoader + anchors.fill: parent sourceComponent: switch (d.activeView) { case UiModule.SELF_AUTHENTICATION: @@ -245,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: @@ -273,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 } @@ -334,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 @@ -366,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) { @@ -388,9 +454,11 @@ ApplicationWindow { } ProxyCredentialsPopup { id: proxyCredentials + } Component { id: detachedLogViewWindow + ApplicationWindow { height: plugin.initialWindowSize.height minimumHeight: appWindow.minimumHeight @@ -404,6 +472,12 @@ ApplicationWindow { d.detachedLogView = null; } + Shortcut { + enabled: Qt.platform.os === "osx" + sequence: "Ctrl+W" + + onActivated: close() + } DetachedLogView { anchors.fill: parent focus: true 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 7b21cd08c..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, @@ -31,6 +31,7 @@ SectionPage { Progress, AccessRights, Workflow, + WorkflowError, Password, PasswordInfo, CardPosition, @@ -56,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) { @@ -77,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; } } } @@ -92,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 @@ -106,6 +115,7 @@ SectionPage { } AuthController { id: authController + onNextView: pName => { if (pName === AuthView.SubViews.ReturnToMain) { if (AuthModel.showChangePinView) { @@ -134,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 @@ -144,12 +155,13 @@ SectionPage { } EditRights { id: editRights + visible: d.activeView === AuthView.SubViews.AccessRights } GeneralWorkflow { id: generalWorkflow + isPinChange: false - passwordInfoLinkText: infoData.linkText visible: d.activeView === AuthView.SubViews.Workflow waitingFor: switch (authController.workflowState) { case AuthController.WorkflowStates.Reader: @@ -160,17 +172,34 @@ SectionPage { return Workflow.WaitingFor.None; } - onRequestPasswordInfo: authView.showPasswordInfo() + onDeviceUnpaired: function (pDeviceName) { + deviceUnpairedView.deviceName = pDeviceName; + showWithPrecedingView(AuthView.SubViews.WorkflowError); + } onSettingsRequested: authView.showSettings() } + ResultView { + id: deviceUnpairedView + + property string deviceName + + 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 + + onNextView: d.view = AuthView.SubViews.Workflow + } 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(); } @@ -178,17 +207,20 @@ 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() } + onAbortCurrentWorkflow: AuthModel.cancelWorkflow() onClose: { d.view = d.precedingView; updateTitleBarActions(); @@ -199,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 @@ -215,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") : @@ -228,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") @@ -265,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") : @@ -276,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 - supportButtonsVisible: AuthModel.errorIsMasked 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 d2906ef40..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/info.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 5129a8f6c..000000000 --- a/resources/qml/Governikus/AuthView/+mobile/+phone/EditRights.qml +++ /dev/null @@ -1,222 +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 - - //: 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: { - ChatModel.transferAccessRights(); - workflowModel.continueWorkflow(); - } - } - 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: !!AuthModel.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 bc13e4615..000000000 --- a/resources/qml/Governikus/AuthView/+mobile/+tablet/EditRights.qml +++ /dev/null @@ -1,214 +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 - - //: 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: { - ChatModel.transferAccessRights(); - workflowModel.continueWorkflow(); - } - - 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 4e2093a0c..889292aa6 100644 --- a/resources/qml/Governikus/AuthView/+mobile/AuthView.qml +++ b/resources/qml/Governikus/AuthView/+mobile/AuthView.qml @@ -1,249 +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.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 { - } - } - Component { - id: selfAuthenticationData - SelfAuthenticationData { - titleBarColor: root.titleBarColor - - onDone: { - pop(); - AuthModel.continueWorkflow(); - } - } - } - 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 - } - } - 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() + Connections { + function onFireWorkflowStarted() { + authController.createObject(root); + setLockedAndHidden(true); } - } - PasswordInfoData { - id: infoData - contentType: fromPasswordType(NumberModel.passwordType, NumberModel.isCanAllowedMode) - } - Component { - id: passwordInfoView - PasswordInfoView { - infoContent: infoData - onClose: pop() - } + enabled: visible + target: AuthModel } 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 bdc775369..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 { - 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.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.AlignCenter - Layout.fillWidth: true - Layout.maximumWidth: Style.dimens.max_text_width / 2 - Layout.preferredWidth: parent.width / 2 - - //: LABEL ANDROID IOS - text: qsTr("No") - - onClicked: pinUnknown() - } - GButton { - Layout.alignment: Qt.AlignCenter - Layout.fillWidth: true - Layout.maximumWidth: Style.dimens.max_text_width / 2 - Layout.preferredWidth: parent.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 6918453e6..3f8a35e1f 100644 --- a/resources/qml/Governikus/ChangePinView/+desktop/ChangePinView.qml +++ b/resources/qml/Governikus/ChangePinView/+desktop/ChangePinView.qml @@ -1,27 +1,30 @@ /** * 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, + WorkflowError, Password, NoPassword, PasswordInfo, @@ -53,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) { @@ -88,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 @@ -102,6 +105,7 @@ SectionPage { } ChangePinController { id: changePinController + onNextView: pName => { if (pName === ChangePinView.SubViews.ReturnToMain) { baseItem.nextView(UiModule.DEFAULT); @@ -117,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 { @@ -133,8 +140,8 @@ SectionPage { } GeneralWorkflow { id: generalWorkflow + isPinChange: true - passwordInfoLinkText: infoData.linkText visible: d.activeView === ChangePinView.SubViews.Workflow waitingFor: switch (changePinController.workflowState) { case ChangePinController.WorkflowStates.Reader: @@ -145,29 +152,62 @@ SectionPage { return Workflow.WaitingFor.None; } - onRequestPasswordInfo: baseItem.showPasswordInfo() + onDeviceUnpaired: function (pDeviceName) { + deviceUnpairedView.deviceName = pDeviceName; + showWithPrecedingView(ChangePinView.SubViews.WorkflowError); + } onSettingsRequested: baseItem.showSettings() } + ResultView { + id: deviceUnpairedView + + property string deviceName + + 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 + + onNextView: d.view = ChangePinView.SubViews.Workflow + } 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 + onAbortCurrentWorkflow: ChangePinModel.cancelWorkflow() onClose: { d.view = d.precedingView; updateTitleBarActions(); @@ -175,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 ? @@ -188,9 +229,23 @@ SectionPage { id: inputError property bool errorConfirmed: false + //: 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.") - resultType: ResultView.Type.IsError - text: NumberModel.inputError + 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 @@ -208,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) @@ -225,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") : @@ -237,10 +293,11 @@ SectionPage { } ResultView { id: pinResult + hintButtonText: ChangePinModel.statusHintActionText hintText: ChangePinModel.statusHintText - resultType: ChangePinModel.error ? ResultView.Type.IsError : ResultView.Type.IsSuccess - supportButtonsVisible: ChangePinModel.errorIsMasked + icon: ChangePinModel.error ? ChangePinModel.statusCodeImage.arg(Style.currentTheme.name) : "qrc:///images/workflow_success_changepin_%1.svg".arg(Style.currentTheme.name) + mailButtonVisible: ChangePinModel.errorIsMasked 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 17155e4e0..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,27 +94,28 @@ 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 onClicked: pop() } + + onAbortCurrentWorkflow: ChangePinModel.cancelWorkflow() } } Component { id: pinUnknownView + PasswordInfoView { infoContent: PasswordInfoData { contentType: PasswordInfoContent.Type.NO_PIN @@ -99,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 d2ea56bdb..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("6-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("5-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 22e9f8e5e..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,29 +201,29 @@ 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. - return qsTr("Start the pairing on your smartphone and enter the pairing code shown there in order to use your smartphone as a card reader (SaC)."); + return qsTr("Enter the pairing code shown on your smartphone."); } //: 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 f96c4dd49..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,35 +30,37 @@ 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" @@ -68,15 +69,15 @@ Item { } 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" 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 0c8a8f26a..6dbd7aaa8 100644 --- a/resources/qml/Governikus/EnterPasswordView/+mobile/EnterPasswordView.qml +++ b/resources/qml/Governikus/EnterPasswordView/+mobile/EnterPasswordView.qml @@ -1,301 +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.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.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 @@ -305,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 @@ -328,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 e8a6dab38..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,16 +38,22 @@ 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" @@ -61,13 +63,17 @@ GridLayout { } 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 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 749f1d1f4..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,21 +40,29 @@ SectionPage { } } + Connections { + function onActivate() { + logView.highlightScrollbar(); + } + } LogFilterModel { id: filterModel + } ColumnLayout { anchors.fill: parent - spacing: filterButton.filter ? Constants.text_spacing : 0 + spacing: 0 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,89 +85,94 @@ 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 } } } - TitledSeparator { - Layout.preferredWidth: parent.width - contentMarginTop: 0 - - //: LABEL ANDROID IOS - title: qsTr("Filter") - visible: filterButton.filter - } - GText { - Layout.leftMargin: Constants.component_spacing - - //: LABEL ANDROID IOS - text: qsTr("Select level:") - textStyle: Style.text.normal_accent - visible: filterButton.filter - } - GridLayout { + GFlickableColumnLayout { + Layout.fillHeight: true Layout.fillWidth: true - Layout.leftMargin: Constants.component_spacing - columnSpacing: Constants.groupbox_spacing - columns: (width + columnSpacing) / (levelRepeater.maxItemWidth + columnSpacing) - rowSpacing: Constants.groupbox_spacing + clip: true + spacing: Constants.text_spacing visible: filterButton.filter - GRepeater { - id: levelRepeater - model: filterModel.levels + GOptionsContainer { + Layout.fillWidth: true + containerPadding: Constants.pane_padding + containerSpacing: Constants.groupbox_spacing + //: LABEL ANDROID IOS + title: qsTr("Filter") + + 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 - delegate: GCheckBox { - Layout.fillWidth: true - checked: filterModel.selectedLevels.indexOf(text) !== -1 - text: modelData + model: filterModel.levels - onToggled: filterModel.configureLevel(text, checked) + delegate: GCheckBox { + checked: filterModel.selectedLevels.indexOf(text) !== -1 + text: modelData + width: levelRepeater.maxItemWidth + + onCheckedChanged: filterModel.configureLevel(text, checked) + } + } } - } - } - GText { - Layout.leftMargin: Constants.component_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 - //: LABEL ANDROID IOS - text: qsTr("Select category:") - textStyle: Style.text.normal_accent - visible: filterButton.filter - } - GridLayout { - Layout.fillWidth: true - Layout.leftMargin: Constants.component_spacing - columnSpacing: Constants.groupbox_spacing - columns: (width + columnSpacing) / (categoryRepeater.maxItemWidth + columnSpacing) - rowSpacing: Constants.groupbox_spacing - visible: filterButton.filter + GRepeater { + id: categoryRepeater - GRepeater { - id: categoryRepeater - model: filterModel.categories + model: filterModel.categories - delegate: GCheckBox { - Layout.fillWidth: true - checked: filterModel.selectedCategories.indexOf(text) !== -1 - text: modelData + delegate: GCheckBox { + checked: filterModel.selectedCategories.indexOf(text) !== -1 + text: modelData + width: categoryRepeater.maxItemWidth - onToggled: filterModel.configureCategory(text, checked) + onCheckedChanged: filterModel.configureCategory(text, checked) + } + } } } } GListView { id: logView + Layout.fillHeight: true Layout.fillWidth: true clip: true model: filterModel + visible: !filterButton.filter delegate: ListItem { readonly property bool isLastItem: index === ListView.view.count - 1 @@ -191,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..354ecd2d0 100644 --- a/resources/qml/Governikus/Global/+desktop/GPane.qml +++ b/resources/qml/Governikus/Global/+desktop/GPane.qml @@ -1,61 +1,66 @@ /** * 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 + property int contentPadding: Constants.pane_padding 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 Accessible.focusable: title !== "" Accessible.name: title Accessible.role: Accessible.Grouping + Layout.maximumHeight: containerCol.Layout.maximumHeight activeFocusOnTab: title !== "" implicitHeight: containerCol.implicitHeight implicitWidth: containerCol.implicitWidth - GPaneBackground { - anchors.fill: parent + layer { + enabled: GraphicsInfo.api !== GraphicsInfo.Software && drawShadow + + effect: GDropShadow { + } } - Column { + ColumnLayout { id: containerCol - anchors.left: parent.left - anchors.leftMargin: Constants.pane_padding - anchors.right: parent.right - anchors.rightMargin: Constants.pane_padding - bottomPadding: Constants.pane_padding - spacing: Constants.pane_spacing - topPadding: Constants.pane_padding + + anchors.fill: parent + spacing: Constants.text_spacing GText { id: titleText + + Layout.leftMargin: Constants.pane_padding + Layout.rightMargin: Constants.pane_padding + Layout.topMargin: Constants.pane_padding elide: Text.ElideRight maximumLineCount: 1 - textStyle: Style.text.header_accent - width: Math.min(parent.width, implicitWidth) + textStyle: Style.text.subline + visible: text !== "" FocusFrame { scope: root } } - Column { + ColumnLayout { id: paneContent + + Layout.bottomMargin: root.contentPadding + Layout.leftMargin: root.contentPadding + Layout.rightMargin: root.contentPadding + Layout.topMargin: titleText.visible ? 0 : root.contentPadding 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 4081d8dcb..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 @@ -18,7 +18,7 @@ MouseArea { enabled: visible preventStealing: enabled - onPositionChanged: { + onPositionChanged: mouse => { let currentVelocity = mouse.x - previousPosX; velocity = (velocity + currentVelocity) / 2.0; previousPosX = mouse.x; @@ -33,7 +33,7 @@ MouseArea { mouse.accepted = false; } } - onReleased: { + onReleased: mouse => { let swipeDistance = mouse.x - startPosX; if (swipeDistance > minSwipeDistance && velocity > minVelocity) { backGestureTriggered(); 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 8fd841f51..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: text.text - property alias textStyle: text.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: text - 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 8a91062d2..5a9b185eb 100644 --- a/resources/qml/Governikus/Global/Utils.qml +++ b/resources/qml/Governikus/Global/Utils.qml @@ -2,37 +2,31 @@ * Copyright (c) 2019-2023 Governikus GmbH & Co. KG, Germany */ pragma Singleton -import QtQuick 2.15 -import Governikus.Type.ApplicationModel 1.0 +import QtQuick +import Governikus.Type.ApplicationModel +import Governikus.Type.SettingsModel QtObject { - function escapeHtml(str) { - return String(str).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); + 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 isSameDate(one, another) { - return one.getFullYear() === another.getFullYear() && one.getMonth() === another.getMonth() && one.getDate() === another.getDate(); + function isSameDate(pOne, pAnother) { + return pOne.getFullYear() === pAnother.getFullYear() && pOne.getMonth() === pAnother.getMonth() && pOne.getDate() === pAnother.getDate(); } - function isThisWeek(date) { - var monday = new Date; + function isThisWeek(pDate) { + let monday = new Date; monday.setDate(monday.getDate() - monday.getDay()); - date.setDate(date.getDate() - date.getDay()); - return isSameDate(monday, date); + pDate.setDate(pDate.getDate() - pDate.getDay()); + return isSameDate(monday, pDate); } - function isToday(date) { - var today = new Date; - return isSameDate(today, date); + function isToday(pDate) { + let today = new Date; + return isSameDate(today, pDate); } - function isYesterday(date) { - var yesterday = new Date; + function isYesterday(pDate) { + let yesterday = new Date; yesterday.setDate(yesterday.getDate() - 1); - return isSameDate(yesterday, date); + return isSameDate(yesterday, pDate); } function scrollPageDown(pFlickable) { if (pFlickable.height >= pFlickable.contentHeight) { 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 1ea38ea42..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.isToday(model.dateTime) ? qsTr("today") : Utils.isYesterday(model.dateTime) ? qsTr("yesterday") : Utils.isThisWeek(model.dateTime) ? model.dateTime.toLocaleString(Qt.locale(SettingsModel.language), "dddd") : model.dateTime.toLocaleString(Qt.locale(), qsTr("dd.MM.yyyy"))) : "") - 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 fdc0ea04c..000000000 --- a/resources/qml/Governikus/HistoryView/+desktop/HistoryViewDetails.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 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 ""; - } - 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 f44c84cb9..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 - - Accessible.description: qsTr("Click to view details of history entry.") - //: LABEL ANDROID IOS - footerText: historyModelItem.purpose !== "" ? historyModelItem.purpose : qsTr("Tap for more details") - //: LABEL ANDROID IOS - headerText: (Utils.isToday(dateTime) ? qsTr("today") : Utils.isYesterday(dateTime) ? qsTr("yesterday") : Utils.isThisWeek(dateTime) ? dateTime.toLocaleString(Qt.locale(SettingsModel.language), "dddd") : dateTime.toLocaleString(Qt.locale(), qsTr("dd.MM.yyyy"))) - 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 99a1b0fa1..000000000 --- a/resources/qml/Governikus/HistoryView/+mobile/HistoryViewDetails.qml +++ /dev/null @@ -1,111 +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 ""; - } - 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 144dfbbbe..2f9f74662 100644 --- a/resources/qml/Governikus/Navigation/+mobile/NavigationView.qml +++ b/resources/qml/Governikus/Navigation/+mobile/NavigationView.qml @@ -1,89 +1,89 @@ /** * 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("Remote") - image: "qrc:///images/mobile/platform_specific_phone.svg" + desc: QT_TR_NOOP("Card reader") + image: "qrc:///images/mobile/phone_card_reader.svg" module: UiModule.REMOTE_SERVICE } 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 b2abf8ca7..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,16 +18,18 @@ 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 readonly property string title: infoContent.title + signal abortCurrentWorkflow signal close titleBarAction: TitleBarAction { id: titleBarAction + rootEnabled: ApplicationModel.currentWorkflow === ApplicationModel.WORKFLOW_NONE showHelp: false showSettings: false @@ -41,106 +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: 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 f3558ac5e..37c781978 100644 --- a/resources/qml/Governikus/PasswordInfoView/+mobile/PasswordInfoView.qml +++ b/resources/qml/Governikus/PasswordInfoView/+mobile/PasswordInfoView.qml @@ -1,29 +1,30 @@ /** * 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 + signal abortCurrentWorkflow signal close - sectionPageFlickable: contentItem + spacing: Constants.component_spacing title: infoContentTitle navigationAction: NavigationAction { @@ -32,87 +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: 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 be23b5548..35f375c9b 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,38 @@ 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.") + + hint: PinResetInformationModel.pinResetHint + hintButtonText: PinResetInformationModel.pinResetActionText //: LABEL ALL_PLATFORMS linkText: qsTr("What is the card PIN?") @@ -74,18 +93,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 6-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 5-digit Transport PIN. Only when you have set a 6-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.")] } ] } @@ -104,62 +151,75 @@ Item { blockTitle: qsTr("How do I choose a secure PIN?") paragraphList: [ //: INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure PIN?' paragraph 1/3 - qsTr("For your 6-digit 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."), + qsTr("For your six-digit 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 PIN?' paragraph 2/3 - qsTr("You can change your 6-digit PIN at any time and an unlimited number of times as long as you know your valid PIN."), + qsTr("You can change your six-digit PIN at any time and an unlimited number of times as long as you know your valid PIN."), //: INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure 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 + id: chooseSmartPinInfo //: LABEL ALL_PLATFORMS - linkText: qsTr("What is the Transport PIN?") + linkText: qsTr("What is the Smart-eID PIN?") + //: LABEL ALL_PLATFORMS - title: qsTr("Transport PIN information") + title: qsTr("Set up Smart-eID") contentList: [ PasswordInfoContentBlock { //: LABEL ALL_PLATFORMS - blockTitle: qsTr("What is the Transport PIN?") + blockTitle: qsTr("What is the Smart-eID PIN?") paragraphList: [ - //: INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 1/3 - qsTr("The 5-digit Transport PIN was sent to you in the PIN letter by mail after you applied for your ID card."), - //: INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 2/3 - qsTr("If you did not set a self-selected 6-digit card PIN when you picked up your ID card, you can do so using the Transport PIN."), - //: INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 3/3 - qsTr("Once you have set a card PIN, the Transport PIN loses its validity.")] + //: 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: smartphoneAsCardReaderInfo - imageType: PasswordInfoImage.SMARTPHONE_AS_CARD_READER + id: transportPinInfo + + hint: PinResetInformationModel.pinResetHintTransportPin + hintButtonText: PinResetInformationModel.pinResetActionText //: LABEL ALL_PLATFORMS - title: qsTr("Smartphone as card reader information") + linkText: qsTr("What is the Transport PIN?") + //: LABEL ALL_PLATFORMS + title: qsTr("Transport PIN information") contentList: [ PasswordInfoContentBlock { + blockHeaderImageType: PasswordInfoImage.LETTER //: LABEL ALL_PLATFORMS - blockTitle: qsTr("Smartphone as card reader information") + blockTitle: qsTr("What is the Transport PIN?") 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.")] + //: INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 1/3 + qsTr("The five-digit Transport PIN was sent to you in the PIN letter by mail after you applied for your ID card."), + //: INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 2/3 + qsTr("If you did not set a self-selected six-digit card PIN when you picked up your ID card, you can do so using the Transport PIN."), + //: INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 3/3 + qsTr("Once you have set a card PIN, the Transport PIN loses its validity.")] } ] } 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,11 +228,12 @@ Item { contentList: [ PasswordInfoContentBlock { + blockHeaderImageType: PasswordInfoImage.LETTER_PUK //: LABEL ALL_PLATFORMS blockTitle: qsTr("Where do I find the PUK?") paragraphList: [ //: INFO ALL_PLATFORMS Answer to the question 'Where do I find the PUK?' - qsTr("The PUK is a 10-digit number that you can find in the PIN letter that was sent to you by mail after you applied for your ID card.")] + qsTr("The PUK is a ten-digit number that you can find in the PIN letter that was sent to you by mail after you applied for your ID card.")] }, PasswordInfoContentBlock { //: LABEL ALL_PLATFORMS @@ -192,7 +253,6 @@ Item { } PasswordInfoContent { id: canInfo - imageType: PasswordInfoImage.CAN //: LABEL ALL_PLATFORMS linkText: qsTr("Why is the CAN required?") @@ -201,6 +261,7 @@ Item { contentList: [ PasswordInfoContentBlock { + blockHeaderImageType: PasswordInfoImage.CAN //: LABEL ALL_PLATFORMS blockTitle: qsTr("When is the card access number (CAN) required?") paragraphList: [ @@ -219,19 +280,22 @@ Item { blockTitle: qsTr("Where can I find the CAN?") paragraphList: [ //: INFO ALL_PLATFORMS Answer to the question 'Where can I find the CAN?' - qsTr("The CAN is a 6-digit number that can be found on the bottom right of the front of the ID card.")] + qsTr("The CAN is a six-digit number that can be found on the bottom right of the front of the ID card.")] } ] } PasswordInfoContent { id: canAllowedInfo - imageType: PasswordInfoImage.CAN + //: LABEL ALL_PLATFORMS + linkText: qsTr("Why is the CAN required?") //: LABEL ALL_PLATFORMS title: qsTr("CAN information") contentList: [ PasswordInfoContentBlock { + blockHeaderImageType: PasswordInfoImage.CAN + //: LABEL ALL_PLATFORMS blockTitle: qsTr("CAN information") paragraphList: [ @@ -252,31 +316,42 @@ 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 - qsTr("Your ID card comes with a 5-digit 'Transport PIN' which you need to replace with a 6-digit PIN that you choose yourself.")] + //: 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 { blockHeaderImageType: PasswordInfoImage.Type.LETTER //: LABEL ALL_PLATFORMS - blockTitle: qsTr("5-digit Transport PIN") + blockTitle: qsTr("Five-digit Transport PIN") paragraphList: [ - //: INFO ALL_PLATFORMS Description text explaining the PINs 2/6 - qsTr("The 5-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 5-digit PIN with a 6-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("6-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 5-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 6-digit PIN at any time in AusweisApp2.")] + blockTitle: qsTr("Six-digit PIN") + 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)] } ] } @@ -300,20 +375,22 @@ 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 + + hint: PinResetInformationModel.pinResetHintNoPin + 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: [ //: INFO ALL_PLATFORMS - qsTr("You have not yet set a 6-digit card PIN and cannot find the PIN letter with the Transport PIN?"), + qsTr("You have not yet set a six-digit card PIN and cannot find the PIN letter with the Transport PIN?"), //: INFO ALL_PLATFORMS qsTr("You set a card PIN when picking up your ID card or later by yourself, but you can no longer remember it?")] } 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 66ec310be..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.isToday(dateTime) ? qsTr("today") : Utils.isYesterday(dateTime) ? qsTr("yesterday") : Utils.isThisWeek(dateTime) ? dateTime.toLocaleString(Qt.locale(SettingsModel.language), "dddd") : dateTime.toLocaleString(Qt.locale(), qsTr("dd.MM.yyyy"))) - 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 418c62d5f..000000000 --- a/resources/qml/Governikus/Provider/+mobile/+tablet/ProviderDetailHistoryItem.qml +++ /dev/null @@ -1,40 +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") - - //: LABEL ANDROID IOS - headerText: (Utils.isToday(dateTime) ? qsTr("today") : Utils.isYesterday(dateTime) ? qsTr("yesterday") : Utils.isThisWeek(dateTime) ? dateTime.toLocaleString(Qt.locale(SettingsModel.language), "dddd") : dateTime.toLocaleString(Qt.locale(), qsTr("dd.MM.yyyy"))) - 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 1693ad2db..c80fa867b 100644 --- a/resources/qml/Governikus/RemoteServiceView/+mobile/DevicesListDelegate.qml +++ b/resources/qml/Governikus/RemoteServiceView/+mobile/DevicesListDelegate.qml @@ -1,27 +1,32 @@ /** * 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 alias highlightTitle: titleText.font.bold property alias linkInactive: linkQualityItem.inactive property alias linkQuality: linkQualityItem.percent + property alias linkQualityVisible: linkQualityItem.visible property alias title: titleText.text Accessible.name: qsTr("Device %1. %2.").arg(title).arg(description) Accessible.role: Accessible.ListItem - height: content.implicitHeight - width: content.implicitWidth + implicitHeight: content.implicitHeight + implicitWidth: content.implicitWidth Accessible.onPressAction: clicked(null) RowLayout { id: content + anchors.fill: parent spacing: Constants.groupbox_spacing @@ -31,23 +36,27 @@ MouseArea { GText { id: titleText + Accessible.ignored: true - Layout.fillWidth: true elide: Text.ElideRight maximumLineCount: 1 - textStyle: 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 9b4363820..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 @@ -13,8 +13,7 @@ Column { GText { horizontalAlignment: Text.AlignHCenter //: INFO IOS Let user know to check the application settings for local network permission - text: qsTr("To be able to use your smartphone as card reader (SaC), please make sure that access to the local network is allowed.") - textStyle: Style.text.normal_secondary + text: qsTr("Ensure that access to the local network is allowed in your settings.") 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 new file mode 100644 index 000000000..06578fbce --- /dev/null +++ b/resources/qml/Governikus/RemoteServiceView/+mobile/PairingCodeInfoView.qml @@ -0,0 +1,73 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Governikus.Global +import Governikus.TitleBar +import Governikus.Style +import Governikus.View +import Governikus.Type.ApplicationModel + +FlickableSectionPage { + property alias text: descriptionContainer.title + + signal navActionClicked + + hiddenNavbarPadding: true + spacing: Constants.component_spacing + + //: LABEL ANDROID IOS + title: qsTr("Pairing Information") + + navigationAction: NavigationAction { + id: navAction + + action: NavigationAction.Action.Back + + 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.name: ApplicationModel.stripHtmlTags(text) + Layout.alignment: Qt.AlignTop + text: (index + 1) + ". " + modelData + } + } + } + } + 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 new file mode 100644 index 000000000..ef2f177e4 --- /dev/null +++ b/resources/qml/Governikus/RemoteServiceView/+mobile/PairingProcessInfo.qml @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ +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("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. + qsTr("On that device choose %1Card reader%2 and then %1Pair device%2 resp. %1Pair new device%2.").arg("").arg(""), + //: 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.")] + + 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 b6bd1b3d9..965dfefb6 100644 --- a/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceView.qml +++ b/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceView.qml @@ -1,40 +1,68 @@ /** * 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("Remote service") + title: qsTr("Card reader") navigationAction: NavigationAction { action: RemoteServiceModel.running ? NavigationAction.Action.Cancel : NavigationAction.Action.None 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() { setLockedAndHidden(RemoteServiceModel.running); - pairingButton.didPairInSaKSession = false; - } - function onFirePairingCompleted() { - pairingButton.didPairInSaKSession = true; } - //: ERROR ANDROID IOS An error occurred while pairing the device. function onFirePairingFailed() { + //: ERROR ANDROID IOS An error occurred while pairing the device. ApplicationModel.showFeedback(qsTr("Pairing failed. Please start a new pairing process on your other device and enter the shown pairing code.")); } @@ -42,202 +70,288 @@ 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 - PropertyChanges { - target: pairingCode - visible: true + 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 + + 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.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 + + readonly property string currentPin: RemoteServiceModel.psk.toString() + + 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() + } } - PropertyChanges { - target: wifiInfo - visible: true + } + } + } + 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 + + spacing: Constants.text_spacing + width: parent.width + + Repeater { + id: knownDeviceList + + model: RemoteServiceModel.allDevices + + delegate: DevicesListDelegate { + highlightTitle: isLastAddedDevice + linkQualityVisible: false + title: remoteDeviceName } + } + GButton { + //: LABEL ANDROID IOS + Accessible.name: qsTr("Start pairing of a new device") + Layout.alignment: Qt.AlignLeft + Layout.topMargin: knownDevices.spacing + background: null + icon.source: "qrc:///images/material_add.svg" + padding: 0 + //: LABEL ANDROID IOS + text: qsTr("Pair new device") + textStyle: Style.text.link + tintIcon: true + visible: !RemoteServiceModel.isPairing && !RemoteServiceModel.running + + onClicked: RemoteServiceModel.setRunning(!RemoteServiceModel.running, !RemoteServiceModel.isPairing) + } + } + } + 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 + 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: networkPermissionText - visible: RemoteServiceModel.requiresLocalNetworkPermission + target: pairConnectButton + //: LABEL ANDROID IOS + text: qsTr("Enable WiFi") + + onClicked: ApplicationModel.enableWifi() } }, State { - name: "UNCONNECTED" - when: RemoteServiceModel.running && !RemoteServiceModel.connectedToPairedDevice + when: RemoteServiceModel.canEnableNfc PropertyChanges { - target: pairingCode - visible: false - } - PropertyChanges { - target: wifiInfo - visible: true - } - PropertyChanges { - target: networkPermissionText - visible: RemoteServiceModel.requiresLocalNetworkPermission + target: pairConnectButton + //: LABEL ANDROID IOS + text: qsTr("Enable NFC") + + onClicked: ApplicationModel.showSettings(ApplicationModel.SETTING_NFC) } }, State { - name: "CONNECTED_OR_STOPPED" - when: !RemoteServiceModel.running || (RemoteServiceModel.running && RemoteServiceModel.connectedToPairedDevice) + when: RemoteServiceModel.runnable && knownDeviceList.count > 0 && !RemoteServiceModel.isPairing && !RemoteServiceModel.running PropertyChanges { - target: pairingCode - visible: false + target: pairConnectButton + //: LABEL ANDROID IOS + text: qsTr("Allow connection") + + onClicked: RemoteServiceModel.setRunning(true) } + }, + State { + when: RemoteServiceModel.runnable && knownDeviceList.count < 1 && !RemoteServiceModel.isPairing + PropertyChanges { - target: wifiInfo - visible: false + target: pairConnectButton + //: LABEL ANDROID IOS + text: qsTr("Pair device") + + onClicked: RemoteServiceModel.setRunning(true, true) } + }, + State { + when: RemoteServiceModel.isPairing + PropertyChanges { - target: networkPermissionText - visible: false + target: pairConnectButton + //: LABEL ANDROID IOS + text: qsTr("Cancel pairing") + visible: true + + onClicked: RemoteServiceModel.setRunning(false, false) } } ] - Image { - 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 - } - 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 || RemoteServiceModel.running ? qsTr("Waiting for connection") : - //: LABEL ANDROID IOS - qsTr("Remote service ready") - textStyle: Style.text.header_accent - } - GText { - readonly property string currentPin: RemoteServiceModel.psk - //: INFO ANDROID IOS - readonly property string enterCodeString: qsTr("Enter the code %1 in the %2 on your other device to use your smartphone as a card reader (SaC).") - - Accessible.name: RemoteServiceModel.isPairing ? enterCodeString.arg(currentPin.split("").join(" ")).arg(Qt.application.name) : text - Layout.fillWidth: true - Layout.topMargin: Constants.text_spacing - horizontalAlignment: Text.AlignHCenter - text: !RemoteServiceModel.runnable ? RemoteServiceModel.errorMessage : RemoteServiceModel.running && RemoteServiceModel.connectedToPairedDevice ? RemoteServiceModel.connectionInfo : RemoteServiceModel.isPairing ? enterCodeString.arg(currentPin).arg(Qt.application.name) : - //: INFO ANDROID IOS - RemoteServiceModel.running ? qsTr("Waiting for connection from a paired device...") : - //: INFO ANDROID IOS - qsTr("Start the remote access in order to make this smartphone visible and use it as a card reader (SaC).\n\nIf you have not already paired a device, start the pairing now to set up this smartphone as a card reader.") - textStyle: RemoteServiceModel.runnable ? Style.text.normal_secondary : Style.text.normal_warning - } - GText { - id: pairingCode - - readonly property string currentPin: RemoteServiceModel.psk.toString() - - Accessible.ignored: true - Layout.fillWidth: true - Layout.topMargin: Constants.component_spacing - horizontalAlignment: Text.AlignHCenter - - //: LABEL ANDROID IOS - text: qsTr("Pairing code: %1").arg(RemoteServiceModel.isPairing ? currentPin : "0000") - textStyle: Style.text.title_accent - visible: false - } - GSpacer { - Layout.fillHeight: true - } - RowLayout { - id: wifiInfo - Layout.fillWidth: true - Layout.topMargin: Constants.component_spacing - spacing: Constants.text_spacing - - TintableIcon { - source: "qrc:/images/info.svg" - sourceSize.width: Style.dimens.small_icon_size - tintColor: Style.text.normal_secondary.textColor - } - GText { - Layout.fillWidth: true - - //: INFO ANDROID IOS The remote service is active. Hint that both devices need to be connected to the same network. - text: qsTr("Both of your devices have to be connected to the same WiFi.") - textStyle: Style.text.normal_secondary - } - } - LocalNetworkInfo { - id: networkPermissionText - Layout.bottomMargin: Constants.text_spacing - Layout.fillWidth: true - Layout.topMargin: Constants.component_spacing - visible: false - } - GButton { - id: startButton - - readonly property int minButtonWidth: Math.max(Math.max(pairingButton.implicitWidth, startButton.implicitWidth), parent.width / 2) - - Layout.alignment: Qt.AlignHCenter - Layout.minimumWidth: startButton.minButtonWidth - Layout.topMargin: Constants.component_spacing - buttonColor: (!ApplicationModel.wifiEnabled || RemoteServiceModel.canEnableNfc) ? Style.color.button : (RemoteServiceModel.running ? Constants.red : Constants.green) - enabled: (RemoteServiceModel.canEnableNfc || RemoteServiceModel.runnable || RemoteServiceModel.running || !ApplicationModel.wifiEnabled) && !RemoteServiceModel.isStarting - //: LABEL ANDROID IOS - text: !ApplicationModel.wifiEnabled ? qsTr("Enable WiFi") : - //: LABEL ANDROID IOS - RemoteServiceModel.canEnableNfc ? qsTr("Enable NFC") : - //: LABEL ANDROID IOS - RemoteServiceModel.running ? qsTr("Stop remote service") : - //: LABEL ANDROID IOS - qsTr("Start remote service") - - onClicked: { - if (!ApplicationModel.wifiEnabled) { - ApplicationModel.enableWifi(); - } else if (RemoteServiceModel.canEnableNfc) { - ApplicationModel.showSettings(ApplicationModel.SETTING_NFC); - } else { - RemoteServiceModel.setRunning(!RemoteServiceModel.running); - } - } - } - GButton { - id: pairingButton - - property bool didPairInSaKSession: false - - Layout.alignment: Qt.AlignHCenter - Layout.minimumWidth: startButton.minButtonWidth - Layout.topMargin: Constants.component_spacing - enabled: RemoteServiceModel.runnable && !RemoteServiceModel.connectedToPairedDevice && !RemoteServiceModel.isStarting && !didPairInSaKSession - - // Set opacity instead of visibility to hide button so it keeps its size - opacity: RemoteServiceModel.connectedToPairedDevice || didPairInSaKSession ? 0 : 1 - text: RemoteServiceModel.isPairing ? - //: LABEL ANDROID IOS - qsTr("Stop pairing") : - //: LABEL ANDROID IOS - qsTr("Start pairing") - visible: RemoteServiceModel.runnable - - 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 a26871a0c..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,40 +28,55 @@ 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 - } - GText { - Accessible.name: text - Accessible.role: Accessible.StaticText + ListView { + id: availablePairedDeviceList - //: LABEL ANDROID IOS - text: qsTr("No device is paired.") - textStyle: Style.text.normal_secondary - visible: !knownDeviceList.visible + height: childrenRect.height + interactive: false + model: RemoteServiceModel.availablePairedDevices + spacing: Constants.component_spacing width: parent.width + + delegate: DevicesListDelegate { + //: LABEL ANDROID IOS + description: qsTr("Available") + linkInactive: !isNetworkVisible + linkQuality: linkQualityInPercent + title: remoteDeviceName + width: availablePairedDeviceList.width + + onClicked: { + deleteDevicePopup.deviceId = deviceId; + deleteDevicePopup.deviceName = remoteDeviceName; + deleteDevicePopup.open(); + } + } } + } + GOptionsContainer { + containerPadding: Constants.pane_padding + //: LABEL ANDROID IOS + title: qsTr("Last connected") + visible: unavailablePairedDeviceList.count > 0 + width: parent.usableWidth + ListView { - id: knownDeviceList + id: unavailablePairedDeviceList + height: childrenRect.height interactive: false - model: RemoteServiceModel.knownDevices + model: RemoteServiceModel.unavailablePairedDevices spacing: Constants.component_spacing - visible: count > 0 width: parent.width delegate: DevicesListDelegate { @@ -68,7 +85,7 @@ Item { linkInactive: !isNetworkVisible linkQuality: linkQualityInPercent title: remoteDeviceName - width: knownDeviceList.width + width: unavailablePairedDeviceList.width onClicked: { deleteDevicePopup.deviceId = deviceId; @@ -94,27 +111,43 @@ 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 + GListView { + id: searchDeviceList - //: LABEL ANDROID IOS - title: qsTr("Available devices") + height: childrenRect.height + model: RemoteServiceModel.availableDevicesInPairingMode + spacing: Constants.component_spacing + visible: ApplicationModel.wifiEnabled && count > 0 width: parent.width + + delegate: DevicesListDelegate { + //: LABEL ANDROID IOS + description: qsTr("Click to pair") + linkQuality: linkQualityInPercent + title: remoteDeviceName + (isSupported ? "" : (" (" + remoteDeviceStatus + ")")) + width: searchDeviceList.width + + onClicked: { + if (isSupported && RemoteServiceModel.rememberServer(deviceId)) { + d.oldLockedAndHiddenStatus = getLockedAndHidden(); + setLockedAndHidden(); + push(enterPinView); + } + } + } } GText { - text: ApplicationModel.wifiEnabled ? - //: INFO ANDROID IOS No SaC was found on the network, both devices need to be connected to the same WiFi network. - qsTr("No unpaired smartphone as card reader (SaC) available. Please make sure that the smartphone as card reader (SaC) functionality in AusweisApp2 on your other device is activated and that both devices are connected to the same WiFi.") : //: INFO ANDROID IOS Wifi is not enabled and no new devices can be paired. - qsTr("Please connect your WiFi to use another smartphone as card reader (SaC).") - textStyle: ApplicationModel.wifiEnabled ? Style.text.normal_secondary : Style.text.normal_warning - visible: !searchDeviceList.visible + text: qsTr("Please connect your WiFi to use another smartphone as card reader (SaC).") + textStyle: Style.text.normal_warning + visible: !ApplicationModel.wifiEnabled width: parent.width } GButton { @@ -131,66 +164,25 @@ Item { visible: RemoteServiceModel.requiresLocalNetworkPermission && !RemoteServiceModel.remoteReaderVisible width: parent.width } - ListView { - id: searchDeviceList - height: childrenRect.height - interactive: false - model: RemoteServiceModel.availableRemoteDevices - spacing: Constants.component_spacing - visible: ApplicationModel.wifiEnabled && count > 0 + PairingProcessInfo { + visible: !searchDeviceList.visible && ApplicationModel.wifiEnabled + width: parent.width + } + RemoteServiceWifiInfo { + visible: !searchDeviceList.visible && ApplicationModel.wifiEnabled width: parent.width - - delegate: DevicesListDelegate { - //: LABEL ANDROID IOS - description: qsTr("Click to pair") - linkQuality: linkQualityInPercent - title: remoteDeviceName + (isSupported ? "" : (" (" + remoteDeviceStatus + ")")) - width: searchDeviceList.width - - onClicked: { - if (isSupported && RemoteServiceModel.rememberServer(deviceId)) { - informationPairingPopup.open(); - } - } - } } - } - } - ConfirmationPopup { - id: informationPairingPopup - style: ConfirmationPopup.PopupStyle.OkButton - //: INFO ANDROID IOS Information dialog that requests the user to start the pairing mode on the smartphone. - text: qsTr("Start the pairing mode on your smartphone if you haven't done it already.") - //: INFO ANDROID IOS - title: qsTr("Pairing mode") - - onConfirmed: { - d.oldLockedAndHiddenStatus = getLockedAndHidden(); - setLockedAndHidden(); - push(enterPinView); - } - } - 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") @@ -202,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 new file mode 100644 index 000000000..1add943ea --- /dev/null +++ b/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceWifiInfo.qml @@ -0,0 +1,25 @@ +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.medium_icon_size + tintColor: infoText.color + } + GText { + 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.") + } + 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 005781765..d30fbbd52 100644 --- a/resources/qml/Governikus/RemoteServiceView/RemoteServiceController.qml +++ b/resources/qml/Governikus/RemoteServiceView/RemoteServiceController.qml @@ -1,71 +1,174 @@ /** * 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.PasswordInfoView 1.0 -import Governikus.TitleBar 1.0 -import Governikus.View 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.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(); + } else if (!RemoteServiceModel.hasCard && !workflowShown) { + push(generalWorkflow); + } + } function requestInput(pState) { if (RemoteServiceModel.isBasicReader && RemoteServiceModel.pinPadModeOn()) { - push(enterPinView); + push(enterPinView, { + "passwordType": NumberModel.passwordType, + "inputError": NumberModel.inputError + }); } else { RemoteServiceModel.continueWorkflow(); } } Connections { - function onFireCurrentStateChanged() { - switch (RemoteServiceModel.currentState) { - case "Initial": - break; - case "StateStartIfdService": - setLockedAndHidden(); - RemoteServiceModel.continueWorkflow(); - break; - case "StateEnterPacePasswordIfd": - requestInput(); - break; - case "StateEnterNewPacePinIfd": - requestInput(); - break; - case "FinalState": - RemoteServiceModel.continueWorkflow(); - setLockedAndHidden(false); - break; - default: - RemoteServiceModel.continueWorkflow(); + function onFireConnectedChanged() { + if (RemoteServiceModel.connectedToPairedDevice && !workflowShown) { + requestCard(); + RemoteServiceModel.setInitialPluginType(); + } else if (!RemoteServiceModel.connectedToPairedDevice && (workflowShown || enterPasswordShown || editRightsShown)) { + pop(); + } + } + function onFireHasCardChanged() { + if (!RemoteServiceModel.connectedToPairedDevice) { + return; + } + 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) + //: LABEL ANDROID IOS + title: qsTr("Card reader") + workflowModel: RemoteServiceModel + + navigationAction: NavigationAction { + action: NavigationAction.Action.Cancel + + onClicked: { + pop(); + RemoteServiceModel.cancelPasswordRequest(); + } + } + + onRightsAccepted: { + ChatModel.transferAccessRights(); + pop(); + requestInput(); + } + } + } + Component { + id: generalWorkflow + + GeneralWorkflow { + smartEidUsed: RemoteServiceModel.readerPlugInType === ReaderPlugIn.SMART + workflowModel: RemoteServiceModel + //: LABEL ANDROID IOS + workflowTitle: qsTr("Remote service") + + navigationAction: NavigationAction { + action: NavigationAction.Action.Cancel + + onClicked: { + RemoteServiceModel.setRunning(false); + } + } + } + } PasswordInfoData { id: infoData + contentType: fromPasswordType(NumberModel.passwordType) } Component { id: passwordInfoView + PasswordInfoView { infoContent: infoData + onAbortCurrentWorkflow: { + popAll(); + RemoteServiceModel.cancelPasswordRequest(); + } onClose: pop() } } Component { id: enterPinView + EnterPasswordView { id: passwordView + enableTransportPinLink: RemoteServiceModel.enableTransportPinLink moreInformationText: infoData.linkText + smartEidUsed: isSmartWorkflow + //: LABEL ANDROID IOS + title: qsTr("Card reader") navigationAction: NavigationAction { action: NavigationAction.Action.Cancel @@ -78,10 +181,29 @@ Controller { onChangePinLength: { RemoteServiceModel.changePinLength(); + passwordView.passwordType = NumberModel.passwordType; } - onPasswordEntered: { - pop(); - 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 a419e9d8e..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("Configure remote service") + 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/RemoteServiceView/qmldir b/resources/qml/Governikus/RemoteServiceView/qmldir index a4aefd146..a17751a56 100644 --- a/resources/qml/Governikus/RemoteServiceView/qmldir +++ b/resources/qml/Governikus/RemoteServiceView/qmldir @@ -1,8 +1,11 @@ module RemoteServiceView internal DevicesListDelegate DevicesListDelegate.qml +internal PairingCodeInfoView PairingCodeInfoView.qml +internal PairingProcessInfo PairingProcessInfo.qml internal RemoteServiceController RemoteServiceController.qml internal RemoteServiceViewRemote RemoteServiceViewRemote.qml +internal RemoteServiceWifiInfo RemoteServiceWifiInfo.qml LinkQuality 1.0 LinkQuality.qml LocalNetworkInfo 1.0 LocalNetworkInfo.qml diff --git a/resources/qml/Governikus/ResultView/+desktop/ResultView.qml b/resources/qml/Governikus/ResultView/+desktop/ResultView.qml index b724585ba..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 popupText: detailedResultPopup.text - property alias popupTitle: detailedResultPopup.title - property int resultType: ResultView.Type.IsSuccess - property alias supportButtonsVisible: supportButtonsLayout.visible + property alias icon: customIcon.source + property alias mailButtonVisible: mailButton.visible + 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,34 +73,34 @@ 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 { } } RowLayout { - id: supportButtonsLayout Layout.alignment: Qt.AlignHCenter Layout.fillWidth: true spacing: Constants.component_spacing - visible: false + visible: popupTitle !== "" || popupText !== "" GButton { + id: mailButton + icon.source: "qrc:///images/material_mail.svg" //: LABEL DESKTOP text: qsTr("Send email") tintIcon: true + visible: false 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 @@ -116,6 +113,7 @@ SectionPage { GFileDialog { id: fileDialog + defaultSuffix: "log" //: LABEL DESKTOP nameFilters: qsTr("Logfiles (*.log)") @@ -127,13 +125,19 @@ SectionPage { } } GButton { - icon.source: "qrc:/images/info.svg" + icon.source: "qrc:/images/desktop/info_white.svg" //: LABEL DESKTOP text: qsTr("See details") tintIcon: true visible: popupTitle !== "" || popupText !== "" - onClicked: detailedResultPopup.open() + onClicked: { + let popup = detailedResultPopup.createObject(baseItem, { + "text": popupText, + "title": popupTitle + }); + popup.open(); + } } } GSpacer { @@ -141,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 334cc8c8c..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,95 +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 @@ -128,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 0da8356f2..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 { @@ -110,8 +74,7 @@ SectionPage { pairingFailedView.errorMessage = pErrorMessage; d.view = ConnectSacView.SubView.PairingFailed; } - function onFirePairingSuccess(pDeviceName) { - ApplicationModel.showFeedback(qsTr("The device \"%1\" has been paired.").arg(pDeviceName)); + function onFirePairingSuccess() { root.closeView(); } @@ -125,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 63647b258..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,22 +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: { - if (!isPaired) { - return qsTr("Click to pair"); - } - return remoteDeviceStatus; - } - textStyle: Style.text.normal + + text: remoteDeviceStatus width: parent.width } } Row { + Layout.alignment: Qt.AlignVCenter Layout.preferredHeight: iconHeight spacing: Constants.component_spacing @@ -71,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 - visible: isPaired + tintColor: Style.color.control + visible: isPaired && !isPairing MouseArea { id: trashMouse + ToolTip.delay: Constants.toolTipDelay ToolTip.text: qsTr("Remove remote device") ToolTip.visible: trashMouse.containsMouse @@ -99,7 +100,7 @@ Item { MouseArea { anchors.fill: parent cursorShape: Qt.PointingHandCursor - visible: !isPaired + visible: !trashMouse.visible onClicked: pairDevice(deviceId) } diff --git a/resources/qml/Governikus/SettingsView/+desktop/RemoteReaderView.qml b/resources/qml/Governikus/SettingsView/+desktop/RemoteReaderView.qml index 57a6726d2..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.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 moreInformation signal pairDevice(string pDeviceId) signal unpairDevice(string pDeviceId) @@ -29,102 +27,134 @@ Item { } Column { id: column + anchors.fill: parent spacing: Constants.component_spacing - GText { - activeFocusOnTab: true - text: qsTr("Paired remote devices") - textStyle: Style.text.header_accent - visible: knownDevices.count > 0 + GPane { + spacing: Constants.component_spacing + //: LABEL DESKTOP + title: qsTr("Paired devices") + visible: availablePairedDevices.count > 0 width: parent.width - FocusFrame { + Repeater { + id: availablePairedDevices + + model: RemoteServiceModel.availablePairedDevices + + delegate: RemoteReaderDelegate { + 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 Repeater { - id: knownDevices - model: RemoteServiceModel.knownDevices + id: unavailablePairedDevices + + model: RemoteServiceModel.unavailablePairedDevices delegate: RemoteReaderDelegate { - height: implicitHeight + Constants.pane_padding - width: parent.width + Layout.fillWidth: true onUnpairDevice: pDeviceId => root.unpairDevice(pDeviceId) } } } - GSeparator { - visible: knownDevices.count > 0 - width: parent.width - } - GText { - activeFocusOnTab: true - text: qsTr("Available remote devices") - textStyle: Style.text.header_accent - width: parent.width + GPane { + spacing: Constants.component_spacing - FocusFrame { - } - } - GListView { - id: availableDevices - height: contentHeight - model: RemoteServiceModel.availableRemoteDevices + //: 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) - } - } - GText { - activeFocusOnTab: true - text: RemoteServiceModel.availableRemoteDevices.emptyListDescriptionString - textStyle: Style.text.normal - visible: availableDevices.count === 0 - width: parent.width + Layout.fillWidth: true + implicitHeight: contentHeight + model: RemoteServiceModel.availableDevicesInPairingMode - FocusFrame { - } - } - GSeparator { - width: parent.width - } - RowLayout { - id: hint - spacing: Constants.text_spacing - width: parent.width + delegate: RemoteReaderDelegate { + height: implicitHeight + Constants.pane_padding + width: availableDevices.width - TintableIcon { - source: "qrc:/images/info.svg" - sourceSize.height: Style.dimens.icon_size - tintColor: Style.color.accent + onPairDevice: pDeviceId => root.pairDevice(pDeviceId) + } } - GText { - id: hintText - Layout.alignment: Qt.AlignVCenter + Column { Layout.fillWidth: true - activeFocusOnTab: true - text: qsTr("Only devices that are already paired or are connected to the same WiFi network and have the remote service enabled are shown here.") - textStyle: Style.text.hint - verticalAlignment: Text.AlignBottom - wrapMode: Text.WordWrap - - FocusFrame { + 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 { + } + } + } } } - } - GButton { - //: LABEL DESKTOP - text: qsTr("More information") + GSeparator { + Layout.fillWidth: true + visible: availableDevices.count === 0 + } + RowLayout { + Layout.fillWidth: true + spacing: Constants.component_spacing + visible: availableDevices.count === 0 - onClicked: moreInformation() + 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 75517f7b5..681b72df2 100644 --- a/resources/qml/Governikus/SettingsView/+desktop/SecurityAndPrivacySettings.qml +++ b/resources/qml/Governikus/SettingsView/+desktop/SecurityAndPrivacySettings.qml @@ -1,161 +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 + GPane { + Layout.fillWidth: true + spacing: Constants.component_spacing //: LABEL DESKTOP - text: qsTr("Clear entire history") + title: qsTr("Onscreen keypad") - onClicked: confirmationPopup.open() - } - GSeparator { - Layout.fillWidth: true - } - GText { - activeFocusOnTab: true + LabeledSwitch { + checked: SettingsModel.useScreenKeyboard - //: LABEL DESKTOP - text: qsTr("Onscreen keypad") - textStyle: Style.text.header_accent + //: LABEL DESKTOP + title: qsTr("Use on screen keypad for PIN entry") - FocusFrame { + onCheckedChanged: SettingsModel.useScreenKeyboard = checked } - } - GCheckBox { - checked: SettingsModel.useScreenKeyboard - - //: LABEL DESKTOP - text: qsTr("Use on screen keypad for PIN entry") + LabeledSwitch { + checked: SettingsModel.shuffleScreenKeyboard + enabled: SettingsModel.useScreenKeyboard - onCheckedChanged: SettingsModel.useScreenKeyboard = checked - } - GCheckBox { - checked: SettingsModel.shuffleScreenKeyboard - enabled: SettingsModel.useScreenKeyboard + //: LABEL DESKTOP + title: qsTr("Shuffle digits of on screen keypad") - //: LABEL DESKTOP - text: qsTr("Shuffle keypad buttons") + onCheckedChanged: SettingsModel.shuffleScreenKeyboard = checked + } + LabeledSwitch { + checked: !SettingsModel.visualPrivacy + //: LABEL DESKTOP + description: qsTr("Visually highlight key presses on screen keypad") + enabled: SettingsModel.useScreenKeyboard - onCheckedChanged: SettingsModel.shuffleScreenKeyboard = checked - } - GCheckBox { - checked: !SettingsModel.visualPrivacy - enabled: SettingsModel.useScreenKeyboard + //: LABEL DESKTOP + title: qsTr("Button animation") - //: LABEL DESKTOP - text: qsTr("Visual feedback when pressing keypad buttons") - - onCheckedChanged: SettingsModel.visualPrivacy = !checked + onCheckedChanged: SettingsModel.visualPrivacy = !checked + } } - GSeparator { + GPane { Layout.fillWidth: true - } - 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 && SettingsModel.autoUpdateAvailable + LabeledSwitch { + checked: SettingsModel.autoUpdateCheck + enabled: !SettingsModel.autoUpdateCheckSetByAdmin - //: LABEL DESKTOP - text: qsTr("Check at program start") + //: 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 + Layout.fillWidth: true + spacing: Constants.component_spacing - GButton { - enabled: SettingsModel.autoUpdateAvailable - 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 bd7238ae6..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,19 +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 - - onMoreInformation: { - d.precedingView = d.view; - d.view = TabbedReaderView.SubView.ConnectSacView; - connectSacView.showPairingInformation(); - updateTitleBarActions(); - } onPairDevice: pDeviceId => { if (RemoteServiceModel.rememberServer(pDeviceId)) { d.view = SettingsView.SubView.ConnectSacView; @@ -114,8 +106,6 @@ SectionPage { } Component { CardReaderView { - height: Math.max(implicitHeight, tabbedPane.availableHeight) - width: parent.width } } Component { @@ -123,9 +113,6 @@ SectionPage { } } } - sectionDelegate: TabbedPaneDelegateText { - sectionName: model ? model.modelData : "" - } Component.onCompleted: { if (plugin.debugBuild) { @@ -138,11 +125,13 @@ SectionPage { Component { id: debugSettings + DebugSettings { } } Component { id: developerSettings + DeveloperSettings { } } @@ -155,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 3f7c6d40f..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 @@ -66,12 +68,6 @@ SectionPage { height: Math.max(implicitHeight, tabbedPane.availableHeight) width: parent.width - onMoreInformation: { - d.precedingView = d.view; - d.view = TabbedReaderView.SubView.ConnectSacView; - connectSacView.showPairingInformation(); - updateTitleBarActions(); - } onPairDevice: pDeviceId => { if (RemoteServiceModel.rememberServer(pDeviceId)) { d.view = TabbedReaderView.SubView.ConnectSacView; @@ -111,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 33a375429..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,215 +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.fillWidth: true + Layout.margins: Constants.component_spacing + maximumLength: Constants.maximumDeviceNameLength + text: SettingsModel.serverName + + onAccepted: saveInput() + onFocusChanged: if (!focus) + saveInput() } + } + GSeparator { + anchors.left: parent.left + anchors.leftMargin: Constants.component_spacing + anchors.right: parent.right + anchors.rightMargin: Constants.component_spacing + } + LabeledSwitch { + checked: SettingsModel.pinPadMode - 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 + //: LABEL ANDROID IOS + title: qsTr("Enter PIN on this device") + width: parent.width - onAccepted: saveInput() - onFocusChanged: if (!focus) - saveInput() + onCheckedChanged: SettingsModel.pinPadMode = checked } - } - 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.showAccessRights + enabled: SettingsModel.pinPadMode - //: LABEL ANDROID IOS - title: qsTr("PIN pad mode") - width: parent.width + //: LABEL ANDROID IOS + title: qsTr("Show requested rights on this device as well") + width: parent.width - onCheckedChanged: SettingsModel.pinPadMode = checked - } - MenuItem { - //: LABEL ANDROID IOS - description: qsTr("Configure remote service for another device") + 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("Remote card reader") - width: parent.width + //: LABEL ANDROID IOS + title: qsTr("Manage pairings") + width: parent.width - onClicked: push(remoteServiceSettings) + onClicked: push(remoteServiceSettings) - Component { - id: remoteServiceSettings - RemoteServiceSettings { - Component.onCompleted: RemoteServiceModel.detectRemoteDevices = true - Component.onDestruction: RemoteServiceModel.detectRemoteDevices = false + Component { + id: remoteServiceSettings + + 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 @@ -244,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") @@ -262,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") @@ -274,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") @@ -296,38 +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(); + } } - Column { - bottomPadding: Constants.component_spacing / 2 - leftPadding: Constants.component_spacing - rightPadding: Constants.component_spacing - topPadding: Constants.component_spacing / 2 - width: parent.width + } + GOptionsContainer { + Layout.fillWidth: true - GRadioButton { - checked: plugin.platformStyle === baseItem.platformId(text) - text: "Phone, iOS" + //: LABEL ANDROID IOS + title: qsTr("Layout style") + visible: plugin.debugBuild - onCheckedChanged: if (checked) { - plugin.applyPlatformStyle(baseItem.platformId(text)); - } - } - GRadioButton { - checked: plugin.platformStyle === baseItem.platformId(text) - text: "Phone, Android" + Column { + padding: Constants.pane_padding + width: parent.width - onCheckedChanged: if (checked) { - plugin.applyPlatformStyle(baseItem.platformId(text)); - } - } GRadioButton { checked: plugin.platformStyle === baseItem.platformId(text) - text: "Tablet, iOS" + text: "iOS" onCheckedChanged: if (checked) { plugin.applyPlatformStyle(baseItem.platformId(text)); @@ -335,27 +415,30 @@ SectionPage { } 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") @@ -366,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") @@ -380,25 +464,7 @@ 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."); - } - } } } } - navigationAction: NavigationAction { - action: topLevelPage ? NavigationAction.Action.None : NavigationAction.Action.Back - - onClicked: pop() - } } 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 82713d611..b32e741d3 100644 --- a/resources/qml/Governikus/SmartView/+mobile/PersonalizationController.qml +++ b/resources/qml/Governikus/SmartView/+mobile/PersonalizationController.qml @@ -1,27 +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.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, @@ -36,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") @@ -46,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; @@ -127,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) @@ -167,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(); @@ -175,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: { @@ -208,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: { @@ -248,8 +259,10 @@ Controller { } Component { id: smartProgress + PersonalizationProgressView { progressBarVisible: workflowProgressVisible + title: smartEidTitle workflowState: controller.workflowState onAbortWorkflow: { @@ -260,31 +273,55 @@ 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: { + ChatModel.transferAccessRights(); + PersonalizationModel.continueWorkflow(); + } } } 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 @@ -294,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) { @@ -324,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 4435138ec..0939d63c7 100644 --- a/resources/qml/Governikus/Style/+mobile/PlatformDimensions.qml +++ b/resources/qml/Governikus/Style/+mobile/PlatformDimensions.qml @@ -1,36 +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 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 ? 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 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 8c1cc9699..c226a407f 100644 --- a/resources/qml/Governikus/Style/TextStyles.qml +++ b/resources/qml/Governikus/Style/TextStyles.qml @@ -1,162 +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_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 e5f3439ec..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 + 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 !== "" - } - Item { - id: additionalContentItem - Layout.alignment: Qt.AlignHCenter - Layout.bottomMargin: Constants.component_spacing - Layout.fillWidth: true - Layout.maximumWidth: Style.dimens.max_text_width - implicitHeight: childrenRect.height - 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 61e22e60f..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/material_settings.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.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 3b65a1442..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 \"Remote\" 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("Start pairing") - - 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 34e5f0478..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 \"Remote\" 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("Start pairing") - - 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 Configure remote service.") : - //: 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 efe19a5a8..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,8 +109,9 @@ Item { } TabBarView { id: helpView + anchors.fill: parent - visible: baseItem.activeModule === UiModule.HELP + visible: baseItem.activeModule === UiModule.HELP || baseItem.activeModule === UiModule.TUTORIAL initialItem: MoreView { } 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 ff8b43531..b9aa42ce8 100644 --- a/resources/qml/Governikus/View/+mobile/SectionPage.qml +++ b/resources/qml/Governikus/View/+mobile/SectionPage.qml @@ -1,63 +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 - readonly property bool topLevelPage: StackView.index === 0 + 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 070861af2..fbd8e89d7 100644 --- a/resources/qml/Governikus/Workflow/+desktop/GeneralWorkflow.qml +++ b/resources/qml/Governikus/Workflow/+desktop/GeneralWorkflow.qml @@ -1,27 +1,25 @@ /** * 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 property bool isPinChange: false - //: LABEL DESKTOP - property string passwordInfoLinkText: qsTr("More information") property int waitingFor: 0 - signal requestPasswordInfo + signal deviceUnpaired(var pDeviceName) signal settingsRequested onWaitingForChanged: if (visible) @@ -36,8 +34,7 @@ SectionPage { } Connections { function onFireCertificateRemoved(pDeviceName) { - //: 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. - ApplicationModel.showFeedback(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(pDeviceName)); + deviceUnpaired(pDeviceName); } target: RemoteServiceModel @@ -47,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 @@ -100,6 +112,7 @@ SectionPage { } GText { id: mainText + Accessible.name: mainText.text activeFocusOnTab: true anchors.horizontalCenter: parent.horizontalCenter @@ -109,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)."); @@ -125,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) @@ -141,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 @@ -153,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: @@ -167,48 +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 { - id: moreInfo + 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: moreInfo - //: 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() - } - }, - State { - name: "moreInformation" - when: waitingFor === Workflow.WaitingFor.Password - - PropertyChanges { - iconVisible: true - target: moreInfo - text: root.passwordInfoLinkText - visible: true - - onClicked: root.requestPasswordInfo() - } - } - ] + 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/BusyImageIndicator.qml b/resources/qml/Governikus/Workflow/+mobile/BusyImageIndicator.qml deleted file mode 100644 index b035a4e6e..000000000 --- a/resources/qml/Governikus/Workflow/+mobile/BusyImageIndicator.qml +++ /dev/null @@ -1,28 +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 - -Item { - property string image - property alias running: busyIndicator.running - - GBusyIndicator { - id: busyIndicator - anchors.centerIn: parent - factor: 1.2 - height: img.height - running: false - width: height - } - Image { - id: img - anchors.centerIn: parent - fillMode: Image.PreserveAspectFit - smooth: true - source: image - width: parent.width - } -} 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 f08536b74..7038a2752 100644 --- a/resources/qml/Governikus/Workflow/+mobile/GeneralWorkflow.qml +++ b/resources/qml/Governikus/Workflow/+mobile/GeneralWorkflow.qml @@ -1,20 +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.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 { @@ -23,61 +32,45 @@ SectionPage { onClicked: workflowModel.cancelWorkflow() } - NfcWorkflow { - visible: workflowModel.readerPlugInType === ReaderPlugIn.NFC - - onStartScanIfNecessary: workflowModel.startScanIfNecessary() - - anchors { - bottom: technologySwitch.top - left: parent.left - right: parent.right - top: parent.top + Component.onCompleted: { + if (initialPlugIn != null) { + technologySwitch.requestPluginType(initialPlugIn); } } - SmartWorkflow { - visible: workflowModel.readerPlugInType === ReaderPlugIn.SMART - workflowModel: baseItem.workflowModel - anchors { - bottom: technologySwitch.top - left: parent.left - right: parent.right - top: parent.top - } - } - RemoteWorkflow { - visible: workflowModel.readerPlugInType === ReaderPlugIn.REMOTE_IFD || workflowModel.readerPlugInType === ReaderPlugIn.PCSC + GridLayout { + anchors.fill: parent + columns: 3 + flow: isLandscape ? Flow.LeftToRight : Flow.TopToBottom + rows: 3 - anchors { - bottom: technologySwitch.top - left: parent.left - right: parent.right - top: parent.top + WorkflowInfoList { + id: technologyInfo + + Layout.fillHeight: true + Layout.fillWidth: true } - } - SimulatorWorkflow { - visible: workflowModel.readerPlugInType === ReaderPlugIn.SIMULATOR - workflowModel: baseItem.workflowModel + GSeparator { + id: separator - anchors { - bottom: technologySwitch.top - left: parent.left - right: parent.right - top: parent.top + readonly property real shorteningFactor: 0.75 + + 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 + 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 85b4bb103..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,13 +14,42 @@ Item { property var cardPosition: null property bool startPositionLeft: true + 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 @@ -41,8 +70,8 @@ Item { name: "on" PropertyChanges { - target: phone - tintEnabled: false + target: symbol + visible: false } PropertyChanges { running: true @@ -61,9 +90,11 @@ Item { } CardPositionModel { id: cardPositionModel + } Timer { id: modelActivationTimer + interval: 1000 onTriggered: cardPositionModel.running = true @@ -79,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" @@ -116,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 { @@ -140,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 - height: Math.ceil(parent.height * 0.25) * 2 - 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 bd34b7927..55567753c 100644 --- a/resources/qml/Governikus/Workflow/+mobile/NfcWorkflow.qml +++ b/resources/qml/Governikus/Workflow/+mobile/NfcWorkflow.qml @@ -1,32 +1,50 @@ /** * 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 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 readonly property int nfcState: visible ? ApplicationModel.nfcState : ApplicationModel.NFC_UNAVAILABLE 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 - height: baseItem.height / 2 - 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: @@ -52,9 +70,9 @@ Item { //: INFO ANDROID IOS NFC is available but needs to be activated in the settings of the smartphone. qsTr("Please enable NFC in your system settings."); case ApplicationModel.NFC_INACTIVE: - //: INFO ANDROID IOS NFC is available but needs to be activated in the settings of the smartphone. + //: INFO ANDROID IOS NFC is available and enabled but needs to be started. return qsTr("NFC scan is not running.") + "
    " + - //: INFO ANDROID IOS NFC is available but needs to be activated in the settings of the smartphone. + //: INFO ANDROID IOS NFC is available and enabled but needs to be started. qsTr("Please start the NFC scan."); default: return ""; @@ -64,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."); @@ -76,6 +97,10 @@ Item { } } 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 use this smartphone as card reader and connect to your id card.").arg(RemoteServiceModel.connectedClientName); + } switch (nfcState) { case ApplicationModel.NFC_UNAVAILABLE: //: INFO ANDROID IOS @@ -93,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/ProgressIndicator.qml b/resources/qml/Governikus/Workflow/+mobile/ProgressIndicator.qml deleted file mode 100644 index 97314e090..000000000 --- a/resources/qml/Governikus/Workflow/+mobile/ProgressIndicator.qml +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Global 1.0 - -Item { - id: baseItem - - property alias imageIconSource: busyIcon.image - property alias imagePhoneSource: phone.source - - TintableIcon { - id: phone - anchors.centerIn: parent - desaturate: true - height: parent.height * 0.5 - opacity: tintEnabled ? 0.7 : 1.0 - visible: baseItem.state === "off" - width: height - } - Item { - id: currentAction - anchors.bottom: pCircle.top - anchors.left: parent.left - anchors.margins: Constants.component_spacing - anchors.right: parent.right - anchors.top: parent.top - - BusyImageIndicator { - id: busyIcon - anchors.centerIn: parent - height: Math.min(parent.height - 40, 2 * pCircle.height) - running: visible - visible: baseItem.state === "one" - width: height - } - CardReader { - anchors.centerIn: parent - cardAnimation: baseItem.state === "two" - height: parent.height - pinFieldAnimation: false - visible: baseItem.state === "two" - } - } - ProgressCircle { - id: pCircle - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right - state: baseItem.state - visible: baseItem.state === "one" || baseItem.state === "two" - } -} diff --git a/resources/qml/Governikus/Workflow/+mobile/RemoteProgressIndicator.qml b/resources/qml/Governikus/Workflow/+mobile/RemoteProgressIndicator.qml new file mode 100644 index 000000000..4a400bf7b --- /dev/null +++ b/resources/qml/Governikus/Workflow/+mobile/RemoteProgressIndicator.qml @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick +import Governikus.Global +import Governikus.Style + +Item { + id: baseItem + + property bool foundSelectedReader: false + + implicitHeight: Style.dimens.workflow_progress_indicator_size + implicitWidth: phone.implicitWidth + + TintableIcon { + id: phone + + anchors.centerIn: parent + 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 + anchors.right: parent.right + anchors.top: parent.top + + CardReader { + anchors.centerIn: parent + height: parent.height + pinFieldAnimation: false + visible: baseItem.foundSelectedReader + } + } + ProgressCircle { + id: pCircle + + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + state: baseItem.foundSelectedReader ? "two" : "off" + visible: baseItem.foundSelectedReader + } +} diff --git a/resources/qml/Governikus/Workflow/+mobile/RemoteWorkflow.qml b/resources/qml/Governikus/Workflow/+mobile/RemoteWorkflow.qml index 2b152f390..90bd72c49 100644 --- a/resources/qml/Governikus/Workflow/+mobile/RemoteWorkflow.qml +++ b/resources/qml/Governikus/Workflow/+mobile/RemoteWorkflow.qml @@ -1,23 +1,32 @@ /** * 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 property bool settingsPushed: remoteServiceSettings.visible property bool wifiEnabled: ApplicationModel.wifiEnabled + signal deviceUnpaired(var pDeviceName) + + clip: true + maximumContentWidth: Style.dimens.max_text_width + spacing: 0 + topMargin: 0 + onFoundSelectedReaderChanged: { if (baseItem.settingsPushed && foundSelectedReader) { remoteServiceSettings.pop(); @@ -26,32 +35,29 @@ Item { Connections { function onFireCertificateRemoved(pDeviceName) { - //: 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. - ApplicationModel.showFeedback(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(pDeviceName)); + deviceUnpaired(pDeviceName); } target: RemoteServiceModel } - ProgressIndicator { + RemoteProgressIndicator { id: progressIndicator + Accessible.ignored: true - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - height: parent.height / 2 - imageIconSource: "qrc:///images/mobile/icon_remote.svg" - imagePhoneSource: "qrc:///images/mobile/phone_remote.svg" - state: foundSelectedReader ? "two" : "off" + Layout.alignment: Qt.AlignCenter + foundSelectedReader: baseItem.foundSelectedReader } TechnologyInfo { id: techInfo + + Layout.alignment: Qt.AlignHCenter enableButtonText: { if (!wifiEnabled) { //: LABEL ANDROID IOS return qsTr("Enable WiFi"); } else if (!foundSelectedReader) { //: LABEL ANDROID IOS - return qsTr("Pair device"); + return qsTr("Manage pairings"); } else { return ""; } @@ -62,7 +68,7 @@ Item { return qsTr("To use the remote service WiFi has to be activated. Please activate WiFi in your device settings."); } else if (!foundSelectedReader) { //: INFO ANDROID IOS No paired and reachable device was found, hint that the remote device needs to be actually started for this feature. - return qsTr("No paired smartphone as card reader (SaC) with activated \"remote service\" available."); + return qsTr("Allow a connection on a paired smartphone or pair a new smartphone."); } else { return ""; } @@ -73,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: { @@ -87,7 +95,7 @@ Item { return qsTr("Wifi disabled"); } else if (!foundSelectedReader) { //: LABEL ANDROID IOS - return qsTr("Waiting for connection"); + return qsTr("No smartphone as card reader connected"); } else { //: LABEL ANDROID IOS return qsTr("Determine card"); @@ -106,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 47c6b033c..9b0aa8605 100644 --- a/resources/qml/Governikus/Workflow/+mobile/SimulatorWorkflow.qml +++ b/resources/qml/Governikus/Workflow/+mobile/SimulatorWorkflow.qml @@ -1,35 +1,43 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 -import Governikus.TechnologyInfo 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: parent.height / 2 - 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 - height: Math.ceil(parent.height * 0.25) * 2 source: "qrc:///images/mobile/phone_simulator.svg" + sourceSize.height: Style.dimens.header_icon_size tintEnabled: false } } TechnologyInfo { id: technologyInfo + + Layout.alignment: Qt.AlignHCenter //: LABEL ANDROID IOS enableButtonText: qsTr("Continue") @@ -37,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 9a040a657..b488dba7d 100644 --- a/resources/qml/Governikus/Workflow/+mobile/SmartProgressIndicator.qml +++ b/resources/qml/Governikus/Workflow/+mobile/SmartProgressIndicator.qml @@ -1,20 +1,25 @@ /** * Copyright (c) 2021-2023 Governikus GmbH & Co. KG, Germany */ -import QtQuick 2.15 -import Governikus.Global 1.0 +import QtQuick +import Governikus.Global +import Governikus.Style Item { id: baseItem property alias disabled: icon.tintEnabled + implicitHeight: Style.dimens.workflow_progress_indicator_size + implicitWidth: icon.implicitWidth + TintableIcon { id: icon + anchors.centerIn: parent desaturate: true - height: Math.ceil(parent.height * 0.25) * 2 opacity: tintEnabled ? 0.7 : 1.0 source: "qrc:///images/mobile/phone_smart.svg" + sourceSize.height: Style.dimens.header_icon_size } } diff --git a/resources/qml/Governikus/Workflow/+mobile/SmartWorkflow.qml b/resources/qml/Governikus/Workflow/+mobile/SmartWorkflow.qml index ce02c0452..3e21c9351 100644 --- a/resources/qml/Governikus/Workflow/+mobile/SmartWorkflow.qml +++ b/resources/qml/Governikus/Workflow/+mobile/SmartWorkflow.qml @@ -1,37 +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.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 isSmartCardAllowed: workflowModel.isSmartCardAllowed + readonly property bool isRemoteWorkflow: ApplicationModel.currentWorkflow === ApplicationModel.WORKFLOW_REMOTE_SERVICE + 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 - height: parent.height / 2 - - 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 ""; @@ -55,18 +66,26 @@ Item { } return ""; default: + if (isRemoteWorkflow) { + //: LABEL ANDROID IOS + return qsTr("You have not yet set up a Smart-eID or it is no longer usable.\n\nTo 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 return qsTr("You have not yet set up a Smart-eID or it is no longer usable.\n\nTo 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."); } } 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 @@ -94,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 c79470eb0..94eb63bac 100644 --- a/resources/qml/Governikus/Workflow/qmldir +++ b/resources/qml/Governikus/Workflow/qmldir @@ -1,12 +1,12 @@ module Workflow -internal BusyImageIndicator BusyImageIndicator.qml internal CardReader CardReader.qml internal NfcProgressIndicator NfcProgressIndicator.qml internal ProgressCircle ProgressCircle.qml -internal ProgressIndicator ProgressIndicator.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 38c86e7ae..e0875f658 100644 --- a/resources/translations/ausweisapp2_de.ts +++ b/resources/translations/ausweisapp2_de.ts @@ -5,7 +5,7 @@ DvcsAttributes revision - 52a5aa47f692 + 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 @@ -178,6 +170,11 @@ LABEL ANDROID IOS A11y button to confirm the PIN and start the provider authenti Do you know your six-digit ID card PIN? Kennen Sie Ihre sechsstellige Karten-PIN? + + 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. + BaseConfirmationPopup @@ -205,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 @@ -302,13 +253,6 @@ LABEL ANDROID IOS A11y button to confirm the PIN and start the provider authenti OpenSSL-Version - - CancelAction - - Cancel - Abbrechen - - CardPositionView @@ -339,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 @@ -353,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. @@ -414,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. @@ -446,55 +417,20 @@ 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. + 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. - 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 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. @@ -505,7 +441,7 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin Was für eine PIN haben Sie? - 6-digit PIN + Six-digit PIN LABEL ALL_PLATFORMS Sechsstellige PIN @@ -515,7 +451,7 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin Von Ihnen selbst gesetzt - 5-digit Transport PIN + Five-digit Transport PIN LABEL ALL_PLATFORMS Fünfstellige Transport-PIN @@ -787,211 +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? + Gerät und Ausweis prüfen - 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. + 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 + 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. - Supported + Smart-eID not supported LABEL ANDROID IOS - Unterstützt + Smart-eID nicht unterstützt - Not supported + Possible causes are: LABEL ANDROID IOS - Nicht unterstützt + Mögliche Ursachen hierfür sind: - Prepared + The setup has not been completed. LABEL ANDROID IOS - Vorbereitet + Die Einrichtung wurde nicht vollständig abgeschlossen. - Not prepared + The Smart-eID PIN has been entered incorrectly three times. LABEL ANDROID IOS - Nicht vorbereitet + Die Smart-eID-PIN wurde drei mal falsch eingegeben. - Set up + The %1 has been uninstalled temporarily. LABEL ANDROID IOS - Eingerichtet + Die %1 wurde zwischenzeitlich deinstalliert. - Not set up + You may continue with the setup of the Smart-eID. LABEL ANDROID IOS - Nicht eingerichtet + Sie können mit der Einrichtung der Smart-eID fortfahren. - Invalid + Continue LABEL ANDROID IOS - Ungültig + Fortsetzen - Ready for use + Your device meets the technical requirements for Smart-eID. You may now continue the setup process. LABEL ANDROID IOS - Einsatzbereit + Ihr Gerät erfüllt die technischen Voraussetzung für die Smart-eID. Sie können mit der Einrichtung fortfahren. - - - CheckSmartSuggestionView - Unknown result code: %1 + Smart-eID supported LABEL ANDROID IOS - Unbekannter Ergebniscode: %1 + Smart-eID unterstützt - Updating Smart-eID status... - LABEL ANDROID IOS - Status der Smart-eID wird aktualisiert... + 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. - Please wait a moment. + Smart-eID invalid LABEL ANDROID IOS - Bitte warten Sie einen Moment. + Smart-eID ungültig - Smart-eID not supported + Smart-eID check failed LABEL ANDROID IOS - Smart-eID nicht unterstützt + Smart-eID-Prüfung fehlgeschlagen - 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. + Back 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. + Zurück + + + ConnectSacView - Check device and ID card - LABEL ANDROID IOS - Gerät und Ausweis prüfen + Pairing + LABEL DESKTOP + Kopplung - 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. - - - 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 - - - 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. - + DarkModeButtons - 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. + System + LABEL ALL_PLATFORMS + Systemeinstellungen - Start check - LABEL ANDROID IOS - Prüfung starten + Dark + LABEL ALL_PLATFORMS + Dunkel - - - ConnectSacView - Pairing - LABEL DESKTOP - Kopplung + Light + LABEL ALL_PLATFORMS + Hell - Pairing the device ... - LABEL DESKTOP - Das Gerät wird gekoppelt ... + Set the app appearance to system mode + LABEL ALL_PLATFORMS + Setzt das Erscheinungsbild der Anwendung auf die Systemeinstellungen - The device "%1" has been paired. - Das Gerät "%1" wurde 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 @@ -1017,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 @@ -1037,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 @@ -1045,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 @@ -1119,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 @@ -1134,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 @@ -1164,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 @@ -1174,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 @@ -1204,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 @@ -1351,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 @@ -1405,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. @@ -1468,11 +1295,6 @@ INFO ANDROID IOS A new six-digit ID card PIN needs to be supplied. Bitte wiederholen Sie die Eingabe Ihrer neuen sechsstelligen Karten-PIN. - - Start the pairing on your smartphone and enter the pairing code shown there in order to use your smartphone as a card reader (SaC). - INFO DESKTOP The pairing code needs to be supplied. - Starten Sie die Kopplung auf Ihrem Smartphone und geben Sie den dort angezeigten Kopplungscode ein um Ihr Smartphone als Kartenleser (SaK) zu verwenden. - Unknown password type: INFO DESKTOP Error message during PIN/CAN/PUK input procedure, the requested password type is unknown; internal error. @@ -1504,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. @@ -1556,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 @@ -1612,6 +1430,39 @@ 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 @@ -1653,52 +1504,58 @@ 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. + + + Network + LABEL DESKTOP + Netzwerk - Close after authentication + Use the proxy (%1) specified during the installation. LABEL DESKTOP - Nach Authentisierung schließen + Benutze den bei der Installation angegebenen Proxy (%1). - Use internal notifications + Appearance LABEL DESKTOP - Interne Benachrichtigungen aktivieren + Erscheinungsbild - 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. + Use the system font + LABEL DESKTOP + Systemschriftart verwenden - Network + Toggling will restart the %1 LABEL DESKTOP - Netzwerk + Ein Umschalten startet die %1 neu - Use the proxy (%1) specified during the installation. + Close %1 after authentication LABEL DESKTOP - Benutze den bei der Installation angegebenen Proxy (%1). + %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 GeneralWorkflow - - 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. - Attempts LABEL DESKTOP Versuche - - Remaining ID card PIN attempts: %1 - Verbleibende Karten-PIN Versuche: %1 - Step %1 of 3 Schritt %1 von 3 @@ -1728,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. @@ -1754,274 +1601,52 @@ LABEL ANDROID IOS Zu den Einstellungen - More information - LABEL DESKTOP - Mehr Informationen + 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. - Zeige Details des Verlaufseintrags. + German + LABEL ALL_PLATFORMS + Deutsch - today - LABEL ANDROID IOS - heute + Set language to german + LABEL ALL_PLATFORMS + Verwende deutsche Sprache - yesterday - gestern + English + LABEL ALL_PLATFORMS + Englisch - dd.MM.yyyy - dd.MM.yyyy + Set language to english + LABEL ALL_PLATFORMS + Verwende englische Sprache - Tap for more details - LABEL ANDROID IOS - Berühren Sie hier für mehr Details - - - - HistoryListViewDelegate - - Delete entry - LABEL ANDROID - Lösche Eintrag - - - Delete history entry: %1 - INFO IOS Accessible name for the trash icon of a history entry. - Lösche Verlaufseintrag: %1 - - - - HistoryRemovalTimePeriodControl - - Time period - LABEL DESKTOP - Zeitspanne - - - Past hour - LABEL DESKTOP - Letzte Stunde - - - 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 - - - today - heute - - - yesterday - gestern - - - dd.MM.yyyy - dd.MM.yyyy - - - 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 - 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 + Ukrainian + LABEL ALL_PLATFORMS + Ukrainisch Set language to ukrainian @@ -2039,14 +1664,6 @@ LABEL ANDROID IOS Verwende russische Sprache - - LanguageSelectionPopup - - Select language - LABEL ANDROID IOS - Sprache auswählen - - LicenseInformation @@ -2057,16 +1674,16 @@ LABEL ANDROID IOS LocalNetworkInfo - - To be able to use your smartphone as card reader (SaC), please make sure that access to the local network is allowed. - INFO IOS Let user know to check the application settings for local network permission - Um Ihr Smartphone als Kartenleser (SaK) nutzen zu können, stellen Sie bitte sicher, dass der Zugriff auf das lokale Netzwerk erlaubt ist. - Go to application settings INFO IOS Link to application settings Zu den Anwendungseinstellungen + + 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 + In den Einstellungen muss der Zugriff auf das lokale Netzwerk erlaubt sein. + LogTitleBarControls @@ -2169,14 +1786,14 @@ INFO ANDROID IOS The current logfile is about to be removed, user confirmation r Filter - Select level: + Level LABEL ANDROID IOS - Level auswählen: + Level - Select category: + Category LABEL ANDROID IOS - Kategorie auswählen: + Kategorie Currently there are no log entries matching your filter. @@ -2184,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 @@ -2191,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 @@ -2228,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 @@ -2243,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 @@ -2266,11 +1888,6 @@ LABEL ANDROID IOS LABEL DESKTOP Allgemein - - Diagnosis and logs - LABEL DESKTOP - Diagnose und Protokolle - Version information LABEL DESKTOP @@ -2280,9 +1897,7 @@ LABEL ANDROID IOS Software license - LABEL DESKTOP ----------- -LABEL ANDROID IOS + LABEL DESKTOP Softwarelizenz @@ -2298,254 +1913,136 @@ LABEL ANDROID IOS Hilfe & Feedback - Tutorial + Privacy statement LABEL ANDROID IOS - Tutorial + Datenschutzerklärung - Do you want to know how to use %1? + Accessibility statement LABEL ANDROID IOS - Möchten Sie wissen, wie die %1 verwendet wird? + Barrierefreiheitserklärung - Video tutorials + Rate %1 LABEL ANDROID IOS - Videotutorials + Bewerten Sie die %1 - Do you want to see the video tutorials? + Logs LABEL ANDROID IOS - Möchten Sie die Videotutorials ansehen? + Protokolle - FAQ + Information LABEL ANDROID IOS - FAQ + Information - Do you have further questions about %1? + List of Providers LABEL ANDROID IOS - Haben Sie weitere Fragen zur %1? + Anbieterliste - Support - LABEL ANDROID IOS - Support + Data and logs + LABEL DESKTOP + Daten und Protokolle - Do you need further support? + FAQ - Frequently asked questions LABEL ANDROID IOS - Benötigen Sie weitergehende Unterstützung? + FAQ – Häufig gestellte Fragen - Privacy statement + Contact LABEL ANDROID IOS - Datenschutzerklärung + Kontakt - Do you want to read the privacy statement? + Show Logs LABEL ANDROID IOS - Möchten Sie die Datenschutzerklärung einsehen? + Protokolle anzeigen - Accessibility statement + Send log to the support LABEL ANDROID IOS - Barrierefreiheitserklärung + Protokoll an den Support senden - Do you want to read the accessibility statement? + Terms of use and software license LABEL ANDROID IOS - Möchten Sie die Barrierefreiheitserklärung einsehen? + Nutzungsbedingungen und Softwarelizenz + + + MoreViewDiagnosis - Rate %1 - LABEL ANDROID IOS - Bewerten Sie die %1 + Logs + LABEL DESKTOP + Protokolle - Do you want to rate us in the App Store? - LABEL ANDROID IOS - Möchten Sie uns im App Store bewerten? + Show logs + LABEL DESKTOP + Zeige Protokolle - Do you want to rate us in the Google Play Store? - Möchten Sie uns im Google Play Store bewerten? + Show system data + LABEL DESKTOP + Zeige Systemdaten - Diagnosis - LABEL ANDROID IOS - Diagnose - - - Logs - LABEL ANDROID IOS - Protokolle - - - Do you want to view the logs of %1? - LABEL ANDROID IOS - Möchten Sie die Protokolle der %1 ansehen? - - - Report error - LABEL ANDROID IOS - Melden Sie einen Fehler - - - Did you find a bug? Please help us by sending us the log file together with a description of the error. - LABEL ANDROID IOS - Haben Sie einen Fehler entdeckt? Helfen Sie uns, indem Sie uns die Protokolldatei zusammen mit einer Fehlerbeschreibung zusenden. - - - Information - LABEL ANDROID IOS - Information - - - Do you want to see detailed information about %1? - LABEL ANDROID IOS - Möchten Sie detaillierte Informationen über die %1 ansehen? - - - Do you want to read the software licenses? - LABEL ANDROID IOS - Möchten Sie die Software-Lizenzen lesen? - - - Do you want to view the release notes of %1? - LABEL ANDROID IOS - Möchten Sie die Release Notes der %1 ansehen? - - - - MoreViewDiagnosis - - Diagnosis - LABEL DESKTOP - Diagnose - - - You can view and save the diagnosis information of the AusweisApp2 and your system here. - LABEL DESKTOP - Sie können die Diagnose-Informationen der AusweisApp2 und Ihres System hier einsehen und speichern. - - - Show diagnosis - LABEL DESKTOP - Zeige Diagnose - - - Logs - LABEL DESKTOP - Protokolle - - - Do you want to view the logs of %1? - LABEL DESKTOP - Möchten Sie die Protokolle der %1 ansehen? - - - Show logs - LABEL DESKTOP - Zeige Protokolle - - - Report error - LABEL DESKTOP - Melden Sie einen Fehler - - - Did you find a bug? Please help us by sending us the log file together with a description of the error. - LABEL DESKTOP - Haben Sie einen Fehler entdeckt? Helfen Sie uns, indem Sie uns die Protokolldatei zusammen mit einer Fehlerbeschreibung zusenden. - - - 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? + System data + LABEL DESKTOP + Systemdaten + + + MoreViewGeneral 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 LABEL DESKTOP Barrierefreiheitserklärung - Do you want to read the accessibility statement? + Do you want to see a list of service providers? LABEL DESKTOP - Möchten Sie die Barrierefreiheitserklärung einsehen? + Möchten Sie eine Liste mit Diensteanbietern sehen? - Setup assistant + List of Providers LABEL DESKTOP - Einrichtungsassistent + Anbieterliste - Do you want to run the setup assistant again? + FAQ - Frequently asked questions LABEL DESKTOP - Möchten Sie den Einrichtungsassistenten erneut durchführen? + FAQ – Häufig gestellte Fragen - Start setup assistant + Contact LABEL DESKTOP - Starte Einrichtungsassistenten + Kontakt + + + + NavigationAction + + Cancel + Abbrechen + + + Back + Zurück @@ -2569,22 +2066,10 @@ LABEL ANDROID IOS NavigationView - - History - Verlauf - Start Start - - Provider - Anbieter - - - Remote - Fernzugriff - Settings Einstellungen @@ -2593,6 +2078,10 @@ LABEL ANDROID IOS Help Hilfe + + Card reader + Kartenleser + NfcWorkflow @@ -2628,12 +2117,12 @@ LABEL ANDROID IOS NFC scan is not running. - INFO ANDROID IOS NFC is available but needs to be activated in the settings of the smartphone. + INFO ANDROID IOS NFC is available and enabled but needs to be started. Der NFC-Scan ist nicht aktiv. Please start the NFC scan. - INFO ANDROID IOS NFC is available but needs to be activated in the settings of the smartphone. + INFO ANDROID IOS NFC is available and enabled but needs to be started. Bitte starten Sie den NFC-Scan. @@ -2671,6 +2160,11 @@ LABEL ANDROID IOS INFO ANDROID The ID card may be inserted, the authentication process may be started. Bitte platzieren Sie Ihren Ausweis direkt an der Geräterückseite.<br/><br/>Die genaue Position des Ausweises ist modellabhängig. Die Animationen zeigen Ihnen mögliche Positionen. Halten Sie jede Position einige Sekunden, bevor Sie eine andere ausprobieren und bewegen Sie den Ausweis nicht mehr, sobald der Kontakt hergestellt wurde. + + The device "%1" wants to use this smartphone as card reader and connect to your id card. + INFO ANDROID IOS %1 will be replaced with the name of the device. + Das Gerät "%1" möchte dieses Smartphone als Kartenleser nutzen und sich mit Ihrem Ausweis verbinden. + NumberField @@ -2717,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. @@ -2732,6 +2227,52 @@ LABEL ANDROID IOS Deaktiviert + + PairingCodeInfoView + + Pairing Information + LABEL ANDROID IOS + Informationen zur Kopplung + + + Open %1 on your %2other device%3. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 3 + Öffnen Sie auf Ihrem %2anderen Gerät%3 die %1. + + + On that device go to %1Settings%2 and then %1Smartphone as card reader%2 resp. %1Manage pairings%2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 3. %1 and %2 are surrounding tags for bold font. + Gehen Sie dort in die %1Einstellungen%2 und dann zu %1Smartphone als Kartenleser%2 bzw. %1Kopplungen verwalten%2. + + + Choose this smartphone in the list to pair it. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 3 + Wählen Sie in der angezeigten Liste dieses Smartphone aus, um es zu koppeln. + + + + PairingProcessInfo + + Open %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. + + + On that device choose %1Card reader%2 and then %1Pair device%2 resp. %1Pair new device%2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 4. %1 and %2 are surrounding tags for bold font. + Wählen Sie dort unter %1Kartenleser%2 die Option %1Gerät koppeln%2 bzw. %1Neues Gerät koppeln%2. + + + Choose the smartphone in the list shown here to pair it. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 4 of 4 + Klicken Sie zum Koppeln auf das hier angezeigte Gerät. + + + Ensure that the %1 on your Smartphone as card reader has at least version %2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 4. %1 is a placeholder-tag for the app name. + Stellen Sie sicher, dass die %1 auf Ihrem Smartphone als Kartenleser mindestens die Version %2 hat. + + PasswordInfoContent @@ -2752,39 +2293,31 @@ LABEL ANDROID IOS LABEL ALL_PLATFORMS PIN-Information - - The card PIN is a 6-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 5-digit Transport PIN. Only when you have set a 6-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 Wie wähle ich eine sichere PIN? - For your 6-digit 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. + For your six-digit 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 PIN?' paragraph 1/3 - Wählen Sie für Ihre sechsstellige PIN eine Zahlenkombination, die nicht zu erraten ist – also weder „123456“, noch Ihr Geburtsdatum oder andere Zahlen, die auf dem Ausweis aufgedruckt sind. + Wählen Sie für Ihre sechsstellige PIN eine Zahlenkombination, die nicht zu erraten ist - also weder „123456“, noch Ihr Geburtsdatum oder andere Zahlen, die auf dem Ausweis aufgedruckt sind. - You can change your 6-digit PIN at any time and an unlimited number of times as long as you know your valid PIN. + You can change your six-digit PIN at any time and an unlimited number of times as long as you know your valid PIN. INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure PIN?' paragraph 2/3 Sie können Ihre sechsstellige PIN jederzeit und unbegrenzt oft ändern, solange Ihnen Ihre gültige PIN bekannt ist. 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. @@ -2798,12 +2331,12 @@ LABEL ANDROID IOS Transport-PIN-Information - The 5-digit Transport PIN was sent to you in the PIN letter by mail after you applied for your ID card. + The five-digit Transport PIN was sent to you in the PIN letter by mail after you applied for your ID card. INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 1/3 Die fünfstellige Transport-PIN wurde Ihnen im PIN-Brief per Post zugesandt, nachdem Sie Ihren Ausweis beantragt haben. - If you did not set a self-selected 6-digit card PIN when you picked up your ID card, you can do so using the Transport PIN. + If you did not set a self-selected six-digit card PIN when you picked up your ID card, you can do so using the Transport PIN. INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 2/3 Falls Sie nicht direkt bei der Abholung Ihres Ausweises eine selbstgewählte, sechsstellige Karten-PIN gesetzt haben, können Sie dies mithilfe der Transport-PIN tun. @@ -2812,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 @@ -2838,7 +2356,7 @@ LABEL ANDROID IOS PUK-Information - The PUK is a 10-digit number that you can find in the PIN letter that was sent to you by mail after you applied for your ID card. + The PUK is a ten-digit number that you can find in the PIN letter that was sent to you by mail after you applied for your ID card. INFO ALL_PLATFORMS Answer to the question 'Where do I find the PUK?' Die PUK ist eine zehnstellige Zahl, die Sie in dem PIN-Brief finden, der Ihnen nach Beantragung Ihres Ausweises per Post zugeschickt wurde. @@ -2898,7 +2416,7 @@ LABEL ANDROID IOS Wo finde ich die CAN? - The CAN is a 6-digit number that can be found on the bottom right of the front of the ID card. + The CAN is a six-digit number that can be found on the bottom right of the front of the ID card. INFO ALL_PLATFORMS Answer to the question 'Where can I find the CAN?' Die CAN ist eine sechsstellige Zahl, die unten rechts auf der Vorderseite des Ausweises zu finden ist. @@ -2935,7 +2453,7 @@ LABEL ALL_PLATFORMS Sie kennen Ihre PIN nicht? - You have not yet set a 6-digit card PIN and cannot find the PIN letter with the Transport PIN? + You have not yet set a six-digit card PIN and cannot find the PIN letter with the Transport PIN? INFO ALL_PLATFORMS Sie haben noch keine sechsstellige PIN gesetzt und können den Brief mit der Transport-PIN nicht finden? @@ -2955,59 +2473,109 @@ LABEL ALL_PLATFORMS PIN-Arten - Your ID card comes with a 5-digit 'Transport PIN' which you need to replace with a 6-digit PIN that you choose yourself. - INFO ALL_PLATFORMS Description text explaining the PINs 1/6 + 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/7 Ihr Ausweis wurde bei Erstellung mit einer fünfstelligen „Transport-PIN“ versehen, die Sie durch eine sechsstellige, selbstgewählte PIN ersetzen müssen. - 5-digit Transport PIN + Five-digit Transport PIN LABEL ALL_PLATFORMS Fünfstellige Transport-PIN - The 5-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 + + + 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 5-digit PIN with a 6-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? - 6-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 5-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 6-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. + + + 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 card PIN, you can request a new PIN free of charge using the PIN Reset Service. + 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. @@ -3075,6 +2643,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 @@ -3133,6 +2706,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 @@ -3171,11 +2749,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 @@ -3224,322 +2797,72 @@ 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 - - - - ProviderDetailDescription - - Description - LABEL ANDROID_TABLET IOS_TABLET - Beschreibung - - - The provider did not provide a description. - LABEL ANDROID_TABLET IOS_TABLET - Der Anbieter hat keine Beschreibung zur Verfügung gestellt. +LABEL DESKTOP Title of the proxy credentials popup. + Anmelden - - - ProviderDetailHistory - List of your past interactions with this provider - Ihre vergangenen Interaktionen mit diesem Anbieter + 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 list is empty, no recorded interaction with this provider. - Die Liste ist leer, keine Interaktion mit diesem Anbieter aufgezeichnet. + Proxy credential username + LABEL DESKTOP Accessible name. + Benutzername 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. + Username + LABEL DESKTOP Label of the textfield for the username. + Nutzername - History - LABEL ANDROID_TABLET IOS_TABLET - Verlauf + Proxy credential password + LABEL DESKTOP Accessible name. + Passwort für den Proxy - Purpose for reading out requested data - LABEL ANDROID_TABLET IOS_TABLET - Zweck des Auslesevorgangs + Password + LABEL DESKTOP Label of the textfield for the password. + Passwort - ProviderDetailHistoryInfo + QObject - Provider - LABEL ANDROID_TABLET IOS_TABLET - Anbieter + 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. - Read data - LABEL ANDROID_TABLET IOS_TABLET - Ausgelesene Daten - - - Terms of usage - LABEL ANDROID_TABLET IOS_TABLET - Nutzungsbedingungen - - - - ProviderDetailHistoryItem - - today - LABEL ANDROID IOS - heute - - - yesterday - gestern - - - dd.MM.yyyy - dd.MM.yyyy - - - Service: - LABEL DESKTOP - Dienst: - - - Provider: - LABEL DESKTOP - Anbieter: - - - Click to view details of history entry. - Zeige Details des Verlaufseintrags. - - - Touch for more details - LABEL ANDROID IOS - Berühren Sie hier für mehr Details - - - - ProviderDetailView - - Description - LABEL DESKTOP - Beschreibung - - - The provider did not provide a description. - LABEL DESKTOP - Der Anbieter hat keine Beschreibung zur Verfügung gestellt. - - - History - LABEL DESKTOP - Verlauf - - - - 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 - - - - ProviderHeader - - To provider - LABEL ANDROID IOS - Zum Anbieter - - - - ProviderInfoSection - - See details under "more..." - LABEL DESKTOP - Weitere Details unter "mehr..." - - - - 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. + 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 @@ -3595,10 +2918,6 @@ LABEL ANDROID IOS Press space to pair the smartphone "%1". Drücken Sie die Leertaste um das Smartphone "%1" zu koppeln. - - Click to pair - Klicken zum Koppeln - Remove remote device Entferne das Gerät @@ -3607,38 +2926,73 @@ LABEL ANDROID IOS RemoteReaderView - Paired remote devices - Gekoppelte Netzwerkgeräte + Paired devices + LABEL DESKTOP + Gekoppelte Geräte + + + Add pairing + LABEL DESKTOP + Kopplung hinzufügen - Available remote devices - Verfügbare Netzwerkgeräte + 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. - Only devices that are already paired or are connected to the same WiFi network and have the remote service enabled are shown here. - Nur Geräte die bereits gekoppelt wurden, oder sich mit aktiviertem Fernzugriff im selben WLAN-Netz befinden, werden hier angezeigt. + Both devices have to be connected to the same WiFi. + Beide Geräte müssen mit demselben WLAN verbunden sein. - More information + On that device go to %1Card reader%2 and then %1Pair device%2 rsp. %1Pair new device%2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 4. %1 and %2 are surrounding tags for bold font + Wählen Sie dort unter %1Kartenleser%2 die Option %1Gerät koppeln%2 bzw. %1Neues Gerät koppeln%2. + + + Choose the device in the list to pair it. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 4 of 4 + Klicken Sie zum Koppeln auf das hier angezeigte Gerät. + + + Last connected LABEL DESKTOP - Mehr Informationen + Zuletzt verbunden + + + Ensure that the %1 on your Smartphone as card reader has at least version %2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 4. %1 is a placeholder-tag for the app name. + Stellen Sie sicher, dass die %1 auf Ihrem Smartphone als Kartenleser mindestens die Version %2 hat. - RemoteServiceSettings + RemoteServiceController + + Remote service + LABEL ANDROID IOS + Fernzugriff + - Configure remote service + You are about to identify yourself towards the following provider using the device "%1": LABEL ANDROID IOS - Fernzugriff konfigurieren + Sie möchten sich mit dem Gerät %1 bei folgendem Anbieter ausweisen: + + + Card reader + LABEL ANDROID IOS + Kartenleser - RemoteServiceView + RemoteServiceSettings - Remote service + Manage pairings LABEL ANDROID IOS - Fernzugriff + Kopplungen verwalten + + + RemoteServiceView Pairing failed. Please start a new pairing process on your other device and enter the shown pairing code. ERROR ANDROID IOS An error occurred while pairing the device. @@ -3669,35 +3023,16 @@ LABEL ANDROID IOS LABEL ANDROID IOS Warte auf Verbindung - - Remote service ready - LABEL ANDROID IOS - Fernzugriff startbereit - Waiting for connection from a paired device... INFO ANDROID IOS Warte auf eine Verbindung eines gekoppelten Gerätes... - - Start the remote access in order to make this smartphone visible and use it as a card reader (SaC). - -If you have not already paired a device, start the pairing now to set up this smartphone as a card reader. - INFO ANDROID IOS - Starten Sie den Fernzugriff, um dieses Smartphone sichtbar und damit als Kartenleser (SaK) nutzbar zu machen. - -Falls Sie noch kein Gerät gekoppelt haben, starten Sie jetzt die Kopplung, um dieses Smartphone als Kartenleser einzurichten. - Pairing code: <b>%1</b> LABEL ANDROID IOS Kopplungscode: <b>%1</b> - - Both of your devices have to be connected to the same WiFi. - INFO ANDROID IOS The remote service is active. Hint that both devices need to be connected to the same network. - Ihre beiden Geräte müssen mit dem selben WLAN-Netz verbunden sein. - Enable WiFi LABEL ANDROID IOS @@ -3709,43 +3044,77 @@ Falls Sie noch kein Gerät gekoppelt haben, starten Sie jetzt die Kopplung, um d NFC aktivieren - Stop remote service + Pair device LABEL ANDROID IOS - Fernzugriff stoppen + Gerät koppeln - Start remote service + Allow connection LABEL ANDROID IOS - Fernzugriff starten + Verbindung erlauben + + + You can use this Smartphone as a card reader for the %1 on other devices e.g. a laptop. + +To do this you first have to pair that device with this smartphone. + INFO ANDROID IOS + Sie können dieses Smartphone als Kartenleser für die %1 auf einem anderen Gerät, z.B. Ihrem Laptop, nutzen. + +Hierfür müssen Sie zuvor das entsprechende Gerät mit diesem Smartphone koppeln. - Stop pairing + Card reader LABEL ANDROID IOS - Kopplung stoppen + Kartenleser - Start pairing + Paired Devices LABEL ANDROID IOS - Kopplung starten + Gekoppelte Geräte - Enter the code %1 in the %2 on your other device to use your smartphone as a card reader (SaC). - INFO ANDROID IOS - Geben Sie den Code %1 in der %2 auf Ihrem anderen Gerät ein, um Ihr Smartphone als Kartenleser (SaK) zu verwenden. + Pair new device + LABEL ANDROID IOS + Neues Gerät koppeln - - - RemoteServiceViewRemote - Paired devices + Waiting for pairing LABEL ANDROID IOS - Gekoppelte Geräte + Warte auf Kopplung - No device is paired. + Start pairing of a new device LABEL ANDROID IOS - Kein Gerät gekoppelt. + Kopplung mit einem neuen Gerät starten. + + Where do I enter the pairing code? + LABEL ANDROID IOS + Wo gebe ich den Kopplungscode ein? + + + Enter the pairing code %1 in the %2 on your other device. + INFO ANDROID IOS + Geben Sie den Kopplungscode %1 in der %2 auf Ihrem anderen Gerät ein. + + + Cancel pairing + LABEL ANDROID IOS + Kopplung abbrechen + + + Allow a connection with paired devices to use this Smartphone as a card reader or pair another device. + INFO ANDROID IOS + Erlauben Sie eine Verbindung mit gekoppelten Geräten, um dieses Smartphone als Kartenleser zu nutzen oder koppeln Sie weitere Geräte. + + + Paired devices may use this Smartphone as a card reader now. + INFO ANDROID IOS + Gekoppelte Geräte können dieses Smartphone jetzt als Kartenleser nutzen. + + + + RemoteServiceViewRemote Click to remove device LABEL ANDROID IOS @@ -3766,16 +3135,6 @@ Falls Sie noch kein Gerät gekoppelt haben, starten Sie jetzt die Kopplung, um d INFO ANDROID IOS Entfernen - - Available devices - LABEL ANDROID IOS - Verfügbare Geräte - - - No unpaired smartphone as card reader (SaC) available. Please make sure that the smartphone as card reader (SaC) functionality in AusweisApp2 on your other device is activated and that both devices are connected to the same WiFi. - INFO ANDROID IOS No SaC was found on the network, both devices need to be connected to the same WiFi network. - Kein ungekoppeltes 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. - Please connect your WiFi to use another smartphone as card reader (SaC). INFO ANDROID IOS Wifi is not enabled and no new devices can be paired. @@ -3787,63 +3146,61 @@ Falls Sie noch kein Gerät gekoppelt haben, starten Sie jetzt die Kopplung, um d WLAN aktivieren - Click to pair + Pairing code LABEL ANDROID IOS - Klicken zum Koppeln + Kopplungscode - Pairing mode - INFO ANDROID IOS - Kopplungsmodus + Add pairing + LABEL ANDROID IOS + Kopplung hinzufügen - Start the pairing mode on your smartphone if you haven't done it already. - INFO ANDROID IOS Information dialog that requests the user to start the pairing mode on the smartphone. - Starten Sie den Kopplungsmodus auf Ihrem Smartphone, falls noch nicht geschehen. + Last connected + LABEL ANDROID IOS + Zuletzt verbunden - Pairing code + Available LABEL ANDROID IOS - Kopplungscode + Verfügbar + + + Paired devices + LABEL ANDROID IOS + Gekoppelte Geräte + + + Click to pair + LABEL ANDROID IOS + Klicken zum Koppeln - RemoteWorkflow + RemoteServiceWifiInfo - 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. + Both devices have to be connected to the same WiFi. + INFO ANDROID IOS The remote service is active. Hint that both devices need to be connected to the same network. + Beide Geräte müssen mit demselben WLAN verbunden sein. + + + RemoteWorkflow Enable WiFi LABEL ANDROID IOS WLAN aktivieren - - Pair device - LABEL ANDROID IOS - Gerät koppeln - To use the remote service WiFi has to be activated. Please activate WiFi in your device settings. INFO ANDROID IOS The WiFi module needs to be enabled in the system settings to use the remote service. Um den Fernzugriff zu nutzen, muss WLAN aktiviert werden. Bitte aktivieren Sie WLAN in Ihren Einstellungen. - - No paired smartphone as card reader (SaC) with activated "remote service" available. - INFO ANDROID IOS No paired and reachable device was found, hint that the remote device needs to be actually started for this feature. - Kein gekoppeltes Smartphone als Kartenleser mit aktiviertem "Fernzugriff" verfügbar. - Wifi disabled LABEL ANDROID IOS WLAN ist deaktiviert - - Waiting for connection - LABEL ANDROID IOS - Warte auf Verbindung - Determine card LABEL ANDROID IOS @@ -3855,17 +3212,28 @@ Falls Sie noch kein Gerät gekoppelt haben, starten Sie jetzt die Kopplung, um d 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 + LABEL ANDROID IOS + Kopplungen verwalten + + + No smartphone as card reader connected + LABEL ANDROID IOS + Kein Smartphone als Kartenleser verbunden + + + Allow a connection on a paired smartphone or pair a new smartphone. + INFO ANDROID IOS No paired and reachable device was found, hint that the remote device needs to be actually started for this feature. + Erlauben Sie die Verbindung auf einem bereits gekoppelten Smartphone oder koppeln Sie ein neues Smartphone. ResultErrorView - - Show error details - Fehlerdetails anzeigen - Details Details @@ -3905,109 +3273,15 @@ Falls Sie noch kein Gerät gekoppelt haben, starten Sie jetzt die Kopplung, um d - ScreenOrientationSelectionPopup - - Select screen orientation - LABEL ANDROID - Bildschirmausrichtung wählen - - - Set screen orientation to portrait - LABEL ANDROID - Bildschirmausrichtung auf Hochformat setzen - - - Portrait - LABEL ANDROID - Hochformat - - - recommended - empfohlen - - - Set screen orientation to landscape - LABEL ANDROID - Bildschirmausrichtung auf Querformat setzen - - - Landscape - LABEL ANDROID - Querformat - - - 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. - - - - SearchBar + RetryCounter - Search - LABEL DESKTOP ----------- -LABEL ANDROID - Suchen - - - Clear - Löschen - - - Type provider to search for - LABEL ANDROID - Tippen Sie den Namen des Anbieters ein, nach dem Sie suchen möchten - - - Abort search - LABEL ANDROID - Suche abbrechen - - - Search provider list - LABEL ANDROID - Durchsuchen der Anbieterliste - - - Enter search string - Sucheingabe - - - Search providers - Anbieter suchen - - - Clear search string - Lösche Sucheingabe - - - Cancel - LABEL IOS - Abbrechen + Remaining ID card PIN attempts: %1 + LABEL DESKTOP + Verbleibende Karten-PIN Versuche: %1 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 @@ -4018,16 +3292,6 @@ LABEL ANDROID 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 @@ -4069,19 +3333,19 @@ LABEL ANDROID Keine Aktualisierungsinformationen vorhanden, bitte prüfen Sie manuell auf verfügbare Aktualisierungen. - Delete history + Shuffle digits of on screen keypad LABEL DESKTOP - Verlauf löschen + Ziffern der Bildschirmtastatur zufällig anordnen - 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. + Button animation + LABEL DESKTOP + Tasten-Animationen - 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. + Visually highlight key presses on screen keypad + LABEL DESKTOP + Eingaben auf der Bildschirmtastatur optisch hervorheben @@ -4101,23 +3365,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 @@ -4125,11 +3377,6 @@ LABEL ANDROID LABEL ANDROID IOS Ausweisen - - Save read self-authentication data - LABEL DESKTOP - Ausgelesene Daten der Selbstauskunft speichern - SelfAuthenticationView @@ -4168,6 +3415,16 @@ LABEL ANDROID IOS LABEL ANDROID IOS Meine Daten einsehen + + Self-authentication + LABEL ANDROID IOS + Selbstauskunft + + + Hint + LABEL ANDROID IOS + Tipp + SettingsView @@ -4223,73 +3480,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 - - Remote card reader - LABEL ANDROID IOS - Smartphone als Kartenleser - - - Configure remote service for another device - LABEL ANDROID IOS - Ein anderes Gerät für den Fernzugriff konfigurieren - - - 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 @@ -4300,1511 +3500,650 @@ 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 - Entwicklermodus - - - Use a more tolerant mode - LABEL ANDROID IOS - Benutze einen toleranten Modus - - - Layout style - LABEL ANDROID IOS - Layout-Stil - - - Create dummy entries - LABEL ANDROID IOS - Erstelle Scheindaten - - - New Logfile - LABEL ALL_PLATFORMS - Neue Protokolldatei - - - 15 days old Logfile - LABEL ALL_PLATFORMS - 15 Tage alte Protokolldatei - - - - SetupAssistantView - - Setup Assistant - LABEL DESKTOP - Einrichtungsassistent - - - 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. - - - 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 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. - - - 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. - - - Auto-start Setting - LABEL DESKTOP - Autostart-Einstellung - - - 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? - - - 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. - - - History Setting - LABEL DESKTOP - Verlaufseinstellungen - - - 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? - - - 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. - - - Card Readers - LABEL DESKTOP - Kartenleser - - - 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. - - - Proceed to start page - INFO DESKTOP A11y button text to exit the setup assistant. - Weiter zur Startseite - - - - SimulatorWorkflow - - Simulator - LABEL ANDROID IOS - Simulator - - - Continue - LABEL ANDROID IOS - Weiter - - - - SmartDeleteStartView - - Delete Smart-eID - LABEL ANDROID IOS - Smart-eID löschen - - - Are you sure you want to delete the Smart-eID? - LABEL ANDROID IOS - Sind Sie sicher, dass Sie die Smart-eID löschen wollen? - - - Delete - LABEL ANDROID IOS - Löschen - - - 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 - Wenn Sie die Funktionalität in Zukunft wieder nutzen möchten, müssen Sie die Smart-eID erneut einrichten. - - - Reset Smart-eID - LABEL ANDROID IOS - Smart-eID zurücksetzen - - - - SmartMainView - - Updating Smart-eID status... - LABEL ANDROID IOS - Status der Smart-eID wird aktualisiert... - - - Smart-eID not supported - LABEL ANDROID IOS - Smart-eID nicht unterstützt - - - Smart-eID invalid - LABEL ANDROID IOS - Smart-eID ungültig - - - Smart-eID ready for use - LABEL ANDROID IOS - Smart-eID einsatzbereit - - - Smart-eID supported - LABEL ANDROID IOS - Smart-eID unterstützt - - - Please wait a moment. - LABEL ANDROID IOS - Bitte warten Sie einen Moment. - - - Unfortunately, this functionality is not supported by your device. - LABEL ANDROID IOS - Leider wird diese Funktion von Ihrem Gerät nicht unterstützt. - - - 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 - 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. - - - 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 - 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. - - - Set up a Smart-eID in order to perform online identifications without your ID card if supported by the provider. - 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. - - - - SmartSettingsView - - Smart-eID - LABEL ANDROID IOS - Smart-eID - - - Check Smart-eID status - LABEL ANDROID IOS - Smart-eID-Status prüfen - - - Check device compatibility and the current state of any present Smart-eID - LABEL ANDROID IOS - Unterstützung des Geräts sowie den aktuellen Zustand der Smart-eID prüfen - - - Set up Smart-eID - LABEL ANDROID IOS - Smart-eID einrichten - - - Set up Smart-eID on this device - LABEL ANDROID IOS - Smart-eID auf diesem Gerät einrichten - - - Renew Smart-eID - LABEL ANDROID IOS - Smart-eID erneuern - - - Renew your Smart-eID with current data - LABEL ANDROID IOS - Smart-eID mit aktuellen Daten neu einrichten - - - Delete Smart-eID - LABEL ANDROID IOS - Smart-eID löschen - - - Remove Smart-eID data from your device - LABEL ANDROID IOS - Smart-eID Daten von diesem Gerät löschen - - - Reset Smart-eID - LABEL ANDROID IOS - Smart-eID zurücksetzen - - - Remove Smart-eID data and provisioning from your device - LABEL ANDROID IOS - Smart-eID Daten und Vorbereitung entfernen - - - - 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 - Sie sind dabei, eine Smart-eID auf Ihrem Gerät einzurichten. Um fortzufahren, benötigen Sie Ihren Ausweis, Ihre sechsstellige Karten-PIN sowie eine Internetverbindung. - - - Set up Smart-eID - LABEL ANDROID IOS - Smart-eID einrichten - - - - 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 - Sie sind dabei, Ihre Smart-eID zu erneuern. Um fortzufahren, benötigen Sie Ihren Ausweis, Ihre sechsstellige Karten-PIN sowie eine Internetverbindung. - - - 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 - Bitte beachten Sie, dass ihre aktuelle Smart-eID während des Prozesses Ihre Gültigkeit verliert und bis zur erfolgreichen Aktualisierung nicht verwendet werden kann. - - - Renew Smart-eID - 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 - LABEL ANDROID IOS - Lösche 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 - 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. - - - Reset Smart-eID - LABEL ANDROID IOS - Smart-eID zurücksetzen - - - Resetting Smart-eID - LABEL ANDROID IOS - Setze Smart-eID zurück - - - - SmartWorkflow - - Updating Smart-eID status... - LABEL ANDROID IOS - Status der Smart-eID wird aktualisiert... - - - Smart-eID unsupported - LABEL ANDROID IOS - Smart-eID nicht unterstützt - - - Smart-eID disallowed - LABEL ANDROID IOS - Smart-eID nicht erlaubt - - - Smart-eID - LABEL ANDROID IOS - Smart-eID - - - Smart-eID not ready - LABEL ANDROID IOS - Smart-eID nicht einsatzbereit - - - Your Smart-eID is ready for use, press "Continue" to proceed. - LABEL ANDROID IOS - Ihre Smart-eID ist einsatzbereit. Klicken Sie auf "Weiter", um fortzufahren. - - - Please wait a moment. - LABEL ANDROID IOS - Bitte warten Sie einen Moment. - - - 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 - Leider wird Smart-eID von Ihrem Gerät nicht unterstützt. - -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. - - - 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 - Leider wird die Nutzung Ihrer Smart-eID für diese Authentisierung durch den Provider nicht erlaubt. - -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. - - - 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 - 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. - - - Continue - Weiter - - - - StoreFeedbackPopup - - Are you satisfied with AusweisApp2? - INFO ANDROID Header of the app rating popup. - Zufrieden mit der 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. - Wir würden uns sehr über eine Bewertung im Google Play Store freuen! - - - Do not ask again - LABEL ANDROID - Ignorieren - - - Rate app - LABEL ANDROID - App bewerten - - - - TabbedReaderView - - Card Readers - LABEL DESKTOP - Kartenleser - - - Smartphone as card reader - Smartphone als Kartenleser - - - USB card reader - USB Kartenleser - - - - TechnologySwitch - - NFC - LABEL ANDROID IOS - NFC - - - SMART - LABEL ANDROID IOS - SMART - - - WiFi - LABEL ANDROID IOS - WLAN - - - SIM - LABEL ANDROID IOS - SIM - - - - 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 - Startseite - - - Settings - Einstellungen - - - 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 - - - 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 - LABEL DESKTOP - Navigiere zu %1 - - - - 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. + Testmodus für die Selbstauskunft - Start the process with a click on: + Internal card simulator LABEL ANDROID IOS - Starten Sie den Vorgang mit: + Interner Kartensimulator - Proceed to PIN entry + Developer mode LABEL ANDROID IOS - Weiter zur PIN-Eingabe + Entwicklermodus - ... and place the top of the iPhone onto the ID card. - LABEL IOS - ...und platzieren Sie die Oberkante des iPhones auf dem Ausweis. + Use a more tolerant mode + LABEL ANDROID IOS + Benutze einen toleranten Modus - ... and place the ID card flat onto the NFC interface. - LABEL ANDROID - ...und platzieren Sie den Ausweis flach an der NFC-Schnittstelle. + Layout style + LABEL ANDROID IOS + Layout-Stil - Do not move device or ID card! + Create dummy entries LABEL ANDROID IOS - Gerät und Ausweis nicht bewegen! + Erstelle Scheindaten - 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. + New Logfile + LABEL ALL_PLATFORMS + Neue Protokolldatei - 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. + 15 days old Logfile + LABEL ALL_PLATFORMS + 15 Tage alte Protokolldatei - You can find more information on compatible devices on our %1mobile device list%2. + Smart-eID 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 + Smart-eID - six-digit PIN + Reset Smart-eID 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! + Smart-eID zurücksetzen - 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 - Funktioniert nur, wenn Sie die fünfstellige Transport-PIN bereits in eine sechsstellige PIN geändert haben. + Smart-eID auf Ihrem Gerät zurücksetzen - Open YouTube video + Show requested rights on this device as well LABEL ANDROID IOS - Öffne das YouTube-Video + Angefragte Berechtigung auch auf diesem Gerät anzeigen - You can also watch this YouTube video explaining the process. + Manage pairings LABEL ANDROID IOS - Sie können sich auch dieses YouTube-Video ansehen das den Prozess erläutert. + Kopplungen verwalten - - - TutorialReaderMethodSacDesktop - Tutorial: Smartphone as card reader + Show Transport PIN reminder, store feedback and close reminder dialogs. LABEL ANDROID IOS - Tutorial: Smartphone als Kartenleser + Zeige Transport-PIN Hinweis, Store Feedback und Fenster-Schließ Hinweis Dialoge. - Smartphone as card reader + Reset hideable dialogs LABEL ANDROID IOS - Smartphone als Kartenleser + Setze versteckbare Dialoge zurück - App on computer <b>without</b> NFC chip + Toggling will restart the %1 LABEL ANDROID IOS - App auf Computer <b>ohne</b> NFC-Chip + Ein Umschalten startet die %1 neu - Smartphone <b>with</b> NFC chip as card reader + Use system font LABEL ANDROID IOS - Smartphone <b>mit</b> NFC-Chip als Kartenleser + Systemschriftart verwenden - Install AusweisApp2 on both your computer <b>and</b> your smartphone with NFC capability. + Appearance LABEL ANDROID IOS - Installieren Sie die AusweisApp2 <b>sowohl</b> auf Ihrem Rechner <b>als auch</b> auf Ihrem NFC-fähigen Smartphone. + Erscheinungsbild - Both devices have to be connected to the same WiFi network + Add and remove devices LABEL ANDROID IOS - Beide Geräte müssen im selben WLAN sein + Geräte hinzufügen oder entfernen - Now choose "Remote" in the AusweisApp2 on your smartphone... + On-site reading LABEL ANDROID IOS - Öffnen Sie nun in der AusweisApp2 auf dem Smartphone die Ansicht "Fernzugriff"... + Vor-Ort-Auslesen - Now + Support CAN allowed mode for on-site reading LABEL ANDROID IOS - Jetzt + CAN-Allowed Modus für Vor-Ort-Auslesen unterstützen - Start pairing + Allow test sample card usage LABEL ANDROID IOS - Kopplung starten + Testmusterkarten erlauben - Pairing code + Simulate a test sample card in authentications LABEL ANDROID IOS - Kopplungscode + Bei der Authentisierung eine Testmusterkarte simulieren - appears! + Visually highlight key presses on screen keypad LABEL ANDROID IOS - erscheint! + Eingaben auf der Bildschirmtastatur optisch hervorheben + + + 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 - 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. + 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? - 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. + 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. - Select the <b>Smartphone as card reader</b> tab. - LABEL ANDROID IOS - Den Reiter <b>Smartphone als Kartenleser</b> auswählen. + 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. - Select smartphone from list - LABEL ANDROID IOS - Smartphone in der Liste auswählen + Autostart Settings + LABEL DESKTOP + Autostart Einstellungen - Enter pairing code next. - LABEL ANDROID IOS - Dann Kopplungscode eingeben. + 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. + + + SimulatorWorkflow - Click link on the website of the provider. + Simulator LABEL ANDROID IOS - Link auf Webseite des Anbieters klicken. + Simulator - The App opens automatically. + Continue LABEL ANDROID IOS - Die App öffnet sich automatisch. + Weiter + + + SmartDeleteBaseView - The AusweisApp2 will display who wants to access which data. + Smart-eID LABEL ANDROID IOS - Ihnen wird angezeigt, wer welche Ihrer Daten abfragen will. + Smart-eID - Start the process with a click on: + Please wait a moment. LABEL ANDROID IOS - Starten Sie den Vorgang mit: + Bitte warten Sie einen Moment. - Proceed to PIN entry + Send log LABEL ANDROID IOS - Weiter zur PIN-Eingabe + Protokoll senden - ... 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 - ...und platzieren Sie den Ausweis auf die NFC-Schnittstelle. + Wenn Sie die Funktionalität in Zukunft wieder nutzen möchten, müssen Sie die Smart-eID erneut einrichten. - Do not move device or ID card! + Reset Smart-eID LABEL ANDROID IOS - Gerät und Ausweis nicht bewegen! + Smart-eID zurücksetzen + + + 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 - 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. + Smart-eID löschen - 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 - 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. + Sie haben Ihre Smart-eID erfolgreich gelöscht. - 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 - Mehr Informationen zu kompatiblen Geräten finden Sie auf unserer %1Mobilgeräteliste%2. + Die Smart-eID konnte nicht erfolgreich von Ihrem Gerät gelöscht werden. - 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 + Back to start page + LABEL ANDROID IOS + Zur Startseite - six-digit PIN + You are about to delete the Smart-eID data that is currently stored on your device. LABEL ANDROID IOS - sechsstellige PIN + Sie sind dabei, die Daten der Smart-eID von Ihrem Gerät zu löschen. - 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! + Are you sure you want to delete the Smart-eID? + LABEL ANDROID IOS + Sind Sie sicher, dass Sie die Smart-eID löschen wollen? - This is only possible if you have exchanged the five-digit Transport PIN with a six-digit PIN beforehand. + Delete LABEL ANDROID IOS - Funktioniert nur, wenn Sie die fünfstellige Transport-PIN bereits in eine sechsstellige PIN geändert haben. + Löschen - Open YouTube video + Deleting Smart-eID LABEL ANDROID IOS - Öffne das YouTube-Video + Lösche Smart-eID - You can also watch this YouTube video explaining the process. + Delete the Smart-eID LABEL ANDROID IOS - Sie können sich auch dieses YouTube-Video ansehen das den Prozess erläutert. + Löschen der Smart-eID - TutorialReaderMethodSacMobile + SmartMainView + + Updating Smart-eID status... + LABEL ANDROID IOS + Status der Smart-eID wird aktualisiert... + - Tutorial: Smartphone as card reader + Smart-eID ready for use LABEL ANDROID IOS - Tutorial: Smartphone als Kartenleser + Smart-eID einsatzbereit - App on tablet or smartphone <b>without</b> NFC chip + Please wait a moment. LABEL ANDROID IOS - App auf Tablet oder Telefon <b>ohne</b> NFC-Chip + Bitte warten Sie einen Moment. - 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 - Smartphone <b>mit</b> NFC-Chip als Kartenleser + 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. - 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 - Installieren Sie die AusweisApp2 auf Ihrem Gerät ohne NFC <b>und</b> auf Ihrem NFC-fähigen Smartphone. + Prüfen Sie hier, ob Ihr Gerät für die Einrichtung einer Smart-eID geeignet ist. - Both devices have to be connected to the same WiFi network + Start check LABEL ANDROID IOS - Beide Geräte müssen im selben WLAN sein + Prüfung starten - Now choose "Remote" 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 - Öffnen Sie nun in der AusweisApp2 auf dem Smartphone den Bereich "Fernzugriff"... + Mit der Smart-eID können Sie die Online-Ausweisfunktion auch ohne Ausweiskarte nutzen. + + + SmartResetView - Now + Reset Smart-eID LABEL ANDROID IOS - Jetzt + Smart-eID zurücksetzen - Start pairing + You have successfully reset your Smart-eID. LABEL ANDROID IOS - Kopplung starten + Sie haben Ihre Smart-eID erfolgreich zurückgesetzt. - Pairing code + You are about to reset your Smart-eID data. This can also be used for troubleshooting as well. LABEL ANDROID IOS - Kopplungscode + Sie sind dabei, die Daten der Smart-eID auf Ihrem Gerät zurücksetzen. Dies kann auch zur Problembeseitigung verwendet werden. - appears! + Are you sure you want to reset the Smart-eID? LABEL ANDROID IOS - erscheint! + Sind Sie sicher, dass Sie die Smart-eID zurücksetzen wollen? - 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. + Reset + LABEL ANDROID IOS + Zurücksetzen - Now open the AusweisApp2 on your device <b>without</b> NFC and select <b>Configure remote service</b>. - LABEL IOS - Öffnen Sie nun die AusweisApp2 auf dem Gerät <b>ohne</b> NFC und wählen Sie <b>Fernzugriff konfigurieren</b> aus. + Resetting Smart-eID + LABEL ANDROID IOS + Setze Smart-eID zurück - 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. + Reset the Smart-eID + LABEL ANDROID IOS + Zurücksetzen der Smart-eID + + + SmartSettingsView - Now select <b>Settings</b>. + Smart-eID LABEL ANDROID IOS - Dort <b>Einstellungen</b> auswählen. + Smart-eID - Choose smartphone from list + Renew Smart-eID LABEL ANDROID IOS - Smartphone aus Liste wählen + Smart-eID erneuern - Enter pairing code next. + Renew your Smart-eID with current data LABEL ANDROID IOS - Dann Kopplungscode eingeben. + Smart-eID mit aktuellen Daten neu einrichten - Click link on the website of the provider on the device <b>without</b> NFC. + Delete Smart-eID LABEL ANDROID IOS - Auf dem Gerät <b>ohne</b> NFC Link auf Webseite des Anbieters klicken. + Smart-eID löschen - The App opens automatically. + Delete Smart-eID data from your device LABEL ANDROID IOS - Die App öffnet sich automatisch. + Smart-eID Daten von diesem Gerät löschen - The AusweisApp2 will display who wants to access which data. + Try Smart-eID LABEL ANDROID IOS - Ihnen wird angezeigt, wer welche Ihrer Daten abfragen will. + Smart-eID ausprobieren - Start the process with a click on: + Show Smart-eID data LABEL ANDROID IOS - Den Vorgang starten mit: + Smart-eID-Daten anzeigen - Proceed to PIN entry + Change Smart-eID PIN LABEL ANDROID IOS - Weiter zur PIN-Eingabe + Smart-eID-PIN ändern - Tap on WiFi + Change the chosen Smart-eID PIN LABEL ANDROID IOS - Tap auf WLAN + Selbstgewählte PIN der Smart-eID ändern + + + SmartSetupStartView - ... and place the ID card onto the NFC interface. + Smart-eID LABEL ANDROID IOS - ...und platzieren Sie den Ausweis auf die NFC-Schnittstelle. + 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 - Gerät und Ausweis nicht bewegen! + Sie sind dabei, eine Smart-eID auf Ihrem Gerät einzurichten. Um fortzufahren, benötigen Sie Ihren Ausweis, Ihre sechsstellige Karten-PIN sowie eine Internetverbindung. - 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 - 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. + Smart-eID einrichten - 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 - 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. + Smart-eID-Einrichtung + + + 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 - Mehr Informationen zu kompatiblen Geräten finden Sie auf unserer %1Mobilgeräteliste%2. + Sie sind dabei, Ihre Smart-eID zu erneuern. Um fortzufahren, benötigen Sie Ihren Ausweis, Ihre sechsstellige Karten-PIN sowie eine Internetverbindung. - 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 + 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 + Bitte beachten Sie, dass ihre aktuelle Smart-eID während des Prozesses Ihre Gültigkeit verliert und bis zur erfolgreichen Aktualisierung nicht verwendet werden kann. - six-digit PIN + Renew Smart-eID LABEL ANDROID IOS - sechsstellige PIN + Smart-eID erneuern - 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! + Renew the Smart-eID + LABEL ANDROID IOS + Erneuern der Smart-eID - 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 - Funktioniert nur, wenn Sie die fünfstellige Transport-PIN bereits in eine sechsstellige PIN geändert haben. + Smart-eID-Erneuerung - TutorialView + SmartView - Tutorial + Smart-eID LABEL ANDROID IOS - Tutorial + Smart-eID - What? + Check Smart-eID LABEL ANDROID IOS - Was? + Smart-eID prüfen + + + SmartWorkflow - Where? + Updating Smart-eID status... LABEL ANDROID IOS - Wo? + Status der Smart-eID wird aktualisiert... - How? + Smart-eID unsupported LABEL ANDROID IOS - Wie? + Smart-eID nicht unterstützt - Important! + Smart-eID disallowed LABEL ANDROID IOS - Wichtig! + Smart-eID nicht erlaubt - - - TutorialWhat - What is the online ID function? + Smart-eID LABEL ANDROID IOS - Was ist die Online-Ausweisfunktion? + Smart-eID - You can use it to authenticate yourself in the internet + Smart-eID not ready LABEL ANDROID IOS - Mit ihr weisen Sie sich sicher im Internet aus + Smart-eID nicht einsatzbereit - 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 - und erledigen damit Behördengänge oder geschäftliche Angelegenheiten einfach elektronisch! + Ihre Smart-eID ist einsatzbereit. Klicken Sie auf "Weiter", um fortzufahren. - Alright, but is it secure? + Please wait a moment. LABEL ANDROID IOS - Alles klar, nur ist das auch sicher? + Bitte warten Sie einen Moment. - 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 - Natürlich, dafür haben wir die sogenannte + Leider wird Smart-eID von Ihrem Gerät nicht unterstützt. + +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. - 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 - gegenseitige Authentifizierung + Leider wird die Nutzung Ihrer Smart-eID für diese Authentisierung durch den Provider nicht erlaubt. + +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. - ... 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 - ...sie stellt eine sichere Verbindung zwischen Ausweis und Anbieter her. + 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. - 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 + Continue + Weiter - 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 - und Sie stimmen der Abfrage mit Ihrer sechsstelligen PIN zu. + 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. Möchten Sie stattdessen eine Smart-eID einrichten, brechen Sie den aktuellen Vorgang bitte ab und starten Sie die Smart-eID-Einrichtung vom Startbildschirm. - ... is the provider authorized for this? - LABEL ANDROID IOS - ... und darf der das? + 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 - The provider needs an authorization of the Federal Office of Administration. - LABEL ANDROID IOS - Der Anbieter benötigt eine Berechtigung vom Bundesverwaltungsamt. + Are you satisfied with %1? + INFO ANDROID Header of the app rating popup. + Zufrieden mit der %1? - Certificate - LABEL ANDROID IOS - Zertifikat + We would be very grateful if you could leave a rating on the Google Play Store! + INFO ANDROID Content of the app rating popup. + Wir würden uns sehr über eine Bewertung im Google Play Store freuen! - Every time both participants authenticate each other... - LABEL ANDROID IOS - Es weisen sich also immer beide Seiten eindeutig aus... + Do not ask again + LABEL ANDROID + Ignorieren - ... and therefore your data is protected and securely transferred. - LABEL ANDROID IOS - ... so werden Ihre Daten geschützt und sicher übermittelt. + Rate app + LABEL ANDROID + App bewerten + + + TabbedReaderView - 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 + Card Readers + LABEL DESKTOP + Kartenleser - Open YouTube video - LABEL ANDROID IOS - Öffne das YouTube-Video + Smartphone as card reader + Smartphone als Kartenleser + + + USB card reader + USB Kartenleser - TutorialWhere + TechnologySwitch - Where can I use the online ID function? + NFC LABEL ANDROID IOS - Wo kann ich die Online-Ausweisfunktion nutzen? + NFC - On every website of a provider where you see this icon: + SMART LABEL ANDROID IOS - Überall, wo Sie auf der Webseite eines Online-Dienstes folgendes Logo sehen: + SMART - By the way, you can find many services directly in the AusweisApp2 <b>provider list</b>. + WiFi LABEL ANDROID IOS - Übrigens, viele Dienste finden Sie direkt in der <b>Anbieterliste</b> der AusweisApp2. + WLAN - The <b>integrated self-authentication</b> is a special service to view the data saved on your ID card. + SIM LABEL ANDROID IOS - Die <b>integrierte Selbstauskunft</b> ist ein spezieller Dienst, um Daten einzusehen, die auf Ihrem Ausweis gespeichert sind. + SIM + + + + TitleBar + + Start page + LABEL DESKTOP + Startseite - And this is how it works - LABEL ANDROID IOS - Und so funktioniert's + Settings + Einstellungen - The AusweisApp2 will always display <b>who</b> wants to access <b>which</b> of your data. - LABEL ANDROID IOS - Die AusweisApp2 zeigt Ihnen immer an, wer welche Ihrer Daten abfragen will. + Open settings view of %1 + Öffne die %1 Einstellungen - To allow the shown service access to the requested data click "Proceed to PIN entry" - LABEL ANDROID IOS - Um dem angezeigten Dienst Zugriff auf die angefragten Daten zu gewähren drücken Sie auf "Weiter zur PIN-Eingabe" + Notifications + Benachrichtigungen + + + Show in-app notifications of %1 + Zeige den interne Benachrichtigungsdialog der %1 - 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. + Title bar + LABEL DESKTOP + Titelleiste + + + TitleBarNavigation - 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. + Cancel + LABEL ANDROID IOS + Abbrechen - 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. + Back + LABEL ANDROID IOS + Zurück + + + TransportPinReminderView - Do not move your iPhone during the procedure! - LABEL IOS - iPhone während des gesamten Vorgangs nicht bewegen! + Do you know your six-digit ID card PIN? + LABEL ANDROID IOS + Kennen Sie Ihre sechsstellige Karten-PIN? - Do not move your device during the procedure! - LABEL ANDROID - Gerät während des gesamten Vorgangs nicht bewegen! + No + LABEL ANDROID IOS + Nein - 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 + Yes + LABEL ANDROID IOS + Ja - 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 - sechsstellige PIN + 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. - 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! + To set up a Smart-eID you also need to have assigned a six-digit PIN beforehand. + LABEL ANDROID IOS + Auch für die Einrichtung der Smart-eID müssen Sie zuvor die sechsstellige Karten-PIN gesetzt haben. @@ -5976,14 +4315,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! @@ -6010,6 +4349,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 @@ -6323,7 +4670,7 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au d. MMMM yyyy, hh:mm:ss AP - LABEL DESKTOP Timestamp, formatted according to the selected language + LABEL DESKTOP Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString d. MMMM yyyy, HH:mm:ss 'Uhr' @@ -6462,9 +4809,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 @@ -6472,9 +4819,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 @@ -6533,7 +4880,7 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au dd.MM.yyyy, hh:mm:ss - LABEL DESKTOP Timestamp + LABEL DESKTOP 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:ss @@ -6764,7 +5111,7 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au The program received an unknown message from the server. - ERROR_MASKED ALL_PLATFORMS The type of a POAS message could not be determined. + ERROR_MASKED ALL_PLATFORMS The type of a PAOS message could not be determined. Die Anwendung hat eine unbekannte Nachricht vom Server erhalten. @@ -6798,9 +5145,9 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au Die Authentisierung ist fehlgeschlagen. - Your card reader does not support Extended Length communication and cannot be used to read the ID card. Unfortunately, the %1 has no influence on this restriction. - ERROR ALL_PLATFORMS DidAuthenticateEAC2 was not able to send the certificates to the card because the card reader does not support extended length. - Ihr Kartenleser unterstützt keine Extended Length Kommunikation und kann nicht zum Auslesen des Ausweises genutzt werden. Auf diese Einschränkung hat die %1 leider keinen Einfluss. + The length of the data sent to the ID card was not accepted. Either the data is faulty or your card reader does not support Extended Length communication and cannot be used to read the ID card. Unfortunately, the %1 has no influence on this restriction. + ERROR ALL_PLATFORMS A card command failed because the data length was wrong or the card reader does not support Extended Length. + Die Länge der an den Ausweis gesendeten Daten wurde nicht akzeptiert. Entweder sind die Daten fehlerhaft oder Ihr Kartenleser unterstützt keine Extended Length Kommunikation und kann nicht zum Auslesen des Ausweises genutzt werden. Auf diese Einschränkung hat die %1 leider keinen Einfluss. No certificate description available. @@ -6828,7 +5175,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. @@ -6847,11 +5194,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 @@ -6968,9 +5310,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. @@ -7017,11 +5359,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. @@ -7033,9 +5370,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). @@ -7082,12 +5419,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. - - - governikus::HistoryModelSearchFilter - dd.MM.yyyy - dd.MM.yyyy + 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. + + + The server could not process the client request. + ERROR_MASKED ALL_PLATFORMS + Der Server konnte die Anfrage des Clients nicht verarbeiten. + + + 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 @@ -7139,6 +5519,7 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au dd.MM.yyyy hh:mm:ss + 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:ss @@ -7198,6 +5579,7 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au governikus::NotificationModel hh:mm:ss + LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString HH:mm:ss @@ -7208,11 +5590,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. @@ -7228,11 +5605,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. @@ -7263,103 +5635,56 @@ 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 - dd.MM.yyyy HH:mm - - - Provider: - LABEL ALL_PLATFORMS - Anbieter: - - - Purpose: - LABEL ALL_PLATFORMS - Zweck: - - Read access: - LABEL ALL_PLATFORMS - Lesezugriff: + 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. - Write access (update): - LABEL ALL_PLATFORMS - Schreibzugriff (Aktualisierung): + 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. - dd.MM.yyyy - LABEL ALL_PLATFORMS - dd.MM.yyyy + 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. + + + governikus::PinResetInformationModel - hh:mm AP - LABEL ALL_PLATFORMS - HH:mm + https://www.personalausweisportal.de/EN + https://www.personalausweisportal.de/DE - At %1 %2 the following data were saved: - LABEL ALL_PLATFORMS - Die folgenden Daten wurden hier %1 %2 gespeichert: + If you have forgotten your ID card PIN or do not have access to the PUK, you may turn to the competent authority and set a new PIN there.<br/><br/>For further information, please visit the ID card portal. + LABEL ALL_PLATFORMS Hint text for requested PUK but both, PUK and PIN are not known. + Sollten Sie Ihre Karten-PIN vergessen haben oder Ihnen die PUK nicht vorliegen, können Sie sich an die zuständige Behörde wenden und dort eine neue PIN festlegen.<br/><br/>Weitere Informationen erhalten Sie auf dem Personalausweisportal. - History - LABEL ALL_PLATFORMS - Verlauf + If you know neither your Transport PIN nor your ID card PIN, you may turn to the competent authority and set a new PIN there.<br/><br/>For further information, please visit the ID card portal. + LABEL ALL_PLATFORMS Hint text for requested Transport PIN but both, Transport PIN and PIN are not known. + Ist Ihnen weder Ihre Transport-PIN noch Ihre Karten-PIN bekannt, können Sie sich an die zuständige Behörde wenden und dort eine neue PIN festlegen.<br/><br/>Weitere Informationen erhalten Sie auf dem Personalausweisportal. - Entry - LABEL ALL_PLATFORMS - Eintrag + If you cannot recall your ID card PIN, you may turn to the competent authority and set a new PIN there.<br/><br/>For further information, please visit the ID card portal. + LABEL ALL_PLATFORMS Hint text for PIN but it is unknown. + Wenn Sie Ihre Karten-PIN vergessen haben, können Sie sich an die zuständige Behörde wenden und dort eine neue PIN festlegen.<br/><br/>Weitere Informationen erhalten Sie auf dem Personalausweisportal. - Content - LABEL ALL_PLATFORMS - Inhalt + You may turn to the competent authority and set a new ID card PIN there.<br/><br/>For further information, please visit the ID card portal. + LABEL ALL_PLATFORMS Hint when a workflow failed because of a blocked PUK + Sie können sich an die zuständige Behörde wenden und dort eine neue Karten-PIN festlegen.<br/><br/>Weitere Informationen erhalten Sie auf dem Personalausweisportal. - 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: + Please contact the competent authority to activate the eID function.<br/><br/>For further information, please visit the ID card portal. + LABEL ALL_PLATFORMS Hint when a workflow failed because the eID function was not activated + Bitte wenden Sie sich an die zuständige Behörde, um die Online-Ausweisfunktion zu aktivieren.<br/><br/>Weitere Informationen erhalten Sie auf dem Personalausweisportal. - Information + Open website LABEL ALL_PLATFORMS - Information - - - - governikus::PinResetInformationModel - - https://www.personalausweisportal.de/EN - https://www.personalausweisportal.de/DE + Öffne Webseite You cannot use the PUK to reset your previously set card PIN. If you forgot your card PIN, you can use the PIN Reset Service to request a new PIN. @@ -7386,46 +5711,20 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au LABEL ALL_PLATFORMS Hint when a workflow failed because of a blocked PUK 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; + 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. - mobile costs may vary. - INFO ALL_PLATFORMS Cell phone charges when calling the hotline. - Mobilfunkpreise abweichen. + If you have forgotten your ID 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. - mobile costs %1 - Mobilfunkpreise max. %1 + You can use the PIN Reset Service to request a new card PIN free of charge. + LABEL ALL_PLATFORMS Hint text for requested Transport PIN but both, Transport PIN and PIN, are not known. + Dann fordern Sie jetzt mithilfe des PIN-Rücksetzdienstes kostenlos eine neue Karten-PIN an. @@ -7455,18 +5754,9 @@ 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 HH:mm:ss @@ -7478,14 +5768,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? @@ -7522,11 +5812,6 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au LABEL ALL_PLATFORMS Gekoppelt, aber nicht unterstützt - - Paired, but unavailable - LABEL ALL_PLATFORMS - Gekoppelt, aber nicht verfügbar - Unsupported LABEL ALL_PLATFORMS @@ -7539,17 +5824,18 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au 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 - online help - Is embedded in a sentence. - Online-Hilfe + Unavailable + LABEL ALL_PLATFORMS + Nicht verfügbar - 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. + Click to pair + LABEL ALL_PLATFORMS + Klicken zum Koppeln @@ -7582,6 +5868,11 @@ Please enable NFC to use your smartphone as a card reader (SaC). Bitte aktivieren Sie NFC, um Ihr Smartphone als Kartenleser (SaK) benutzen zu können. + + Pairing with %1 successful. + LABEL ALL_PLATFORMS + Die Kopplung mit %1 war erfolgreich. + governikus::RemoteServiceSettings @@ -7605,14 +5896,17 @@ Bitte aktivieren Sie NFC, um Ihr Smartphone als Kartenleser (SaK) benutzen zu k dd.MM.yyyy + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString dd.MM.yyyy xx.MM.yyyy + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString with unknown day xx.MM.yyyy xx.xx.yyyy + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString with unknown day and month xx.xx.yyyy @@ -7679,24 +5973,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. @@ -7724,11 +6068,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 @@ -7755,6 +6109,14 @@ Bitte aktivieren Sie NFC, um Ihr Smartphone als Kartenleser (SaK) benutzen zu k Zugriff verweigert. + + governikus::StateEstablishPaceChannel + + The secure channel is opened + INFO ALL_PLATFORMS First status message after the PIN was entered. + Der sichere Kanal wird geöffnet + + governikus::StateFinalizePersonalization @@ -7803,22 +6165,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 @@ -7843,18 +6195,11 @@ Bitte aktivieren Sie NFC, um Ihr Smartphone als Kartenleser (SaK) benutzen zu k - governikus::StateWriteHistory + governikus::StateUpdateSupportInfo - Validity: -%1 - %2 - LABEL ALL_PLATFORMS - Gültigkeit: -%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 - Ergebnisse werden vorbereitet + Checking Smart-eID status + LABEL ANDROID IOS + Überprüfe Smart-eID-Status @@ -7888,8 +6233,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 @@ -7909,9 +6254,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 @@ -7941,26 +6286,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 @@ -7982,6 +6319,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 @@ -8016,13 +6358,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 @@ -8038,9 +6405,7 @@ Bitte aktivieren Sie NFC, um Ihr Smartphone als Kartenleser (SaK) benutzen zu k The program remains available via the icon in the system tray. Click on the %1 icon to reopen the user interface. - INFO DESKTOP Content of the popup that is shown when the AA2 is closed for the first time. ----------- -INFO DESKTOP Content of the popup that is shown when the AA2 is closed and a workflow is still active and the close/minimize info was not disabled. + INFO DESKTOP Content of the popup that is shown when the AA2 is closed and the close/minimize info was not disabled. Das Programm steht weiterhin im Infobereich zur Verfügung. Klicken Sie auf das Symbol der %1, um die Anwendung wieder zu öffnen. @@ -8087,5 +6452,25 @@ INFO DESKTOP Content of the popup that is shown when the AA2 is closed and a wor INFO ANDROID IOS Hint that is shown if the users pressed the "back" button on the top-most navigation level for the first time (a second press closes the app). Um die Anwendung zu schließen, drücken Sie zweimal schnell die Zurück-Taste. + + The program remains available via the icon in the menu bar. Click on the %1 icon to reopen the user interface. + 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 620dd89f9..a545fca43 100644 --- a/resources/translations/ausweisapp2_ru.ts +++ b/resources/translations/ausweisapp2_ru.ts @@ -5,7 +5,7 @@ DvcsAttributes revision - 52a5aa47f692 + 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,41 +157,24 @@ 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 + Аутентификация с помощью провайдера Online identification with Transport PIN is not possible. The self-selected, six-digit ID card PIN is mandatory to use the eID function. - + Онлайн-идентификация с помощью временного PIN-кода невозможна. Для использования функции eID необходим 6-значный PIN-код идентификационной карты, который пользователь создает самостоятельно. Do you know your six-digit ID card PIN? Вы знаете 6-значный PIN-код идентификационной карты? + + 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» не было выполнено, поскольку оно не отвечало на попытки соединения. Снова выполните сопряжение устройства для его использования в качестве устройства чтения карт. + BaseConfirmationPopup @@ -205,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 @@ -302,13 +253,6 @@ LABEL ANDROID IOS A11y button to confirm the PIN and start the provider authenti Версия OpenSSL - - CancelAction - - Cancel - Отмена - - CardPositionView @@ -339,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-устройства чтения карт @@ -353,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-код больше не действует. @@ -414,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-код. @@ -446,55 +417,20 @@ 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 указан внизу справа на передней стороне идентификационной карты. + 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» не было выполнено, поскольку оно не отвечало на попытки соединения. Снова выполните сопряжение устройства для его использования в качестве устройства чтения карт. - 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 DESKTOP + Внимание: вы можете использовать 5-значный временный PIN-код только один раз — для смены 6-значного PIN-кода. Если вы уже установили 6-значный PIN-код, 5-значный временный PIN-код больше не действует. @@ -505,34 +441,34 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin Какой у вас PIN-код? - 6-digit PIN + Six-digit PIN LABEL ALL_PLATFORMS - + 6-значный PIN-код Set by yourself LABEL ALL_PLATFORMS - + Создается пользователем самостоятельно - 5-digit Transport PIN + Five-digit Transport PIN LABEL ALL_PLATFORMS - + 5-значный временный PIN-код Received by mail in PIN letter LABEL ALL_PLATFORMS - + Получен по почте в письме с PIN-кодом No PIN LABEL ALL_PLATFORMS - + PIN-код отсутствует Lost, forgotten, or never received it LABEL ALL_PLATFORMS - + Утерян, забыт или не получен вовсе @@ -665,7 +601,7 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin Your mobile device has no NFC interface. This is required to read the ID card. However, you can use a separate smartphone as card reader to utilize the eID function.<br><br>You can find smartphones compatible with the %1 on our website. LABEL ANDROID IOS - В вашем мобильном устройстве нет интерфейса NFC. Он требуется для считывания идентификационной карты. Вы также можете использовать другой смартфон в качестве устройства чтения карт для онлайн-идентификации.<br><br>Список совместимых с %1 смартфонов см. на нашем сайте. + В вашем мобильном устройстве нет интерфейса NFC. Он требуется для считывания идентификационной карты. Вы можете воспользоваться функцией eID на другом смартфоне, используемом в качестве устройства чтения карт.<br><br>Список совместимых с %1 смартфонов см. на нашем сайте. Open website @@ -677,11 +613,6 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin LABEL ANDROID IOS Поддерживаемые карты не обнаружены - - No supported ID card was detected. The %1 supports:<p><ul><li>German ID cards</li><li>Electronic residence permits (eAT)</li><li>eID cards</li></ul></p>If you have used one of the above documents and this error message still appears, please restart the check.<br><br>Tip: Try a different card position, make sure that you do not move the ID card during the check and that there are no other NFC cards (e.g. credit cards) near the device. - LABEL ANDROID IOS - Поддерживаемые идентификационные карты не обнаружены. %1 поддерживает:<p><ul><li>идентификационные карты Германии;</li><li>электронные разрешения на временное пребывание (РВП);</li><li>карты eID.</li></ul></p>Если вы используете один из перечисленных документов, но данное сообщение об ошибке все равно появляется, перезапустите проверку.<br><br>Совет: попробуйте изменить положение карты; убедитесь в том, что идентификационная карта не смещается во время проверки и рядом с устройством нет других карт с NFC (например, банковских карт). - Retry LABEL ANDROID IOS @@ -695,7 +626,7 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin The NFC interface of your mobile device does not support Extended Length communication and cannot be used to read the ID card. Unfortunately, the %1 has no influence on this restriction.<br><br>You can find smartphones compatible with the %1 on our website. LABEL ANDROID IOS - Интерфейс NFC вашего мобильного устройства не поддерживает связь по протоколу с расширенной длиной и не может использоваться для считывания идентификационной карты. %1 не имеет какого-либо влияния на это ограничение.<br><br>Список совместимых с %1 смартфонов см. на нашем сайте. + Интерфейс NFC вашего мобильного устройства не поддерживает связь по протоколу с расширенной длиной и не может использоваться для считывания идентификационной карты. К сожалению, %1 не влияет на это ограничение.<br><br>Список совместимых с %1 смартфонов см. на нашем сайте. ID card access failed @@ -725,7 +656,7 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin The ID card PIN has been entered incorrectly twice in a row. This is why you must first enter the six-digit Card Access Number (CAN) for the next identification process. You can find it at the bottom right of the front of your ID card.<br><br>You may now try the function: "See my personal data". There you can also use the CAN to unblock the ID card PIN. LABEL ANDROID IOS - PIN-код идентификационной карты введен неправильно два раза подряд. Поэтому перед следующей попыткой идентификации необходимо ввести 6-значный код доступа (CAN). Он расположен внизу справа на передней стороне идентификационной карты.<br><br>Теперь проверьте работу функции. «Просмотреть персональные данные». Вы также можете использовать код CAN для разблокировки PIN-кода идентификационной карты. + PIN-код идентификационной карты введен неправильно два раза подряд. Поэтому перед следующей попыткой идентификации необходимо ввести 6-значный код доступа (CAN). Он указан внизу справа на передней стороне вашей идентификационной карты.<br><br>Проверьте функцию: «Просмотреть персональные данные». Вы также можете использовать код CAN для разблокировки PIN-кода идентификационной карты. Continue @@ -740,7 +671,17 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin The ID card PIN has been entered incorrectly thrice. Therefore, you must first enter the ten-digit PUK during the next authentication process. You can find it in the PIN letter you received after applying for your ID card.<br><br>You may now try the function: "See my personal data". Have your PUK ready to unlock the ID card PIN. LABEL ANDROID IOS - PIN-код идентификационной карты введен неправильно трижды. Поэтому при следующем процессе аутентификации сначала необходимо ввести 10-значный PUK-код. Он указан в письме с PIN-кодом, которое вы получили после заказа идентификационной карты.<br><br>Теперь проверьте работу функции. «Просмотреть персональные данные». Подготовьте PUK-код для разблокировки PIN-кода идентификационной карты. + PIN-код идентификационной карты введен неправильно трижды. Поэтому при следующем процессе аутентификации сначала необходимо ввести 10-значный PUK-код. Он указан в письме с PIN-кодом, которое вы получили после заказа идентификационной карты.<br><br>Проверьте функцию: «Просмотреть персональные данные». Подготовьте PUK-код для разблокировки PIN-кода идентификационной карты. + + + Try a different card position, make sure that you do not move the ID card during the check and that there are no other NFC cards (e.g. credit cards) near the device. + LABEL ANDROID IOS + попробуйте изменить положение карты; убедитесь в том, что идентификационная карта не смещается во время проверки и рядом с устройством нет других карт с NFC (например, банковских карт). + + + No supported ID card was detected. The %1 supports:<p><ul><li>German ID cards</li><li>Electronic residence permits (eAT)</li><li>eID cards for citizen of the EU/EEA/</li></ul></p>If you have used one of the above documents and this error message still appears, please restart the check. + LABEL ANDROID IOS + @@ -787,101 +728,79 @@ 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. - Проверьте функцию: «Просмотреть персональные данные». Для продолжения нажмите кнопку «Продолжить». + 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. - Supported + Smart-eID not supported LABEL ANDROID IOS - Поддерживается + Smart-eID не поддерживается - Not supported + Possible causes are: LABEL ANDROID IOS - Не поддерживается + Возможные причины - Prepared + The setup has not been completed. LABEL ANDROID IOS - Подготовлено + Создание не завершено. - Not prepared + The Smart-eID PIN has been entered incorrectly three times. LABEL ANDROID IOS - Не подготовлено + PIN-код для Smart-eID трижды введен неправильно. - Set up + The %1 has been uninstalled temporarily. LABEL ANDROID IOS - Настроено + %1 временно удалено. - Not set up + You may continue with the setup of the Smart-eID. LABEL ANDROID IOS - Не настроено + Вы можете продолжить настройку Smart-eID. - Invalid + Continue LABEL ANDROID IOS - Недействительно + Продолжить - Ready for use + Your device meets the technical requirements for Smart-eID. You may now continue the setup process. LABEL ANDROID IOS - Готово к использованию + Ваше устройство соответствует техническим требованиям для Smart-eID. Теперь можно продолжить процесс настройки. - - - CheckSmartSuggestionView - Unknown result code: %1 + Smart-eID supported LABEL ANDROID IOS - Неизвестный код результата: %1 + Электронная идентификационная карта Smart-eID не поддерживается - Updating Smart-eID status... - LABEL ANDROID IOS - Обновление статуса Smart-eID… - - - Please wait a moment. - LABEL ANDROID IOS - Подождите. - - - Smart-eID not supported - 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. - LABEL ANDROID IOS - Ваше мобильное устройство не соответствует техническим требованиям для Smart-eID.<br><br>Вы можете проверить пригодность вашего устройства и идентификационной карты для использования функции eID. - - - Check device and ID card - 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, однако созданная электронная идентификационная карта Smart-eID недействительна. Smart-eID invalid @@ -889,87 +808,14 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin Электронная идентификационная карта Smart-eID недействительна - 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 недействительна. - - - 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. - - - - CheckSmartView - - Check Smart-eID - LABEL ANDROID IOS - Проверить Smart-eID - - - Your device needs to meet the technical requirements to use the Smart-eID function. - LABEL ANDROID IOS - Ваше устройство должно соответствовать техническим требованиям для использования функций Smart-eID. - - - Check here if your device is suitable to set up a Smart-eID. + Smart-eID check failed LABEL ANDROID IOS - Проверьте здесь, подходит ли ваше устройство для создания Smart-eID. + Сбой проверки Smart-eID - Start check + Back LABEL ANDROID IOS - Запуск проверки + Назад @@ -984,25 +830,38 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin LABEL DESKTOP Сопряжение устройства… + + + DarkModeButtons - The device "%1" has been paired. - Устройство «%1» сопряжено. + System + LABEL ALL_PLATFORMS + Система - Pairing to "%1" failed: - ERROR DESKTOP An error occurred while pairing the device. - Сбой сопряжения «%1»: + Dark + LABEL ALL_PLATFORMS + Темная тема + + + Light + LABEL ALL_PLATFORMS + Светлая тема + + + Set the app appearance to system mode + LABEL ALL_PLATFORMS + Установить для приложения тему в зависимости от режима системы - - - DataGroup - selected - выбрано + Set the app appearance to dark mode + LABEL ALL_PLATFORMS + Установить для приложения темную тему - not selected - не выбрано + Set the app appearance to light mode + LABEL ALL_PLATFORMS + Установить для приложения светлую тему @@ -1017,11 +876,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 @@ -1037,6 +891,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 + Показывать напоминание временного PIN-кода, сохранять обратную связь и закрывать диалоговые окна с напоминаниями. + DecisionView @@ -1045,11 +909,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 @@ -1119,11 +978,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 @@ -1134,11 +988,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 @@ -1164,6 +1013,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 + Режим разработчика деактивирует некоторые проверки безопасности, и процесс аутентификации продолжается даже при возникновении ошибок. Пропущенные ошибки будут отображены как уведомления. Режим разработчика можно использовать только с тестовой ИОК. + DevicesListDelegate @@ -1174,15 +1038,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 @@ -1204,145 +1059,106 @@ 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 ANDROID_TABLET IOS_TABLET + LABEL IOS ANDROID Вы собираетесь пройти самоидентификацию для следующего провайдера: - - Provider - LABEL IOS_PHONE ANDROID_PHONE ----------- -LABEL ANDROID_TABLET IOS_TABLET - Провайдер - - - Touch for more details - LABEL IOS_PHONE ANDROID_PHONE - Нажмите для получения подробной информации - EnterPasswordView @@ -1351,11 +1167,6 @@ LABEL ANDROID_TABLET IOS_TABLET LABEL DESKTOP Попытки - - Remaining ID card PIN attempts: %1 - LABEL DESKTOP - Осталось попыток ввода PIN-кода идентификационной карты: %1 - Enter CAN LABEL DESKTOP @@ -1405,13 +1216,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. @@ -1468,11 +1272,6 @@ INFO ANDROID IOS A new six-digit ID card PIN needs to be supplied. Подтвердите новый 6-значный PIN-код идентификационной карты. - - Start the pairing on your smartphone and enter the pairing code shown there in order to use your smartphone as a card reader (SaC). - INFO DESKTOP The pairing code needs to be supplied. - Запустите сопряжение на смартфоне и введите указанный в смартфоне код сопряжения для использования смартфона в качестве устройства чтения карт (SaC). - Unknown password type: INFO DESKTOP Error message during PIN/CAN/PUK input procedure, the requested password type is unknown; internal error. @@ -1504,18 +1303,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 становится недействительной, ее необходимо создать повторно. @@ -1556,61 +1346,89 @@ 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 + Вы дважды ввели неправильный 6-значный PIN-код для Smart-eID. После третьей попытки неправильного ввода вы больше не сможете использовать Smart-eID, и ее придется настроить еще раз. + Send CAN LABEL DESKTOP ---------- LABEL ANDROID IOS - + Отправить CAN-код Send PUK LABEL DESKTOP ---------- LABEL ANDROID IOS - + Отправить PUK-код Send pairing code LABEL DESKTOP ---------- LABEL ANDROID IOS - + Отправить код сопряжения Send new ID card PIN LABEL DESKTOP ---------- LABEL ANDROID IOS - + Отправить новый PIN-код идентификационной карты Send Transport PIN LABEL DESKTOP ---------- LABEL ANDROID IOS - + Отправить временный PIN-код Send Smart-eID PIN LABEL DESKTOP ---------- LABEL ANDROID IOS - + Отправить PIN-код для Smart-eID Send new Smart-eID PIN LABEL DESKTOP ---------- LABEL ANDROID IOS - + Отправить новый PIN-код для Smart-eID Send ID card PIN LABEL DESKTOP ---------- LABEL ANDROID IOS - + Отправить PIN-код идентификационной карты + + + Send confirmation of new ID card PIN + LABEL ANDROID IOS + Отправить подтверждение нового PIN-кода идентификационной карты + + + Send confirmation of new Smart-eID PIN + LABEL ANDROID IOS + Отправить подтверждение нового PIN-кода для Smart-eID + + + Enter the pairing code shown on your smartphone. + INFO DESKTOP The pairing code needs to be supplied. + Введите указанный в смартфоне код сопряжения. + + + + GCollapsible + + Currently selected is %1 + LABEL ANDROID IOS + В настоящее время выбрано %1 @@ -1637,11 +1455,6 @@ LABEL ANDROID IOS GeneralSettings - - Language selection - LABEL DESKTOP - Выбор языка - Behavior LABEL DESKTOP @@ -1653,52 +1466,63 @@ 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. + В режиме разработчика оповещения включаются принудительно. - Close after authentication + Network LABEL DESKTOP - Закрытие после аутентификации + Сеть - Use internal notifications + Use the proxy (%1) specified during the installation. LABEL DESKTOP - Включение внутренних оповещений + Используйте указанный при установке прокси-сервер (%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. - В режиме разработчика оповещения включаются принудительно. + Appearance + LABEL DESKTOP + Внешний вид - Network + Use the system font LABEL DESKTOP - Сеть + Использовать системный шрифт - Use the proxy (%1) specified during the installation. + Toggling will restart the %1 LABEL DESKTOP - Используйте указанный при установке прокси-сервер (%1). + Переключение приведет к перезапуску %1 + + + Close %1 after authentication + LABEL DESKTOP + Закрыть %1 после аутентификации + + + Show notifications inside of %1 + LABEL DESKTOP + Показывать уведомления внутри %1 + + + Auto-start %1 after boot and add a tray icon + LABEL WINDOWS Text for auto-start option + Автозапуск %1 после загрузки + + + Change language + LABEL DESKTOP + Изменить язык GeneralWorkflow - - 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 не было выполнено, поскольку оно не отвечало на попытки соединения. Снова выполните сопряжение устройства для его использования в качестве устройства чтения карт. - Attempts LABEL DESKTOP Попытки - - Remaining ID card PIN attempts: %1 - Осталось попыток ввода PIN-кода идентификационной карты: %1 - Step %1 of 3 Шаг %1 из 3 @@ -1728,16 +1552,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. @@ -1754,250 +1568,28 @@ LABEL ANDROID IOS Перейти к настройкам устройства чтения карт - More information - LABEL DESKTOP - Дополнительные сведения - - - - Hint - - Hint - Совет - - - - HistoryListItem - - Click to view details of history entry. - Щелкните, чтобы просмотреть подробную информацию о записи журнала. - - - today - LABEL ANDROID IOS - сегодня - - - yesterday - вчера - - - dd.MM.yyyy - dd.MM.yyyy - - - Tap for more details - LABEL ANDROID IOS - Нажмите для получения подробной информации - - - - HistoryListViewDelegate - - Delete entry - LABEL ANDROID - Удалить запись - - - Delete history entry: %1 - INFO IOS Accessible name for the trash icon of a history entry. - Удалить запись журнала: %1 - - - - HistoryRemovalTimePeriodControl - - Time period - LABEL DESKTOP - Временной промежуток - - - Past hour - LABEL DESKTOP - Последний час - - - Past day - LABEL DESKTOP - Последний день - - - Past week - LABEL DESKTOP - Последняя неделя - - - Last four weeks - LABEL DESKTOP - Последние четыре недели - - - All history - LABEL DESKTOP - Весь журнал - - - - HistoryView - - Delete history? - INFO DESKTOP Header of the confirmation dialog to clear the entire authentication history. - Удалить журнал? - - - All history entries will be deleted. - INFO DESKTOP Content of the confirmation dialog to clear the entire authentication history. - Все записи журнала будут удалены. - - - Deleted %1 entries from the history. - INFO DESKTOP Feedback how many history entries were removed. - Удалено записей из журнала: %1. - - - History - LABEL DESKTOP - Журнал - - - Search in history - LABEL DESKTOP - Поиск в журнале + 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. + Идентификационная карта не обнаружена. Следуйте инструкциям в смартфоне (подключен к %1), чтобы использовать его в качестве устройства чтения карт. - today - сегодня - - - yesterday - вчера - - - dd.MM.yyyy - dd.MM.yyyy - - - 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 - Удалить + 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). + Следуйте инструкциям в смартфоне (подключен к %1) или вставьте идентификационную карту в устройство чтения карт. - 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 - dd.MM.yyyy - - - Write access (update) - LABEL DESKTOP ----------- -LABEL ANDROID IOS - Доступ для записи (обновление) - - - Read access - LABEL DESKTOP ----------- -LABEL ANDROID IOS - Доступ для чтения - + Hint - Terms of usage + Hint LABEL DESKTOP ---------- LABEL ANDROID IOS - Условия использования - - - - HistoryViewTitleBarControls - - Delete all entries - LABEL ANDROID - Удалить все записи + Совет - LanguageButtons + LanguageButtonData German LABEL ALL_PLATFORMS @@ -2039,14 +1631,6 @@ LABEL ANDROID IOS Использовать русский язык - - LanguageSelectionPopup - - Select language - LABEL ANDROID IOS - Выбрать язык - - LicenseInformation @@ -2057,16 +1641,16 @@ LABEL ANDROID IOS LocalNetworkInfo - - To be able to use your smartphone as card reader (SaC), please make sure that access to the local network is allowed. - INFO IOS Let user know to check the application settings for local network permission - Чтобы использовать смартфон в качестве устройства чтения карт (SaC), убедитесь в наличии доступа к локальной сети. - 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 @@ -2074,10 +1658,6 @@ LABEL ANDROID IOS Share log Поделиться файлом журнала - - Delete log - Удалить файл журнала - Delete all logs Удалить все файлы журнала @@ -2100,31 +1680,14 @@ LABEL ANDROID IOS LABEL DESKTOP Файлы журнала (*.log) - - Delete log - LABEL DESKTOP ----------- -LABEL ANDROID IOS - Удалить файл журнала - The current log will be automatically deleted at exit. Текущий файл журнала будет автоматически удален при выходе. - - Delete old logs - LABEL DESKTOP - Удалить старые файлы журнала - Detach log viewer Показать файл журнала отдельно - - Delete selected log - LABEL DESKTOP - Удалить выбранный файл журнала - All old logs will be deleted. INFO DESKTOP All logfiles are about to be removed, user confirmation required. @@ -2132,13 +1695,6 @@ LABEL ANDROID IOS INFO ANDROID IOS All logfiles are about to be removed, user confirmation required. Все старые файлы журнала будут удалены. - - The log will be deleted. - INFO DESKTOP The current logfile is about to be removed, user confirmation required. ----------- -INFO ANDROID IOS The current logfile is about to be removed, user confirmation required. - Файл журнала будет удален. - Log LABEL ANDROID IOS @@ -2150,12 +1706,16 @@ INFO ANDROID IOS The current logfile is about to be removed, user confirmation r Delete all logs - LABEL ANDROID IOS + LABEL DESKTOP +---------- +LABEL ANDROID IOS Удалить все файлы журнала Delete - LABEL ANDROID IOS + LABEL DESKTOP +---------- +LABEL ANDROID IOS Удалить @@ -2169,14 +1729,14 @@ INFO ANDROID IOS The current logfile is about to be removed, user confirmation r Фильтр - Select level: + Level LABEL ANDROID IOS - Выберите уровень: + Уровень - Select category: + Category LABEL ANDROID IOS - Выберите категорию: + Категория Currently there are no log entries matching your filter. @@ -2184,6 +1744,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 @@ -2191,48 +1759,21 @@ 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 Справка - - Start page - LABEL ANDROID IOS - Начальная страница - Check device and ID card LABEL ANDROID IOS Проверить устройство и идентификационную карту - - Change my (Transport) PIN - LABEL ANDROID IOS - Изменить (временный) PIN-код - See my personal data LABEL ANDROID IOS @@ -2243,6 +1784,21 @@ LABEL ANDROID IOS LABEL ANDROID IOS Smart-eID + + Two finger swipe to scroll. + Пролистывание двумя пальцами. + + + Item %1 of %2 + Элемент %1 из %2 + + + Change PIN + LABEL DESKTOP +---------- +LABEL ANDROID IOS + Изменить PIN-код + MoreInformationLink @@ -2263,26 +1819,19 @@ LABEL ANDROID IOS General - LABEL DESKTOP + LABEL DESKTOP +---------- +LABEL ANDROID IOS Общая информация - - Diagnosis and logs - LABEL DESKTOP - Диагностика и файлы журнала - Version information - LABEL DESKTOP ----------- -LABEL ANDROID IOS + LABEL ANDROID IOS Информация о версии Software license - LABEL DESKTOP ----------- -LABEL ANDROID IOS + LABEL DESKTOP Лицензия на программное обеспечение @@ -2293,274 +1842,119 @@ LABEL ANDROID IOS Примечания к версии - Help & Feedback + Privacy statement LABEL ANDROID IOS - Помощь и обратная связь + Положение о конфиденциальности - Tutorial + Accessibility statement LABEL ANDROID IOS - Руководство + Заявление о доступности - Do you want to know how to use %1? + Rate %1 LABEL ANDROID IOS - Хотите узнать, как пользоваться %1? + Оценить %1 - Video tutorials + Logs LABEL ANDROID IOS - Видеоруководство + Файлы журнала - Do you want to see the video tutorials? - LABEL ANDROID IOS - Хотите посмотреть видеоруководство? + Information + LABEL DESKTOP +---------- +LABEL ANDROID IOS + Информация - FAQ + List of Providers 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? - LABEL ANDROID IOS - Просмотреть файлы журнала %1? - - - Report error - 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 - LABEL DESKTOP - Диагностика - - - You can view and save the diagnosis information of the AusweisApp2 and your system here. - LABEL DESKTOP - Здесь можно просмотреть и сохранить информацию о диагностике AusweisApp2 и вашей системы. - - - Show diagnosis - LABEL DESKTOP - Показать диагностику - Logs 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. + Show system data LABEL DESKTOP - Нашли ошибку? Помогите нам устранить ее, отправив файл журнала с описанием этой ошибки. + Показать системные данные - Open website + System data LABEL DESKTOP - Открыть сайт + Системные данные MoreViewGeneral - - Online help - LABEL DESKTOP - Онлайн-справка - - - Do you have questions about %1? - LABEL DESKTOP - Есть вопросы о %1? - Open website LABEL DESKTOP Открыть сайт - Video tutorials + List of Providers LABEL DESKTOP - Видеоруководство + Список провайдеров - Do you want to see the video tutorials? - LABEL DESKTOP - Хотите посмотреть видеоруководство? - - - FAQ + FAQ - Frequently asked questions 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? - LABEL DESKTOP - Хотите прочитать заявление о доступности? - - - Setup assistant - LABEL DESKTOP - Помощник по настройке - - - Do you want to run the setup assistant again? - LABEL DESKTOP - Запустить помощника по настройке снова? - - - Start setup assistant + Contact LABEL DESKTOP - Запустить помощника по настройке + Контакты - NavigationButton + NavigationAction - Yes - Да - - - No - Нет - - - Continue - Продолжить + Cancel + Отмена Back @@ -2569,22 +1963,10 @@ LABEL ANDROID IOS NavigationView - - History - Журнал - Start Пуск - - Provider - Провайдер - - - Remote - Удаленный доступ - Settings Настройки @@ -2593,6 +1975,10 @@ LABEL ANDROID IOS Help Справка + + Card reader + Устройство чтения карт + NfcWorkflow @@ -2628,12 +2014,12 @@ LABEL ANDROID IOS NFC scan is not running. - INFO ANDROID IOS NFC is available but needs to be activated in the settings of the smartphone. + INFO ANDROID IOS NFC is available and enabled but needs to be started. NFC-сканирование не выполняется. Please start the NFC scan. - INFO ANDROID IOS NFC is available but needs to be activated in the settings of the smartphone. + INFO ANDROID IOS NFC is available and enabled but needs to be started. Запустите NFC-сканирование. @@ -2669,7 +2055,12 @@ LABEL ANDROID IOS Please place your ID card directly on the device's back side.<br/><br/>The exact position of the ID card is device dependent. The animations depict possible positions. Keep one position for several seconds before trying another one and do not move the ID card after contact was established. INFO ANDROID The ID card may be inserted, the authentication process may be started. - Расположите идентификационную карту на устройстве (точное положение зависит от устройства). Возможное положение показано в анимации. Удерживайте идентификационную карту в одном положении несколько секунд, прежде чем поменять положение, и не смещайте ее после установки соединения. + Расположите идентификационную карту непосредственно на задней стороне устройства.<br/><br/>Точное положение идентификационной карты зависит от устройства. Возможное положение показано в анимации. Удерживайте идентификационную карту в одном положении несколько секунд, прежде чем поменять положение, и не смещайте ее после установки соединения. + + + The device "%1" wants to use this smartphone as card reader and connect to your id card. + INFO ANDROID IOS %1 will be replaced with the name of the device. + Устройство «%1» планирует использовать данный смартфон в качестве устройства чтения карт и установить соединение с вашей идентификационной картой. @@ -2697,7 +2088,7 @@ LABEL ANDROID IOS The password is visible. Digits entered so far: %1 LABEL DESKTOP Screenreader text for the password field - + Пароль отображается. Цифры, введенные ранее: %1 @@ -2709,20 +2100,31 @@ LABEL ANDROID IOS Delete last digit + LABEL DESKTOP A11y text for the "delete" button image. +---------- +LABEL ANDROID IOS A11y text for the "delete" button image. Удалить последний знак Submit + LABEL DESKTOP A11y text for the "submit" button image. +---------- +LABEL ANDROID IOS A11y text for the "submit" button image. Подтвердить Delete last digit, disabled until input is present. - + LABEL DESKTOP A11y text for the "delete" button text when the button is disabled. +---------- +LABEL ANDROID IOS A11y text for the "delete" button text when the button is disabled. + Удалить последнюю цифру, деактивировано до начала ввода данных. , disabled until input is complete. - LABEL ANDROID IOS A11y text, appended onto the "submit" button text when the button is disabled. - + LABEL DESKTOP A11y text, appended onto the "submit" button text when the button is disabled. +---------- +LABEL ANDROID IOS A11y text, appended onto the "submit" button text when the button is disabled. + , деактивировано до завершения ввода данных. @@ -2732,6 +2134,72 @@ LABEL ANDROID IOS Деактивировано + + PairingCodeInfoView + + Pairing Information + LABEL ANDROID IOS + Информация о сопряжении + + + Open %1 on your %2other device%3. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 3 + Откройте %1 в другом %2вашем устройстве%3. + + + On that device go to %1Settings%2 and then %1Smartphone as card reader%2 resp. %1Manage pairings%2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 3. %1 and %2 are surrounding tags for bold font. + В данном устройстве перейдите в меню %1Настройки%2, а затем %1Смартфон в качестве устройства чтения карт%2 и в соответствующее меню %1Управлять сопряжениями%2. + + + Choose this smartphone in the list to pair it. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 3 + Чтобы выполнить сопряжение, выберите данный смартфон в списке. + + + + PairingFailedView + + Pairing to "%1" failed: + ERROR ALL_PLATFORMS An error occurred while pairing the device. + Сбой сопряжения «%1»: + + + + PairingProcessInfo + + Open %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. + Откройте %1 в вашем смартфоне в качестве устройства чтения карт. + + + On that device choose %1Card reader%2 and then %1Pair device%2 resp. %1Pair new device%2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 4. %1 and %2 are surrounding tags for bold font. + В данном устройстве выберите %1Устройство чтения карт%2, а затем %1Выполнить сопряжение устройства%2 и соответствующее меню %1Выполнить сопряжение нового устройства%2. + + + Choose the smartphone in the list shown here to pair it. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 4 of 4 + Чтобы выполнить сопряжение, выберите смартфон в приведенном списке. + + + Ensure that the %1 on your Smartphone as card reader has at least version %2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 4. %1 is a placeholder-tag for the app name. + Убедитесь, что программа %1, установленная на смартфоне в качестве устройства чтения карт, имеет версию не ниже %2. + + + + PairingSuccessView + + Pairing with %1 successful, it will be listed under "Paired devices". + INFO ALL_PLATFORMS The pairing with the SaC server was successful. + + + + The device may now be used as a card reader. + + + PasswordInfoContent @@ -2745,52 +2213,44 @@ LABEL ANDROID IOS What is the card PIN? LABEL ALL_PLATFORMS - + Что такое PIN-код карты? PIN information LABEL ALL_PLATFORMS Информация о PIN-коде - - The card PIN is a 6-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?' - - Where can I find the card PIN? LABEL ALL_PLATFORMS - - - - 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 5-digit Transport PIN. Only when you have set a 6-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-код карты? How do I choose a secure PIN? LABEL ALL_PLATFORMS - + Как выбрать безопасный PIN-код? - For your 6-digit 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. + For your six-digit 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 PIN?' paragraph 1/3 - + Не выбирайте для 6-значного PIN-кода комбинации, которые легко отгадать (например, «123456», дату своего рождения или любые другие цифры с идентификационной карты). - You can change your 6-digit PIN at any time and an unlimited number of times as long as you know your valid PIN. + You can change your six-digit PIN at any time and an unlimited number of times as long as you know your valid PIN. INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure PIN?' paragraph 2/3 - + Изменить 6-значный PIN-код можно в любое время и неограниченное количество раз, если вы знаете свой действительный PIN-код. 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-код в секрете и измените его, если о нем станет известно другому человеку. What is the Transport PIN? LABEL ALL_PLATFORMS - + Что такое временный PIN-код? Transport PIN information @@ -2798,39 +2258,24 @@ LABEL ANDROID IOS Информация о временном PIN-коде - The 5-digit Transport PIN was sent to you in the PIN letter by mail after you applied for your ID card. + The five-digit Transport PIN was sent to you in the PIN letter by mail after you applied for your ID card. INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 1/3 - + 5-значный временный PIN-код был отправлен вам в письме с PIN-кодом по почте после того, как вы заказали идентификационную карту. - If you did not set a self-selected 6-digit card PIN when you picked up your ID card, you can do so using the Transport PIN. + If you did not set a self-selected six-digit card PIN when you picked up your ID card, you can do so using the Transport PIN. INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 2/3 - + Если при получении идентификационной карты вы не установили 6-значный PIN-код карты, это можно сделать с помощью временного PIN-кода. Once you have set a card PIN, the Transport PIN loses its validity. INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 3/3 - - - - 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 - - - - 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 - + После создания PIN-кода карты временный PIN-код перестает действовать. Where do I find the PUK? LABEL ALL_PLATFORMS - + Где найти PUK-код? PUK information @@ -2838,34 +2283,34 @@ LABEL ANDROID IOS Информация о PUK-коде - The PUK is a 10-digit number that you can find in the PIN letter that was sent to you by mail after you applied for your ID card. + The PUK is a ten-digit number that you can find in the PIN letter that was sent to you by mail after you applied for your ID card. INFO ALL_PLATFORMS Answer to the question 'Where do I find the PUK?' - + PUK-код — это 10-значный номер, который можно найти в письме с PIN-кодом, отправленном вам по почте после того, как вы заказали идентификационную карту. Why is the PUK required? LABEL ALL_PLATFORMS - + Для чего необходим PUK-код? The PUK is required if the card PIN has been entered incorrectly three times in a row. As a result, the card PIN is blocked. INFO ALL_PLATFORMS Answer to the question 'Why is the PUK required?' - + PUK-код необходим в том случае, если PIN-код карты введен неправильно три раза подряд. После этого PIN-код карты блокируется. What is the PUK's purpose? LABEL ALL_PLATFORMS - + В чем назначение PUK-кода? By entering the PUK, you unblock the card PIN and have another three chances to enter the correct PIN. INFO ALL_PLATFORMS Answer to the question 'What is the PUK's purpose?' - + После ввода PUK-кода разблокируется PIN-код карты и появляется возможность ввести правильный PIN-код еще три раза. Why is the CAN required? LABEL ALL_PLATFORMS - + Для чего необходим CAN-код? CAN information @@ -2875,32 +2320,32 @@ LABEL ANDROID IOS When is the card access number (CAN) required? LABEL ALL_PLATFORMS - + Когда необходим код доступа к карте (CAN-код)? The card access number (CAN) is required when the card PIN has been entered incorrectly twice. INFO ALL_PLATFORMS Answer to the question 'When is the card access number (CAN) required?' - + Код доступа к карте (CAN-код) требуется, если PIN-код карты дважды введен неправильно. Why do I have to enter the CAN before a third attempt? LABEL ALL_PLATFORMS - + Почему нужно вводить CAN-код перед третьей попыткой? A third incorrect entry blocks your PIN and you can no longer use the eID function until it is unblocked. Requesting the CAN ensures that a third incorrect entry can only be made with direct access to your ID card. INFO ALL_PLATFORMS Answer to the question 'Why do I have to enter the CAN before a third attempt?' - + Третий неверный ввод блокирует PIN-код, и вы больше не сможете использовать функцию eID до тех пор, пока он не будет разблокирован. Запрос CAN-кода гарантирует, что третий неправильный ввод может быть выполнен только при наличии прямого доступа к идентификационной карте. Where can I find the CAN? LABEL ALL_PLATFORMS - + Где найти CAN-код? - The CAN is a 6-digit number that can be found on the bottom right of the front of the ID card. + The CAN is a six-digit number that can be found on the bottom right of the front of the ID card. INFO ALL_PLATFORMS Answer to the question 'Where can I find the CAN?' - + CAN-код — это 6-значный номер, указанный в нижнем правом углу на передней стороне идентификационной карты. The Card Access Number (CAN) allows to access the imprinted data of the ID card. The CAN is a six-digit number that can be found on the front of the ID card. It is located at the bottom right next to the validity date (marked in red). @@ -2917,12 +2362,12 @@ LABEL ALL_PLATFORMS Just like the physical ID card, the Smart-eID stored on your Smartphone can be blocked. This might be required if you ever lose your device. INFO ANDROID IOS Description text of Smart-eID PIN - + Сохраненную на смартфоне электронную идентификационную карту Smart-eID можно заблокировать, как и физическую идентификационную карту. Это может потребоваться при потере устройства. To revoke an active Smart-eID, a blocking code is required. The blocking code will be displayed after successfully creating the Smart-eID. Furthermore, it is contained in the letter you will receive after creation. INFO ANDROID IOS Description text of Smart-eID PIN - + Для блокировки активной электронной идентификационной карты Smart-eID требуется код блокировки. Код блокировки отображается на дисплее после успешного создания электронной идентификационной карты Smart-eID. Кроме того, он указан в письме, которое вы получите после создания. No PIN known @@ -2932,90 +2377,140 @@ LABEL ALL_PLATFORMS You do not know your PIN? LABEL ALL_PLATFORMS - + Знаете ли вы свой PIN-код? - You have not yet set a 6-digit card PIN and cannot find the PIN letter with the Transport PIN? + You have not yet set a six-digit card PIN and cannot find the PIN letter with the Transport PIN? INFO ALL_PLATFORMS - + Вы еще не установили 6-значный PIN-код карты и не можете найти письмо с PIN-кодом, где указан временный PIN-код? You set a card PIN when picking up your ID card or later by yourself, but you can no longer remember it? INFO ALL_PLATFORMS - + Вы установили PIN-код карты при получении идентификационной карты или позже самостоятельно, но не можете его вспомнить? Learn more about the two types of PIN LABEL ALL_PLATFORMS - + Узнайте больше о двух типах PIN-кодов Types of PIN LABEL ALL_PLATFORMS - + Типы PIN-кодов - Your ID card comes with a 5-digit 'Transport PIN' which you need to replace with a 6-digit PIN that you choose yourself. - INFO ALL_PLATFORMS Description text explaining the PINs 1/6 - + 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/7 + К вашей идентификационной карте прилагается 5-значный временный PIN-код, который необходимо заменить на 6-значным PIN-кодом (его вы выберете сами). - 5-digit Transport PIN + Five-digit Transport PIN LABEL ALL_PLATFORMS - + 5-значный временный PIN-код - The 5-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 + 6-значный PIN-код - The PIN can only be used once. When you set up the eID function, you will replace this 5-digit PIN with a 6-digit PIN that you choose yourself. - INFO ALL_PLATFORMS Description text explaining the PINs 3/6 - + 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-код был отправлен вам по почте после того, как вы заказали идентификационную карту. - 6-digit PIN + What is the Smart-eID PIN? LABEL ALL_PLATFORMS - + Что такое PIN-код для Smart-eID? - This is a number that you choose yourself when you set up the eID function for the first time. It replaces your 5-digit Transport PIN. - INFO ALL_PLATFORMS Description text explaining the PINs 4/6 - + Set up Smart-eID + LABEL ALL_PLATFORMS + Создание Smart-eID - 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 - + 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?' + PIN-код для Smart-eID — это 6-значный PIN-код, который пользователь создает самостоятельно. Этот PIN-код необходим для использования Smart-eID. - You can change your 6-digit PIN at any time in AusweisApp2. - INFO ALL_PLATFORMS Description text explaining the PINs 6/6 - + 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 + Не выбирайте для 6-значного PIN-кода Smart-eID комбинации, которые легко отгадать (например, «123456», дату своего рождения или любые другие цифры с идентификационной карты). - You can use the PIN Reset Service to request a new card PIN free of charge. - LABEL ALL_PLATFORMS - + 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 + Изменить 6-значный PIN-код для Smart-eID можно в любое время и неограниченное количество раз, если вы знаете свой действительный PIN-код для Smart-eID. - 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. - + 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 + Этот PIN-код можно использовать только один раз. Настроив функцию eID, вы замените этот 5-значный временный PIN-код 6-значным PIN-кодом карты, который выберете сами. - 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. - + 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 + 6-значный PIN-код — это номер, который вы выбираете сами при настройке функции eID в первый раз. Он заменяет 5-значный временный PIN-код. - - - PersonalizationController - Smart-eID - LABEL ANDROID IOS - Smart-eID + 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 + PIN-код для Smart-eID состоит из шести знаков. Вы выбираете этот PIN-код сами при первой настройке Smart-eID. + + + 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 + Вы можете изменить PIN-код для своей Smart-eID в любое время в меню %1. + + + 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 + Ввод 6-значного PIN-кода подтверждает в режиме онлайн то, что идентификационная карта или Smart-eID принадлежит вам. Никто не сможет использовать функцию eID без этого 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?' + PIN-код карты — это 6-значный PIN-код, который пользователь создает самостоятельно. Этот PIN-код необходим, если планируется использовать функцию eID с вашей идентификационной картой. + + + 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) + Вы устанавливаете PIN-код карты либо непосредственно при получении идентификационной карты в ведомстве по делам граждан (Bürgeramt), либо позже в %1, используя для этого 5-значный временный PIN-код. Только установив 6-значный PIN-код по своему выбору, вы можете использовать функцию eID и настраивать Smart-eID. + + + 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. + Если вы забыли PIN-код для Smart-eID, вы можете обновить свою Smart-eID и установить новый PIN-код. + + + Where can I find the Smart-eID PIN? + LABEL ALL_PLATFORMS + Где найти PIN-код для Smart-eID? + + + 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?' + Вы устанавливаете PIN-код для Smart-eID при настройке Smart-eID. + + + 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 + Ввод 6-значного PIN-кода подтверждает в режиме онлайн то, что идентификационная карта принадлежит вам. Никто не сможет использовать функцию eID без этого 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 + Вы можете изменить PIN-код карты в любое время в %1. + + + + PersonalizationController + + Smart-eID + LABEL ANDROID IOS + Smart-eID Set up Smart-eID @@ -3075,6 +2570,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 + При удалении %1 или сбросе настроек смартфона необходимо заново настраивать Smart-eID. + PersonalizationProgressView @@ -3133,6 +2633,11 @@ LABEL ALL_PLATFORMS LABEL ANDROID IOS Smart-eID + + Please wait a moment, the current process is being finished. + LABEL ANDROID IOS + Подождите, текущий процесс завершается. + PersonalizationResultView @@ -3171,11 +2676,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 @@ -3224,271 +2724,36 @@ LABEL ALL_PLATFORMS - ProviderContactInfo + ProviderInfo - Provider contact information - Контактная информация провайдера - - - Contact information of the selected provider. - Контактная информация выбранного провайдера. + See details under "more..." + LABEL ALL_PLATFORMS + Подробнее см. в пункте «Дополнительные сведения». - Contact + Show more information about the service provider LABEL DESKTOP - Контакты + Показать больше информации о провайдере службы - Unknown + You are about to identify yourself towards the following provider: LABEL DESKTOP - Неизвестно - - - - ProviderDetailButtonBar - - To provider - LABEL DESKTOP ----------- -LABEL ANDROID_TABLET IOS_TABLET - К провайдеру - - - - ProviderDetailDescription - - Description - LABEL ANDROID_TABLET IOS_TABLET - Описание - - - The provider did not provide a description. - LABEL ANDROID_TABLET IOS_TABLET - Провайдер не предоставил описание. - - - - ProviderDetailHistory - - List of your past interactions with this provider - Список случаев вашего взаимодействия с этим провайдером - - - The list is empty, no recorded interaction with this provider. - Список пуст, нет записанных случаев взаимодействия с этим провайдером. - - - Currently there are no history entries. - INFO DESKTOP No authentication history, placeholder text. ----------- -INFO ANDROID_TABLET IOS_TABLET No authentication history, placeholder text. - В настоящее время в журнале нет записей. - - - History - LABEL ANDROID_TABLET IOS_TABLET - Журнал - - - Purpose for reading out requested data - LABEL ANDROID_TABLET IOS_TABLET - Цель считывания запрошенных данных + Вы собираетесь пройти самоидентификацию для следующего провайдера: - - - ProviderDetailHistoryInfo Provider - LABEL ANDROID_TABLET IOS_TABLET - Провайдер - - - Purpose for reading out requested data - LABEL ANDROID_TABLET IOS_TABLET - Цель считывания запрошенных данных - - - Read data - LABEL ANDROID_TABLET IOS_TABLET - Считать данные - - - Terms of usage - LABEL ANDROID_TABLET IOS_TABLET - Условия использования - - - - ProviderDetailHistoryItem - - today LABEL ANDROID IOS - сегодня - - - yesterday - вчера - - - dd.MM.yyyy - dd.MM.yyyy - - - Service: - LABEL DESKTOP - Служба: - - - Provider: - LABEL DESKTOP - Провайдер: - - - Click to view details of history entry. - Щелкните, чтобы просмотреть подробную информацию о записи журнала. + Провайдер Touch for more details LABEL ANDROID IOS Нажмите для получения подробной информации - - - ProviderDetailView - - Description - LABEL DESKTOP - Описание - - - The provider did not provide a description. - LABEL DESKTOP - Провайдер не предоставил описание. - - - History - LABEL DESKTOP - Журнал - - - - 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 - По вашему запросу результатов не найдено - - - - ProviderHeader - - To provider - LABEL ANDROID IOS - К провайдеру - - - - ProviderInfoSection - - See details under "more..." - LABEL DESKTOP - Подробнее см. в пункте «Дополнительные сведения» - - - - ProviderListItemDelegate - - Open provider details for %1 - Открыть подробную информацию провайдера %1 - - - Click to set category filter to %1 - Нажмите здесь, чтобы настроить фильтр категорий %1 - - - - ProviderModelItem - - Click to open homepage. - INFO ALL_PLATFORMS A11y action text appended to provider homepage to be read read by screen reader. - Нажмите, чтобы открыть домашнюю страницу. - - - Click to send email. - INFO ALL_PLATFORMS A11y action text appended to provider mail to be read read by screen reader. - Нажмите, чтобы отправить сообщение электронной почты. - - - Costs - 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 + Details about the provider LABEL DESKTOP - Поиск провайдеров + Подробная информация о провайдере @@ -3595,10 +2860,6 @@ LABEL ANDROID IOS Press space to pair the smartphone "%1". Нажмите пробел для сопряжения смартфона «%1». - - Click to pair - Нажмите для сопряжения - Remove remote device Удалить дистанционное устройство @@ -3607,43 +2868,73 @@ LABEL ANDROID IOS RemoteReaderView - Paired remote devices - Сопряженные дистанционные устройства + Paired devices + LABEL DESKTOP + Сопряженные устройства + + + Add pairing + LABEL DESKTOP + Добавить сопряжение - Available remote devices - Доступные дистанционные устройства + 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. + Откройте %1 в вашем смартфоне в качестве устройства чтения карт. - Only devices that are already paired or are connected to the same WiFi network and have the remote service enabled are shown here. - Здесь отображаются только уже сопряженные или подключенные к той же сети Wi-Fi устройства с активированной удаленной службой. + Both devices have to be connected to the same WiFi. + Оба устройства должны быть подключены к одной сети Wi-Fi. - More information + On that device go to %1Card reader%2 and then %1Pair device%2 rsp. %1Pair new device%2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 4. %1 and %2 are surrounding tags for bold font + В данном устройстве перейдите в меню %1Устройство чтения карт%2, а затем %1Выполнить сопряжение устройства%2 и в соответствующее меню %1Выполнить сопряжение нового устройства%2. + + + Choose the device in the list to pair it. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 4 of 4 + Чтобы выполнить сопряжение, выберите устройство в списке. + + + Last connected LABEL DESKTOP - Дополнительные сведения + Последние подключенные - - - RemoteServiceSettings - Configure remote service - LABEL ANDROID IOS - Сконфигурировать удаленную службу + Ensure that the %1 on your Smartphone as card reader has at least version %2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 4. %1 is a placeholder-tag for the app name. + Убедитесь, что программа %1, установленная на смартфоне в качестве устройства чтения карт, имеет версию не ниже %2. - RemoteServiceView + RemoteServiceController Remote service LABEL ANDROID IOS Удаленная служба - Pairing failed. Please start a new pairing process on your other device and enter the shown pairing code. - ERROR ANDROID IOS An error occurred while pairing the device. - Сбой сопряжения. Перезапустите сопряжение на другом устройстве и введите указанный код сопряжения. + You are about to identify yourself towards the following provider using the device "%1": + LABEL ANDROID IOS + Вы собираетесь пройти самоидентификацию для следующего провайдера, используя устройство «%1»: + + + Card reader + LABEL ANDROID IOS + Устройство чтения карт + + + + RemoteServiceSettings + + Manage pairings + LABEL ANDROID IOS + Управление сопряжениями + + + RemoteServiceView WiFi not active LABEL ANDROID IOS @@ -3669,35 +2960,16 @@ LABEL ANDROID IOS LABEL ANDROID IOS Ожидание соединения - - Remote service ready - LABEL ANDROID IOS - Удаленная служба готова к работе - Waiting for connection from a paired device... INFO ANDROID IOS Ожидание соединения сопряженного устройства… - - Start the remote access in order to make this smartphone visible and use it as a card reader (SaC). - -If you have not already paired a device, start the pairing now to set up this smartphone as a card reader. - INFO ANDROID IOS - Запустите удаленный доступ, чтобы смартфон стал видимым и его можно было использовать как устройство чтения карт (SaC). - -Если сопряженных устройств еще нет, запустите сопряжение, чтобы настроить смартфон как устройство чтения карт. - Pairing code: <b>%1</b> LABEL ANDROID IOS Код сопряжения: <b>%1</b> - - Both of your devices have to be connected to the same WiFi. - INFO ANDROID IOS The remote service is active. Hint that both devices need to be connected to the same network. - Оба устройства должны быть подключены к одной сети Wi-Fi. - Enable WiFi LABEL ANDROID IOS @@ -3709,47 +2981,81 @@ If you have not already paired a device, start the pairing now to set up this sm Активировать NFC - Stop remote service + Pair device LABEL ANDROID IOS - Остановить удаленную службу + Выполнить сопряжение устройства - Start remote service + Allow connection LABEL ANDROID IOS - Запустить удаленную службу + Разрешить подключение + + + You can use this Smartphone as a card reader for the %1 on other devices e.g. a laptop. + +To do this you first have to pair that device with this smartphone. + INFO ANDROID IOS + Можно использовать данный смартфон в качестве устройства чтения карт для %1 в других устройствах, например в ноутбуке. + +Для этого сначала следует выполнить сопряжение данного устройства с этим смартфоном. - Stop pairing + Card reader LABEL ANDROID IOS - Остановить сопряжение + Устройство чтения карт - Start pairing + Paired Devices LABEL ANDROID IOS - Запустить сопряжение + Сопряженные устройства - Enter the code %1 in the %2 on your other device to use your smartphone as a card reader (SaC). - INFO ANDROID IOS - Введите этот код в %1 на вашем устройстве, чтобы использовать смартфон в качестве устройства чтения карт (SaC). + Pair new device + LABEL ANDROID IOS + Выполнить сопряжение нового устройства - - - RemoteServiceViewRemote - Paired devices + Waiting for pairing LABEL ANDROID IOS - Сопряженные устройства + Ожидание сопряжения - No device is paired. + Start pairing of a new device LABEL ANDROID IOS - Нет сопряженных устройств. + Начать сопряжение нового устройства - Click to remove device + Where do I enter the pairing code? LABEL ANDROID IOS - Нажмите для удаления устройства + Где следует вводить код сопряжения? + + + Enter the pairing code %1 in the %2 on your other device. + INFO ANDROID IOS + Введите код сопряжения %1 в поле %2 в другом вашем устройстве. + + + Cancel pairing + LABEL ANDROID IOS + Отменить сопряжение + + + Allow a connection with paired devices to use this Smartphone as a card reader or pair another device. + INFO ANDROID IOS + Разрешите подключение к сопряженным устройствам, чтобы использовать этот смартфон в качестве устройства чтения карт, а также для сопряжения с другим устройством. + + + Paired devices may use this Smartphone as a card reader now. + INFO ANDROID IOS + Теперь сопряженные устройства могут использовать этот смартфон в качестве устройства чтения карт. + + + + RemoteServiceViewRemote + + Click to remove device + LABEL ANDROID IOS + Нажмите для удаления устройства Remove pairing @@ -3766,16 +3072,6 @@ If you have not already paired a device, start the pairing now to set up this sm INFO ANDROID IOS Удалить - - Available devices - LABEL ANDROID IOS - Доступные устройства - - - No unpaired smartphone as card reader (SaC) available. Please make sure that the smartphone as card reader (SaC) functionality in AusweisApp2 on your other device is activated and that both devices are connected to the same WiFi. - INFO ANDROID IOS No SaC was found on the network, both devices need to be connected to the same WiFi network. - Нет доступных сопряженных смартфонов, используемых как устройство чтения карт (SaC). Убедитесь в том, что смартфон активирован в AusweisApp2 на другом устройстве в качестве устройства чтения карт (SaC) и оба устройства подключены к одной сети Wi-Fi. - Please connect your WiFi to use another smartphone as card reader (SaC). INFO ANDROID IOS Wifi is not enabled and no new devices can be paired. @@ -3787,63 +3083,66 @@ If you have not already paired a device, start the pairing now to set up this sm Активировать Wi-Fi - Click to pair + Pairing code LABEL ANDROID IOS - Нажмите для сопряжения + Код сопряжения - Pairing mode - INFO ANDROID IOS - Режим сопряжения + Add pairing + LABEL ANDROID IOS + Добавить сопряжение + + + Last connected + LABEL ANDROID IOS + Последние подключенные - Start the pairing mode on your smartphone if you haven't done it already. - INFO ANDROID IOS Information dialog that requests the user to start the pairing mode on the smartphone. - Запустите режим сопряжения на смартфоне, если вы еще не сделали это. + Available + LABEL ANDROID IOS + Доступно - Pairing code + Paired devices LABEL ANDROID IOS - Код сопряжения + Сопряженные устройства + + + Click to pair + LABEL ANDROID IOS + Нажмите для сопряжения + + + Pairing the device ... + LABEL ANDROID IOS + Сопряжение устройства… - RemoteWorkflow + RemoteServiceWifiInfo - 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 не было выполнено, поскольку оно не отвечало на попытки соединения. Снова выполните сопряжение устройства для его использования в качестве устройства чтения карт. + Both devices have to be connected to the same WiFi. + INFO ANDROID IOS The remote service is active. Hint that both devices need to be connected to the same network. + Оба устройства должны быть подключены к одной сети Wi-Fi. + + + RemoteWorkflow Enable WiFi LABEL ANDROID IOS Активировать Wi-Fi - - Pair device - LABEL ANDROID IOS - Выполнить сопряжение устройства - To use the remote service WiFi has to be activated. Please activate WiFi in your device settings. INFO ANDROID IOS The WiFi module needs to be enabled in the system settings to use the remote service. Для использования удаленной службы необходимо активировать Wi-Fi. Активируйте Wi-Fi в настройках устройства. - - No paired smartphone as card reader (SaC) with activated "remote service" available. - INFO ANDROID IOS No paired and reachable device was found, hint that the remote device needs to be actually started for this feature. - Нет доступных смартфонов, используемых в качестве устройства чтения карт (SaC), с активированной удаленной службой. - Wifi disabled LABEL ANDROID IOS Wi-Fi деактивирован - - Waiting for connection - LABEL ANDROID IOS - Ожидание соединения - Determine card LABEL ANDROID IOS @@ -3855,17 +3154,28 @@ If you have not already paired a device, start the pairing now to set up this sm К сожалению, подключенный в качестве устройства чтения карт (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 смартфона на идентификационной карте. + Подключено к %1. Следуйте инструкциям в подключенном смартфоне. + + + Manage pairings + LABEL ANDROID IOS + Управление сопряжениями + + + No smartphone as card reader connected + LABEL ANDROID IOS + Смартфон в качестве устройства чтения карт не подключен + + + Allow a connection on a paired smartphone or pair a new smartphone. + INFO ANDROID IOS No paired and reachable device was found, hint that the remote device needs to be actually started for this feature. + Разрешите подключение к сопряженному смартфону или выполните сопряжение нового смартфона. ResultErrorView - - Show error details - Показать подробную информацию об ошибке - Details Подробная информация @@ -3905,109 +3215,15 @@ If you have not already paired a device, start the pairing now to set up this sm - 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 @@ -4018,16 +3234,6 @@ LABEL ANDROID LABEL DESKTOP Использовать экранную клавиатуру для ввода PIN-кода - - Shuffle keypad buttons - LABEL DESKTOP - Случайное расположение кнопок клавиатуры - - - Visual feedback when pressing keypad buttons - LABEL DESKTOP - Анимация кнопок экранной клавиатуры при нажатии - Software updates LABEL DESKTOP @@ -4069,19 +3275,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 + Визуальное выделение нажатой клавиши на экранной клавиатуре @@ -4101,23 +3307,11 @@ LABEL ANDROID LABEL DESKTOP Title of the self authentication result data view Считать данные - - Save as PDF... - LABEL DESKTOP - Сохранить как PDF… - - - Information - Информация - - - Portable Document Format (*.pdf) - LABEL DESKTOP - Portable Document Format (*.pdf) - OK - LABEL DESKTOP + LABEL DESKTOP +---------- +LABEL ANDROID IOS OK @@ -4125,11 +3319,6 @@ LABEL ANDROID LABEL ANDROID IOS Идентифицировать - - Save read self-authentication data - LABEL DESKTOP - Сохранить cчитать данные самоаутентификации - SelfAuthenticationView @@ -4168,6 +3357,16 @@ LABEL ANDROID IOS LABEL ANDROID IOS Просмотреть персональные данные + + Self-authentication + LABEL ANDROID IOS + Самоаутентификация + + + Hint + LABEL ANDROID IOS + Совет + SettingsView @@ -4223,176 +3422,154 @@ 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-код на этом устройстве - Remote card reader + Randomize the order of the on screen keypad buttons LABEL ANDROID IOS - Удаленное устройство чтения карт + Случайное расположение кнопок экранной клавиатуры - Configure remote service for another device + Keypad animations LABEL ANDROID IOS - Сконфигурировать удаленную службу для другого устройства + Анимация кнопок - Save history + Skip rights page LABEL ANDROID IOS - Сохранить журнал + Пропустить страницу с разрешениями - Save authentication history + Testmode for the self-authentication LABEL ANDROID IOS - Сохранить журнал процессов аутентификации + Тестовый режим для самоаутентификации - History - LABEL ANDROID IOS ----------- -LABEL ALL_PLATFORMS - Журнал + Internal card simulator + LABEL ANDROID IOS + Внутренний симулятор карт - View authentication history + Developer mode LABEL ANDROID IOS - Показать журнал процессов аутентификации + Режим разработчика - Shuffle keypad buttons + Use a more tolerant mode LABEL ANDROID IOS - Случайное расположение кнопок клавиатуры + Использовать менее чувствительный режим - Randomize the order of the on screen keypad buttons + Layout style LABEL ANDROID IOS - Случайное расположение кнопок экранной клавиатуры + Стиль макета - Keypad animations + Create dummy entries LABEL ANDROID IOS - Анимация кнопок + Создание фиктивных записей - Visual feedback when pressing keypad buttons - LABEL ANDROID IOS - Анимация кнопок экранной клавиатуры при нажатии + New Logfile + LABEL ALL_PLATFORMS + Новый файл журнала - CAN allowed mode - LABEL ANDROID IOS - Режим «Код CAN разрешен» + 15 days old Logfile + LABEL ALL_PLATFORMS + Файл журнала, созданный 15 дней назад - Support CAN allowed mode + Smart-eID LABEL ANDROID IOS - Поддержка режима «Код CAN разрешен» + Smart-eID - Allow the id card to be used with only the CAN + Reset Smart-eID LABEL ANDROID IOS - Поддержка использования идентификационной карты только с CAN + Сбросить Smart-eID - Skip rights page + Reset Smart-eID data on your device LABEL ANDROID IOS - Пропустить страницу с разрешениями + Сбросить данные Smart-eID на вашем устройстве - Do not show the rights page, when in can allowed mode + Show requested rights on this device as well LABEL ANDROID IOS - Не показывать страницу с правами в режиме «Код CAN разрешен» + Показывать запрошенные права также и в этом устройстве - Testmode for the self-authentication + Manage pairings LABEL ANDROID IOS - Тестовый режим для самоаутентификации + Управление сопряжениями - Use the test environment during a self-authentication + Show Transport PIN reminder, store feedback and close reminder dialogs. LABEL ANDROID IOS - Использование тестовой среды при самоаутентификации + Показывать напоминание временного PIN-кода, сохранять обратную связь и закрывать диалоговые окна с напоминаниями. - Internal card simulator + Reset hideable dialogs LABEL ANDROID IOS - Внутренний симулятор карт + Сбросить скрываемые диалоговые окна - Enable internal card simulator + Toggling will restart the %1 LABEL ANDROID IOS - Включить внутренний симулятор карт + Переключение приведет к перезапуску %1 - Developer mode + Use system font LABEL ANDROID IOS - Режим разработчика + Использовать системный шрифт - Use a more tolerant mode + Appearance LABEL ANDROID IOS - Использовать менее чувствительный режим + Внешний вид - Layout style + Add and remove devices LABEL ANDROID IOS - Стиль макета + Добавить/удалить устройства - Create dummy entries + On-site reading LABEL ANDROID IOS - Создание фиктивных записей + Чтение данных на месте - New Logfile - LABEL ALL_PLATFORMS - Новый файл журнала + Support CAN allowed mode for on-site reading + LABEL ANDROID IOS + Поддержка режима «Код CAN разрешен» для чтения данных на месте - 15 days old Logfile - LABEL ALL_PLATFORMS - Файл журнала, созданный 15 дней назад + Allow test sample card usage + LABEL ANDROID IOS + Разрешить использование тестовой карты - - - SetupAssistantView - Setup Assistant - LABEL DESKTOP - Помощник по настройке + Simulate a test sample card in authentications + LABEL ANDROID IOS + Моделировать тестовую карту в процессах аутентификации - 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. Уделите время для настройки среды приложения в соответствии с вашими требованиями. Любую настройку позднее можно изменить в меню настроек. + Visually highlight key presses on screen keypad + LABEL ANDROID IOS + Визуальное выделение нажатой клавиши на экранной клавиатуре + + + SetupAutostartView Do you want to automatically start the %1 after boot? INFO DESKTOP Question if the App shall be started automatically after boot @@ -4405,53 +3582,18 @@ LABEL ALL_PLATFORMS 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 + INFO MACOS Additional information that macOS auto-start adds a symbol to the menu bar Запуск добавит значок в строку меню. - Auto-start Setting + Autostart Settings 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. - Далее к начальной странице + 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. + @@ -4468,1343 +3610,498 @@ LABEL ALL_PLATFORMS - 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 - Продолжить - - - - 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 - - - - - 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 - Приложение на смартфоне с ОС 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 - Для длинных форм, например заявок на ссуду для обучения от государства, рекомендуем использовать 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 - 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> или <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 - Если вы не можете вспомнить 6-значный 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 в качестве устройства чтения карт - - - Click link on the website of the provider. - LABEL ANDROID IOS - Нажмите ссылку на сайт провайдера. - - - The App opens automatically. - LABEL ANDROID IOS - Приложение открывается автоматически. - - - The AusweisApp2 will display who wants to access which data. - LABEL ANDROID IOS - AusweisApp2 показывает, кто и какие данные запрашивает. - - - Start the process with a click on: - LABEL ANDROID IOS - Запустите процесс нажатием: - - - Proceed to PIN entry - LABEL ANDROID IOS - Далее к вводу PIN-кода - - - ... and place the top of the iPhone onto the ID card. - LABEL IOS - …и расположите верхнюю часть iPhone на идентификационной карте. - - - ... and place the ID card flat onto the NFC interface. - LABEL ANDROID - …и расположите идентификационную карту на интерфейсе NFC. - - - Do not move device or ID card! - 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. - LABEL ANDROID - Правильное положение зависит от вашего устройства. Если в текущем положении функция не работает, попробуйте изменить положение. AusweisApp2 показывает различные подходящие положения. - - - 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 - Если ваше устройство не обнаруживает идентификационную карту, проверьте возможности устройства, нажав «Проверить устройство и идентификационную карту» на начальной странице. - - - You can find more information on compatible devices on our %1mobile device list%2. - 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. - Ввести - - - six-digit PIN - 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 accoording to the first line. - сейчас! - - - 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-код. - - - Open YouTube video - LABEL ANDROID IOS - Открыть видео на YouTube - - - You can also watch this YouTube video explaining the process. - LABEL ANDROID IOS - Вы также можете просмотреть видео с описанием процесса на YouTube. - - - - TutorialReaderMethodSacDesktop + SmartDeleteBaseView - Tutorial: Smartphone as card reader + Smart-eID LABEL ANDROID IOS - Руководство: Смартфон в качестве устройства чтения карт + Smart-eID - Smartphone as card reader + Please wait a moment. LABEL ANDROID IOS - Смартфон в качестве устройства чтения карт + Подождите. - App on computer <b>without</b> NFC chip + Send log LABEL ANDROID IOS - Приложение на компьютере <b>без</b> чипсета NFC + Отправить файл журнала - Smartphone <b>with</b> NFC chip as card reader + If you want to use that functionality again, you need to set up a new Smart-eID first. LABEL ANDROID IOS - Смартфон <b>с</b> чипсетом NFC в качестве устройства чтения карт + Если вы хотите в будущем снова использовать этот функционал, необходимо сначала создать новую Smart-eID. - Install AusweisApp2 on both your computer <b>and</b> your smartphone with NFC capability. + Reset Smart-eID LABEL ANDROID IOS - Установите AusweisApp2 на компьютер <b>и</b> смартфон с поддержкой NFC. + Сбросить Smart-eID + + + SmartDeleteView - Both devices have to be connected to the same WiFi network + Delete Smart-eID LABEL ANDROID IOS - Оба устройства должны быть подключены к одной сети Wi-Fi. + Удалить Smart-eID - Now choose "Remote" in the AusweisApp2 on your smartphone... + You have successfuly deleted your Smart-eID. LABEL ANDROID IOS - Далее выберите «Удаленный доступ» в AusweisApp2 на смартфоне… + Вы успешно удалили Smart-eID. - Now + The Smart-eID could not be successfully deleted from your device. LABEL ANDROID IOS - сейчас + Невозможно удалить Smart-eID из вашего устройства. - Start pairing + Back to start page LABEL ANDROID IOS - Запустить сопряжение + Назад к начальной странице - Pairing code + You are about to delete the Smart-eID data that is currently stored on your device. LABEL ANDROID IOS - Код сопряжения + Вы собираетесь удалить данные Smart-eID, сохраненные на вашем устройстве. - appears! + Are you sure you want to delete 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 для этого приложения. + Удалить Smart-eID? - Start the App now on your computer and enter the settings. + Delete LABEL ANDROID IOS - Откройте приложение на компьютере и перейдите в раздел настроек. + Удалить - Select the <b>Smartphone as card reader</b> tab. + Deleting Smart-eID LABEL ANDROID IOS - Выберите вкладку <b>Смартфон в качестве устройства чтения карт</b>. + Удаление Smart-eID - Select smartphone from list + Delete the Smart-eID LABEL ANDROID IOS - Выбрать смартфон из списка + Удалить Smart-eID + + + SmartMainView - Enter pairing code next. + Updating Smart-eID status... LABEL ANDROID IOS - Далее введите код сопряжения. + Обновление статуса Smart-eID… - Click link on the website of the provider. + Smart-eID ready for use LABEL ANDROID IOS - Нажмите ссылку на сайт провайдера. + Электронная идентификационная карта Smart-eID готова к использованию - The App opens automatically. + Please wait a moment. LABEL ANDROID IOS - Приложение открывается автоматически. + Подождите. - The AusweisApp2 will display who wants to access which data. + 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 - AusweisApp2 показывает, кто и какие данные запрашивает. + Ваша электронная идентификационная карта Smart-eID создана и готова к использованию. Теперь вы можете выполнять онлайн-идентификацию без идентификационной карты, если эта функция поддерживается провайдером. - Start the process with a click on: + Check here if your device is suitable to set up a Smart-eID. LABEL ANDROID IOS - Запустите процесс нажатием: + Проверьте здесь, подходит ли ваше устройство для создания Smart-eID. - Proceed to PIN entry + Start check LABEL ANDROID IOS - Далее к вводу PIN-кода + Запуск проверки - ... and place the ID card onto the NFC interface. + With the Smart-eID you may also use the online identification function without the ID card. LABEL ANDROID IOS - …и расположите идентификационную карту на интерфейсе NFC. + С помощью Smart-eID вы также можете использовать функцию онлайн-идентификации без идентификационной карты. + + + SmartResetView - Do not move device or ID card! + Reset 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. + You have successfully reset your 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 are about to reset your Smart-eID data. This can also be used for troubleshooting as well. LABEL ANDROID IOS - Если ваше устройство не обнаруживает идентификационную карту, проверьте возможности устройства, нажав «Проверить устройство и идентификационную карту» на начальной странице. + Вы собираетесь сбросить данные Smart-eID. Это также может потребоваться для устранения ошибок. - You can find more information on compatible devices on our %1mobile device list%2. + Are you sure you want to reset the Smart-eID? LABEL ANDROID IOS - Подробную информацию о совместимых устройствах см. в нашем %1списке мобильных устройств%2. + Сбросить настройки 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. - Ввести + Reset + LABEL ANDROID IOS + Сбросить - six-digit PIN + Resetting 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 according to the first line. - сейчас! + Reset the Smart-eID + LABEL ANDROID IOS + Сбросить Smart-eID + + + SmartSettingsView - This is only possible if you have exchanged the five-digit Transport PIN with a six-digit PIN beforehand. + Smart-eID LABEL ANDROID IOS - Возможно, только если 5-значный временный PIN-код уже изменен на 6-значный PIN-код. + Smart-eID - Open YouTube video + Renew Smart-eID LABEL ANDROID IOS - Открыть видео на YouTube + Обновить Smart-eID - You can also watch this YouTube video explaining the process. + Renew your Smart-eID with current data LABEL ANDROID IOS - Вы также можете просмотреть видео с описанием процесса на YouTube. + Обновить Smart-eID с актуальными данными - - - TutorialReaderMethodSacMobile - Tutorial: Smartphone as card reader + Delete Smart-eID LABEL ANDROID IOS - Руководство: Смартфон в качестве устройства чтения карт + Удалить Smart-eID - App on tablet or smartphone <b>without</b> NFC chip + Delete Smart-eID data from your device LABEL ANDROID IOS - Приложение на планшете или смартфоне <b>без</b> чипсета NFC + Удалить данные Smart-eID из вашего устройства - Smartphone <b>with</b> NFC chip as card reader + Try Smart-eID LABEL ANDROID IOS - Смартфон <b>с</b> чипсетом NFC в качестве устройства чтения карт + Попробовать Smart-eID - Install AusweisApp2 on both your device without NFC <b>and</b> your smartphone with NFC capability. + Show Smart-eID data LABEL ANDROID IOS - Установите AusweisApp2 на устройство без NFC <b>и</b> смартфон с поддержкой NFC. + Показать данные Smart-eID - Both devices have to be connected to the same WiFi network + Change Smart-eID PIN LABEL ANDROID IOS - Оба устройства должны быть подключены к одной сети Wi-Fi. + Изменить PIN-код для Smart-eID - Now choose "Remote" in the AusweisApp2 on your smartphone... + Change the chosen Smart-eID PIN LABEL ANDROID IOS - Далее выберите «Удаленный доступ» в AusweisApp2 на смартфоне… + Изменить PIN-код для выбранной Smart-eID + + + SmartSetupStartView - Now + Smart-eID LABEL ANDROID IOS - сейчас + Smart-eID - Start pairing + 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-код идентификационной карты и подключение к Интернету. - Pairing code + Set up Smart-eID LABEL ANDROID IOS - Код сопряжения + Создание Smart-eID - appears! + Smart-eID setup LABEL ANDROID IOS - отображается! + Настройка Smart-eID + + + SmartUpdateStartView - 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 для этого приложения. + 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-код идентификационной карты и подключение к Интернету. - Now open the AusweisApp2 on your device <b>without</b> NFC and select <b>Configure remote service</b>. - LABEL IOS - Откройте AusweisApp2 на вашем устройстве <b>без</b> NFC и выберите <b>Сконфигурировать удаленную службу</b>. + 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 становится недействительной, ее нельзя использовать до завершения процесса обновления. - 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 и выберите <b>Смартфон в качестве устройства чтения карт</b>. + Renew Smart-eID + LABEL ANDROID IOS + Обновить Smart-eID - Now select <b>Settings</b>. + Renew the Smart-eID LABEL ANDROID IOS - Далее выберите <b>Настройки</b>. + Обновить Smart-eID - Choose smartphone from list + Smart-eID renewal LABEL ANDROID IOS - Выбрать смартфон из списка + Обновление Smart-eID + + + 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. + Устройство «%1» запрашивает доступ к вашей Smart-eID. - 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 + TabbedPane - What is the online ID function? - LABEL ANDROID IOS - Что такое функция онлайн-идентификации? + Tab selected + - You can use it to authenticate yourself in the internet - LABEL ANDROID IOS - Вы можете использовать ее для самоаутентификации в сети Интернет + You may navigate to different tabs by using the up/down arrows. + LABEL DESKTOP Additional description of TabbedPane behavior for a11y. + + + + TabbedReaderView - and also to deal with administrative paperwork and business matters electronically! - LABEL ANDROID IOS - и таким образом решать административные и деловые вопросы в электронном виде! + Card Readers + LABEL DESKTOP + Устройства чтения карт - Alright, but is it secure? - LABEL ANDROID IOS - Хорошо, а это безопасно? + Smartphone as card reader + Смартфон в качестве устройства чтения карт - Of course, because we use a so called - LABEL ANDROID IOS - Конечно, потому что мы используем так называемую + USB card reader + USB-устройство чтения карт - Mutual authentication - LABEL ANDROID IOS - обоюдную аутентификацию: + Found new USB card reader that is suitable for the ID card. The workflow may now be continued. + + + + 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 - Где можно использовать функцию онлайн-идентификации? - - - On every website of a provider where you see this icon: - LABEL ANDROID IOS - На любом сайте провайдера, где есть такой символ: - + TitleBarNavigation - By the way, you can find many services directly in the AusweisApp2 <b>provider list</b>. + Cancel LABEL ANDROID IOS - Кстати, многие службы перечислены в <b>списке провайдеров</b> AusweisApp2. + Отмена - The <b>integrated self-authentication</b> is a special service to view the data saved on your ID card. + Back LABEL ANDROID IOS - <b>Интегрированная самоаутентификация</b> — это специальная служба для просмотра данных, сохраненных на идентификационной карте. + Назад + + + TransportPinReminderView - And this is how it works + Do you know your six-digit ID card PIN? LABEL ANDROID IOS - Как это работает + Вы знаете 6-значный PIN-код идентификационной карты? - The AusweisApp2 will always display <b>who</b> wants to access <b>which</b> of your data. + No LABEL ANDROID IOS - AusweisApp2 всегда показывает, <b>кто</b> и <b>какие</b> данные запрашивает. + Нет - To allow the shown service access to the requested data click "Proceed to PIN entry" + Yes 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. - Ввести + Да - 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 - 6-значный PIN-код + Онлайн-идентификация с помощью временного PIN-кода невозможна. Для использования функции eID необходим 6-значный PIN-код идентификационной карты, который пользователь создает самостоятельно. Чтобы настроить Smart-eID, необходимо предварительно задать 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. - сейчас! + To set up a Smart-eID you also need to have assigned a six-digit PIN beforehand. + LABEL ANDROID IOS + @@ -5962,6 +4259,21 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& LABEL ANDROID IOS Расширенные настройки деактивированы. + + Open website + LABEL DESKTOP + Открыть сайт + + + Privacy statement + LABEL DESKTOP + Положение о конфиденциальности + + + Accessibility statement + LABEL DESKTOP + Заявление о доступности + WhiteListSurveyView @@ -5976,9 +4288,9 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& Отправить данные устройства? - 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. @@ -6010,6 +4322,14 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& Отправить + + 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 @@ -6173,7 +4493,7 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& Reason: INFO ALL_PLATFORMS Failure code (string) of current workflow error. - + Причина @@ -6323,7 +4643,7 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& d. MMMM yyyy, hh:mm:ss AP - LABEL DESKTOP Timestamp, formatted according to the selected language + LABEL DESKTOP Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString d MMMM yyyy г., hh:mm:ss @@ -6462,9 +4782,9 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& Брандмауэры сторонних провайдеров - Outgoing AusweisApp2 rule + Outgoing %1 rule LABEL DESKTOP - Исходящее правило AusweisApp2 + Исходящее правило %1 Exists: %1 @@ -6472,9 +4792,9 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& Существует: %1 - Incoming AusweisApp2 rule + Incoming %1 rule LABEL DESKTOP - Входящее правило AusweisApp2 + Входящее правило %1 Windows firewall rules @@ -6533,8 +4853,8 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& dd.MM.yyyy, hh:mm:ss - LABEL DESKTOP Timestamp - dd.MM.yyyy, hh:mm:ss + LABEL DESKTOP Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString + дд.ММ.гггг, чч:мм:сс Last connection: %1 @@ -6594,12 +4914,12 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& Service addresses LABEL DESKTOP - + Служебные адреса Not bound LABEL DESKTOP - + Не привязано @@ -6764,7 +5084,7 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& The program received an unknown message from the server. - ERROR_MASKED ALL_PLATFORMS The type of a POAS message could not be determined. + ERROR_MASKED ALL_PLATFORMS The type of a PAOS message could not be determined. Программа получила неизвестное сообщение с сервера. @@ -6798,9 +5118,9 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& Сбой аутентификации. - Your card reader does not support Extended Length communication and cannot be used to read the ID card. Unfortunately, the %1 has no influence on this restriction. - ERROR ALL_PLATFORMS DidAuthenticateEAC2 was not able to send the certificates to the card because the card reader does not support extended length. - Ваше устройство чтения карт не поддерживает связь по протоколу с расширенной длиной и не может использоваться для считывания идентификационной карты. К сожалению, %1 не влияет на это ограничение. + The length of the data sent to the ID card was not accepted. Either the data is faulty or your card reader does not support Extended Length communication and cannot be used to read the ID card. Unfortunately, the %1 has no influence on this restriction. + ERROR ALL_PLATFORMS A card command failed because the data length was wrong or the card reader does not support Extended Length. + Размер данных, отправленных на идентификационную карту, не был принят. Либо данные неверны, либо ваше устройство чтения карт не поддерживает связь по протоколу с расширенной длиной и не может использоваться для считывания идентификационной карты. К сожалению, %1 не влияет на это ограничение. No certificate description available. @@ -6828,7 +5148,7 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& Программа получила ошибку с сервера. - 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. @@ -6847,11 +5167,6 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& 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 @@ -6968,9 +5283,9 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& Произошла ошибка при обмене данными с идентификационной картой. Убедитесь в том, что идентификационная карта правильно расположена на устройстве чтения карт, и повторите попытку. - 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. @@ -7017,11 +5332,6 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& 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. @@ -7033,9 +5343,9 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& Ошибка запроса соединения со смартфоном, используемым в качестве устройства чтения карт (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). @@ -7082,12 +5392,55 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& ERROR ALL_PLATFORMS Starting the update failed. Не удалось запустить новый процесс обновления. - - - governikus::HistoryModelSearchFilter - dd.MM.yyyy - dd.MM.yyyy + 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 + Не удалось получить сервисную информацию о 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. + Smart-eID больше не готова к использованию. Причиной может быть неправильный ввод PIN-кода для Smart-eID трижды. Вы можете персонализировать новую Smart-eID, чтобы устранить проблему. + + + The preparation of the Smart-eID failed. + ERROR ANDROID The preparation of the Smart-eID Applet failed + Сбой подготовки Smart-eID. + + + The program did not receive a StartPaosResponse message from the server. + ERROR_MASKED ALL_PLATFORMS The PAOS message StartPaosResponse was not received. + Программа не получила сообщение StartPaosResponse с сервера. + + + The server could not process the client request. + ERROR_MASKED ALL_PLATFORMS + Серверу не удалось обработать клиентский запрос. + + + 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 Поддержка @@ -7139,6 +5492,7 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& dd.MM.yyyy hh:mm:ss + 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:ss @@ -7198,7 +5552,8 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& governikus::NotificationModel hh:mm:ss - hh:mm:ss + LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString + чч:мм:сс @@ -7208,11 +5563,6 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& 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. @@ -7228,11 +5578,6 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& 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. @@ -7263,169 +5608,96 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& 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 - dd.MM.yyyy hh:mm - - - Provider: - LABEL ALL_PLATFORMS - Провайдер: - - - Purpose: - LABEL ALL_PLATFORMS - Цель: - - Read access: - 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. + Вы дважды ввели неправильный 6-значный PIN-код для Smart-eID. После третьей попытки неправильного ввода вы больше не сможете использовать Smart-eID, и ее придется настроить еще раз. - Write access (update): - LABEL ALL_PLATFORMS - Доступ для записи (обновление): + The input does not match. Please choose a new Smart-eID PIN. + ALL_PLATFORMS Error message if the new pin confirmation mismatches. + Введенные данные не совпадают. Выберите новый PIN-код для Smart-eID. - dd.MM.yyyy - LABEL ALL_PLATFORMS - dd.MM.yyyy + The input does not match. Please choose a new ID card PIN. + Введенные данные не совпадают. Выберите новый PIN-код идентификационной карты. + + + governikus::PinResetInformationModel - hh:mm AP - LABEL ALL_PLATFORMS - hh:mm + https://www.personalausweisportal.de/EN + https://www.personalausweisportal.de/EN - At %1 %2 the following data were saved: - LABEL ALL_PLATFORMS - %1 %2 сохранены следующие данные. + If you have forgotten your ID card PIN or do not have access to the PUK, you may turn to the competent authority and set a new PIN there.<br/><br/>For further information, please visit the ID card portal. + LABEL ALL_PLATFORMS Hint text for requested PUK but both, PUK and PIN are not known. + Если вы забыли PIN-код идентификационной карты или у вас нет доступа к PUK-коду, то вы можете обратиться в ответственное учреждение и установить новый PIN-код.<br/><br/>Подробную информацию см. на портале идентификационных карт. - History - LABEL ALL_PLATFORMS - Журнал + If you know neither your Transport PIN nor your ID card PIN, you may turn to the competent authority and set a new PIN there.<br/><br/>For further information, please visit the ID card portal. + LABEL ALL_PLATFORMS Hint text for requested Transport PIN but both, Transport PIN and PIN are not known. + Если вы не знаете временный PIN-код и PIN-код идентификационной карты, то вы можете обратиться в ответственное учреждение и установить новый PIN-код.<br/><br/>Подробную информацию см. на портале идентификационных карт. - Entry - LABEL ALL_PLATFORMS - Запись + If you cannot recall your ID card PIN, you may turn to the competent authority and set a new PIN there.<br/><br/>For further information, please visit the ID card portal. + LABEL ALL_PLATFORMS Hint text for PIN but it is unknown. + Если вы не можете вспомнить PIN-код идентификационной карты, обратитесь в ответственное учреждение для создания нового PIN-кода.<br/><br/>Подробную информацию см. на портале идентификационных карт. - Content - LABEL ALL_PLATFORMS - Содержание + You may turn to the competent authority and set a new ID card PIN there.<br/><br/>For further information, please visit the ID card portal. + LABEL ALL_PLATFORMS Hint when a workflow failed because of a blocked PUK + Вы можете обратиться в ответственное учреждение и установить там новый PIN-код идентификационной карты.<br/><br/>Подробную информацию см. на портале идентификационных карт. - At %1 %2 the following data has been read out of your ID card: - LABEL ALL_PLATFORMS - %1 %2 считаны следующие данные вашей идентификационной карты. + Please contact the competent authority to activate the eID function.<br/><br/>For further information, please visit the ID card portal. + LABEL ALL_PLATFORMS Hint when a workflow failed because the eID function was not activated + Чтобы активировать функцию онлайн-идентификации, обратитесь в ответственное учреждение.<br/><br/>Дополнительную информацию см. на портале идентификационных карт. - Information + Open website LABEL ALL_PLATFORMS - Информация - - - - governikus::PinResetInformationModel - - https://www.personalausweisportal.de/EN - https://www.personalausweisportal.de/EN + Открыть сайт You cannot use the PUK to reset your previously set card PIN. If you forgot your card PIN, you can use the PIN Reset Service to request a new PIN. LABEL ALL_PLATFORMS Hint text for requested PUK but both, PUK and PIN are not known. - + Невозможно использовать PUK-код для сброса ранее установленного PIN-кода карты. Если вы забыли PIN-код своей карты, вы можете воспользоваться службой сброса PIN-кода, чтобы запросить новый PIN-код. Go to PIN Reset Service LABEL ALL_PLATFORMS - + Перейти к службе сброса PIN-кода You can request activation of the eID function without charge. LABEL ALL_PLATFORMS Hint when a workflow failed because the eID function was not activated - + Вы можете запросить активацию функции eID без дополнительной оплаты. Go to Activation Service LABEL ALL_PLATFORMS - + Перейти к службе активации Request a new card PIN free of charge to be able to use the eID function again. LABEL ALL_PLATFORMS Hint when a workflow failed because of a blocked PUK - - - - - 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 секунд бесплатно, далее + Запросите новый PIN-код карты бесплатно, чтобы снова иметь возможность использовать функцию eID. - landline costs %1; - INFO ALL_PLATFORMS Land line charges when calling the hotline. - стоимость стационарной связи %1; + 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. + Если вы не знаете ни своего временного PIN-кода, ни PIN-кода карты, вы можете бесплатно запросить новый PIN-код, воспользовавшись службой сброса PIN-кода. - mobile costs may vary. - INFO ALL_PLATFORMS Cell phone charges when calling the hotline. - Стоимость мобильной связи может отличаться. + If you have forgotten your ID 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. + Если вы забыли PIN-код карты, вы можете бесплатно запросить новый PIN-код, воспользовавшись службой сброса PIN-кода. - mobile costs %1 - Стоимость мобильной связи %1 + You can use the PIN Reset Service to request a new card PIN free of charge. + LABEL ALL_PLATFORMS Hint text for requested Transport PIN but both, Transport PIN and PIN, are not known. + Вы можете воспользоваться службой сброса PIN-кода, чтобы бесплатно запросить новый PIN-код карты. @@ -7455,18 +5727,9 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& 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 hh:mm:ss @@ -7478,24 +5741,24 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& 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. - + Не удается связаться с локальным приложением %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. - + Ваше локальное приложение %1 не запущено. Запустите локальное приложение %1 и повторите попытку. Would you like to try again? ERROR ALL_PLATFORMS The local AusweisApp (access via reverse proxy) is not reachable, part of an HTML error page. - Повторить попытку? + Повторить попытку? Try again ERROR ALL_PLATFORMS The local AusweisApp (access via reverse proxy) is not reachable, part of an HTML error page. - Повторить попытку + Повторить попытку @@ -7522,11 +5785,6 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& LABEL ALL_PLATFORMS Сопряжено, но не поддерживается - - Paired, but unavailable - LABEL ALL_PLATFORMS - Сопряжено, но недоступно - Unsupported LABEL ALL_PLATFORMS @@ -7539,17 +5797,18 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& 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 - online help - Is embedded in a sentence. - онлайн-справка + Unavailable + LABEL ALL_PLATFORMS + Недоступно - 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. + Click to pair + LABEL ALL_PLATFORMS + Нажмите для сопряжения @@ -7605,14 +5864,17 @@ Please enable NFC to use your smartphone as a card reader (SaC). dd.MM.yyyy - dd.MM.yyyy + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString + дд.ММ.гггг xx.MM.yyyy + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString with unknown day хх.ММ.гггг xx.xx.yyyy + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString with unknown day and month хх.хх.гггг @@ -7679,24 +5941,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. + Сбой онлайн-проверки поддержки Smart-eID вашим устройством. Обратите внимание на то, что для данного процесса требуется интернет-соединение. - 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. + Сбой онлайн-проверки поддержки Smart-eID вашим устройством, поскольку в данный момент на сервер поступает слишком много запросов. Повторите попытку позднее. - 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. + Сбой онлайн-проверки поддержки Smart-eID вашим устройством из-за технических работ на сервере. Повторите попытку позднее. - 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. + Невозможно удалить данные и подготовку Smart-eID из вашего устройства. Обратите внимание на то, что для данного процесса требуется интернет-соединение. + + + 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. + Невозможно удалить данные и подготовку Smart-eID из вашего устройства, поскольку в данный момент на сервер поступает слишком много запросов. Повторите попытку позднее. + + + 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. + Невозможно удалить данные и подготовку Smart-eID из вашего устройства из-за технических работ на сервере. Повторите попытку позднее. + + + 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. + Невозможно удалить данные и подготовку Smart-eID из вашего устройства. Для доступа к требуемой памяти устройства необходимо активировать функцию NFC. Активируйте NFC и перезапустите процесс. + + + 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. + Сбой онлайн-проверки поддержки Smart-eID вашим устройством. Для доступа к требуемой памяти устройства необходимо активировать функцию NFC. Активируйте NFC и повторите попытку. + + + 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. + Сбой онлайн-проверки поддержки Smart-eID вашим устройством. Сбой проверки целостности Google Play. + + + 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. + Сбой онлайн-проверки поддержки Smart-eID вашим устройством. Возникла проблема при аутентификации (например, доступ к ресурсу получен без авторизации, или неавторизованное приложение попыталось получить доступ к компоненту безопасности). + + + 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. + Невозможно удалить данные и подготовку Smart-eID из вашего устройства. Сбой проверки целостности Google Play. + + + 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. + Невозможно удалить данные и подготовку Smart-eID из вашего устройства. Возникла проблема при аутентификации (например, доступ к ресурсу получен без авторизации, или неавторизованное приложение попыталось получить доступ к компоненту безопасности). + + + 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. + Сбой онлайн-проверки поддержки Smart-eID вашим устройством. Убедитесь в том, что установлено интернет-соединение и что антивирусное ПО и брандмауэр не блокируют соединение. + + + 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. + Невозможно удалить данные и подготовку Smart-eID из вашего устройства. Убедитесь в том, что установлено интернет-соединение и что антивирусное ПО и брандмауэр не блокируют соединение. @@ -7724,11 +6036,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 @@ -7755,6 +6077,14 @@ Please enable NFC to use your smartphone as a card reader (SaC). Доступ отклонен. + + governikus::StateEstablishPaceChannel + + The secure channel is opened + INFO ALL_PLATFORMS First status message after the PIN was entered. + Защищенный канал открыт + + governikus::StateFinalizePersonalization @@ -7803,22 +6133,12 @@ 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 - governikus::StateTransmit @@ -7843,18 +6163,11 @@ Please enable NFC to use your smartphone as a card reader (SaC). - governikus::StateWriteHistory - - Validity: -%1 - %2 - LABEL ALL_PLATFORMS - Действие: -%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 - Подготовка результатов + Checking Smart-eID status + LABEL ANDROID IOS + Проверка статуса Smart-eID @@ -7888,8 +6201,8 @@ Please enable NFC to use your smartphone as a card reader (SaC). Макс. длина пакета NFC - AusweisApp2 Version - Версия AusweisApp2 + %1 Version + Версия %1 NFC Tag Type @@ -7909,16 +6222,16 @@ Please enable NFC to use your smartphone as a card reader (SaC). Открыть - Quit AusweisApp2 + Quit %1 LABEL DESKTOP - Выйти из AusweisApp2 + Выйти из %1 governikus::UIPlugInProxy Reverse proxy plugin is enabled - + Активирован плагин обратного прокси-сервера @@ -7941,26 +6254,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! - + Вы попытались запустить более старую версию (%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 @@ -7982,6 +6287,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 @@ -8016,12 +6326,37 @@ 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 + Используемая Smart-eID не принимается сервером. Перезапустите удаленную службу в подключенном смартфоне и повторите попытку, используя физическую идентификационную карту. + + + 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 + Используемая Smart-eID не принимается сервером. Остановите удаленную службу и используйте другую Smart-eID или свяжитесь с провайдером услуг. + + + 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 + Используемая идентификационная карта не принимается сервером. Удалите идентификационную карту из вашего устройства или из устройства чтения карт и используйте Smart-eID или свяжитесь с провайдером услуг. + + + 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 + Обновите Smart-eID и установите новый PIN-код в меню 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 + Перейти в меню Smart-eID @@ -8038,9 +6373,7 @@ Please enable NFC to use your smartphone as a card reader (SaC). The program remains available via the icon in the system tray. Click on the %1 icon to reopen the user interface. - INFO DESKTOP Content of the popup that is shown when the AA2 is closed for the first time. ----------- -INFO DESKTOP Content of the popup that is shown when the AA2 is closed and a workflow is still active and the close/minimize info was not disabled. + INFO DESKTOP Content of the popup that is shown when the AA2 is closed and the close/minimize info was not disabled. Программа по-прежнему доступна через значок на панели задач. Нажмите на символ %1, чтобы снова открыть пользовательский интерфейс. @@ -8083,9 +6416,29 @@ INFO DESKTOP Content of the popup that is shown when the AA2 is closed and a wor Средство просмотра файлов журнала - To close the app, quickly press the back button twice. + To close the app, press the back button twice. INFO ANDROID IOS Hint that is shown if the users pressed the "back" button on the top-most navigation level for the first time (a second press closes the app). - Чтобы закрыть приложение, дважды быстро нажмите кнопку «Назад». + Чтобы закрыть приложение, дважды нажмите кнопку «Назад». + + + The program remains available via the icon in the menu bar. Click on the %1 icon to reopen the user interface. + 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 c0d35f06d..daf2ac61f 100644 --- a/resources/translations/ausweisapp2_uk.ts +++ b/resources/translations/ausweisapp2_uk.ts @@ -5,7 +5,7 @@ DvcsAttributes revision - 52a5aa47f692 + 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,41 +157,24 @@ 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 + Виконайте автентифікацію у провайдера Online identification with Transport PIN is not possible. The self-selected, six-digit ID card PIN is mandatory to use the eID function. - + Онлайн-ідентифікація за допомогою транспортного PIN-коду неможлива. Самостійно обраний шестизначний PIN-код ID-картки обов’язковий для використання функції eID. Do you know your six-digit ID card PIN? Ви знаєте шестизначний PIN-код своєї ID-картки? + + 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» було скасовано, оскільки він не реагував на спроби підключення. Створіть пару з пристроєм знову, щоб використовувати його як пристрій читання карток. + BaseConfirmationPopup @@ -205,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 @@ -302,13 +253,6 @@ LABEL ANDROID IOS A11y button to confirm the PIN and start the provider authenti Версія OpenSSL - - CancelAction - - Cancel - Скасувати - - CardPositionView @@ -339,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-пристрої читання карток @@ -353,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-код більше не дійсний. @@ -414,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-код. @@ -446,55 +417,20 @@ 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-картки. + 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» було скасовано, оскільки він не реагував на спроби підключення. Створіть пару з пристроєм знову, щоб використовувати його як пристрій читання карток. - 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 DESKTOP + Зверніть увагу, що ви можете використати п’ятизначний транспортний PIN-код лише один раз, щоб змінити його на шестизначний PIN-код ID-картки. Якщо ви вже встановили шестизначний PIN-код ID-картки, п’ятизначний транспортний PIN-код більше не дійсний. @@ -505,34 +441,34 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin Якого типу ваш PIN-код? - 6-digit PIN + Six-digit PIN LABEL ALL_PLATFORMS - + Шестизначний PIN-код Set by yourself LABEL ALL_PLATFORMS - + Встановлений вами самостійно - 5-digit Transport PIN + Five-digit Transport PIN LABEL ALL_PLATFORMS - + П’ятизначний транспортний PIN-код Received by mail in PIN letter LABEL ALL_PLATFORMS - + Отриманий поштою в листі з PIN-кодом No PIN LABEL ALL_PLATFORMS - + Немає PIN-коду Lost, forgotten, or never received it LABEL ALL_PLATFORMS - + Загубили, забули або ніколи його не отримували @@ -665,7 +601,7 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin Your mobile device has no NFC interface. This is required to read the ID card. However, you can use a separate smartphone as card reader to utilize the eID function.<br><br>You can find smartphones compatible with the %1 on our website. LABEL ANDROID IOS - Ваш мобільний пристрій не має інтерфейсу NFC. Він потрібен для читання ID-картки. Однак ви можете використовувати окремий смартфон як пристрій читання карток, щоб застосовувати функцію онлайн-ідентифікації.<br><br>Ви можете знайти смартфони, сумісні з %1, на нашому сайті. + Ваш мобільний пристрій не має інтерфейсу NFC. Він потрібен для читання ID-картки. Однак ви можете використовувати окремий смартфон як пристрій читання карток, щоб застосовувати функцію eID.<br><br>Ви можете знайти смартфони, сумісні з %1, на нашому сайті. Open website @@ -695,7 +631,7 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin The NFC interface of your mobile device does not support Extended Length communication and cannot be used to read the ID card. Unfortunately, the %1 has no influence on this restriction.<br><br>You can find smartphones compatible with the %1 on our website. LABEL ANDROID IOS - Інтерфейс NFC вашого мобільного пристрою не підтримує зв’язок за допомогою функції Extended Length і не може використовуватися для читання ID-картки. На жаль, %1 не впливає на це обмеження.<br><br>Ви можете знайти смартфони, сумісні з %1, на нашому сайті. + Інтерфейс NFC вашого мобільного пристрою не підтримує зв’язок за допомогою функції Extended Length і не може використовуватися для читання ID-картки. На жаль, %1 не має впливу на це обмеження.<br><br>Ви можете знайти смартфони, сумісні з %1, на нашому сайті. ID card access failed @@ -787,211 +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. - Тепер ви можете спробувати скористатися функцією: «Дивитися мої особисті дані». Для цього натисніть кнопку «Продовжити». + 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. - Supported + Smart-eID not supported LABEL ANDROID IOS - Підтримується + Smart-eID не підтримується - Not supported + Possible causes are: LABEL ANDROID IOS - Не підтримується + Можливі причини: - Prepared + The setup has not been completed. LABEL ANDROID IOS - Підготовлено + Налаштування не завершено. - Not prepared + The Smart-eID PIN has been entered incorrectly three times. LABEL ANDROID IOS - Не підготовлено + PIN-код Smart-eID було введено неправильно тричі. - Set up + The %1 has been uninstalled temporarily. LABEL ANDROID IOS - Налаштовано + Програму %1 тимчасово видалено. - Not set up + You may continue with the setup of the Smart-eID. LABEL ANDROID IOS - Не налаштовано + - Invalid + Continue LABEL ANDROID IOS - Недійсний + Продовжити - Ready for use + Your device meets the technical requirements for Smart-eID. You may now continue the setup process. LABEL ANDROID IOS - Готово до використання + - - - CheckSmartSuggestionView - Unknown result code: %1 + Smart-eID supported LABEL ANDROID IOS - Невідомий код результату: %1 + - Updating Smart-eID status... - LABEL ANDROID IOS - Триває оновлення статусу Smart-eID… + 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 + - Please wait a moment. + Smart-eID invalid LABEL ANDROID IOS - Трохи зачекайте. + - Smart-eID not supported + Smart-eID check failed 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. + Back LABEL ANDROID IOS - Ваш мобільний пристрій не відповідає технічним вимогам щодо Smart-eID.<br><br>Ви можете перевірити, чи підходять ваш пристрій та ID-картка для використання функції eID. + Назад + + + ConnectSacView - Check device and ID card - LABEL ANDROID IOS - Перевірити пристрій та ID-картку + Pairing + LABEL DESKTOP + Створення пари - Smart-eID invalid - LABEL ANDROID IOS - Smart-eID недійсний - - - 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 є недійсним. - - - 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 не налаштовано + Pairing the device ... + LABEL DESKTOP + Створення пари з пристроєм… - 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 + DarkModeButtons - Check Smart-eID - LABEL ANDROID IOS - Перевірте Smart-eID - - - Your device needs to meet the technical requirements to use the Smart-eID function. - LABEL ANDROID IOS - Для використання функції Smart-eID ваш пристрій має відповідати технічним вимогам. - - - Check here if your device is suitable to set up a Smart-eID. - LABEL ANDROID IOS - Перевірте тут, чи підходить ваш пристрій для налаштування Smart-eID. + System + LABEL ALL_PLATFORMS + Система - Start check - LABEL ANDROID IOS - Почати перевірку + Dark + LABEL ALL_PLATFORMS + - - - ConnectSacView - Pairing - LABEL DESKTOP - Створення пари + Light + LABEL ALL_PLATFORMS + - Pairing the device ... - LABEL DESKTOP - Створення пари з пристроєм… + Set the app appearance to system mode + LABEL ALL_PLATFORMS + - The device "%1" has been paired. - Пару з пристроєм «%1» створено. + 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 + @@ -1017,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 @@ -1037,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 @@ -1045,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 @@ -1119,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 @@ -1134,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 @@ -1164,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 @@ -1174,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 @@ -1204,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 Постачальник @@ -1351,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 @@ -1405,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. @@ -1468,11 +1295,6 @@ INFO ANDROID IOS A new six-digit ID card PIN needs to be supplied. Підтвердьте новий шестизначний PIN-код ID-картки. - - Start the pairing on your smartphone and enter the pairing code shown there in order to use your smartphone as a card reader (SaC). - INFO DESKTOP The pairing code needs to be supplied. - Щоб використовувати смартфон як пристрій читання карток (SaC), почніть на ньому створення пари та введіть показаний на його екрані код створення пари. - Unknown password type: INFO DESKTOP Error message during PIN/CAN/PUK input procedure, the requested password type is unknown; internal error. @@ -1504,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 стане недійсним і вам доведеться знову його налаштувати. @@ -1556,60 +1369,98 @@ 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 ---------- LABEL ANDROID IOS - + Надіслати CAN Send PUK LABEL DESKTOP ---------- LABEL ANDROID IOS - + Надіслати PUK Send pairing code LABEL DESKTOP ---------- LABEL ANDROID IOS - + Надіслати код створення пари Send new ID card PIN LABEL DESKTOP ---------- LABEL ANDROID IOS - + Надіслати новий PIN-код ID-картки Send Transport PIN LABEL DESKTOP ---------- LABEL ANDROID IOS - + Надіслати транспортний PIN-код Send Smart-eID PIN LABEL DESKTOP ---------- LABEL ANDROID IOS - + Надіслати PIN-код Smart-eID Send new Smart-eID PIN LABEL DESKTOP ---------- LABEL ANDROID IOS - + Надіслати новий PIN-код Smart-eID Send ID card PIN LABEL DESKTOP ---------- 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 @@ -1653,52 +1504,58 @@ 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. + Використання режиму розробника примусово вмикає сповіщення. - Close after authentication + Network LABEL DESKTOP - Закрити після автентифікації + Мережа - Use internal notifications + Use the proxy (%1) specified during the installation. LABEL DESKTOP - Використовувати внутрішні сповіщення + Використовувати проксі-сервер (%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. - Використання режиму розробника примусово вмикає сповіщення. + Appearance + LABEL DESKTOP + - Network + Use the system font LABEL DESKTOP - Мережа + - Use the proxy (%1) specified during the installation. + Toggling will restart the %1 LABEL DESKTOP - Використовувати проксі-сервер (%1), зазначений під час інсталяції. + + + + Close %1 after authentication + LABEL DESKTOP + Закрити після автентифікації + + + 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 після завантаження GeneralWorkflow - - 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 було скасовано, оскільки він не реагував на спроби підключення. Створіть пару з пристроєм знову, щоб використовувати його як пристрій читання карток. - Attempts LABEL DESKTOP Спроби - - Remaining ID card PIN attempts: %1 - Залишилося стільки спроб введення PIN-коду ID-картки: %1 - Step %1 of 3 Крок %1 із 3 @@ -1728,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. @@ -1754,254 +1601,32 @@ LABEL ANDROID IOS Перейти до параметрів пристрою читання - More information - LABEL DESKTOP - Додаткова інформація + 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 + LanguageButtonData - Click to view details of history entry. - Натисніть, щоб переглянути відомості про запис в історії. - - - today - LABEL ANDROID IOS - сьогодні - - - yesterday - вчора - - - dd.MM.yyyy - dd.MM.yyyy - - - Tap for more details - LABEL ANDROID IOS - Торкніться, щоб отримати докладніші відомості - - - - HistoryListViewDelegate - - Delete entry - LABEL ANDROID - Видалити запис - - - Delete history entry: %1 - INFO IOS Accessible name for the trash icon of a history entry. - Видалити запис із історії: %1 - - - - HistoryRemovalTimePeriodControl - - Time period - LABEL DESKTOP - Період часу - - - Past hour - LABEL DESKTOP - Минула година - - - Past day - LABEL DESKTOP - Минулий день - - - Past week - LABEL DESKTOP - Минулий тиждень - - - Last four weeks - LABEL DESKTOP - Останні чотири тижні - - - All history - LABEL DESKTOP - Уся історія - - - - HistoryView - - Delete history? - INFO DESKTOP Header of the confirmation dialog to clear the entire authentication history. - Видалити історію? - - - All history entries will be deleted. - INFO DESKTOP Content of the confirmation dialog to clear the entire authentication history. - Усі записи в історії буде видалено. - - - Deleted %1 entries from the history. - INFO DESKTOP Feedback how many history entries were removed. - Видалено записи з історії (%1). - - - History - LABEL DESKTOP - Історія - - - Search in history - LABEL DESKTOP - Пошук в історії - - - today - сьогодні - - - yesterday - вчора - - - dd.MM.yyyy - dd.MM.yyyy - - - 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 - 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 - Німецька + German + LABEL ALL_PLATFORMS + Німецька Set language to german @@ -2039,14 +1664,6 @@ LABEL ANDROID IOS Использовать русский язык - - LanguageSelectionPopup - - Select language - LABEL ANDROID IOS - Вибрати мову - - LicenseInformation @@ -2057,16 +1674,16 @@ LABEL ANDROID IOS LocalNetworkInfo - - To be able to use your smartphone as card reader (SaC), please make sure that access to the local network is allowed. - INFO IOS Let user know to check the application settings for local network permission - Щоб мати можливість використовувати свій смартфон як пристрій читання карток (SaC), переконайтеся, що доступ до локальної мережі дозволено. - 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 @@ -2169,14 +1786,14 @@ INFO ANDROID IOS The current logfile is about to be removed, user confirmation r Фільтр - Select level: + Level LABEL ANDROID IOS - Вибрати рівень: + Рівень - Select category: + Category LABEL ANDROID IOS - Вибрати категорію: + Категорія Currently there are no log entries matching your filter. @@ -2184,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 @@ -2191,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 @@ -2228,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 @@ -2243,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 @@ -2266,11 +1888,6 @@ LABEL ANDROID IOS LABEL DESKTOP Загальні - - Diagnosis and logs - LABEL DESKTOP - Діагностика й журнали - Version information LABEL DESKTOP @@ -2280,9 +1897,7 @@ LABEL ANDROID IOS Software license - LABEL DESKTOP ----------- -LABEL ANDROID IOS + LABEL DESKTOP Ліцензія на програмне забезпечення @@ -2298,254 +1913,136 @@ LABEL ANDROID IOS Довідка та зворотний зв’язок - Tutorial + Privacy statement LABEL ANDROID IOS - Посібник + Заява про конфіденційність - Do you want to know how to use %1? + Accessibility statement LABEL ANDROID IOS - Хочете дізнатися, як використовувати %1? + Заява про спеціальні можливості - Video tutorials + Rate %1 LABEL ANDROID IOS - Відеопосібники + Оцінити %1 - Do you want to see the video tutorials? + Logs LABEL ANDROID IOS - Бажаєте дивитися відеопосібники? + Журнали - FAQ + Information LABEL ANDROID IOS - Запитання й відповіді + Інформація - Do you have further questions about %1? + List of Providers LABEL ANDROID IOS - Маєте додаткові запитання про %1? + - Support - LABEL ANDROID IOS - Підтримка + Data and logs + LABEL DESKTOP + Діагностика й журнали - Do you need further support? + FAQ - Frequently asked questions LABEL ANDROID IOS - Потрібна додаткова підтримка? + Запитання й відповіді - Privacy statement + Contact LABEL ANDROID IOS - Заява про конфіденційність + Підтримка - Do you want to read the privacy statement? + Show Logs LABEL ANDROID IOS - Бажаєте прочитати заяву про конфіденційність? + Журнали - Accessibility statement + Send log to the support LABEL ANDROID IOS - Заява про спеціальні можливості + Повідомити про помилку - Do you want to read the accessibility statement? + Terms of use and software license LABEL ANDROID IOS - Бажаєте прочитати заяву про спеціальні можливості? + Ліцензія на програмне забезпечення + + + MoreViewDiagnosis - Rate %1 - LABEL ANDROID IOS - Оцінити %1 + Logs + LABEL DESKTOP + Журнали - Do you want to rate us in the App Store? - LABEL ANDROID IOS - Бажаєте оцінити нас у магазині App Store? + Show logs + LABEL DESKTOP + Показати журнали - Do you want to rate us in the Google Play Store? - Бажаєте оцінити нас у магазині Google Play? + Show system data + LABEL DESKTOP + Показати діагностику - Diagnosis - LABEL ANDROID IOS - Діагностика + System data + LABEL DESKTOP + Діагностика + + + MoreViewGeneral - Logs - LABEL ANDROID IOS - Журнали + Open website + LABEL DESKTOP + Відкрити сайт - Do you want to view the logs of %1? - LABEL ANDROID IOS - Бажаєте переглянути журнали %1? + Privacy statement + LABEL DESKTOP + Заява про конфіденційність - Report error - LABEL ANDROID IOS - Повідомити про помилку - - - Did you find a bug? Please help us by sending us the log file together with a description of the error. - LABEL ANDROID IOS - Знайшли помилку? Допоможіть нам, надіславши нам файл журналу разом з описом помилки. - - - Information - LABEL ANDROID IOS - Інформація - - - Do you want to see detailed information about %1? - LABEL ANDROID IOS - Бажаєте дивитися докладну інформацію про %1? - - - Do you want to read the software licenses? - LABEL ANDROID IOS - Бажаєте ознайомитися з ліцензіями на програмне забезпечення? - - - Do you want to view the release notes of %1? - LABEL ANDROID IOS - Бажаєте переглянути примітки до випуску %1? - - - - MoreViewDiagnosis - - Diagnosis - LABEL DESKTOP - Діагностика - - - You can view and save the diagnosis information of the AusweisApp2 and your system here. - LABEL DESKTOP - Тут можна переглянути й зберегти інформацію про діагностику програми AusweisApp2 та вашої системи. - - - Show diagnosis - LABEL DESKTOP - Показати діагностику - - - Logs - LABEL DESKTOP - Журнали - - - Do you want to view the logs of %1? + Accessibility statement LABEL DESKTOP - Бажаєте переглянути журнали %1? + Заява про спеціальні можливості - Show logs + Do you want to see a list of service providers? LABEL DESKTOP - Показати журнали + - Report error + List of Providers 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 DESKTOP - Знайшли помилку? Допоможіть нам, надіславши нам файл журналу разом з описом помилки. + Запитання й відповіді - Open website + Contact 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 - Бажаєте дивитися відеопосібники? - + NavigationAction - 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? - LABEL DESKTOP - Бажаєте прочитати заяву про спеціальні можливості? - - - Setup assistant - LABEL DESKTOP - Помічник з налаштування - - - Do you want to run the setup assistant again? - LABEL DESKTOP - Бажаєте знову запустити помічник з налаштування? + Cancel + Скасувати - Start setup assistant - LABEL DESKTOP - Запустити помічник з налаштування + Back + Назад @@ -2569,22 +2066,10 @@ LABEL ANDROID IOS NavigationView - - History - Історія - Start Почати - - Provider - Постачальник - - - Remote - Віддалений доступ - Settings Параметри @@ -2593,6 +2078,10 @@ LABEL ANDROID IOS Help Довідка + + Card reader + Пристрій читання карток + NfcWorkflow @@ -2628,12 +2117,12 @@ LABEL ANDROID IOS NFC scan is not running. - INFO ANDROID IOS NFC is available but needs to be activated in the settings of the smartphone. + INFO ANDROID IOS NFC is available and enabled but needs to be started. Сканування NFC не виконується. Please start the NFC scan. - INFO ANDROID IOS NFC is available but needs to be activated in the settings of the smartphone. + INFO ANDROID IOS NFC is available and enabled but needs to be started. Почніть сканування NFC. @@ -2669,7 +2158,12 @@ LABEL ANDROID IOS Please place your ID card directly on the device's back side.<br/><br/>The exact position of the ID card is device dependent. The animations depict possible positions. Keep one position for several seconds before trying another one and do not move the ID card after contact was established. INFO ANDROID The ID card may be inserted, the authentication process may be started. - Покладіть свою ID-картку на пристрій; точне положення залежить від пристрою. На анімації показано можливі положення. Утримуйте ID-картку в одному положенні кілька секунд, перш ніж спробувати інше, і не переміщайте її після встановлення контакту. + Покладіть ID-картку безпосередньо на задній бік пристрою.<br/><br/>Точне положення ID-картки залежить від пристрою. На анімації показано можливі положення. Утримуйте ID-картку в одному положенні кілька секунд, перш ніж спробувати інше, і не переміщайте її після встановлення контакту. + + + The device "%1" wants to use this smartphone as card reader and connect to your id card. + INFO ANDROID IOS %1 will be replaced with the name of the device. + Пристрій «%1» намагається використовувати цей смартфон як пристрій читання карток і встановити з’єднання з вашою ID-карткою. @@ -2697,7 +2191,7 @@ LABEL ANDROID IOS The password is visible. Digits entered so far: %1 LABEL DESKTOP Screenreader text for the password field - + Пароль показано. Наразі введені цифри: %1 @@ -2717,12 +2211,13 @@ 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. + Видалити останній знак, вимкнено до введення. , disabled until input is complete. LABEL ANDROID IOS A11y text, appended onto the "submit" button text when the button is disabled. - + , вимкнено до завершення введення. @@ -2732,6 +2227,52 @@ LABEL ANDROID IOS Вимкнено + + PairingCodeInfoView + + Pairing Information + LABEL ANDROID IOS + Інформація про створення пари + + + Open %1 on your %2other device%3. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 3 + Відкрийте %1 на своєму %2іншому пристрої%3. + + + On that device go to %1Settings%2 and then %1Smartphone as card reader%2 resp. %1Manage pairings%2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 3. %1 and %2 are surrounding tags for bold font. + Перейдіть на тому пристрої до розділу %1Параметри%2, а тоді виберіть %1Смартфон як пристрій читання карток%2 і %1Керування створенням пари%2. + + + Choose this smartphone in the list to pair it. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 3 + Виберіть цей смартфон у переліку, щоб створити з ним пару. + + + + PairingProcessInfo + + Open %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. + Відкрийте %1 на своєму смартфоні як пристрій читання карток. + + + On that device choose %1Card reader%2 and then %1Pair device%2 resp. %1Pair new device%2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 4. %1 and %2 are surrounding tags for bold font. + Виберіть на тому пристрої %1Пристрій читання карток%2, а тоді — %1Створити пару з пристроєм%2 і %1Створити пару з новим пристроєм%2. + + + Choose the smartphone in the list shown here to pair it. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 4 of 4 + У наведеному тут переліку виберіть смартфон, щоб створити з ним пару. + + + Ensure that the %1 on your Smartphone as card reader has at least version %2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 4. %1 is a placeholder-tag for the app name. + Переконайтеся, що %1 на вашому смартфоні як пристрiй читання карток має версію не нижче %2. + + PasswordInfoContent @@ -2745,52 +2286,44 @@ LABEL ANDROID IOS What is the card PIN? LABEL ALL_PLATFORMS - + Що таке PIN-код картки? PIN information LABEL ALL_PLATFORMS Інформація про PIN-код - - The card PIN is a 6-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?' - - Where can I find the card PIN? LABEL ALL_PLATFORMS - - - - 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 5-digit Transport PIN. Only when you have set a 6-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-код картки? How do I choose a secure PIN? LABEL ALL_PLATFORMS - + Як вибрати безпечний PIN-код? - For your 6-digit 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. + For your six-digit 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 PIN?' paragraph 1/3 - + Для свого шестизначного PIN-коду виберіть комбінацію цифр, яку неможливо вгадати. Наприклад, не використовуйте ані послідовність цифр «123456», ані дату народження, ані жодні інші числа, надруковані на вашій ID-картці. - You can change your 6-digit PIN at any time and an unlimited number of times as long as you know your valid PIN. + You can change your six-digit PIN at any time and an unlimited number of times as long as you know your valid PIN. INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure PIN?' paragraph 2/3 - + Ви можете змінювати свій шестизначний PIN-код у будь-який час і необмежену кількість разів, якщо ви знаєте свій дійсний PIN-код. 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-код у таємниці та змініть його, якщо він стане відомий іншій особі. What is the Transport PIN? LABEL ALL_PLATFORMS - + Що таке транспортний PIN-код? Transport PIN information @@ -2798,39 +2331,24 @@ LABEL ANDROID IOS Інформація про транспортний PIN-код - The 5-digit Transport PIN was sent to you in the PIN letter by mail after you applied for your ID card. + The five-digit Transport PIN was sent to you in the PIN letter by mail after you applied for your ID card. INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 1/3 - + П’ятизначний транспортний PIN-код був надісланий вам у листі з PIN-кодом поштою після того, як ви подали заяву на отримання ID-картки. - If you did not set a self-selected 6-digit card PIN when you picked up your ID card, you can do so using the Transport PIN. + If you did not set a self-selected six-digit card PIN when you picked up your ID card, you can do so using the Transport PIN. INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 2/3 - + Якщо ви не встановили самостійно обраний шестизначний PIN-код картки, коли забирали ID-картку, ви можете зробити це за допомогою транспортного PIN-коду. Once you have set a card PIN, the Transport PIN loses its validity. INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 3/3 - - - - 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 - - - - 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 - + Після встановлення PIN-коду картки транспортний PIN-код втрачає чинність. Where do I find the PUK? LABEL ALL_PLATFORMS - + Де я можу дізнатися PUK-код картки? PUK information @@ -2838,34 +2356,34 @@ LABEL ANDROID IOS Інформація про PUK-код - The PUK is a 10-digit number that you can find in the PIN letter that was sent to you by mail after you applied for your ID card. + The PUK is a ten-digit number that you can find in the PIN letter that was sent to you by mail after you applied for your ID card. INFO ALL_PLATFORMS Answer to the question 'Where do I find the PUK?' - + PUK-код – це десятизначний номер, який ви можете знайти в листі з PIN-кодом, надісланому вам поштою після того, як ви подали заяву на отримання ID-картки. Why is the PUK required? LABEL ALL_PLATFORMS - + Навіщо потрібен PUK-код? The PUK is required if the card PIN has been entered incorrectly three times in a row. As a result, the card PIN is blocked. INFO ALL_PLATFORMS Answer to the question 'Why is the PUK required?' - + PUK-код потрібен, якщо PIN-код-картки було введено неправильно тричі поспіль. Внаслідок цього PIN-код-картки блокується. What is the PUK's purpose? LABEL ALL_PLATFORMS - + Для чого призначений PUK-код? By entering the PUK, you unblock the card PIN and have another three chances to enter the correct PIN. INFO ALL_PLATFORMS Answer to the question 'What is the PUK's purpose?' - + Ввівши PUK-код, ви розблоковуєте PIN-код картки й маєте ще три спроби ввести правильний PIN-код. Why is the CAN required? LABEL ALL_PLATFORMS - + Навіщо потрібен CAN-код? CAN information @@ -2875,32 +2393,32 @@ LABEL ANDROID IOS When is the card access number (CAN) required? LABEL ALL_PLATFORMS - + Коли потрібен номер доступу до картки (CAN)? The card access number (CAN) is required when the card PIN has been entered incorrectly twice. INFO ALL_PLATFORMS Answer to the question 'When is the card access number (CAN) required?' - + Номер доступу до картки (CAN) потрібен, коли PIN-код картки було двічі введено неправильно. Why do I have to enter the CAN before a third attempt? LABEL ALL_PLATFORMS - + Чому потрібно вводити CAN-код перед третьою спробою? A third incorrect entry blocks your PIN and you can no longer use the eID function until it is unblocked. Requesting the CAN ensures that a third incorrect entry can only be made with direct access to your ID card. INFO ALL_PLATFORMS Answer to the question 'Why do I have to enter the CAN before a third attempt?' - + Третє неправильне введення призведе до блокування PIN-коду, і ви більше не зможете користуватися функцією eID, доки його не буде розблоковано. Запит CAN-коду гарантує, що третє неправильне введення може бути зроблене лише за умови прямого доступу до вашої ID-картки. Where can I find the CAN? LABEL ALL_PLATFORMS - + Де я можу дізнатися CAN-код картки? - The CAN is a 6-digit number that can be found on the bottom right of the front of the ID card. + The CAN is a six-digit number that can be found on the bottom right of the front of the ID card. INFO ALL_PLATFORMS Answer to the question 'Where can I find the CAN?' - + CAN-код – це шестизначний номер, який можна знайти в нижній правій частині лицьового боку ID-картки. The Card Access Number (CAN) allows to access the imprinted data of the ID card. The CAN is a six-digit number that can be found on the front of the ID card. It is located at the bottom right next to the validity date (marked in red). @@ -2917,12 +2435,12 @@ LABEL ALL_PLATFORMS Just like the physical ID card, the Smart-eID stored on your Smartphone can be blocked. This might be required if you ever lose your device. INFO ANDROID IOS Description text of Smart-eID PIN - + Так само як і фізичну ID-картку, Smart-eID, збережений на вашому смартфоні, можна заблокувати. Це може знадобитися, якщо ви коли-небудь загубите свій пристрій. To revoke an active Smart-eID, a blocking code is required. The blocking code will be displayed after successfully creating the Smart-eID. Furthermore, it is contained in the letter you will receive after creation. INFO ANDROID IOS Description text of Smart-eID PIN - + Щоб відкликати активний Smart-eID, потрібен код блокування. Код блокування відобразиться після успішного створення Smart-eID. Крім того, він міститься в листі, який ви отримаєте після створення. No PIN known @@ -2932,83 +2450,133 @@ LABEL ALL_PLATFORMS You do not know your PIN? LABEL ALL_PLATFORMS - + Ви не знаєте свій PIN-код? - You have not yet set a 6-digit card PIN and cannot find the PIN letter with the Transport PIN? + You have not yet set a six-digit card PIN and cannot find the PIN letter with the Transport PIN? INFO ALL_PLATFORMS - + Ви ще не встановили шестизначний PIN-код картки й не можете знайти лист із транспортним PIN-кодом? You set a card PIN when picking up your ID card or later by yourself, but you can no longer remember it? INFO ALL_PLATFORMS - + Ви встановили PIN-код картки під час отримання ID-картки або пізніше самостійно, але вже не пам’ятаєте його? Learn more about the two types of PIN LABEL ALL_PLATFORMS - + Дізнайтеся більше про два типи PIN-кодів Types of PIN LABEL ALL_PLATFORMS - + Типи PIN-кодів + + + 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/7 + До вашої ID-картки додається п’ятизначний « PIN-код», який вам потрібно змінити на шестизначний PIN-код, який ви обираєте самостійно. + + + Five-digit Transport PIN + LABEL ALL_PLATFORMS + П’ятизначний транспортний PIN-код + + + Six-digit PIN + LABEL ALL_PLATFORMS + Шестизначний PIN-код - Your ID card comes with a 5-digit 'Transport PIN' which you need to replace with a 6-digit PIN that you choose yourself. - INFO ALL_PLATFORMS Description text explaining the PINs 1/6 + 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 - 5-digit Transport PIN + 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?' - The 5-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 + 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 - The PIN can only be used once. When you set up the eID function, you will replace this 5-digit PIN with a 6-digit PIN that you choose yourself. - INFO ALL_PLATFORMS Description text explaining the PINs 3/6 + 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 - 6-digit PIN - LABEL ALL_PLATFORMS + 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 - This is a number that you choose yourself when you set up the eID function for the first time. It replaces your 5-digit Transport PIN. - INFO ALL_PLATFORMS Description text explaining the PINs 4/6 + 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 - 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 + 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 6-digit PIN at any time in AusweisApp2. - INFO ALL_PLATFORMS Description text explaining the PINs 6/6 + 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 - You can use the PIN Reset Service to request a new card PIN free of charge. - LABEL ALL_PLATFORMS + 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 - 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. + 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?' - If you have forgotten your card PIN, you can request a new PIN free of charge using the PIN Reset Service. + 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 @@ -3075,6 +2643,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 @@ -3133,6 +2706,11 @@ LABEL ALL_PLATFORMS LABEL ANDROID IOS Smart-eID + + Please wait a moment, the current process is being finished. + LABEL ANDROID IOS + + PersonalizationResultView @@ -3171,11 +2749,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 @@ -3224,281 +2797,31 @@ 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 - Постачальник не надав опис. - - - - ProviderDetailHistory - - List of your past interactions with this provider - Список ваших минулих взаємодій із цим постачальником - - - The list is empty, no recorded interaction with this provider. - Список порожній, взаємодію з цим постачальником не зафіксовано. - - - Currently there are no history entries. - INFO DESKTOP No authentication history, placeholder text. ----------- -INFO ANDROID_TABLET IOS_TABLET No authentication history, placeholder text. - Наразі записів в історії немає. - - - History - LABEL ANDROID_TABLET IOS_TABLET - Історія - - - Purpose for reading out requested data - LABEL ANDROID_TABLET IOS_TABLET - Мета зчитування запитуваних даних - - - - ProviderDetailHistoryInfo - - Provider - LABEL ANDROID_TABLET IOS_TABLET - Постачальник - - - Purpose for reading out requested data - LABEL ANDROID_TABLET IOS_TABLET - Мета зчитування запитуваних даних - - - Read data - LABEL ANDROID_TABLET IOS_TABLET - Зчитати дані - - - Terms of usage - LABEL ANDROID_TABLET IOS_TABLET - Умови використання - - - - ProviderDetailHistoryItem - - today - LABEL ANDROID IOS - сьогодні - - - yesterday - вчора - - - dd.MM.yyyy - dd.MM.yyyy - - - Service: - LABEL DESKTOP - Служба: - - - Provider: - LABEL DESKTOP - Постачальник: - - - Click to view details of history entry. - Натисніть, щоб переглянути відомості про запис в історії. - - - Touch for more details - LABEL ANDROID IOS - Торкніться, щоб отримати докладніші відомості - - - - ProviderDetailView - - Description - LABEL DESKTOP - Опис - - - The provider did not provide a description. - LABEL DESKTOP - Постачальник не надав опис. - - - History - LABEL DESKTOP - Історія - - - - 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 - Не знайдено збігів за вашим пошуковим запитом - - - - ProviderHeader - - To provider - LABEL ANDROID IOS - До постачальника - - - - ProviderInfoSection - - See details under "more..." - LABEL DESKTOP - Див. відомості в розділі «Додаткова інформація» - - - - ProviderListItemDelegate - - Open provider details for %1 - Відкрити відомості про постачальника для %1 - - - Click to set category filter to %1 - Натисніть, щоб установити фільтр категорії %1 - - - - ProviderModelItem - - Click to open homepage. - INFO ALL_PLATFORMS A11y action text appended to provider homepage to be read read by screen reader. - Натисніть, щоб відкрити домашню сторінку. - - - Click to send email. - INFO ALL_PLATFORMS A11y action text appended to provider mail to be read read by screen reader. - Натисніть, щоб надіслати електронний лист. - - - Costs - 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. - Увійти +LABEL DESKTOP Title of the proxy credentials popup. + Увійти The proxy %1 requires username and password. @@ -3595,10 +2918,6 @@ LABEL ANDROID IOS Press space to pair the smartphone "%1". Натисніть пробіл, щоб створити пару зі смартфоном «%1». - - Click to pair - Натисніть, щоб створити пару - Remove remote device Видаліть віддалений пристрій @@ -3607,38 +2926,73 @@ LABEL ANDROID IOS RemoteReaderView - Paired remote devices - З’єднані віддалені пристрої + Paired devices + LABEL DESKTOP + З’єднані пристрої + + + Add pairing + LABEL DESKTOP + Додавання пари - Available remote devices - Доступні віддалені пристрої + 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. + Відкрийте %1 на своєму смартфоні як пристрій читання карток. - Only devices that are already paired or are connected to the same WiFi network and have the remote service enabled are shown here. - Тут відображаються лише пристрої, які вже з’єднано або підключено до однієї мережі Wi-Fi і для яких увімкнено віддалену службу. + Both devices have to be connected to the same WiFi. + Обидва пристрої мають бути підключені до однієї мережі Wi-Fi. - More information + On that device go to %1Card reader%2 and then %1Pair device%2 rsp. %1Pair new device%2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 4. %1 and %2 are surrounding tags for bold font + Перейдіть на тому пристрої до розділу %1Пристрій читання карток%2, а тоді виберіть %1Створити пару з пристроєм%2 і %1Створити пару з новим пристроєм%2. + + + Choose the device in the list to pair it. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 4 of 4 + Виберіть пристрій у переліку, щоб створити з ним пару. + + + Last connected LABEL DESKTOP - Додаткова інформація + Останнє з’єднання + + + Ensure that the %1 on your Smartphone as card reader has at least version %2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 4. %1 is a placeholder-tag for the app name. + Переконайтеся, що %1 на вашому смартфоні як пристрiй читання карток має версію не нижче %2. - RemoteServiceSettings + RemoteServiceController + + Remote service + LABEL ANDROID IOS + Віддалена служба + + + You are about to identify yourself towards the following provider using the device "%1": + LABEL ANDROID IOS + Ви збираєтеся ідентифікувати себе за допомогою пристрою «%1» для такого постачальника: + - Configure remote service + Card reader LABEL ANDROID IOS - Налаштувати віддалену службу + Пристрій читання карток - RemoteServiceView + RemoteServiceSettings - Remote service + Manage pairings LABEL ANDROID IOS - Віддалена служба + Керування створенням пари + + + RemoteServiceView Pairing failed. Please start a new pairing process on your other device and enter the shown pairing code. ERROR ANDROID IOS An error occurred while pairing the device. @@ -3669,35 +3023,16 @@ LABEL ANDROID IOS LABEL ANDROID IOS Очікування підключення - - Remote service ready - LABEL ANDROID IOS - Віддалена служба готова - Waiting for connection from a paired device... INFO ANDROID IOS Очікування підключення від пристрою, з яким створено пару… - - Start the remote access in order to make this smartphone visible and use it as a card reader (SaC). - -If you have not already paired a device, start the pairing now to set up this smartphone as a card reader. - INFO ANDROID IOS - Запустіть віддалений доступ, щоб зробити цей смартфон видимим і використовувати його як пристрій читання карток (SaC). - -Якщо ви ще не створили пару для пристрою, почніть створення пари зараз, щоб налаштувати цей смартфон як пристрій читання карток. - Pairing code: <b>%1</b> LABEL ANDROID IOS Код створення пари: <b>%1</b> - - Both of your devices have to be connected to the same WiFi. - INFO ANDROID IOS The remote service is active. Hint that both devices need to be connected to the same network. - Обидва ваші пристрої має бути підключено до однієї мережі Wi-Fi. - Enable WiFi LABEL ANDROID IOS @@ -3709,43 +3044,77 @@ If you have not already paired a device, start the pairing now to set up this sm Увімкнути NFC - Stop remote service + Pair device LABEL ANDROID IOS - Зупинити віддалену службу + Створити пару з пристроєм - Start remote service + Allow connection LABEL ANDROID IOS - Запустити віддалену службу + Дозволити з’єднання + + + You can use this Smartphone as a card reader for the %1 on other devices e.g. a laptop. + +To do this you first have to pair that device with this smartphone. + INFO ANDROID IOS + Ви можете використовувати цей смартфон як пристрій читання карток для %1 на інших пристроях, наприклад, на ноутбуці. + +Для цього вам потрібно спочатку створити пару між таким пристроєм і цим смартфоном. - Stop pairing + Card reader LABEL ANDROID IOS - Зупинити створення пари + Пристрій читання карток - Start pairing + Paired Devices LABEL ANDROID IOS - Почати створення пари + З’єднані пристрої - Enter the code %1 in the %2 on your other device to use your smartphone as a card reader (SaC). - INFO ANDROID IOS - Введіть код %1 у %2 на іншому пристрої, щоб використовувати свій смартфон як пристрій читання карток (SaC). + Pair new device + LABEL ANDROID IOS + Створення пари з новим пристроєм - - - RemoteServiceViewRemote - Paired devices + Waiting for pairing LABEL ANDROID IOS - З’єднані пристрої + Очікування на створення пари - No device is paired. + Start pairing of a new device LABEL ANDROID IOS - Із жодним пристроєм не створено пару. + Почати створення пари з новим пристроєм + + + Where do I enter the pairing code? + LABEL ANDROID IOS + Куди вводити код створення пари? + + + Enter the pairing code %1 in the %2 on your other device. + INFO ANDROID IOS + Введіть код створення пари %1 у %2 на своєму іншому пристрої. + + + Cancel pairing + LABEL ANDROID IOS + Скасувати створення пари + + + Allow a connection with paired devices to use this Smartphone as a card reader or pair another device. + INFO ANDROID IOS + Надайте дозвіл на встановлення зв’язку зі з’єднаними пристроями, щоб використовувати цей смартфон як пристрій читання карток або створити пару з іншим пристроєм. + + + Paired devices may use this Smartphone as a card reader now. + INFO ANDROID IOS + Тепер з’єднані пристрої можуть використовувати цей смартфон як пристрій читання карток. + + + RemoteServiceViewRemote Click to remove device LABEL ANDROID IOS @@ -3766,16 +3135,6 @@ If you have not already paired a device, start the pairing now to set up this sm INFO ANDROID IOS Видалити - - Available devices - LABEL ANDROID IOS - Доступні пристрої - - - No unpaired smartphone as card reader (SaC) available. Please make sure that the smartphone as card reader (SaC) functionality in AusweisApp2 on your other device is activated and that both devices are connected to the same WiFi. - INFO ANDROID IOS No SaC was found on the network, both devices need to be connected to the same WiFi network. - Немає жодного з’єднаного смартфона як пристрою читання карток (SaC). Переконайтеся, що функцію смартфона як пристрою для читання карток (SaC) активовано в програмі AusweisApp2 на вашому іншому пристрої і що обидва пристрої підключено до однієї мережі Wi-Fi. - Please connect your WiFi to use another smartphone as card reader (SaC). INFO ANDROID IOS Wifi is not enabled and no new devices can be paired. @@ -3787,63 +3146,61 @@ If you have not already paired a device, start the pairing now to set up this sm Увімкнути Wi-Fi - Click to pair + Pairing code LABEL ANDROID IOS - Натисніть, щоб створити пару + Код створення пари - Pairing mode - INFO ANDROID IOS - Режим створення пари + Add pairing + LABEL ANDROID IOS + Додавання пари - Start the pairing mode on your smartphone if you haven't done it already. - INFO ANDROID IOS Information dialog that requests the user to start the pairing mode on the smartphone. - Запустіть режим створення пари на своєму смартфоні, якщо ви ще цього не зробили. + Last connected + LABEL ANDROID IOS + Останнє з’єднання - Pairing code + Available LABEL ANDROID IOS - Код створення пари + Доступно - - - RemoteWorkflow - 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 було скасовано, оскільки він не реагував на спроби підключення. Створіть пару з пристроєм знову, щоб використовувати його як пристрій читання карток. + Paired devices + LABEL ANDROID IOS + З’єднані пристрої - Enable WiFi + Click to pair LABEL ANDROID IOS - Увімкнути Wi-Fi + Натисніть, щоб створити пару + + + RemoteServiceWifiInfo - Pair device + Both devices have to be connected to the same WiFi. + INFO ANDROID IOS The remote service is active. Hint that both devices need to be connected to the same network. + Обидва пристрої мають бути підключені до однієї мережі Wi-Fi. + + + + RemoteWorkflow + + Enable WiFi LABEL ANDROID IOS - Створити пару з пристроєм + Увімкнути Wi-Fi To use the remote service WiFi has to be activated. Please activate WiFi in your device settings. INFO ANDROID IOS The WiFi module needs to be enabled in the system settings to use the remote service. Для використання віддаленої служби має бути активовано Wi-Fi. Активуйте Wi-Fi у параметрах пристрою. - - No paired smartphone as card reader (SaC) with activated "remote service" available. - INFO ANDROID IOS No paired and reachable device was found, hint that the remote device needs to be actually started for this feature. - Немає жодного з’єднаного смартфона як пристрою читання карток (SaC) з активованою «віддаленою службою». - Wifi disabled LABEL ANDROID IOS Wi-Fi вимкнено - - Waiting for connection - LABEL ANDROID IOS - Очікування підключення - Determine card LABEL ANDROID IOS @@ -3855,17 +3212,28 @@ If you have not already paired a device, start the pairing now to set up this sm Підключений смартфон як пристрій читання карток (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 + LABEL ANDROID IOS + Керування створенням пари + + + No smartphone as card reader connected + LABEL ANDROID IOS + Не з’єднано жоден смартфон як пристрій читання карток + + + Allow a connection on a paired smartphone or pair a new smartphone. + INFO ANDROID IOS No paired and reachable device was found, hint that the remote device needs to be actually started for this feature. + Надайте дозвіл на встановлення зв’язку на з’єднаному смартфоні або створіть пару з новим смартфоном. ResultErrorView - - Show error details - Показати відомості про помилку - Details Відомості @@ -3905,109 +3273,15 @@ If you have not already paired a device, start the pairing now to set up this sm - 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 - Список постачальників для пошуку - + RetryCounter - Enter search string - Увести пошуковий запит - - - Search providers - Шукати постачальників - - - Clear search string - Очистити пошуковий запит - - - 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 @@ -4018,16 +3292,6 @@ LABEL ANDROID LABEL DESKTOP Використовувати екранну клавіатуру для введення PIN-коду - - Shuffle keypad buttons - LABEL DESKTOP - Кнопки клавіатури в довільному порядку - - - Visual feedback when pressing keypad buttons - LABEL DESKTOP - Візуальний відгук під час натискання кнопок клавіатури - Software updates LABEL DESKTOP @@ -4069,19 +3333,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 + @@ -4101,23 +3365,11 @@ LABEL ANDROID LABEL DESKTOP Title of the self authentication result data view Зчитати дані - - Save as PDF... - LABEL DESKTOP - Зберегти як файл PDF… - - - Information - Інформація - - - Portable Document Format (*.pdf) - LABEL DESKTOP - Файл формату Adobe Portable Document Format (*.pdf) - OK - LABEL DESKTOP + LABEL DESKTOP +---------- +LABEL ANDROID IOS OK @@ -4125,11 +3377,6 @@ LABEL ANDROID LABEL ANDROID IOS Ідентифікувати - - Save read self-authentication data - LABEL DESKTOP - Зберегти читати дані самоавтентифікації - SelfAuthenticationView @@ -4168,6 +3415,16 @@ LABEL ANDROID IOS LABEL ANDROID IOS Дивитися мої особисті дані + + Self-authentication + LABEL ANDROID IOS + + + + Hint + LABEL ANDROID IOS + Підказка + SettingsView @@ -4223,73 +3480,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-код на цьому пристрої - - Remote card reader - LABEL ANDROID IOS - Віддалений пристрій читання карток - - - Configure remote service for another device - LABEL ANDROID IOS - Налаштувати віддалену службу для іншого пристрою - - - 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 @@ -4300,56 +3500,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 - Дозволити використовувати 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 @@ -4380,1431 +3545,605 @@ LABEL ALL_PLATFORMS LABEL ALL_PLATFORMS Файл журналу строком 15 днів - - - SetupAssistantView - Setup Assistant - LABEL DESKTOP - Помічник з налаштування + Smart-eID + LABEL ANDROID IOS + Smart-eID - 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! Приділіть кілька хвилин, щоб налаштувати середовище відповідно до своїх потреб. Кожне прийняте вами рішення пізніше можна буде змінити в меню параметрів. + Reset Smart-eID + LABEL ANDROID IOS + Скинути Smart-eID - Do you want to automatically start the %1 after boot? - INFO DESKTOP Question if the App shall be started automatically after boot - Автоматично запускати %1 після завантаження? + Reset Smart-eID data on your device + 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. Тому рекомендовано активувати автозапуск після запуску системи. + Show Transport PIN reminder, store feedback and close reminder dialogs. + LABEL ANDROID IOS + - 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 - Після запуску до рядка меню буде додано піктограму. + Reset hideable dialogs + LABEL ANDROID IOS + - Auto-start Setting - LABEL DESKTOP - Налаштування автозапуску + Show requested rights on this device as well + LABEL ANDROID IOS + Показати запит на права також на цьому пристрої - Do you want to save a history of performed authentications on your device? - INFO DESKTOP Question if the authentication history shall be stored. - Зберегти історію виконаних автентифікацій на вашому пристрої? + Manage pairings + LABEL ANDROID IOS + Керування створенням пари - 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. - Історія зберігається лише локально. Ви можете використовувати її, щоб бачити, в який день і які дані ви передали якій стороні. Після ввімкнення історії ви можете будь-коли переглядати й видаляти записи. + Toggling will restart the %1 + LABEL ANDROID IOS + - History Setting - LABEL DESKTOP - Налаштування історії + Use system font + LABEL ANDROID IOS + - 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>? + Appearance + LABEL ANDROID IOS + - 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 - Щоб використовувати функцію онлайн-ідентифікації на комп’ютері, перед першим процесом автентифікації необхідно налаштувати відповідний смартфон або пристрій читання карток. + Add and remove devices + LABEL ANDROID IOS + Керування з’єднаними пристроями й додавання нових пристроїв - Card Readers - LABEL DESKTOP - Пристрої читання карток + On-site reading + LABEL ANDROID IOS + Дозволений режим CAN - You have completed the setup of the AusweisApp2 successfully. - INFO DESKTOP Success message after completing the setup assistant. - Ви успішно завершили налаштування AusweisApp2. + Support CAN allowed mode for on-site reading + LABEL ANDROID IOS + Підтримувати дозволений режим CAN - Proceed to start page - INFO DESKTOP A11y button text to exit the setup assistant. - Перейти до початкової сторінки + Allow test sample card usage + LABEL ANDROID IOS + - - - SimulatorWorkflow - Simulator + Simulate a test sample card in authentications LABEL ANDROID IOS - Симулятор + - Continue + Visually highlight key presses on screen keypad LABEL ANDROID IOS - Продовжити + - SmartDeleteStartView + SetupAutostartView - Delete Smart-eID - LABEL ANDROID IOS - Видалити Smart-eID + Do you want to automatically start the %1 after boot? + INFO DESKTOP Question if the App shall be started automatically after boot + Автоматично запускати %1 після завантаження? - Are you sure you want to delete the Smart-eID? - LABEL ANDROID IOS - Справді видалити Smart-eID? + 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. Тому рекомендовано активувати автозапуск після запуску системи. - Delete - 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 + Після запуску до рядка меню буде додано піктограму. - Smart-eID - LABEL ANDROID IOS - Smart-eID + Autostart Settings + LABEL DESKTOP + - 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 - Продовжити - - - - 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 + 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. - 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> або <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 як пристрій читання карток - - - Click link on the website of the provider. - LABEL ANDROID IOS - Натисніть посилання на сайті постачальника. - - - The App opens automatically. - LABEL ANDROID IOS - Програма відкриється автоматично. - - - The AusweisApp2 will display who wants to access which data. - LABEL ANDROID IOS - Програма AusweisApp2 покаже, хто хоче отримати доступ і до яких даних. - - - Start the process with a click on: - LABEL ANDROID IOS - Почніть процес, натиснувши: - - - Proceed to PIN entry - LABEL ANDROID IOS - Перейти до введення PIN-коду - - - ... and place the top of the iPhone onto the ID card. - LABEL IOS - … і помістіть верхню частину iPhone на ID-картку. - - - ... and place the ID card flat onto the NFC interface. - LABEL ANDROID - … і прикладіть ID-картку до інтерфейсу NFC. - - - Do not move device or ID card! - 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 показує різні поширені положення. - - - 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-картку» на початковій сторінці. - - - You can find more information on compatible devices on our %1mobile device list%2. - 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. - Уведіть - - - six-digit PIN - LABEL ANDROID IOS - шестизначний 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. - зараз! - - - This is only possible if you have exchanged the five-digit Transport PIN with a six-digit PIN beforehand. - LABEL ANDROID IOS - Це можливо, лише якщо ви перед цим замінили п’ятизначний транспортний PIN-код на шестизначний PIN-код. - - - Open YouTube video - LABEL ANDROID IOS - Відкрити відео на YouTube - - - You can also watch this YouTube video explaining the process. - LABEL ANDROID IOS - Ви також можете переглянути це відео на YouTube, у якому пояснюється цей процес. - - - - TutorialReaderMethodSacDesktop - - Tutorial: Smartphone as card reader - 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 як пристрій читання карток - - - Install AusweisApp2 on both your computer <b>and</b> your smartphone with NFC capability. - LABEL ANDROID IOS - Установіть програму AusweisApp2 на комп’ютері <b>та</b> смартфоні з функцією NFC. - - - Both devices have to be connected to the same WiFi network - LABEL ANDROID IOS - Обидва пристрої має бути підключено до однієї мережі Wi-Fi - - - Now choose "Remote" in the AusweisApp2 on your smartphone... - LABEL ANDROID IOS - Тепер виберіть «Віддалений доступ» у програмі AusweisApp2 на смартфоні… - - - Now - LABEL ANDROID IOS - Зараз - + SimulatorWorkflow - Start pairing + Simulator LABEL ANDROID IOS - Почати створення пари + Симулятор - Pairing code + Continue LABEL ANDROID IOS - Код створення пари + Продовжити + + + SmartDeleteBaseView - appears! + 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 для цієї програми. + 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. + Send log LABEL ANDROID IOS - Виберіть вкладку <b>Смартфон як пристрій читання карток</b>. + Надіслати журнал - Select smartphone from list + If you want to use that functionality again, you need to set up a new Smart-eID first. LABEL ANDROID IOS - Виберіть смартфон зі списку + Якщо ви хочете знову використовувати цю функцію, вам спочатку потрібно налаштувати новий Smart-eID. - Enter pairing code next. + Reset Smart-eID LABEL ANDROID IOS - Далі введіть код створення пари. + Скинути Smart-eID + + + SmartDeleteView - Click link on the website of the provider. + Delete Smart-eID LABEL ANDROID IOS - Натисніть посилання на сайті постачальника. + Видалити Smart-eID - The App opens automatically. + You have successfuly deleted your Smart-eID. LABEL ANDROID IOS - Програма відкриється автоматично. + - The AusweisApp2 will display who wants to access which data. + The Smart-eID could not be successfully deleted from your device. LABEL ANDROID IOS - Програма AusweisApp2 покаже, хто хоче отримати доступ і до яких даних. + - Start the process with a click on: + Back to start page LABEL ANDROID IOS - Почніть процес, натиснувши: + - Proceed to PIN entry + You are about to delete the Smart-eID data that is currently stored on your device. LABEL ANDROID IOS - Перейти до введення PIN-коду + Ви збираєтеся видалити дані Smart-eID, які зараз зберігаються на вашому пристрої. - ... and place the ID card onto the NFC interface. + Are you sure you want to delete the Smart-eID? LABEL ANDROID IOS - … і помістіть ID-картку на інтерфейс NFC. + Справді видалити Smart-eID? - Do not move device or ID card! + Delete 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. + Deleting 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. + Delete the Smart-eID LABEL ANDROID IOS - Якщо ваш пристрій не може виявити вашу ID-картку, спробуйте перевірити його можливості, натиснувши «Перевірити пристрій та ID-картку» на початковій сторінці. + + + + SmartMainView - You can find more information on compatible devices on our %1mobile device list%2. + Updating Smart-eID status... LABEL ANDROID IOS - Ви можете знайти докладнішу інформацію про сумісні пристрої в нашому списку %1мобільних пристроїв%2. + Триває оновлення статусу 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. - Уведіть + Smart-eID ready for use + LABEL ANDROID IOS + Smart-eID готовий до використання - six-digit PIN + Please wait a moment. LABEL ANDROID IOS - шестизначний 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. - зараз! + 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-картки, якщо це підтримується постачальником. - This is only possible if you have exchanged the five-digit Transport PIN with a six-digit PIN beforehand. + Check here if your device is suitable to set up a Smart-eID. LABEL ANDROID IOS - Це можливо, лише якщо ви перед цим замінили п’ятизначний транспортний PIN-код на шестизначний PIN-код. + Перевірте тут, чи підходить ваш пристрій для налаштування Smart-eID. - Open YouTube video + Start check LABEL ANDROID IOS - Відкрити відео на YouTube + Почати перевірку - You can also watch this YouTube video explaining the process. + With the Smart-eID you may also use the online identification function without the ID card. LABEL ANDROID IOS - Ви також можете переглянути це відео на YouTube, у якому пояснюється цей процес. + - TutorialReaderMethodSacMobile + SmartResetView - Tutorial: Smartphone as card reader + Reset Smart-eID LABEL ANDROID IOS - Посібник: Смартфон як пристрій читання карток + Скинути Smart-eID - App on tablet or smartphone <b>without</b> NFC chip + You have successfully reset your Smart-eID. LABEL ANDROID IOS - Програма на планшеті або смартфоні <b>без</b> мікросхеми NFC + - Smartphone <b>with</b> NFC chip as card reader + You are about to reset your Smart-eID data. This can also be used for troubleshooting as well. LABEL ANDROID IOS - Смартфон <b>з</b> мікросхемою NFC як пристрій читання карток + - Install AusweisApp2 on both your device without NFC <b>and</b> your smartphone with NFC capability. + Are you sure you want to reset the Smart-eID? LABEL ANDROID IOS - Установіть програму AusweisApp2 на пристрої без NFC <b>та</b> смартфоні з функцією NFC. + - Both devices have to be connected to the same WiFi network + Reset LABEL ANDROID IOS - Обидва пристрої має бути підключено до однієї мережі Wi-Fi + - Now choose "Remote" in the AusweisApp2 on your smartphone... + Resetting Smart-eID LABEL ANDROID IOS - Тепер виберіть «Віддалений доступ» у програмі AusweisApp2 на смартфоні… + Скидання Smart-eID - Now + Reset the Smart-eID LABEL ANDROID IOS - Зараз + + + + SmartSettingsView - Start pairing + Smart-eID LABEL ANDROID IOS - Почати створення пари + Smart-eID - Pairing code + Renew Smart-eID LABEL ANDROID IOS - Код створення пари + Поновити Smart-eID - appears! + Renew your Smart-eID with current data 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>Configure remote service</b>. - LABEL IOS - Тепер відкрийте програму AusweisApp2 на пристрої <b>без</b> NFC і виберіть <b>Налаштувати віддалену службу</b>. - - - 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 і виберіть <b>Смартфон як пристрій читання карток</b>. + Поновіть свій Smart-eID за допомогою поточних даних - Now select <b>Settings</b>. + Delete Smart-eID LABEL ANDROID IOS - Тепер виберіть <b>Параметри</b>. + Видалити Smart-eID - Choose smartphone from list + Delete Smart-eID data from your device LABEL ANDROID IOS - Виберіть смартфон зі списку + - Enter pairing code next. + Try Smart-eID LABEL ANDROID IOS - Далі введіть код створення пари. + - Click link on the website of the provider on the device <b>without</b> NFC. + Show Smart-eID data LABEL ANDROID IOS - Натисніть посилання на сайті постачальника на пристрої <b>без</b> NFC. + - The App opens automatically. + Change Smart-eID PIN LABEL ANDROID IOS - Програма відкриється автоматично. + Змінити PIN-код Smart-eID - The AusweisApp2 will display who wants to access which data. + Change the chosen Smart-eID PIN LABEL ANDROID IOS - Програма AusweisApp2 покаже, хто хоче отримати доступ і до яких даних. + + + + SmartSetupStartView - Start the process with a click on: + Smart-eID LABEL ANDROID IOS - Почніть процес, натиснувши: + Smart-eID - Proceed to PIN entry + 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 - Перейти до введення PIN-коду + Ви збираєтеся налаштувати Smart-eID на своєму пристрої. Щоб продовжити, вам потрібні ID-картка, шестизначний PIN-код ID-картки й підключення до Інтернету. - Tap on WiFi + Set up Smart-eID LABEL ANDROID IOS - Торкніться Wi-Fi + Налаштувати Smart-eID - ... and place the ID card onto the NFC interface. + Smart-eID setup LABEL ANDROID IOS - … і помістіть ID-картку на інтерфейс NFC. + + + + SmartUpdateStartView - Do not move device or ID card! + 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 - Не рухайте пристрій та 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. + 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 - Правильне положення залежить від конкретного пристрою. Якщо якесь положення не дає бажаного результату, спробуйте інше. 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. + Renew Smart-eID LABEL ANDROID IOS - Якщо ваш пристрій не може виявити вашу ID-картку, спробуйте перевірити його можливості, натиснувши «Перевірити пристрій та ID-картку» на початковій сторінці. + Поновити Smart-eID - You can find more information on compatible devices on our %1mobile device list%2. + Renew the 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. - Уведіть + - six-digit PIN + Smart-eID renewal LABEL ANDROID IOS - шестизначний PIN-код + + + + SmartView - 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 + LABEL ANDROID IOS + Smart-eID - This is only possible if you have exchanged the five-digit Transport PIN with a six-digit PIN beforehand. + Check Smart-eID LABEL ANDROID IOS - Це можливо, лише якщо ви перед цим замінили п’ятизначний транспортний PIN-код на шестизначний PIN-код. + Перевірте Smart-eID - TutorialView - - Tutorial - LABEL ANDROID IOS - Посібник - + SmartWorkflow - What? + Updating Smart-eID status... LABEL ANDROID IOS - Що? + Триває оновлення статусу Smart-eID… - Where? + Smart-eID unsupported LABEL ANDROID IOS - Де? + Smart-eID не підтримується - How? + Smart-eID disallowed LABEL ANDROID IOS - Як? + Smart-eID не дозволено - Important! + Smart-eID LABEL ANDROID IOS - Важливо! + Smart-eID - - - TutorialWhat - What is the online ID function? + Smart-eID not ready LABEL ANDROID IOS - Що таке функція онлайн-ідентифікації? + Smart-eID не готовий - You can use it to authenticate yourself in the internet + Your Smart-eID is ready for use, press "Continue" to proceed. LABEL ANDROID IOS - Ви можете використовувати її для автентифікації в Інтернеті, + Ваш Smart-eID готовий до використання, натисніть «Продовжити». - and also to deal with administrative paperwork and business matters electronically! + Please wait a moment. LABEL ANDROID IOS - а також щоб вирішувати адміністративні та ділові питання в електронному вигляді! + Трохи зачекайте. - Alright, but is it secure? + 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», щоб підключитися до іншого пристрою як пристрою читання карток. - Of course, because we use a so called + 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», щоб підключитися до іншого пристрою як пристрою читання карток. - Mutual authentication + 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 з головного екрана. - ... it establishes a secure connection between ID card and provider. - LABEL ANDROID IOS - … вона встановлює безпечне з’єднання між ID-карткою та постачальником. + Continue + Продовжити - On every authentication you get displayed <b>who</b> wants to access <b>which</b> data + 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 - Під час кожної автентифікації відображаються відомості, <b>хто</b> хоче отримати доступ та до <b>яких</b> даних, + Ви ще не налаштували Smart-eID або він більше не придатний для використання. + +Щоб продовжити, скористайтеся своєю ID-карткою, вибравши інтерфейс NFC. Якщо ви хочете натомість налаштувати Smart-eID, перервіть поточний процес і почніть налаштування Smart-eID з головного екрана. - and you consent to the request with your six-digit PIN. - LABEL ANDROID IOS - а ви даєте згоду на запит за допомогою шестизначного PIN-коду. + The device "%1" wants to access your Smart-eID. + INFO ANDROID IOS %1 will be replaced with the name of the device. + + + + StoreFeedbackPopup - ... is the provider authorized for this? - LABEL ANDROID IOS - … чи має право постачальник робити це? + Are you satisfied with %1? + INFO ANDROID Header of the app rating popup. + Ви задоволені програмою %1? - The provider needs an authorization of the Federal Office of Administration. - 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! - Certificate - LABEL ANDROID IOS - Сертифікат + Do not ask again + LABEL ANDROID + Більше не запитувати - Every time both participants authenticate each other... - LABEL ANDROID IOS - Щоразу обидва учасники автентифікують один одного… + Rate app + LABEL ANDROID + Оцінити програму + + + TabbedReaderView - ... and therefore your data is protected and securely transferred. - LABEL ANDROID IOS - …і тому ваші дані захищені та передаються безпечним чином. + 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 - And this is how it works - LABEL ANDROID IOS - Ось як це працює + Start page + LABEL DESKTOP + Початкова сторінка - 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> ваших даних. + Settings + Параметри - To allow the shown service access to the requested data click "Proceed to PIN entry" - LABEL ANDROID IOS - Щоб надати цій службі доступ до запитуваних даних, натисніть «Перейти до введення PIN-коду». + Open settings view of %1 + Відкрити вікно параметрів %1 - Now lay down your ID card and hold the top of your iPhone to the ID card. - LABEL IOS - Тепер покладіть свою ID-картку і прикладіть до неї верхню частину свого iPhone. + Notifications + Сповіщення - Now place your ID card on the NFC-interface of your smartphone. - LABEL ANDROID - Тепер помістіть свою ID-картку на інтерфейс NFC свого смартфона. + Show in-app notifications of %1 + Показувати сповіщення в програмі щодо %1 - 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-картку» на початковій сторінці. + Title bar + LABEL DESKTOP + + + + TitleBarNavigation - Do not move your iPhone during the procedure! - LABEL IOS - Не рухайте iPhone під час виконання цієї процедури! + Cancel + LABEL ANDROID IOS + Скасувати - Do not move your device during the procedure! - LABEL ANDROID - Не рухайте пристрій під час виконання цієї процедури! + Back + LABEL ANDROID IOS + Назад + + + + TransportPinReminderView + + Do you know your six-digit ID card PIN? + LABEL ANDROID IOS + Ви знаєте шестизначний PIN-код своєї ID-картки? + + + 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 + @@ -5976,9 +4315,9 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& Надіслати дані пристрою? - 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. @@ -6010,6 +4349,14 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& Надіслати + + 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 @@ -6173,7 +4520,7 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& Reason: INFO ALL_PLATFORMS Failure code (string) of current workflow error. - + Причина: @@ -6323,7 +4670,7 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& d. MMMM yyyy, hh:mm:ss AP - LABEL DESKTOP Timestamp, formatted according to the selected language + LABEL DESKTOP Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString d MMMM yyyy р., hh:mm:ss @@ -6462,9 +4809,9 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& Брандмауери від сторонніх постачальників - Outgoing AusweisApp2 rule + Outgoing %1 rule LABEL DESKTOP - Вихідне правило AusweisApp2 + Вихідне правило %1 Exists: %1 @@ -6472,9 +4819,9 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& Існує: %1 - Incoming AusweisApp2 rule + Incoming %1 rule LABEL DESKTOP - Вхідне правило AusweisApp2 + Вхідне правило %1 Windows firewall rules @@ -6533,7 +4880,7 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& dd.MM.yyyy, hh:mm:ss - LABEL DESKTOP Timestamp + LABEL DESKTOP 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:ss @@ -6594,12 +4941,12 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& Service addresses LABEL DESKTOP - + Сервісні адреси Not bound LABEL DESKTOP - + Не зв’язані @@ -6764,7 +5111,7 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& The program received an unknown message from the server. - ERROR_MASKED ALL_PLATFORMS The type of a POAS message could not be determined. + ERROR_MASKED ALL_PLATFORMS The type of a PAOS message could not be determined. Програма отримала невідоме повідомлення від сервера. @@ -6798,9 +5145,9 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& Не вдалося виконати автентифікацію. - Your card reader does not support Extended Length communication and cannot be used to read the ID card. Unfortunately, the %1 has no influence on this restriction. - ERROR ALL_PLATFORMS DidAuthenticateEAC2 was not able to send the certificates to the card because the card reader does not support extended length. - Ваш пристрій читання карток не підтримує зв’язок за допомогою функції Extended Length і не може використовуватися для читання ID-картки. На жаль, %1 не має впливу на це обмеження. + The length of the data sent to the ID card was not accepted. Either the data is faulty or your card reader does not support Extended Length communication and cannot be used to read the ID card. Unfortunately, the %1 has no influence on this restriction. + ERROR ALL_PLATFORMS A card command failed because the data length was wrong or the card reader does not support Extended Length. + Довжину даних, надісланих на ID-картку, відхилено. Дані неправильні або ваш пристрій читання карток не підтримує зв’язок за допомогою функції Extended Length і не може використовуватися для читання ID-картки. На жаль, %1 не має впливу на це обмеження. No certificate description available. @@ -6828,7 +5175,7 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& Програма отримала помилку від сервера. - 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. @@ -6847,11 +5194,6 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& 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 @@ -6968,9 +5310,9 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& Під час зв’язку з 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. @@ -7017,11 +5359,6 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& 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. @@ -7033,9 +5370,9 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& Запит на підключення смартфона як пристрою читання карток (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). @@ -7082,12 +5419,55 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& ERROR ALL_PLATFORMS Starting the update failed. Не вдалося почати новий процес для запуску оновлення. - - - governikus::HistoryModelSearchFilter - dd.MM.yyyy - dd.MM.yyyy + 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 від сервера. + + + The server could not process the client request. + ERROR_MASKED ALL_PLATFORMS + + + + 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 @@ -7139,6 +5519,7 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& dd.MM.yyyy hh:mm:ss + 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:ss @@ -7198,6 +5579,7 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& governikus::NotificationModel hh:mm:ss + LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString hh:mm:ss @@ -7208,11 +5590,6 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& 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. @@ -7228,11 +5605,6 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& 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. @@ -7263,169 +5635,96 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& 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 - dd.MM.yyyy hh:mm - - - Provider: - LABEL ALL_PLATFORMS - Постачальник: - - - Purpose: - LABEL ALL_PLATFORMS - Мета: - - - Read access: - 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. + - Write access (update): - LABEL ALL_PLATFORMS - Доступ для записування (оновлення): + The input does not match. Please choose a new Smart-eID PIN. + ALL_PLATFORMS Error message if the new pin confirmation mismatches. + - dd.MM.yyyy - LABEL ALL_PLATFORMS - dd.MM.yyyy + The input does not match. Please choose a new ID card PIN. + + + + governikus::PinResetInformationModel - hh:mm AP - LABEL ALL_PLATFORMS - hh:mm + https://www.personalausweisportal.de/EN + https://www.personalausweisportal.de/EN - At %1 %2 the following data were saved: - LABEL ALL_PLATFORMS - У %1 %2 було збережено такі дані: + If you have forgotten your ID card PIN or do not have access to the PUK, you may turn to the competent authority and set a new PIN there.<br/><br/>For further information, please visit the ID card portal. + LABEL ALL_PLATFORMS Hint text for requested PUK but both, PUK and PIN are not known. + Якщо ви забули PIN-код своєї ID-картки або не маєте доступу до PUK-коду, ви можете звернутися до компетентного органа й установити там новий PIN-код.<br/><br/>Для отримання додаткової інформації відвідайте портал ID-карток. - History - LABEL ALL_PLATFORMS - Історія + If you know neither your Transport PIN nor your ID card PIN, you may turn to the competent authority and set a new PIN there.<br/><br/>For further information, please visit the ID card portal. + LABEL ALL_PLATFORMS Hint text for requested Transport PIN but both, Transport PIN and PIN are not known. + Якщо ви не знаєте ні транспортного PIN-коду, ні PIN-коду своєї ID-картки, ви можете звернутися до компетентного органа й установити там новий PIN-код.<br/><br/>Для отримання додаткової інформації відвідайте портал ID-карток. - Entry - LABEL ALL_PLATFORMS - Уведення + If you cannot recall your ID card PIN, you may turn to the competent authority and set a new PIN there.<br/><br/>For further information, please visit the ID card portal. + LABEL ALL_PLATFORMS Hint text for PIN but it is unknown. + Якщо ви не можете згадати PIN-код своєї ID-картки, ви можете звернутися до компетентного органа й установити там новий PIN-код.<br/><br/>Для отримання додаткової інформації відвідайте портал ID-карток. - Content - LABEL ALL_PLATFORMS - Вміст + You may turn to the competent authority and set a new ID card PIN there.<br/><br/>For further information, please visit the ID card portal. + LABEL ALL_PLATFORMS Hint when a workflow failed because of a blocked PUK + Ви можете звернутися до компетентного органа й установити там новий PIN-код ID-картки.<br/><br/>Для отримання додаткової інформації відвідайте портал ID-карток. - At %1 %2 the following data has been read out of your ID card: - LABEL ALL_PLATFORMS - У %1 %2 з вашої ID-картки було зчитано такі дані: + Please contact the competent authority to activate the eID function.<br/><br/>For further information, please visit the ID card portal. + LABEL ALL_PLATFORMS Hint when a workflow failed because the eID function was not activated + Зверніться до компетентного органа, щоб активувати функцію онлайн-ідентифікації.<br/><br/>Для отримання додаткової інформації відвідайте портал ID-карток. - Information + Open website LABEL ALL_PLATFORMS - Інформація - - - - governikus::PinResetInformationModel - - https://www.personalausweisportal.de/EN - https://www.personalausweisportal.de/EN + Відкрити сайт You cannot use the PUK to reset your previously set card PIN. If you forgot your card PIN, you can use the PIN Reset Service to request a new PIN. LABEL ALL_PLATFORMS Hint text for requested PUK but both, PUK and PIN are not known. - + Ви не можете використовувати PUK-код для скидання раніше встановленого PIN-коду картки. Якщо ви забули PIN-код своєї картки, ви можете скористатися службою скидання PIN-коду, щоб надіслати запит на новий PIN-код. Go to PIN Reset Service LABEL ALL_PLATFORMS - + Перейти до служби скидання PIN-коду You can request activation of the eID function without charge. LABEL ALL_PLATFORMS Hint when a workflow failed because the eID function was not activated - + Ви можете надіслати запит на безкоштовну активацію функції eID. Go to Activation Service LABEL ALL_PLATFORMS - + Перейти до служби активації Request a new card PIN free of charge to be able to use the eID function again. LABEL ALL_PLATFORMS Hint when a workflow failed because of a blocked PUK - - - - - 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 секунд безкоштовно, а потім + Надішліть безкоштовно запит на новий PIN-код картки, щоб знову мати змогу користуватися функцією eID. - landline costs %1; - INFO ALL_PLATFORMS Land line charges when calling the hotline. - вартість стаціонарного телефонного зв’язку %1; + 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. + Якщо ви не знаєте ні транспортний PIN-код, ні PIN-код картки, ви можете безкоштовно надіслати запит на новий PIN-код, скориставшись службою скидання PIN-коду. - mobile costs may vary. - INFO ALL_PLATFORMS Cell phone charges when calling the hotline. - вартість мобільного зв’язку може відрізнятися. + If you have forgotten your ID 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. + Якщо ви забули PIN-код картки, ви можете безкоштовно надіслати запит на новий PIN-код, скориставшись службою скидання PIN-коду. - mobile costs %1 - вартість мобільного зв’язку %1 + You can use the PIN Reset Service to request a new card PIN free of charge. + LABEL ALL_PLATFORMS Hint text for requested Transport PIN but both, Transport PIN and PIN, are not known. + Ви можете скористатися службою скидання PIN-коду, щоб безкоштовно надіслати запит на новий PIN-код картки. @@ -7455,18 +5754,9 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& 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 hh:mm:ss @@ -7478,24 +5768,24 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& 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. - + Немає доступу до локальної версії додатка %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. - + Локальна версія додатка %1 не запущена. Запустіть локальну версію додатка %1 і спробуйте ще раз. Would you like to try again? ERROR ALL_PLATFORMS The local AusweisApp (access via reverse proxy) is not reachable, part of an HTML error page. - Бажаєте повторити спробу? + Бажаєте повторити спробу? Try again ERROR ALL_PLATFORMS The local AusweisApp (access via reverse proxy) is not reachable, part of an HTML error page. - Повторіть спробу + Повторіть спробу @@ -7522,11 +5812,6 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& LABEL ALL_PLATFORMS З’єднаний, але не підтримується - - Paired, but unavailable - LABEL ALL_PLATFORMS - З’єднаний, але недоступний - Unsupported LABEL ALL_PLATFORMS @@ -7539,17 +5824,18 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& 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 - online help - Is embedded in a sentence. - онлайн-довідка + Unavailable + LABEL ALL_PLATFORMS + Недоступно - 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. + Click to pair + LABEL ALL_PLATFORMS + Натисніть, щоб створити пару @@ -7582,6 +5868,11 @@ Please enable NFC to use your smartphone as a card reader (SaC). Увімкніть NFC, щоб використовувати свій смартфон як пристрій читання карток (SaC). + + Pairing with %1 successful. + LABEL ALL_PLATFORMS + Створено пару з %1. + governikus::RemoteServiceSettings @@ -7605,15 +5896,18 @@ Please enable NFC to use your smartphone as a card reader (SaC). dd.MM.yyyy + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString dd.MM.yyyy xx.MM.yyyy - xx.ММ.рррр + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString with unknown day + xx.MM.yyyy xx.xx.yyyy - xx.xx.рррр + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString with unknown day and month + xx.xx.yyyy Family name @@ -7679,24 +5973,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. + @@ -7724,11 +6068,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 @@ -7755,6 +6109,14 @@ Please enable NFC to use your smartphone as a card reader (SaC). Немає доступу. + + governikus::StateEstablishPaceChannel + + The secure channel is opened + INFO ALL_PLATFORMS First status message after the PIN was entered. + Захищений канал відкрито + + governikus::StateFinalizePersonalization @@ -7803,21 +6165,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 @@ -7843,18 +6195,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 @@ -7888,8 +6233,8 @@ Please enable NFC to use your smartphone as a card reader (SaC). Макс. довжина пакета NFC - AusweisApp2 Version - Версія AusweisApp2 + %1 Version + Версія %1 NFC Tag Type @@ -7909,16 +6254,16 @@ Please enable NFC to use your smartphone as a card reader (SaC). Відкрити - Quit AusweisApp2 + Quit %1 LABEL DESKTOP - Завершити роботу AusweisApp2 + Завершити роботу %1 governikus::UIPlugInProxy Reverse proxy plugin is enabled - + Плагін зворотного проксі ввімкнено @@ -7933,7 +6278,7 @@ Please enable NFC to use your smartphone as a card reader (SaC). An unknown program uses the required port (%1). Please exit the other program and try again! ERROR ALL_PLATFORMS An unknown programme is using the local port on which the AA2 listens. - Невідома програма використовує потрібний порт (%1). Вийдіть з іншої програми й повторіть спробу. + Невідома програма використовує потрібний порт (%1). Вийдіть з іншої програми й повторіть спробу. The program (%1) uses the required port (%2). Please close %1 and try again! @@ -7941,26 +6286,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! - + Ви намагалися запустити старішу версію (%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 @@ -7982,6 +6319,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 @@ -8016,11 +6358,36 @@ 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 @@ -8038,9 +6405,7 @@ Please enable NFC to use your smartphone as a card reader (SaC). The program remains available via the icon in the system tray. Click on the %1 icon to reopen the user interface. - INFO DESKTOP Content of the popup that is shown when the AA2 is closed for the first time. ----------- -INFO DESKTOP Content of the popup that is shown when the AA2 is closed and a workflow is still active and the close/minimize info was not disabled. + INFO DESKTOP Content of the popup that is shown when the AA2 is closed and the close/minimize info was not disabled. Програма залишається доступною через піктограму в системному лотку. Натисніть піктограму %1, щоб знову відкрити інтерфейс користувача. @@ -8087,5 +6452,25 @@ INFO DESKTOP Content of the popup that is shown when the AA2 is closed and a wor INFO ANDROID IOS Hint that is shown if the users pressed the "back" button on the top-most navigation level for the first time (a second press closes the app). Щоб закрити програму, двічі швидко натисніть кнопку «Назад». + + The program remains available via the icon in the menu bar. Click on the %1 icon to reopen the user interface. + 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 b21d54fcf..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": [ @@ -219,18 +218,16 @@ "": "Auskunft aus den Zentralen Registern des Kraftfahrt-Bundesamtes" }, "longDescription": { - "": "Mit der Anwendung können Privatpersonen eine Auskunft aus dem Fahreignungsregister (Punkteauskunft), dem Zentralen Fahrzeugregister (Fahrzeugzulassungen), dem Zentralen Fahrerlaubnisregister (Führerschein) sowie dem Berufskraftfahrerqualifikationsregister des Kraftfahrt-Bundesamtes erhalten. Diese umfasst ausgewählte Daten, die zu der jeweiligen Person gespeichert sind.
    • Die Online-Auskunft aus dem Zentralen Fahrzeugregister umfasst Informationen zur Fahrzeugbeschreibung, den Halterdaten, der Haftpflichtversicherung, der letzten Haupt- bzw. Sicherheitsüberprüfung, der Fahrzeughistorie und den zulassungsrechtlich relevanten Ereignissen. Daten von vormaligen Haltern und interne Verwaltungsdaten sind von der Auskunft ausgenommen.
    • Die Online-Auskunft aus dem Fahreignungsregister umfasst Informationen zu den eingetragenen Verkehrsverstößen, deren Punktbewertung und Löschungsdatum.
    • Die Online-Auskunft aus dem Zentralen Fahrerlaubnisregister umfasst Informationen zu Fahrerlaubnissen, die seit dem 01.01.1999 erteilt, erweitert oder umgeschrieben wurden. Über die anderen vor dem 01.01.1999 ausgestellten Führerscheine führt nur die jeweils ausstellende Fahrerlaubnisbehörde eine Kartei/Datei.
    • Die Online-Auskunft aus dem Berufskraftfahrerqualifikationsregister umfasst Informationen zu Fahrerqualifizierungsnachweisen sowie Teilnahmebescheinigungen zu Grundqualifikationen, Weiterbildungen und anderen abgeschlossenen Maßnahmen von Berufskraftfahrerinnen und -fahrern.
    " + "": "Mit der Anwendung können Privatpersonen eine Auskunft aus dem Fahreignungsregister (Punkteauskunft), dem Zentralen Fahrzeugregister (Fahrzeugzulassungen), dem Zentralen Fahrerlaubnisregister (Führerschein) sowie dem Berufskraftfahrerqualifikationsregister des Kraftfahrt-Bundesamtes erhalten. Diese umfasst ausgewählte Daten, die zu der jeweiligen Person gespeichert sind.
    • Die Online-Auskunft aus dem Fahreignungsregister umfasst Informationen zu den eingetragenen Verkehrsverstößen, deren Punktbewertung und Löschungsdatum.
    • Die Online-Auskunft aus dem Zentralen Fahrzeugregister umfasst Informationen zur Fahrzeugbeschreibung, den Halterdaten, der Haftpflichtversicherung, der letzten Haupt- bzw. Sicherheitsüberprüfung, der Fahrzeughistorie und den zulassungsrechtlich relevanten Ergebnissen. Daten von vormaligen Haltern und interne Verwaltungsdaten sind von der Auskunft ausgenommen.
    • Die Online-Auskunft aus dem Zentralen Fahrerlaubnisregister umfasst Informationen zu Fahrerlaubnissen, die seit dem 01.01.1999 erteilt, erweitert oder umgeschrieben wurden. Über die anderen vor dem 01.01.1999 ausgestellten Führerscheine führt nur die jeweils ausstellende Fahrerlaubnisbehörde eine Kartei/Datei.
    • Die Online-Auskunft aus dem Berufskraftfahrerqualifikationsregister umfasst Informationen zu Fahrerqualifizierungsnachweisen sowie Teilnahmebescheinigungen zu Grundqualifikationen, Weiterbildungen und anderen abgeschlossenen Maßnahmen von Berufskraftfahrerinnen und -fahrern.
    " }, - "address": "https://www.kba-online.de/registerauskunft/ora/web", + "address": "https://www.kba-online.de/registerauskunft/app", "homepage": "https://www.kba.de", "phone": "+49 461 316 0", "email": "kba@kba.de", "postalAddress": "Kraftfahrt-Bundesamt
    Fördestraße 16
    24944 Flensburg", - "icon": "KraftfahrtBundesamt_icon.png", + "icon": "KraftfahrtBundesamt_icon.svg", "category": "citizen", - "subjectUrls": [ - "https://www.kba-online.de" - ] + "subjectUrlInfo": "Using service from bundID (https://id.bund.de)." }, { "shortName": { @@ -289,9 +286,7 @@ "postalAddress": "Ministerium für Wissenschaft, Energie, Klimaschutz und Umwelt des Landes Sachsen-Anhalt
    Leipziger Straße 58
    39112 Magdeburg", "icon": "BafoegDigital_icon.svg", "category": "citizen", - "subjectUrls": [ - "https://id.bund.de" - ] + "subjectUrlInfo": "Using service from bundID (https://id.bund.de)." }, { "shortName": { @@ -366,9 +361,6 @@ ] }, { - "exclude": [ - "ios" - ], "eidSupport": false, "shortName": { "": "Bundestag ePetition" @@ -464,24 +456,6 @@ "category": "citizen", "subjectUrlInfo": "Using service from Servicekonto Nordrhein-Westfalen (https://servicekonto.nrw)." }, - { - "shortName": { - "": "Stadt Magdeburg - iKFZ" - }, - "longName": { - "": "Stadt Magdeburg - Internetbasierte Fahrzeugzulassung" - }, - "longDescription": { - "": "Die internetbasierte Außerbetriebsetzung und Wiederzulassung eines Kraftfahrzeuges können über das Portal der Landeshauptstadt Magdeburg beantragt werden." - }, - "address": "https://www.magdeburg.de/loadDocument.phtml?ObjSvrID=37&ObjID=27929", - "homepage": "https://www.magdeburg.de/Start/B%C3%BCrger-Stadt/Verwaltung-Service/B%C3%BCrgerService", - "phone": "+49 391 54 00", - "email": "info@magdeburg.de", - "postalAddress": "Landeshauptstadt Magdeburg
    Alter Markt 6
    39104 Magdeburg", - "category": "citizen", - "subjectUrlInfo": "Using service from Serviceportal Sachsen-Anhalt (https://bk.sachsen-anhalt-connect.de)" - }, { "shortName": { "": "Stadt Netphen" @@ -502,35 +476,17 @@ "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" - ] - }, - { - "exclude": [ - "ios" - ], "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", @@ -541,20 +497,17 @@ "subjectUrlInfo": "Using service from Bürgerservice-Portal Krz (https://www.buergerserviceportal.nrw)." }, { - "exclude": [ - "ios" - ], "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", @@ -585,9 +538,6 @@ ] }, { - "exclude": [ - "ios" - ], "eidSupport": false, "shortName": { "": "Bürgerservice-Portal Stadt Lage" @@ -609,9 +559,6 @@ "subjectUrlInfo": "Using service from Bürgerservice-Portal Krz (https://www.buergerserviceportal.nrw)." }, { - "exclude": [ - "ios" - ], "eidSupport": false, "shortName": { "": "Bürgerservice-Portal Stadt Norderstedt" @@ -653,9 +600,6 @@ ] }, { - "exclude": [ - "ios" - ], "eidSupport": false, "shortName": { "": "Bürgerservice-Portale der bayerischen Kommunen" @@ -674,7 +618,8 @@ "category": "citizen", "subjectUrls": [ "https://www.buergerserviceportal.de", - "https://bayernid.freistaat.bayern" + "https://bayernid.freistaat.bayern", + "https://id.bayernportal.de" ] }, { @@ -721,25 +666,21 @@ "": "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)." }, { - "exclude": [ - "ios" - ], "eidSupport": false, "shortName": { "": "eAntrag der Investitionsbank Berlin (IBB)" @@ -761,9 +702,6 @@ ] }, { - "exclude": [ - "ios" - ], "eidSupport": false, "shortName": { "": "ekom21 (KGRZ Hessen)" @@ -806,9 +744,6 @@ ] }, { - "exclude": [ - "ios" - ], "eidSupport": false, "shortName": { "": "Stadt Frankfurt am Main - iKFZ" @@ -957,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" @@ -977,9 +932,6 @@ } }, { - "exclude": [ - "ios" - ], "eidSupport": false, "shortName": { "": "invenio" @@ -1062,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" @@ -1081,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" @@ -1138,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": { @@ -1181,9 +1132,6 @@ ] }, { - "exclude": [ - "ios" - ], "eidSupport": false, "shortName": { "": "Landkreis Hildburghausen - iKFZ" @@ -1232,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", @@ -1261,9 +1209,6 @@ "subjectUrlInfo": "Using service from Landesportal Brandenburg (https://e-ident.brandenburg.de)." }, { - "exclude": [ - "ios" - ], "eidSupport": false, "shortName": { "": "Landkreis Rostock - iKFZ" @@ -1285,9 +1230,6 @@ ] }, { - "exclude": [ - "ios" - ], "eidSupport": false, "shortName": { "": "De-Mail Registrierung" @@ -1404,6 +1346,26 @@ "category": "citizen", "subjectUrlInfo": "Using service from Servicekonto Nordrhein-Westfalen (https://servicekonto.nrw)." }, + { + "shortName": { + "": "Serviceportal der Stadtverwaltung Siegen" + }, + "longName": { + "": "Serviceportal der Stadtverwaltung Siegen" + }, + "longDescription": { + "": "Im Serviceportal der Stadtverwaltung Siegen finden Sie Informationen zu zahlreichen Dienstleistungen, von denen Sie viele bequem von zu Hause aus beantragen, bezahlen und erledigen können. Das Angebot wird ständig erweitert und verbessert.

    Für einige Online-Services ist eine einmalige Registrierung über das Servicekonto.NRW (Konto für alle Online-Anwendungen des Landes und der Kommunen in Nordrhein-Westfalen) erforderlich." + }, + "address": "https://serviceportal.siegen.de", + "homepage": "https://www.siegen.de", + "phone": "+49 271 404 0", + "email": "serviceportal@siegen.de", + "postalAddress": "Stadt Siegen
    Rathaus/Markt 2
    57072 Siegen", + "image": "Siegen_image.jpg", + "icon": "Siegen_icon.jpg", + "category": "citizen", + "subjectUrlInfo": "Using service from Servicekonto Nordrhein-Westfalen (https://servicekonto.nrw)." + }, { "shortName": { "": "Online Services der Stadt Bad Oeynhausen" @@ -1502,9 +1464,6 @@ "subjectUrlInfo": "Using service from Bürgerportal Baden-Württemberg (https://eid.service-bw.de)." }, { - "exclude": [ - "ios" - ], "eidSupport": false, "shortName": { "": "Rheingau-Taunus-Kreis - iKFZ" @@ -1549,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", @@ -1564,9 +1523,6 @@ ] }, { - "exclude": [ - "ios" - ], "eidSupport": false, "shortName": { "": "Kreis Lippe - iKFZ" @@ -1577,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", @@ -1628,10 +1584,6 @@ ] }, { - "exclude": [ - "ios", - "android" - ], "eidSupport": false, "shortName": { "": "nEHS-Register" @@ -1975,9 +1927,6 @@ "subjectUrlInfo": "Using service from Serviceportal Mecklenburg-Vorpommern (https://login.mv-serviceportal.de)." }, { - "exclude": [ - "ios" - ], "eidSupport": false, "shortName": { "": "Serviceportal Sachsen-Anhalt" @@ -2046,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)." }, @@ -2137,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" @@ -2161,20 +2130,22 @@ }, { "shortName": { - "": "Online-Bürgerdienste Nürnberg" + "": "Mein Nürnberg" }, "longName": { - "": "Online-Bürgerdienste der Stadt Nürnberg" + "": "Mein Nürnberg - Die digitale Serviceplattform der Stadt Nürnberg" }, "longDescription": { - "": "Die Stadt Nürnberg bietet Ihnen mit ihrem Bürgerserviceportal ,Mein.Nürnberg' erstmals die Möglichkeit, Ihre Verwaltungsangelegenheiten komplett elektronisch abzuwickeln - von der Antragstellung bis zur Rückmeldung der Bescheide oder Schriftstücke in Ihren persönlichen Bereich auf dem Portal. Alle Online-Dienste der Stadt Nürnberg wurden zudem für die Nutzung mit mobilen Endgeräten optimiert.
    Bei immer mehr Verfahren akzeptiert die Stadtverwaltung einen Unterschriftersatz durch die Online-Ausweisfunktion.
    Jeder Online-Dienst der Stadt Nürnberg, der die Online-Ausweisfunktion nutzt, ist an dem Hinweis 'mit eID' erkennbar. Derzeit sind dies z. B.:
    • Aufenthaltstitel beantragen
    • Gaststättenrechtliche Erlaubnis für den Ausschank von Alkohol beantragen
    • Hunde - Negativzeugnis für Kampfhunde beantragen
    • Kfz-Halterauskunft beantragen
    • Melderegister - Widerspruch gegen Datenübermittlung
    • Veranstaltung, Messe, Markt beantragen
    " + "": "Über die Serviceplattform 'Mein Nürnberg' können Sie schnell, einfach und von zuhause aus Ihre Behördengänge erledigen! Kein langes Anstehen, Warten oder Nummer Ziehen. Mit einem persönlichen 'Mein Nürnberg'-Account bleiben Sie bequem zuhause und erledigen alles von dort - und das rund um die Uhr. Sie sparen sich nicht nur den Weg in die Behörde, sondern können auch den aktuellen Status Ihres Antrages einsehen. Melden Sie sich jetzt an! Das Angebot an Online-Diensten wird ständig erweitert. Ob Sie Ihr Anliegen bereits digital erledigen können, finden Sie über den Behördenwegweiser Nürnberg oder direkt über die Internetseiten der jeweiligen Ämter heraus." }, - "address": "https://www.nuernberg.de/internet/onlinedienste", - "homepage": "https://www.nuernberg.de", - "phone": "+49 9 11 2 31 8613", - "email": "poststelle@stadt.nuernberg.de", - "postalAddress": "Amt für Organisation, Informationsverarbeitung und Zentrale Dienste
    E-Government-Büro
    Rathausplatz 2
    III. OG
    90403 Nürnberg", + "address": "https://www.nuernberg.de/internet/mein_nuernberg", + "homepage": "https://www.nuernberg.de/internet/stadtportal", + "phone": "+49 9 11 2 31 4 50 00", + "email": "online-services@stadt.nuernberg.de", + "postalAddress": "Stadt Nürnberg
    Amt für Digitalisierung und Prozessorganisation Rathausplatz 2
    90403 Nürnberg", "category": "citizen", + "image": "MeinNuernberg_image.jpg", + "icon": "MeinNuernberg_icon.png", "subjectUrls": [ "https://meinkonto.nuernberg.de" ] @@ -2220,9 +2191,6 @@ "subjectUrlInfo": "Using service from Servicekonto Nordrhein-Westfalen (https://servicekonto.nrw)." }, { - "exclude": [ - "ios" - ], "eidSupport": false, "shortName": { "": "Saalekreis - iKFZ" @@ -2251,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", @@ -2262,27 +2229,6 @@ ] }, { - "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)." - }, - { - "exclude": [ - "ios" - ], "eidSupport": false, "shortName": { "": "Urkundenservice Köln" @@ -2304,9 +2250,6 @@ ] }, { - "exclude": [ - "ios" - ], "eidSupport": false, "shortName": { "": "Virtuelles Rathaus Stadt Dortmund" @@ -2326,9 +2269,6 @@ "subjectUrlInfo": "Using service from Servicekonto Nordrhein-Westfalen (https://servicekonto.nrw)." }, { - "exclude": [ - "ios" - ], "eidSupport": false, "shortName": { "": "Vollstreckungsportal" @@ -2368,10 +2308,6 @@ "subjectUrlInfo": "Using service from Servicekonto Nordrhein-Westfalen (https://servicekonto.nrw)." }, { - "exclude": [ - "ios", - "android" - ], "eidSupport": false, "shortName": { "": "Z-EU-S" @@ -2393,6 +2329,196 @@ "subjectUrls": [ "https://www.foerderportal-zeus.de" ] + }, + { + "shortName": { + "": "Landkreis Elbe-Elster" + }, + "longName": { + "": "Landkreis Elbe-Elster - Online Dienste" + }, + "longDescription": { + "": "Bürgerinnen und Bürger im Landkreis Elbe-Elster können viele Behördengänge digital erledigen.
    Je nach Anforderung der jeweiligen Verwaltungsleistung benötigen Sie ein kostenloses Bürgerkonto 'BundID'. Damit können Sie sich elektronisch identifizieren. Sie weisen sich also online gegenüber diesen Leistungen aus." + }, + "address": "https://www.lkee.de/Service-Verwaltung/Online-Dienste", + "homepage": "https://www.lkee.de", + "phone": "+49 3535 460", + "email": "eap@lkee.de", + "postalAddress": "Landkreis Elbe-Elster
    Der Landrat
    Ludwig-Jahn-Str. 2
    04916 Herzberg / Elster", + "image": "lkee_image.jpg", + "icon": "lkee_icon.png", + "category": "citizen", + "subjectUrlInfo": "Using service from Landesportal Brandenburg (https://e-ident.brandenburg.de)." + }, + { + "shortName": { + "": "Online-Services der Landeshauptstadt München" + }, + "longName": { + "": "Online-Services der Landeshauptstadt München" + }, + "longDescription": { + "": "Die Landeshauptstadt München verfügt über eine Vielzahl an Online-Services. Diese können Sie hier einsehen und nutzen." + }, + "address": "https://stadt.muenchen.de/infos/online-services.html", + "homepage": "https://www.muenchen.de", + "email": "rathaus@muenchen.de", + "postalAddress": "Landeshauptstadt München
    80313 München", + "image": "LandeshauptstadtMuenchen_image.png", + "icon": "LandeshauptstadtMuenchen_icon.png", + "category": "citizen", + "subjectUrlInfo": "Using service from Bürgerservice-Portale der bayerischen Kommunen (https://bayernid.freistaat.bayern)." + }, + { + "shortName": { + "": "Antrag auf Elterngeld in Bayern" + }, + "longName": { + "": "Antrag auf Elterngeld in Bayern" + }, + "longDescription": { + "": "Den Antrag auf Elterngeld können Sie in Bayern bei der Landesbehörde Zentrum Bayern Familie und Soziales (ZBFS) stellen. Die Abfragen im Online-Verfahren werden individuell auf Ihre Angaben abgestimmt und Sie erhalten eine Checkliste mit den benötigten Unterlagen. Der Antrag kann digital unterschieben werden." + }, + "address": "https://www.elterngeld.bayern.de/onlineantrag/default.aspx", + "homepage": "https://www.zbfs.bayern.de", + "email": "poststelle@zbfs.bayern.de", + "postalAddress": "Zentrum Bayern Familie und Soziales
    95440 Bayreuth", + "icon": "ZBFS_icon.png", + "category": "citizen", + "subjectUrlInfo": "Using service from Bürgerservice-Portale der bayerischen Kommunen (https://bayernid.freistaat.bayern)." + }, + { + "shortName": { + "": "bundID" + }, + "longName": { + "": "bundID - Ihr Zugang zur digitalen Verwaltung. Einfach. Sicher." + }, + "address": "https://id.bund.de", + "homepage": "https://id.bund.de", + "longDescription": { + "": " Die BundID bietet Ihnen ein zentrales Konto zur Identifizierung für alle Ihre Online-Anträge (z. B. mit einem Online-Ausweis). Sie können das Formular Ihres Online-Antrags durch das Hinterlegen Ihrer persönlichen Daten vorausfüllen lassen. Das spart Zeit, ist sicher und bewahrt Sie vor Tippfehlern.

    Sie erhalten alle Bescheide und Nachrichten in Bezug auf den Online-Antrag bequem in Ihr elektronisches Postfach in Ihrem BundID-Konto." + }, + "postalAddress": "Bundesministerium des Innern und für Heimat
    Alt-Moabit 140
    10557 Berlin", + "category": "citizen", + "subjectUrls": [ + "https://id.bund.de" + ] + }, + { + "shortName": { + "": "Stadt Oberhausen" + }, + "longName": { + "": "Stadt Oberhausen" + }, + "address": "https://serviceportal.oberhausen.de/home", + "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 AusweisApp." + }, + "postalAddress": "Stadt Oberhausen
    Schwartzstraße 72
    46042 Oberhausen", + "icon": "StadtOberhausen_icon.png", + "category": "citizen", + "subjectUrlInfo": "Using service from Servicekonto Nordrhein-Westfalen (https://servicekonto.nrw)." + }, + { + "shortName": { + "": "Digitale Rentenübersicht" + }, + "longName": { + "": "Digitale Rentenübersicht - Zentrale Stelle für die Digitale Rentenübersicht (Deutsche Rentenversicherung Bund)" + }, + "address": "https://app.rentenuebersicht.de", + "homepage": "https://www.rentenuebersicht.de", + "phone": "+49 800 1000 787", + "email": "digitalerentenuebersicht@drv-bund.de", + "longDescription": { + "": "Mit der Online-Ausweisfunktion im neuen Personalausweis können Sie ...
    • Ihre individuellen Altersvorsorge-Ansprüche der gesetzlichen, betrieblichen und privaten Altersvorsorge bequem digital abrufen und
    • die Informationen zum Stand Ihrer Altersvorsorge-Ansprüche als Grundlage für eine weitere unabhängige Beratung herunterladen.
    " + }, + "postalAddress": "Deutsche Rentenversicherung Bund Zentrale Stelle für die Digitale Rentenübersicht
    10868 Berlin", + "icon": "DigitaleRentenuebersicht_icon.svg", + "category": "citizen", + "subjectUrls": [ + "https://login.deutsche-rentenversicherung.de" + ] + }, + { + "shortName": { + "": "Zoll-Portal" + }, + "longName": { + "": "Zoll-Portal" + }, + "address": "https://www.zoll-portal.de", + "homepage": "https://www.zoll-portal.de", + "email": "Zoll-Portal@zoll.bund.de", + "longDescription": { + "": "Das Zoll-Portal bietet Ihnen einen einfachen und effizienten Zugang zu den Dienstleistungen des Zolls (z.B. Kraftfahrzeugsteuer, Agrardieselvergütung oder Energiesteuer). Nach einmaliger Registrierung können Sie Anträge online abwickeln und Bescheide rechtssicher abrufen. Verwenden Sie für die Registrierung und den Login Ihre Online-Ausweisfunktion und Sie können alle Dienstleistungen und Features uneingeschränkt in Anspruch nehmen." + }, + "postalAddress": "Generalzolldirektion
    Am Propsthof 78a
    53121 Bonn", + "icon": "ZollPortal_icon.svg", + "image": "ZollPortal_image.svg", + "category": "citizen", + "subjectUrls": [ + "https://www.zoll-portal.de" + ] + }, + { + "shortName": { + "": "Stadt Augsburg - Digitale Bürgerservices nutzen" + }, + "longName": { + "": "Stadt Augsburg - Digitale Bürgerservices nutzen" + }, + "address": "https://www.augsburg.de/online-services", + "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 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 b336596f5..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,32 +243,30 @@ 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) ##################################################################### include(Install) -include(FeatureSummary) -FEATURE_SUMMARY(WHAT ALL) 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 b4d2d6002..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)); } @@ -207,11 +194,22 @@ public static boolean isStartedByAuth() } + private void convertChromeOsIntent(Intent pIntent) + { + if (pIntent != null && "org.chromium.arc.intent.action.VIEW".equals(pIntent.getAction())) + { + LogHandler.getLogger().info("Convert Intent action " + pIntent.getAction() + " to " + Intent.ACTION_VIEW); + pIntent.setAction(Intent.ACTION_VIEW); + } + } + + @Override public void onCreate(Bundle savedInstanceState) { setTheme(R.style.AppTheme); + convertChromeOsIntent(getIntent()); LogHandler.getLogger().info("onCreate: " + getIntent()); super.onCreate(savedInstanceState); @@ -256,6 +254,7 @@ public void onCreate(Bundle savedInstanceState) @Override protected void onNewIntent(Intent newIntent) { + convertChromeOsIntent(newIntent); cIntent = newIntent; setIntent(newIntent); LogHandler.getLogger().info("onNewIntent: " + newIntent); @@ -263,6 +262,9 @@ protected void onNewIntent(Intent newIntent) } + private native void setReaderModeNative(boolean pEnabled); + + @Override public void onResume() { @@ -270,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(); } @@ -295,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(); + } } @@ -382,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 bb159fecb..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); } @@ -133,7 +144,7 @@ ResponseApduResult CardConnectionWorker::transmit(const CommandApdu& pCommandApd ResponseApduResult result = card->transmit(commandApdu); if (result.mResponseApdu.getStatusCode() == StatusCode::WRONG_LENGTH) { - return {CardReturnCode::EXTENDED_LENGTH_MISSING}; + return {CardReturnCode::WRONG_LENGTH}; } if (mSecureMessaging) @@ -141,7 +152,7 @@ ResponseApduResult CardConnectionWorker::transmit(const CommandApdu& pCommandApd result.mResponseApdu = mSecureMessaging->decrypt(result.mResponseApdu); if (result.mResponseApdu.isEmpty()) { - qCDebug(::card) << "Stopping Secure Messaging since it failed. The channel therefore must no be re-used."; + qCDebug(::card) << "Stopping Secure Messaging since it failed. The channel therefore must not be re-used."; stopSecureMessaging(); return {CardReturnCode::COMMAND_FAILED}; 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/CommandApdu.cpp b/src/card/base/apdu/CommandApdu.cpp index 7ad0b9b28..24b3e56dd 100644 --- a/src/card/base/apdu/CommandApdu.cpp +++ b/src/card/base/apdu/CommandApdu.cpp @@ -13,13 +13,6 @@ using namespace governikus; Q_DECLARE_LOGGING_CATEGORY(card) -#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) - #define HEX hex -#else - #define HEX Qt::hex -#endif - - constexpr std::byte CLA {0x00}; constexpr std::byte CLA_PROPRIETARY {0x80}; constexpr std::byte CLA_COMMAND_CHAINING {0x10}; @@ -128,12 +121,12 @@ CommandApdu::CommandApdu(const QByteArray& pHeader, const QByteArray& pData, int if (mData.size() > EXTENDED_MAX_LC) { - qCCritical(card).nospace() << "Command data exceeds maximum of 0x" << HEX << EXTENDED_MAX_LC; + qCCritical(card).nospace() << "Command data exceeds maximum of 0x" << Qt::hex << EXTENDED_MAX_LC; } if (mLe > EXTENDED_MAX_LE) { - qCCritical(card).nospace() << "Expected length exceeds maximum value of 0x" << HEX << EXTENDED_MAX_LE; + qCCritical(card).nospace() << "Expected length exceeds maximum value of 0x" << Qt::hex << EXTENDED_MAX_LE; } } @@ -148,12 +141,12 @@ CommandApdu::CommandApdu(Ins pIns, uchar pP1, uchar pP2, const QByteArray& pData { if (mData.size() > EXTENDED_MAX_LC) { - qCCritical(card).nospace() << "Command data exceeds maximum of 0x" << HEX << EXTENDED_MAX_LC; + qCCritical(card).nospace() << "Command data exceeds maximum of 0x" << Qt::hex << EXTENDED_MAX_LC; } if (mLe > EXTENDED_MAX_LE) { - qCCritical(card).nospace() << "Expected length exceeds maximum value of 0x" << HEX << EXTENDED_MAX_LE; + qCCritical(card).nospace() << "Expected length exceeds maximum value of 0x" << Qt::hex << EXTENDED_MAX_LE; } } @@ -210,7 +203,7 @@ Ins CommandApdu::getINS() const return Ins(mIns); } - qCCritical(card).nospace().noquote() << "Unknown INS value, returning UNKNOWN, value: 0x" << HEX << mIns; + qCCritical(card).nospace().noquote() << "Unknown INS value, returning UNKNOWN, value: 0x" << Qt::hex << mIns; return Ins::UNKNOWN; } 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/DidAuthenticateEAC2Command.cpp b/src/card/base/command/DidAuthenticateEAC2Command.cpp index b4936f8c0..cea6160e8 100644 --- a/src/card/base/command/DidAuthenticateEAC2Command.cpp +++ b/src/card/base/command/DidAuthenticateEAC2Command.cpp @@ -190,7 +190,7 @@ CardReturnCode DidAuthenticateEAC2Command::putCertificateChain(const CVCertifica break; case StatusCode::WRONG_LENGTH: - return CardReturnCode::EXTENDED_LENGTH_MISSING; + return CardReturnCode::WRONG_LENGTH; default: qCWarning(card) << "TA PSO:Verify Certificate failed:" << psoResult.getStatusCode(); 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 d2e66356b..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; } @@ -115,7 +114,7 @@ EstablishPaceChannelErrorCode EstablishPaceChannelOutput::generateReturnCode(Car case CardReturnCode::PUK_INOPERATIVE: case CardReturnCode::UNEXPECTED_TRANSMIT_STATUS: case CardReturnCode::PROTOCOL_ERROR: - case CardReturnCode::EXTENDED_LENGTH_MISSING: + case CardReturnCode::WRONG_LENGTH: return EstablishPaceChannelErrorCode::UnexpectedDataInInput; case CardReturnCode::INVALID_CAN: @@ -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 2fc096812..72485a177 100644 --- a/src/card/pcsc/PcscReader.cpp +++ b/src/card/pcsc/PcscReader.cpp @@ -25,16 +25,7 @@ PcscReader::PcscReader(const QString& pReaderName) qCDebug(card_pcsc) << pReaderName; setObjectName(pReaderName); - PCSC_RETURNCODE returnCode = SCardEstablishContext(SCARD_SCOPE_USER, nullptr, nullptr, &mContextHandle); - qCDebug(card_pcsc) << "SCardEstablishContext:" << PcscUtils::toString(returnCode); - if (returnCode != PcscUtils::Scard_S_Success) - { - qCWarning(card_pcsc) << "Cannot establish context"; - return; - } - memset(&mReaderState, 0, sizeof(SCARD_READERSTATE)); - #if defined(Q_OS_WIN) && defined(UNICODE) wchar_t* name = new wchar_t[static_cast(pReaderName.size()) + 1](); pReaderName.toWCharArray(name); @@ -42,27 +33,44 @@ PcscReader::PcscReader(const QString& pReaderName) #else mReaderState.szReader = qstrdup(pReaderName.toUtf8().data()); #endif +} + + +PCSC_RETURNCODE PcscReader::init() +{ + PCSC_RETURNCODE returnCode = SCardEstablishContext(SCARD_SCOPE_USER, nullptr, nullptr, &mContextHandle); + 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; + return returnCode; } setInfoBasicReader(!hasFeature(FeatureID::EXECUTE_PACE)); PcscReader::updateCard(); setTimerId(startTimer(500)); + return pcsc::Scard_S_Success; } PcscReader::~PcscReader() { qCDebug(card_pcsc) << getReaderInfo().getName(); - qCDebug(card_pcsc) << "SCardCancel: " << PcscUtils::toString(SCardCancel(mContextHandle)); - qCDebug(card_pcsc) << "SCardReleaseContext:" << PcscUtils::toString(SCardReleaseContext(mContextHandle)); - mContextHandle = 0; + + if (mContextHandle != 0) + { + qCDebug(card_pcsc) << "SCardCancel: " << pcsc::toString(SCardCancel(mContextHandle)); + qCDebug(card_pcsc) << "SCardReleaseContext:" << pcsc::toString(SCardReleaseContext(mContextHandle)); + mContextHandle = 0; + } delete[] mReaderState.szReader; } @@ -149,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) { @@ -164,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; } @@ -211,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()) { @@ -271,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) @@ -305,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/PcscReader.h b/src/card/pcsc/PcscReader.h index 85af8313b..7d121b8e3 100644 --- a/src/card/pcsc/PcscReader.h +++ b/src/card/pcsc/PcscReader.h @@ -40,6 +40,7 @@ class PcscReader public: explicit PcscReader(const QString& pReaderName); + [[nodiscard]] PCSC_RETURNCODE init(); ~PcscReader() override; [[nodiscard]] Card* getCard() const override; diff --git a/src/card/pcsc/PcscReaderManagerPlugIn.cpp b/src/card/pcsc/PcscReaderManagerPlugIn.cpp index 5928495f3..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)) @@ -133,20 +133,7 @@ void PcscReaderManagerPlugIn::updateReaders() } removeReaders(readersToRemove); - - for (QMutableListIterator iterator(readersToAdd); iterator.hasNext();) - { - QString readerName = iterator.next(); - Reader* reader = new PcscReader(readerName); - mReaders.insert(readerName, reader); - - connect(reader, &Reader::fireCardInserted, this, &PcscReaderManagerPlugIn::fireCardInserted); - connect(reader, &Reader::fireCardRemoved, this, &PcscReaderManagerPlugIn::fireCardRemoved); - connect(reader, &Reader::fireCardInfoChanged, this, &PcscReaderManagerPlugIn::fireCardInfoChanged); - - qCDebug(card_pcsc) << "fireReaderAdded:" << readerName << "(" << mReaders.size() << "reader in total )"; - Q_EMIT fireReaderAdded(reader->getReaderInfo()); - } + addReaders(readersToAdd); } @@ -162,6 +149,30 @@ QString PcscReaderManagerPlugIn::extractReaderName(const PCSC_CHAR_PTR pReaderPo } +void PcscReaderManagerPlugIn::addReaders(const QStringList& pReaderNames) +{ + for (const auto& readerName : pReaderNames) + { + auto pcscReader = std::make_unique(readerName); + if (pcscReader->init() != pcsc::Scard_S_Success) + { + qCDebug(card_pcsc) << "Initialization of" << readerName << "failed"; + continue; + } + + Reader* reader = pcscReader.release(); + mReaders.insert(readerName, reader); + + connect(reader, &Reader::fireCardInserted, this, &PcscReaderManagerPlugIn::fireCardInserted); + connect(reader, &Reader::fireCardRemoved, this, &PcscReaderManagerPlugIn::fireCardRemoved); + connect(reader, &Reader::fireCardInfoChanged, this, &PcscReaderManagerPlugIn::fireCardInfoChanged); + + qCDebug(card_pcsc) << "fireReaderAdded:" << readerName << "(" << mReaders.size() << "reader in total )"; + Q_EMIT fireReaderAdded(reader->getReaderInfo()); + } +} + + void PcscReaderManagerPlugIn::removeReader(const QString& pReaderName) { if (!mReaders.contains(pReaderName)) @@ -187,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 b69a5c39d..a36f844b5 100644 --- a/src/card/pcsc/PcscReaderManagerPlugIn.h +++ b/src/card/pcsc/PcscReaderManagerPlugIn.h @@ -17,6 +17,9 @@ #include +class test_PcscReaderManagerPlugIn; + + namespace governikus { @@ -26,6 +29,7 @@ class PcscReaderManagerPlugIn Q_OBJECT Q_PLUGIN_METADATA(IID "governikus.ReaderManagerPlugIn" FILE "metadata.json") Q_INTERFACES(governikus::ReaderManagerPlugIn) + friend class ::test_PcscReaderManagerPlugIn; private: SCARDCONTEXT mContextHandle; @@ -33,9 +37,10 @@ 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); void removeReader(const QString& pReaderName); void removeReaders(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 98a6707c1..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" @@ -35,6 +36,7 @@ SimulatorCard::SimulatorCard(const SimulatorFileSystem& pFileSystem) , mAuxiliaryData() , mSecureMessaging() , mNewSecureMessaging() + , mCaKeyId(0) , mRiKeyId(0) { } @@ -179,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)}; @@ -238,6 +240,10 @@ ResponseApduResult SimulatorCard::executeMseSetAt(const CommandApdu& pCmd) if (pCmd.getP1() == CommandApdu::CHIP_AUTHENTICATION && pCmd.getP2() == CommandApdu::AUTHENTICATION_TEMPLATE) { const auto& cmr = cmdData.getData(V_ASN1_CONTEXT_SPECIFIC, CommandData::CRYPTOGRAPHIC_MECHANISM_REFERENCE); + if (cmr == Oid(KnownOid::ID_CA_ECDH_AES_CBC_CMAC_128).getData()) + { + mCaKeyId = cmdData.getData(V_ASN1_CONTEXT_SPECIFIC, CommandData::PRIVATE_KEY_REFERENCE).back(); + } if (cmr == Oid(KnownOid::ID_RI_ECDH_SHA_256).getData()) { mRiKeyId = cmdData.getData(V_ASN1_CONTEXT_SPECIFIC, CommandData::PRIVATE_KEY_REFERENCE).back(); @@ -257,37 +263,36 @@ ResponseApduResult SimulatorCard::executeMseSetAt(const CommandApdu& pCmd) ResponseApduResult SimulatorCard::executeGeneralAuthenticate(const CommandApdu& pCmd) { - ResponseApduResult result = {CardReturnCode::OK, ResponseApdu(StatusCode::SUCCESS)}; - const CommandData cmdData(pCmd.getData()); const auto& caKey = cmdData.getData(V_ASN1_CONTEXT_SPECIFIC, CommandData::CA_EPHEMERAL_PUBLIC_KEY); if (!caKey.isEmpty()) { - // CA General Authenticate - Chip Authentication const QByteArray nonce = QByteArray::fromHex("0001020304050607"); const QByteArray& authenticationToken = generateAuthenticationToken(caKey, nonce); auto ga = newObject(); Asn1OctetStringUtil::setValue(nonce, ga->mNonce); Asn1OctetStringUtil::setValue(authenticationToken, ga->mAuthenticationToken); - result = {CardReturnCode::OK, ResponseApdu(encodeObject(ga.data()) + QByteArray::fromHex("9000"))}; + return {CardReturnCode::OK, ResponseApdu(encodeObject(ga.data()) + QByteArray::fromHex("9000"))}; } - else + + const auto& riKey = cmdData.getData(V_ASN1_CONTEXT_SPECIFIC, CommandData::RI_EPHEMERAL_PUBLIC_KEY); + if (!riKey.isEmpty()) { - const auto& riKey = cmdData.getData(V_ASN1_CONTEXT_SPECIFIC, CommandData::RI_EPHEMERAL_PUBLIC_KEY); - if (!riKey.isEmpty()) + const auto& oid = cmdData.getData(V_ASN1_UNIVERSAL, CommandData::RI_EPHEMERAL_PUBLIC_KEY); + if (oid != Oid(KnownOid::ID_RI_ECDH_SHA_256).getData()) { - // RE General Authenticate - Restricted Identification - const QByteArray& restrictedId = generateRestrictedId(riKey); + return {CardReturnCode::OK, ResponseApdu(StatusCode::NO_BINARY_FILE)}; + } - const auto responseData = Asn1Util::encode(V_ASN1_CONTEXT_SPECIFIC, 1, restrictedId); - const auto response = Asn1Util::encode(V_ASN1_APPLICATION, 28, responseData, true); + const QByteArray& restrictedId = generateRestrictedId(riKey); - result = {CardReturnCode::OK, ResponseApdu(response + QByteArray::fromHex("9000"))}; - } + const auto responseData = Asn1Util::encode(V_ASN1_CONTEXT_SPECIFIC, 1, restrictedId); + const auto response = Asn1Util::encode(V_ASN1_APPLICATION, 28, responseData, true); + return {CardReturnCode::OK, ResponseApdu(response + QByteArray::fromHex("9000"))}; } - return result; + return {CardReturnCode::OK, ResponseApdu(StatusCode::SUCCESS)}; } @@ -302,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"; } @@ -321,7 +326,7 @@ QByteArray SimulatorCard::generateAuthenticationToken(const QByteArray& pPublicK { const Oid oid(KnownOid::ID_CA_ECDH_AES_CBC_CMAC_128); - QByteArray sharedSecret = brainpoolP256r1Multiplication(pPublicKey, mFileSystem.getCardAuthenticationKey()); + QByteArray sharedSecret = brainpoolP256r1Multiplication(pPublicKey, mFileSystem.getPrivateKey(mCaKeyId)); const auto protocol = SecurityProtocol(oid); KeyDerivationFunction kdf(protocol); @@ -342,11 +347,11 @@ 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); - QByteArray sharedSecret = brainpoolP256r1Multiplication(pPublicKey, mFileSystem.getRestrictedIdentificationKey(mRiKeyId)); + QByteArray sharedSecret = brainpoolP256r1Multiplication(pPublicKey, mFileSystem.getPrivateKey(mRiKeyId)); return QCryptographicHash::hash(sharedSecret, QCryptographicHash::Sha256); } @@ -355,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 4331aa3be..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" @@ -31,6 +30,7 @@ class SimulatorCard QSharedPointer mAuxiliaryData; std::unique_ptr mSecureMessaging; std::unique_ptr mNewSecureMessaging; + int mCaKeyId; int mRiKeyId; public: @@ -54,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 57063e4ed..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" @@ -24,11 +23,12 @@ using namespace governikus; Q_DECLARE_LOGGING_CATEGORY(card) -SimulatorFileSystem::SimulatorFileSystem() - : mSelectedFile() - , mFiles() - , mFileIds() +void SimulatorFileSystem::initMandatoryData() { + mKeys.insert(1, QByteArray::fromHex("0353859C2EC67780BA39015DE8C682AF2326D43DE9CE1E07737087BD1E17CB22")); + mKeys.insert(2, QByteArray::fromHex("9AD0AD7F4DFAAA06988339FC31D3A111F4C7964AC7F377373A2454327C43E2FF")); + mKeys.insert(41, QByteArray::fromHex("A07EB62E891DAA84643E0AFCC1AF006891B669B8F51E379477DBEAB8C987A610")); + createFile(FileRef::efDir().getIdentifier(), FileRef::efDir().getShortIdentifier(), QByteArray::fromHex( "61324F0FE828BD080FA000000167455349474E500F434941207A752044462E655369676E5100730C4F0AA00000016745" "5349474E61094F07A0000002471001610B4F09E80704007F00070302610C4F0AA000000167455349474E")); @@ -93,6 +93,16 @@ SimulatorFileSystem::SimulatorFileSystem() "0304046630640230582364C74D9C694D3C8F99ACBF82A7A847141248B015AED8BEE3C395E82788426F032978D196303A" "6B81D9FA8B8DBC8E02305BF169DE97B344A4B03E862C48A76226F044C6DA1EA78E380C2C6479B79526415735345764D7" "B6E738EE83931AABE840")); +} + + +SimulatorFileSystem::SimulatorFileSystem() + : mSelectedFile() + , mKeys() + , mFiles() + , mFileIds() +{ + initMandatoryData(); // Default profile 01 : 01 - 0A, 0D, 11 - 12 // Additional data fields : 0B - 0C, 0E - 0F, 13 - 16 @@ -135,9 +145,15 @@ SimulatorFileSystem::SimulatorFileSystem() SimulatorFileSystem::SimulatorFileSystem(const QJsonObject& pData) + : mSelectedFile() + , mKeys() + , mFiles() + , mFileIds() { + initMandatoryData(); + const auto& files = pData[QLatin1String("files")].toArray(); - for (JsonValueRef value : files) + for (const QJsonValueConstRef value : files) { if (!value.isObject()) { @@ -159,6 +175,27 @@ SimulatorFileSystem::SimulatorFileSystem(const QJsonObject& pData) QByteArray::fromHex(shortFileId.toUtf8()), QByteArray::fromHex(content.toUtf8())); } + + const auto& keys = pData[QLatin1String("keys")].toArray(); + for (const QJsonValueConstRef value : keys) + { + if (!value.isObject()) + { + qCWarning(card) << "Skipping key entry. Expected JSON object, got" << value; + continue; + } + + const auto& key = value.toObject(); + const auto& keyId = key[QLatin1String("id")].toInt(0); + const auto& privateKey = key[QLatin1String("private")].toString(); + if (keyId == 0 || privateKey.isNull()) + { + qCWarning(card) << "Skipping key entry. Expected JSON object with 'id' and 'private', got" << key; + continue; + } + + mKeys.insert(keyId, QByteArray::fromHex(privateKey.toUtf8())); + } } @@ -184,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) { @@ -218,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)) { @@ -241,29 +278,13 @@ QByteArray SimulatorFileSystem::getEfCardAccess() const } -QByteArray SimulatorFileSystem::getCardAuthenticationKey() const -{ - return QByteArray::fromHex("A07EB62E891DAA84643E0AFCC1AF006891B669B8F51E379477DBEAB8C987A610"); -} - - -QByteArray SimulatorFileSystem::getRestrictedIdentificationKey(int pKeyId) const +QByteArray SimulatorFileSystem::getPrivateKey(int pKeyId) const { - switch (pKeyId) - { - case 1: - return QByteArray::fromHex("0353859C2EC67780BA39015DE8C682AF2326D43DE9CE1E07737087BD1E17CB22"); - - case 2: - return QByteArray::fromHex("9AD0AD7F4DFAAA06988339FC31D3A111F4C7964AC7F377373A2454327C43E2FF"); - - default: - return QByteArray(); - } + return mKeys[pKeyId]; } -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 efd84a98f..48cc8f967 100644 --- a/src/card/simulator/SimulatorFileSystem.h +++ b/src/card/simulator/SimulatorFileSystem.h @@ -25,22 +25,24 @@ class SimulatorFileSystem { private: QByteArray mSelectedFile; + QMap mKeys; QMap mFiles; QMap mFileIds; + void initMandatoryData(); + public: 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 getCardAuthenticationKey() const; - [[nodiscard]] QByteArray getRestrictedIdentificationKey(int pKeyId) 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 43afb959a..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(); } @@ -60,9 +61,12 @@ void SimulatorReaderManagerPlugIn::stopScan(const QString& pError) if (mSimulatorReader) { mSimulatorReader->disconnectReader(pError); + + auto info = mSimulatorReader->getReaderInfo(); + mSimulatorReader.reset(); + Q_EMIT fireReaderRemoved(info); } ReaderManagerPlugIn::stopScan(pError); - mSimulatorReader.reset(); } @@ -70,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 06e7bcb14..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 } @@ -395,104 +431,162 @@ void SmartManager::abortSDKWorkflow() const } -#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) - #define HEX hex -#else - #define HEX Qt::hex -#endif - - 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" << 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" << 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::UNSUPPORTED: + result = QLatin1String("UNSUPPORTED"); + break; - case EidServiceResult::UNDEFINED: - return QLatin1String("UNDEFINED"); + case EidServiceResult::OVERLOAD_PROTECTION: + result = QLatin1String("OVERLOAD_PROTECTION"); + break; - case EidServiceResult::INFO: - return QLatin1String("INFO"); + case EidServiceResult::UNDER_MAINTENANCE: + result = QLatin1String("UNDER_MAINTENANCE"); + break; - case EidServiceResult::WARN: - return QLatin1String("WARN"); + case EidServiceResult::NFC_NOT_ACTIVATED: + result = QLatin1String("NFC_NOT_ACTIVATED"); + break; - case EidServiceResult::ERROR: - return QLatin1String("ERROR"); + case EidServiceResult::INTEGRITY_CHECK_FAILED: + result = QLatin1String("INTEGRITY_CHECK_FAILED"); + break; - case EidServiceResult::UNSUPPORTED: - return QLatin1String("UNSUPPORTED"); - } + case EidServiceResult::NOT_AUTHENTICATED: + result = QLatin1String("NOT_AUTHENTICATED"); + break; - Q_UNREACHABLE(); - }; + case EidServiceResult::NETWORK_CONNECTION_ERROR: + result = QLatin1String("NETWORK_CONNECTION_ERROR"); + break; + } QDebugStateSaver saver(pDbg); - pDbg.nospace() << toString(pResult) << " 0x" << HEX << static_cast(pResult); + pDbg.nospace() << result << " 0x" << Qt::hex << static_cast(pResult); + return pDbg; +} + + +QDebug operator<<(QDebug pDbg, const SmartEidType& pType) +{ + QLatin1String type; + switch (pType) + { + case SmartEidType::UNKNOWN: + type = QLatin1String("UNKNOWN"); + break; + + case SmartEidType::APPLET: + type = QLatin1String("APPLET"); + break; + + case SmartEidType::NON_APPLET: + type = QLatin1String("NON_APPLET"); + break; + } + + 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 << "{" << 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/DiagnosisConnectionTest.cpp b/src/diagnosis/DiagnosisConnectionTest.cpp index b4f1be915..93d7e61e9 100644 --- a/src/diagnosis/DiagnosisConnectionTest.cpp +++ b/src/diagnosis/DiagnosisConnectionTest.cpp @@ -159,7 +159,14 @@ void DiagnosisConnectionTest::startConnectionTest() mConnectionTestWithProxyDone = false; mConnectionTestWithoutProxyDone = false; - const auto& proxy = QNetworkProxy::applicationProxy(); + const QUrl& testUrl = QUrl(Env::getSingleton()->getUpdateServerBaseUrl()); + const auto& proxies = QNetworkProxyFactory::proxyForQuery(QNetworkProxyQuery(testUrl)); + const auto& proxy = proxies.constFirst(); + if (proxies.size() > 1) + { + qDebug() << "More than one proxy found, using first proxy:" << proxy; + } + if (proxy.type() == QNetworkProxy::ProxyType::NoProxy) { mIsProxySet = false; @@ -175,7 +182,6 @@ void DiagnosisConnectionTest::startConnectionTest() mProxyCapabilities = getProxyCapabilitiesAsQString(proxy.capabilities()); } - const QUrl& testUrl = QUrl(Env::getSingleton()->getUpdateServerBaseUrl()); if (mIsProxySet) { mPingSocketToProxy.reset(); 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 bb2f13a68..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); } @@ -339,7 +395,7 @@ void DiagnosisModel::onTimestampChanged() QDateTime timestampValue = mContext->getTimestamp(); if (timestampValue.isValid()) { - //: LABEL DESKTOP Timestamp, formatted according to the selected language + //: LABEL DESKTOP Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString QString timestamp = LanguageLoader::getInstance().getUsedLocale().toString(timestampValue, tr("d. MMMM yyyy, hh:mm:ss AP")); //: LABEL DESKTOP mTimestampSection << ContentItem(tr("Time of diagnosis"), timestamp); @@ -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 @@ -706,7 +762,7 @@ void DiagnosisModel::onRemoteInfosChanged() if (!info.getFingerprint().isEmpty()) { - //: LABEL DESKTOP Timestamp + //: LABEL DESKTOP Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString const QString& timestamp = LanguageLoader::getInstance().getUsedLocale().toString(info.getLastConnected(), tr("dd.MM.yyyy, hh:mm:ss")); //: LABEL DESKTOP mRemoteDeviceSection << ContentItem(info.getNameEscaped(), tr("Last connection: %1").arg(timestamp)); @@ -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 c22ccd03f..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 - 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 - QString date = locale.toString(now, tr("dd.MM.yyyy")); - //: LABEL ALL_PLATFORMS - 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 - QString date = locale.toString(pDate, tr("dd.MM.yyyy")); - //: LABEL ALL_PLATFORMS - 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 index 0e5ea8711..45f8298e4 100644 --- a/src/external/smart/README.md +++ b/src/external/smart/README.md @@ -1,35 +1,13 @@ eid-applet-service jni bridge ============================= -- Current `eid_applet_interface.h` version: `0.16.0` -- Current `eid-applet-service-lib.aar` version: `0.10.3-180` +- Current `eid_applet_interface.h` version: `0.23.0` +- Current `eid-applet-service-lib.aar` version: `1.1.0` -## Availability +## Description -If you have access to the `partner.bdr.de` network, the -`eid-applet-service-lib` library is also available through the -artifactory maven repository. `app/build.gradle` integration: - -```gradle - implementation "de.bdr.android.eid-applet-service-lib:eid-applet-service-lib:0.10.3-180" -``` - -Parse and set the credentials within the root `build.gradle`. - -```gradle -allprojects { - repositories { - // ... - maven { - url 'https://partner.bdr.de/artifactory/mid-mvn/' - credentials { - username "Your_User_Name" - password "Your_Password_Or_API_Key" - } - } - } -} -``` +Creates the interface between the `eID Client` (AA2) application and the +`eid-applet-service-lib` (delivered as .aar - android archive) ## Usage @@ -45,12 +23,30 @@ successfully. ## Additional remarks -- Currently used ndk version: `21.3.6528147` +- Currently used ndk version: `25.2.9519653` License ------- +EN version: + ``` -Copyright (C) 2021 Bundesdruckerei GmbH and Governikus GmbH +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 047d811fc..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; @@ -32,8 +31,8 @@ GlobalStatus CardReturnCodeUtil::toGlobalStatus(CardReturnCode pCode) case CardReturnCode::PROTOCOL_ERROR: return GlobalStatus::Code::Card_Protocol_Error; - case CardReturnCode::EXTENDED_LENGTH_MISSING: - return GlobalStatus::Code::Workflow_No_Extended_Length_Error; + case CardReturnCode::WRONG_LENGTH: + return GlobalStatus::Code::Workflow_Wrong_Length_Error; case CardReturnCode::UNEXPECTED_TRANSMIT_STATUS: return GlobalStatus::Code::Card_Unexpected_Transmit_Status; @@ -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: @@ -99,13 +97,12 @@ bool CardReturnCodeUtil::equalsWrongPacePassword(CardReturnCode pCode) case CardReturnCode::UNKNOWN: case CardReturnCode::COMMAND_FAILED: case CardReturnCode::PROTOCOL_ERROR: - case CardReturnCode::EXTENDED_LENGTH_MISSING: + case CardReturnCode::WRONG_LENGTH: case CardReturnCode::UNEXPECTED_TRANSMIT_STATUS: case CardReturnCode::OK: 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 a9222ff2c..691f830a7 100644 --- a/src/global/CardReturnCode.h +++ b/src/global/CardReturnCode.h @@ -35,9 +35,8 @@ defineEnumType(CardReturnCode, PIN_BLOCKED, PIN_NOT_BLOCKED, PUK_INOPERATIVE, - NO_ACTIVE_PIN_SET, PROTOCOL_ERROR, - EXTENDED_LENGTH_MISSING, + 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 dcf829505..e1e99921d 100644 --- a/src/global/ECardApiResult.cpp +++ b/src/global/ECardApiResult.cpp @@ -95,53 +95,62 @@ void ECardApiResult::initConversionMaps() return; } + addConversionElement(GlobalStatus::Code::No_Error, Minor::null); + addConversionElement(GlobalStatus::Code::Paos_Error_AL_Unknown_Error, Minor::AL_Unknown_Error); addConversionElement(GlobalStatus::Code::Paos_Unexpected_Warning, Minor::AL_Unknown_Error); addConversionElement(GlobalStatus::Code::Unknown_Error, Minor::AL_Unknown_Error); addConversionElement(GlobalStatus::Code::Card_Unexpected_Transmit_Status, Minor::AL_Unknown_Error); + addConversionElement(GlobalStatus::Code::Card_NewPin_Invalid_Length, Minor::AL_Unknown_Error); + addConversionElement(GlobalStatus::Code::Workflow_AlreadyInProgress_Error, Minor::AL_Unknown_Error); + addConversionElement(GlobalStatus::Code::Workflow_Wrong_Length_Error, Minor::AL_Unknown_Error); + addConversionElement(GlobalStatus::Code::Card_Not_Found, Minor::AL_Unknown_Error); + addConversionElement(GlobalStatus::Code::Card_Communication_Error, Minor::AL_Unknown_Error); + addConversionElement(GlobalStatus::Code::Card_Input_TimeOut, Minor::AL_Unknown_Error); + addConversionElement(GlobalStatus::Code::Card_Pin_Blocked, Minor::AL_Unknown_Error); + addConversionElement(GlobalStatus::Code::Card_Pin_Not_Blocked, Minor::AL_Unknown_Error); + addConversionElement(GlobalStatus::Code::Card_NewPin_Mismatch, Minor::AL_Unknown_Error); + addConversionElement(GlobalStatus::Code::Card_ValidityVerificationFailed, Minor::SAL_MEAC_DocumentValidityVerificationFailed); + addConversionElement(GlobalStatus::Code::RemoteReader_CloseCode_AbnormalClose, Minor::AL_Unknown_Error); + addConversionElement(GlobalStatus::Code::IfdConnector_InvalidRequest, Minor::AL_Unknown_Error); + addConversionElement(GlobalStatus::Code::IfdConnector_NoSupportedApiLevel, Minor::AL_Unknown_Error); + addConversionElement(GlobalStatus::Code::IfdConnector_ConnectionTimeout, Minor::AL_Unknown_Error); + addConversionElement(GlobalStatus::Code::IfdConnector_ConnectionError, Minor::AL_Unknown_Error); + addConversionElement(GlobalStatus::Code::IfdConnector_RemoteHostRefusedConnection, Minor::AL_Unknown_Error); + addConversionElement(GlobalStatus::Code::Downloader_File_Not_Found, Minor::AL_Unknown_Error); + addConversionElement(GlobalStatus::Code::Downloader_Cannot_Save_File, Minor::AL_Unknown_Error); + addConversionElement(GlobalStatus::Code::Downloader_Data_Corrupted, Minor::AL_Unknown_Error); + addConversionElement(GlobalStatus::Code::Downloader_Missing_Platform, Minor::AL_Unknown_Error); + addConversionElement(GlobalStatus::Code::Downloader_Aborted, Minor::AL_Unknown_Error); + addConversionElement(GlobalStatus::Code::Update_Execution_Failed, Minor::AL_Unknown_Error); + 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::No_Error, Minor::null); - - addConversionElement(GlobalStatus::Code::Workflow_Card_Removed, Minor::IFDL_CancellationByUser); + 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::Workflow_No_Unique_DvCvc, ECardApiResult::Minor::IL_Signature_InvalidCertificatePath); - addConversionElement(GlobalStatus::Code::Workflow_No_Unique_AtCvc, ECardApiResult::Minor::IL_Signature_InvalidCertificatePath); - addConversionElement(GlobalStatus::Code::Workflow_Preverification_Error, ECardApiResult::Minor::IL_Signature_InvalidCertificatePath); - addConversionElement(GlobalStatus::Code::Workflow_Preverification_Developermode_Error, ECardApiResult::Minor::IL_Signature_InvalidCertificatePath); + addConversionElement(GlobalStatus::Code::Paos_Error_AL_Internal_Error, Minor::AL_Internal_Error); + addConversionElement(GlobalStatus::Code::Workflow_Cannot_Confirm_IdCard_Authenticity, Minor::AL_Internal_Error); + addConversionElement(GlobalStatus::Code::Workflow_Unknown_Paos_From_EidServer, Minor::AL_Internal_Error); + addConversionElement(GlobalStatus::Code::Workflow_Start_Paos_Response_Missing, Minor::AL_Internal_Error); + addConversionElement(GlobalStatus::Code::Workflow_Unexpected_Message_From_EidServer, Minor::AL_Internal_Error); + addConversionElement(GlobalStatus::Code::Card_Protocol_Error, Minor::AL_Internal_Error); addConversionElement(GlobalStatus::Code::Workflow_Certificate_No_Description, Minor::AL_Parameter_Error); addConversionElement(GlobalStatus::Code::Workflow_Certificate_No_Url_In_Description, Minor::AL_Parameter_Error); addConversionElement(GlobalStatus::Code::Workflow_Certificate_Hash_Error, Minor::AL_Parameter_Error); addConversionElement(GlobalStatus::Code::Workflow_Certificate_Sop_Error, Minor::AL_Parameter_Error); - 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_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); - addConversionElement(GlobalStatus::Code::Workflow_TrustedChannel_Ssl_Certificate_Unsupported_Algorithm_Or_Length, Minor::DP_Trusted_Channel_Establishment_Failed); - addConversionElement(GlobalStatus::Code::Workflow_TrustedChannel_ServiceUnavailable, Minor::DP_Trusted_Channel_Establishment_Failed); - addConversionElement(GlobalStatus::Code::Workflow_TrustedChannel_TimeOut, Minor::DP_Trusted_Channel_Establishment_Failed); - addConversionElement(GlobalStatus::Code::Workflow_TrustedChannel_Proxy_Error, Minor::DP_Trusted_Channel_Establishment_Failed); - addConversionElement(GlobalStatus::Code::Workflow_TrustedChannel_Establishment_Error, Minor::DP_Trusted_Channel_Establishment_Failed); - addConversionElement(GlobalStatus::Code::Workflow_TrustedChannel_Server_Format_Error, Minor::DP_Trusted_Channel_Establishment_Failed); - addConversionElement(GlobalStatus::Code::Workflow_TrustedChannel_Other_Network_Error, Minor::DP_Trusted_Channel_Establishment_Failed); - - addConversionElement(GlobalStatus::Code::Paos_Error_SAL_Cancellation_by_User, Minor::SAL_Cancellation_by_User); - 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_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::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); @@ -153,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); @@ -160,28 +171,33 @@ void ECardApiResult::initConversionMaps() addConversionElement(GlobalStatus::Code::Card_Invalid_Pin, Minor::AL_Communication_Error); addConversionElement(GlobalStatus::Code::Card_Invalid_Can, Minor::AL_Communication_Error); addConversionElement(GlobalStatus::Code::Card_Invalid_Puk, Minor::AL_Communication_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_PrePersonalization_Failed, Minor::AL_Unknown_Error); - addConversionElement(GlobalStatus::Code::Workflow_Smart_eID_Personalization_Failed, Minor::AL_Unknown_Error); - addConversionElement(GlobalStatus::Code::Card_NewPin_Invalid_Length, Minor::AL_Unknown_Error); - addConversionElement(GlobalStatus::Code::Workflow_AlreadyInProgress_Error, Minor::AL_Unknown_Error); - addConversionElement(GlobalStatus::Code::Workflow_No_Extended_Length_Error, Minor::AL_Unknown_Error); - addConversionElement(GlobalStatus::Code::Card_Not_Found, Minor::AL_Unknown_Error); - addConversionElement(GlobalStatus::Code::Card_Communication_Error, Minor::AL_Unknown_Error); - addConversionElement(GlobalStatus::Code::Card_Input_TimeOut, Minor::AL_Unknown_Error); - addConversionElement(GlobalStatus::Code::Card_Pin_Blocked, Minor::AL_Unknown_Error); - addConversionElement(GlobalStatus::Code::Card_Pin_Not_Blocked, Minor::AL_Unknown_Error); - addConversionElement(GlobalStatus::Code::Card_NewPin_Mismatch, Minor::AL_Unknown_Error); - addConversionElement(GlobalStatus::Code::Card_ValidityVerificationFailed, Minor::SAL_MEAC_DocumentValidityVerificationFailed); - addConversionElement(GlobalStatus::Code::Card_Smart_Invalid, Minor::AL_Unknown_Error); + 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_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); + addConversionElement(GlobalStatus::Code::Workflow_TrustedChannel_Ssl_Certificate_Unsupported_Algorithm_Or_Length, Minor::DP_Trusted_Channel_Establishment_Failed); + addConversionElement(GlobalStatus::Code::Workflow_TrustedChannel_ServiceUnavailable, Minor::DP_Trusted_Channel_Establishment_Failed); + addConversionElement(GlobalStatus::Code::Workflow_TrustedChannel_TimeOut, Minor::DP_Trusted_Channel_Establishment_Failed); + addConversionElement(GlobalStatus::Code::Workflow_TrustedChannel_Proxy_Error, Minor::DP_Trusted_Channel_Establishment_Failed); + addConversionElement(GlobalStatus::Code::Workflow_TrustedChannel_Server_Format_Error, Minor::DP_Trusted_Channel_Establishment_Failed); + addConversionElement(GlobalStatus::Code::Workflow_TrustedChannel_Other_Network_Error, Minor::DP_Trusted_Channel_Establishment_Failed); - addConversionElement(GlobalStatus::Code::Paos_Error_AL_Internal_Error, Minor::AL_Internal_Error); - addConversionElement(GlobalStatus::Code::Workflow_Cannot_Confirm_IdCard_Authenticity, Minor::AL_Internal_Error); - addConversionElement(GlobalStatus::Code::Workflow_Unknown_Paos_From_EidServer, Minor::AL_Internal_Error); - addConversionElement(GlobalStatus::Code::Workflow_Unexpected_Message_From_EidServer, Minor::AL_Internal_Error); - addConversionElement(GlobalStatus::Code::Card_Protocol_Error, Minor::AL_Internal_Error); + addConversionElement(GlobalStatus::Code::Workflow_No_Unique_DvCvc, ECardApiResult::Minor::IL_Signature_InvalidCertificatePath); + addConversionElement(GlobalStatus::Code::Workflow_No_Unique_AtCvc, ECardApiResult::Minor::IL_Signature_InvalidCertificatePath); + addConversionElement(GlobalStatus::Code::Workflow_Preverification_Error, ECardApiResult::Minor::IL_Signature_InvalidCertificatePath); + addConversionElement(GlobalStatus::Code::Workflow_Preverification_Developermode_Error, ECardApiResult::Minor::IL_Signature_InvalidCertificatePath); + + addConversionElement(GlobalStatus::Code::Paos_Error_SAL_Cancellation_by_User, Minor::SAL_Cancellation_by_User); + 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::Paos_Generic_Server_Error, Minor::AL_Unknown_API_Function); addConversionElement(GlobalStatus::Code::Paos_Generic_Server_Error, Minor::AL_Not_Initialized); @@ -197,30 +213,15 @@ void ECardApiResult::initConversionMaps() 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::IL_Signature_InvalidCertificatePath); 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_Error_SAL_Invalid_Key, Minor::SAL_Invalid_Key); - - addConversionElement(GlobalStatus::Code::RemoteReader_CloseCode_AbnormalClose, Minor::AL_Unknown_Error); - addConversionElement(GlobalStatus::Code::IfdConnector_InvalidRequest, Minor::AL_Unknown_Error); - addConversionElement(GlobalStatus::Code::IfdConnector_NoSupportedApiLevel, Minor::AL_Unknown_Error); - addConversionElement(GlobalStatus::Code::IfdConnector_ConnectionTimeout, Minor::AL_Unknown_Error); - addConversionElement(GlobalStatus::Code::IfdConnector_ConnectionError, Minor::AL_Unknown_Error); - addConversionElement(GlobalStatus::Code::IfdConnector_RemoteHostRefusedConnection, Minor::AL_Unknown_Error); - addConversionElement(GlobalStatus::Code::Downloader_File_Not_Found, Minor::AL_Unknown_Error); - addConversionElement(GlobalStatus::Code::Downloader_Cannot_Save_File, Minor::AL_Unknown_Error); - addConversionElement(GlobalStatus::Code::Downloader_Data_Corrupted, Minor::AL_Unknown_Error); - addConversionElement(GlobalStatus::Code::Downloader_Missing_Platform, Minor::AL_Unknown_Error); - addConversionElement(GlobalStatus::Code::Downloader_Aborted, Minor::AL_Unknown_Error); - addConversionElement(GlobalStatus::Code::Update_Execution_Failed, Minor::AL_Unknown_Error); } @@ -230,6 +231,10 @@ void ECardApiResult::addConversionElement(const GlobalStatus::Code pCode, const { cConversionMap1[pCode] = pMinor; } + else + { + Q_ASSERT(pCode == GlobalStatus::Code::Paos_Generic_Server_Error); + } if (!cConversionMap2.contains(pMinor)) { 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 4b1a1d5ef..0c376a5bf 100644 --- a/src/global/FailureCode.h +++ b/src/global/FailureCode.h @@ -26,11 +26,16 @@ class FailureCode { User_Cancelled, Card_Removed, + Parse_TcToken_Invalid_Url, + Parse_TcToken_Missing_Url, Get_TcToken_Invalid_Url, Get_TcToken_Invalid_Redirect_Url, 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, @@ -39,12 +44,47 @@ class FailureCode Certificate_Check_Failed_Hash_Mismatch, Certificate_Check_Failed_Same_Origin_Policy_Violation, Certificate_Check_Failed_Hash_Missing_In_Description, - Check_Refresh_Address_Fatal_Ssl_Error_Before_Reply, + Pre_Verification_No_Test_Environment, + Pre_Verification_Invalid_Certificate_Chain, + Pre_Verification_Invalid_Certificate_Signature, + Pre_Verification_Certificate_Expired, + Extract_Cvcs_From_Eac1_No_Unique_At, + Extract_Cvcs_From_Eac1_No_Unique_Dv, + Extract_Cvcs_From_Eac1_At_Missing, + Extract_Cvcs_From_Eac1_Dv_Missing, + Connect_Card_Connection_Failed, + Connect_Card_Eid_Inactive, + Prepace_Pace_Smart_Eid_Invalidated, + Establish_Pace_Channel_Basic_Reader_No_Pin, + Establish_Pace_Channel_Puk_Inoperative, + Establish_Pace_Channel_User_Cancelled, + Maintain_Card_Connection_Pace_Unrecoverable, + Did_Authenticate_Eac1_Card_Command_Failed, + Process_Certificates_From_Eac2_Cvc_Chain_Missing, + Did_Authenticate_Eac2_Invalid_Cvc_Chain, + Did_Authenticate_Eac2_Card_Command_Failed, + Generic_Send_Receive_Paos_Unhandled, + 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, + Generic_Send_Receive_Invalid_Ephemeral_Key_Length, + Generic_Send_Receive_Certificate_Error, + Generic_Send_Receive_Session_Resumption_Failed, + Transmit_Card_Command_Failed, + Start_Paos_Response_Missing, + Start_Paos_Response_Error, + 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_Ssl_Error_After_Reply, + Check_Refresh_Address_Fatal_Tls_Error_After_Reply, Check_Refresh_Address_Unknown_Network_Error, Check_Refresh_Address_Invalid_Http_Response, Check_Refresh_Address_Empty, @@ -53,6 +93,15 @@ class FailureCode Check_Refresh_Address_Fetch_Certificate_Error, Check_Refresh_Address_Unsupported_Certificate, Check_Refresh_Address_Hash_Missing_In_Certificate, + 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, Change_Pin_User_Cancelled, @@ -61,89 +110,58 @@ class FailureCode Change_Pin_Unexpected_Transmit_Status, Change_Pin_Card_New_Pin_Mismatch, Change_Pin_Card_User_Cancelled, - Connect_Card_Connection_Failed, - Connect_Card_Eid_Inactive, - Destroy_Pace_No_Connection_To_Destroy, - Get_SelfAuthData_Invalid_Or_Empty, + Start_Ifd_Service_Failed, + Prepare_Pace_Ifd_Unknown, + 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, - Check_Status_Unavailable, - Check_Applet_Error, - Check_Applet_Unavailable, - Start_Ifd_Service_Failed, - Process_Ifd_Messages_No_Server_Connection, - Prepare_Pace_Ifd_Unknown, - Establish_Pace_Ifd_Unknown, - Enter_Pace_Password_Ifd_User_Cancelled, - Enter_New_Pace_Pin_Ifd_User_Cancelled, - Write_History_No_Eac1, - Write_History_No_Chat, - Verify_Retry_Counter_No_Card_Connection, - Update_Retry_Counter_No_Card_Connection, - Update_Retry_Counter_Communication_Error, - Start_Paos_Response_Missing, - Start_Paos_Response_Error, - Redirect_Browser_Send_Error_Page_Failed, - Redirect_Browser_Send_Redirect_Failed, - Processing_Send_Status_Failed, - Process_Certificates_From_Eac2_Cvc_Chain_Missing, - Prepace_Pace_No_Card_Connection, - Prepace_Pace_Smart_Eid_Invalidated, - Pre_Verfication_No_Test_Environment, - Pre_Verfication_Invalid_Certificate_Chain, - Pre_Verfication_Invalid_Certificate_Signature, - Pre_Verfication_Certificate_Expired, - Parse_TcToken_Invalid_Url, - Parse_TcToken_Missing_Url, - Extract_Cvcs_From_Eac1_No_Unique_At, - Extract_Cvcs_From_Eac1_No_Unique_Dv, - Extract_Cvcs_From_Eac1_At_Missing, - Extract_Cvcs_From_Eac1_Dv_Missing, - Establish_Pace_Channel_No_Active_Pin, - Establish_Pace_Channel_Transport_Pin, - Establish_Pace_Channel_No_Card_Connection, - Establish_Pace_Channel_Basic_Reader_No_Pin, - Establish_Pace_Channel_Puk_Inoperative, - Establish_Pace_Channel_User_Cancelled, - Establish_Pace_Channel_Invalid_Card_Return_Code, - Did_Authenticate_Eac1_Card_Command_Failed, - Did_Authenticate_Eac2_Invalid_Cvc_Chain, - Did_Authenticate_Eac2_Card_Command_Failed, - Maintain_Card_Connection_Pace_Unrecoverable, - Generic_Send_Receive_Network_Error, - Generic_Provider_Communication_Network_Error, - Generic_Provider_Communication_Invalid_Ephemeral_Key_Length, - Generic_Provider_Communication_Certificate_Error, - Generic_Provider_Communication_Ssl_Error, - Generic_Send_Receive_Paos_Unhandled, - Generic_Send_Receive_Ssl_Error, - Generic_Send_Receive_Server_Error, - Generic_Send_Receive_Client_Error, - Generic_Send_Receive_Paos_Unknown, - Generic_Send_Receive_Paos_Unexpected, - Generic_Send_Receive_Invalid_Ephemeral_Key_Length, - Generic_Send_Receive_Certificate_Error, - Generic_Send_Receive_Session_Resumption_Failed, - Transmit_Card_Command_Failed, 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 53d0b6e14..624e7d557 100644 --- a/src/global/GlobalStatus.cpp +++ b/src/global/GlobalStatus.cpp @@ -28,6 +28,7 @@ bool GlobalStatus::isMessageMasked() const switch (d->mStatusCode) { case Code::Workflow_Unknown_Paos_From_EidServer: + case Code::Workflow_Start_Paos_Response_Missing: case Code::Workflow_Unexpected_Message_From_EidServer: case Code::Workflow_Preverification_Error: case Code::Workflow_No_Unique_AtCvc: @@ -36,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: @@ -130,9 +130,13 @@ QString GlobalStatus::toErrorDescriptionInternal() const return tr("The authenticity of your ID card could not be confirmed."); case Code::Workflow_Unknown_Paos_From_EidServer: - //: ERROR_MASKED ALL_PLATFORMS The type of a POAS message could not be determined. + //: ERROR_MASKED ALL_PLATFORMS The type of a PAOS message could not be determined. return tr("The program received an unknown message from the server."); + case Code::Workflow_Start_Paos_Response_Missing: + //: ERROR_MASKED ALL_PLATFORMS The PAOS message StartPaosResponse was not received. + return tr("The program did not receive a StartPaosResponse message from the server."); + case Code::Workflow_Unexpected_Message_From_EidServer: //: ERROR_MASKED ALL_PLATFORMS The server sent a valid PAOS message but its type was unexpected. return tr("The program received an unexpected message from the server."); @@ -157,9 +161,9 @@ QString GlobalStatus::toErrorDescriptionInternal() const //: ERROR ALL_PLATFORMS DidAuthenticateEAC2, AA2 or the ID card declined the certificates. return tr("Authentication failed."); - case Code::Workflow_No_Extended_Length_Error: - //: ERROR ALL_PLATFORMS DidAuthenticateEAC2 was not able to send the certificates to the card because the card reader does not support extended length. - return tr("Your card reader does not support Extended Length communication and cannot be used to read the ID card. Unfortunately, the %1 has no influence on this restriction.").arg(QCoreApplication::applicationName()); + case Code::Workflow_Wrong_Length_Error: + //: ERROR ALL_PLATFORMS A card command failed because the data length was wrong or the card reader does not support Extended Length. + return tr("The length of the data sent to the ID card was not accepted. Either the data is faulty or your card reader does not support Extended Length communication and cannot be used to read the ID card. Unfortunately, the %1 has no influence on this restriction.").arg(QCoreApplication::applicationName()); case Code::Workflow_Certificate_No_Description: //: ERROR_MASKED ALL_PLATFORMS @@ -177,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. @@ -200,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 @@ -216,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. @@ -318,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. @@ -361,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. @@ -373,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 56c9624a7..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, @@ -50,22 +52,22 @@ class GlobalStatus Workflow_Card_Removed, Workflow_Cannot_Confirm_IdCard_Authenticity, Workflow_Unknown_Paos_From_EidServer, + Workflow_Start_Paos_Response_Missing, Workflow_Unexpected_Message_From_EidServer, Workflow_Preverification_Developermode_Error, Workflow_Preverification_Error, Workflow_No_Unique_AtCvc, Workflow_No_Unique_DvCvc, Workflow_No_Permission_Error, - Workflow_No_Extended_Length_Error, + Workflow_Wrong_Length_Error, Workflow_Certificate_No_Description, 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, @@ -87,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, @@ -142,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 090a0ea04..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; @@ -284,6 +284,9 @@ QByteArray LogHandler::formatFunction(const char* const pFunction, const QByteAr { QByteArray function(pFunction); + // Remove anonymous namespace + function.replace(QByteArrayLiteral("(anonymous namespace)::"), ""); + // Remove the parameter list function = function.left(function.indexOf('(')); @@ -291,13 +294,17 @@ QByteArray LogHandler::formatFunction(const char* const pFunction, const QByteAr function.replace(QByteArrayLiteral("governikus::"), ""); // Remove the return type (if any) - if (function.indexOf(' ') != -1) + if (const auto index = function.lastIndexOf(' ') + 1; index > 0) { - function = function.mid(function.lastIndexOf(' ') + 1); + function = function.mid(index); + if (!function.isEmpty() && function.at(0) == '*') + { + function.remove(0, 1); + } } // 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()) { @@ -331,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 c87093224..4a47ea4fd 100644 --- a/src/ifd/base/ConnectRequest.cpp +++ b/src/ifd/base/ConnectRequest.cpp @@ -53,7 +53,11 @@ ConnectRequest::ConnectRequest(const IfdDescriptor& pIfdDescriptor, mSocket->setProxy(QNetworkProxy(QNetworkProxy::NoProxy)); connect(mSocket.data(), &QWebSocket::connected, this, &ConnectRequest::onConnected); +#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)) + connect(mSocket.data(), &QWebSocket::errorOccurred, this, &ConnectRequest::onError); +#else connect(mSocket.data(), QOverload::of(&QWebSocket::error), this, &ConnectRequest::onError); +#endif mTimer.setSingleShot(true); mTimer.setInterval(pTimeoutMs); @@ -156,7 +160,8 @@ void ConnectRequest::onError(QAbstractSocket::SocketError pError) qCWarning(ifd) << "Connection error:" << pError; mTimer.stop(); - if (pError == QAbstractSocket::SocketError::RemoteHostClosedError) + if (pError == QAbstractSocket::SocketError::RemoteHostClosedError + || pError == QAbstractSocket::SocketError::SslHandshakeFailedError) { Q_EMIT fireConnectionError(mIfdDescriptor, IfdErrorCode::REMOTE_HOST_REFUSED_CONNECTION); } @@ -173,7 +178,7 @@ void ConnectRequest::onTimeout() } -void ConnectRequest::onPreSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator* pAuthenticator) +void ConnectRequest::onPreSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator* pAuthenticator) const { qCDebug(ifd) << "Request pairing..."; pAuthenticator->setPreSharedKey(mPsk); @@ -210,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/DataChannel.h b/src/ifd/base/DataChannel.h index 6ed4d37ac..39c91302d 100644 --- a/src/ifd/base/DataChannel.h +++ b/src/ifd/base/DataChannel.h @@ -27,6 +27,7 @@ class DataChannel Q_INVOKABLE virtual void send(const QByteArray& pDataBlock) = 0; Q_INVOKABLE virtual void close() = 0; + [[nodiscard]] virtual bool isPairingConnection() const = 0; [[nodiscard]] virtual const QString& getId() const = 0; Q_SIGNALS: 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/IfdDescriptor.cpp b/src/ifd/base/IfdDescriptor.cpp index dc1e76226..9ecc362d1 100644 --- a/src/ifd/base/IfdDescriptor.cpp +++ b/src/ifd/base/IfdDescriptor.cpp @@ -38,11 +38,13 @@ QUrl urlFromMsgAndHost(const Discovery& pDiscovery, IfdDescriptor::IfdDescriptorData::IfdDescriptorData(const QString& pIfdName, const QString& pIfdId, const QVector& pApiVersions, + const bool pIsPairingAnnounced, const QUrl& pRemoteUrl, bool pIsLocalIfd) : mIfdName(pIfdName) , mIfdId(pIfdId) , mApiVersions(pApiVersions) + , mIsPairingAnnounced(pIsPairingAnnounced) , mUrl(pRemoteUrl) , mIsLocalIfd(pIsLocalIfd) { @@ -57,6 +59,7 @@ bool IfdDescriptor::IfdDescriptorData::operator==(const IfdDescriptorData& pOthe return mIfdName == pOther.mIfdName && mIfdId == pOther.mIfdId && mApiVersions == pOther.mApiVersions && + mIsPairingAnnounced == pOther.mIsPairingAnnounced && mUrl == pOther.mUrl; } @@ -79,7 +82,8 @@ IfdDescriptor::IfdDescriptor(const Discovery& pDiscovery, const QHostAddress& pH const QString& ifdName = pDiscovery.getIfdName(); const QString& ifdId = pDiscovery.getIfdId(); const QVector& supportedApis = pDiscovery.getSupportedApis(); - d = new IfdDescriptorData(ifdName, ifdId, supportedApis, url, pLocalIfd); + const bool isPairing = pDiscovery.getPairing(); + d = new IfdDescriptorData(ifdName, ifdId, supportedApis, isPairing, url, pLocalIfd); } @@ -113,6 +117,12 @@ bool IfdDescriptor::isSupported() const } +bool IfdDescriptor::isPairingAnnounced() const +{ + return !isNull() && d->mIsPairingAnnounced; +} + + const QUrl& IfdDescriptor::getUrl() const { static const QUrl EMPTY_URL; diff --git a/src/ifd/base/IfdDescriptor.h b/src/ifd/base/IfdDescriptor.h index db9129310..9020c50d1 100644 --- a/src/ifd/base/IfdDescriptor.h +++ b/src/ifd/base/IfdDescriptor.h @@ -30,6 +30,7 @@ class IfdDescriptor IfdDescriptorData(const QString& pIfdName, const QString& pIfdId, const QVector& pApiVersions, + const bool pIsPairingAnnounced, const QUrl& pUrl, bool pIsLocalIfd); @@ -38,6 +39,7 @@ class IfdDescriptor const QString mIfdName; const QString mIfdId; const QVector mApiVersions; + const bool mIsPairingAnnounced; const QUrl mUrl; const bool mIsLocalIfd; @@ -57,6 +59,7 @@ class IfdDescriptor [[nodiscard]] const QString& getIfdId() const; [[nodiscard]] const QVector& getApiVersions() const; [[nodiscard]] bool isSupported() const; + [[nodiscard]] bool isPairingAnnounced() const; [[nodiscard]] const QUrl& getUrl() const; [[nodiscard]] bool isNull() const; [[nodiscard]] bool isLocalIfd() const; diff --git a/src/ifd/base/IfdDispatcher.cpp b/src/ifd/base/IfdDispatcher.cpp index f76821450..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" @@ -89,6 +88,17 @@ void IfdDispatcher::setVersion(IfdVersion::Version pVersion) } +bool IfdDispatcher::isPairingConnection() const +{ + if (!mDataChannel) + { + return false; + } + + return mDataChannel->isPairingConnection(); +} + + QString IfdDispatcher::getId() const { if (!mDataChannel) @@ -112,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 cf195160e..40dfda30d 100644 --- a/src/ifd/base/IfdDispatcher.h +++ b/src/ifd/base/IfdDispatcher.h @@ -46,10 +46,11 @@ class IfdDispatcher explicit IfdDispatcher(IfdVersion::Version pVersion, const QSharedPointer& pDataChannel); ~IfdDispatcher() override; + [[nodiscard]] virtual bool isPairingConnection() const; [[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 6f1a77690..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,62 +68,87 @@ 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); - if (isInitialPairing(pIfdName, pId)) - { - QMetaObject::invokeMethod(dispatcher.data(), &IfdDispatcher::close, Qt::QueuedConnection); - } - else + + if (getInfo().getPlugInType() == ReaderManagerPlugInType::REMOTE_IFD) { - QMetaObject::invokeMethod(dispatcher.data(), [dispatcher] { - const QSharedPointer& ifdGetStatus = QSharedPointer::create(); - dispatcher->send(ifdGetStatus); - }, Qt::QueuedConnection); + dispatcher->saveRemoteNameInSettings(pIfdName); + if (dispatcher->isPairingConnection()) + { + QMetaObject::invokeMethod(dispatcher.data(), &IfdDispatcher::close, Qt::QueuedConnection); + return; + } } + + QMetaObject::invokeMethod(dispatcher.data(), [dispatcher] { + const QSharedPointer& ifdGetStatus = QSharedPointer::create(); + dispatcher->send(ifdGetStatus); + }, Qt::QueuedConnection); } @@ -190,6 +220,8 @@ IfdReaderManagerPlugIn::~IfdReaderManagerPlugIn() void IfdReaderManagerPlugIn::init() { + ReaderManagerPlugIn::init(); + const auto ifdClient = getIfdClient(); connect(ifdClient, &IfdClient::fireNewDispatcher, this, &IfdReaderManagerPlugIn::addDispatcher); } @@ -197,7 +229,9 @@ void IfdReaderManagerPlugIn::init() QList IfdReaderManagerPlugIn::getReaders() const { - return mReaderList.values(); + auto readerList = mReaderList.values(); + readerList.removeAll(nullptr); + return readerList; } @@ -218,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 97774b0eb..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" @@ -13,6 +12,10 @@ #include #include + +class test_RemoteIfdReaderManagerPlugIn; + + namespace governikus { @@ -21,6 +24,7 @@ class IfdReaderManagerPlugIn : public ReaderManagerPlugIn { Q_OBJECT + friend class ::test_RemoteIfdReaderManagerPlugIn; private: QMultiMap mReadersForDispatcher; @@ -30,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); @@ -40,7 +44,6 @@ class IfdReaderManagerPlugIn void removeDispatcher(const QString& pId); [[nodiscard]] const QMap>& getDispatchers() const; - virtual bool isInitialPairing(const QString& pIfdName, const QString& pId) = 0; virtual IfdClient* getIfdClient() = 0; public: 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 c736f9402..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 @@ -45,7 +46,8 @@ class IfdServer void firePskChanged(const QByteArray& pPsk); void fireConnectedChanged(bool pConnected); void fireIsRunningChanged(); - void firePairingCompleted(); + void firePairingCompleted(const QSslCertificate& pCertificate); + void fireSocketError(QAbstractSocket::SocketError pSocketError); }; } // namespace governikus diff --git a/src/ifd/base/ServerMessageHandler.h b/src/ifd/base/ServerMessageHandler.h index f08fd50a4..26b3c701f 100644 --- a/src/ifd/base/ServerMessageHandler.h +++ b/src/ifd/base/ServerMessageHandler.h @@ -35,9 +35,11 @@ class ServerMessageHandler virtual void sendEstablishPaceChannelResponse(const QString& pSlotHandle, const EstablishPaceChannelOutput&) = 0; virtual void sendModifyPinResponse(const QString& pSlotHandle, const ResponseApdu& pResponseApdu) = 0; + virtual void setAllowedCardTypes(const QVector& pAllowedCardTypes) = 0; Q_SIGNALS: void fireCardConnected(const QSharedPointer& pConnection); + void fireDisplayTextChanged(const QString& pDisplayText); void fireEstablishPaceChannel(const QSharedPointer& pMessage, const QSharedPointer& pConnection); void fireModifyPin(const QSharedPointer& pMessage, const QSharedPointer& pConnection); void fireCardDisconnected(const QSharedPointer& pConnection); diff --git a/src/ifd/base/ServerMessageHandlerImpl.cpp b/src/ifd/base/ServerMessageHandlerImpl.cpp index 077963138..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" @@ -40,10 +39,12 @@ template<> ServerMessageHandler* createNewObject& pDataChannel, const QVector& pAllowedPlugInTypes) +ServerMessageHandlerImpl::ServerMessageHandlerImpl(const QSharedPointer& pDataChannel, + const QVector& pAllowedTypes) : ServerMessageHandler() , mDispatcher(Env::create(pDataChannel), &QObject::deleteLater) - , mAllowedPlugInTypes(pAllowedPlugInTypes) + , mAllowedPlugInTypes(pAllowedTypes) + , mAllowedCardTypes(pAllowedTypes) , mCardConnections() { connect(mDispatcher.data(), &IfdDispatcherServer::fireReceived, this, &ServerMessageHandlerImpl::onMessage); @@ -76,8 +77,7 @@ void ServerMessageHandlerImpl::handleIfdGetStatus(const QJsonObject& pJsonObject return; } - const auto& ifdStatusMsg = QSharedPointer::create(readerInfo); - mDispatcher->send(ifdStatusMsg); + sendIfdStatus(readerInfo); return; } @@ -94,8 +94,7 @@ void ServerMessageHandlerImpl::handleIfdGetStatus(const QJsonObject& pJsonObject continue; } - const auto& ifdStatusMsg = QSharedPointer::create(readerInfo); - mDispatcher->send(ifdStatusMsg); + sendIfdStatus(readerInfo); } } @@ -216,6 +215,7 @@ void ServerMessageHandlerImpl::handleIfdTransmit(const QJsonObject& pJsonObject) if (!progressMessage.isNull()) { cardConnection->setProgressMessage(progressMessage); + Q_EMIT fireDisplayTextChanged(progressMessage); } qCDebug(ifd) << "Transmit card APDU for" << slotHandle; @@ -299,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); @@ -337,6 +347,21 @@ void ServerMessageHandlerImpl::sendModifyPinResponse(const QString& pSlotHandle, } +void ServerMessageHandlerImpl::setAllowedCardTypes(const QVector& pAllowedCardTypes) +{ + if (mAllowedCardTypes != pAllowedCardTypes) + { + mAllowedCardTypes = pAllowedCardTypes; + + const auto& readerInfos = Env::getSingleton()->getReaderInfos(ReaderFilter(mAllowedPlugInTypes)); + for (const auto& readerInfo : readerInfos) + { + sendIfdStatus(readerInfo); + } + } +} + + void ServerMessageHandlerImpl::onTransmitCardCommandDone(QSharedPointer pCommand) { auto transmitCommand = pCommand.staticCast(); @@ -444,7 +469,7 @@ void ServerMessageHandlerImpl::onReaderChanged(const ReaderInfo& pInfo) } } - mDispatcher->send(QSharedPointer::create(pInfo)); + sendIfdStatus(pInfo); } @@ -455,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 b6f21a250..a229df68f 100644 --- a/src/ifd/base/ServerMessageHandlerImpl.h +++ b/src/ifd/base/ServerMessageHandlerImpl.h @@ -33,6 +33,7 @@ class ServerMessageHandlerImpl private: const QSharedPointer mDispatcher; QVector mAllowedPlugInTypes; + QVector mAllowedCardTypes; QMap> mCardConnections; [[nodiscard]] QString slotHandleForReaderName(const QString& pReaderName) const; @@ -43,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); @@ -54,10 +56,11 @@ class ServerMessageHandlerImpl public: explicit ServerMessageHandlerImpl(const QSharedPointer& pDataChannel, - const QVector& pAllowedPlugInTypes = Enum::getList()); + const QVector& pAllowedTypes = Enum::getList()); void sendEstablishPaceChannelResponse(const QString& pSlotHandle, const EstablishPaceChannelOutput& pChannelOutput) override; void sendModifyPinResponse(const QString& pSlotHandle, const ResponseApdu& pResponseApdu) override; + void setAllowedCardTypes(const QVector& pAllowedCardTypes) override; }; diff --git a/src/ifd/base/TlsServer.cpp b/src/ifd/base/TlsServer.cpp index b369c115e..204f1d968 100644 --- a/src/ifd/base/TlsServer.cpp +++ b/src/ifd/base/TlsServer.cpp @@ -48,6 +48,12 @@ void TlsServer::stopListening() } +bool TlsServer::hasPsk() const +{ + return !mPsk.isEmpty(); +} + + void TlsServer::incomingConnection(qintptr pSocketDescriptor) { if (mSocket.isNull()) @@ -85,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); @@ -96,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 4df443c36..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(); @@ -44,10 +47,12 @@ class TlsServer void setPsk(const QByteArray& pPsk); void stopListening(); virtual bool startListening(quint16 pPort) = 0; + [[nodiscard]] bool hasPsk() const; Q_SIGNALS: void fireNewConnection(QTcpSocket* pSocket); void firePskChanged(const QByteArray& pPsk); + void fireSocketError(QAbstractSocket::SocketError pSocketError); }; } // namespace governikus diff --git a/src/ifd/base/WebSocketChannel.cpp b/src/ifd/base/WebSocketChannel.cpp index 855d29832..35c209222 100644 --- a/src/ifd/base/WebSocketChannel.cpp +++ b/src/ifd/base/WebSocketChannel.cpp @@ -5,6 +5,7 @@ #include "WebSocketChannel.h" #include "RemoteServiceSettings.h" +#include "SecureStorage.h" #include #include @@ -94,6 +95,13 @@ void WebSocketChannel::close() } +bool WebSocketChannel::isPairingConnection() const +{ + const auto& pairingCiphers = Env::getSingleton()->getTlsConfigRemoteIfd(SecureStorage::TlsSuite::PSK).getCiphers(); + return pairingCiphers.contains(mConnection->sslConfiguration().sessionCipher()); +} + + const QString& WebSocketChannel::getId() const { return mId; diff --git a/src/ifd/base/WebSocketChannel.h b/src/ifd/base/WebSocketChannel.h index 40214b8cb..8ae639994 100644 --- a/src/ifd/base/WebSocketChannel.h +++ b/src/ifd/base/WebSocketChannel.h @@ -35,6 +35,7 @@ class WebSocketChannel void send(const QByteArray& pDataBlock) override; void close() override; + [[nodiscard]] bool isPairingConnection() const override; [[nodiscard]] const QString& getId() const override; private Q_SLOTS: 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 6b33e1e3c..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 @@ -81,17 +82,28 @@ void IfdStatus::parsePinPad(const QJsonObject& pMessageObject) } -IfdStatus::IfdStatus(const ReaderInfo& pReaderInfo) +IfdStatus::IfdStatus(const ReaderInfo& pReaderInfo, bool pPublishCard) : IfdMessage(IfdMessageType::IFDStatus) , mSlotName(pReaderInfo.getName()) , mHasPinPad(!pReaderInfo.isBasicReader()) , mMaxApduLength(pReaderInfo.getMaxApduLength()) , mConnectedReader(pReaderInfo.isValid()) - , mCardAvailable(pReaderInfo.hasCard()) + , 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/base/messages/IfdStatus.h b/src/ifd/base/messages/IfdStatus.h index 885db639c..0acdfdc03 100644 --- a/src/ifd/base/messages/IfdStatus.h +++ b/src/ifd/base/messages/IfdStatus.h @@ -33,7 +33,7 @@ class IfdStatus void parsePinPad(const QJsonObject& pMessageObject); public: - explicit IfdStatus(const ReaderInfo& pReaderInfo); + explicit IfdStatus(const ReaderInfo& pReaderInfo, bool pPublishCard = true); explicit IfdStatus(const QJsonObject& pMessageObject); ~IfdStatus() override = default; 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 3a43d5f3f..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,15 +97,7 @@ void LocalIfdReaderManagerPlugIn::onLocalIfdConnectionClosed(GlobalStatus::Code } -bool LocalIfdReaderManagerPlugIn::isInitialPairing(const QString& pIfdName, const QString& pId) -{ - Q_UNUSED(pIfdName) - Q_UNUSED(pId) - return false; -} - - -bool LocalIfdReaderManagerPlugIn::isAusweisApp2Installed() +bool LocalIfdReaderManagerPlugIn::isAusweisAppInstalled() { if (mServiceConnected) { @@ -121,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; } @@ -130,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; } @@ -141,7 +133,7 @@ bool LocalIfdReaderManagerPlugIn::isAusweisApp2Installed() }); if (!hasValidCertificate) { - qCWarning(ifd) << "Invalid AusweisApp2 certificate"; + qCWarning(ifd) << "Invalid AusweisApp certificate"; setState(LocalIfdState::INVALID_CERTIFICATE); return false; } @@ -164,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 ea816126b..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" @@ -36,7 +35,6 @@ class LocalIfdReaderManagerPlugIn void stopScan(const QString& pError = QString()) override; protected: - bool isInitialPairing(const QString& pIfdName, const QString& pId) override; LocalIfdClient* getIfdClient() override; void addDispatcher(const QSharedPointer& pDispatcher) override; @@ -45,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 837ae7355..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); } @@ -40,29 +39,53 @@ void RemoteIfdReaderManagerPlugIn::continueConnectToPairedReaders(const QVector< const RemoteServiceSettings& remoteServiceSettings = Env::getSingleton()->getRemoteServiceSettings(); for (const QSharedPointer& remoteDevice : pRemoteDevices) { - if (!remoteDevice->getIfdDescriptor().isSupported()) + const auto& ifdDescriptor = remoteDevice->getIfdDescriptor(); + if (!ifdDescriptor.isSupported() || ifdDescriptor.isPairingAnnounced()) { continue; } - const QString ifdId = remoteDevice->getIfdDescriptor().getIfdId(); + const QString ifdId = ifdDescriptor.getIfdId(); // 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); + } } @@ -70,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); @@ -106,19 +129,3 @@ IfdClient* RemoteIfdReaderManagerPlugIn::getIfdClient() { return Env::getSingleton(); } - - -bool RemoteIfdReaderManagerPlugIn::isInitialPairing(const QString& pIfdName, const QString& pId) -{ - RemoteServiceSettings& settings = Env::getSingleton()->getRemoteServiceSettings(); - auto info = settings.getRemoteInfo(pId); - bool initialPairing = false; - if (info.getNameEscaped().isEmpty()) - { - initialPairing = true; - } - info.setNameUnescaped(pIfdName); - settings.updateRemoteInfo(info); - - return initialPairing; -} diff --git a/src/ifd/remote/RemoteIfdReaderManagerPlugIn.h b/src/ifd/remote/RemoteIfdReaderManagerPlugIn.h index 68bbb35bc..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(); @@ -40,7 +47,6 @@ class RemoteIfdReaderManagerPlugIn void stopScan(const QString& pError = QString()) override; protected: - bool isInitialPairing(const QString& pIfdName, const QString& pId) override; IfdClient* getIfdClient() override; }; diff --git a/src/ifd/remote/RemoteIfdServer.cpp b/src/ifd/remote/RemoteIfdServer.cpp index 16c81a0bb..3abed53d8 100644 --- a/src/ifd/remote/RemoteIfdServer.cpp +++ b/src/ifd/remote/RemoteIfdServer.cpp @@ -32,7 +32,8 @@ void RemoteIfdServer::onConnectedChanged(bool pConnected) const auto& remoteServiceSettings = Env::getSingleton()->getRemoteServiceSettings(); const auto& ifdId = QString::fromLatin1(remoteServiceSettings.getCertificate().toPem()); quint16 port = mWebSocketServer->getServerPort(); - mRemoteReaderAdvertiser.reset(Env::create(ifdName, ifdId, port)); + bool isPairing = mWebSocketServer->isPairingAnnounced(); + mRemoteReaderAdvertiser.reset(Env::create(ifdName, ifdId, port, isPairing)); } Q_EMIT fireConnectedChanged(pConnected); @@ -48,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/RemoteReaderAdvertiser.cpp b/src/ifd/remote/RemoteReaderAdvertiser.cpp index d49fa85e7..91e8ecd19 100644 --- a/src/ifd/remote/RemoteReaderAdvertiser.cpp +++ b/src/ifd/remote/RemoteReaderAdvertiser.cpp @@ -18,9 +18,9 @@ Q_DECLARE_LOGGING_CATEGORY(ifd) namespace governikus { -template<> RemoteReaderAdvertiser* createNewObject(const QString& pIfdName, const QString& pIfdId, quint16& pPort) +template<> RemoteReaderAdvertiser* createNewObject(const QString& pIfdName, const QString& pIfdId, quint16& pPort, bool& pIsPairing) { - return new RemoteReaderAdvertiserImpl(pIfdName, pIfdId, pPort); + return new RemoteReaderAdvertiserImpl(pIfdName, pIfdId, pPort, pIsPairing); } @@ -51,7 +51,7 @@ RemoteReaderAdvertiserImpl::~RemoteReaderAdvertiserImpl() } -RemoteReaderAdvertiserImpl::RemoteReaderAdvertiserImpl(const QString& pIfdName, const QString& pIfdId, quint16 pPort, int pTimerInterval, bool pPairing) +RemoteReaderAdvertiserImpl::RemoteReaderAdvertiserImpl(const QString& pIfdName, const QString& pIfdId, quint16 pPort, bool pPairing, int pTimerInterval) : RemoteReaderAdvertiser() , mHandler(Env::create(false)) , mTimerId(startTimer(pTimerInterval)) diff --git a/src/ifd/remote/RemoteReaderAdvertiser.h b/src/ifd/remote/RemoteReaderAdvertiser.h index bd7134077..1c5dd0e03 100644 --- a/src/ifd/remote/RemoteReaderAdvertiser.h +++ b/src/ifd/remote/RemoteReaderAdvertiser.h @@ -53,7 +53,7 @@ class RemoteReaderAdvertiserImpl public: ~RemoteReaderAdvertiserImpl() override; - RemoteReaderAdvertiserImpl(const QString& pIfdName, const QString& pIfdId, quint16 pPort, int pTimerInterval = 1000, bool pPairing = false); + RemoteReaderAdvertiserImpl(const QString& pIfdName, const QString& pIfdId, quint16 pPort, bool pPairing = false, int pTimerInterval = 1000); void setPairing(bool pEnabled) override; }; diff --git a/src/ifd/remote/RemoteTlsServer.cpp b/src/ifd/remote/RemoteTlsServer.cpp index 9ce2daac6..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; } @@ -110,10 +113,11 @@ void RemoteTlsServer::onEncrypted() const auto& pairingCiphers = Env::getSingleton()->getTlsConfigRemoteIfd(SecureStorage::TlsSuite::PSK).getCiphers(); if (pairingCiphers.contains(cfg.sessionCipher())) { - qCDebug(ifd) << "Pairing completed | Add certificate:" << cfg.peerCertificate(); - settings.addTrustedCertificate(cfg.peerCertificate()); + const auto& sslCertificate = cfg.peerCertificate(); + qCDebug(ifd) << "Pairing completed | Add certificate:" << sslCertificate; + settings.addTrustedCertificate(sslCertificate); setPairing(false); - Q_EMIT firePairingCompleted(); + Q_EMIT firePairingCompleted(sslCertificate); } else { @@ -122,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()); } @@ -145,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/RemoteTlsServer.h b/src/ifd/remote/RemoteTlsServer.h index 39fc7a10f..648b5574d 100644 --- a/src/ifd/remote/RemoteTlsServer.h +++ b/src/ifd/remote/RemoteTlsServer.h @@ -32,7 +32,7 @@ class RemoteTlsServer void onSslErrors(const QList& pErrors) override; Q_SIGNALS: - void firePairingCompleted(); + void firePairingCompleted(const QSslCertificate& pCertificate); }; } // namespace governikus diff --git a/src/ifd/remote/RemoteWebSocketServer.h b/src/ifd/remote/RemoteWebSocketServer.h index 91a614bd2..938f3c5aa 100644 --- a/src/ifd/remote/RemoteWebSocketServer.h +++ b/src/ifd/remote/RemoteWebSocketServer.h @@ -22,11 +22,12 @@ class RemoteWebSocketServer ~RemoteWebSocketServer() override; [[nodiscard]] virtual bool isPairingConnection() const = 0; + [[nodiscard]] virtual bool isPairingAnnounced() const = 0; virtual void setPairing(bool pEnable = true) = 0; [[nodiscard]] virtual QSslCertificate getCurrentCertificate() const = 0; Q_SIGNALS: - void firePairingCompleted(); + void firePairingCompleted(const QSslCertificate& pCertificate); }; diff --git a/src/ifd/remote/RemoteWebSocketServerImpl.cpp b/src/ifd/remote/RemoteWebSocketServerImpl.cpp index da8b91309..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); @@ -103,6 +103,12 @@ bool RemoteWebSocketServerImpl::isPairingConnection() const } +bool RemoteWebSocketServerImpl::isPairingAnnounced() const +{ + return mRemoteTlsServer->hasPsk(); +} + + void RemoteWebSocketServerImpl::setPairing(bool pEnable) { mRemoteTlsServer->setPairing(pEnable); diff --git a/src/ifd/remote/RemoteWebSocketServerImpl.h b/src/ifd/remote/RemoteWebSocketServerImpl.h index 6089f00fe..ba7d8bf4a 100644 --- a/src/ifd/remote/RemoteWebSocketServerImpl.h +++ b/src/ifd/remote/RemoteWebSocketServerImpl.h @@ -45,6 +45,7 @@ class RemoteWebSocketServerImpl const QSharedPointer& getMessageHandler() const override; [[nodiscard]] bool isPairingConnection() const override; + [[nodiscard]] bool isPairingAnnounced() const override; void setPairing(bool pEnable = true) override; [[nodiscard]] QSslCertificate getCurrentCertificate() const override; }; diff --git a/src/init/Bootstrap.cpp b/src/init/Bootstrap.cpp index 21cb7d969..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); @@ -76,16 +76,13 @@ static inline void printInfo() { qCDebug(init) << "Library path:" << path; } + + qCDebug(init) << "TLS backends:" << QSslSocket::availableBackends() << "| using:" << QSslSocket::activeBackend(); } 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)); @@ -134,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)) @@ -150,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)); @@ -160,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]{ @@ -181,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/DatagramHandlerImpl.cpp b/src/network/DatagramHandlerImpl.cpp index bd241e7b8..5d7cd7500 100644 --- a/src/network/DatagramHandlerImpl.cpp +++ b/src/network/DatagramHandlerImpl.cpp @@ -238,17 +238,18 @@ void DatagramHandlerImpl::sendToAllAddressEntries(const QByteArray& pData, quint for (const QHostAddress& broadcastAddr : std::as_const(broadcastAddresses)) { - const auto alreadyFailed = mFailedAddresses.contains(broadcastAddr); + const auto& addrString = broadcastAddr.toString(); // QTBUG-112528 + const auto alreadyFailed = mFailedAddresses.contains(addrString); const auto sendSuccess = sendToAddress(pData, broadcastAddr, pPort, !alreadyFailed); if (sendSuccess && alreadyFailed) { - mFailedAddresses.removeAll(broadcastAddr); + mFailedAddresses.removeAll(addrString); } else if (!sendSuccess && !alreadyFailed) { qCDebug(network) << "Broadcasting to" << broadcastAddr << "failed"; - mFailedAddresses << broadcastAddr; + mFailedAddresses << addrString; } } } diff --git a/src/network/DatagramHandlerImpl.h b/src/network/DatagramHandlerImpl.h index c51c8c0b6..f533ee9aa 100644 --- a/src/network/DatagramHandlerImpl.h +++ b/src/network/DatagramHandlerImpl.h @@ -32,7 +32,7 @@ class DatagramHandlerImpl QScopedPointer mSocket; QScopedPointer mMulticastLock; QList mAllAddresses; - QVector mFailedAddresses; + QStringList mFailedAddresses; quint16 mUsedPort; PortFile mPortFile; bool mEnableListening; diff --git a/src/network/HttpHandler.cpp b/src/network/HttpHandler.cpp index f6a749df6..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; } @@ -110,7 +110,6 @@ void HttpHandler::handleImageRequest(const QSharedPointer& pRequest { qCCritical(network) << "Unknown image file requested" << pImagePath; response.setStatus(HTTP_STATUS_NOT_FOUND); - response.setBody(QByteArrayLiteral("Not found"), QByteArrayLiteral("text/plain; charset=utf-8")); } pRequest->send(response); diff --git a/src/network/HttpRequest.cpp b/src/network/HttpRequest.cpp index bc62d74c8..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(); @@ -58,9 +56,13 @@ QTcpSocket* HttpRequest::take() HttpRequest::~HttpRequest() { - if (mSocket && mSocket->state() == QAbstractSocket::ConnectedState) + if (mSocket && mSocket->bytesToWrite() && mSocket->state() == QAbstractSocket::ConnectedState && !mSocket->flush()) { - mSocket->flush(); + qCDebug(network) << "Flush socket failed. Waiting for bytes:" << mSocket->bytesToWrite(); + if (!mSocket->waitForBytesWritten()) + { + qCWarning(network) << "Cannot wait for socket anymore... abort!"; + } } } 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 369fc8bf2..9af2abe41 100644 --- a/src/network/NetworkManager.cpp +++ b/src/network/NetworkManager.cpp @@ -5,11 +5,8 @@ #include "NetworkManager.h" #include "AppSettings.h" -#include "NetworkReplyError.h" -#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) - #include "NetworkReplyTimeout.h" -#endif #include "LogHandler.h" +#include "NetworkReplyError.h" #include "SecureStorage.h" #include "TlsChecker.h" #include "VersionInfo.h" @@ -193,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; } @@ -210,7 +208,7 @@ void NetworkManager::onShutdown() } -void NetworkManager::onProxyChanged() +void NetworkManager::onProxyChanged() const { setApplicationProxyFactory(); } @@ -219,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: @@ -256,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}; @@ -300,7 +325,7 @@ GlobalStatus NetworkManager::toStatus(const QSharedPointer& } -bool NetworkManager::prepareConnection(QNetworkRequest& pRequest) +bool NetworkManager::prepareConnection(QNetworkRequest& pRequest) const { if (mApplicationExitInProgress) { @@ -310,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()) @@ -335,10 +360,6 @@ QSharedPointer NetworkManager::trackConnection(QNetworkReply* pRe --mOpenConnectionCount; }); connect(this, &NetworkManager::fireShutdown, pResponse, &QNetworkReply::abort, Qt::QueuedConnection); - -#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) - NetworkReplyTimeout::setTimeout(this, pResponse, 30000); -#endif } return QSharedPointer(pResponse, &QObject::deleteLater); @@ -428,12 +449,6 @@ class SystemProxyFactory : public QNetworkProxyFactory { public: - SystemProxyFactory() - : QNetworkProxyFactory() - { - } - - QList queryProxy(const QNetworkProxyQuery& pInputQuery = QNetworkProxyQuery()) override { qCDebug(network) << pInputQuery; @@ -449,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/NetworkReplyTimeout.cpp b/src/network/NetworkReplyTimeout.cpp deleted file mode 100644 index 14acf8d46..000000000 --- a/src/network/NetworkReplyTimeout.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright (c) 2014-2023 Governikus GmbH & Co. KG, Germany - */ - -#include "NetworkReplyTimeout.h" - -#include - -using namespace governikus; - -NetworkReplyTimeout::NetworkReplyTimeout(QNetworkReply* pReply, const int pTimeout) - : QObject(pReply) -{ - Q_ASSERT(pReply); - if (pReply == nullptr) - { - return; - } - - connect(&mTimer, &QTimer::timeout, this, &NetworkReplyTimeout::onTimeout); - mTimer.setSingleShot(true); - mTimer.setInterval(pTimeout); - mTimer.start(); -} - - -void NetworkReplyTimeout::onTimeout() -{ - auto* reply = static_cast(parent()); - if (reply != nullptr && reply->isRunning()) - { - reply->abort(); - } -} - - -void NetworkReplyTimeout::onShutdown() -{ - mTimer.stop(); - onTimeout(); -} - - -void NetworkReplyTimeout::setTimeout(const NetworkManager* pManager, QNetworkReply* pReply, const int pTimeout) -{ - // since the QNetworkReply is set as parent, we don't need to care about destruction - const auto* timeout = new NetworkReplyTimeout(pReply, pTimeout); - connect(pManager, &NetworkManager::fireShutdown, timeout, &NetworkReplyTimeout::onShutdown); -} diff --git a/src/network/NetworkReplyTimeout.h b/src/network/NetworkReplyTimeout.h deleted file mode 100644 index 729e46d15..000000000 --- a/src/network/NetworkReplyTimeout.h +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (c) 2014-2023 Governikus GmbH & Co. KG, Germany - */ - -/*! - * \brief Utility class to set a timeout on a QNetworkReply - */ - -#pragma once - -#include "NetworkManager.h" - -#include -#include - -namespace governikus -{ - -class NetworkReplyTimeout - : public QObject -{ - Q_OBJECT - - private: - QTimer mTimer; - - NetworkReplyTimeout(QNetworkReply* pReply, const int pTimeout); - - private Q_SLOTS: - void onTimeout(); - void onShutdown(); - - public: - /*! - * Set the timeout in milli-seconds on the specified QNetworkReply. - */ - static void setTimeout(const NetworkManager* pManager, QNetworkReply* pReply, const int pTimeoutMilliSeconds); -}; - -} // namespace governikus 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 eab8254ac..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)) @@ -25,14 +25,16 @@ void Service::doAppUpdate(UpdateType pType, bool pForceUpdate) { case UpdateType::APPCAST: mExplicitSuccessMessage = pForceUpdate; -#if defined(Q_OS_WIN) || defined(Q_OS_MACOS) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) - mTimer.start(mOneDayInMs); - if (pForceUpdate || Env::getSingleton()->getGeneralSettings().isAutoUpdateCheck()) + if (Env::getSingleton()->getGeneralSettings().isAutoUpdateAvailable()) { - Q_UNUSED(Env::getSingleton()->checkAppUpdate(pForceUpdate)) - break; + mTimer.start(mOneDayInMs); + if (pForceUpdate || Env::getSingleton()->getGeneralSettings().isAutoUpdateCheck()) + { + Q_UNUSED(Env::getSingleton()->checkAppUpdate(pForceUpdate)) + break; + } } -#endif + Q_FALLTHROUGH(); case UpdateType::PROVIDER: 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..5a1576b3a 100644 --- a/src/settings/AbstractSettings.cpp +++ b/src/settings/AbstractSettings.cpp @@ -39,10 +39,18 @@ 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); +#if defined(Q_OS_IOS) || defined(Q_OS_MACOS) + const auto& organization = QCoreApplication::organizationDomain(); + +#else + const auto& organization = QCoreApplication::organizationName(); + +#endif + + return pFilename.isEmpty() ? QSharedPointer::create(organization, 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 4e5cbc7bd..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()); @@ -447,7 +455,7 @@ void GeneralSettings::setLastReaderPluginType(const QString& pLastReaderPluginTy bool GeneralSettings::isAutoUpdateAvailable() const { -#if !defined(QT_NO_DEBUG) || defined(Q_OS_WIN) || defined(Q_OS_MACOS) +#if !defined(QT_NO_DEBUG) || defined(Q_OS_WIN) return true; #else @@ -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 a105833bf..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; @@ -29,6 +24,7 @@ namespace SETTINGS_NAME(SETTINGS_GROUP_NAME_REMOTEREADER, "remotereader") SETTINGS_NAME(SETTINGS_NAME_DEVICE_NAME, "serverName") SETTINGS_NAME(SETTINGS_NAME_PIN_PAD_MODE, "pinPadMode") +SETTINGS_NAME(SETTINGS_NAME_SHOW_ACCESS_RIGHTS, "showAccessRights") SETTINGS_NAME(SETTINGS_ARRAY_NAME_TRUSTED_CERTIFICATES, "trustedCertificates") SETTINGS_NAME(SETTINGS_NAME_TRUSTED_CERTIFICATE_ITEM, "certificate") SETTINGS_NAME(SETTINGS_NAME_TRUSTED_REMOTE_INFO, "trustedRemoteInfo") @@ -84,7 +80,7 @@ void RemoteServiceSettings::setServerName(const QString& pName) bool RemoteServiceSettings::getPinPadMode() const { - return mStore->value(SETTINGS_NAME_PIN_PAD_MODE(), false).toBool(); + return mStore->value(SETTINGS_NAME_PIN_PAD_MODE(), true).toBool(); } @@ -95,6 +91,19 @@ void RemoteServiceSettings::setPinPadMode(bool pPinPadMode) } +bool RemoteServiceSettings::getShowAccessRights() const +{ + return mStore->value(SETTINGS_NAME_SHOW_ACCESS_RIGHTS(), false).toBool(); +} + + +void RemoteServiceSettings::setShowAccessRights(bool pShowAccessRights) +{ + mStore->setValue(SETTINGS_NAME_SHOW_ACCESS_RIGHTS(), pShowAccessRights); + save(mStore); +} + + QList RemoteServiceSettings::getTrustedCertificates() const { const int itemCount = mStore->beginReadArray(SETTINGS_ARRAY_NAME_TRUSTED_CERTIFICATES()); @@ -172,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() @@ -215,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(); } @@ -229,6 +242,11 @@ void RemoteServiceSettings::setKey(const QSslKey& pKey) const RemoteServiceSettings::RemoteInfo RemoteServiceSettings::getRemoteInfo(const QSslCertificate& pCertificate) const { + if (pCertificate.isNull()) + { + return RemoteInfo(); + } + return getRemoteInfo(generateFingerprint(pCertificate)); } @@ -254,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()); } @@ -322,8 +340,13 @@ bool RemoteServiceSettings::updateRemoteInfo(const RemoteInfo& pInfo) iter.next(); if (iter.value().getFingerprint() == pInfo.getFingerprint()) { + const bool hadNoNameYet = iter.value().mName.isEmpty(); iter.setValue(pInfo); setRemoteInfos(infos); + if (hadNoNameYet) + { + Q_EMIT fireInitialDeviceNameSet(pInfo.getNameEscaped()); + } return true; } } diff --git a/src/settings/RemoteServiceSettings.h b/src/settings/RemoteServiceSettings.h index 97f2bb993..f75bae742 100644 --- a/src/settings/RemoteServiceSettings.h +++ b/src/settings/RemoteServiceSettings.h @@ -89,12 +89,15 @@ class RemoteServiceSettings [[nodiscard]] bool getPinPadMode() const; void setPinPadMode(bool pPinPadMode); + [[nodiscard]] bool getShowAccessRights() const; + void setShowAccessRights(bool pShowAccessRights); + [[nodiscard]] QList getTrustedCertificates() const; void addTrustedCertificate(const QSslCertificate& pCertificate); 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; @@ -112,6 +115,7 @@ class RemoteServiceSettings Q_SIGNALS: void fireTrustedCertificatesChanged(); void fireTrustedRemoteInfosChanged(); + void fireInitialDeviceNameSet(const QString& pName); }; 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/CMakeLists.txt b/src/ui/functional/CMakeLists.txt index cdfc5d3bb..46a108e38 100644 --- a/src/ui/functional/CMakeLists.txt +++ b/src/ui/functional/CMakeLists.txt @@ -11,3 +11,7 @@ target_link_libraries(AusweisAppUiFunctional ${Qt}::Core AusweisAppUi AusweisApp target_compile_definitions(AusweisAppUiFunctional PRIVATE QT_STATICPLUGIN) set_target_properties(AusweisAppUiFunctional PROPERTIES PUBLIC_HEADER "AusweisApp2.h") + +if(IOS) + target_link_options(AusweisAppUiFunctional PUBLIC -exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/exported_symbols.txt) +endif() 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/functional/exported_symbols.txt b/src/ui/functional/exported_symbols.txt new file mode 100644 index 000000000..73f190594 --- /dev/null +++ b/src/ui/functional/exported_symbols.txt @@ -0,0 +1,4 @@ +_ausweisapp2_init +_ausweisapp2_shutdown +_ausweisapp2_is_running +_ausweisapp2_send diff --git a/src/ui/json/MessageDispatcher.cpp b/src/ui/json/MessageDispatcher.cpp index cc5d7a1ad..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,8 +387,19 @@ MsgHandler MessageDispatcher::interrupt() #ifdef Q_OS_IOS { const auto allowedStates = {MsgType::ENTER_PIN, MsgType::ENTER_CAN, MsgType::ENTER_PUK, MsgType::ENTER_NEW_PIN}; - return handleCurrentState(cmdType, allowedStates, [] { - Env::getSingleton()->stopScanAll(QLatin1String("")); // Null string is interpreted as 'success' + const auto lastPaceResult = mContext.getContext()->getLastPaceResult(); + return handleCurrentState(cmdType, allowedStates, [lastPaceResult] { + switch (lastPaceResult) + { + case CardReturnCode::OK: + case CardReturnCode::OK_PUK: + Env::getSingleton()->stopScan(ReaderManagerPlugInType::NFC); // Null string is interpreted as 'success' + break; + + default: + 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/MsgHandlerChangePin.cpp b/src/ui/json/messages/MsgHandlerChangePin.cpp index 496aa7f22..f01b2c08b 100644 --- a/src/ui/json/messages/MsgHandlerChangePin.cpp +++ b/src/ui/json/messages/MsgHandlerChangePin.cpp @@ -36,4 +36,10 @@ MsgHandlerChangePin::MsgHandlerChangePin(const QSharedPointergetLastPaceResult() == CardReturnCode::OK && !pContext->isWorkflowCancelled(); + + const auto& failureCode = pContext->getFailureCode(); + if (failureCode.has_value()) + { + mJsonObject[QLatin1String("reason")] = Enum::getName(failureCode.value().getReason()); + } } 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 8d63b5bf4..6e8070c18 100644 --- a/src/ui/qml/ApplicationModel.cpp +++ b/src/ui/qml/ApplicationModel.cpp @@ -6,11 +6,11 @@ #include "context/AuthContext.h" #include "context/ChangePinContext.h" +#include "context/IfdServiceContext.h" #include "context/SelfAuthContext.h" #include "BuildHelper.h" #include "Env.h" -#include "HelpAction.h" #include "LanguageLoader.h" #include "Randomizer.h" #include "ReaderFilter.h" @@ -53,7 +53,6 @@ void ApplicationModel::onStatusChanged(const ReaderManagerPlugInInfo& pInfo) ApplicationModel::ApplicationModel() : mContext() - , mScaleFactor(DEFAULT_SCALE_FACTOR) , mWifiInfo() , mWifiEnabled(false) , mFeedback() @@ -76,7 +75,7 @@ ApplicationModel::ApplicationModel() mFeedbackTimer.setSingleShot(true); connect(&mFeedbackTimer, &QTimer::timeout, this, &ApplicationModel::onShowNextFeedback, Qt::QueuedConnection); - onApplicationStateChanged(qGuiApp->applicationState()); + onApplicationStateChanged(QGuiApplication::applicationState()); connect(qGuiApp, &QGuiApplication::applicationStateChanged, this, &ApplicationModel::onApplicationStateChanged); } @@ -155,7 +154,7 @@ ApplicationModel::QmlNfcState ApplicationModel::getNfcState() const return QmlNfcState::NFC_DISABLED; } - if (!Env::getSingleton()->isScanRunning(type)) + if (!pluginInfo.isScanRunning()) { return QmlNfcState::NFC_INACTIVE; } @@ -188,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()) @@ -216,21 +197,25 @@ ApplicationModel::Workflow ApplicationModel::getCurrentWorkflow() const { return Workflow::WORKFLOW_SELF_AUTHENTICATION; } - if (mContext.objectCast()) - { - return Workflow::WORKFLOW_AUTHENTICATION; - } #if __has_include("context/PersonalizationContext.h") if (mContext.objectCast()) { return Workflow::WORKFLOW_SMART; } #endif + if (mContext.objectCast()) + { + return Workflow::WORKFLOW_AUTHENTICATION; + } + if (mContext.objectCast()) + { + return Workflow::WORKFLOW_REMOTE_SERVICE; + } return Workflow::WORKFLOW_NONE; } -int ApplicationModel::getAvailableReader() const +qsizetype ApplicationModel::getAvailableReader() const { if (!mContext) { @@ -304,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;", @@ -351,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](){ @@ -387,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(); @@ -401,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()); @@ -422,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())) @@ -465,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 472499d5a..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; @@ -97,6 +98,7 @@ class ApplicationModel WORKFLOW_SELF_AUTHENTICATION, WORKFLOW_AUTHENTICATION, WORKFLOW_SMART, + WORKFLOW_REMOTE_SERVICE, WORKFLOW_NONE }; Q_ENUM(Workflow) @@ -121,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; @@ -133,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 @@ -163,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 10df26852..fb3747de1 100644 --- a/src/ui/qml/CertificateDescriptionModel.cpp +++ b/src/ui/qml/CertificateDescriptionModel.cpp @@ -5,6 +5,8 @@ #include "CertificateDescriptionModel.h" #include "LanguageLoader.h" +#include "context/AuthContext.h" +#include "context/IfdServiceContext.h" using namespace governikus; @@ -21,9 +23,14 @@ CertificateDescriptionModel::CertificateDescriptionModel() QSharedPointer CertificateDescriptionModel::getCertificateDescription() const { - if (mContext && mContext->getDidAuthenticateEac1()) + if (const auto authContext = mContext.objectCast(); authContext && authContext->getDidAuthenticateEac1()) { - return mContext->getDidAuthenticateEac1()->getCertificateDescription(); + return authContext->getDidAuthenticateEac1()->getCertificateDescription(); + } + + if (const auto ifdContext = mContext.objectCast(); ifdContext && ifdContext->getCertificateDescription()) + { + return ifdContext->getCertificateDescription(); } return QSharedPointer(); @@ -85,13 +92,17 @@ void CertificateDescriptionModel::initModelData(const QSharedPointer& pContext) +void CertificateDescriptionModel::resetContext(const QSharedPointer& pContext) { mContext = pContext; - if (mContext) + if (auto authContext = pContext.objectCast()) + { + connect(authContext.data(), &AuthContext::fireDidAuthenticateEac1Changed, this, &CertificateDescriptionModel::onDidAuthenticateEac1Changed); + connect(authContext.data(), &AuthContext::fireAccessRightManagerCreated, this, &CertificateDescriptionModel::onDidAuthenticateEac1Changed); + } + else if (auto ifdContext = pContext.objectCast()) { - connect(mContext.data(), &AuthContext::fireDidAuthenticateEac1Changed, this, &CertificateDescriptionModel::onDidAuthenticateEac1Changed); - connect(mContext.data(), &AuthContext::fireAccessRightManagerCreated, this, &CertificateDescriptionModel::onDidAuthenticateEac1Changed); + connect(ifdContext.data(), &IfdServiceContext::fireAccessRightManagerCreated, this, &CertificateDescriptionModel::onDidAuthenticateEac1Changed); } onDidAuthenticateEac1Changed(); @@ -121,9 +132,9 @@ QString CertificateDescriptionModel::getPurpose() const QString CertificateDescriptionModel::getValidity() const { - if (mContext && mContext->getAccessRightManager() && mContext->getAccessRightManager()->getTerminalCvc()) + if (const auto authContext = mContext.objectCast(); authContext&& authContext->getAccessRightManager() && authContext->getAccessRightManager()->getTerminalCvc()) { - const CVCertificateBody body = mContext->getAccessRightManager()->getTerminalCvc()->getBody(); + const CVCertificateBody body = authContext->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); @@ -136,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 c2adc3a2f..cb631f11a 100644 --- a/src/ui/qml/CertificateDescriptionModel.h +++ b/src/ui/qml/CertificateDescriptionModel.h @@ -10,7 +10,7 @@ #include "Env.h" #include "asn1/CertificateDescription.h" -#include "context/AuthContext.h" +#include "context/WorkflowContext.h" #include #include @@ -18,6 +18,10 @@ #include #include + +class test_UIPlugInQml; + + namespace governikus { @@ -26,13 +30,14 @@ 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) private: QVector> mData; - QSharedPointer mContext; + QSharedPointer mContext; CertificateDescriptionModel(); ~CertificateDescriptionModel()override = default; @@ -54,7 +59,7 @@ class CertificateDescriptionModel TEXT }; - void resetContext(const QSharedPointer& pContext = QSharedPointer()); + void resetContext(const QSharedPointer& pContext = QSharedPointer()); [[nodiscard]] QString getSubjectName() const; [[nodiscard]] QString getSubjectUrl() const; 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 e658a4863..5317d5783 100644 --- a/src/ui/qml/ChatModel.cpp +++ b/src/ui/qml/ChatModel.cpp @@ -10,14 +10,14 @@ #include "AppSettings.h" #include "asn1/AccessRoleAndRight.h" -#include "asn1/CVCertificate.h" -#include "context/SelfAuthContext.h" +#include "context/AuthContext.h" +#include "context/IfdServiceContext.h" using namespace governikus; ChatModel::ChatModel() : QAbstractListModel() - , mAuthContext() + , mContext() , mAllRights() , mOptionalRights() , mSelectedRights() @@ -41,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); @@ -49,9 +49,9 @@ void ChatModel::initFilterModel(QSortFilterProxyModel& pModel, QAbstractItemMode } -void ChatModel::resetContext(const QSharedPointer& pContext) +void ChatModel::resetContext(const QSharedPointer& pContext) { - mAuthContext = pContext; + mContext = pContext; beginResetModel(); @@ -61,9 +61,13 @@ void ChatModel::resetContext(const QSharedPointer& pContext) endResetModel(); - if (!pContext.isNull()) + if (auto authContext = pContext.objectCast()) { - connect(pContext.data(), &AuthContext::fireAccessRightManagerCreated, this, &ChatModel::onAuthenticationDataChanged); + connect(authContext.data(), &AuthContext::fireAccessRightManagerCreated, this, &ChatModel::onAuthenticationDataChanged); + } + else if (auto ifdContext = pContext.objectCast()) + { + connect(ifdContext.data(), &IfdServiceContext::fireAccessRightManagerCreated, this, &ChatModel::onAuthenticationDataChanged); } } @@ -107,38 +111,47 @@ void ChatModel::setOrderedAllRights(const QSet& pAllRights) int ChatModel::rowCount(const QModelIndex&) const { - return mAllRights.size(); + return static_cast(mAllRights.size()); } QVariant ChatModel::data(const QModelIndex& pIndex, int pRole) const { - if (pIndex.isValid() && pIndex.row() < rowCount()) + if (!pIndex.isValid() || pIndex.row() >= rowCount()) { - auto right = mAllRights.at(pIndex.row()); - if (pRole == Qt::DisplayRole || pRole == NAME_ROLE) + return QVariant(); + } + + const auto& right = mAllRights.at(pIndex.row()); + switch (pRole) + { + case Qt::DisplayRole: + case NAME_ROLE: { QString displayText = AccessRoleAndRightsUtil::toDisplayText(right); if (right == AccessRight::AGE_VERIFICATION) { - displayText += QStringLiteral(" (%1)").arg(mAuthContext->getDidAuthenticateEac1()->getAuthenticatedAuxiliaryData()->getRequiredAge()); + if (auto authContext = mContext.objectCast()) + { + displayText += QStringLiteral(" (%1)").arg(authContext->getDidAuthenticateEac1()->getAuthenticatedAuxiliaryData()->getRequiredAge()); + } } return displayText; } - if (pRole == OPTIONAL_ROLE) - { + + case OPTIONAL_ROLE: return mOptionalRights.contains(right); - } - if (pRole == SELECTED_ROLE) - { + + case SELECTED_ROLE: return mSelectedRights.contains(right); - } - if (pRole == WRITE_RIGHT) - { + + case WRITE_RIGHT: return AccessRoleAndRightsUtil::isWriteAccessRight(right); - } + + default: + Q_UNREACHABLE(); + return QVariant(); } - return QVariant(); } @@ -183,11 +196,13 @@ bool ChatModel::setData(const QModelIndex& pIndex, const QVariant& pValue, int p } -void ChatModel::transferAccessRights() +void ChatModel::transferAccessRights() const { - Q_ASSERT(mAuthContext->getAccessRightManager()); - - *mAuthContext->getAccessRightManager() = mSelectedRights; + if (auto authContext = mContext.objectCast()) + { + Q_ASSERT(authContext->getAccessRightManager()); + *authContext->getAccessRightManager() = mSelectedRights; + } } diff --git a/src/ui/qml/ChatModel.h b/src/ui/qml/ChatModel.h index cf2dc05d6..d84351167 100644 --- a/src/ui/qml/ChatModel.h +++ b/src/ui/qml/ChatModel.h @@ -15,9 +15,13 @@ #include #include "Env.h" -#include "context/AuthContext.h" +#include "context/AccessRightManager.h" +#include "context/WorkflowContext.h" + class test_ChatModel; +class test_UIPlugInQml; + namespace governikus { @@ -30,13 +34,14 @@ 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) Q_PROPERTY(QSortFilterProxyModel * write READ getFilterWriteModel CONSTANT) private: - QSharedPointer mAuthContext; + QSharedPointer mContext; QList mAllRights; QSet mOptionalRights; QSet mSelectedRights; @@ -56,21 +61,21 @@ 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: void onAuthenticationDataChanged(QSharedPointer pAccessRightManager); public: - void resetContext(const QSharedPointer& pContext = QSharedPointer()); + void resetContext(const QSharedPointer& pContext = QSharedPointer()); [[nodiscard]] int rowCount(const QModelIndex& = QModelIndex()) const override; [[nodiscard]] QVariant data(const QModelIndex& pIndex, int pRole = Qt::DisplayRole) const override; [[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 8337f40c5..000000000 --- a/src/ui/qml/HistoryModel.cpp +++ /dev/null @@ -1,327 +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: - return AccessRoleAndRightsUtil::joinFromTechnicalName(entry.getRequestedData(), AccessRoleAndRightsUtil::READ); - - 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 1acf6d801..000000000 --- a/src/ui/qml/HistoryModelSearchFilter.cpp +++ /dev/null @@ -1,44 +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); - 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 dd6782d19..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(); @@ -125,6 +126,7 @@ QStringList LogModel::getLogFileNames() const { if (!entry.isEmpty()) { + //: LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString logFileNames += LanguageLoader::getInstance().getUsedLocale().toString(LogHandler::getFileDate(QFileInfo(entry)), tr("dd.MM.yyyy hh:mm:ss")); } } @@ -203,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); } @@ -217,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(); } @@ -269,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 ad03e0252..d6cf6a602 100644 --- a/src/ui/qml/NotificationModel.cpp +++ b/src/ui/qml/NotificationModel.cpp @@ -40,7 +40,9 @@ 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}); endInsertRows(); @@ -53,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/PinResetInformationModel.cpp b/src/ui/qml/PinResetInformationModel.cpp index 160903ced..685a4916d 100644 --- a/src/ui/qml/PinResetInformationModel.cpp +++ b/src/ui/qml/PinResetInformationModel.cpp @@ -4,10 +4,13 @@ #include "PinResetInformationModel.h" +#include "LanguageLoader.h" #include "ProviderConfiguration.h" + using namespace governikus; + PinResetInformationModel::PinResetInformationModel() : QObject() { @@ -16,6 +19,14 @@ PinResetInformationModel::PinResetInformationModel() } +bool PinResetInformationModel::hasPinResetService() const +{ + const auto& config = Env::getSingleton(); + const auto& info = config->getProviderInfo(QStringLiteral("pinResetService")); + return !info.getAddress().isEmpty(); +} + + QUrl PinResetInformationModel::getPinResetUrl() const { const auto& config = Env::getSingleton(); @@ -27,28 +38,42 @@ QUrl PinResetInformationModel::getPinResetUrl() const return tr("https://www.personalausweisportal.de/EN"); } + if (LanguageLoader::getLocaleCode() != QStringLiteral("de")) + { + return homepage + QStringLiteral("/en"); + } + return homepage; } QString PinResetInformationModel::getNoPinAndNoPukHint() const { - //: LABEL ALL_PLATFORMS Hint text for requested PUK but both, PUK and PIN are not known. - return tr("You cannot use the PUK to reset your previously set card PIN. If you forgot your card PIN, you can use the PIN Reset Service to request a new PIN."); + return hasPinResetService() ? + //: LABEL ALL_PLATFORMS Hint text for requested PUK but both, PUK and PIN are not known. + tr("You cannot use the PUK to reset your previously set card PIN. If you forgot your card PIN, you can use the PIN Reset Service to request a new PIN.") : + //: LABEL ALL_PLATFORMS Hint text for requested PUK but both, PUK and PIN are not known. + tr("If you have forgotten your ID card PIN or do not have access to the PUK, you may turn to the competent authority and set a new PIN there.

    For further information, please visit the ID card portal."); } QString PinResetInformationModel::getRequestNewPinHint() const { - //: LABEL ALL_PLATFORMS Hint when a workflow failed because of a blocked PUK - return tr("Request a new card PIN free of charge to be able to use the eID function again."); + return hasPinResetService() ? + //: LABEL ALL_PLATFORMS Hint when a workflow failed because of a blocked PUK + tr("Request a new card PIN free of charge to be able to use the eID function again.") : + //: LABEL ALL_PLATFORMS Hint when a workflow failed because of a blocked PUK + tr("You may turn to the competent authority and set a new ID card PIN there.

    For further information, please visit the ID card portal."); } QString PinResetInformationModel::getActivateOnlineFunctionHint() const { - //: LABEL ALL_PLATFORMS Hint when a workflow failed because the eID function was not activated - return tr("You can request activation of the eID function without charge."); + return hasPinResetService() ? + //: LABEL ALL_PLATFORMS Hint when a workflow failed because the eID function was not activated + tr("You can request activation of the eID function without charge.") : + //: LABEL ALL_PLATFORMS Hint when a workflow failed because the eID function was not activated + tr("Please contact the competent authority to activate the eID function.

    For further information, please visit the ID card portal."); } @@ -60,15 +85,51 @@ QString PinResetInformationModel::getActivateOnlineFunctionDescription() const QString PinResetInformationModel::getActivateOnlineFunctionActionText() const { - //: LABEL ALL_PLATFORMS - return tr("Go to Activation Service"); + return hasPinResetService() ? + //: LABEL ALL_PLATFORMS + tr("Go to Activation Service") : + //: LABEL ALL_PLATFORMS + tr("Open website"); +} + + +QString PinResetInformationModel::getPinResetHintNoPin() const +{ + return hasPinResetService() ? + //: LABEL ALL_PLATFORMS Hint text for requested Transport PIN but both, Transport PIN and PIN, are not known. + tr("You can use the PIN Reset Service to request a new card PIN free of charge.") : + //: LABEL ALL_PLATFORMS Hint text for requested Transport PIN but both, Transport PIN and PIN are not known. + tr("You may turn to the competent authority and set a new ID card PIN there.

    For further information, please visit the ID card portal."); +} + + +QString PinResetInformationModel::getPinResetHintTransportPin() const +{ + return hasPinResetService() ? + //: LABEL ALL_PLATFORMS Hint text for requested Transport PIN but both, Transport PIN and PIN, are not known. + tr("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. + tr("If you know neither your Transport PIN nor your ID card PIN, you may turn to the competent authority and set a new PIN there.

    For further information, please visit the ID card portal."); +} + + +QString PinResetInformationModel::getPinResetHint() const +{ + return hasPinResetService() ? + //: LABEL ALL_PLATFORMS Hint text for PIN but it is unknown. + tr("If you have forgotten your ID 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. + tr("If you cannot recall your ID card PIN, you may turn to the competent authority and set a new PIN there.

    For further information, please visit the ID card portal."); } QString PinResetInformationModel::getPinResetActionText() const { - //: LABEL ALL_PLATFORMS - return tr("Go to PIN Reset Service"); + return hasPinResetService() ? + //: LABEL ALL_PLATFORMS + tr("Go to PIN Reset Service") : + //: LABEL ALL_PLATFORMS + tr("Open website"); } diff --git a/src/ui/qml/PinResetInformationModel.h b/src/ui/qml/PinResetInformationModel.h index 803e5809d..5a6e7b228 100644 --- a/src/ui/qml/PinResetInformationModel.h +++ b/src/ui/qml/PinResetInformationModel.h @@ -19,8 +19,14 @@ class PinResetInformationModel Q_PROPERTY(QString requestNewPinHint READ getRequestNewPinHint NOTIFY fireUpdated) Q_PROPERTY(QString activateOnlineFunctionHint READ getActivateOnlineFunctionHint NOTIFY fireUpdated) Q_PROPERTY(QString activateOnlineFunctionDescription READ getActivateOnlineFunctionDescription NOTIFY fireUpdated) + Q_PROPERTY(QString pinResetHintNoPin READ getPinResetHintNoPin NOTIFY fireUpdated) + Q_PROPERTY(QString pinResetHintTransportPin READ getPinResetHintTransportPin NOTIFY fireUpdated) + Q_PROPERTY(QString pinResetHint READ getPinResetHint NOTIFY fireUpdated) Q_PROPERTY(QString pinResetActionText READ getPinResetActionText NOTIFY fireUpdated) + private: + bool hasPinResetService() const; + public: PinResetInformationModel(); @@ -30,6 +36,9 @@ class PinResetInformationModel [[nodiscard]] QString getActivateOnlineFunctionHint() const; [[nodiscard]] QString getActivateOnlineFunctionDescription() const; [[nodiscard]] QString getActivateOnlineFunctionActionText() const; + [[nodiscard]] QString getPinResetHintNoPin() const; + [[nodiscard]] QString getPinResetHintTransportPin() const; + [[nodiscard]] QString getPinResetHint() const; [[nodiscard]] QString getPinResetActionText() const; public Q_SLOTS: 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 bb603488d..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,20 +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(); } - 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.cpp b/src/ui/qml/RemoteDeviceFilterModel.cpp new file mode 100644 index 000000000..8a8e7ff14 --- /dev/null +++ b/src/ui/qml/RemoteDeviceFilterModel.cpp @@ -0,0 +1,81 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ + +#include "RemoteDeviceFilterModel.h" + +#include "RemoteDeviceModel.h" + +using namespace governikus; +using namespace std::placeholders; + + +RemoteDeviceFilterModel::RemoteDeviceFilterModel(QAbstractItemModel* pSourceModel, const FilterFunctionType& pFilterFunction) + : QSortFilterProxyModel() + , mFilterToApply(pFilterFunction) +{ + QSortFilterProxyModel::setSourceModel(pSourceModel); +} + + +RemoteDeviceFilterModel::ShowAvailableAndPaired RemoteDeviceFilterModel::showAvailableAndPaired = {}; +RemoteDeviceFilterModel::ShowUnavailableAndPaired RemoteDeviceFilterModel::showUnavailableAndPaired = {}; +RemoteDeviceFilterModel::ShowActivePairingMode RemoteDeviceFilterModel::showActivePairingMode = {}; + + +RemoteDeviceFilterModel::RemoteDeviceFilterModel(QAbstractItemModel* pSourceModel, ShowAvailableAndPaired) + : RemoteDeviceFilterModel(pSourceModel, std::bind(&RemoteDeviceFilterModel::availableNotPairing, this, _1, _2)) +{ +} + + +RemoteDeviceFilterModel::RemoteDeviceFilterModel(QAbstractItemModel* pSourceModel, ShowUnavailableAndPaired) + : RemoteDeviceFilterModel(pSourceModel, std::bind(&RemoteDeviceFilterModel::unavailableAndPaired, this, _1, _2)) +{ +} + + +RemoteDeviceFilterModel::RemoteDeviceFilterModel(QAbstractItemModel* pSourceModel, ShowActivePairingMode) + : RemoteDeviceFilterModel(pSourceModel, std::bind(&RemoteDeviceFilterModel::isPairing, this, _1, _2)) +{ +} + + +bool RemoteDeviceFilterModel::available(int pSourceRow, const QModelIndex& pSourceParent) const +{ + const QModelIndex index = sourceModel()->index(pSourceRow, 0, pSourceParent); + const bool isNetworkVisible = sourceModel()->data(index, RemoteDeviceModel::SettingsRemoteRoles::IS_NETWORK_VISIBLE).toBool(); + return isNetworkVisible; +} + + +bool RemoteDeviceFilterModel::isDevicePaired(int pSourceRow, const QModelIndex& pSourceParent) const +{ + const QModelIndex index = sourceModel()->index(pSourceRow, 0, pSourceParent); + return sourceModel()->data(index, RemoteDeviceModel::SettingsRemoteRoles::IS_PAIRED).toBool(); +} + + +bool RemoteDeviceFilterModel::availableNotPairing(int pSourceRow, const QModelIndex& pSourceParent) const +{ + return available(pSourceRow, pSourceParent) && !isPairing(pSourceRow, pSourceParent); +} + + +bool RemoteDeviceFilterModel::unavailableAndPaired(int pSourceRow, const QModelIndex& pSourceParent) const +{ + return !available(pSourceRow, pSourceParent) && isDevicePaired(pSourceRow, pSourceParent); +} + + +bool RemoteDeviceFilterModel::isPairing(int pSourceRow, const QModelIndex& pSourceParent) const +{ + const QModelIndex index = sourceModel()->index(pSourceRow, 0, pSourceParent); + return sourceModel()->data(index, RemoteDeviceModel::SettingsRemoteRoles::IS_PAIRING).toBool(); +} + + +bool RemoteDeviceFilterModel::filterAcceptsRow(int pSourceRow, const QModelIndex& pSourceParent) const +{ + return mFilterToApply(pSourceRow, pSourceParent); +} diff --git a/src/ui/qml/RemoteDeviceFilterModel.h b/src/ui/qml/RemoteDeviceFilterModel.h new file mode 100644 index 000000000..18d8a3e7b --- /dev/null +++ b/src/ui/qml/RemoteDeviceFilterModel.h @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include + +class test_RemoteDeviceFilterModel; + +namespace governikus +{ + +class RemoteDeviceFilterModel + : public QSortFilterProxyModel +{ + Q_OBJECT + + friend class ::test_RemoteDeviceFilterModel; + + private: + using FilterFunctionType = std::function; + FilterFunctionType mFilterToApply; + + RemoteDeviceFilterModel(QAbstractItemModel* pSourceModel, const FilterFunctionType& pFilterFunction); + + public: + struct ShowAvailableAndPaired {}; + struct ShowUnavailableAndPaired {}; + struct ShowActivePairingMode {}; + + static ShowAvailableAndPaired showAvailableAndPaired; + static ShowUnavailableAndPaired showUnavailableAndPaired; + static ShowActivePairingMode showActivePairingMode; + + RemoteDeviceFilterModel(QAbstractItemModel* pSourceModel, ShowAvailableAndPaired); + RemoteDeviceFilterModel(QAbstractItemModel* pSourceModel, ShowUnavailableAndPaired); + RemoteDeviceFilterModel(QAbstractItemModel* pSourceModel, ShowActivePairingMode); + + ~RemoteDeviceFilterModel() override = default; + + private: + [[nodiscard]] bool available(int pSourceRow, const QModelIndex& pSourceParent) const; + [[nodiscard]] bool isDevicePaired(int pSourceRow, const QModelIndex& pSourceParent) const; + + [[nodiscard]] bool availableNotPairing(int pSourceRow, const QModelIndex& pSourceParent) const; + [[nodiscard]] bool unavailableAndPaired(int pSourceRow, const QModelIndex& pSourceParent) const; + [[nodiscard]] bool isPairing(int pSourceRow, const QModelIndex& pSourceParent) const; + + protected: + [[nodiscard]] bool filterAcceptsRow(int pSourceRow, const QModelIndex& pSourceParent) const override; +}; + +} // namespace governikus diff --git a/src/ui/qml/RemoteDeviceModel.cpp b/src/ui/qml/RemoteDeviceModel.cpp index e994d425d..0df9944b1 100644 --- a/src/ui/qml/RemoteDeviceModel.cpp +++ b/src/ui/qml/RemoteDeviceModel.cpp @@ -6,160 +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 QString& pDeviceNameEscaped, - const QString& pId, - const QSharedPointer& pRemoteDeviceListEntry) - : mDeviceName(pDeviceNameEscaped) - , mId(pId) - , mPaired(false) - , mNetworkVisible(false) - , mConnected(false) - , mSupported(pRemoteDeviceListEntry->getIfdDescriptor().isSupported()) - , mLastConnected() - , mRemoteDeviceListEntry(pRemoteDeviceListEntry) -{ - Q_ASSERT(!mDeviceName.contains(QLatin1Char('<'))); -} - - -RemoteDeviceModelEntry::RemoteDeviceModelEntry(const QString& pDeviceNameEscaped, - const QString& pId, - bool pNetworkVisible, - bool pConnected, - bool pSupported, - const QDateTime& pLastConnected, - const QSharedPointer& pRemoteDeviceListEntry) - : mDeviceName(pDeviceNameEscaped) - , mId(pId) - , mPaired(true) - , 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) - , 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; -} - - -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) @@ -191,7 +48,9 @@ QHash RemoteDeviceModel::roleNames() const roles.insert(IS_NETWORK_VISIBLE, QByteArrayLiteral("isNetworkVisible")); roles.insert(IS_SUPPORTED, QByteArrayLiteral("isSupported")); roles.insert(IS_PAIRED, QByteArrayLiteral("isPaired")); + roles.insert(IS_PAIRING, QByteArrayLiteral("isPairing")); roles.insert(LINK_QUALITY, QByteArrayLiteral("linkQualityInPercent")); + roles.insert(IS_LAST_ADDED_DEVICE, QByteArrayLiteral("isLastAddedDevice")); return roles; } @@ -222,6 +81,12 @@ QString RemoteDeviceModel::getStatus(const RemoteDeviceModelEntry& pRemoteDevice return tr("Not connected"); } + if (pRemoteDeviceModelEntry.isPairing()) + { + //: LABEL ALL_PLATFORMS + return tr("Click to pair"); + } + if (pRemoteDeviceModelEntry.isPaired()) { if (pRemoteDeviceModelEntry.isNetworkVisible()) @@ -235,7 +100,7 @@ QString RemoteDeviceModel::getStatus(const RemoteDeviceModelEntry& pRemoteDevice return tr("Paired, but unsupported"); } //: LABEL ALL_PLATFORMS - return tr("Paired, but unavailable"); + return tr("Unavailable"); } if (!pRemoteDeviceModelEntry.isSupported()) @@ -259,6 +124,7 @@ void RemoteDeviceModel::updatePairedReaders() bool visible = false; bool connected = false; bool supported = true; + bool isPairing = false; QSharedPointer deviceListEntry; for (const auto& availableReader : availableReaders) { @@ -267,6 +133,7 @@ void RemoteDeviceModel::updatePairedReaders() visible = true; connected = connectedDeviceIDs.contains(availableReader.getId()); supported = availableReader.isSupported(); + isPairing = availableReader.isPairing(); deviceListEntry = availableReader.getRemoteDeviceListEntry(); break; } @@ -284,6 +151,7 @@ void RemoteDeviceModel::updatePairedReaders() visible, connected, supported, + isPairing, pairedReader.getLastConnected(), deviceListEntry); addOrUpdateReader(modelEntry); @@ -309,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); @@ -336,10 +202,9 @@ QVector RemoteDeviceModel::presentReaders() const const auto& announcingRemoteDevices = Env::getSingleton()->getAnnouncingRemoteDevices(); QVector presentReaders; - for (auto deviceListEntry : announcingRemoteDevices) + for (auto& deviceListEntry : announcingRemoteDevices) { - const auto& deviceDescriptor = deviceListEntry->getIfdDescriptor(); - auto modelEntry = RemoteDeviceModelEntry(RemoteServiceSettings::escapeDeviceName(deviceDescriptor.getIfdName()), deviceDescriptor.getIfdId(), deviceListEntry); + auto modelEntry = RemoteDeviceModelEntry(deviceListEntry); presentReaders.append(modelEntry); } @@ -351,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; } @@ -368,7 +233,7 @@ bool RemoteDeviceModel::addOrUpdateReader(const RemoteDeviceModelEntry& pModelEn int RemoteDeviceModel::rowCount(const QModelIndex&) const { - return mAllRemoteReaders.size(); + return static_cast(mAllRemoteReaders.size()); } @@ -382,6 +247,7 @@ QVariant RemoteDeviceModel::data(const QModelIndex& pIndex, int pRole) const const auto& reader = mAllRemoteReaders.at(pIndex.row()); switch (pRole) { + case Qt::DisplayRole: case REMOTE_DEVICE_NAME: return reader.getDeviceNameEscaped(); @@ -391,6 +257,8 @@ QVariant RemoteDeviceModel::data(const QModelIndex& pIndex, int pRole) const case LAST_CONNECTED: { const auto& locale = LanguageLoader::getInstance().getUsedLocale(); + + //: 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"); return locale.toString(reader.getLastConnected(), dateTimeFormat); } @@ -407,8 +275,14 @@ QVariant RemoteDeviceModel::data(const QModelIndex& pIndex, int pRole) const case IS_PAIRED: return isPaired(pIndex); + case IS_PAIRING: + return isPairing(pIndex); + case LINK_QUALITY: return reader.getLinkQuality(); + + case IS_LAST_ADDED_DEVICE: + return mLastPairedDevice.getFingerprint() == reader.getId(); } return QVariant(); @@ -451,6 +325,17 @@ bool RemoteDeviceModel::isPaired(const QModelIndex& pIndex) const } +bool RemoteDeviceModel::isPairing(const QModelIndex& pIndex) const +{ + if (!indexIsValid(pIndex)) + { + return false; + } + + return mAllRemoteReaders.at(pIndex.row()).isPairing(); +} + + bool RemoteDeviceModel::isSupported(const QModelIndex& pIndex) const { if (!indexIsValid(pIndex)) @@ -464,7 +349,7 @@ bool RemoteDeviceModel::isSupported(const QModelIndex& pIndex) const void RemoteDeviceModel::setDetectRemoteDevices(bool pNewStatus) { - if (!mShowUnpairedReaders || mIsDetectingRemoteDevices == pNewStatus) + if (mIsDetectingRemoteDevices == pNewStatus) { return; } @@ -503,7 +388,7 @@ void RemoteDeviceModel::onKnownRemoteReadersChanged() void RemoteDeviceModel::onApplicationStateChanged(bool pIsAppInForeground) { - if (!mShowUnpairedReaders || !mIsDetectingRemoteDevices) + if (!mIsDetectingRemoteDevices) { return; } @@ -530,15 +415,9 @@ void RemoteDeviceModel::onApplicationStateChanged(bool pIsAppInForeground) void RemoteDeviceModel::onUpdateReaderList() { - if (mShowPairedReaders) - { - updatePairedReaders(); - } + updatePairedReaders(); - if (mShowUnpairedReaders) - { - updateUnpairedReaders(); - } + updateUnpairedReaders(); removeVanishedReaders(); @@ -574,14 +453,11 @@ void RemoteDeviceModel::forgetDevice(const QString& pDeviceId) } -QString RemoteDeviceModel::getEmptyListDescriptionString() const +void RemoteDeviceModel::setLastPairedReader(const QSslCertificate& pCert) { - 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); + const RemoteServiceSettings& settings = Env::getSingleton()->getRemoteServiceSettings(); + mLastPairedDevice = settings.getRemoteInfo(pCert); + Q_EMIT dataChanged(index(0), index(rowCount() - 1), {IS_LAST_ADDED_DEVICE}); } diff --git a/src/ui/qml/RemoteDeviceModel.h b/src/ui/qml/RemoteDeviceModel.h index 5fe5a91a5..cf83b8a43 100644 --- a/src/ui/qml/RemoteDeviceModel.h +++ b/src/ui/qml/RemoteDeviceModel.h @@ -9,78 +9,36 @@ #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 mNetworkVisible; - bool mConnected; - bool mSupported; - QDateTime mLastConnected; - QSharedPointer mRemoteDeviceListEntry; - - public: - RemoteDeviceModelEntry(const QString& pDeviceNameEscaped, - const QString& mId, - const QSharedPointer& pRemoteDeviceListEntry); - RemoteDeviceModelEntry(const QString& pDeviceNameEscaped, - const QString& mId, - bool pNetworkVisible, - bool pConnected, - bool pSupported, - const QDateTime& pLastConnected, - const QSharedPointer& pRemoteDeviceListEntry); - explicit RemoteDeviceModelEntry(const QString& pDeviceNameEscaped = QStringLiteral("UnknownReader")); - - [[nodiscard]] bool isPaired() const; - void setPaired(bool pPaired); - [[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; private: QMap mPairedReaders; QVector mAllRemoteReaders; - const bool mShowPairedReaders; - const bool mShowUnpairedReaders; + RemoteServiceSettings::RemoteInfo mLastPairedDevice; QTimer mTimer; bool mIsDetectingRemoteDevices; #if defined(Q_OS_IOS) @@ -112,10 +70,12 @@ class RemoteDeviceModel IS_NETWORK_VISIBLE, IS_SUPPORTED, IS_PAIRED, - LINK_QUALITY + IS_PAIRING, + LINK_QUALITY, + 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; @@ -124,11 +84,11 @@ class RemoteDeviceModel [[nodiscard]] QSharedPointer getRemoteDeviceListEntry(const QModelIndex& pIndex) const; [[nodiscard]] QSharedPointer getRemoteDeviceListEntry(const QString& pDeviceId) const; [[nodiscard]] bool isPaired(const QModelIndex& pIndex) const; + [[nodiscard]] bool isPairing(const QModelIndex& pIndex) const; [[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: void setDetectRemoteDevices(bool pNewStatus); 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 1daf0816e..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" @@ -19,6 +20,12 @@ using namespace governikus; +namespace +{ +const QRegularExpression percentMatcher = QRegularExpression(QStringLiteral("(\\s|^)(100|\\d{1,2}) ?%")); +} // namespace + + RemoteServiceModel::RemoteServiceModel() : WorkflowModel() , mContext() @@ -28,8 +35,10 @@ RemoteServiceModel::RemoteServiceModel() , mPairingRequested(false) , mErrorMessage() , mPsk() - , mAvailableRemoteDevices(this, false, true) - , mKnownDevices(this, true, false) + , mAllDevices(this) + , mAvailableDevicesInPairingMode(&mAllDevices, RemoteDeviceFilterModel::showActivePairingMode) + , mAvailablePairedDevices(&mAllDevices, RemoteDeviceFilterModel::showAvailableAndPaired) + , mUnavailablePairedDevices(&mAllDevices, RemoteDeviceFilterModel::showUnavailableAndPaired) , mConnectionInfo() , mConnectedServerDeviceNames() , mRememberedServerEntry() @@ -42,6 +51,11 @@ RemoteServiceModel::RemoteServiceModel() , mRequiresLocalNetworkPermission(false) #endif { + QQmlEngine::setObjectOwnership(&mAllDevices, QQmlEngine::CppOwnership); + QQmlEngine::setObjectOwnership(&mAvailableDevicesInPairingMode, QQmlEngine::CppOwnership); + QQmlEngine::setObjectOwnership(&mAvailablePairedDevices, QQmlEngine::CppOwnership); + QQmlEngine::setObjectOwnership(&mUnavailablePairedDevices, QQmlEngine::CppOwnership); + const auto readerManager = Env::getSingleton(); connect(readerManager, &ReaderManager::firePluginAdded, this, &RemoteServiceModel::onEnvironmentChanged); connect(readerManager, &ReaderManager::fireStatusChanged, this, &RemoteServiceModel::onEnvironmentChanged); @@ -59,6 +73,14 @@ RemoteServiceModel::RemoteServiceModel() connect(ifdClient, &IfdClient::fireDeviceVanished, this, &RemoteServiceModel::fireRemoteReaderVisibleChanged); connect(ifdClient, &IfdClient::fireCertificateRemoved, this, &RemoteServiceModel::fireCertificateRemoved); + connect(this, &WorkflowModel::fireReaderPlugInTypeChanged, this, &RemoteServiceModel::onReaderPlugInTypesChanged); + + const RemoteServiceSettings& settings = Env::getSingleton()->getRemoteServiceSettings(); + connect(&settings, &RemoteServiceSettings::fireInitialDeviceNameSet, this, [](const QString& pName){ + //: LABEL ALL_PLATFORMS + Env::getSingleton()->showFeedback(tr("Pairing with %1 successful.").arg(pName)); + }); + QMetaObject::invokeMethod(this, &RemoteServiceModel::onEnvironmentChanged, Qt::QueuedConnection); } @@ -114,12 +136,54 @@ void RemoteServiceModel::onApplicationStateChanged(bool pIsAppInForeground) } +void RemoteServiceModel::onPairingCompleted(const QSslCertificate& pCertificate) +{ + mAllDevices.setLastPairedReader(pCertificate); + Q_EMIT firePairingCompleted(); +} + + void RemoteServiceModel::onTranslationChanged() { onEnvironmentChanged(); } +void RemoteServiceModel::onReaderPlugInTypesChanged(bool pExplicitStart) +{ + if (!mContext) + { + return; + } + + const auto& plugInType = getReaderPlugInType(); + if (mContext->getIfdServer() && mContext->getIfdServer()->getMessageHandler()) + { + mContext->getIfdServer()->getMessageHandler()->setAllowedCardTypes({plugInType}); + } + + auto* readerManager = Env::getSingleton(); + 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) +#else + Q_UNUSED(pExplicitStart) +#endif + { + readerManager->startScan(plugInType); + } + } +} + + bool RemoteServiceModel::isRunning() const { return mContext ? mContext->isRunning() : false; @@ -151,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); } } @@ -170,22 +234,33 @@ bool RemoteServiceModel::isStarting() const } -RemoteDeviceModel* RemoteServiceModel::getAvailableRemoteDevices() +RemoteDeviceModel* RemoteServiceModel::getAllDevices() { - return &mAvailableRemoteDevices; + return &mAllDevices; } -RemoteDeviceModel* RemoteServiceModel::getKnownDevices() +RemoteDeviceFilterModel* RemoteServiceModel::getAvailablePairedDevices() { - return &mKnownDevices; + return &mAvailablePairedDevices; +} + + +RemoteDeviceFilterModel* RemoteServiceModel::getAvailableDevicesInPairingMode() +{ + return &mAvailableDevicesInPairingMode; +} + + +RemoteDeviceFilterModel* RemoteServiceModel::getUnavailablePairedDevices() +{ + return &mUnavailablePairedDevices; } void RemoteServiceModel::setDetectRemoteDevices(bool pNewStatus) { - mAvailableRemoteDevices.setDetectRemoteDevices(pNewStatus); - mKnownDevices.setDetectRemoteDevices(pNewStatus); + mAllDevices.setDetectRemoteDevices(pNewStatus); } @@ -208,9 +283,21 @@ void RemoteServiceModel::connectToRememberedServer(const QString& pServerPsk) } +QVector RemoteServiceModel::getSupportedReaderPlugInTypes() const +{ +#if __has_include("SmartManager.h") + return {ReaderManagerPlugInType::NFC, ReaderManagerPlugInType::SMART}; + +#else + return {ReaderManagerPlugInType::NFC}; + +#endif +} + + bool RemoteServiceModel::rememberServer(const QString& pDeviceId) { - mRememberedServerEntry = mAvailableRemoteDevices.getRemoteDeviceListEntry(pDeviceId); + mRememberedServerEntry = mAllDevices.getRemoteDeviceListEntry(pDeviceId); return !mRememberedServerEntry.isNull(); } @@ -227,7 +314,7 @@ void RemoteServiceModel::onEstablishConnectionDone(const QSharedPointer()->getRemoteServiceSettings(); - const QString peerName = settings.getRemoteInfo(mContext->getIfdServer()->getCurrentCertificate()).getNameEscaped(); //: INFO ANDROID IOS The smartphone is connected as card reader (SaK) and currently processing an authentication request. The user is asked to pay attention the its screen. - mConnectionInfo = tr("Please pay attention to the display on your other device \"%1\".").arg(peerName); + mConnectionInfo = tr("Please pay attention to the display on your other device \"%1\".").arg(getConnectedClientName()); Q_EMIT fireConnectionInfoChanged(); } + else if (mContext) + { + mContext->setReaderPlugInTypes({}); + } Q_EMIT fireConnectedChanged(); } -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); } @@ -275,8 +364,9 @@ void RemoteServiceModel::resetRemoteServiceContext(const QSharedPointergetIfdServer().data(), &IfdServer::firePskChanged, this, &RemoteServiceModel::firePskChanged); + connect(mContext.data(), &IfdServiceContext::fireDisplayTextChanged, this, &RemoteServiceModel::fireDisplayTextChanged); connect(mContext->getIfdServer().data(), &IfdServer::fireConnectedChanged, this, &RemoteServiceModel::onConnectionInfoChanged); - connect(mContext->getIfdServer().data(), &IfdServer::firePairingCompleted, this, &RemoteServiceModel::firePairingCompleted); + connect(mContext->getIfdServer().data(), &IfdServer::firePairingCompleted, this, &RemoteServiceModel::onPairingCompleted); connect(mContext.data(), &IfdServiceContext::fireCardConnected, this, &RemoteServiceModel::onCardConnected); connect(mContext.data(), &IfdServiceContext::fireCardDisconnected, this, &RemoteServiceModel::onCardDisconnected); connect(mContext.data(), &IfdServiceContext::fireEstablishPaceChannelUpdated, this, &RemoteServiceModel::fireEstablishPaceChannelUpdated); @@ -296,7 +386,7 @@ void RemoteServiceModel::resetRemoteServiceContext(const QSharedPointergetDisplayText() : QString(); + return displayText.remove(percentMatcher); +} + + +int RemoteServiceModel::getPercentage() const +{ + QString displayText = mContext ? mContext->getDisplayText() : QString(); + return percentMatcher.match(displayText).captured(2).toInt(); +} + + QString RemoteServiceModel::getConnectionInfo() const { return mConnectionInfo; @@ -375,6 +479,25 @@ bool RemoteServiceModel::getRemoteReaderVisible() const } +QString RemoteServiceModel::getTransactionInfo() const +{ + return QString(); +} + + +QString RemoteServiceModel::getConnectedClientName() const +{ + if (mContext) + { + const auto& sslCertificate = mContext->getIfdServer()->getCurrentCertificate(); + const RemoteServiceSettings& settings = Env::getSingleton()->getRemoteServiceSettings(); + return settings.getRemoteInfo(sslCertificate).getNameEscaped(); + } + + return QString(); +} + + bool RemoteServiceModel::pinPadModeOn() const { return Env::getSingleton()->getRemoteServiceSettings().getPinPadMode(); @@ -405,7 +528,7 @@ QString RemoteServiceModel::getErrorMessage(bool pNfcPluginAvailable, bool pNfcP void RemoteServiceModel::forgetDevice(const QString& pId) { - mKnownDevices.forgetDevice(pId); + mAllDevices.forgetDevice(pId); } @@ -427,6 +550,12 @@ void RemoteServiceModel::changePinLength() } +bool RemoteServiceModel::isPinAuthentication() const +{ + return mContext && mContext->isPinAuthentication(); +} + + void RemoteServiceModel::onConnectedDevicesChanged() { auto* const ifdClient = Env::getSingleton(); diff --git a/src/ui/qml/RemoteServiceModel.h b/src/ui/qml/RemoteServiceModel.h index 6b1741e86..aeaa3a1db 100644 --- a/src/ui/qml/RemoteServiceModel.h +++ b/src/ui/qml/RemoteServiceModel.h @@ -9,7 +9,7 @@ #pragma once #include "Env.h" -#include "ReaderManager.h" +#include "RemoteDeviceFilterModel.h" #include "RemoteDeviceModel.h" #include "WorkflowModel.h" #include "WorkflowRequest.h" @@ -18,6 +18,10 @@ #include #include + +class test_UIPlugInQml; + + namespace governikus { @@ -26,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) @@ -34,15 +39,21 @@ class RemoteServiceModel Q_PROPERTY(QString errorMessage READ getErrorMessage NOTIFY fireEnvironmentChanged) Q_PROPERTY(bool isPairing READ isPairing NOTIFY firePskChanged) Q_PROPERTY(QByteArray psk READ getPsk NOTIFY firePskChanged) + Q_PROPERTY(QString displayText READ getDisplayText NOTIFY fireDisplayTextChanged) + Q_PROPERTY(int percentage READ getPercentage NOTIFY fireDisplayTextChanged) Q_PROPERTY(bool connectedToPairedDevice READ isConnectedToPairedDevice NOTIFY fireConnectedChanged) Q_PROPERTY(QString connectionInfo READ getConnectionInfo NOTIFY fireConnectionInfoChanged) Q_PROPERTY(QString connectedServerDeviceNames READ getConnectedServerDeviceNames NOTIFY fireConnectedServerDeviceNamesChanged) - Q_PROPERTY(RemoteDeviceModel * availableRemoteDevices READ getAvailableRemoteDevices CONSTANT) - Q_PROPERTY(RemoteDeviceModel * knownDevices READ getKnownDevices CONSTANT) + Q_PROPERTY(RemoteDeviceModel * allDevices READ getAllDevices CONSTANT) + Q_PROPERTY(RemoteDeviceFilterModel * availableDevicesInPairingMode READ getAvailableDevicesInPairingMode CONSTANT) + Q_PROPERTY(RemoteDeviceFilterModel * availablePairedDevices READ getAvailablePairedDevices CONSTANT) + Q_PROPERTY(RemoteDeviceFilterModel * unavailablePairedDevices READ getUnavailablePairedDevices CONSTANT) Q_PROPERTY(bool detectRemoteDevices READ detectRemoteDevices WRITE setDetectRemoteDevices NOTIFY fireDetectionChanged) Q_PROPERTY(bool enableTransportPinLink READ enableTransportPinLink NOTIFY fireEstablishPaceChannelUpdated) Q_PROPERTY(bool remoteReaderVisible READ getRemoteReaderVisible NOTIFY fireRemoteReaderVisibleChanged) Q_PROPERTY(bool requiresLocalNetworkPermission MEMBER mRequiresLocalNetworkPermission CONSTANT) + Q_PROPERTY(QString transactionInfo READ getTransactionInfo NOTIFY fireTransactionInfoChanged) + Q_PROPERTY(QString connectedClientName READ getConnectedClientName NOTIFY fireConnectionInfoChanged) private: QSharedPointer mContext; @@ -52,8 +63,10 @@ class RemoteServiceModel bool mPairingRequested; QString mErrorMessage; QByteArray mPsk; - RemoteDeviceModel mAvailableRemoteDevices; - RemoteDeviceModel mKnownDevices; + RemoteDeviceModel mAllDevices; + RemoteDeviceFilterModel mAvailableDevicesInPairingMode; + RemoteDeviceFilterModel mAvailablePairedDevices; + RemoteDeviceFilterModel mUnavailablePairedDevices; QString mConnectionInfo; QString mConnectedServerDeviceNames; QSharedPointer mRememberedServerEntry; @@ -73,44 +86,55 @@ 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); + void onPairingCompleted(const QSslCertificate& pCertificate); public Q_SLOTS: void onTranslationChanged(); + void onReaderPlugInTypesChanged(bool pExplicitStart); public: [[nodiscard]] bool isRunning() const; Q_INVOKABLE void setRunning(bool pState, bool pEnablePairing = false); [[nodiscard]] bool isStarting() const; - [[nodiscard]] RemoteDeviceModel* getAvailableRemoteDevices(); - [[nodiscard]] RemoteDeviceModel* getKnownDevices(); + + [[nodiscard]] RemoteDeviceModel* getAllDevices(); + [[nodiscard]] RemoteDeviceFilterModel* getAvailableDevicesInPairingMode(); + [[nodiscard]] RemoteDeviceFilterModel* getAvailablePairedDevices(); + [[nodiscard]] RemoteDeviceFilterModel* getUnavailablePairedDevices(); void setDetectRemoteDevices(bool pNewStatus); [[nodiscard]] bool detectRemoteDevices() const; Q_INVOKABLE bool rememberServer(const QString& pDeviceId); Q_INVOKABLE void connectToRememberedServer(const QString& pServerPsk); + [[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; [[nodiscard]] bool isCanEnableNfc() const; [[nodiscard]] QString getErrorMessage() const; [[nodiscard]] QByteArray getPsk() const; + [[nodiscard]] QString getDisplayText() const; + [[nodiscard]] int getPercentage() const; [[nodiscard]] QString getConnectionInfo() const; [[nodiscard]] QString getConnectedServerDeviceNames() const; [[nodiscard]] bool getRemoteReaderVisible() const; + [[nodiscard]] QString getTransactionInfo() const; + [[nodiscard]] QString getConnectedClientName() const; [[nodiscard]] Q_INVOKABLE bool pinPadModeOn() const; 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); @@ -118,17 +142,19 @@ class RemoteServiceModel void fireIsRunningChanged(); void fireEnvironmentChanged(); void firePskChanged(const QByteArray& pPsk); + void fireDisplayTextChanged(); void fireConnectedChanged(); void fireServerPskChanged(); void fireDetectionChanged(); void firePairingFailed(const QString& pDeviceName, const QString& pErrorMessage); - void firePairingSuccess(const QString& pDeviceName); + void firePairingSuccess(); void firePairingCompleted(); void fireConnectionInfoChanged(); void fireConnectedServerDeviceNamesChanged(); void fireRemoteReaderVisibleChanged(); void fireEstablishPaceChannelUpdated(); void fireCertificateRemoved(const QString& pDeviceName); + void fireTransactionInfoChanged(); }; 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 95e89d402..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(); @@ -165,35 +155,32 @@ bool SettingsModel::getPinPadMode() const void SettingsModel::setPinPadMode(bool pPinPadMode) { - auto& settings = Env::getSingleton()->getRemoteServiceSettings(); - settings.setPinPadMode(pPinPadMode); + if (getPinPadMode() != pPinPadMode) + { + auto& settings = Env::getSingleton()->getRemoteServiceSettings(); + settings.setPinPadMode(pPinPadMode); + Q_EMIT firePinPadModeChanged(); + } } -bool SettingsModel::isHistoryEnabled() const +bool SettingsModel::getShowAccessRights() const { - const auto& settings = Env::getSingleton()->getHistorySettings(); - return settings.isEnabled(); + return Env::getSingleton()->getRemoteServiceSettings().getShowAccessRights(); } -void SettingsModel::setHistoryEnabled(bool pEnabled) +void SettingsModel::setShowAccessRights(bool pShowAccessRights) { - if (isHistoryEnabled() != pEnabled) + if (getShowAccessRights() != pShowAccessRights) { - auto& settings = Env::getSingleton()->getHistorySettings(); - settings.setEnabled(pEnabled); + auto& settings = Env::getSingleton()->getRemoteServiceSettings(); + settings.setShowAccessRights(pShowAccessRights); + Q_EMIT fireShowAccessRightsChanged(); } } -int SettingsModel::removeEntireHistory() -{ - auto& settings = Env::getSingleton()->getHistorySettings(); - return settings.deleteSettings(TimePeriod::ALL_HISTORY); -} - - bool SettingsModel::isUseScreenKeyboard() const { return Env::getSingleton()->getGeneralSettings().isUseScreenKeyboard(); @@ -285,7 +272,7 @@ bool SettingsModel::isSimulatorEnabled() const } -void SettingsModel::setSimulatorEnabled(bool pEnabled) +void SettingsModel::setSimulatorEnabled(bool pEnabled) const { if (isSimulatorEnabled() != pEnabled) { @@ -349,6 +336,7 @@ void SettingsModel::setAutoStart(bool pEnabled) auto& settings = Env::getSingleton()->getGeneralSettings(); settings.setAutoStart(pEnabled); Q_EMIT fireAutoStartChanged(); + Q_EMIT fireShowTrayIconChanged(); } } @@ -367,7 +355,7 @@ bool SettingsModel::requestStoreFeedback() const } -void SettingsModel::hideFutureStoreFeedbackDialogs() +void SettingsModel::hideFutureStoreFeedbackDialogs() const { Env::getSingleton()->getGeneralSettings().setRequestStoreFeedback(false); } @@ -419,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(); @@ -460,7 +454,7 @@ bool SettingsModel::isShowInAppNotifications() const } -void SettingsModel::setShowInAppNotifications(bool pShowInAppNotifications) +void SettingsModel::setShowInAppNotifications(bool pShowInAppNotifications) const { if (isShowInAppNotifications() != pShowInAppNotifications) { @@ -470,7 +464,7 @@ void SettingsModel::setShowInAppNotifications(bool pShowInAppNotifications) } -void SettingsModel::updateAppcast() +void SettingsModel::updateAppcast() const { Env::getSingleton()->updateAppcast(); } @@ -520,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 77c8096f9..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 { @@ -31,8 +37,8 @@ class SettingsModel Q_PROPERTY(bool showBetaTesting MEMBER mShowBetaTesting NOTIFY fireDeveloperOptionsChanged) Q_PROPERTY(bool useSelfauthenticationTestUri READ useSelfauthenticationTestUri WRITE setUseSelfauthenticationTestUri NOTIFY fireDeveloperOptionsChanged) 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) @@ -42,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) @@ -54,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; @@ -65,32 +74,30 @@ 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); - [[nodiscard]] bool isHistoryEnabled() const; - void setHistoryEnabled(bool pEnabled); + [[nodiscard]] bool getShowAccessRights() const; + void setShowAccessRights(bool pShowAccessRights); [[nodiscard]] bool isUseScreenKeyboard() const; void setUseScreenKeyboard(bool pUseScreenKeyboard); @@ -108,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); @@ -125,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); @@ -133,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(); @@ -156,7 +174,7 @@ class SettingsModel void fireDeveloperOptionsChanged(); void fireDeviceNameChanged(); void firePinPadModeChanged(); - void fireHistoryEnabledChanged(); + void fireShowAccessRightsChanged(); void fireScreenKeyboardChanged(); void fireCanAllowedChanged(); void fireStartupModuleChanged(); @@ -168,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 7bbce886e..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,78 +337,85 @@ 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); + Env::getSingleton()->resetContext(remoteServiceContext); } } -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(); @@ -435,48 +425,52 @@ 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(); + Env::getSingleton()->resetContext(); } #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); @@ -491,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 { @@ -508,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 } @@ -587,7 +582,7 @@ void UIPlugInQml::onShowUserInformation(const QString& pMessage) } -void UIPlugInQml::onUpdateScheduled() +void UIPlugInQml::onUpdateScheduled() const { if (!isHidden()) { @@ -612,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) @@ -649,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(); @@ -735,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) @@ -914,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 { @@ -924,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); +} + + +bool UIPlugInQml::getShowFocusIndicator() const +{ + return mShowFocusIndicator; +} + - if (isTablet || isPhone) +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(); + } } @@ -954,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 87c54f444..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,17 +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::fireIsSmartCardAllowedChanged, this, &WorkflowModel::fireIsSmartCardAllowedChanged); + connect(mContext.data(), &WorkflowContext::fireCardConnectionChanged, this, &WorkflowModel::fireHasCardChanged); + 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(); } @@ -117,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})); @@ -159,11 +165,11 @@ void WorkflowModel::cancelWorkflow() } -void WorkflowModel::startScanIfNecessary() +void WorkflowModel::startScanExplicitly() { if (mContext) { - Q_EMIT mContext->fireReaderPlugInTypesChanged(); + Q_EMIT mContext->fireReaderPlugInTypesChanged(true); } } @@ -190,35 +196,23 @@ bool WorkflowModel::isRemoteReader() const } -bool WorkflowModel::isSmartCardAllowed() const +bool WorkflowModel::hasCard() 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); + const auto& readerInfos = Env::getSingleton()->getReaderInfos(ReaderFilter({getReaderPlugInType()})); + const auto& readersWithEid = filter([](const ReaderInfo& i){return i.hasEid();}, readerInfos); + return !readersWithEid.isEmpty(); +} - case MobileEidType::HW_KEYSTORE: - return acceptedEidTypes.contains(AcceptedEidType::HW_KEYSTORE); - case MobileEidType::UNKNOWN: - return false; - } - Q_UNREACHABLE(); +bool WorkflowModel::isCurrentSmartCardAllowed() const +{ + const auto& mobileEidType = Env::getSingleton()->getMobileEidType(); + return mContext && mContext->isMobileEidTypeAllowed(mobileEidType); } @@ -263,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()) @@ -274,7 +318,11 @@ QString WorkflowModel::getStatusHintText() const return Env::getSingleton()->getActivateOnlineFunctionHint(); case GlobalStatus::Code::Card_ValidityVerificationFailed: - return tr("Contact your local citizens' office (Bürgeramt) to apply for a new ID card or to unblock the ID card."); + 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(); @@ -292,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(); } @@ -307,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; } @@ -381,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()); } @@ -426,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); @@ -465,4 +521,32 @@ void WorkflowModel::onReaderManagerSignal() mReaderImage = newReaderImage; Q_EMIT fireReaderImageChanged(); } + + 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 287818f16..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,12 +34,15 @@ 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; private: @@ -47,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); @@ -65,8 +69,9 @@ class WorkflowModel [[nodiscard]] bool isBasicReader() const; [[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; @@ -75,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; @@ -86,7 +93,7 @@ class WorkflowModel Q_INVOKABLE void insertSmartCard(); Q_INVOKABLE void insertSimulator(); Q_INVOKABLE void cancelWorkflow(); - Q_INVOKABLE void startScanIfNecessary(); + Q_INVOKABLE void startScanExplicitly(); Q_INVOKABLE void continueWorkflow(); Q_INVOKABLE void setInitialPluginType(); [[nodiscard]] Q_INVOKABLE bool shouldSkipResultView() const; @@ -95,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); @@ -102,15 +111,21 @@ class WorkflowModel void onReaderManagerSignal(); Q_SIGNALS: + void fireWorkflowStarted(); void fireCurrentStateChanged(const QString& pState); + void fireStateEntered(const QString& pState); void fireResultChanged(); - void fireReaderPlugInTypeChanged(); + 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 bb2051208..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; } @@ -71,6 +71,18 @@ AccessRightManager::AccessRightManager(QSharedPointer pDIDA } +AccessRightManager::AccessRightManager(QSharedPointer pRequiredChat) + : QObject() + , mTerminalCvc() + , mDIDAuthenticateEAC1() + , mOptionalAccessRights() + , mEffectiveAccessRights(pRequiredChat->getAccessRights()) + , mRequiredAccessRights(pRequiredChat->getAccessRights()) +{ + +} + + void AccessRightManager::removeForbiddenAccessRights(QSet& pAccessRights) { if (!mTerminalCvc) diff --git a/src/workflows/base/context/AccessRightManager.h b/src/workflows/base/context/AccessRightManager.h index 564bdfd70..b866fdbdc 100644 --- a/src/workflows/base/context/AccessRightManager.h +++ b/src/workflows/base/context/AccessRightManager.h @@ -29,6 +29,7 @@ class AccessRightManager public: explicit AccessRightManager(QSharedPointer pDIDAuthenticateEAC1, QSharedPointer pTerminalCvc); + explicit AccessRightManager(QSharedPointer pRequiredChat); [[nodiscard]] const QSharedPointer& getTerminalCvc() const 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 26ee92ffe..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() @@ -220,7 +221,9 @@ void WorkflowContext::setCardConnection(const QSharedPointer& pC if (mCardConnection != pCardConnection) { mCardConnection = pCardConnection; + Q_EMIT fireCardConnectionChanged(); + Q_EMIT fireEidTypeMismatchChanged(); } } @@ -588,11 +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; + } + + if (cardType == CardType::EID_CARD) + { + return !acceptedEidTypes.contains(AcceptedEidType::CARD_CERTIFIED); + } + + return !isMobileEidTypeAllowed(mobileEidType); +} + + +bool WorkflowContext::isMobileEidTypeAllowed(const MobileEidType& mobileEidType) const +{ + 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 cb439639f..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; @@ -73,11 +74,12 @@ class WorkflowContext Q_SIGNALS: void fireStateApprovedChanged(bool pApproved); void fireStateChanged(const QString& pNewState); - void fireReaderPlugInTypesChanged(); + void fireReaderPlugInTypesChanged(bool pExplicitStart = false); void fireReaderInfoChanged(); void fireReaderNameChanged(); void fireCardConnectionChanged(); - void fireIsSmartCardAllowedChanged(); + void fireAcceptedEidTypesChanged(); + void fireEidTypeMismatchChanged(); void fireCanChanged(); void firePinChanged(); void firePukChanged(); @@ -93,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 @@ -102,6 +104,12 @@ class WorkflowContext } + [[nodiscard]] bool isActivateUi() const + { + return mActivateUi; + } + + [[nodiscard]] bool wasClaimed() const; void claim(const QObject* pClaimant); @@ -219,7 +227,8 @@ class WorkflowContext [[nodiscard]] virtual QVector getAcceptedEidTypes() const = 0; - bool isPhysicalCardRequired() const; + [[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 37c8c57c3..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); @@ -61,16 +58,16 @@ ChangePinController::ChangePinController(QSharedPointer pConte sUpdateRetryCounterFinal->addTransition(sUpdateRetryCounterFinal, &AbstractState::fireContinue, sCleanUpReaderManager); sUpdateRetryCounterFinal->addTransition(sUpdateRetryCounterFinal, &AbstractState::fireAbort, sCleanUpReaderManager); + sUpdateRetryCounterFinal->addTransition(sUpdateRetryCounterFinal, &StateUpdateRetryCounter::fireNoCardConnection, sCleanUpReaderManager); sCleanUpReaderManager->addTransition(sCleanUpReaderManager, &AbstractState::fireContinue, sFinal); sCleanUpReaderManager->addTransition(sCleanUpReaderManager, &AbstractState::fireAbort, sFinal); } -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()) @@ -81,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 b2bcf9279..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,18 +192,7 @@ bool AbstractState::isStartStopEnabled() const } -void AbstractState::startNfcScanIfNecessary() -{ -#if defined(Q_OS_IOS) - if (isStartStopEnabled()) - { - Env::getSingleton()->startScan(ReaderManagerPlugInType::NFC); - } -#endif -} - - -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 afb6035bd..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,36 +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 startNfcScanIfNecessary(); - 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/CompositeStatePace.cpp b/src/workflows/base/states/CompositeStatePace.cpp index 0d1ce2af8..f76275cf8 100644 --- a/src/workflows/base/states/CompositeStatePace.cpp +++ b/src/workflows/base/states/CompositeStatePace.cpp @@ -72,12 +72,15 @@ CompositeStatePace::CompositeStatePace(const QSharedPointer& pC sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &AbstractState::fireContinue, sVerifyRetryCounter); sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &AbstractState::fireAbort, sMaintainCardConnection); + sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &StateUpdateRetryCounter::fireNoCardConnection, sMaintainCardConnection); sVerifyRetryCounter->addTransition(sVerifyRetryCounter, &AbstractState::fireContinue, sPreparePace); sVerifyRetryCounter->addTransition(sVerifyRetryCounter, &AbstractState::fireAbort, sMaintainCardConnection); + sVerifyRetryCounter->addTransition(sVerifyRetryCounter, &StateVerifyRetryCounter::fireNoCardConnection, sMaintainCardConnection); sPreparePace->addTransition(sPreparePace, &AbstractState::fireContinue, sMaintainCardConnection); sPreparePace->addTransition(sPreparePace, &AbstractState::fireAbort, sMaintainCardConnection); + sPreparePace->addTransition(sPreparePace, &StatePreparePace::fireNoCardConnection, sMaintainCardConnection); sPreparePace->addTransition(sPreparePace, &StatePreparePace::fireEnterPacePassword, sEnterPacePassword); sPreparePace->addTransition(sPreparePace, &StatePreparePace::fireEstablishPaceChannel, sEstablishPaceChannel); @@ -86,8 +89,9 @@ CompositeStatePace::CompositeStatePace(const QSharedPointer& pC sEnterPacePassword->addTransition(sEnterPacePassword, &StateEnterPacePassword::firePropagateAbort, sMaintainCardConnection); sEstablishPaceChannel->addTransition(sEstablishPaceChannel, &AbstractState::fireContinue, sMaintainCardConnection); + sEstablishPaceChannel->addTransition(sEstablishPaceChannel, &StateEstablishPaceChannel::fireNoCardConnection, sMaintainCardConnection); sEstablishPaceChannel->addTransition(sEstablishPaceChannel, &AbstractState::fireAbort, sMaintainCardConnection); - sEstablishPaceChannel->addTransition(sEstablishPaceChannel, &StateEstablishPaceChannel::firePropagateAbort, sMaintainCardConnection); + sEstablishPaceChannel->addTransition(sEstablishPaceChannel, &StateEstablishPaceChannel::firePaceChannelFailed, sMaintainCardConnection); connect(sEstablishPaceChannel, &StateEstablishPaceChannel::firePaceChannelEstablished, this, &CompositeStatePace::fireContinue); sEstablishPaceChannel->addTransition(sEstablishPaceChannel, &StateEstablishPaceChannel::firePaceChannelInoperative, sClearPacePasswordsBeforeDestroy); sEstablishPaceChannel->addTransition(sEstablishPaceChannel, &StateEstablishPaceChannel::fireAbortAndUnfortunateCardPosition, sUnfortunateCardPosition); diff --git a/src/workflows/base/states/CompositeStateTrustedChannel.cpp b/src/workflows/base/states/CompositeStateTrustedChannel.cpp index e81f7cfef..40f1035d0 100644 --- a/src/workflows/base/states/CompositeStateTrustedChannel.cpp +++ b/src/workflows/base/states/CompositeStateTrustedChannel.cpp @@ -106,6 +106,7 @@ CompositeStateTrustedChannel::CompositeStateTrustedChannel(const QSharedPointer< sSendDidAuthenticateResponseEac1->addTransition(sSendDidAuthenticateResponseEac1, &AbstractState::fireContinue, sEacAdditionalInputType); sSendDidAuthenticateResponseEac1->addTransition(sSendDidAuthenticateResponseEac1, &AbstractState::fireAbort, sDestroyPace); + sSendDidAuthenticateResponseEac1->addTransition(sSendDidAuthenticateResponseEac1, &StateSendDIDAuthenticateResponseEAC1::fireReceivedStartPaosResponse, sDestroyPace); sEacAdditionalInputType->addTransition(sEacAdditionalInputType, &AbstractState::fireContinue, sProcessCertificatesFromEac2); sEacAdditionalInputType->addTransition(sEacAdditionalInputType, &AbstractState::fireAbort, sSendDidAuthenticatResponseEacAdditionalInput); @@ -113,6 +114,7 @@ CompositeStateTrustedChannel::CompositeStateTrustedChannel(const QSharedPointer< sSendDidAuthenticatResponseEacAdditionalInput->addTransition(sSendDidAuthenticatResponseEacAdditionalInput, &AbstractState::fireContinue, sProcessCertificatesFromEac2); sSendDidAuthenticatResponseEacAdditionalInput->addTransition(sSendDidAuthenticatResponseEacAdditionalInput, &AbstractState::fireAbort, sDestroyPace); + sSendDidAuthenticatResponseEacAdditionalInput->addTransition(sSendDidAuthenticatResponseEacAdditionalInput, &StateSendDIDAuthenticateResponseEACAdditionalInputType::fireReceivedStartPaosResponse, sDestroyPace); sProcessCertificatesFromEac2->addTransition(sProcessCertificatesFromEac2, &AbstractState::fireContinue, sDidAuthenticateEac2); sProcessCertificatesFromEac2->addTransition(sProcessCertificatesFromEac2, &AbstractState::fireAbort, sSendDidAuthenticateResponseEac2); @@ -122,13 +124,14 @@ CompositeStateTrustedChannel::CompositeStateTrustedChannel(const QSharedPointer< sSendDidAuthenticateResponseEac2->addTransition(sSendDidAuthenticateResponseEac2, &AbstractState::fireContinue, sTransmit); sSendDidAuthenticateResponseEac2->addTransition(sSendDidAuthenticateResponseEac2, &AbstractState::fireAbort, sDestroyPace); + sSendDidAuthenticateResponseEac2->addTransition(sSendDidAuthenticateResponseEac2, &StateSendDIDAuthenticateResponseEAC2::fireReceivedStartPaosResponse, sDestroyPace); sTransmit->addTransition(sTransmit, &AbstractState::fireContinue, sSendTransmitResponse); sTransmit->addTransition(sTransmit, &AbstractState::fireAbort, sSendTransmitResponse); - sSendTransmitResponse->addTransition(sSendTransmitResponse, &AbstractState::fireContinue, sDestroyPace); + sSendTransmitResponse->addTransition(sSendTransmitResponse, &AbstractState::fireContinue, sTransmit); sSendTransmitResponse->addTransition(sSendTransmitResponse, &AbstractState::fireAbort, sDestroyPace); - sSendTransmitResponse->addTransition(sSendTransmitResponse, &StateSendTransmitResponse::fireReceivedTransmit, sTransmit); + sSendTransmitResponse->addTransition(sSendTransmitResponse, &StateSendTransmitResponse::fireReceivedStartPaosResponse, sDestroyPace); sDestroyPace->addTransition(sDestroyPace, &AbstractState::fireContinue, sClearPacePasswords); sDestroyPace->addTransition(sDestroyPace, &AbstractState::fireAbort, sClearPacePasswords); @@ -138,6 +141,7 @@ CompositeStateTrustedChannel::CompositeStateTrustedChannel(const QSharedPointer< sUpdateRetryCounterFinal->addTransition(sUpdateRetryCounterFinal, &AbstractState::fireContinue, sCleanUpReaderManager); sUpdateRetryCounterFinal->addTransition(sUpdateRetryCounterFinal, &AbstractState::fireAbort, sCleanUpReaderManager); + sUpdateRetryCounterFinal->addTransition(sUpdateRetryCounterFinal, &StateUpdateRetryCounter::fireNoCardConnection, sCleanUpReaderManager); sCleanUpReaderManager->addTransition(sCleanUpReaderManager, &AbstractState::fireContinue, sStartPaosResponse); sCleanUpReaderManager->addTransition(sCleanUpReaderManager, &AbstractState::fireAbort, sStartPaosResponse); 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 64e7f4985..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); } @@ -173,19 +174,27 @@ void StateCheckRefreshAddress::onSslErrors(const QList& pErrors) if (TlsChecker::containsFatalError(mReply, pErrors)) { reportCommunicationError({GlobalStatus::Code::Network_Ssl_Establishment_Error, {GlobalStatus::ExternalInformation::LAST_URL, mReply->url().toString()} - }, {FailureCode::Reason::Check_Refresh_Address_Fatal_Ssl_Error_Before_Reply}); + }, FailureCode::Reason::Check_Refresh_Address_Fatal_Tls_Error_Before_Reply); } } -void StateCheckRefreshAddress::reportCommunicationError(const GlobalStatus& pStatus, const FailureCode& pFailure) +void StateCheckRefreshAddress::reportCommunicationError(const GlobalStatus& pStatus, FailureCode::Reason pFailure, const QString& pErrorString) { qCritical() << pStatus; updateStatus(pStatus); clearConnections(); mReply->abort(); - Q_EMIT fireAbort(pFailure); + + if (pErrorString.isEmpty()) + { + Q_EMIT fireAbort(pFailure); + return; + } + + Q_EMIT fireAbort({pFailure, {FailureCode::Info::Network_Error, mReply->errorString()} + }); } @@ -209,35 +218,35 @@ bool StateCheckRefreshAddress::checkSslConnectionAndSaveCertificate(const QSslCo if (!TlsChecker::hasValidEphemeralKeyLength(pSslConfiguration.ephemeralServerKey())) { reportCommunicationError({GlobalStatus::Code::Workflow_Network_Ssl_Connection_Unsupported_Algorithm_Or_Length, infoMap}, - {FailureCode::Reason::Check_Refresh_Address_Invalid_Ephemeral_Key_Length}); + FailureCode::Reason::Check_Refresh_Address_Invalid_Ephemeral_Key_Length); return false; } 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; } @@ -250,27 +259,37 @@ void StateCheckRefreshAddress::onNetworkReply() { case NetworkManager::NetworkError::ServiceUnavailable: reportCommunicationError({GlobalStatus::Code::Network_ServiceUnavailable, {GlobalStatus::ExternalInformation::LAST_URL, mUrl.toString()} - }, {FailureCode::Reason::Check_Refresh_Address_Service_Unavailable}); + }, 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}); + }, FailureCode::Reason::Check_Refresh_Address_Service_Timeout, mReply->errorString()); break; case NetworkManager::NetworkError::ProxyError: reportCommunicationError({GlobalStatus::Code::Network_Proxy_Error, {GlobalStatus::ExternalInformation::LAST_URL, mUrl.toString()} - }, {FailureCode::Reason::Check_Refresh_Address_Proxy_Error}); + }, FailureCode::Reason::Check_Refresh_Address_Proxy_Error, mReply->errorString()); break; case NetworkManager::NetworkError::SecurityError: reportCommunicationError({GlobalStatus::Code::Network_Ssl_Establishment_Error, {GlobalStatus::ExternalInformation::LAST_URL, mUrl.toString()} - }, {FailureCode::Reason::Check_Refresh_Address_Fatal_Ssl_Error_After_Reply}); + }, FailureCode::Reason::Check_Refresh_Address_Fatal_Tls_Error_After_Reply, mReply->errorString()); break; case NetworkManager::NetworkError::OtherError: reportCommunicationError({GlobalStatus::Code::Network_Other_Error, {GlobalStatus::ExternalInformation::LAST_URL, mUrl.toString()} - }, {FailureCode::Reason::Check_Refresh_Address_Unknown_Network_Error}); + }, FailureCode::Reason::Check_Refresh_Address_Unknown_Network_Error, mReply->errorString()); break; } return; @@ -284,7 +303,7 @@ void StateCheckRefreshAddress::onNetworkReply() {GlobalStatus::ExternalInformation::LAST_URL, mUrl.toString()} }; reportCommunicationError({GlobalStatus::Code::Workflow_Network_Expected_Redirect, infoMap}, - {FailureCode::Reason::Check_Refresh_Address_Invalid_Http_Response}); + FailureCode::Reason::Check_Refresh_Address_Invalid_Http_Response); return; } @@ -293,7 +312,7 @@ void StateCheckRefreshAddress::onNetworkReply() { qCritical() << "Got empty redirect URL"; reportCommunicationError({GlobalStatus::Code::Workflow_Network_Empty_Redirect_Url, {GlobalStatus::ExternalInformation::LAST_URL, mUrl.toString()} - }, {FailureCode::Reason::Check_Refresh_Address_Empty}); + }, FailureCode::Reason::Check_Refresh_Address_Empty); return; } @@ -305,7 +324,7 @@ void StateCheckRefreshAddress::onNetworkReply() {GlobalStatus::ExternalInformation::LAST_URL, mUrl.toString()} }; reportCommunicationError({GlobalStatus::Code::Workflow_Network_Malformed_Redirect_Url, infoMap}, - {FailureCode::Reason::Check_Refresh_Address_Invalid_Url}); + FailureCode::Reason::Check_Refresh_Address_Invalid_Url); return; } @@ -325,7 +344,7 @@ void StateCheckRefreshAddress::onNetworkReply() {GlobalStatus::ExternalInformation::LAST_URL, redirectUrl.toString()} }; reportCommunicationError({GlobalStatus::Code::Workflow_Network_Invalid_Scheme, infoMap}, - {FailureCode::Reason::Check_Refresh_Address_No_Https_Scheme}); + FailureCode::Reason::Check_Refresh_Address_No_Https_Scheme); return; } } @@ -378,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); } @@ -419,7 +438,7 @@ void StateCheckRefreshAddress::onNetworkErrorFetchingServerCertificate(QNetworkR } qCritical() << "An error occurred fetching the server certificate:" << mReply->errorString(); reportCommunicationError({GlobalStatus::Code::Workflow_Network_Empty_Redirect_Url, {GlobalStatus::ExternalInformation::LAST_URL, mReply->url().toString()} - }, {FailureCode::Reason::Check_Refresh_Address_Fetch_Certificate_Error}); + }, FailureCode::Reason::Check_Refresh_Address_Fetch_Certificate_Error); } diff --git a/src/workflows/base/states/StateCheckRefreshAddress.h b/src/workflows/base/states/StateCheckRefreshAddress.h index 03fa8ec6c..469659d65 100644 --- a/src/workflows/base/states/StateCheckRefreshAddress.h +++ b/src/workflows/base/states/StateCheckRefreshAddress.h @@ -44,13 +44,13 @@ class StateCheckRefreshAddress [[nodiscard]] bool isMatchingSameOriginPolicyInDevMode() const; void run() override; - QUrl determineSubjectUrl(); + QUrl determineSubjectUrl() const; void sendGetRequest(); void fetchServerCertificate(); bool checkSslConnectionAndSaveCertificate(const QSslConfiguration& pSslConfiguration); void doneSuccess(); - void reportCommunicationError(const GlobalStatus& pStatus, const FailureCode& pFailure); + void reportCommunicationError(const GlobalStatus& pStatus, FailureCode::Reason pFailure, const QString& pErrorString = QString()); private Q_SLOTS: void onSslHandshakeDone(); diff --git a/src/workflows/base/states/StateCleanUpReaderManager.cpp b/src/workflows/base/states/StateCleanUpReaderManager.cpp index d1a979dcd..039f85c00 100644 --- a/src/workflows/base/states/StateCleanUpReaderManager.cpp +++ b/src/workflows/base/states/StateCleanUpReaderManager.cpp @@ -21,9 +21,7 @@ StateCleanUpReaderManager::StateCleanUpReaderManager(const QSharedPointer context = getContext(); - - const auto& reader = context->getReaderName(); - if (!reader.isEmpty() && !context->getStatus().isError()) + if (const auto& reader = context->getReaderName(); !reader.isEmpty()) { const auto& readerInfo = Env::getSingleton()->getReaderInfo(reader); if (readerInfo.hasCard() && readerInfo.getCardInfo().getCardType() != CardType::SMART_EID) diff --git a/src/workflows/base/states/StateConnectCard.cpp b/src/workflows/base/states/StateConnectCard.cpp index 01d17039c..28f7f87f5 100644 --- a/src/workflows/base/states/StateConnectCard.cpp +++ b/src/workflows/base/states/StateConnectCard.cpp @@ -25,9 +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); - mConnections += connect(readerManager, &ReaderManager::fireStatusChanged, this, &StateConnectCard::onReaderStatusChanged); + *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(); } @@ -41,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); } } @@ -66,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; } @@ -96,34 +98,12 @@ void StateConnectCard::onCommandDone(QSharedPointer } -void StateConnectCard::onReaderStatusChanged(const ReaderManagerPlugInInfo& pInfo) -{ - Q_UNUSED(pInfo) - -#if defined(Q_OS_IOS) - if (!Env::getSingleton()->isUsedAsSDK()) - { - return; - } - - const auto activePlugins = getContext()->getReaderPlugInTypes(); - if (activePlugins.size() > 1 || !activePlugins.contains(ReaderManagerPlugInType::NFC)) - { - return; - } - - if (!Env::getSingleton()->isScanRunning(ReaderManagerPlugInType::NFC)) - { - Q_EMIT getContext()->fireCancelWorkflow(); - } -#endif -} - - -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(); } } @@ -131,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); @@ -138,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 4cbd6238b..0c6f06419 100644 --- a/src/workflows/base/states/StateConnectCard.h +++ b/src/workflows/base/states/StateConnectCard.h @@ -28,8 +28,7 @@ class StateConnectCard private Q_SLOTS: void onCardInserted(); void onCommandDone(QSharedPointer pCommand); - void onReaderRemoved(const ReaderInfo& pInfo); - void onReaderStatusChanged(const ReaderManagerPlugInInfo& 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 cb2eb9c2c..292cdd01d 100644 --- a/src/workflows/base/states/StateDestroyPace.cpp +++ b/src/workflows/base/states/StateDestroyPace.cpp @@ -24,12 +24,12 @@ void StateDestroyPace::run() auto cardConnection = getContext()->getCardConnection(); if (!cardConnection) { - qCDebug(statemachine) << "No card connection available."; - Q_EMIT fireAbort(FailureCode::Reason::Destroy_Pace_No_Connection_To_Destroy); + qCDebug(statemachine) << "Nothing to do. No card connection available."; + Q_EMIT fireContinue(); 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 f8dfbae4d..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()); } @@ -62,8 +62,8 @@ void StateDidAuthenticateEac2::onCardCommandDone(QSharedPointer newStatus = GlobalStatus::Code::Workflow_Card_Removed; break; - case CardReturnCode::EXTENDED_LENGTH_MISSING: - newStatus = GlobalStatus::Code::Workflow_No_Extended_Length_Error; + case CardReturnCode::WRONG_LENGTH: + newStatus = GlobalStatus::Code::Workflow_Wrong_Length_Error; break; default: diff --git a/src/workflows/base/states/StateEnterPacePassword.cpp b/src/workflows/base/states/StateEnterPacePassword.cpp index 39a8c7445..8811ae385 100644 --- a/src/workflows/base/states/StateEnterPacePassword.cpp +++ b/src/workflows/base/states/StateEnterPacePassword.cpp @@ -4,6 +4,8 @@ #include "StateEnterPacePassword.h" +#include "VolatileSettings.h" + using namespace governikus; @@ -40,8 +42,9 @@ void StateEnterPacePassword::onEntry(QEvent* pEvent) break; default: + const auto* volatileSettings = Env::getSingleton(); //: INFO IOS The current session was interrupted because of a wrong password. - stopNfcScanIfNecessary(tr("Access denied.")); + stopNfcScanIfNecessary(volatileSettings->isUsedAsSDK() ? volatileSettings->getMessages().getSessionFailed() : tr("Access denied.")); } AbstractState::onEntry(pEvent); diff --git a/src/workflows/base/states/StateEstablishPaceChannel.cpp b/src/workflows/base/states/StateEstablishPaceChannel.cpp index 43ca6ac64..acb2d2ffd 100644 --- a/src/workflows/base/states/StateEstablishPaceChannel.cpp +++ b/src/workflows/base/states/StateEstablishPaceChannel.cpp @@ -22,21 +22,24 @@ StateEstablishPaceChannel::StateEstablishPaceChannel(const QSharedPointergetStatus().isError()) + const auto& context = getContext(); + Q_ASSERT(context); + + if (context->getStatus().isError()) { - Q_ASSERT(getContext()->getFailureCode().has_value()); - Q_EMIT firePropagateAbort(); + Q_ASSERT(context->getFailureCode().has_value()); + Q_EMIT firePaceChannelFailed(); return; } QByteArray effectiveChat; QByteArray certificateDescription; - auto authContext = getContext().objectCast(); - mPasswordId = getContext()->getEstablishPaceChannelType(); + const auto& authContext = context.objectCast(); + mPasswordId = context->getEstablishPaceChannelType(); Q_ASSERT(mPasswordId != PacePasswordId::UNKNOWN); if (mPasswordId == PacePasswordId::PACE_PIN || - (mPasswordId == PacePasswordId::PACE_CAN && getContext()->isCanAllowedMode())) + (mPasswordId == PacePasswordId::PACE_CAN && context->isCanAllowedMode())) { if (authContext && authContext->getDidAuthenticateEac1()) { @@ -55,20 +58,15 @@ void StateEstablishPaceChannel::run() switch (mPasswordId) { case PacePasswordId::PACE_CAN: - password = getContext()->getCan().toLatin1(); + password = context->getCan().toLatin1(); break; case PacePasswordId::PACE_PIN: - password = getContext()->getPin().toLatin1(); - if (authContext && password.size() == 5) - { - abortToChangePin(FailureCode::Reason::Establish_Pace_Channel_Transport_Pin); - return; - } + password = context->getPin().toLatin1(); break; case PacePasswordId::PACE_PUK: - password = getContext()->getPuk().toLatin1(); + password = context->getPuk().toLatin1(); break; case PacePasswordId::UNKNOWN: @@ -77,11 +75,12 @@ void StateEstablishPaceChannel::run() break; } - auto cardConnection = getContext()->getCardConnection(); + auto cardConnection = context->getCardConnection(); if (!cardConnection) { qCDebug(statemachine) << "No card connection available."; - abort(FailureCode::Reason::Establish_Pace_Channel_No_Card_Connection); + context->setLastPaceResult(CardReturnCode::CARD_NOT_FOUND); + Q_EMIT fireNoCardConnection(); return; } @@ -90,26 +89,27 @@ void StateEstablishPaceChannel::run() qCCritical(statemachine) << "We hit an invalid state! PACE password is empty for basic reader."; Q_ASSERT(false); - qCDebug(statemachine) << "Resetting all PACE passwords."; - getContext()->resetPacePasswords(); - - abort(FailureCode::Reason::Establish_Pace_Channel_Basic_Reader_No_Pin); + updateStatus(GlobalStatus::Code::Card_Invalid_Pin); + Q_EMIT fireAbort(FailureCode::Reason::Establish_Pace_Channel_Basic_Reader_No_Pin); return; } + //: INFO ALL_PLATFORMS First status message after the PIN was entered. + context->setProgress(context->getProgressValue(), tr("The secure channel is opened")); + qDebug() << "Establish connection using" << mPasswordId; Q_ASSERT(!password.isEmpty() || !cardConnection->getReaderInfo().isBasicReader()); if (mPasswordId == PacePasswordId::PACE_PIN && !cardConnection->getReaderInfo().isBasicReader()) { - const auto pinContext = getContext().objectCast(); + const auto pinContext = context.objectCast(); if (pinContext && pinContext->isRequestTransportPin()) { password = QByteArray(5, 0); } } - mConnections += cardConnection->callEstablishPaceChannelCommand(this, + *this << cardConnection->callEstablishPaceChannelCommand(this, &StateEstablishPaceChannel::onEstablishConnectionDone, mPasswordId, password, @@ -125,26 +125,7 @@ void StateEstablishPaceChannel::onUserCancelled() } -void StateEstablishPaceChannel::abort(FailureCode::Reason pReason) -{ - getContext()->resetLastPaceResult(); - Q_EMIT fireAbort(pReason); -} - - -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) { @@ -214,10 +195,6 @@ void StateEstablishPaceChannel::onEstablishConnectionDone(QSharedPointer::getName(returnCode)} - }); + Q_EMIT firePaceChannelFailed(); return; } diff --git a/src/workflows/base/states/StateEstablishPaceChannel.h b/src/workflows/base/states/StateEstablishPaceChannel.h index 89e14f609..6df5a46ea 100644 --- a/src/workflows/base/states/StateEstablishPaceChannel.h +++ b/src/workflows/base/states/StateEstablishPaceChannel.h @@ -34,18 +34,17 @@ class StateEstablishPaceChannel void run() override; void onUserCancelled() override; - void abort(FailureCode::Reason pReason); - void abortToChangePin(FailureCode::Reason pReason); - void handleNpaPosition(CardReturnCode pReturnCode); + void handleNpaPosition(CardReturnCode pReturnCode) const; private Q_SLOTS: void onEstablishConnectionDone(QSharedPointer pCommand); Q_SIGNALS: + void fireNoCardConnection(); void firePaceChannelEstablished(); void firePaceChannelInoperative(); void fireAbortAndUnfortunateCardPosition(); - void firePropagateAbort(); + void firePaceChannelFailed(); }; } // namespace governikus diff --git a/src/workflows/base/states/StateGenericProviderCommunication.cpp b/src/workflows/base/states/StateGenericProviderCommunication.cpp index 50c5b4214..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); } @@ -124,7 +122,7 @@ void StateGenericProviderCommunication::onSslErrors(const QList& pErr } const GlobalStatus& status = {GlobalStatus::Code::Network_Ssl_Establishment_Error, infoMap}; - const FailureCode& failure {FailureCode::Reason::Generic_Provider_Communication_Ssl_Error, + const FailureCode& failure {FailureCode::Reason::Generic_Provider_Communication_Tls_Error, { {FailureCode::Info::Network_Error, mReply->errorString()}, {FailureCode::Info::Ssl_Errors, TlsChecker::sslErrorsToString(pErrors)}, @@ -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 d168c60b7..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()); @@ -102,7 +122,7 @@ void StateGenericSendReceive::onSslErrors(const QList& pErrors) {FailureCode::Info::State_Name, getStateName()}, {FailureCode::Info::Ssl_Errors, TlsChecker::sslErrorsToString(pErrors)} }; - Q_EMIT fireAbort({FailureCode::Reason::Generic_Send_Receive_Ssl_Error, infoMap}); + Q_EMIT fireAbort({FailureCode::Reason::Generic_Send_Receive_Tls_Error, infoMap}); } } @@ -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; @@ -331,6 +334,13 @@ void StateGenericSendReceive::onReplyFinished() return; } + if (receivedType == PaosType::STARTPAOS_RESPONSE) + { + setReceivedMessage(paosHandler.getPaosMessage()); + Q_EMIT fireReceivedStartPaosResponse(); + return; + } + if (mOtherResponseTypes.contains(receivedType)) { setReceivedMessage(paosHandler.getPaosMessage()); diff --git a/src/workflows/base/states/StateGenericSendReceive.h b/src/workflows/base/states/StateGenericSendReceive.h index a956b1aaf..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,10 +54,13 @@ class StateGenericSendReceive private Q_SLOTS: void onReplyFinished(); - void onPreSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator* pAuthenticator); + void onPreSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator* pAuthenticator) const; public: void onExit(QEvent* pEvent) override; + + Q_SIGNALS: + void fireReceivedStartPaosResponse(); }; class StateSendStartPaos @@ -70,8 +74,7 @@ class StateSendStartPaos : StateGenericSendReceive(pContext, PaosType::INITIALIZE_FRAMEWORK, { - PaosType::DID_AUTHENTICATE_EAC1, - PaosType::STARTPAOS_RESPONSE + PaosType::DID_AUTHENTICATE_EAC1 }) { } @@ -95,15 +98,10 @@ class StateSendStartPaos { Q_EMIT fireReceivedExtractCvcsFromEac1InputType(); } - else if (pResponseType == PaosType::STARTPAOS_RESPONSE) - { - Q_EMIT fireReceivedStartPaosResponse(); - } } Q_SIGNALS: void fireReceivedExtractCvcsFromEac1InputType(); - void fireReceivedStartPaosResponse(); }; @@ -117,10 +115,7 @@ class StateSendInitializeFrameworkResponse private: explicit StateSendInitializeFrameworkResponse(const QSharedPointer& pContext) : StateGenericSendReceive(pContext, - PaosType::DID_AUTHENTICATE_EAC1, - { - PaosType::STARTPAOS_RESPONSE - }) + PaosType::DID_AUTHENTICATE_EAC1) { } @@ -137,18 +132,6 @@ class StateSendInitializeFrameworkResponse } - void emitStateMachineSignal(PaosType pResponseType) override - { - if (pResponseType == PaosType::STARTPAOS_RESPONSE) - { - Q_EMIT fireReceivedStartPaosResponse(); - } - } - - Q_SIGNALS: - void fireReceivedStartPaosResponse(); - - }; class StateSendDIDAuthenticateResponseEAC1 @@ -160,10 +143,7 @@ class StateSendDIDAuthenticateResponseEAC1 private: explicit StateSendDIDAuthenticateResponseEAC1(const QSharedPointer& pContext) : StateGenericSendReceive(pContext, - PaosType::DID_AUTHENTICATE_EAC2, - { - PaosType::STARTPAOS_RESPONSE - }) + PaosType::DID_AUTHENTICATE_EAC2) { setAbortOnCardRemoved(); } @@ -192,10 +172,7 @@ class StateSendDIDAuthenticateResponseEACAdditionalInputType private: explicit StateSendDIDAuthenticateResponseEACAdditionalInputType(const QSharedPointer& pContext) : StateGenericSendReceive(pContext, - PaosType::DID_AUTHENTICATE_EAC_ADDITIONAL_INPUT_TYPE, - { - PaosType::STARTPAOS_RESPONSE - }) + PaosType::DID_AUTHENTICATE_EAC_ADDITIONAL_INPUT_TYPE) { setAbortOnCardRemoved(); } @@ -224,10 +201,7 @@ class StateSendDIDAuthenticateResponseEAC2 private: explicit StateSendDIDAuthenticateResponseEAC2(const QSharedPointer& pContext) : StateGenericSendReceive(pContext, - PaosType::TRANSMIT, - { - PaosType::STARTPAOS_RESPONSE - }) + PaosType::TRANSMIT) { setAbortOnCardRemoved(); } @@ -256,10 +230,7 @@ class StateSendTransmitResponse private: explicit StateSendTransmitResponse(const QSharedPointer& pContext) : StateGenericSendReceive(pContext, - PaosType::STARTPAOS_RESPONSE, - { - PaosType::TRANSMIT - }) + PaosType::TRANSMIT) { setAbortOnCardRemoved(); } @@ -277,17 +248,6 @@ class StateSendTransmitResponse } - void emitStateMachineSignal(PaosType pResponseType) override - { - if (pResponseType == PaosType::TRANSMIT) - { - Q_EMIT fireReceivedTransmit(); - } - } - - Q_SIGNALS: - void fireReceivedTransmit(); - }; } // namespace governikus diff --git a/src/workflows/base/states/StateGetTcToken.cpp b/src/workflows/base/states/StateGetTcToken.cpp index 370515d1a..5bcf5fe03 100644 --- a/src/workflows/base/states/StateGetTcToken.cpp +++ b/src/workflows/base/states/StateGetTcToken.cpp @@ -9,7 +9,7 @@ #include "NetworkManager.h" #include "TlsChecker.h" -#include +#include #include #include #include @@ -31,12 +31,12 @@ StateGetTcToken::StateGetTcToken(const QSharedPointer& pContext void StateGetTcToken::run() { - auto url = getContext()->getTcTokenUrl(); - qDebug() << "Got TC Token URL:" << url; + const auto& url = getContext()->getTcTokenUrl(); getContext()->setProgress(0, tr("Fetch TCToken")); if (!isValidRedirectUrl(url)) { + qCCritical(network) << "TCToken URL is invalid:" << url; Q_EMIT fireAbort(FailureCode::Reason::Get_TcToken_Invalid_Url); return; } @@ -53,7 +53,7 @@ bool StateGetTcToken::isValidRedirectUrl(const QUrl& pUrl) { if (pUrl.isEmpty()) { - qCritical() << "Error while connecting to the provider. The server returns an invalid or empty redirect URL."; + qCCritical(network) << "Error while connecting to the provider. The server returns an invalid or empty redirect URL."; updateStatus(GlobalStatus::Code::Workflow_TrustedChannel_Server_Format_Error); return false; } @@ -68,8 +68,8 @@ bool StateGetTcToken::isValidRedirectUrl(const QUrl& pUrl) } else { - qCritical() << httpsError1; - qCritical() << httpsError2; + qCCritical(network) << httpsError1; + qCCritical(network) << httpsError2; // according to TR-03124-1 in case of a non-HTTPS URL a createTrustedChannelEstablishmentError error must be sent // in contrast a HTTP error 404 must be sent, if the TCToken could not be determined getContext()->setTcTokenNotFound(false); @@ -87,11 +87,12 @@ bool StateGetTcToken::isValidRedirectUrl(const QUrl& pUrl) 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); } @@ -127,7 +128,7 @@ void StateGetTcToken::onSslHandshakeDone() { clearConnections(); mReply->abort(); - qCritical() << "Error while connecting to the provider. The server's SSL certificate uses an unsupported key algorithm or length."; + qCCritical(network) << "Error while connecting to the provider. The server's SSL certificate uses an unsupported key algorithm or length."; updateStatus(status); Q_EMIT fireAbort(FailureCode::Reason::Get_TcToken_Invalid_Certificate_Key_Length); return; @@ -137,7 +138,7 @@ void StateGetTcToken::onSslHandshakeDone() { clearConnections(); mReply->abort(); - qCritical() << "Error while connecting to the provider. The SSL connection uses an unsupported key algorithm or length."; + qCCritical(network) << "Error while connecting to the provider. The SSL connection uses an unsupported key algorithm or length."; updateStatus(status); Q_EMIT fireAbort(FailureCode::Reason::Get_TcToken_Invalid_Ephemeral_Key_Length); return; @@ -151,12 +152,12 @@ void StateGetTcToken::onSslHandshakeDone() void StateGetTcToken::onNetworkReply() { - qCDebug(network) << "Received TCToken from eID-Service"; + qCDebug(network) << "TCToken request finished"; const auto statusCode = NetworkManager::getLoggedStatusCode(mReply, spawnMessageLogger(network)); if (mReply->error() != QNetworkReply::NoError) { - qCritical() << NetworkManager::toStatus(mReply); + qCCritical(network) << NetworkManager::toStatus(mReply); updateStatus(NetworkManager::toTrustedChannelStatus(mReply)); Q_EMIT fireAbort({FailureCode::Reason::Get_TcToken_Network_Error, {FailureCode::Info::Network_Error, mReply->errorString()} @@ -166,32 +167,59 @@ void StateGetTcToken::onNetworkReply() if (statusCode == HTTP_STATUS_OK) { + qCDebug(network) << "Received TCToken from eID-Service"; parseTcToken(); 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)} + }); } @@ -202,7 +230,7 @@ void StateGetTcToken::parseTcToken() QByteArray data = mReply->readAll(); if (data.isEmpty()) { - qDebug() << "Received no data."; + qCDebug(network) << "Received no data."; updateStatus({GlobalStatus::Code::Workflow_TrustedChannel_No_Data_Received, {GlobalStatus::ExternalInformation::LAST_URL, mReply->url().toString()} }); Q_EMIT fireAbort(FailureCode::Reason::Get_TcToken_Empty_Data); @@ -224,7 +252,7 @@ void StateGetTcToken::parseTcToken() return; } - qCritical() << "TCToken invalid"; + qCCritical(network) << "TCToken invalid"; updateStatus({GlobalStatus::Code::Workflow_TrustedChannel_Server_Format_Error, {GlobalStatus::ExternalInformation::LAST_URL, mReply->url().toString()} }); Q_EMIT fireAbort(FailureCode::Reason::Get_TcToken_Invalid_Data); diff --git a/src/workflows/base/states/StateMaintainCardConnection.cpp b/src/workflows/base/states/StateMaintainCardConnection.cpp index e66d70d90..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,13 +56,12 @@ 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: case CardReturnCode::COMMAND_FAILED: case CardReturnCode::PROTOCOL_ERROR: - case CardReturnCode::EXTENDED_LENGTH_MISSING: + case CardReturnCode::WRONG_LENGTH: case CardReturnCode::UNEXPECTED_TRANSMIT_STATUS: { Q_ASSERT(!CardReturnCodeUtil::equalsWrongPacePassword(lastPaceResult)); @@ -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 4e203d6da..82d1ff576 100644 --- a/src/workflows/base/states/StatePreVerification.cpp +++ b/src/workflows/base/states/StatePreVerification.cpp @@ -53,7 +53,7 @@ void StatePreVerification::run() { qCritical() << "Using the developer mode is only allowed in a test environment"; updateStatus(GlobalStatus::Code::Workflow_Preverification_Developermode_Error); - Q_EMIT fireAbort(FailureCode::Reason::Pre_Verfication_No_Test_Environment); + Q_EMIT fireAbort(FailureCode::Reason::Pre_Verification_No_Test_Environment); return; } @@ -68,14 +68,14 @@ void StatePreVerification::run() { qCritical() << "Pre-verification failed: cannot build certificate chain"; updateStatus(GlobalStatus::Code::Workflow_Preverification_Error); - Q_EMIT fireAbort(FailureCode::Reason::Pre_Verfication_Invalid_Certificate_Chain); + Q_EMIT fireAbort(FailureCode::Reason::Pre_Verification_Invalid_Certificate_Chain); return; } else if (!SignatureChecker(certificateChain).check()) { qCritical() << "Pre-verification failed: signature check failed"; updateStatus(GlobalStatus::Code::Workflow_Preverification_Error); - Q_EMIT fireAbort(FailureCode::Reason::Pre_Verfication_Invalid_Certificate_Signature); + Q_EMIT fireAbort(FailureCode::Reason::Pre_Verification_Invalid_Certificate_Signature); return; } else if (!isValid(certificateChain)) @@ -88,7 +88,7 @@ void StatePreVerification::run() { qCritical() << "Pre-verification failed: certificate not valid"; updateStatus(GlobalStatus::Code::Workflow_Preverification_Error); - Q_EMIT fireAbort(FailureCode::Reason::Pre_Verfication_Certificate_Expired); + Q_EMIT fireAbort(FailureCode::Reason::Pre_Verification_Certificate_Expired); return; } } @@ -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 fb5ed84e2..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 fireAbort(FailureCode::Reason::Prepace_Pace_No_Card_Connection); - 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 e8f83b974..c13833e55 100644 --- a/src/workflows/base/states/StatePreparePace.h +++ b/src/workflows/base/states/StatePreparePace.h @@ -25,11 +25,13 @@ class StatePreparePace private: explicit StatePreparePace(const QSharedPointer& pContext); + void handleRetryCounter(int pRetryCounter); void run() override; bool requestPaceCanIfStillRequired(); Q_SIGNALS: + void fireNoCardConnection(); void fireEnterPacePassword(); void fireEstablishPaceChannel(); }; 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 520e46cc1..51322b4cb 100644 --- a/src/workflows/base/states/StateSelectReader.cpp +++ b/src/workflows/base/states/StateSelectReader.cpp @@ -26,10 +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); + *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(); @@ -94,8 +95,28 @@ void StateSelectReader::onReaderInfoChanged() } +void StateSelectReader::onReaderStatusChanged(const ReaderManagerPlugInInfo& pInfo) const +{ +#if defined(Q_OS_IOS) + if (!Env::getSingleton()->isUsedAsSDK() || pInfo.getPlugInType() != ReaderManagerPlugInType::NFC) + { + return; + } + + if (!pInfo.isScanRunning()) + { + Q_EMIT getContext()->fireCancelWorkflow(); + } +#else + Q_UNUSED(pInfo) +#endif +} + + void StateSelectReader::onEntry(QEvent* pEvent) { + AbstractState::onEntry(pEvent); + const WorkflowContext* const context = getContext().data(); Q_ASSERT(context); @@ -103,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/StateSelectReader.h b/src/workflows/base/states/StateSelectReader.h index 714fcd03e..1a2446333 100644 --- a/src/workflows/base/states/StateSelectReader.h +++ b/src/workflows/base/states/StateSelectReader.h @@ -24,6 +24,7 @@ class StateSelectReader private Q_SLOTS: void onReaderInfoChanged(); + void onReaderStatusChanged(const ReaderManagerPlugInInfo& pInfo) const; public: void onEntry(QEvent* pEvent) override; diff --git a/src/workflows/base/states/StateStartPaosResponse.cpp b/src/workflows/base/states/StateStartPaosResponse.cpp index a273f156e..e48bcee56 100644 --- a/src/workflows/base/states/StateStartPaosResponse.cpp +++ b/src/workflows/base/states/StateStartPaosResponse.cpp @@ -25,6 +25,7 @@ void StateStartPaosResponse::run() const QSharedPointer& startPaosResponse = getContext()->getStartPaosResponse(); if (!startPaosResponse) { + updateStatus(GlobalStatus::Code::Workflow_Start_Paos_Response_Missing); Q_EMIT fireAbort(FailureCode::Reason::Start_Paos_Response_Missing); return; } 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 111b69006..bd8a05d38 100644 --- a/src/workflows/base/states/StateUpdateRetryCounter.cpp +++ b/src/workflows/base/states/StateUpdateRetryCounter.cpp @@ -26,12 +26,12 @@ void StateUpdateRetryCounter::run() if (!cardConnection) { qCDebug(statemachine) << "No card connection available."; - Q_EMIT fireAbort(FailureCode::Reason::Update_Retry_Counter_No_Card_Connection); + Q_EMIT fireNoCardConnection(); return; } Q_ASSERT(cardConnection != nullptr); - mConnections += cardConnection->callUpdateRetryCounterCommand(this, &StateUpdateRetryCounter::onUpdateRetryCounterDone); + *this << cardConnection->callUpdateRetryCounterCommand(this, &StateUpdateRetryCounter::onUpdateRetryCounterDone); } @@ -42,11 +42,9 @@ void StateUpdateRetryCounter::onUpdateRetryCounterDone(QSharedPointergetReturnCode(); if (returnCode != CardReturnCode::OK) { - qCCritical(statemachine) << "An error 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 fireAbort({FailureCode::Reason::Update_Retry_Counter_Communication_Error, - {FailureCode::Info::Card_Return_Code, Enum::getName(returnCode)} - }); + Q_EMIT fireNoCardConnection(); return; } diff --git a/src/workflows/base/states/StateUpdateRetryCounter.h b/src/workflows/base/states/StateUpdateRetryCounter.h index 9d34ea635..988b1510f 100644 --- a/src/workflows/base/states/StateUpdateRetryCounter.h +++ b/src/workflows/base/states/StateUpdateRetryCounter.h @@ -31,6 +31,9 @@ class StateUpdateRetryCounter private Q_SLOTS: void onUpdateRetryCounterDone(QSharedPointer pCommand); + + Q_SIGNALS: + void fireNoCardConnection(); }; } // namespace governikus diff --git a/src/workflows/base/states/StateVerifyRetryCounter.cpp b/src/workflows/base/states/StateVerifyRetryCounter.cpp index 6715b240e..b670df15a 100644 --- a/src/workflows/base/states/StateVerifyRetryCounter.cpp +++ b/src/workflows/base/states/StateVerifyRetryCounter.cpp @@ -24,7 +24,7 @@ void StateVerifyRetryCounter::run() if (!cardConnection) { qCDebug(statemachine) << "Card connection lost."; - Q_EMIT fireAbort(FailureCode::Reason::Verify_Retry_Counter_No_Card_Connection); + Q_EMIT fireNoCardConnection(); return; } diff --git a/src/workflows/base/states/StateVerifyRetryCounter.h b/src/workflows/base/states/StateVerifyRetryCounter.h index 558ac60cf..674ac3f07 100644 --- a/src/workflows/base/states/StateVerifyRetryCounter.h +++ b/src/workflows/base/states/StateVerifyRetryCounter.h @@ -28,8 +28,7 @@ class StateVerifyRetryCounter void run() override; Q_SIGNALS: - void fireEnterPacePassword(); - void fireEstablishPaceChannel(); + void fireNoCardConnection(); }; } // namespace governikus diff --git a/src/workflows/base/states/StateWriteHistory.cpp b/src/workflows/base/states/StateWriteHistory.cpp deleted file mode 100644 index 78fe27431..000000000 --- a/src/workflows/base/states/StateWriteHistory.cpp +++ /dev/null @@ -1,99 +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; - } - - if (context->getDidAuthenticateEac1() == nullptr) - { - qWarning() << "No EAC1 structure in context."; - Q_EMIT fireAbort(FailureCode::Reason::Write_History_No_Eac1); - return; - } - - if (context->getAccessRightManager()->getEffectiveAccessRights().isEmpty()) - { - qWarning() << "No effective CHAT in context."; - Q_EMIT fireAbort(FailureCode::Reason::Write_History_No_Chat); - return; - } - - if (auto certDesc = context->getDidAuthenticateEac1()->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 cc7145c83..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); @@ -28,10 +28,12 @@ IfdServiceContext::IfdServiceContext(const QSharedPointer& pIfdServer , mIfdServer(pIfdServer) , mNewPin() , mSlotHandle() + , mDisplayText() , mEstablishPaceChannel() , mRequestTransportPin(false) , mAllowToChangePinLength(false) , mEstablishPaceChannelOutput() + , mAccessRightManager() , mModifyPinMessage() , mModifyPinMessageResponseApdu() { @@ -116,10 +118,18 @@ void IfdServiceContext::setEstablishPaceChannel(const QSharedPointergetInputData(); mRequestTransportPin = pMessage->getExpectedPinLength() == 5; mAllowToChangePinLength = isPinChangeWorkflow() && pMessage->getExpectedPinLength() == 0; + const auto& chat = mEstablishPaceChannel.getChat(); + if (!chat.isEmpty()) + { + const auto& requiredChat = CHAT::decode(chat); + mAccessRightManager = QSharedPointer::create(requiredChat); + Q_EMIT fireAccessRightManagerCreated(mAccessRightManager); + } } else { mSlotHandle.clear(); + mAccessRightManager.clear(); mEstablishPaceChannel = EstablishPaceChannel(); mRequestTransportPin = false; mAllowToChangePinLength = false; @@ -139,12 +149,46 @@ const QString& IfdServiceContext::getSlotHandle() const } +void IfdServiceContext::setDisplayText(const QString& pDisplayText) +{ + if (mDisplayText != pDisplayText) + { + mDisplayText = pDisplayText; + Q_EMIT fireDisplayTextChanged(); + } +} + + +const QString& IfdServiceContext::getDisplayText() const +{ + return mDisplayText; +} + + const EstablishPaceChannel& IfdServiceContext::getEstablishPaceChannel() const { return mEstablishPaceChannel; } +QSharedPointer IfdServiceContext::getAccessRightManager() const +{ + return mAccessRightManager; +} + + +QSharedPointer IfdServiceContext::getCertificateDescription() const +{ + const auto& certDescription = mEstablishPaceChannel.getCertificateDescription(); + if (certDescription.isEmpty()) + { + return QSharedPointer(); + } + + return CertificateDescription::decode(certDescription); +} + + void IfdServiceContext::changePinLength() { if (isPinChangeWorkflow()) @@ -222,6 +266,7 @@ void IfdServiceContext::reset() { qDebug() << "Resetting all PACE passwords and further relevant context information."; + setDisplayText(QString()); resetPacePasswords(); resetCardConnection(); resetLastPaceResult(); @@ -232,9 +277,5 @@ void IfdServiceContext::reset() [[nodiscard]] QVector IfdServiceContext::getAcceptedEidTypes() const { - if (mIfdServer->isLocal()) - { - return {AcceptedEidType::CARD_CERTIFIED, AcceptedEidType::SE_CERTIFIED, AcceptedEidType::SE_ENDORSED, AcceptedEidType::HW_KEYSTORE}; - } - return {AcceptedEidType::CARD_CERTIFIED}; + return {AcceptedEidType::CARD_CERTIFIED, AcceptedEidType::SE_CERTIFIED, AcceptedEidType::SE_ENDORSED, AcceptedEidType::HW_KEYSTORE}; } diff --git a/src/workflows/ifd/context/IfdServiceContext.h b/src/workflows/ifd/context/IfdServiceContext.h index 986ee691c..a8a5a5de9 100644 --- a/src/workflows/ifd/context/IfdServiceContext.h +++ b/src/workflows/ifd/context/IfdServiceContext.h @@ -9,6 +9,8 @@ #pragma once #include "IfdServer.h" +#include "asn1/CertificateDescription.h" +#include "context/AccessRightManager.h" #include "context/WorkflowContext.h" #include "messages/IfdEstablishPaceChannel.h" #include "messages/IfdModifyPin.h" @@ -32,10 +34,12 @@ class IfdServiceContext QString mNewPin; QString mSlotHandle; + QString mDisplayText; EstablishPaceChannel mEstablishPaceChannel; bool mRequestTransportPin; bool mAllowToChangePinLength; EstablishPaceChannelOutput mEstablishPaceChannelOutput; + QSharedPointer mAccessRightManager; QSharedPointer mModifyPinMessage; ResponseApdu mModifyPinMessageResponseApdu; @@ -43,14 +47,16 @@ 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); + void fireDisplayTextChanged(); void fireCardDisconnected(const QSharedPointer& pConnection); void fireCancelPasswordRequest(); void fireEstablishPaceChannelUpdated(); void fireIsRunningChanged(); + void fireAccessRightManagerCreated(QSharedPointer pAccessRightManager); public: explicit IfdServiceContext(const QSharedPointer& pIfdServer); @@ -70,7 +76,11 @@ class IfdServiceContext void setEstablishPaceChannel(const QSharedPointer& pMessage); [[nodiscard]] const QString& getSlotHandle() const; + void setDisplayText(const QString& pDisplayText); + [[nodiscard]] const QString& getDisplayText() const; [[nodiscard]] const EstablishPaceChannel& getEstablishPaceChannel() const; + [[nodiscard]] QSharedPointer getAccessRightManager() const; + [[nodiscard]] QSharedPointer getCertificateDescription() const; void changePinLength(); [[nodiscard]] bool allowToChangePinLength() const; diff --git a/src/workflows/ifd/controller/IfdServiceController.cpp b/src/workflows/ifd/controller/IfdServiceController.cpp index 34cdf8011..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(); @@ -61,9 +60,11 @@ IfdServiceController::IfdServiceController(QSharedPointer pCo sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &AbstractState::fireContinue, sVerifyRetryCounter); sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &AbstractState::fireAbort, sEstablishPaceChannelResponse); + sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &StateUpdateRetryCounter::fireNoCardConnection, sEstablishPaceChannelResponse); sVerifyRetryCounter->addTransition(sVerifyRetryCounter, &AbstractState::fireContinue, sPreparePaceIfd); sVerifyRetryCounter->addTransition(sVerifyRetryCounter, &AbstractState::fireAbort, sEstablishPaceChannelResponse); + sVerifyRetryCounter->addTransition(sVerifyRetryCounter, &StateVerifyRetryCounter::fireNoCardConnection, sEstablishPaceChannelResponse); sPreparePaceIfd->addTransition(sPreparePaceIfd, &AbstractState::fireContinue, sEstablishPaceChannelIfd); sPreparePaceIfd->addTransition(sPreparePaceIfd, &AbstractState::fireAbort, sEstablishPaceChannelResponse); 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 37b81e26b..68e721bc0 100644 --- a/src/workflows/ifd/states/StateProcessIfdMessages.cpp +++ b/src/workflows/ifd/states/StateProcessIfdMessages.cpp @@ -29,10 +29,9 @@ void StateProcessIfdMessages::run() const QSharedPointer server = context->getIfdServer(); Q_ASSERT(server); - mConnections += connect(Env::getSingleton(), &ReaderManager::fireStatusChanged, this, &StateProcessIfdMessages::onReaderStatusChanged); - mConnections += connect(Env::getSingleton(), &ReaderManager::fireReaderPropertiesUpdated, this, &StateProcessIfdMessages::onReaderPropertiesUpdated); - mConnections += connect(server.data(), &IfdServer::fireMessageHandlerAdded, this, &StateProcessIfdMessages::onMessageHandlerAdded); - mConnections += connect(server.data(), &IfdServer::fireConnectedChanged, this, &StateProcessIfdMessages::onConnectedChanged); + *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) @@ -54,6 +53,7 @@ void StateProcessIfdMessages::onMessageHandlerAdded(const QSharedPointergetIfdServer()->isPairingConnection()) - { - startNfcScanIfNecessary(); - Env::getSingleton()->startScan(ReaderManagerPlugInType::SMART); - } - else - { - stopNfcScanIfNecessary(); - Env::getSingleton()->stopScan(ReaderManagerPlugInType::SMART); - } -} - - void StateProcessIfdMessages::onClosed() { qCDebug(statemachine) << "ServerMessageHandler closed"; @@ -90,34 +75,34 @@ void StateProcessIfdMessages::onClosed() } -void StateProcessIfdMessages::onReaderStatusChanged(const ReaderManagerPlugInInfo& pInfo) +void StateProcessIfdMessages::onConnectedChanged(bool pConnected) const { - if (pInfo.getPlugInType() != ReaderManagerPlugInType::NFC) + if (!Env::getSingleton()->isUsedAsSDK()) { return; } - if (Env::getSingleton()->isScanRunning(ReaderManagerPlugInType::NFC)) + if (pConnected && !getContext()->getIfdServer()->isPairingConnection()) { - return; + Env::getSingleton()->startScan(ReaderManagerPlugInType::SMART); } - - const auto& context = getContext(); - if (context->getIfdServer()->isConnected()) + else { - Q_EMIT fireAbort(FailureCode::Reason::Process_Ifd_Messages_No_Server_Connection); + Env::getSingleton()->stopScan(ReaderManagerPlugInType::SMART); } } -void StateProcessIfdMessages::onReaderPropertiesUpdated(const ReaderInfo& pInfo) +void StateProcessIfdMessages::onReaderPropertiesUpdated(const ReaderInfo& pInfo) const { - if (Env::getSingleton()->isUsedAsSDK()) + if (!Env::getSingleton()->isUsedAsSDK()) + { + return; + } + + if (pInfo.isInsertable() && pInfo.getCardInfo().getCardType() == CardType::NONE) { - if (pInfo.isInsertable() && pInfo.getCardInfo().getCardType() == CardType::NONE) - { - Env::getSingleton()->insert(pInfo); - } + Env::getSingleton()->insert(pInfo); } } @@ -128,6 +113,12 @@ void StateProcessIfdMessages::onCardConnected() } +void StateProcessIfdMessages::onDisplayTextChanged(const QString& pDisplayText) const +{ + getContext()->setDisplayText(pDisplayText); +} + + void StateProcessIfdMessages::onEstablishPaceChannel(const QSharedPointer& pMessage, const QSharedPointer& pConnection) { Q_ASSERT(pMessage); @@ -155,8 +146,9 @@ void StateProcessIfdMessages::onModifyPin(const QSharedPointersetDisplayText(QString()); if (mResetContextOnDisconnect) { getContext()->reset(); @@ -164,14 +156,6 @@ void StateProcessIfdMessages::onCardDisconnected() } -void StateProcessIfdMessages::onEntry(QEvent* pEvent) -{ - onConnectedChanged(getContext()->getIfdServer()->isConnected()); - - AbstractState::onEntry(pEvent); -} - - void StateProcessIfdMessages::onExit(QEvent* pEvent) { for (const auto& connection : std::as_const(mMessageConnections)) diff --git a/src/workflows/ifd/states/StateProcessIfdMessages.h b/src/workflows/ifd/states/StateProcessIfdMessages.h index cbf89918e..d1671f0fd 100644 --- a/src/workflows/ifd/states/StateProcessIfdMessages.h +++ b/src/workflows/ifd/states/StateProcessIfdMessages.h @@ -38,16 +38,15 @@ class StateProcessIfdMessages private Q_SLOTS: void onMessageHandlerAdded(const QSharedPointer& pHandler); void onClosed(); - void onConnectedChanged(bool pConnected); - void onReaderStatusChanged(const ReaderManagerPlugInInfo& pInfo); - void onReaderPropertiesUpdated(const ReaderInfo& pInfo); + 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 onEntry(QEvent* pEvent) override; void onExit(QEvent* pEvent) override; public: 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/StateSendStartPaosPersonalization.cpp b/src/workflows/personalization/states/StateSendStartPaosPersonalization.cpp index 1d48f9e80..27af1fef8 100644 --- a/src/workflows/personalization/states/StateSendStartPaosPersonalization.cpp +++ b/src/workflows/personalization/states/StateSendStartPaosPersonalization.cpp @@ -12,9 +12,8 @@ using namespace governikus; StateSendStartPaosPersonalization::StateSendStartPaosPersonalization(const QSharedPointer& pContext) : StateGenericSendReceive(pContext, PaosType::TRANSMIT, - { - PaosType::STARTPAOS_RESPONSE - }, true) + {}, + true) { } @@ -29,12 +28,3 @@ QSharedPointer StateSendStartPaosPersonalization::getAsCreator() { return getContext()->getStartPaos(); } - - -void StateSendStartPaosPersonalization::emitStateMachineSignal(PaosType pResponseType) -{ - if (pResponseType == PaosType::STARTPAOS_RESPONSE) - { - Q_EMIT fireReceivedStartPaosResponse(); - } -} diff --git a/src/workflows/personalization/states/StateSendStartPaosPersonalization.h b/src/workflows/personalization/states/StateSendStartPaosPersonalization.h index 46204a302..4a857c95f 100644 --- a/src/workflows/personalization/states/StateSendStartPaosPersonalization.h +++ b/src/workflows/personalization/states/StateSendStartPaosPersonalization.h @@ -22,12 +22,6 @@ class StateSendStartPaosPersonalization protected: QSharedPointer getAsResponse() override; QSharedPointer getAsCreator() override; - void emitStateMachineSignal(PaosType pResponseType) override; - - Q_SIGNALS: - void fireReceivedStartPaosResponse(); - - }; } // namespace governikus diff --git a/src/workflows/personalization/states/StateSendTransmitResponsePersonalization.cpp b/src/workflows/personalization/states/StateSendTransmitResponsePersonalization.cpp index 386ee6501..6a28a55c2 100644 --- a/src/workflows/personalization/states/StateSendTransmitResponsePersonalization.cpp +++ b/src/workflows/personalization/states/StateSendTransmitResponsePersonalization.cpp @@ -12,9 +12,8 @@ using namespace governikus; StateSendTransmitResponsePersonalization::StateSendTransmitResponsePersonalization(const QSharedPointer& pContext) : StateGenericSendReceive(pContext, PaosType::TRANSMIT, - { - PaosType::STARTPAOS_RESPONSE - }, true) + {}, + true) { } @@ -29,12 +28,3 @@ QSharedPointer StateSendTransmitResponsePersonalization::getAsCreat { return getContext()->getTransmitResponse(); } - - -void StateSendTransmitResponsePersonalization::emitStateMachineSignal(PaosType pResponseType) -{ - if (pResponseType == PaosType::STARTPAOS_RESPONSE) - { - Q_EMIT fireReceivedStartPaosResponse(); - } -} diff --git a/src/workflows/personalization/states/StateSendTransmitResponsePersonalization.h b/src/workflows/personalization/states/StateSendTransmitResponsePersonalization.h index df2f5abc6..d16192ba6 100644 --- a/src/workflows/personalization/states/StateSendTransmitResponsePersonalization.h +++ b/src/workflows/personalization/states/StateSendTransmitResponsePersonalization.h @@ -22,12 +22,6 @@ class StateSendTransmitResponsePersonalization protected: QSharedPointer getAsResponse() override; QSharedPointer getAsCreator() override; - void emitStateMachineSignal(PaosType pResponseType) override; - - Q_SIGNALS: - void fireReceivedStartPaosResponse(); - - }; } // namespace governikus diff --git a/src/workflows/personalization/states/StateStartPaosPersonalizationResponse.cpp b/src/workflows/personalization/states/StateStartPaosPersonalizationResponse.cpp new file mode 100644 index 000000000..36682365c --- /dev/null +++ b/src/workflows/personalization/states/StateStartPaosPersonalizationResponse.cpp @@ -0,0 +1,67 @@ +/** + * Copyright (c) 2014-2023 Governikus GmbH & Co. KG, Germany + */ + +#include "StateStartPaosPersonalizationResponse.h" + + +Q_DECLARE_LOGGING_CATEGORY(secure) + + +using namespace governikus; + + +StateStartPaosPersonalizationResponse::StateStartPaosPersonalizationResponse(const QSharedPointer& pContext) + : AbstractState(pContext) + , GenericContextContainer(pContext) +{ +} + + +void StateStartPaosPersonalizationResponse::run() +{ + const QSharedPointer& startPaosResponse = getContext()->getStartPaosResponse(); + if (!startPaosResponse) + { + updateStatus(GlobalStatus::Code::Workflow_Start_Paos_Response_Missing); + Q_EMIT fireAbort(FailureCode::Reason::Start_Paos_Response_Personalization_Empty); + 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& blockingCode = startPaosResponse->getBlockingCode(); + if (context && !blockingCode.isEmpty()) + { + context->setBlockingCode(blockingCode); + qDebug() << "Personalization was successful."; + } + + Q_EMIT fireContinue(); + return; + } + + 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/StateStartPaosResponsePersonalization.cpp b/src/workflows/personalization/states/StateStartPaosResponsePersonalization.cpp deleted file mode 100644 index 306c23273..000000000 --- a/src/workflows/personalization/states/StateStartPaosResponsePersonalization.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Copyright (c) 2014-2023 Governikus GmbH & Co. KG, Germany - */ - -#include "StateStartPaosResponsePersonalization.h" - -#include "context/PersonalizationContext.h" - -Q_DECLARE_LOGGING_CATEGORY(secure) - -using namespace governikus; - - -StateStartPaosResponsePersonalization::StateStartPaosResponsePersonalization(const QSharedPointer& pContext) - : AbstractState(pContext) - , GenericContextContainer(pContext) -{ -} - - -void StateStartPaosResponsePersonalization::run() -{ - const QSharedPointer& startPaosResponse = getContext()->getStartPaosResponse(); - if (!startPaosResponse) - { - Q_EMIT fireAbort(FailureCode::Reason::Start_Paos_Response_Personalization_Empty); - return; - } - - 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(); - return; - } - - qDebug() << "Processing server result:" << result.getMajorString() << result.getMinorString() << result.getMessage(); - updateStartPaosResult(result); - Q_EMIT fireAbort(FailureCode::Reason::Start_Paos_Response_Personalization_Invalid); -} 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/SelfAuthenticationData.cpp b/src/workflows/selfauth/SelfAuthenticationData.cpp index 0d2b80abf..9d6b930c0 100644 --- a/src/workflows/selfauth/SelfAuthenticationData.cpp +++ b/src/workflows/selfauth/SelfAuthenticationData.cpp @@ -248,8 +248,11 @@ void SelfAuthenticationData::SelfData::addAddress(OrderedSelfData& pSelfData) co QString SelfAuthenticationData::SelfData::formatDate(const QString& pDate) { static const QVector> formattingPattern({ + //: LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString qMakePair(QStringLiteral("yyyy-MM-dd+hh:mm"), QLatin1String(QT_TR_NOOP("dd.MM.yyyy"))), + //: LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString with unknown day qMakePair(QStringLiteral("yyyy-MM"), QLatin1String(QT_TR_NOOP("xx.MM.yyyy"))), + //: LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString with unknown day and month qMakePair(QStringLiteral("yyyy"), QLatin1String(QT_TR_NOOP("xx.xx.yyyy"))), }); 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 16a2fc302..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") @@ -40,6 +40,11 @@ function(GET_TEST_ENV testenv testname) list(APPEND ENV "QT_ENABLE_REGEXP_JIT=0") + if((LINUX OR BSD) AND "${testname}" MATCHES "card_pcsc_PcscReader") + list(APPEND ENV "ASAN_OPTIONS=verify_asan_link_order=0") + list(APPEND ENV "LD_PRELOAD=${PROJECT_BINARY_DIR}/test/helper/pcsc/libPcsc.so") + endif() + set(${testenv} "${ENV}" PARENT_SCOPE) endfunction() @@ -72,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}) @@ -90,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/simulatorFiles.json b/test/fixture/card/simulatorFiles.json index 8476990d8..b4ebaa763 100644 --- a/test/fixture/card/simulatorFiles.json +++ b/test/fixture/card/simulatorFiles.json @@ -25,5 +25,11 @@ {"fileId": "0114", "shortFileId": "14", "content": "7416a1140c125245534944454e4345205045524d49542032"}, {"fileId": "0115", "shortFileId": "15", "content": "7515131374656c3a2b34392d3033302d31323334353637"}, {"fileId": "0116", "shortFileId": "16", "content": "761516136572696b61406d75737465726d616e6e2e6465"} +], +"keys": +[ + {"id": 1, "private": "0353859c2ec67780ba39015de8c682af2326d43de9ce1e07737087bd1e17cb22"}, + {"id": 2, "private": "9ad0ad7f4dfaaa06988339fc31d3a111f4c7964ac7f377373a2454327c43e2ff"}, + {"id": 41, "private": "a07eb62e891daa84643e0afcc1af006891b669b8f51e379477dbeab8c987a610"} ] } 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/CMakeLists.txt b/test/helper/CMakeLists.txt index 27703d249..00eefcc57 100644 --- a/test/helper/CMakeLists.txt +++ b/test/helper/CMakeLists.txt @@ -11,6 +11,7 @@ if(TARGET AusweisAppIfd) endif() add_subdirectory(ui) +add_subdirectory(pcsc) # TestModule detection misses indirect dependency currently if(TARGET AusweisAppTestHelperUiWebsocket) 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/ifd/MockDataChannel.cpp b/test/helper/ifd/MockDataChannel.cpp index 1668e8848..22fc30071 100644 --- a/test/helper/ifd/MockDataChannel.cpp +++ b/test/helper/ifd/MockDataChannel.cpp @@ -10,8 +10,9 @@ using namespace governikus; -MockDataChannel::MockDataChannel() - : mId(QUuid::createUuid().toString()) +MockDataChannel::MockDataChannel(bool pPairing) + : mPairing(pPairing) + , mId(QUuid::createUuid().toString()) , mReceivedDataBlocks() { } @@ -28,6 +29,12 @@ void MockDataChannel::close() } +bool MockDataChannel::isPairingConnection() const +{ + return mPairing; +} + + const QString& MockDataChannel::getId() const { return mId; diff --git a/test/helper/ifd/MockDataChannel.h b/test/helper/ifd/MockDataChannel.h index 24e4e4b46..ecb615eed 100644 --- a/test/helper/ifd/MockDataChannel.h +++ b/test/helper/ifd/MockDataChannel.h @@ -22,15 +22,17 @@ class MockDataChannel Q_OBJECT private: + bool mPairing; QString mId; QVector mReceivedDataBlocks; public: - MockDataChannel(); + explicit MockDataChannel(bool pPairing = false); ~MockDataChannel() override; void send(const QByteArray& pDataBlock) override; void close() override; + [[nodiscard]] bool isPairingConnection() const override; [[nodiscard]] const QString& getId() const override; void closeAbnormal(); diff --git a/test/helper/ifd/MockIfdDispatcher.cpp b/test/helper/ifd/MockIfdDispatcher.cpp index 480fa1ff4..065286cba 100644 --- a/test/helper/ifd/MockIfdDispatcher.cpp +++ b/test/helper/ifd/MockIfdDispatcher.cpp @@ -24,12 +24,25 @@ using namespace governikus; MockIfdDispatcher::MockIfdDispatcher(DispatcherState pState) : IfdDispatcherClient(IfdVersion::Version::v2, QSharedPointer::create()) , mState(pState) + , mPairing(false) , mId(QUuid::createUuid().toString()) , mContextHandle(QStringLiteral("#TestContext")) { } +void MockIfdDispatcher::setPairingConnection(bool pPairing) +{ + mPairing = pPairing; +} + + +bool MockIfdDispatcher::isPairingConnection() const +{ + return mPairing; +} + + QString MockIfdDispatcher::getId() const { return mId; diff --git a/test/helper/ifd/MockIfdDispatcher.h b/test/helper/ifd/MockIfdDispatcher.h index 47580fea2..c4a89614b 100644 --- a/test/helper/ifd/MockIfdDispatcher.h +++ b/test/helper/ifd/MockIfdDispatcher.h @@ -30,12 +30,15 @@ class MockIfdDispatcher private: DispatcherState mState; + bool mPairing; QString mId; QString mContextHandle; public: MockIfdDispatcher(DispatcherState pState = DispatcherState::WithoutReader); + void setPairingConnection(bool pPairing); + [[nodiscard]] bool isPairingConnection() const override; [[nodiscard]] QString getId() const override; [[nodiscard]] const QString& getContextHandle() const override; Q_INVOKABLE void send(const QSharedPointer& pMessage) override; diff --git a/test/helper/pcsc/CMakeLists.txt b/test/helper/pcsc/CMakeLists.txt new file mode 100644 index 000000000..6af1ae377 --- /dev/null +++ b/test/helper/pcsc/CMakeLists.txt @@ -0,0 +1,6 @@ +if(LINUX OR BSD) + file(GLOB SRC "*.cpp") + + add_library(Pcsc SHARED "${SRC}") + target_link_libraries(Pcsc ${Qt}::Core PkgConfig::PCSC) +endif() diff --git a/test/helper/pcsc/main.cpp b/test/helper/pcsc/main.cpp new file mode 100644 index 000000000..6916fb47d --- /dev/null +++ b/test/helper/pcsc/main.cpp @@ -0,0 +1,86 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ + +#include +#include +#include +#ifndef Q_OS_WIN + #include +#endif + + +LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1, LPCVOID pvReserved2, LPSCARDCONTEXT phContext) +{ + Q_UNUSED(dwScope) + Q_UNUSED(pvReserved1) + Q_UNUSED(pvReserved2) + * phContext = 4; + + return SCARD_S_SUCCESS; +} + + +LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard, LPDWORD pdwActiveProtocol) +{ + Q_ASSERT(hContext == 4); + Q_UNUSED(szReader) + Q_UNUSED(dwShareMode) + Q_UNUSED(dwPreferredProtocols) + * phCard = 8; + Q_UNUSED(pdwActiveProtocol) + + return SCARD_S_SUCCESS; +} + + +LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer, DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength, LPDWORD lpBytesReturned) +{ + Q_ASSERT(hCard == 8); + Q_UNUSED(dwControlCode) + Q_UNUSED(pbSendBuffer) + Q_UNUSED(cbSendLength) + + const auto featuresTLV = QByteArray::fromHex("120442330012"); + Q_ASSERT(static_cast(cbRecvLength) >= featuresTLV.size()); + memcpy(pbRecvBuffer, featuresTLV.data(), static_cast(featuresTLV.size())); + *lpBytesReturned = static_cast(featuresTLV.size()); + + return SCARD_S_SUCCESS; +} + + +LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition) +{ + Q_ASSERT(hCard == 8); + Q_UNUSED(dwDisposition) + + return SCARD_S_SUCCESS; +} + + +LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout, SCARD_READERSTATE* rgReaderStates, DWORD cReaders) +{ + Q_ASSERT(hContext == 4); + Q_UNUSED(dwTimeout) + Q_UNUSED(rgReaderStates) + Q_UNUSED(cReaders) + + return SCARD_S_SUCCESS; +} + + +LONG SCardCancel(SCARDCONTEXT hContext) +{ + Q_ASSERT(hContext == 4); + + return SCARD_S_SUCCESS; +} + + +LONG SCardReleaseContext(SCARDCONTEXT hContext) +{ + Q_ASSERT(hContext == 4); + + return SCARD_S_SUCCESS; +} 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 90% rename from resources/json-schemas/supported-providers.json rename to test/json/supported-providers.json index 05b6c570a..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", @@ -118,7 +118,7 @@ }, "postalAddress": { "type": "string", - "pattern": "^([\\w\\. \\(\\)äöüÄÖÜß\\-\\/,:&–]|())+$" + "pattern": "^([\\w\\. \\(\\)äöüÄÖÜß\\-\\/,:&]|())+$" }, "category": { "type": "string", @@ -141,20 +141,6 @@ "type": "string", "minLength": 1 }, - "exclude": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "android", - "bsd", - "ios", - "linux", - "mac", - "win" - ] - } - }, "eidSupport": { "type": "boolean" }, 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/+mobile/test_ProviderModelItem.qml b/test/qml/AuthView/+desktop/test_ProviderInfoSection.qml similarity index 59% rename from test/qml/Provider/+mobile/test_ProviderModelItem.qml rename to test/qml/AuthView/+desktop/test_ProviderInfoSection.qml index 29098b60a..c2485f812 100644 --- a/test/qml/Provider/+mobile/test_ProviderModelItem.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; ProviderModelItem {}", testCase); + return createTemporaryQmlObject("import \"qrc:/qml/Governikus/AuthView/+desktop/\"; ProviderInfoSection {}", testCase); } function test_load() { let testObject = createTestObject(); verify(testObject, "Object loaded"); } - name: "test_ProviderModelItem" + 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_SearchBar.qml b/test/qml/Global/+desktop/test_RetryCounter.qml similarity index 58% rename from test/qml/Global/test_SearchBar.qml rename to test/qml/Global/+desktop/test_RetryCounter.qml index c6cb455d4..6f6fa4d2b 100644 --- a/test/qml/Global/test_SearchBar.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; SearchBar {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; RetryCounter { width: 64; height: 64 }", testCase); } function test_load() { let testObject = createTestObject(); verify(testObject, "Object loaded"); } - name: "test_SearchBar" + 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 a66b7ad40..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,54 +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); - waitForRendering(button); - compare(button.height, data.height); - compare(button.width, data.width); + 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() { - if (Qt.platform.os !== "osx") { - skip(); - } - 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); - waitForRendering(text); - let longTextWidth = Math.round(text.width + 0.1); + 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 ? 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() { @@ -90,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(); @@ -110,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_GGridView.qml b/test/qml/Global/test_GPaneBackgroundDelegate.qml similarity index 58% rename from test/qml/Global/test_GGridView.qml rename to test/qml/Global/test_GPaneBackgroundDelegate.qml index e27d4c889..edb15aabd 100644 --- a/test/qml/Global/test_GGridView.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; GGridView {}", testCase); + return createTemporaryQmlObject("import Governikus.Global; GPaneBackgroundDelegate {}", testCase); } function test_load() { let testObject = createTestObject(); verify(testObject, "Object loaded"); } - name: "test_GGridView" + 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/test_ProviderDetailView.qml b/test/qml/Provider/test_ProviderDetailView.qml deleted file mode 100644 index c3a14a87e..000000000 --- a/test/qml/Provider/test_ProviderDetailView.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; ProviderDetailView {}", testCase); - } - function test_load() { - let testObject = createTestObject(); - verify(testObject, "Object loaded"); - } - - name: "test_ProviderDetailView" - 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 new file mode 100644 index 000000000..30c31cc8a --- /dev/null +++ b/test/qt/card/pcsc/test_PcscReader.cpp @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ + +/*! + * \brief Unit tests for \ref PcscReader + */ + +#include "PcscReader.h" + +#include + +using namespace governikus; + + +class test_PcscReader + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void createDestroy() + { +#if !(defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) && !defined(Q_OS_FREEBSD) + QSKIP("Using LD_PRELOAD is not supported"); +#endif + + const QString readerName = QStringLiteral("PCSC"); + + QTest::ignoreMessage(QtDebugMsg, QStringLiteral("\"%1\"").arg(readerName).toUtf8().data()); + QScopedPointer reader(new PcscReader(readerName)); + QCOMPARE(reader->objectName(), readerName); + QVERIFY(reader->getState().szReader); + QVERIFY(!reader->hasFeature(FeatureID::TLV_PROPERTIES)); + + QTest::ignoreMessage(QtDebugMsg, QStringLiteral("\"%1\"").arg(readerName).toUtf8().data()); + QTest::ignoreMessage(QtDebugMsg, QStringLiteral("\"%1\"").arg(readerName).toUtf8().data()); + reader.reset(new PcscReader(readerName)); + + QCOMPARE(reader->init(), pcsc::Scard_S_Success); + QVERIFY(reader->hasFeature(FeatureID::TLV_PROPERTIES)); + QCOMPARE(reader->getFeatureValue(FeatureID::TLV_PROPERTIES), 1110638610); + + QTest::ignoreMessage(QtDebugMsg, QStringLiteral("\"%1\"").arg(readerName).toUtf8().data()); + reader.reset(); + } + + +}; + +QTEST_GUILESS_MAIN(test_PcscReader) +#include "test_PcscReader.moc" diff --git a/test/qt/card/pcsc/test_PcscReaderManagerPlugIn.cpp b/test/qt/card/pcsc/test_PcscReaderManagerPlugIn.cpp new file mode 100644 index 000000000..c114f645b --- /dev/null +++ b/test/qt/card/pcsc/test_PcscReaderManagerPlugIn.cpp @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ + +/*! + * \brief Unit tests for \ref PcscReaderManagerPlugIn + */ + +#include "PcscReaderManagerPlugIn.h" + +#include + +using namespace governikus; + + +class test_PcscReaderManagerPlugIn + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void addReaders() + { +#if !(defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) && !defined(Q_OS_FREEBSD) + QSKIP("Using LD_PRELOAD is not supported"); +#endif + + const QString readerName = QStringLiteral("PCSC"); + + PcscReaderManagerPlugIn plugin; + QCOMPARE(plugin.objectName(), QStringLiteral("PcscReaderManager")); + QVERIFY(plugin.getReaders().isEmpty()); + + QSignalSpy spyAdded(&plugin, &PcscReaderManagerPlugIn::fireReaderAdded); + QTest::ignoreMessage(QtDebugMsg, QStringLiteral("fireReaderAdded: \"%1\" ( 1 reader in total )").arg(readerName).toUtf8().data()); + plugin.addReaders({readerName}); + QCOMPARE(spyAdded.size(), 1); + QCOMPARE(plugin.getReaders().size(), 1); + } + + +}; + +QTEST_GUILESS_MAIN(test_PcscReaderManagerPlugIn) +#include "test_PcscReaderManagerPlugIn.moc" 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/simulator/test_SimulatorCard.cpp b/test/qt/card/simulator/test_SimulatorCard.cpp index 0c462030a..4653e5c9a 100644 --- a/test/qt/card/simulator/test_SimulatorCard.cpp +++ b/test/qt/card/simulator/test_SimulatorCard.cpp @@ -67,6 +67,16 @@ class test_SimulatorCard "56A7864104373CD3BAD6245F6EDEB382E066C57107B84BF5EF2834201AAEA41CC0D472890308" "3687C8C37C1D005C61BE2C122364101C2CBC41FFC3EC48C96E3F1D4F646ABE8701010100") << QByteArray::fromHex("7C2281206C877EC6E470BCC1C40F5AAC180D90EDB907AC091E33D402BDD3C99CD0DDE5039000"); + QTest::newRow("generalAuthenticateRi - wrong key") + << QByteArray::fromHex("008600000001257C820121A082011D060A04007F000702020502018120A9FB57DBA1EEA9BC3E" + "660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF6753041" + "7AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF95" + "8416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1" + "E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D" + "54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E829748" + "56A7864104373CD3BAD6245F6EDEB382E066C57107B84BF5EF2834201AAEA41CC0D472890308" + "3687C8C37C1D005C61BE2C122364101C2CBC41FFC3EC48C96E3F1D4F646ABE8701010100") + << QByteArray::fromHex("6981"); QTest::newRow("verify - existing") << QByteArray::fromHex("802080000B060904007f000703010403") << QByteArray::fromHex("9000"); QTest::newRow("verify - unknown") << QByteArray::fromHex("802080000B060904007f000703010404") << QByteArray::fromHex("6300"); QTest::newRow("verify - not proprietary") << QByteArray::fromHex("002080000B060904007f000703010403") << QByteArray::fromHex("6E00"); @@ -79,6 +89,9 @@ class test_SimulatorCard QFETCH(QByteArray, response); SimulatorCard card((SimulatorFileSystem())); + // Fill mCaKeyId for the restricted identification + card.transmit(CommandApdu(QByteArray::fromHex("002241A40F800A04007F00070202030202840129"))); + // Fill mRiKeyId for the restricted identification card.transmit(CommandApdu(QByteArray::fromHex("002241A40F800A04007F00070202050203840101"))); diff --git a/test/qt/card/simulator/test_SimulatorFileSystem.cpp b/test/qt/card/simulator/test_SimulatorFileSystem.cpp index 21e677a50..64be8ef22 100644 --- a/test/qt/card/simulator/test_SimulatorFileSystem.cpp +++ b/test/qt/card/simulator/test_SimulatorFileSystem.cpp @@ -9,6 +9,7 @@ #include "ResourceLoader.h" #include "TestFileHelper.h" +#include #include #include @@ -40,24 +41,36 @@ class test_SimulatorFileSystem void initTestCase() { - QJsonObject file; - file.insert("fileId", QJsonValue("0101")); - file.insert("shortFileId", QJsonValue("01")); - QJsonValue value(file); - - QJsonArray innerArray; - innerArray.append(value); - - QJsonArray array; - array.append(QJsonValue(innerArray)); - array.append(QJsonValue(value)); - - QJsonObject object; - object[QLatin1String("files")] = array; + QJsonDocument doc = QJsonDocument::fromJson(QByteArray(R"({ + "files": [ + [ + { + "fileId": "0101", + "shortFileId": "01" + } + ], + { + "fileId": "0101", + "shortFileId": "01" + } + ], + "keys": [ + [ + { + "id": 1 + } + ], + { + "id": 1 + } + ] +})")); QTest::ignoreMessage(QtWarningMsg, R"(Skipping file entry. Expected JSON object, got QJsonValue(array, QJsonArray([{"fileId":"0101","shortFileId":"01"}])))"); QTest::ignoreMessage(QtWarningMsg, R"(Skipping file entry. Expected JSON object with 'fileId', 'shortFileId' and 'content', got QJsonObject({"fileId":"0101","shortFileId":"01"}))"); - SimulatorFileSystem fs(object); + QTest::ignoreMessage(QtWarningMsg, R"(Skipping key entry. Expected JSON object, got QJsonValue(array, QJsonArray([{"id":1}])))"); + QTest::ignoreMessage(QtWarningMsg, R"(Skipping key entry. Expected JSON object with 'id' and 'private', got QJsonObject({"id":1}))"); + SimulatorFileSystem fs(doc.object()); } 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 9bc73f3a5..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, 20); + QCOMPARE(attachedEidCounter, 19); } diff --git a/test/qt/configuration/test_ProviderConfigurationParser.cpp b/test/qt/configuration/test_ProviderConfigurationParser.cpp index e78c05468..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 = 112; - const int withEidSupport = 90; + 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 cb6dfe095..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)); } @@ -447,6 +485,12 @@ class test_LogHandler QTest::newRow("createSingleton") << QByteArray("T* governikus::Env::createSingleton() [with T = governikus::AppUpdater]") << QByteArray("Env::createSingleton"); + QTest::newRow("createSingletonPtr") << QByteArray("T *governikus::Env::createSingleton() [T = governikus::NetworkManager]") + << QByteArray("Env::createSingleton"); + + QTest::newRow("processUpdaterRequest") << QByteArray("auto governikus::NetworkManager::processUpdaterRequest(QNetworkRequest &, const std::function (QNetworkRequest &)> &)::(anonymous class)::operator()() const") + << QByteArray("NetworkManager::processUpdaterRequest"); + QTest::newRow("printInfo") << QByteArray("void printInfo()") << QByteArray("printInfo"); @@ -466,6 +510,8 @@ class test_LogHandler QTest::newRow("UILoader::load") << QByteArray("std::enable_if_t::value, bool> governikus::UILoader::load() const [with T = governikus::UIPlugInJson; std::enable_if_t::value, bool> = bool]") << QByteArray("UILoader::load"); + QTest::newRow("anonymous") << QByteArray("virtual QList (anonymous namespace)::SystemProxyFactory::queryProxy(const QNetworkProxyQuery &)") + << QByteArray("SystemProxyFactory::queryProxy"); } @@ -481,6 +527,15 @@ class test_LogHandler } + void formatFunctionNullptr() + { + const auto* handler = Env::getSingleton(); + const auto& formattedFunction = handler->formatFunction(nullptr, QByteArray(), 1811); + + QCOMPARE(formattedFunction, QByteArray()); + } + + }; QTEST_GUILESS_MAIN(test_LogHandler) 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 4b2e81f5b..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")); @@ -111,9 +169,11 @@ class test_RemoteIfdReaderManagerPlugIn Env::set(RemoteIfdClient::staticMetaObject, mIfdClient.data()); mDispatcher1.reset(new MockIfdDispatcher()); + mDispatcher1->setPairingConnection(false); mDispatcher1->moveToThread(&mNetworkThread); mDispatcher2.reset(new MockIfdDispatcher()); + mDispatcher2->setPairingConnection(true); mDispatcher2->moveToThread(&mNetworkThread); mPlugin.reset(new RemoteIfdReaderManagerPlugIn()); @@ -150,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); @@ -160,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); @@ -172,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); @@ -183,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); } @@ -246,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); @@ -266,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")); @@ -278,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")); @@ -289,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")); @@ -300,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")); @@ -309,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); } @@ -525,6 +655,72 @@ 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); + + Q_EMIT mIfdClient->fireNewDispatcher(mDispatcher1); + QTRY_COMPARE(spySend.count(), 1); // clazy:exclude=qstring-allocations + spySend.clear(); + + mPlugin->onContextEstablished(QStringLiteral("MAC-MINI"), mDispatcher1->getId()); + QTRY_COMPARE(spySend.count(), 1); // clazy:exclude=qstring-allocations + QSharedPointer result = qvariant_cast>(spySend.takeFirst().at(0)); + QCOMPARE(result->getType(), IfdMessageType::IFDGetStatus); + } + + + void testClosePairingConnection() + { + QSignalSpy spySend(mDispatcher2.data(), &MockIfdDispatcher::fireSend); + QSignalSpy spyClosed(mDispatcher2.data(), &MockIfdDispatcher::fireClosed); + + Q_EMIT mIfdClient->fireNewDispatcher(mDispatcher2); + QTRY_COMPARE(spySend.count(), 1); // clazy:exclude=qstring-allocations + + mPlugin->onContextEstablished(QStringLiteral("MAC-MINI"), mDispatcher2->getId()); + QTRY_COMPARE(spyClosed.count(), 1); // clazy:exclude=qstring-allocations + } + + }; QTEST_GUILESS_MAIN(test_RemoteIfdReaderManagerPlugIn) diff --git a/test/qt/ifd/remote/test_RemoteIfdServer.cpp b/test/qt/ifd/remote/test_RemoteIfdServer.cpp index 9ae1000b3..ea6488b87 100644 --- a/test/qt/ifd/remote/test_RemoteIfdServer.cpp +++ b/test/qt/ifd/remote/test_RemoteIfdServer.cpp @@ -98,6 +98,12 @@ class RemoteWebSocketServerMock } + [[nodiscard]] bool isPairingAnnounced() const override + { + return mPairing; + } + + void setPairing(bool pEnabled = true) override { mPairing = pEnabled; @@ -159,11 +165,11 @@ class test_RemoteIfdServer private Q_SLOTS: void init() { - std::function creator = [this](const QString& pIfdName, const QString& pIfdId, quint16& pPort){ + std::function creator = [this](const QString& pIfdName, const QString& pIfdId, quint16& pPort, bool&){ mAdvertiserMock = new RemoteReaderAdvertiserMock(pIfdName, pIfdId, pPort); return mAdvertiserMock; }; - Env::setCreator(creator); + Env::setCreator(creator); std::function creator2 = [this](){ mWebSocketMock = new RemoteWebSocketServerMock(); return mWebSocketMock; diff --git a/test/qt/ifd/remote/test_RemoteReaderAdvertiser.cpp b/test/qt/ifd/remote/test_RemoteReaderAdvertiser.cpp index e1cd78291..09ad044b5 100644 --- a/test/qt/ifd/remote/test_RemoteReaderAdvertiser.cpp +++ b/test/qt/ifd/remote/test_RemoteReaderAdvertiser.cpp @@ -19,9 +19,9 @@ namespace governikus { -template<> RemoteReaderAdvertiser* createNewObject(const QString& pIfdName, const QString& pIfdId, quint16& pPort, int& pTimerInterval, bool& pPairing) +template<> RemoteReaderAdvertiser* createNewObject(const QString& pIfdName, const QString& pIfdId, quint16& pPort, int& pInterval, bool& pPairing) { - return new RemoteReaderAdvertiserImpl(pIfdName, pIfdId, pPort, pTimerInterval, pPairing); + return new RemoteReaderAdvertiserImpl(pIfdName, pIfdId, pPort, pPairing, pInterval); } diff --git a/test/qt/ifd/remote/test_RemoteTlsServer.cpp b/test/qt/ifd/remote/test_RemoteTlsServer.cpp index 6e431255c..616794c3d 100644 --- a/test/qt/ifd/remote/test_RemoteTlsServer.cpp +++ b/test/qt/ifd/remote/test_RemoteTlsServer.cpp @@ -57,6 +57,7 @@ class test_RemoteTlsServer RemoteTlsServer server; server.setPairing(serverPairing); server.startListening(0); + QCOMPARE(server.hasPsk(), serverPairing); auto config = Env::getSingleton()->getTlsConfigRemoteIfd(clientConfig).getConfiguration(); config.setPrivateKey(pair.getKey()); @@ -72,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); } @@ -91,6 +88,7 @@ class test_RemoteTlsServer }); server.setPairing(); server.startListening(0); + QVERIFY(server.hasPsk()); auto config = Env::getSingleton()->getTlsConfigRemoteIfd(SecureStorage::TlsSuite::PSK).getConfiguration(); config.setPrivateKey(pair.getKey()); diff --git a/test/qt/ifd/remote/test_RemoteWebSocketServer.cpp b/test/qt/ifd/remote/test_RemoteWebSocketServer.cpp index 7cd8b282c..0b9f3fcc0 100644 --- a/test/qt/ifd/remote/test_RemoteWebSocketServer.cpp +++ b/test/qt/ifd/remote/test_RemoteWebSocketServer.cpp @@ -176,6 +176,7 @@ class test_RemoteWebSocketServer PskHandler pskHandler(&client, mServer.data()); mServer->setPairing(); QVERIFY(mServer->listen(QStringLiteral("TestServer"))); + QVERIFY(mServer->isPairingAnnounced()); client.open(QString("wss://127.0.0.1:").append(QString::number(mServer->getServerPort()))); @@ -279,6 +280,7 @@ class test_RemoteWebSocketServer PskHandler pskHandler(&client, mServer.data()); mServer->setPairing(); client.open(QString("wss://127.0.0.1:").append(QString::number(mServer->getServerPort()))); + QVERIFY(mServer->isPairingAnnounced()); QTRY_COMPARE(newConnectionSpy.count(), 1); // clazy:exclude=qstring-allocations QTRY_COMPARE(serverConnectedSpy.count(), 1); // clazy:exclude=qstring-allocations diff --git a/test/qt/ifd/test_IfdConnector.cpp b/test/qt/ifd/test_IfdConnector.cpp index a3ce401c6..dc2b7e7ab 100644 --- a/test/qt/ifd/test_IfdConnector.cpp +++ b/test/qt/ifd/test_IfdConnector.cpp @@ -427,11 +427,7 @@ class test_IfdConnector QTRY_COMPARE(spyConnectorError.count(), 1); // clazy:exclude=qstring-allocations QCOMPARE(spyConnectorSuccess.count(), 0); -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) - verifyErrorSignal(spyConnectorError, {IfdErrorCode::CONNECTION_ERROR}, serverPort, QStringLiteral("Smartphone1")); -#else verifyErrorSignal(spyConnectorError, {IfdErrorCode::REMOTE_HOST_REFUSED_CONNECTION}, serverPort, QStringLiteral("Smartphone1")); -#endif QCOMPARE(spySocketError.count(), 0); QCOMPARE(spySocketSuccess.count(), 0); diff --git a/test/qt/ifd/test_IfdDispatcher.cpp b/test/qt/ifd/test_IfdDispatcher.cpp index 412ed370c..1cb2bd052 100644 --- a/test/qt/ifd/test_IfdDispatcher.cpp +++ b/test/qt/ifd/test_IfdDispatcher.cpp @@ -338,6 +338,22 @@ class test_IfdDispatcher } + void isNormalConnection() + { + const QSharedPointer clientChannel(new MockDataChannel(false)); + const QSharedPointer clientDispatcher(new IfdDispatcherClient(IfdVersion::Version::v2, clientChannel)); + QVERIFY(!clientDispatcher->isPairingConnection()); + } + + + void isPairingConnection() + { + const QSharedPointer clientChannel(new MockDataChannel(true)); + const QSharedPointer clientDispatcher(new IfdDispatcherClient(IfdVersion::Version::v2, clientChannel)); + QVERIFY(clientDispatcher->isPairingConnection()); + } + + }; QTEST_GUILESS_MAIN(test_IfdDispatcher) 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 0bae9449f..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); @@ -603,6 +604,82 @@ class test_ServerMessageHandler } + void ifdTransmit_data() + { + QTest::addColumn("sendProgressMessage"); + + QTest::newRow("Send message") << true; + QTest::newRow("Don't send message") << false; + } + + + void ifdTransmit() + { + QFETCH(bool, sendProgressMessage); + + QSignalSpy logSpy(Env::getSingleton()->getEventHandler(), &LogEventHandler::fireLog); + ServerMessageHandlerImpl serverMessageHandler(mDataChannel); + QString contextHandle; + ensureContext(contextHandle); + + QSignalSpy sendSpy(mDataChannel.data(), &MockDataChannel::fireSend); + + MockReader* reader = MockReaderManagerPlugIn::getInstance().addReader("test-reader"); + QTRY_COMPARE(sendSpy.count(), 1); // clazy:exclude=qstring-allocations + reader->setCard(MockCardConfig({ + {CardReturnCode::OK, QByteArray("9000")} + })); + QTRY_COMPARE(sendSpy.count(), 2); // clazy:exclude=qstring-allocations + const CardInfo cardInfo(CardType::EID_CARD, QSharedPointer(), 3, true); + ReaderInfo info = reader->getReaderInfo(); + info.setCardInfo(cardInfo); + reader->setReaderInfo(info); + QTRY_COMPARE(sendSpy.count(), 3); // clazy:exclude=qstring-allocations + sendSpy.clear(); + + const QByteArray ifdConnectMsg = IfdConnect(QStringLiteral("test-reader"), true).toByteArray(IfdVersion::Version::latest, contextHandle); + mDataChannel->onReceived(ifdConnectMsg); + + QTRY_COMPARE(sendSpy.count(), 1); // clazy:exclude=qstring-allocations + + const QList& connectResponseArguments = sendSpy.last(); + const QVariant connectResponseVariant = connectResponseArguments.at(0); + QVERIFY(connectResponseVariant.canConvert()); + + const IfdConnectResponse connectResponse(IfdMessage::parseByteArray(connectResponseVariant.toByteArray())); + QVERIFY(!connectResponse.isIncomplete()); + QCOMPARE(connectResponse.getType(), IfdMessageType::IFDConnectResponse); + QCOMPARE(connectResponse.getContextHandle(), contextHandle); + QVERIFY(!connectResponse.getSlotHandle().isEmpty()); + + QVERIFY(!connectResponse.resultHasError()); + QCOMPARE(connectResponse.getResultMinor(), ECardApiResult::Minor::null); + + sendSpy.clear(); + + QSignalSpy displayTextSpy(&serverMessageHandler, &ServerMessageHandler::fireDisplayTextChanged); + // Card connected, try to provoke message. + const QByteArray ifdTransmitMsg = IfdTransmit(connectResponse.getSlotHandle(), QByteArray("ABCDEF"), sendProgressMessage ? QStringLiteral("DummyText") : QString()).toByteArray(IfdVersion::Version::latest, contextHandle); + mDataChannel->onReceived(ifdTransmitMsg); + QTRY_COMPARE(sendSpy.count(), 1); // clazy:exclude=qstring-allocations + + const QList& transmitResponseArguments = sendSpy.last(); + const QVariant transmitResponseVariant = transmitResponseArguments.at(0); + QVERIFY(transmitResponseVariant.canConvert()); + + const IfdTransmitResponse transmitResponse(IfdMessage::parseByteArray(transmitResponseVariant.toByteArray())); + QVERIFY(!transmitResponse.isIncomplete()); + QCOMPARE(transmitResponse.getType(), IfdMessageType::IFDTransmitResponse); + QCOMPARE(transmitResponse.getContextHandle(), contextHandle); + QCOMPARE(transmitResponse.getSlotHandle(), connectResponse.getSlotHandle()); + QVERIFY(!transmitResponse.resultHasError()); + QCOMPARE(transmitResponse.getResultMinor(), ECardApiResult::Minor::null); + QCOMPARE(displayTextSpy.count(), sendProgressMessage ? 1 : 0); + + removeReaderAndConsumeMessages(QStringLiteral("test-reader")); + } + + void ifdEstablishPACEChannelWithBasicReaderNameSendsAL_Unknown_Error() { const bool pinpadModeToSave = Env::getSingleton()->getRemoteServiceSettings().getPinPadMode(); 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/settings/test_RemoteServiceSettings.cpp b/test/qt/settings/test_RemoteServiceSettings.cpp index 8dbe07f30..168c8097a 100644 --- a/test/qt/settings/test_RemoteServiceSettings.cpp +++ b/test/qt/settings/test_RemoteServiceSettings.cpp @@ -71,8 +71,16 @@ class test_RemoteServiceSettings void testPinPadMode() { RemoteServiceSettings settings; + QCOMPARE(settings.getPinPadMode(), true); + settings.setPinPadMode(false); QCOMPARE(settings.getPinPadMode(), false); - QCOMPARE(settings.getPinPadMode(), false); + } + + + void testShowAccessRights() + { + RemoteServiceSettings settings; + QCOMPARE(settings.getShowAccessRights(), false); settings.setPinPadMode(true); QCOMPARE(settings.getPinPadMode(), true); } 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 05f0e8cdc..daf89c637 100644 --- a/test/qt/ui/qml/test_ApplicationModel.cpp +++ b/test/qt/ui/qml/test_ApplicationModel.cpp @@ -8,6 +8,15 @@ #include "ApplicationModel.h" +#include "MockIfdServer.h" +#include "context/AuthContext.h" +#include "context/ChangePinContext.h" +#include "context/IfdServiceContext.h" +#include "context/SelfAuthContext.h" +#if __has_include("context/PersonalizationContext.h") + #include "context/PersonalizationContext.h" +#endif + #include using namespace governikus; @@ -42,6 +51,33 @@ class test_ApplicationModel } + void test_getCurrentWorkflow_data() + { + QTest::addColumn>("context"); + QTest::addColumn("workflow"); + + QTest::addRow("No Context") << QSharedPointer() << ApplicationModel::Workflow::WORKFLOW_NONE; + 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; +#if __has_include("context/PersonalizationContext.h") + QTest::addRow("PersonalizationContext") << QSharedPointer(new PersonalizationContext(QString())) << ApplicationModel::Workflow::WORKFLOW_SMART; +#endif + } + + + void test_getCurrentWorkflow() + { + QFETCH(QSharedPointer, context); + QFETCH(ApplicationModel::Workflow, workflow); + + auto model = Env::getSingleton(); + model->resetContext(context); + QCOMPARE(model->getCurrentWorkflow(), workflow); + } + + }; QTEST_MAIN(test_ApplicationModel) 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 8c52fd113..61fe4298d 100644 --- a/test/qt/ui/qml/test_CertificateDescriptionModel.cpp +++ b/test/qt/ui/qml/test_CertificateDescriptionModel.cpp @@ -8,8 +8,10 @@ #include "CertificateDescriptionModel.h" +#include "MockIfdServer.h" #include "TestAuthContext.h" #include "TestFileHelper.h" +#include "context/IfdServiceContext.h" #include #include @@ -27,10 +29,23 @@ class test_CertificateDescriptionModel CertificateDescriptionModel* mModel = nullptr; QSharedPointer mContext; + static EstablishPaceChannel createDataToParse(const PacePasswordId& pinId) + { + const QByteArray chat = QByteArray::fromHex("7F4C12060904007F00070301020253050000000F0F"); + const QByteArray certDescription = QByteArray::fromHex("30 8202A4" + " 06 0A 04007F00070301030103" + " A1 0E 0C0C442D547275737420476D6248" + " A3 3A 0C38476573616D7476657262616E64206465722064657574736368656E20566572736963686572756E67737769727473636861667420652E562E" + " A5 820248" + " 04 820244 4E616D652C20416E7363687269667420756E6420452D4D61696C2D4164726573736520646573204469656E737465616E626965746572733A0D0A476573616D7476657262616E64206465722064657574736368656E20566572736963686572756E67737769727473636861667420652E562E0D0A57696C68656C6D73747261C39F652034332F3433670D0A3130313137204265726C696E0D0A6265726C696E406764762E64650D0A0D0A4765736368C3A46674737A7765636B3A0D0A2D52656769737472696572756E6720756E64204C6F67696E20616D204744562D4D616B6C6572706F7274616C2D0D0A0D0A48696E7765697320617566206469652066C3BC722064656E204469656E737465616E626965746572207A757374C3A46E646967656E205374656C6C656E2C20646965206469652045696E68616C74756E672064657220566F7273636872696674656E207A756D20446174656E73636875747A206B6F6E74726F6C6C696572656E3A0D0A4265726C696E6572204265617566747261677465722066C3BC7220446174656E73636875747A20756E6420496E666F726D6174696F6E7366726569686569740D0A416E20646572205572616E696120342D31300D0A3130373837204265726C696E0D0A3033302F3133382038392D300D0A6D61696C626F7840646174656E73636875747A2D6265726C696E2E64650D0A687474703A2F2F7777772E646174656E73636875747A2D6265726C696E2E64650D0A416E737072656368706172746E65723A2044722E20416C6578616E64657220446978"); + + return EstablishPaceChannel(pinId, chat, certDescription); + } + private Q_SLOTS: void init() { - mContext.reset(new TestAuthContext(nullptr, ":/paos/DIDAuthenticateEAC1.xml")); + mContext.reset(new TestAuthContext(":/paos/DIDAuthenticateEAC1.xml")); mModel = Env::getSingleton(); } @@ -81,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); @@ -98,6 +113,21 @@ class test_CertificateDescriptionModel } + void test_IfdContext() + { + auto ifdContext = QSharedPointer::create(QSharedPointer::create()); + mModel->resetContext(ifdContext); + const auto& establishPaceChannel = createDataToParse(PacePasswordId::PACE_PIN); + ifdContext->setEstablishPaceChannel(QSharedPointer::create(QString(), establishPaceChannel, 6)); + + QCOMPARE(mModel->data(mModel->index(0), CertificateDescriptionModel::UserRoles::LABEL), QString("Provider")); + QCOMPARE(mModel->data(mModel->index(0), CertificateDescriptionModel::UserRoles::TEXT), QString("Gesamtverband der deutschen Versicherungswirtschaft e.V.\n")); + QCOMPARE(mModel->data(mModel->index(1), CertificateDescriptionModel::UserRoles::LABEL), QString("Certificate issuer")); + QCOMPARE(mModel->data(mModel->index(1), CertificateDescriptionModel::UserRoles::TEXT), QString("D-Trust GmbH\n")); + QCOMPARE(mModel->data(mModel->index(2), CertificateDescriptionModel::UserRoles::LABEL), QString("Provider information")); + } + + }; QTEST_GUILESS_MAIN(test_CertificateDescriptionModel) 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_RemoteDeviceFilterModel.cpp b/test/qt/ui/qml/test_RemoteDeviceFilterModel.cpp new file mode 100644 index 000000000..4d505f3e5 --- /dev/null +++ b/test/qt/ui/qml/test_RemoteDeviceFilterModel.cpp @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ + +/*! + * \brief Unit tests for \ref RemoteDeviceModel + */ + +#include "RemoteDeviceFilterModel.h" + +#include "RemoteDeviceModel.h" + +#include + + +using namespace governikus; + + +class test_RemoteDeviceFilterModel + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void test_FilterAcceptsRow() + { + QSharedPointer sourceModel = QSharedPointer::create(); + QSharedPointer filterModelAvail = QSharedPointer::create(sourceModel.data(), RemoteDeviceFilterModel::showAvailableAndPaired); + QSharedPointer filterModelUnavail = QSharedPointer::create(sourceModel.data(), RemoteDeviceFilterModel::showUnavailableAndPaired); + QSharedPointer filterModelAvailPair = QSharedPointer::create(sourceModel.data(), RemoteDeviceFilterModel::showActivePairingMode); + + const RemoteDeviceModelEntry availableEntry(QString("reader 1"), QString("test id"), true, false, true, false, QDateTime(QDate(2019, 5, 14), QTime(0, 0)), nullptr); + const RemoteDeviceModelEntry unavailableEntry(QString("reader 2"), QString("test id"), false, false, true, false, QDateTime(QDate(2019, 5, 14), QTime(0, 0)), nullptr); + const RemoteDeviceModelEntry availablePairingEntry(QString("reader 2"), QString("test id"), true, false, true, true, QDateTime(QDate(2019, 5, 14), QTime(0, 0)), nullptr); + + sourceModel->mAllRemoteReaders.insert(0, availableEntry); + sourceModel->mAllRemoteReaders.insert(1, unavailableEntry); + sourceModel->mAllRemoteReaders.insert(2, availablePairingEntry); + + QCOMPARE(filterModelAvail->filterAcceptsRow(0, QModelIndex()), true); + QCOMPARE(filterModelAvail->filterAcceptsRow(1, QModelIndex()), false); + + QCOMPARE(filterModelUnavail->filterAcceptsRow(0, QModelIndex()), false); + QCOMPARE(filterModelUnavail->filterAcceptsRow(1, QModelIndex()), true); + + QCOMPARE(filterModelAvailPair->filterAcceptsRow(0, QModelIndex()), false); + QCOMPARE(filterModelAvailPair->filterAcceptsRow(1, QModelIndex()), false); + QCOMPARE(filterModelAvailPair->filterAcceptsRow(2, QModelIndex()), true); + } + + +}; + +QTEST_MAIN(test_RemoteDeviceFilterModel) +#include "test_RemoteDeviceFilterModel.moc" diff --git a/test/qt/ui/qml/test_RemoteDeviceModel.cpp b/test/qt/ui/qml/test_RemoteDeviceModel.cpp index 73fe79908..0c806363b 100644 --- a/test/qt/ui/qml/test_RemoteDeviceModel.cpp +++ b/test/qt/ui/qml/test_RemoteDeviceModel.cpp @@ -2,6 +2,8 @@ * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ +#include "AppSettings.h" +#include "IfdDescriptor.h" #include "RemoteDeviceModel.h" #include @@ -42,6 +44,14 @@ class test_RemoteDeviceModel } + void test_IsPairing() + { + QVERIFY(!mEntry->isPairing()); + mEntry->setIsPairing(true); + QVERIFY(mEntry->isPairing()); + } + + void test_DeviceNameEscaped() { QCOMPARE(mEntry->getDeviceNameEscaped(), mName); @@ -76,7 +86,7 @@ class test_RemoteDeviceModel RemoteDeviceModelEntry entry1(name); const IfdDescriptor descriptor = IfdDescriptor(); QSharedPointer pointer(new IfdListEntry(descriptor)); - RemoteDeviceModelEntry entry2(name, id, true, true, true, time, pointer); + RemoteDeviceModelEntry entry2(name, id, true, true, true, true, time, pointer); QVERIFY(!entry1.isSupported()); QVERIFY(entry2.isSupported()); @@ -86,15 +96,23 @@ class test_RemoteDeviceModel void test_RemoteDeviceListEntry() { const QString name = QStringLiteral("name"); - + const QString id = QStringLiteral("id"); RemoteDeviceModelEntry entry1(name); QCOMPARE(entry1.getRemoteDeviceListEntry(), nullptr); - const IfdDescriptor descriptor = IfdDescriptor(); - QSharedPointer pointer(new IfdListEntry(descriptor)); - const QString id = QStringLiteral("id"); - RemoteDeviceModelEntry entry2(name, id, pointer); - QCOMPARE(entry2.getRemoteDeviceListEntry(), pointer); + const IfdDescriptor defaultDescriptor = IfdDescriptor(); + QSharedPointer listEntry1(new IfdListEntry(defaultDescriptor)); + RemoteDeviceModelEntry entry2(listEntry1); + QCOMPARE(entry2.getRemoteDeviceListEntry(), listEntry1); + + const Discovery discovery = Discovery(name, id, 11111, {IfdVersion::supported()}, true); + const IfdDescriptor descriptor = IfdDescriptor(discovery, QHostAddress::LocalHost, true); + QSharedPointer listEntry2(new IfdListEntry(descriptor)); + RemoteDeviceModelEntry entry3(listEntry2); + QCOMPARE(entry3.getRemoteDeviceListEntry(), listEntry2); + QCOMPARE(entry3.getId(), id); + QCOMPARE(entry3.getDeviceNameEscaped(), name); + QVERIFY(entry3.isSupported()); } @@ -111,17 +129,27 @@ class test_RemoteDeviceModel void test_RoleNames() { - QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::REMOTE_DEVICE_NAME)); - QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::LAST_CONNECTED)); - QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::DEVICE_ID)); - QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::IS_NETWORK_VISIBLE)); + QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::IS_LAST_ADDED_DEVICE)); + QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::LINK_QUALITY)); + QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::IS_PAIRING)); + QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::IS_PAIRED)); QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::IS_SUPPORTED)); + QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::IS_NETWORK_VISIBLE)); + QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::DEVICE_ID)); + QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::LAST_CONNECTED)); + QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::REMOTE_DEVICE_STATUS)); + QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::REMOTE_DEVICE_NAME)); QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("remoteDeviceName"))); + QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("remoteDeviceStatus"))); QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("lastConnected"))); QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("deviceId"))); QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("isNetworkVisible"))); QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("isSupported"))); + QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("isPaired"))); + QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("isPairing"))); + QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("linkQualityInPercent"))); + QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("isLastAddedDevice"))); } @@ -139,13 +167,18 @@ class test_RemoteDeviceModel QCOMPARE(mModel->getStatus(entry), QString("Not paired")); entry.setPaired(true); - QCOMPARE(mModel->getStatus(entry), QString("Paired, but unavailable")); + QCOMPARE(mModel->getStatus(entry), QString("Unavailable")); entry.setNetworkVisible(true); QCOMPARE(mModel->getStatus(entry), QString("Available")); entry.mSupported = false; QCOMPARE(mModel->getStatus(entry), QString("Paired, but unsupported")); + + entry.setNetworkVisible(true); + entry.mSupported = true; + entry.mIsPairing = true; + QCOMPARE(mModel->getStatus(entry), QString("Click to pair")); } @@ -166,8 +199,11 @@ class test_RemoteDeviceModel void test_GetRemoteDeviceListEntryModelIndex() { - QSharedPointer listEntry(new IfdListEntry(IfdDescriptor())); - RemoteDeviceModelEntry entry1(QString("entry 1"), QStringLiteral("01"), listEntry); + const Discovery discovery = Discovery(QStringLiteral("entry 1"), QStringLiteral("01"), 11111, {IfdVersion::supported()}, true); + const IfdDescriptor descriptor = IfdDescriptor(discovery, QHostAddress::LocalHost, true); + QSharedPointer listEntry(new IfdListEntry(descriptor)); + RemoteDeviceModelEntry entry1(listEntry); + RemoteDeviceModelEntry entry2(QString("entry 2")); mModel->mAllRemoteReaders << entry1 << entry2; @@ -193,7 +229,9 @@ class test_RemoteDeviceModel QTest::newRow("network visible") << RemoteDeviceModel::SettingsRemoteRoles::IS_NETWORK_VISIBLE << 1 << 0 << QVariant(bool(false)); QTest::newRow("supported") << RemoteDeviceModel::SettingsRemoteRoles::IS_SUPPORTED << 0 << 0 << QVariant(bool(true)); QTest::newRow("paired") << RemoteDeviceModel::SettingsRemoteRoles::IS_PAIRED << 0 << 0 << QVariant(bool(true)); + QTest::newRow("is pairing") << RemoteDeviceModel::SettingsRemoteRoles::IS_PAIRED << 0 << 0 << QVariant(bool(true)); QTest::newRow("link quality") << RemoteDeviceModel::SettingsRemoteRoles::LINK_QUALITY << 0 << 0 << QVariant(int(0)); + QTest::newRow("is last added device") << RemoteDeviceModel::SettingsRemoteRoles::IS_LAST_ADDED_DEVICE << 0 << 0 << QVariant(bool(false)); } @@ -206,7 +244,7 @@ class test_RemoteDeviceModel QVector readers; QSharedPointer listEntry(new IfdListEntry(IfdDescriptor())); - const RemoteDeviceModelEntry entry1(QString("reader 1"), QString("test id"), true, false, true, QDateTime(QDate(2019, 5, 14), QTime(0, 0)), listEntry); + const RemoteDeviceModelEntry entry1(QString("reader 1"), QString("test id"), true, false, true, false, QDateTime(QDate(2019, 5, 14), QTime(0, 0)), listEntry); const RemoteDeviceModelEntry entry2(QString("reader 2")); readers << entry1 << entry2; mModel->mAllRemoteReaders = readers; @@ -215,6 +253,28 @@ class test_RemoteDeviceModel } + void test_SetLastPairedReader() + { + const auto cert = QSslCertificate(); + + RemoteServiceSettings& settings = Env::getSingleton()->getRemoteServiceSettings(); + settings.addTrustedCertificate(cert); + + const auto dName = QStringLiteral("myDeviceName"); + const auto dId = QStringLiteral("myDeviceId"); + const auto disco = Discovery(dName, dId, 12345, {IfdVersion::Version::latest}, false); + const auto ifdDesc = IfdDescriptor(disco, QHostAddress(QStringLiteral("127.0.0.1"))); + const QSharedPointer remoteDeviceListEntry(new IfdListEntry(ifdDesc)); + + mModel->addOrUpdateReader(RemoteDeviceModelEntry(remoteDeviceListEntry)); + + QSignalSpy spy(mModel.get(), &RemoteDeviceModel::dataChanged); + mModel->setLastPairedReader(cert); + QTRY_COMPARE(spy.size(), 1); + QVERIFY(mModel->data(mModel->index(0), RemoteDeviceModel::IS_LAST_ADDED_DEVICE).toBool()); + } + + }; QTEST_MAIN(test_RemoteDeviceModel) diff --git a/test/qt/ui/qml/test_RemoteServiceModel.cpp b/test/qt/ui/qml/test_RemoteServiceModel.cpp index 17bb04396..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 @@ -28,19 +29,6 @@ class test_RemoteServiceModel RemoteServiceModel* mModel = nullptr; QSharedPointer mContext; - static EstablishPaceChannel createDataToParse(const PacePasswordId& pinId) - { - const QByteArray chat = QByteArray::fromHex("7F4C12060904007F00070301020253050000000F0F"); - const QByteArray certDescription = QByteArray::fromHex("30 8202A4" - " 06 0A 04007F00070301030103" - " A1 0E 0C0C442D547275737420476D6248" - " A3 3A 0C38476573616D7476657262616E64206465722064657574736368656E20566572736963686572756E67737769727473636861667420652E562E" - " A5 820248" - " 04 820244 4E616D652C20416E7363687269667420756E6420452D4D61696C2D4164726573736520646573204469656E737465616E626965746572733A0D0A476573616D7476657262616E64206465722064657574736368656E20566572736963686572756E67737769727473636861667420652E562E0D0A57696C68656C6D73747261C39F652034332F3433670D0A3130313137204265726C696E0D0A6265726C696E406764762E64650D0A0D0A4765736368C3A46674737A7765636B3A0D0A2D52656769737472696572756E6720756E64204C6F67696E20616D204744562D4D616B6C6572706F7274616C2D0D0A0D0A48696E7765697320617566206469652066C3BC722064656E204469656E737465616E626965746572207A757374C3A46E646967656E205374656C6C656E2C20646965206469652045696E68616C74756E672064657220566F7273636872696674656E207A756D20446174656E73636875747A206B6F6E74726F6C6C696572656E3A0D0A4265726C696E6572204265617566747261677465722066C3BC7220446174656E73636875747A20756E6420496E666F726D6174696F6E7366726569686569740D0A416E20646572205572616E696120342D31300D0A3130373837204265726C696E0D0A3033302F3133382038392D300D0A6D61696C626F7840646174656E73636875747A2D6265726C696E2E64650D0A687474703A2F2F7777772E646174656E73636875747A2D6265726C696E2E64650D0A416E737072656368706172746E65723A2044722E20416C6578616E64657220446978"); - - return EstablishPaceChannel(pinId, chat, certDescription); - } - private Q_SLOTS: void initTestCase() { @@ -63,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; @@ -119,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()); @@ -153,6 +152,86 @@ class test_RemoteServiceModel } + void test_getSupportedReaderPlugInTypes() + { + QVector supportedPlugIns {ReaderManagerPlugInType::NFC}; +#if __has_include("SmartManager.h") + supportedPlugIns << ReaderManagerPlugInType::SMART; +#endif + QCOMPARE(mModel->getSupportedReaderPlugInTypes(), supportedPlugIns); + } + + + void test_TransactionInfo() + { + mModel->resetRemoteServiceContext(mContext); + QCOMPARE(mModel->getTransactionInfo(), QString()); + } + + + void test_DisplayText_data() + { + QTest::addColumn("inputText"); + QTest::addColumn("outputText"); + QTest::addColumn("expectedPercentage"); + + QTest::newRow("positive two digits") << "Dummy Text\n15%" << "Dummy Text" << 15; + QTest::newRow("positive two digits with space") << "Dummy Text\n15 %" << "Dummy Text" << 15; + QTest::newRow("negative two digits") << "Dummy Text\n-15%" << "Dummy Text\n-15%" << 0; + QTest::newRow("positive two digits with percentage") << "Dummy Text\n15%" << "Dummy Text" << 15; + QTest::newRow("Whitespace input") << " " << " " << 0; + QTest::newRow("Special characters") << "!@#$%^&*()" << "!@#$%^&*()" << 0; + QTest::newRow("Digits only") << "12345" << "12345" << 0; + QTest::newRow("Single Digit") << "Dummy Text\n1%" << "Dummy Text" << 1; + QTest::newRow("Triple Digit") << "Dummy Text\n111%" << "Dummy Text\n111%" << 0; + QTest::newRow("100 Percent") << "Dummy Text\n100%" << "Dummy Text" << 100; + QTest::newRow("Quadruple Digit") << "Dummy Text\n1111%" << "Dummy Text\n1111%" << 0; + QTest::newRow("Real Number") << "Dummy Text\n11.1%" << "Dummy Text\n11.1%" << 0; + QTest::newRow("Zero Digit without Space") << "%" << "%" << 0; + QTest::newRow("Single Digit without Space") << "1%" << "" << 1; + QTest::newRow("Double Digit without Space") << "42%" << "" << 42; + QTest::newRow("Triple Digit without Space") << "100%" << "" << 100; + QTest::newRow("Zero Digit with Space") << " %" << " %" << 0; + QTest::newRow("Single Digit with Space") << "1 %" << "" << 1; + QTest::newRow("Double Digit with Space") << "42 %" << "" << 42; + QTest::newRow("Triple Digit with Space") << "100 %" << "" << 100; + + } + + + void test_DisplayText() + { + QFETCH(QString, inputText); + QFETCH(QString, outputText); + QFETCH(int, expectedPercentage); + + QSignalSpy spyDisplayTextChanged(mModel, &RemoteServiceModel::fireDisplayTextChanged); + + mModel->resetRemoteServiceContext(mContext); + mContext->setDisplayText(inputText); + QCOMPARE(spyDisplayTextChanged.count(), 1); + QCOMPARE(mModel->getDisplayText(), outputText); + QCOMPARE(mModel->getPercentage(), expectedPercentage); + } + + + void test_DisplayTextSignals() + { + QSignalSpy spyDisplayTextChanged(mModel, &RemoteServiceModel::fireDisplayTextChanged); + + QCOMPARE(mModel->getDisplayText(), ""); + QCOMPARE(mModel->getPercentage(), 0); + + mModel->resetRemoteServiceContext(mContext); + QCOMPARE(spyDisplayTextChanged.count(), 0); + mContext->setDisplayText("Dummy"); + QCOMPARE(spyDisplayTextChanged.count(), 1); + mContext->setDisplayText("Dummy"); + QCOMPARE(spyDisplayTextChanged.count(), 1); + + } + + }; QTEST_MAIN(test_RemoteServiceModel) 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 25e8a3e3c..7e78fa693 100644 --- a/test/qt/ui/qml/test_WorkflowModel.cpp +++ b/test/qt/ui/qml/test_WorkflowModel.cpp @@ -8,13 +8,20 @@ #include "WorkflowModel.h" +#include "Env.h" #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; @@ -24,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); @@ -103,9 +137,92 @@ class test_WorkflowModel } - void test_isSmartCardAllowed() + void test_isCurrentSmartCardAllowed() + { + WorkflowModel workflowModel; + QVERIFY2(!workflowModel.isCurrentSmartCardAllowed(), "Ensure that this will not crash when the model has no WorkflowContext."); + } + + + void test_startScanExplicitly() + { + QSharedPointer context(new TestWorkflowContext()); + QSignalSpy spy(context.data(), &WorkflowContext::fireReaderPlugInTypesChanged); + + WorkflowModel model; + model.resetWorkflowContext(context); + + model.startScanExplicitly(); + QTRY_COMPARE(spy.count(), 1); + QCOMPARE(spy.takeFirst().at(0).toBool(), true); + } + + + void test_hasCard() + { + WorkflowModel model; + QCOMPARE(model.hasCard(), false); + + QSharedPointer context(new TestWorkflowContext()); + model.resetWorkflowContext(context); + QCOMPARE(model.hasCard(), false); + + auto mockReader = MockReaderManagerPlugIn::getInstance().addReader("SomeReaderWithCard"); + auto info = mockReader->getReaderInfo(); + info.setCardInfo(CardInfo(CardType::EID_CARD, QSharedPointer(), 3, false, false, false)); + mockReader->setReaderInfo(info); + model.setReaderPlugInType(ReaderManagerPlugInType::MOCK); + QCOMPARE(model.hasCard(), true); + } + + + 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() { - QVERIFY(true); + 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)); + } + } 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 bee49e5e7..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; } @@ -142,11 +145,12 @@ class test_UIPlugInWebService { QTest::addColumn("url"); QTest::addColumn("header"); + QTest::addColumn("size"); QTest::addColumn("error"); - QTest::newRow("favicon") << QString("/favicon.ico") << QString("image/x-icon") << QNetworkReply::NoError; - QTest::newRow("logo") << QString("/images/html_templates/Logo_AusweisApp2.png") << QString("image/png") << QNetworkReply::NoError; - QTest::newRow("nothing") << QString("/images/html_templates/nothing.gif") << QString("text/plain; charset=utf-8") << QNetworkReply::ContentNotFoundError; + QTest::newRow("favicon") << QString("/favicon.ico") << QString("image/x-icon") << 94921 << 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; } @@ -154,11 +158,13 @@ class test_UIPlugInWebService { QFETCH(QString, url); QFETCH(QString, header); + QFETCH(int, size); QFETCH(QNetworkReply::NetworkError, error); HttpServerRequestor requestor; QSharedPointer reply = requestor.getRequest(getUrl(url)); QVERIFY(reply); + QCOMPARE(reply->readAll().size(), size); QCOMPARE(reply->error(), error); const auto& contentType = reply->header(QNetworkRequest::ContentTypeHeader); @@ -167,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); @@ -186,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; @@ -249,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 f5bee5ae9..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,6 +300,72 @@ class test_WorkflowContext } + 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() + { + QFETCH(MobileEidType, mobileEidType); + QFETCH(QVector, acceptedTypes); + QFETCH(bool, result); + + mContext->setAcceptedEidTypes(acceptedTypes); + + QCOMPARE(mContext->isMobileEidTypeAllowed(mobileEidType), result); + } + + }; QTEST_GUILESS_MAIN(test_WorkflowContext) 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_StateEstablishPaceChannelResponse.cpp b/test/qt/workflows/ifd/test_StateEstablishPaceChannelResponse.cpp index f6467ef3b..7c4d9456d 100644 --- a/test/qt/workflows/ifd/test_StateEstablishPaceChannelResponse.cpp +++ b/test/qt/workflows/ifd/test_StateEstablishPaceChannelResponse.cpp @@ -41,6 +41,12 @@ class MockServerMsgHandler } + void setAllowedCardTypes(const QVector& pAllowedCardTypes) override + { + Q_UNUSED(pAllowedCardTypes) + } + + QString getResponse() { return mResponse; diff --git a/test/qt/workflows/ifd/test_StateProcessIfdMessages.cpp b/test/qt/workflows/ifd/test_StateProcessIfdMessages.cpp index 5d533913b..9265c6baa 100644 --- a/test/qt/workflows/ifd/test_StateProcessIfdMessages.cpp +++ b/test/qt/workflows/ifd/test_StateProcessIfdMessages.cpp @@ -35,8 +35,8 @@ class test_StateProcessIfdMessages const QSharedPointer context(new IfdServiceContext(mIfdServer)); StateProcessIfdMessages state(context); state.run(); - QCOMPARE(state.mConnections.size(), 4); - QCOMPARE(state.mMessageConnections.size(), 6); + QCOMPARE(state.mConnections.size(), 3); + QCOMPARE(state.mMessageConnections.size(), 7); } @@ -50,7 +50,7 @@ class test_StateProcessIfdMessages QCOMPARE(state.mMessageConnections.size(), 0); state.onMessageHandlerAdded(messageHandler); - QCOMPARE(state.mMessageConnections.size(), 6); + QCOMPARE(state.mMessageConnections.size(), 7); } @@ -115,6 +115,21 @@ class test_StateProcessIfdMessages } + void test_OnDisplayTextChanged() + { + const QSharedPointer context(new IfdServiceContext(mIfdServer)); + StateProcessIfdMessages state(context); + QSignalSpy spy(context.data(), &IfdServiceContext::fireDisplayTextChanged); + + state.onDisplayTextChanged(QStringLiteral("dummy text")); + QCOMPARE(spy.count(), 1); + QCOMPARE(context->getDisplayText(), QStringLiteral("dummy text")); + state.onCardDisconnected(); + QCOMPARE(spy.count(), 2); + QCOMPARE(context->getDisplayText(), QStringLiteral("")); + } + + }; QTEST_GUILESS_MAIN(test_StateProcessIfdMessages) 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 69670c2dd..0c51ed6cc 100644 --- a/test/qt/workflows/personalization/test_StateGetChallenge.cpp +++ b/test/qt/workflows/personalization/test_StateGetChallenge.cpp @@ -4,12 +4,10 @@ #include "states/StateGetChallenge.h" -#include "LogHandler.h" #include "ResourceLoader.h" #include "context/PersonalizationContext.h" #include "MockNetworkReply.h" -#include "TestFileHelper.h" #include @@ -36,10 +34,8 @@ class test_StateGetChallenge void init() { - Env::getSingleton()->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()); } @@ -63,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 {}; @@ -72,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")); } @@ -80,12 +77,10 @@ class test_StateGetChallenge { mState->mReply.reset(new MockNetworkReply(), &QObject::deleteLater); - QSignalSpy logSpy(Env::getSingleton()->getEventHandler(), &LogEventHandler::fireLog); QSignalSpy spyAbort(mState.data(), &StateGetChallenge::fireAbort); + QTest::ignoreMessage(QtDebugMsg, "No valid challenge to prepare personalization"); mState->onNetworkReply(); - const QString logMsg(logSpy.takeLast().at(0).toString()); - QVERIFY(logMsg.contains("No valid challenge to prepare personalization")); QCOMPARE(spyAbort.count(), 1); QCOMPARE(mState->getContext()->getStatus(), GlobalStatus::Code::Workflow_Server_Incomplete_Information_Provided); QCOMPARE(mState->getContext()->getFailureCode() == FailureCode::Reason::Get_Challenge_Invalid, true); @@ -112,24 +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 logSpy(Env::getSingleton()->getEventHandler(), &LogEventHandler::fireLog); QSignalSpy spyAbort(mState.data(), &StateGetChallenge::fireAbort); mState->onNetworkReply(); - const QString logMsg(logSpy.takeLast().at(0).toString()); - QVERIFY(logMsg.contains("Network request failed")); 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 65922710a..1237d28ee 100644 --- a/test/qt/workflows/personalization/test_StateGetSessionId.cpp +++ b/test/qt/workflows/personalization/test_StateGetSessionId.cpp @@ -4,11 +4,9 @@ #include "states/StateGetSessionId.h" -#include "LogHandler.h" #include "context/PersonalizationContext.h" #include "MockNetworkReply.h" -#include "TestFileHelper.h" #include @@ -29,10 +27,8 @@ class test_StateGetSessionId private Q_SLOTS: void init() { - Env::getSingleton()->init(); mContext = QSharedPointer::create(QString()); - mState.reset(new StateGetSessionId(mContext)); - mState->setStateName("StateGetSessionId"); + mState.reset(StateBuilder::createState(mContext)); QVERIFY(mContext->getSessionIdentifier().isNull()); } @@ -56,33 +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 logSpy(Env::getSingleton()->getEventHandler(), &LogEventHandler::fireLog); QSignalSpy spyAbort(mState.data(), &StateGetSessionId::fireAbort); + const auto bytes = logMsg.toUtf8(); + QTest::ignoreMessage(QtDebugMsg, bytes.data()); mState->onNetworkReply(); - const QString logMsg(logSpy.takeLast().at(0).toString()); - QVERIFY(logMsg.contains("No valid sessionID to prepare personalization")); 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()); } @@ -98,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}" + })"); } @@ -106,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(); @@ -119,23 +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 logSpy(Env::getSingleton()->getEventHandler(), &LogEventHandler::fireLog); QSignalSpy spyAbort(mState.data(), &StateGetSessionId::fireAbort); mState->onNetworkReply(); - const QString logMsg(logSpy.takeLast().at(0).toString()); - QVERIFY(logMsg.contains("Network request failed")); 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 8fb687e72..c71f7184a 100644 --- a/test/qt/workflows/personalization/test_StatePreparePersonalization.cpp +++ b/test/qt/workflows/personalization/test_StatePreparePersonalization.cpp @@ -9,7 +9,6 @@ #include "context/PersonalizationContext.h" #include "MockNetworkManager.h" -#include "TestFileHelper.h" #include @@ -39,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()); @@ -79,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); } @@ -95,23 +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 logSpy(Env::getSingleton()->getEventHandler(), &LogEventHandler::fireLog); QSignalSpy spyAbort(mState.data(), &StatePreparePersonalization::fireAbort); mState->onNetworkReply(); - const QString logMsg(logSpy.takeLast().at(0).toString()); - QVERIFY(logMsg.contains("Network request failed")); 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); } @@ -119,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 f28a65f5d..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)); } @@ -78,29 +77,50 @@ class test_StateEstablishPaceChannel void test_Run_NoConnection() { mAuthContext->setEstablishPaceChannelType(PacePasswordId::PACE_PIN); - QSignalSpy spyAbort(mState.data(), &StateEstablishPaceChannel::fireAbort); + QSignalSpy spyNoCardConnection(mState.data(), &StateEstablishPaceChannel::fireNoCardConnection); QTest::ignoreMessage(QtDebugMsg, "No card connection available."); mState->run(); - QCOMPARE(spyAbort.count(), 1); - QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Establish_Pace_Channel_No_Card_Connection); + QCOMPARE(spyNoCardConnection.count(), 1); + QVERIFY(!mAuthContext->getFailureCode().has_value()); + } + + + 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); + 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(), initialProgress); + QCOMPARE(mAuthContext->getProgressMessage(), tr("The secure channel is opened")); } @@ -108,27 +128,26 @@ class test_StateEstablishPaceChannel { mAuthContext->setStatus(GlobalStatus::Code::Card_Cancellation_By_User); mAuthContext->setFailureCode(FailureCode::Reason::User_Cancelled); - QSignalSpy spyPropagateAbort(mState.data(), &StateEstablishPaceChannel::firePropagateAbort); + QSignalSpy spyPaceChannelFailed(mState.data(), &StateEstablishPaceChannel::firePaceChannelFailed); mState->run(); - QCOMPARE(spyPropagateAbort.count(), 1); + QCOMPARE(spyPaceChannelFailed.count(), 1); } void test_OnKillWorkflow() { QSignalSpy spyAbort(mState.data(), &AbstractState::fireAbort); - QSignalSpy spyPropagateAbort(mState.data(), &StateEstablishPaceChannel::firePropagateAbort); - mState->setStateName("StateEstablishPaceChannel"); + QSignalSpy spyPaceChannelFailed(mState.data(), &StateEstablishPaceChannel::firePaceChannelFailed); mState->onEntry(nullptr); QCOMPARE(spyAbort.count(), 0); - QCOMPARE(spyPropagateAbort.count(), 0); + QCOMPARE(spyPaceChannelFailed.count(), 0); mAuthContext->killWorkflow(); QTRY_COMPARE(spyAbort.count(), 1); // clazy:exclude=qstring-allocations - QTRY_COMPARE(spyPropagateAbort.count(), 1); // clazy:exclude=qstring-allocations + QTRY_COMPARE(spyPaceChannelFailed.count(), 1); // clazy:exclude=qstring-allocations } 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 32d3121c4..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()); @@ -131,7 +130,7 @@ class test_StateGenericProviderCommunication QCOMPARE(spy.count(), 1); const auto& failureCode = mState->getContext()->getFailureCode(); - QCOMPARE(failureCode, FailureCode::Reason::Generic_Provider_Communication_Ssl_Error); + QCOMPARE(failureCode, FailureCode::Reason::Generic_Provider_Communication_Tls_Error); QCOMPARE(failureCode->getFailureInfoMap()[FailureCode::Info::Network_Error], mState->mReply->errorString()); QCOMPARE(failureCode->getFailureInfoMap()[FailureCode::Info::Ssl_Errors], TlsChecker::sslErrorsToString(errorList)); } @@ -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 0a6cbea74..7bd1100d7 100644 --- a/test/qt/workflows/states/test_StateGetTcToken.cpp +++ b/test/qt/workflows/states/test_StateGetTcToken.cpp @@ -33,19 +33,19 @@ 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")); QSignalSpy spyAbort(&state, &StateGetTcToken::fireAbort); context->setTcTokenUrl(validUrl); - QTest::ignoreMessage(QtDebugMsg, "Got TC Token URL: QUrl(\"https://a.not.existing.valid.test.url.com\")"); + QTest::ignoreMessage(QtDebugMsg, "Fetch TCToken URL: QUrl(\"https://a.not.existing.valid.test.url.com\")"); state.run(); QCOMPARE(spyAbort.count(), 0); context->setTcTokenUrl(invalidUrl); - QTest::ignoreMessage(QtDebugMsg, "Got TC Token URL: QUrl(\"test\")"); + QTest::ignoreMessage(QtCriticalMsg, "TCToken URL is invalid: QUrl(\"test\")"); state.run(); QCOMPARE(spyAbort.count(), 1); QCOMPARE(context->getFailureCode(), FailureCode::Reason::Get_TcToken_Invalid_Url); @@ -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 4ba263363..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); } @@ -91,7 +90,7 @@ class test_StatePreVerification QTRY_COMPARE(spyAbort.count(), isValid ? 0 : 1); // clazy:exclude=qstring-allocations if (!isValid) { - QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verfication_Certificate_Expired); + QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verification_Certificate_Expired); } } @@ -104,7 +103,7 @@ class test_StatePreVerification mAuthContext->setStateApproved(); QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations - QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verfication_Certificate_Expired); + QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verification_Certificate_Expired); } @@ -116,7 +115,7 @@ class test_StatePreVerification mAuthContext->setStateApproved(); QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations - QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verfication_Invalid_Certificate_Chain); + QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verification_Invalid_Certificate_Chain); } @@ -124,19 +123,16 @@ 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); mAuthContext->setStateApproved(); QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations - QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verfication_Invalid_Certificate_Signature); + QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verification_Invalid_Certificate_Signature); } @@ -148,7 +144,7 @@ class test_StatePreVerification mAuthContext->setStateApproved(); QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations - QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verfication_Certificate_Expired); + QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verification_Certificate_Expired); } @@ -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_StatePreparePace.cpp b/test/qt/workflows/states/test_StatePreparePace.cpp index bd83b0c37..87ed27ae5 100644 --- a/test/qt/workflows/states/test_StatePreparePace.cpp +++ b/test/qt/workflows/states/test_StatePreparePace.cpp @@ -48,13 +48,13 @@ class test_StatePreparePace void test_Run_NoCardConnection() { - QSignalSpy spyAbort(mState.data(), &StatePreparePace::fireAbort); + QSignalSpy spyNoCardConnection(mState.data(), &StatePreparePace::fireNoCardConnection); QTest::ignoreMessage(QtDebugMsg, "Card connection lost."); mContext->setStateApproved(); - QTRY_COMPARE(spyAbort.count(), 1); // clazy:exclude=qstring-allocations + QTRY_COMPARE(spyNoCardConnection.count(), 1); // clazy:exclude=qstring-allocations QCOMPARE(mContext->getEstablishPaceChannelType(), PacePasswordId::UNKNOWN); - QCOMPARE(mContext->getFailureCode(), FailureCode::Reason::Prepace_Pace_No_Card_Connection); + QVERIFY(!mContext->getFailureCode().has_value()); } 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 a2fa945a3..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); } @@ -39,6 +39,24 @@ class test_StateStartPaosResponse } + void missingStartPAOSResponse() + { + QSignalSpy spyAbort(mState.data(), &StateStartPaosResponse::fireAbort); + + mAuthContext->setStateApproved(); + QTRY_COMPARE(spyAbort.count(), 1); // clazy:exclude=qstring-allocations + + const GlobalStatus& status = mState->getContext()->getStatus(); + QCOMPARE(status.getStatusCode(), GlobalStatus::Code::Workflow_Start_Paos_Response_Missing); + + const ECardApiResult& result = mState->getContext()->getStartPaosResult(); + QCOMPARE(result.getMajor(), ECardApiResult::Major::Ok); + QCOMPARE(result.getMinor(), ECardApiResult::Minor::null); + + QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Start_Paos_Response_Missing); + } + + void takeResultFromStartPAOSResponse() { QSharedPointer startPAOSResponse(new StartPaosResponse(TestFileHelper::readFile(":/paos/StartPAOSResponse3.xml"))); 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 8c23ce3b9..a4ff192bf 100644 --- a/test/qt/workflows/states/test_StateUpdRetryCounter.cpp +++ b/test/qt/workflows/states/test_StateUpdRetryCounter.cpp @@ -55,12 +55,14 @@ class test_StateUpdateRetryCounter StateUpdateRetryCounter counter(context); QSignalSpy spyContinue(&counter, &StateUpdateRetryCounter::fireContinue); QSignalSpy spyAbort(&counter, &StateUpdateRetryCounter::fireAbort); + QSignalSpy spyNoCardConnection(&counter, &StateUpdateRetryCounter::fireNoCardConnection); QTest::ignoreMessage(QtDebugMsg, "No card connection available."); counter.run(); QCOMPARE(spyContinue.count(), 0); - QCOMPARE(spyAbort.count(), 1); - QCOMPARE(context->getFailureCode(), FailureCode::Reason::Update_Retry_Counter_No_Card_Connection); + QCOMPARE(spyAbort.count(), 0); + QCOMPARE(spyNoCardConnection.count(), 1); + QVERIFY(!context->getFailureCode().has_value()); } @@ -72,13 +74,14 @@ class test_StateUpdateRetryCounter const QSharedPointer command(new MockCardCommand(worker)); QSignalSpy spyContinue(&counter, &StateUpdateRetryCounter::fireContinue); QSignalSpy spyAbort(&counter, &StateUpdateRetryCounter::fireAbort); + QSignalSpy spyNoCardConnection(&counter, &StateUpdateRetryCounter::fireNoCardConnection); QTest::ignoreMessage(QtDebugMsg, "StateUpdateRetryCounter::onUpdateRetryCounterDone()"); - QTest::ignoreMessage(QtCriticalMsg, "An error 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(), 1); - QCOMPARE(context->getFailureCode(), FailureCode::Reason::Update_Retry_Counter_Communication_Error); - + QCOMPARE(spyAbort.count(), 0); + QCOMPARE(spyNoCardConnection.count(), 1); + QVERIFY(!context->getFailureCode().has_value()); command->setMockReturnCode(CardReturnCode::OK); context->setCardConnection(QSharedPointer::create()); QTest::ignoreMessage(QtDebugMsg, "StateUpdateRetryCounter::onUpdateRetryCounterDone()"); diff --git a/test/qt/workflows/states/test_StateVerifyRetryCounter.cpp b/test/qt/workflows/states/test_StateVerifyRetryCounter.cpp index 2bbfeacb4..6e3b0b198 100644 --- a/test/qt/workflows/states/test_StateVerifyRetryCounter.cpp +++ b/test/qt/workflows/states/test_StateVerifyRetryCounter.cpp @@ -66,12 +66,12 @@ class test_StateVerifyRetryCounter void test_Run_NoConnection() { - QSignalSpy spyAbort(mState.data(), &StateVerifyRetryCounter::fireAbort); + QSignalSpy spyNoCardConnection(mState.data(), &StateVerifyRetryCounter::fireNoCardConnection); QTest::ignoreMessage(QtDebugMsg, "Card connection lost."); mContext->setStateApproved(); - QTRY_COMPARE(spyAbort.count(), 1); // clazy:exclude=qstring-allocations - QCOMPARE(mContext->getFailureCode(), FailureCode::Reason::Verify_Retry_Counter_No_Card_Connection); + QTRY_COMPARE(spyNoCardConnection.count(), 1); // clazy:exclude=qstring-allocations + QVERIFY(!mContext->getFailureCode().has_value()); } diff --git a/test/qt/workflows/states/test_StateWriteHistory.cpp b/test/qt/workflows/states/test_StateWriteHistory.cpp deleted file mode 100644 index fec2f6e8e..000000000 --- a/test/qt/workflows/states/test_StateWriteHistory.cpp +++ /dev/null @@ -1,147 +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_RunNoEffectiveAccessRights() - { - QSignalSpy spyAbort(mState.data(), &StateWriteHistory::fireAbort); - Env::getSingleton()->getHistorySettings().setEnabled(true); - *mContext->getAccessRightManager() = {}; - - QTest::ignoreMessage(QtWarningMsg, "No effective CHAT in context."); - mContext->setStateApproved(); - QTRY_COMPARE(spyAbort.count(), 1); // clazy:exclude=qstring-allocations - QCOMPARE(*mContext->getFailureCode(), FailureCode::Reason::Write_History_No_Chat); - } - - - 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);