diff --git a/headers/bluerockbackend.h b/headers/bluerockbackend.h index fa20efe..ffbef21 100644 --- a/headers/bluerockbackend.h +++ b/headers/bluerockbackend.h @@ -35,6 +35,10 @@ #include #include "QZXing.h" +#ifdef Q_OS_ANDROID +#include +#endif + #include "shareUtils/shareutils.h" class BlueRockBackend : public QObject @@ -54,10 +58,14 @@ signals: public slots: - QVariant getWidgetData(QVariantMap params); - QVariantMap getParamsFromUrl(QString url); - void shareResultsAsUrl(QString url, QString compName); - void shareResultsAsPoster(QString url, QString compName); + Q_INVOKABLE QVariant getWidgetData(QVariantMap params); + Q_INVOKABLE QVariantMap getParamsFromUrl(QString url); + Q_INVOKABLE void shareResultsAsUrl(QString url, QString compName); + Q_INVOKABLE void shareResultsAsPoster(QString url, QString compName); + + Q_INVOKABLE bool isCameraPermissionGranted(); + Q_INVOKABLE bool requestCameraPermission(); + #if defined(Q_OS_ANDROID) void onApplicationStateChanged(Qt::ApplicationState applicationState); #endif diff --git a/resources/qml/Components/QrCodeScanPopup.qml b/resources/qml/Components/QrCodeScanPopup.qml index 12469a3..1ebc2ca 100644 --- a/resources/qml/Components/QrCodeScanPopup.qml +++ b/resources/qml/Components/QrCodeScanPopup.qml @@ -31,7 +31,10 @@ Dialog { onOpened: { setDefaultStatusText() control._freezeScanning = false - cameraLoader.sourceComponent = cameraComponent + if(serverConn.isCameraPermissionGranted()) + cameraLoader.sourceComponent = cameraComponent + else + cameraLoader.sourceComponent = noPermissionComponent } onClosed: cameraLoader.sourceComponent = null @@ -168,6 +171,65 @@ Dialog { } } + Component { + id: noPermissionComponent + Item { + anchors.fill: parent + + Label { + id: noPermissionIcon + anchors { + top: parent.top + topMargin: parent.height * 0 + horizontalCenter: parent.horizontalCenter + } + font.pixelSize: parent.height * 0.3 + font.family: fa5solid.name + text: "\uf3ed" + } + Label { + id: noPermissionText + anchors { + top: noPermissionIcon.bottom + topMargin: noPermissionIcon.height * 0.15 + horizontalCenter: parent.horizontalCenter + } + + width: parent.width * 0.9 + + font.bold: true + font.pixelSize: noPermissionIcon.height * 0.15 + + horizontalAlignment: Text.AlignHCenter + + wrapMode: Text.Wrap + + //% "Camera permission denied!" + text: qsTrId("#cameraPermissionDenied") + } + + Label { + id: noPermissionDetailText + anchors { + top: noPermissionText.bottom + topMargin: noPermissionText.height * 0.15 + horizontalCenter: parent.horizontalCenter + } + + width: parent.width * 0.9 + + font.pixelSize: noPermissionText.font.pixelSize * 0.7 + + horizontalAlignment: Text.AlignHCenter + + wrapMode: Text.Wrap + + //% "This app requires access to your camera in order to scan QR-Codes. It will never record or store any photos or videos." + text: qsTrId("#cameraPermissionDeniedDetails") + } + + } + } QZXingFilter { id: zxingFilter diff --git a/resources/translations/de.qm b/resources/translations/de.qm index df728ad..0fa4d50 100644 Binary files a/resources/translations/de.qm and b/resources/translations/de.qm differ diff --git a/resources/translations/de.ts b/resources/translations/de.ts index 7928105..7028d3e 100644 --- a/resources/translations/de.ts +++ b/resources/translations/de.ts @@ -5,21 +5,33 @@ + Scan QR-Code QR-Code scannen - + Place the Code in the center Positioniere den Code in der Mitte + + + Camera permission denied! + + + + + This app requires access to your camera in order to scan QR-Codes. It will never record or store any photos or videos. + This app requires access to your camera in order to scan QR-Codes. It will never record store any photos or videos. + + - + Plase wait Bitte warten - + Invalid QR-Code Ungültiger QR-Code @@ -55,9 +67,8 @@ Jetzt kaufen für - This item is currently unavailable - Diese Produkt ist nicht verfügbar + Diese Produkt ist nicht verfügbar @@ -65,17 +76,18 @@ Das ist eine premium Funktion. - + + This item is currently unavailable Diese Produkt ist nicht verfügbar - + Restore purchase Kauf wiederherstellen - + contact support Support kontaktieren @@ -100,17 +112,17 @@ Über blueROCK - + Where are the IFSC results? Wo sind die IFSC Ergebnisse? - + Unfortunately, the IFSC has restricted the access to their data and <b>is not willing to share results with blueROCK anymore</b>. Because of this, blueROCK is no longer able to access and display IFSC results.<br><br>You can find current IFSC results <a href="https://ifsc.results.info">over here</a> and on <a href="https://ifsc-climbing.org">their website</a>. Leider hat die IFSC den Zugang zu ihren Ergebnissen eingeschränkt<b>und ist nicht mehr bereit, Ergebnisse mit blueROCK zu teilen</b>. Daher ist blueROCK nicht länger in der Lage auf IFSC Ergebnisse zuzugriefen und diese anzuzeigen.<br><br>Aktuelle IFSC Ergebnisse finden sich <a href="https://ifsc.results.info">hier</a> und auf der <a href="https://ifsc-climbing.org">IFSC Webseite</a>. - + This app was built using the <a href='https://qt.io'>Qt Framework</a> licensed under the <a href='https://www.gnu.org/licenses/lgpl-3.0.en.html'>GNU lgplV3 license</a>.<br><br>This app is open source and licensed under the <a href='https://www.gnu.org/licenses/agpl-3.0.en.html'>GNU agplV3 license</a>, the source code can be found <a href='https://itsblue.dev/dorian/blueROCK/'>here</a>.<br><br>Resultservice and rankings provided by <a href='http://www.digitalROCK.de'>digital ROCK</a>. Diese App wurde unter Verwendung des <a href='https://qt.io'>Qt Frameworks</a> unter der <a href='https://www.gnu.org/licenses/lgpl-3.0.en.html'>GNU lgplV3 Lizenz</a> erstellt.<br><br>Diese App ist Open-source und lizensiert unter der <a href='https://www.gnu.org/licenses/agpl-3.0.en.html'>GNU agplV3 Lizenz</a>. Der Sourcecode findet sich <a href='https://itsblue.dev/dorian/blueROCK/'>hier</a>.Die Ergebnisse und Ranglisten werden von <a href='http://www.digitalROCK.de'>digital ROCK</a> zur Verfügung gestellt. diff --git a/resources/translations/en.qm b/resources/translations/en.qm index bbc25d2..eb94bc0 100644 Binary files a/resources/translations/en.qm and b/resources/translations/en.qm differ diff --git a/resources/translations/en.ts b/resources/translations/en.ts index b7e3af6..6689a06 100644 --- a/resources/translations/en.ts +++ b/resources/translations/en.ts @@ -10,17 +10,28 @@ - + Place the Code in the center + + + Camera permission denied! + + + + + This app requires access to your camera in order to scan QR-Codes. It will never record or store any photos or videos. + This app requires access to your camera in order to scan QR-Codes. It will never record store any photos or videos. + + - + Plase wait - + Invalid QR-Code diff --git a/sources/bluerockbackend.cpp b/sources/bluerockbackend.cpp index 93a9f2b..6438387 100644 --- a/sources/bluerockbackend.cpp +++ b/sources/bluerockbackend.cpp @@ -130,8 +130,10 @@ void BlueRockBackend::shareResultsAsPoster(QString url, QString compName) { QPixmap barcode; int size = writer.width() * 0.5; + QZXingEncoderConfig encoderConfig(QZXing::EncoderFormat_QR_CODE, QSize(size, size), QZXing::EncodeErrorCorrectionLevel_M, false, false); barcode.convertFromImage(QZXing::encodeData(url, encoderConfig)); + painter.drawPixmap((writer.width() - size) / 2, size * 0.5, size, size, barcode); painter.end(); @@ -140,6 +142,73 @@ void BlueRockBackend::shareResultsAsPoster(QString url, QString compName) { this->_shareUtils->sendFile(path, compName, "application/pdf", 1); } +bool BlueRockBackend::isCameraPermissionGranted() { +#ifdef Q_OS_ANDROID + QtAndroid::PermissionResult cameraAccess = QtAndroid::checkPermission("android.permission.CAMERA"); + return cameraAccess == QtAndroid::PermissionResult::Granted; +#else + return false; +#endif +} + +bool BlueRockBackend::requestCameraPermission() { + if(this->isCameraPermissionGranted()) + return true; + +#ifdef Q_OS_ANDROID + // try to get permission + QtAndroid::PermissionResultMap resultMap = QtAndroid::requestPermissionsSync({"android.permission.CAMERA"}); + bool resultBool = true; + for(QtAndroid::PermissionResult result : resultMap) { + if(result != QtAndroid::PermissionResult::Granted) { + resultBool = false; + } + } + + if(resultBool) { + return true; + } + + // getting permission the traditional way failed -> open the settings app + QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;"); + if (activity.isValid()) + { + // get the package name + QAndroidJniObject context = QtAndroid::androidContext(); + QAndroidJniObject applicationPackageName = context.callObjectMethod("getPackageName"); + + QAndroidJniObject param = QAndroidJniObject::fromString("package:" + applicationPackageName.toString()); + + // Equivalent to Jave code: 'Uri uri = Uri::parse("...");' + QAndroidJniObject uri = QAndroidJniObject::callStaticObjectMethod("android/net/Uri", "parse", "(Ljava/lang/String;)Landroid/net/Uri;", param.object()); + if (!uri.isValid()) { + qWarning("ERROR: Unable to create Uri object"); + return false; + } + QAndroidJniObject packageName = QAndroidJniObject::fromString("android.settings.APPLICATION_DETAILS_SETTINGS"); + + QAndroidJniObject intent("android/content/Intent","(Ljava/lang/String;)V", packageName.object()); + if (!intent.isValid()) { + qWarning("ERROR: Unable to create Intent object"); + return false; + } + intent.callObjectMethod("addCategory", "(Ljava/lang/String;)Landroid/content/Intent;", QAndroidJniObject::fromString("android.intent.category.DEFAULT").object()); + intent.callObjectMethod("setData", "(Landroid/net/Uri;)Landroid/content/Intent;", uri.object()); + + activity.callMethod("startActivity","(Landroid/content/Intent;)V",intent.object()); + } + else { + qWarning() << "ERROR: Activity not valid!"; + return false; + } + + return true; +#else + return false; +#endif + +} + // ------------------------ // --- Helper functions --- // ------------------------