Started to implement propper permission handling

This commit is contained in:
Dorian Zedler 2021-06-21 16:03:42 +02:00
parent 9ca38f8651
commit 5a50ef8cbe
Signed by: dorian
GPG key ID: 989DE36109AFA354
7 changed files with 181 additions and 19 deletions

View file

@ -35,6 +35,10 @@
#include <QPdfWriter> #include <QPdfWriter>
#include "QZXing.h" #include "QZXing.h"
#ifdef Q_OS_ANDROID
#include <QtAndroidExtras>
#endif
#include "shareUtils/shareutils.h" #include "shareUtils/shareutils.h"
class BlueRockBackend : public QObject class BlueRockBackend : public QObject
@ -54,10 +58,14 @@ signals:
public slots: public slots:
QVariant getWidgetData(QVariantMap params); Q_INVOKABLE QVariant getWidgetData(QVariantMap params);
QVariantMap getParamsFromUrl(QString url); Q_INVOKABLE QVariantMap getParamsFromUrl(QString url);
void shareResultsAsUrl(QString url, QString compName); Q_INVOKABLE void shareResultsAsUrl(QString url, QString compName);
void shareResultsAsPoster(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) #if defined(Q_OS_ANDROID)
void onApplicationStateChanged(Qt::ApplicationState applicationState); void onApplicationStateChanged(Qt::ApplicationState applicationState);
#endif #endif

View file

@ -31,7 +31,10 @@ Dialog {
onOpened: { onOpened: {
setDefaultStatusText() setDefaultStatusText()
control._freezeScanning = false control._freezeScanning = false
cameraLoader.sourceComponent = cameraComponent if(serverConn.isCameraPermissionGranted())
cameraLoader.sourceComponent = cameraComponent
else
cameraLoader.sourceComponent = noPermissionComponent
} }
onClosed: cameraLoader.sourceComponent = null 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 { QZXingFilter {
id: zxingFilter id: zxingFilter

Binary file not shown.

View file

@ -5,21 +5,33 @@
<name></name> <name></name>
<message id="#scanQrCode"> <message id="#scanQrCode">
<location filename="../qml/Components/QrCodeScanPopup.qml" line="27"/> <location filename="../qml/Components/QrCodeScanPopup.qml" line="27"/>
<location filename="../qml/Pages/StartPage.qml" line="120"/>
<source>Scan QR-Code</source> <source>Scan QR-Code</source>
<translation>QR-Code scannen</translation> <translation>QR-Code scannen</translation>
</message> </message>
<message id="#placeQrCodeInCenter"> <message id="#placeQrCodeInCenter">
<location filename="../qml/Components/QrCodeScanPopup.qml" line="41"/> <location filename="../qml/Components/QrCodeScanPopup.qml" line="44"/>
<source>Place the Code in the center</source> <source>Place the Code in the center</source>
<translation>Positioniere den Code in der Mitte</translation> <translation>Positioniere den Code in der Mitte</translation>
</message> </message>
<message id="#cameraPermissionDenied">
<location filename="../qml/Components/QrCodeScanPopup.qml" line="208"/>
<source>Camera permission denied!</source>
<translation type="unfinished"></translation>
</message>
<message id="#cameraPermissionDeniedDetails">
<location filename="../qml/Components/QrCodeScanPopup.qml" line="228"/>
<source>This app requires access to your camera in order to scan QR-Codes. It will never record or store any photos or videos.</source>
<oldsource>This app requires access to your camera in order to scan QR-Codes. It will never record store any photos or videos.</oldsource>
<translation type="unfinished"></translation>
</message>
<message id="#pleaseWait"> <message id="#pleaseWait">
<location filename="../qml/Components/QrCodeScanPopup.qml" line="183"/> <location filename="../qml/Components/QrCodeScanPopup.qml" line="245"/>
<source>Plase wait</source> <source>Plase wait</source>
<translation>Bitte warten</translation> <translation>Bitte warten</translation>
</message> </message>
<message id="#invalidQrCode"> <message id="#invalidQrCode">
<location filename="../qml/Components/QrCodeScanPopup.qml" line="189"/> <location filename="../qml/Components/QrCodeScanPopup.qml" line="251"/>
<source>Invalid QR-Code</source> <source>Invalid QR-Code</source>
<translation>Ungültiger QR-Code</translation> <translation>Ungültiger QR-Code</translation>
</message> </message>
@ -55,9 +67,8 @@
<translation>Jetzt kaufen für</translation> <translation>Jetzt kaufen für</translation>
</message> </message>
<message id="#itemUnavailable"> <message id="#itemUnavailable">
<location filename="../qml/Components/SpeedFlowChartLocker.qml" line="36"/>
<source>This item is currently unavailable</source> <source>This item is currently unavailable</source>
<translation>Diese Produkt ist nicht verfügbar</translation> <translation type="vanished">Diese Produkt ist nicht verfügbar</translation>
</message> </message>
<message id="#thisIsAPremiumFeature"> <message id="#thisIsAPremiumFeature">
<location filename="../qml/Components/SpeedFlowChartLocker.qml" line="60"/> <location filename="../qml/Components/SpeedFlowChartLocker.qml" line="60"/>
@ -65,17 +76,18 @@
<translation>Das ist eine premium Funktion.</translation> <translation>Das ist eine premium Funktion.</translation>
</message> </message>
<message id="#itemIsUnavailable"> <message id="#itemIsUnavailable">
<location filename="../qml/Components/SpeedFlowChartLocker.qml" line="92"/> <location filename="../qml/Components/SpeedFlowChartLocker.qml" line="36"/>
<location filename="../qml/Components/SpeedFlowChartLocker.qml" line="91"/>
<source>This item is currently unavailable</source> <source>This item is currently unavailable</source>
<translation>Diese Produkt ist nicht verfügbar</translation> <translation>Diese Produkt ist nicht verfügbar</translation>
</message> </message>
<message id="#restorePurchase"> <message id="#restorePurchase">
<location filename="../qml/Components/SpeedFlowChartLocker.qml" line="108"/> <location filename="../qml/Components/SpeedFlowChartLocker.qml" line="107"/>
<source>Restore purchase</source> <source>Restore purchase</source>
<translation>Kauf wiederherstellen</translation> <translation>Kauf wiederherstellen</translation>
</message> </message>
<message id="#contact support"> <message id="#contact support">
<location filename="../qml/Components/SpeedFlowChartLocker.qml" line="119"/> <location filename="../qml/Components/SpeedFlowChartLocker.qml" line="118"/>
<source>contact support</source> <source>contact support</source>
<translation>Support kontaktieren</translation> <translation>Support kontaktieren</translation>
</message> </message>
@ -100,17 +112,17 @@
<translation>Über blueROCK</translation> <translation>Über blueROCK</translation>
</message> </message>
<message id="#ifscDisclaimerTitle"> <message id="#ifscDisclaimerTitle">
<location filename="../qml/Pages/StartPage.qml" line="164"/> <location filename="../qml/Pages/StartPage.qml" line="163"/>
<source>Where are the IFSC results?</source> <source>Where are the IFSC results?</source>
<translation>Wo sind die IFSC Ergebnisse?</translation> <translation>Wo sind die IFSC Ergebnisse?</translation>
</message> </message>
<message id="#ifscDisclaimer"> <message id="#ifscDisclaimer">
<location filename="../qml/Pages/StartPage.qml" line="166"/> <location filename="../qml/Pages/StartPage.qml" line="165"/>
<source>Unfortunately, the IFSC has restricted the access to their data and &lt;b&gt;is not willing to share results with blueROCK anymore&lt;/b&gt;. Because of this, blueROCK is no longer able to access and display IFSC results.&lt;br&gt;&lt;br&gt;You can find current IFSC results &lt;a href=&quot;https://ifsc.results.info&quot;&gt;over here&lt;/a&gt; and on &lt;a href=&quot;https://ifsc-climbing.org&quot;&gt;their website&lt;/a&gt;.</source> <source>Unfortunately, the IFSC has restricted the access to their data and &lt;b&gt;is not willing to share results with blueROCK anymore&lt;/b&gt;. Because of this, blueROCK is no longer able to access and display IFSC results.&lt;br&gt;&lt;br&gt;You can find current IFSC results &lt;a href=&quot;https://ifsc.results.info&quot;&gt;over here&lt;/a&gt; and on &lt;a href=&quot;https://ifsc-climbing.org&quot;&gt;their website&lt;/a&gt;.</source>
<translation>Leider hat die IFSC den Zugang zu ihren Ergebnissen eingeschränkt&lt;b&gt;und ist nicht mehr bereit, Ergebnisse mit blueROCK zu teilen&lt;/b&gt;. Daher ist blueROCK nicht länger in der Lage auf IFSC Ergebnisse zuzugriefen und diese anzuzeigen.&lt;br&gt;&lt;br&gt;Aktuelle IFSC Ergebnisse finden sich &lt;a href=&quot;https://ifsc.results.info&quot;&gt;hier&lt;/a&gt; und auf der &lt;a href=&quot;https://ifsc-climbing.org&quot;&gt;IFSC Webseite&lt;/a&gt;.</translation> <translation>Leider hat die IFSC den Zugang zu ihren Ergebnissen eingeschränkt&lt;b&gt;und ist nicht mehr bereit, Ergebnisse mit blueROCK zu teilen&lt;/b&gt;. Daher ist blueROCK nicht länger in der Lage auf IFSC Ergebnisse zuzugriefen und diese anzuzeigen.&lt;br&gt;&lt;br&gt;Aktuelle IFSC Ergebnisse finden sich &lt;a href=&quot;https://ifsc.results.info&quot;&gt;hier&lt;/a&gt; und auf der &lt;a href=&quot;https://ifsc-climbing.org&quot;&gt;IFSC Webseite&lt;/a&gt;.</translation>
</message> </message>
<message id="#aboutBluerockDisclaimer"> <message id="#aboutBluerockDisclaimer">
<location filename="../qml/Pages/StartPage.qml" line="174"/> <location filename="../qml/Pages/StartPage.qml" line="173"/>
<source>This app was built using the &lt;a href=&apos;https://qt.io&apos;&gt;Qt Framework&lt;/a&gt; licensed under the &lt;a href=&apos;https://www.gnu.org/licenses/lgpl-3.0.en.html&apos;&gt;GNU lgplV3 license&lt;/a&gt;.&lt;br&gt;&lt;br&gt;This app is open source and licensed under the &lt;a href=&apos;https://www.gnu.org/licenses/agpl-3.0.en.html&apos;&gt;GNU agplV3 license&lt;/a&gt;, the source code can be found &lt;a href=&apos;https://itsblue.dev/dorian/blueROCK/&apos;&gt;here&lt;/a&gt;.&lt;br&gt;&lt;br&gt;Resultservice and rankings provided by &lt;a href=&apos;http://www.digitalROCK.de&apos;&gt;digital ROCK&lt;/a&gt;.</source> <source>This app was built using the &lt;a href=&apos;https://qt.io&apos;&gt;Qt Framework&lt;/a&gt; licensed under the &lt;a href=&apos;https://www.gnu.org/licenses/lgpl-3.0.en.html&apos;&gt;GNU lgplV3 license&lt;/a&gt;.&lt;br&gt;&lt;br&gt;This app is open source and licensed under the &lt;a href=&apos;https://www.gnu.org/licenses/agpl-3.0.en.html&apos;&gt;GNU agplV3 license&lt;/a&gt;, the source code can be found &lt;a href=&apos;https://itsblue.dev/dorian/blueROCK/&apos;&gt;here&lt;/a&gt;.&lt;br&gt;&lt;br&gt;Resultservice and rankings provided by &lt;a href=&apos;http://www.digitalROCK.de&apos;&gt;digital ROCK&lt;/a&gt;.</source>
<translation type="unfinished">Diese App wurde unter Verwendung des &lt;a href=&apos;https://qt.io&apos;&gt;Qt Frameworks&lt;/a&gt; unter der &lt;a href=&apos;https://www.gnu.org/licenses/lgpl-3.0.en.html&apos;&gt;GNU lgplV3 Lizenz&lt;/a&gt; erstellt.&lt;br&gt;&lt;br&gt;Diese App ist Open-source und lizensiert unter der &lt;a href=&apos;https://www.gnu.org/licenses/agpl-3.0.en.html&apos;&gt;GNU agplV3 Lizenz&lt;/a&gt;. Der Sourcecode findet sich &lt;a href=&apos;https://itsblue.dev/dorian/blueROCK/&apos;&gt;hier&lt;/a&gt;.Die Ergebnisse und Ranglisten werden von &lt;a href=&apos;http://www.digitalROCK.de&apos;&gt;digital ROCK&lt;/a&gt; zur Verfügung gestellt.</translation> <translation type="unfinished">Diese App wurde unter Verwendung des &lt;a href=&apos;https://qt.io&apos;&gt;Qt Frameworks&lt;/a&gt; unter der &lt;a href=&apos;https://www.gnu.org/licenses/lgpl-3.0.en.html&apos;&gt;GNU lgplV3 Lizenz&lt;/a&gt; erstellt.&lt;br&gt;&lt;br&gt;Diese App ist Open-source und lizensiert unter der &lt;a href=&apos;https://www.gnu.org/licenses/agpl-3.0.en.html&apos;&gt;GNU agplV3 Lizenz&lt;/a&gt;. Der Sourcecode findet sich &lt;a href=&apos;https://itsblue.dev/dorian/blueROCK/&apos;&gt;hier&lt;/a&gt;.Die Ergebnisse und Ranglisten werden von &lt;a href=&apos;http://www.digitalROCK.de&apos;&gt;digital ROCK&lt;/a&gt; zur Verfügung gestellt.</translation>
</message> </message>

Binary file not shown.

View file

@ -10,17 +10,28 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message id="#placeQrCodeInCenter"> <message id="#placeQrCodeInCenter">
<location filename="../qml/Components/QrCodeScanPopup.qml" line="41"/> <location filename="../qml/Components/QrCodeScanPopup.qml" line="44"/>
<source>Place the Code in the center</source> <source>Place the Code in the center</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message id="#cameraPermissionDenied">
<location filename="../qml/Components/QrCodeScanPopup.qml" line="208"/>
<source>Camera permission denied!</source>
<translation type="unfinished"></translation>
</message>
<message id="#cameraPermissionDeniedDetails">
<location filename="../qml/Components/QrCodeScanPopup.qml" line="228"/>
<source>This app requires access to your camera in order to scan QR-Codes. It will never record or store any photos or videos.</source>
<oldsource>This app requires access to your camera in order to scan QR-Codes. It will never record store any photos or videos.</oldsource>
<translation type="unfinished"></translation>
</message>
<message id="#pleaseWait"> <message id="#pleaseWait">
<location filename="../qml/Components/QrCodeScanPopup.qml" line="183"/> <location filename="../qml/Components/QrCodeScanPopup.qml" line="245"/>
<source>Plase wait</source> <source>Plase wait</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message id="#invalidQrCode"> <message id="#invalidQrCode">
<location filename="../qml/Components/QrCodeScanPopup.qml" line="189"/> <location filename="../qml/Components/QrCodeScanPopup.qml" line="251"/>
<source>Invalid QR-Code</source> <source>Invalid QR-Code</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>

View file

@ -130,8 +130,10 @@ void BlueRockBackend::shareResultsAsPoster(QString url, QString compName) {
QPixmap barcode; QPixmap barcode;
int size = writer.width() * 0.5; int size = writer.width() * 0.5;
QZXingEncoderConfig encoderConfig(QZXing::EncoderFormat_QR_CODE, QSize(size, size), QZXing::EncodeErrorCorrectionLevel_M, false, false); QZXingEncoderConfig encoderConfig(QZXing::EncoderFormat_QR_CODE, QSize(size, size), QZXing::EncodeErrorCorrectionLevel_M, false, false);
barcode.convertFromImage(QZXing::encodeData(url, encoderConfig)); barcode.convertFromImage(QZXing::encodeData(url, encoderConfig));
painter.drawPixmap((writer.width() - size) / 2, size * 0.5, size, size, barcode); painter.drawPixmap((writer.width() - size) / 2, size * 0.5, size, size, barcode);
painter.end(); painter.end();
@ -140,6 +142,73 @@ void BlueRockBackend::shareResultsAsPoster(QString url, QString compName) {
this->_shareUtils->sendFile(path, compName, "application/pdf", 1); 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<jstring>("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<jstring>());
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<jstring>());
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<jstring>());
intent.callObjectMethod("setData", "(Landroid/net/Uri;)Landroid/content/Intent;", uri.object<jobject>());
activity.callMethod<void>("startActivity","(Landroid/content/Intent;)V",intent.object<jobject>());
}
else {
qWarning() << "ERROR: Activity not valid!";
return false;
}
return true;
#else
return false;
#endif
}
// ------------------------ // ------------------------
// --- Helper functions --- // --- Helper functions ---
// ------------------------ // ------------------------