mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-22 02:01:08 +07:00
remove old code
This commit is contained in:
@@ -66,30 +66,16 @@ class CameraActivity : ComponentActivity() {
|
|||||||
private var boundImageAnalysis: ImageAnalysis? = null
|
private var boundImageAnalysis: ImageAnalysis? = null
|
||||||
private var torchOn: Boolean = false
|
private var torchOn: Boolean = false
|
||||||
|
|
||||||
/** CameraX analyzer thread only; ML Kit Task callbacks use [ContextCompat.getMainExecutor] so they are not rejected after [ExecutorService.shutdown]. */
|
|
||||||
private var imageAnalysisExecutor: ExecutorService? = null
|
private var imageAnalysisExecutor: ExecutorService? = null
|
||||||
|
|
||||||
/** After a successful decode, ignore further frames (ML Kit otherwise hits "detector is already closed"). */
|
|
||||||
private val qrHandledOrClosing = AtomicBoolean(false)
|
private val qrHandledOrClosing = AtomicBoolean(false)
|
||||||
|
|
||||||
/**
|
|
||||||
* Pairing mode: QR was accepted by Qt ([decodeQrCode] true) and we are finishing normally.
|
|
||||||
* Do not apply JNI reopen cooldown on destroy — user may cancel confirm and return to scan immediately.
|
|
||||||
*/
|
|
||||||
private var pairingQrDeliveredToQt = false
|
private var pairingQrDeliveredToQt = false
|
||||||
|
|
||||||
/**
|
|
||||||
* Pairing mode: user closed camera via back / toolbar (not a successful scan).
|
|
||||||
* Skip JNI reopen cooldown — otherwise Qt stays on the black overlay shell until cooldown ends and a second back pops the page.
|
|
||||||
*/
|
|
||||||
private var pairingQrUserDismissedCamera = false
|
private var pairingQrUserDismissedCamera = false
|
||||||
|
|
||||||
private var barcodeScanner: BarcodeScanner? = null
|
private var barcodeScanner: BarcodeScanner? = null
|
||||||
|
|
||||||
/**
|
|
||||||
* [PreviewView.getOutputTransform] is main-thread-only; the image analyzer runs on a background
|
|
||||||
* executor. Refresh this cache whenever layout / preview geometry may change.
|
|
||||||
*/
|
|
||||||
private val cachedPreviewOutputTransform = AtomicReference<OutputTransform?>(null)
|
private val cachedPreviewOutputTransform = AtomicReference<OutputTransform?>(null)
|
||||||
|
|
||||||
private var previewTransformLayoutListener: View.OnLayoutChangeListener? = null
|
private var previewTransformLayoutListener: View.OnLayoutChangeListener? = null
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
#if !MACOS_NE
|
#if !MACOS_NE
|
||||||
#include "QRCodeReaderBase.h"
|
#include "QRCodeReaderBase.h"
|
||||||
|
|
||||||
#include "platforms/ios/iosPairingCameraAccess.h"
|
|
||||||
|
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
@@ -197,7 +195,6 @@ static UIWindow *amneziaKeyWindowForQrCamera(void)
|
|||||||
[self.videoPreviewPlayer setFrame:bounds];
|
[self.videoPreviewPlayer setFrame:bounds];
|
||||||
self.videoPreviewPlayer.zPosition = -1000.f;
|
self.videoPreviewPlayer.zPosition = -1000.f;
|
||||||
[keyWindow.layer insertSublayer:self.videoPreviewPlayer atIndex:0];
|
[keyWindow.layer insertSublayer:self.videoPreviewPlayer atIndex:0];
|
||||||
amneziaIosPairingRelayoutChromeIfNeeded();
|
|
||||||
|
|
||||||
AVCaptureSession *runningSession = self.captureSession;
|
AVCaptureSession *runningSession = self.captureSession;
|
||||||
dispatch_async(_sessionQueue, ^{
|
dispatch_async(_sessionQueue, ^{
|
||||||
|
|||||||
@@ -7,10 +7,4 @@ bool amneziaIosPairingCameraAccessGranted();
|
|||||||
void amneziaIosRequestPairingCameraAccess(const std::function<void(bool)> &onDone);
|
void amneziaIosRequestPairingCameraAccess(const std::function<void(bool)> &onDone);
|
||||||
void amneziaIosOpenApplicationSettings();
|
void amneziaIosOpenApplicationSettings();
|
||||||
|
|
||||||
void amneziaIosApplyEmbeddedCameraUnderlayToQtView(bool enable);
|
|
||||||
|
|
||||||
void amneziaIosSetPairingEmbeddedCameraNativeBottomExtraPt(int extraPt);
|
|
||||||
|
|
||||||
void amneziaIosPairingRelayoutChromeIfNeeded(void);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -3,269 +3,6 @@
|
|||||||
#import <AVFoundation/AVFoundation.h>
|
#import <AVFoundation/AVFoundation.h>
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
static UIViewController *amneziaKeyWindowViewController(void)
|
|
||||||
{
|
|
||||||
UIApplication *app = [UIApplication sharedApplication];
|
|
||||||
if (@available(iOS 13.0, *)) {
|
|
||||||
for (UIScene *scene in app.connectedScenes) {
|
|
||||||
if (scene.activationState != UISceneActivationStateForegroundActive) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (![scene isKindOfClass:[UIWindowScene class]]) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
UIWindowScene *windowScene = (UIWindowScene *)scene;
|
|
||||||
for (UIWindow *window in windowScene.windows) {
|
|
||||||
if (window.isKeyWindow && window.rootViewController) {
|
|
||||||
return window.rootViewController;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (UIWindow *window in windowScene.windows) {
|
|
||||||
if (!window.isHidden && window.rootViewController) {
|
|
||||||
return window.rootViewController;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (UIWindow *window in app.windows) {
|
|
||||||
if (window.isKeyWindow && window.rootViewController) {
|
|
||||||
return window.rootViewController;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (UIWindow *window in app.windows) {
|
|
||||||
if (window.rootViewController) {
|
|
||||||
return window.rootViewController;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** QML window is shorter than UIKit UIWindow (e.g. 759 vs 852); camera preview covers full window — dim strips in safe areas. */
|
|
||||||
static UIView *s_pairingSafeTopDim = nil;
|
|
||||||
static UIView *s_pairingSafeBottomDim = nil;
|
|
||||||
static id s_pairingSafeDimOrientationToken = nil;
|
|
||||||
/** Qt root for layout: bottom strip fills from maxY to host bottom when Qt view is shorter than host. */
|
|
||||||
static __unsafe_unretained UIView *s_pairingDimQtRoot = nil;
|
|
||||||
/** QML-driven tab band (e.g. scanDimBleedBottom) added to safe bottom when Qt root is full height. */
|
|
||||||
static int s_pairingNativeBottomExtraPt = 0;
|
|
||||||
/** Opaque strip on UIWindow.layer above AVCaptureVideoPreviewLayer — preview can composite above UIDropShadowView subviews. */
|
|
||||||
static CALayer *s_pairingWindowBottomMaskLayer = nil;
|
|
||||||
|
|
||||||
static UIColor *amneziaPairingBottomChromeOpaqueColor(void)
|
|
||||||
{
|
|
||||||
return [UIColor colorWithRed:(CGFloat)(28.0 / 255.0) green:(CGFloat)(29.0 / 255.0) blue:(CGFloat)(33.0 / 255.0) alpha:1.0f];
|
|
||||||
}
|
|
||||||
|
|
||||||
static CALayer *amneziaFindVideoPreviewLayerInWindow(UIWindow *window)
|
|
||||||
{
|
|
||||||
if (!window) {
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
for (CALayer *ly in window.layer.sublayers) {
|
|
||||||
if ([ly isKindOfClass:[AVCaptureVideoPreviewLayer class]]) {
|
|
||||||
return ly;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void amneziaRemovePairingWindowBottomMaskLayer(void)
|
|
||||||
{
|
|
||||||
[s_pairingWindowBottomMaskLayer removeFromSuperlayer];
|
|
||||||
s_pairingWindowBottomMaskLayer = nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Maps bottom strip from host (UIDropShadowView) into window coords and stacks above camera preview on window.layer. */
|
|
||||||
static void amneziaSyncPairingWindowBottomMaskLayer(UIWindow *window, UIView *host, CGFloat bottomY, CGFloat bottomH, CGFloat width)
|
|
||||||
{
|
|
||||||
if (!window || !host || bottomH < 0.5f) {
|
|
||||||
amneziaRemovePairingWindowBottomMaskLayer();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
CGRect hostRect = CGRectMake(0, bottomY, width, bottomH);
|
|
||||||
CGRect winRect = [window convertRect:hostRect fromView:host];
|
|
||||||
if (!s_pairingWindowBottomMaskLayer) {
|
|
||||||
s_pairingWindowBottomMaskLayer = [[CALayer alloc] init];
|
|
||||||
s_pairingWindowBottomMaskLayer.backgroundColor = amneziaPairingBottomChromeOpaqueColor().CGColor;
|
|
||||||
}
|
|
||||||
s_pairingWindowBottomMaskLayer.frame = winRect;
|
|
||||||
s_pairingWindowBottomMaskLayer.zPosition = -500.f;
|
|
||||||
|
|
||||||
CALayer *preview = amneziaFindVideoPreviewLayerInWindow(window);
|
|
||||||
if (preview) {
|
|
||||||
[window.layer insertSublayer:s_pairingWindowBottomMaskLayer above:preview];
|
|
||||||
} else if (s_pairingWindowBottomMaskLayer.superlayer) {
|
|
||||||
[s_pairingWindowBottomMaskLayer removeFromSuperlayer];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void amneziaRemovePairingSafeAreaDimStrips(void)
|
|
||||||
{
|
|
||||||
if (s_pairingSafeDimOrientationToken) {
|
|
||||||
[[NSNotificationCenter defaultCenter] removeObserver:s_pairingSafeDimOrientationToken];
|
|
||||||
s_pairingSafeDimOrientationToken = nil;
|
|
||||||
}
|
|
||||||
[s_pairingSafeTopDim removeFromSuperview];
|
|
||||||
[s_pairingSafeBottomDim removeFromSuperview];
|
|
||||||
s_pairingSafeTopDim = nil;
|
|
||||||
s_pairingSafeBottomDim = nil;
|
|
||||||
s_pairingDimQtRoot = nil;
|
|
||||||
amneziaRemovePairingWindowBottomMaskLayer();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void amneziaLayoutPairingSafeAreaDimStrips(void)
|
|
||||||
{
|
|
||||||
if (!s_pairingSafeTopDim || !s_pairingSafeTopDim.superview) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
UIWindow *w = s_pairingSafeTopDim.window;
|
|
||||||
UIView *host = s_pairingSafeTopDim.superview;
|
|
||||||
if (!w || !host) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
UIEdgeInsets insets = w.safeAreaInsets;
|
|
||||||
CGRect hb = host.bounds;
|
|
||||||
s_pairingSafeTopDim.frame = CGRectMake(0, 0, hb.size.width, insets.top);
|
|
||||||
|
|
||||||
CGFloat bottomY = hb.size.height - insets.bottom;
|
|
||||||
CGFloat bottomH = insets.bottom;
|
|
||||||
UIView *qt = s_pairingDimQtRoot;
|
|
||||||
if (qt && qt.superview) {
|
|
||||||
CGRect qInHost = [host convertRect:qt.bounds fromView:qt];
|
|
||||||
const CGFloat qMaxY = CGRectGetMaxY(qInHost);
|
|
||||||
if (qMaxY < hb.size.height - 0.5f) {
|
|
||||||
bottomY = qMaxY;
|
|
||||||
bottomH = hb.size.height - qMaxY;
|
|
||||||
} else if (s_pairingNativeBottomExtraPt > 0) {
|
|
||||||
bottomH = insets.bottom + (CGFloat)s_pairingNativeBottomExtraPt;
|
|
||||||
bottomY = hb.size.height - bottomH;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bottomH < 0.5f) {
|
|
||||||
bottomH = 0.f;
|
|
||||||
bottomY = hb.size.height;
|
|
||||||
} else {
|
|
||||||
/** Pull strip slightly past layout bounds — QML vs UIKit gap can leave a hairline of preview at the physical bottom. */
|
|
||||||
const CGFloat kBottomOverscanPt = 12.f;
|
|
||||||
bottomH += kBottomOverscanPt;
|
|
||||||
bottomY = hb.size.height - bottomH;
|
|
||||||
if (bottomY < insets.top + 2.f) {
|
|
||||||
bottomY = insets.top + 2.f;
|
|
||||||
bottomH = hb.size.height - bottomY;
|
|
||||||
}
|
|
||||||
/** Stack↔tab hairline: preview on UIWindow.layer can leak slightly above computed strip top vs Qt chrome. */
|
|
||||||
const CGFloat kHairlineCoverUpPt = 4.f;
|
|
||||||
bottomY -= kHairlineCoverUpPt;
|
|
||||||
bottomH += kHairlineCoverUpPt;
|
|
||||||
if (bottomY < insets.top + 2.f) {
|
|
||||||
bottomH -= (insets.top + 2.f) - bottomY;
|
|
||||||
bottomY = insets.top + 2.f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s_pairingSafeBottomDim.frame = CGRectMake(0, bottomY, hb.size.width, bottomH);
|
|
||||||
|
|
||||||
amneziaSyncPairingWindowBottomMaskLayer(w, host, bottomY, bottomH, hb.size.width);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void amneziaInstallPairingSafeAreaDimStrips(UIWindow *window, UIView *qtRootView)
|
|
||||||
{
|
|
||||||
amneziaRemovePairingSafeAreaDimStrips();
|
|
||||||
if (!window || !qtRootView) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
UIView *host = qtRootView.superview ?: window;
|
|
||||||
if (!host) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
UIEdgeInsets insets = window.safeAreaInsets;
|
|
||||||
CGRect hb = host.bounds;
|
|
||||||
UIColor *dim = [UIColor colorWithWhite:0 alpha:0.55f];
|
|
||||||
UIColor *bottomChromeOpaque = amneziaPairingBottomChromeOpaqueColor();
|
|
||||||
|
|
||||||
s_pairingSafeTopDim = [[UIView alloc] initWithFrame:CGRectMake(0, 0, hb.size.width, insets.top)];
|
|
||||||
s_pairingSafeTopDim.backgroundColor = dim;
|
|
||||||
s_pairingSafeTopDim.opaque = NO;
|
|
||||||
s_pairingSafeTopDim.layer.opaque = NO;
|
|
||||||
s_pairingSafeTopDim.userInteractionEnabled = NO;
|
|
||||||
s_pairingSafeTopDim.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin;
|
|
||||||
|
|
||||||
s_pairingSafeBottomDim = [[UIView alloc] initWithFrame:CGRectMake(0, hb.size.height - insets.bottom, hb.size.width, insets.bottom)];
|
|
||||||
s_pairingSafeBottomDim.backgroundColor = bottomChromeOpaque;
|
|
||||||
s_pairingSafeBottomDim.opaque = YES;
|
|
||||||
s_pairingSafeBottomDim.layer.opaque = YES;
|
|
||||||
s_pairingSafeBottomDim.userInteractionEnabled = NO;
|
|
||||||
s_pairingSafeBottomDim.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
|
|
||||||
|
|
||||||
s_pairingDimQtRoot = qtRootView;
|
|
||||||
|
|
||||||
[host insertSubview:s_pairingSafeTopDim belowSubview:qtRootView];
|
|
||||||
[host insertSubview:s_pairingSafeBottomDim belowSubview:qtRootView];
|
|
||||||
|
|
||||||
s_pairingSafeDimOrientationToken = [[NSNotificationCenter defaultCenter]
|
|
||||||
addObserverForName:UIDeviceOrientationDidChangeNotification
|
|
||||||
object:nil
|
|
||||||
queue:[NSOperationQueue mainQueue]
|
|
||||||
usingBlock:^(__unused NSNotification *note) {
|
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
|
||||||
amneziaLayoutPairingSafeAreaDimStrips();
|
|
||||||
});
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
static void amneziaApplyUnderlayTransparencyToView(UIView *view, BOOL transparent, NSUInteger depth, NSUInteger maxDepth)
|
|
||||||
{
|
|
||||||
if (!view || depth > maxDepth) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (transparent) {
|
|
||||||
view.opaque = NO;
|
|
||||||
view.backgroundColor = [UIColor clearColor];
|
|
||||||
view.layer.opaque = NO;
|
|
||||||
} else {
|
|
||||||
view.opaque = YES;
|
|
||||||
view.backgroundColor = [UIColor blackColor];
|
|
||||||
view.layer.opaque = YES;
|
|
||||||
}
|
|
||||||
if (depth < maxDepth) {
|
|
||||||
for (UIView *child in view.subviews) {
|
|
||||||
amneziaApplyUnderlayTransparencyToView(child, transparent, depth + 1, maxDepth);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Qt's QUIMetalView often sits deeper than a shallow walk; render thread can reset layer flags after resize. */
|
|
||||||
static void amneziaForceMetalViewsTransparent(UIView *view, NSUInteger depth, NSUInteger maxDepth)
|
|
||||||
{
|
|
||||||
if (!view || depth > maxDepth) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
NSString *cn = NSStringFromClass([view class]);
|
|
||||||
if ([cn rangeOfString:@"Metal"].location != NSNotFound) {
|
|
||||||
view.opaque = NO;
|
|
||||||
view.backgroundColor = [UIColor clearColor];
|
|
||||||
view.layer.opaque = NO;
|
|
||||||
if (view.layer) {
|
|
||||||
view.layer.backgroundColor = [UIColor clearColor].CGColor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (depth < maxDepth) {
|
|
||||||
for (UIView *child in view.subviews) {
|
|
||||||
amneziaForceMetalViewsTransparent(child, depth + 1, maxDepth);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void amneziaApplyPairingUnderlayWalk(UIView *root, BOOL enable)
|
|
||||||
{
|
|
||||||
const NSUInteger kMaxDepth = 24;
|
|
||||||
amneziaApplyUnderlayTransparencyToView(root, enable ? YES : NO, 0, kMaxDepth);
|
|
||||||
if (enable) {
|
|
||||||
amneziaForceMetalViewsTransparent(root, 0, kMaxDepth);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool amneziaIosPairingCameraAccessGranted()
|
bool amneziaIosPairingCameraAccessGranted()
|
||||||
{
|
{
|
||||||
const AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
|
const AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
|
||||||
@@ -298,69 +35,3 @@ void amneziaIosOpenApplicationSettings()
|
|||||||
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
|
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void amneziaIosPairingRelayoutChromeIfNeeded(void)
|
|
||||||
{
|
|
||||||
if (!s_pairingSafeBottomDim || !s_pairingSafeBottomDim.superview) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
amneziaLayoutPairingSafeAreaDimStrips();
|
|
||||||
}
|
|
||||||
|
|
||||||
void amneziaIosSetPairingEmbeddedCameraNativeBottomExtraPt(int extraPt)
|
|
||||||
{
|
|
||||||
const int v = extraPt < 0 ? 0 : extraPt;
|
|
||||||
if (s_pairingNativeBottomExtraPt == v) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
s_pairingNativeBottomExtraPt = v;
|
|
||||||
void (^relayout)(void) = ^{
|
|
||||||
amneziaLayoutPairingSafeAreaDimStrips();
|
|
||||||
};
|
|
||||||
if ([NSThread isMainThread]) {
|
|
||||||
relayout();
|
|
||||||
} else {
|
|
||||||
dispatch_async(dispatch_get_main_queue(), relayout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void amneziaIosApplyEmbeddedCameraUnderlayToQtView(bool enable)
|
|
||||||
{
|
|
||||||
void (^work)(void) = ^{
|
|
||||||
UIViewController *vc = amneziaKeyWindowViewController();
|
|
||||||
if (!vc || !vc.view) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
UIView *root = vc.view;
|
|
||||||
UIWindow *win = root.window;
|
|
||||||
if (!enable) {
|
|
||||||
s_pairingNativeBottomExtraPt = 0;
|
|
||||||
amneziaRemovePairingSafeAreaDimStrips();
|
|
||||||
}
|
|
||||||
if (enable) {
|
|
||||||
vc.edgesForExtendedLayout = UIRectEdgeAll;
|
|
||||||
if (@available(iOS 11.0, *)) {
|
|
||||||
vc.extendedLayoutIncludesOpaqueBars = YES;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
amneziaApplyPairingUnderlayWalk(root, enable);
|
|
||||||
if (enable && win) {
|
|
||||||
amneziaInstallPairingSafeAreaDimStrips(win, root);
|
|
||||||
amneziaLayoutPairingSafeAreaDimStrips();
|
|
||||||
}
|
|
||||||
if (enable) {
|
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
|
||||||
UIViewController *vc2 = amneziaKeyWindowViewController();
|
|
||||||
if (!vc2 || !vc2.view) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
amneziaApplyPairingUnderlayWalk(vc2.view, YES);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if ([NSThread isMainThread]) {
|
|
||||||
work();
|
|
||||||
} else {
|
|
||||||
dispatch_sync(dispatch_get_main_queue(), work);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -11,9 +11,3 @@ void amneziaIosRequestPairingCameraAccess(const std::function<void(bool)> &onDon
|
|||||||
}
|
}
|
||||||
|
|
||||||
void amneziaIosOpenApplicationSettings() {}
|
void amneziaIosOpenApplicationSettings() {}
|
||||||
|
|
||||||
void amneziaIosApplyEmbeddedCameraUnderlayToQtView(bool) {}
|
|
||||||
|
|
||||||
void amneziaIosSetPairingEmbeddedCameraNativeBottomExtraPt(int) {}
|
|
||||||
|
|
||||||
void amneziaIosPairingRelayoutChromeIfNeeded(void) {}
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#include "pairingUiController.h"
|
#include "pairingUiController.h"
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QDataStream>
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QIODevice>
|
#include <QIODevice>
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
@@ -99,49 +98,6 @@ int pairingRetryDelayMs(int zeroBasedAttempt)
|
|||||||
return baseMs * (1 << zeroBasedAttempt);
|
return baseMs * (1 << zeroBasedAttempt);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tryDecodeLegacyChunkedPairingQrPayload(const QString &t, QString *outUuid)
|
|
||||||
{
|
|
||||||
static const QRegularExpression binUrlSafe(QStringLiteral("^[A-Za-z0-9_-]+$"));
|
|
||||||
if (!binUrlSafe.match(t).hasMatch() || t.size() < 16) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
QByteArray padded = t.toUtf8();
|
|
||||||
switch (padded.size() % 4) {
|
|
||||||
case 2:
|
|
||||||
padded += "==";
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
padded += "=";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
const QByteArray raw = QByteArray::fromBase64(padded, QByteArray::Base64UrlEncoding);
|
|
||||||
if (raw.isEmpty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
QDataStream ds(raw);
|
|
||||||
ds.setByteOrder(QDataStream::BigEndian);
|
|
||||||
qint16 magic = 0;
|
|
||||||
quint8 nChunks = 0;
|
|
||||||
quint8 chunkIndex = 0;
|
|
||||||
QByteArray pl;
|
|
||||||
ds >> magic >> nChunks >> chunkIndex >> pl;
|
|
||||||
if (ds.status() != QDataStream::Ok) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (magic != qrCodeUtils::qrMagicCode || nChunks < 1 || nChunks > 200 || chunkIndex >= nChunks) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const QString candidate = QString::fromUtf8(pl).trimmed();
|
|
||||||
const QUuid u = QUuid::fromString(candidate);
|
|
||||||
if (u.isNull()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
*outUuid = u.toString(QUuid::WithoutBraces);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString extractPairingSessionUuidFromScanText(const QString &raw)
|
QString extractPairingSessionUuidFromScanText(const QString &raw)
|
||||||
{
|
{
|
||||||
const QString t = raw.trimmed();
|
const QString t = raw.trimmed();
|
||||||
@@ -154,10 +110,6 @@ QString extractPairingSessionUuidFromScanText(const QString &raw)
|
|||||||
if (m.hasMatch()) {
|
if (m.hasMatch()) {
|
||||||
return m.captured(0);
|
return m.captured(0);
|
||||||
}
|
}
|
||||||
QString fromLegacy;
|
|
||||||
if (tryDecodeLegacyChunkedPairingQrPayload(t, &fromLegacy)) {
|
|
||||||
return fromLegacy;
|
|
||||||
}
|
|
||||||
const QUuid parsed = QUuid::fromString(t);
|
const QUuid parsed = QUuid::fromString(t);
|
||||||
if (!parsed.isNull()) {
|
if (!parsed.isNull()) {
|
||||||
return parsed.toString(QUuid::WithoutBraces);
|
return parsed.toString(QUuid::WithoutBraces);
|
||||||
|
|||||||
@@ -4,9 +4,6 @@ import QtQuick.Controls
|
|||||||
StackView {
|
StackView {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
/** Allow pages (e.g. pairing QR dim) to paint outside stack bounds into tab bar / safe areas. */
|
|
||||||
clip: false
|
|
||||||
|
|
||||||
pushEnter: Transition {
|
pushEnter: Transition {
|
||||||
PropertyAnimation {
|
PropertyAnimation {
|
||||||
property: "opacity"
|
property: "opacity"
|
||||||
|
|||||||
@@ -109,15 +109,10 @@ PageType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onPhonePairingSucceeded() {
|
function onPhonePairingSucceeded() {
|
||||||
var serverId = ServersUiController.getServerId(ServersUiController.processedServerIndex)
|
|
||||||
if (serverId.length === 0) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
SubscriptionUiController.getAccountInfo(serverId, true)
|
|
||||||
SubscriptionUiController.updateApiDevicesModel()
|
|
||||||
if (!root.visible) {
|
if (!root.visible) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
SubscriptionUiController.updateApiDevicesModel()
|
||||||
const label = PairingUiController.lastSuccessfulPhonePairingDisplayName
|
const label = PairingUiController.lastSuccessfulPhonePairingDisplayName
|
||||||
if (label.length > 0) {
|
if (label.length > 0) {
|
||||||
PageController.showNotificationMessage(
|
PageController.showNotificationMessage(
|
||||||
|
|||||||
Reference in New Issue
Block a user