mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-22 02:01:08 +07:00
add check access camera
This commit is contained in:
@@ -24,5 +24,9 @@
|
||||
<string name="notificationSettingsDialogMessage">To show notifications, you must enable notifications in the system settings</string>
|
||||
<string name="openNotificationSettings">Open notification settings</string>
|
||||
|
||||
<string name="cameraPermissionDialogTitle">Camera access</string>
|
||||
<string name="cameraPermissionDialogMessage">To scan a QR code for device pairing, Amnezia VPN needs access to the camera.</string>
|
||||
<string name="cameraPermissionContinue">Continue</string>
|
||||
|
||||
<string name="tvNoFileBrowser">Please install a file management utility to browse files</string>
|
||||
</resources>
|
||||
@@ -73,6 +73,7 @@ private const val CHECK_VPN_PERMISSION_ACTION_CODE = 1
|
||||
private const val CREATE_FILE_ACTION_CODE = 2
|
||||
private const val OPEN_FILE_ACTION_CODE = 3
|
||||
private const val CHECK_NOTIFICATION_PERMISSION_ACTION_CODE = 4
|
||||
private const val CHECK_CAMERA_PERMISSION_ACTION_CODE = 5
|
||||
|
||||
private const val PREFS_NOTIFICATION_PERMISSION_ASKED = "NOTIFICATION_PERMISSION_ASKED"
|
||||
private const val OPEN_FILE_AFTER_RESUME_DELAY_MS = 400L
|
||||
@@ -880,6 +881,66 @@ class AmneziaActivity : QtActivity() {
|
||||
@SuppressLint("UnsupportedChromeOsCameraSystemFeature")
|
||||
fun isCameraPresent(): Boolean = applicationContext.packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA)
|
||||
|
||||
@Suppress("unused")
|
||||
fun isCameraPermissionGranted(): Boolean =
|
||||
ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED
|
||||
|
||||
@Suppress("unused")
|
||||
fun requestCameraPermissionForQrPairing() {
|
||||
if (isCameraPermissionGranted()) {
|
||||
mainScope.launch {
|
||||
qtInitialized.await()
|
||||
QtAndroidController.onCameraPermissionResult(true)
|
||||
}
|
||||
return
|
||||
}
|
||||
runOnUiThread {
|
||||
AlertDialog.Builder(this)
|
||||
.setTitle(R.string.cameraPermissionDialogTitle)
|
||||
.setMessage(R.string.cameraPermissionDialogMessage)
|
||||
.setNegativeButton(R.string.cancel) { _, _ ->
|
||||
mainScope.launch {
|
||||
qtInitialized.await()
|
||||
QtAndroidController.onCameraPermissionResult(false)
|
||||
}
|
||||
}
|
||||
.setPositiveButton(R.string.cameraPermissionContinue) { _, _ ->
|
||||
requestPermission(
|
||||
Manifest.permission.CAMERA,
|
||||
CHECK_CAMERA_PERMISSION_ACTION_CODE,
|
||||
PermissionRequestHandler(
|
||||
onSuccess = {
|
||||
mainScope.launch {
|
||||
qtInitialized.await()
|
||||
QtAndroidController.onCameraPermissionResult(true)
|
||||
}
|
||||
},
|
||||
onFail = {
|
||||
mainScope.launch {
|
||||
qtInitialized.await()
|
||||
QtAndroidController.onCameraPermissionResult(false)
|
||||
}
|
||||
},
|
||||
onAny = {}
|
||||
)
|
||||
)
|
||||
}
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
fun openApplicationDetailsSettings() {
|
||||
try {
|
||||
Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
|
||||
data = Uri.fromParts("package", packageName, null)
|
||||
startActivity(this)
|
||||
}
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
Log.e(TAG, "openApplicationDetailsSettings: $e")
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
fun isOnTv(): Boolean = applicationContext.packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)
|
||||
|
||||
@@ -1179,6 +1240,7 @@ class AmneziaActivity : QtActivity() {
|
||||
CREATE_FILE_ACTION_CODE -> "CREATE_FILE"
|
||||
OPEN_FILE_ACTION_CODE -> "OPEN_FILE"
|
||||
CHECK_NOTIFICATION_PERMISSION_ACTION_CODE -> "CHECK_NOTIFICATION_PERMISSION"
|
||||
CHECK_CAMERA_PERMISSION_ACTION_CODE -> "CHECK_CAMERA_PERMISSION"
|
||||
else -> actionCode.toString()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,4 +34,6 @@ object QtAndroidController {
|
||||
|
||||
external fun onActivityPaused()
|
||||
external fun onActivityResumed()
|
||||
|
||||
external fun onCameraPermissionResult(granted: Boolean)
|
||||
}
|
||||
@@ -44,6 +44,7 @@ set(SOURCES ${SOURCES}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/iosnotificationhandler.mm
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/iosglue.mm
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QRCodeReaderBase.mm
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/iosPairingCameraAccess.mm
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QtAppDelegate.mm
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/StoreKitController.mm
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/AmneziaSceneDelegateHooks.mm
|
||||
|
||||
@@ -49,6 +49,7 @@ set(SOURCES ${SOURCES}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/iosglue.mm
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QRCodeReaderBase.mm
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QtAppDelegate.mm
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/iosPairingCameraAccess_stub.cpp
|
||||
)
|
||||
|
||||
set(ICON_FILE ${CMAKE_CURRENT_SOURCE_DIR}/images/app.icns)
|
||||
|
||||
@@ -65,6 +65,7 @@ set(HEADERS ${HEADERS}
|
||||
${CLIENT_ROOT_DIR}/core/utils/utilities.h
|
||||
${CLIENT_ROOT_DIR}/core/utils/managementServer.h
|
||||
${CLIENT_ROOT_DIR}/core/utils/constants.h
|
||||
${CLIENT_ROOT_DIR}/platforms/ios/iosPairingCameraAccess.h
|
||||
)
|
||||
|
||||
# Mozilla headres
|
||||
@@ -155,6 +156,7 @@ set(SOURCES ${SOURCES}
|
||||
if(NOT IOS AND NOT MACOS_NE)
|
||||
set(SOURCES ${SOURCES}
|
||||
${CLIENT_ROOT_DIR}/platforms/ios/QRCodeReaderBase.cpp
|
||||
${CLIENT_ROOT_DIR}/platforms/ios/iosPairingCameraAccess_stub.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -104,7 +104,8 @@ bool AndroidController::initialize()
|
||||
{"onImeInsetsChanged", "(I)V", reinterpret_cast<void *>(onImeInsetsChanged)},
|
||||
{"onSystemBarsInsetsChanged", "(II)V", reinterpret_cast<void *>(onSystemBarsInsetsChanged)},
|
||||
{"onActivityPaused", "()V", reinterpret_cast<void *>(onActivityPaused)},
|
||||
{"onActivityResumed", "()V", reinterpret_cast<void *>(onActivityResumed)}
|
||||
{"onActivityResumed", "()V", reinterpret_cast<void *>(onActivityResumed)},
|
||||
{"onCameraPermissionResult", "(Z)V", reinterpret_cast<void *>(onCameraPermissionResult)}
|
||||
};
|
||||
|
||||
QJniEnvironment env;
|
||||
@@ -202,6 +203,21 @@ bool AndroidController::isCameraPresent()
|
||||
return callActivityMethod<jboolean>("isCameraPresent", "()Z");
|
||||
}
|
||||
|
||||
bool AndroidController::isCameraPermissionGranted()
|
||||
{
|
||||
return callActivityMethod<jboolean>("isCameraPermissionGranted", "()Z");
|
||||
}
|
||||
|
||||
void AndroidController::requestCameraPermissionForQrPairing()
|
||||
{
|
||||
callActivityMethod("requestCameraPermissionForQrPairing", "()V");
|
||||
}
|
||||
|
||||
void AndroidController::openApplicationDetailsSettings()
|
||||
{
|
||||
callActivityMethod("openApplicationDetailsSettings", "()V");
|
||||
}
|
||||
|
||||
bool AndroidController::isOnTv()
|
||||
{
|
||||
return callActivityMethod<jboolean>("isOnTv", "()Z");
|
||||
@@ -583,4 +599,13 @@ void AndroidController::onActivityResumed(JNIEnv *env, jobject thiz)
|
||||
emit AndroidController::instance()->activityResumed();
|
||||
}
|
||||
|
||||
// static
|
||||
void AndroidController::onCameraPermissionResult(JNIEnv *env, jobject thiz, jboolean granted)
|
||||
{
|
||||
Q_UNUSED(env);
|
||||
Q_UNUSED(thiz);
|
||||
|
||||
emit AndroidController::instance()->cameraPermissionResult(static_cast<bool>(granted));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -38,6 +38,9 @@ public:
|
||||
void closeFd();
|
||||
QString getFileName(const QString &uri);
|
||||
bool isCameraPresent();
|
||||
bool isCameraPermissionGranted();
|
||||
void requestCameraPermissionForQrPairing();
|
||||
void openApplicationDetailsSettings();
|
||||
bool isOnTv();
|
||||
bool isEdgeToEdgeEnabled();
|
||||
int getStatusBarHeight();
|
||||
@@ -77,6 +80,7 @@ signals:
|
||||
void systemBarsInsetsChanged(int navBarHeightDp, int statusBarHeightDp);
|
||||
void activityPaused();
|
||||
void activityResumed();
|
||||
void cameraPermissionResult(bool granted);
|
||||
|
||||
private:
|
||||
bool isWaitingStatus = true;
|
||||
@@ -109,6 +113,7 @@ private:
|
||||
static void onSystemBarsInsetsChanged(JNIEnv *env, jobject thiz, jint navBarHeightDp, jint statusBarHeightDp);
|
||||
static void onActivityPaused(JNIEnv *env, jobject thiz);
|
||||
static void onActivityResumed(JNIEnv *env, jobject thiz);
|
||||
static void onCameraPermissionResult(JNIEnv *env, jobject thiz, jboolean granted);
|
||||
|
||||
template <typename Ret, typename ...Args>
|
||||
static auto callActivityMethod(const char *methodName, const char *signature, Args &&...args);
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifndef IOS_PAIRING_CAMERA_ACCESS_H
|
||||
#define IOS_PAIRING_CAMERA_ACCESS_H
|
||||
|
||||
#include <functional>
|
||||
|
||||
bool amneziaIosPairingCameraAccessGranted();
|
||||
void amneziaIosRequestPairingCameraAccess(const std::function<void(bool)> &onDone);
|
||||
void amneziaIosOpenApplicationSettings();
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,37 @@
|
||||
#include "platforms/ios/iosPairingCameraAccess.h"
|
||||
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
bool amneziaIosPairingCameraAccessGranted()
|
||||
{
|
||||
const AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
|
||||
return status == AVAuthorizationStatusAuthorized;
|
||||
}
|
||||
|
||||
void amneziaIosRequestPairingCameraAccess(const std::function<void(bool)> &onDone)
|
||||
{
|
||||
const AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
|
||||
if (status == AVAuthorizationStatusAuthorized) {
|
||||
onDone(true);
|
||||
return;
|
||||
}
|
||||
if (status == AVAuthorizationStatusDenied || status == AVAuthorizationStatusRestricted) {
|
||||
onDone(false);
|
||||
return;
|
||||
}
|
||||
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo
|
||||
completionHandler:^(BOOL granted) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
onDone(static_cast<bool>(granted));
|
||||
});
|
||||
}];
|
||||
}
|
||||
|
||||
void amneziaIosOpenApplicationSettings()
|
||||
{
|
||||
NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
|
||||
if (url != nil) {
|
||||
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#include "platforms/ios/iosPairingCameraAccess.h"
|
||||
|
||||
bool amneziaIosPairingCameraAccessGranted()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void amneziaIosRequestPairingCameraAccess(const std::function<void(bool)> &onDone)
|
||||
{
|
||||
onDone(true);
|
||||
}
|
||||
|
||||
void amneziaIosOpenApplicationSettings() {}
|
||||
@@ -9,6 +9,8 @@
|
||||
#include <QTimer>
|
||||
#include <QUuid>
|
||||
|
||||
#include "platforms/ios/iosPairingCameraAccess.h"
|
||||
|
||||
#if defined(Q_OS_ANDROID)
|
||||
#include "platforms/android/android_controller.h"
|
||||
#endif
|
||||
@@ -109,6 +111,8 @@ PairingUiController::PairingUiController(PairingController *pairingController, S
|
||||
{
|
||||
#if defined(Q_OS_ANDROID)
|
||||
g_pairingUiForAndroidQr = this;
|
||||
connect(AndroidController::instance(), &AndroidController::cameraPermissionResult, this,
|
||||
[this](bool granted) { emit pairingCameraAccessFinished(granted); });
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -157,6 +161,40 @@ void PairingUiController::openPairingQrScanner()
|
||||
#endif
|
||||
}
|
||||
|
||||
bool PairingUiController::isPairingCameraAccessGranted() const
|
||||
{
|
||||
#if defined(Q_OS_ANDROID)
|
||||
return AndroidController::instance()->isCameraPermissionGranted();
|
||||
#elif defined(Q_OS_IOS)
|
||||
return amneziaIosPairingCameraAccessGranted();
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void PairingUiController::requestPairingCameraAccess()
|
||||
{
|
||||
#if defined(Q_OS_ANDROID)
|
||||
AndroidController::instance()->requestCameraPermissionForQrPairing();
|
||||
#elif defined(Q_OS_IOS)
|
||||
amneziaIosRequestPairingCameraAccess([this](bool granted) {
|
||||
QMetaObject::invokeMethod(
|
||||
this, [this, granted]() { emit pairingCameraAccessFinished(granted); }, Qt::QueuedConnection);
|
||||
});
|
||||
#else
|
||||
emit pairingCameraAccessFinished(true);
|
||||
#endif
|
||||
}
|
||||
|
||||
void PairingUiController::openPairingCameraAppSettings()
|
||||
{
|
||||
#if defined(Q_OS_ANDROID)
|
||||
AndroidController::instance()->openApplicationDetailsSettings();
|
||||
#elif defined(Q_OS_IOS)
|
||||
amneziaIosOpenApplicationSettings();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool PairingUiController::applyScannedTextAsPairingUuid(const QString &raw)
|
||||
{
|
||||
const QString t = raw.trimmed();
|
||||
|
||||
@@ -74,6 +74,13 @@ public slots:
|
||||
/** Android: system camera activity. iOS: toggle camera from QML. */
|
||||
void openPairingQrScanner();
|
||||
|
||||
/** Mobile: whether the app may use the camera for QR pairing (OS permission). Desktop: true. */
|
||||
Q_INVOKABLE bool isPairingCameraAccessGranted() const;
|
||||
/** Mobile: show rationale / system camera permission UI; emits pairingCameraAccessFinished. Desktop: emits granted. */
|
||||
Q_INVOKABLE void requestPairingCameraAccess();
|
||||
/** Open system settings for this app (camera can be enabled there). No-op on desktop. */
|
||||
Q_INVOKABLE void openPairingCameraAppSettings();
|
||||
|
||||
/** If \a raw contains a session UUID (not vpn://), emits pairingUuidFromScan and returns true. */
|
||||
bool applyScannedTextAsPairingUuid(const QString &raw);
|
||||
|
||||
@@ -97,6 +104,8 @@ signals:
|
||||
|
||||
void pairingUuidFromScan(const QString &uuid);
|
||||
void tvPairingUiPhaseChanged();
|
||||
/** After requestPairingCameraAccess(): true if OS granted camera access. */
|
||||
void pairingCameraAccessFinished(bool granted);
|
||||
|
||||
private:
|
||||
void setTvBusy(bool busy);
|
||||
|
||||
@@ -19,19 +19,103 @@ import "../Components"
|
||||
PageType {
|
||||
id: root
|
||||
|
||||
/** True after "Add Device via QR" until permission result or navigation. */
|
||||
property bool pendingOpenQrPageAfterCamera: false
|
||||
/** True after denial: user may enable camera in system settings; resume opens QR page when granted. */
|
||||
property bool waitingSettingsReturnForQrPage: false
|
||||
|
||||
function proceedOpenQrPairingPage() {
|
||||
PageController.goToPage(PageEnum.PageSettingsApiQrPairingSend)
|
||||
pendingOpenQrPageAfterCamera = false
|
||||
waitingSettingsReturnForQrPage = false
|
||||
}
|
||||
|
||||
function showCameraDeniedDrawer() {
|
||||
showQuestionDrawer(
|
||||
qsTr("Camera access is required"),
|
||||
qsTr("Allow camera access to scan the pairing QR code. You can enable it in the system settings for Amnezia VPN."),
|
||||
qsTr("Open settings"),
|
||||
qsTr("Cancel"),
|
||||
function() {
|
||||
PairingUiController.openPairingCameraAppSettings()
|
||||
},
|
||||
function() {
|
||||
waitingSettingsReturnForQrPage = false
|
||||
})
|
||||
}
|
||||
|
||||
function tryResumeQrPageAfterCameraSettings() {
|
||||
if (!waitingSettingsReturnForQrPage || !root.visible) {
|
||||
return
|
||||
}
|
||||
if (PairingUiController.isPairingCameraAccessGranted()) {
|
||||
proceedOpenQrPairingPage()
|
||||
}
|
||||
}
|
||||
|
||||
function openAddDeviceViaQr() {
|
||||
const maxC = ApiAccountInfoModel.data("maxDeviceCount")
|
||||
const activeC = ApiAccountInfoModel.data("activeDeviceCount")
|
||||
if (maxC > 0 && activeC >= maxC) {
|
||||
PageController.goToPage(PageEnum.PageSettingsApiDeviceLimit)
|
||||
} else {
|
||||
return
|
||||
}
|
||||
if (Qt.platform.os !== "android" && Qt.platform.os !== "ios") {
|
||||
PageController.goToPage(PageEnum.PageSettingsApiQrPairingSend)
|
||||
return
|
||||
}
|
||||
if (PairingUiController.isPairingCameraAccessGranted()) {
|
||||
proceedOpenQrPairingPage()
|
||||
return
|
||||
}
|
||||
pendingOpenQrPageAfterCamera = true
|
||||
PairingUiController.requestPairingCameraAccess()
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if (!visible) {
|
||||
pendingOpenQrPageAfterCamera = false
|
||||
waitingSettingsReturnForQrPage = false
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Qt.application
|
||||
|
||||
function onStateChanged() {
|
||||
if (Qt.application.state !== Qt.ApplicationActive) {
|
||||
return
|
||||
}
|
||||
root.tryResumeQrPageAfterCameraSettings()
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SettingsController
|
||||
|
||||
enabled: Qt.platform.os === "android"
|
||||
|
||||
function onActivityResumed() {
|
||||
root.tryResumeQrPageAfterCameraSettings()
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: PairingUiController
|
||||
|
||||
function onPairingCameraAccessFinished(granted) {
|
||||
if (!root.pendingOpenQrPageAfterCamera) {
|
||||
return
|
||||
}
|
||||
root.pendingOpenQrPageAfterCamera = false
|
||||
if (granted) {
|
||||
root.proceedOpenQrPairingPage()
|
||||
} else {
|
||||
root.waitingSettingsReturnForQrPage = true
|
||||
root.showCameraDeniedDrawer()
|
||||
}
|
||||
}
|
||||
|
||||
function onPhonePairingSucceeded() {
|
||||
const serverIndex = ServersUiController.getProcessedServerIndex()
|
||||
if (serverIndex < 0) {
|
||||
|
||||
@@ -6,6 +6,7 @@ import QRCodeReader 1.0
|
||||
import PageEnum 1.0
|
||||
import Style 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
import "../Controls2/TextTypes"
|
||||
import "../Config"
|
||||
@@ -23,6 +24,10 @@ PageType {
|
||||
property int lastInvalidPairingQrToastClockMs: 0
|
||||
/** iOS may deliver many QR frames; guard duplicate step transitions. */
|
||||
property bool addDeviceConfirmNavigationScheduled: false
|
||||
/** Mobile: waiting for camera permission before starting scan UI / Android scanner. */
|
||||
property bool awaitingCameraPermissionForScan: false
|
||||
/** After denial on scan screen: user may enable camera in settings. */
|
||||
property bool waitingSettingsReturnForScan: false
|
||||
|
||||
Timer {
|
||||
id: pairingCameraKickTimer
|
||||
@@ -31,6 +36,38 @@ PageType {
|
||||
onTriggered: root.restartPairingIosCamera()
|
||||
}
|
||||
|
||||
function startPairingScanAfterPermission() {
|
||||
if (Qt.platform.os === "android") {
|
||||
PairingUiController.openPairingQrScanner()
|
||||
} else if (Qt.platform.os === "ios") {
|
||||
root.pairingCameraOpen = true
|
||||
}
|
||||
}
|
||||
|
||||
function showScanCameraDeniedDrawer() {
|
||||
showQuestionDrawer(
|
||||
qsTr("Camera access is required"),
|
||||
qsTr("Allow camera access to scan the pairing QR code. You can enable it in the system settings for Amnezia VPN."),
|
||||
qsTr("Open settings"),
|
||||
qsTr("Cancel"),
|
||||
function() {
|
||||
PairingUiController.openPairingCameraAppSettings()
|
||||
},
|
||||
function() {
|
||||
root.waitingSettingsReturnForScan = false
|
||||
})
|
||||
}
|
||||
|
||||
function tryResumeScanAfterCameraSettings() {
|
||||
if (!root.waitingSettingsReturnForScan || !root.visible || root.pairingWizardStep !== 0) {
|
||||
return
|
||||
}
|
||||
if (PairingUiController.isPairingCameraAccessGranted()) {
|
||||
root.waitingSettingsReturnForScan = false
|
||||
root.startPairingScanAfterPermission()
|
||||
}
|
||||
}
|
||||
|
||||
function restartPairingIosCamera() {
|
||||
if (Qt.platform.os !== "ios" || !root.pairingCameraOpen) {
|
||||
return
|
||||
@@ -63,6 +100,7 @@ PageType {
|
||||
pairingQrReader.stopReading()
|
||||
root.pairingCameraOpen = false
|
||||
root.pairingWizardStep = 0
|
||||
root.waitingSettingsReturnForScan = false
|
||||
if (!root.keepPhonePairingInBackgroundOnClose && !PairingUiController.phonePairingBusy) {
|
||||
PairingUiController.cancelAllPairingActivity()
|
||||
}
|
||||
@@ -70,6 +108,27 @@ PageType {
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Qt.application
|
||||
|
||||
function onStateChanged() {
|
||||
if (Qt.application.state !== Qt.ApplicationActive) {
|
||||
return
|
||||
}
|
||||
root.tryResumeScanAfterCameraSettings()
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SettingsController
|
||||
|
||||
enabled: Qt.platform.os === "android"
|
||||
|
||||
function onActivityResumed() {
|
||||
root.tryResumeScanAfterCameraSettings()
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root
|
||||
function onPairingCameraOpenChanged() {
|
||||
@@ -161,6 +220,11 @@ PageType {
|
||||
}
|
||||
enabled: !PairingUiController.phonePairingBusy
|
||||
clickedFunc: function() {
|
||||
if (!PairingUiController.isPairingCameraAccessGranted()) {
|
||||
root.awaitingCameraPermissionForScan = true
|
||||
PairingUiController.requestPairingCameraAccess()
|
||||
return
|
||||
}
|
||||
if (Qt.platform.os === "android") {
|
||||
PairingUiController.openPairingQrScanner()
|
||||
} else {
|
||||
@@ -238,14 +302,6 @@ PageType {
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
|
||||
ParagraphTextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
text: qsTr("Devices available with Amnezia Premium: %1").arg(ApiAccountInfoModel.data("availableDeviceSlots"))
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
@@ -296,6 +352,19 @@ PageType {
|
||||
Connections {
|
||||
target: PairingUiController
|
||||
|
||||
function onPairingCameraAccessFinished(granted) {
|
||||
if (!root.awaitingCameraPermissionForScan) {
|
||||
return
|
||||
}
|
||||
root.awaitingCameraPermissionForScan = false
|
||||
if (granted) {
|
||||
root.startPairingScanAfterPermission()
|
||||
} else {
|
||||
root.waitingSettingsReturnForScan = true
|
||||
root.showScanCameraDeniedDrawer()
|
||||
}
|
||||
}
|
||||
|
||||
function onPairingUuidFromScan(uuid) {
|
||||
if (root.addDeviceConfirmNavigationScheduled) {
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user