Merge pull request #77 from amnezia-vpn/qr-code-native-ios

Qr code reader native for iOS
This commit is contained in:
pokamest 2022-07-06 16:23:19 +03:00 committed by GitHub
commit 240e55029b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 260 additions and 19 deletions

View file

@ -75,7 +75,8 @@ HEADERS += \
logger.h \
loghandler.h \
loglevel.h \
constants.h
constants.h \
platforms/ios/QRCodeReader.h
SOURCES += \
configurators/cloak_configurator.cpp \
@ -126,8 +127,8 @@ SOURCES += \
vpnconnection.cpp \
protocols/vpnprotocol.cpp \
logger.cpp \
loghandler.cpp
loghandler.cpp \
platforms/ios/QRCodeReader.cpp
RESOURCES += \
resources.qrc
@ -297,14 +298,18 @@ ios {
platforms/ios/bigintipv6addr.h \
platforms/ios/ipaddress.h \
platforms/ios/ipaddressrange.h
SOURCES += \
SOURCES -= \
platforms/ios/QRCodeReader.cpp
SOURCES += \
protocols/ios_vpnprotocol.mm \
platforms/ios/iosnotificationhandler.mm \
platforms/ios/json.cpp \
platforms/ios/iosglue.mm \
platforms/ios/ipaddress.cpp \
platforms/ios/ipaddressrange.cpp
platforms/ios/ipaddressrange.cpp \
platforms/ios/QRCodeReader.mm
Q_ENABLE_BITCODE.value = NO
Q_ENABLE_BITCODE.name = ENABLE_BITCODE

View file

@ -37,6 +37,8 @@
#include "QZXing.h"
#include "platforms/ios/QRCodeReader.h"
#include "debug.h"
#include "defines.h"
@ -167,6 +169,7 @@ int main(int argc, char *argv[])
declareQmlContainerEnum();
qmlRegisterType<PageType>("PageType", 1, 0, "PageType");
qmlRegisterType<QRCodeReader>("QRCodeReader", 1, 0, "QRCodeReader");
QScopedPointer<ContainerProps> containerProps(new ContainerProps);
qmlRegisterSingletonInstance("ContainerProps", 1, 0, "ContainerProps", containerProps.get());

View file

@ -0,0 +1,14 @@
#include "QRCodeReader.h"
QRCodeReader::QRCodeReader()
{
}
QRect QRCodeReader::cameraSize() {
return QRect();
}
void QRCodeReader::startReading() {}
void QRCodeReader::stopReading() {}
void QRCodeReader::setCameraSize(QRect) {};

View file

@ -0,0 +1,28 @@
#ifndef QRCODEREADER_H
#define QRCODEREADER_H
#include <QObject>
#include <QRect>
class QRCodeReader: public QObject {
Q_OBJECT
public:
QRCodeReader();
QRect cameraSize();
public slots:
void startReading();
void stopReading();
void setCameraSize(QRect value);
signals:
void codeReaded(QString code);
private:
void* m_qrCodeReader;
QRect m_cameraSize;
};
#endif // QRCODEREADER_H

View file

@ -0,0 +1,109 @@
#include "QRCodeReader.h"
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
@interface QRCodeReaderImpl : UIViewController
@end
@interface QRCodeReaderImpl () <AVCaptureMetadataOutputObjectsDelegate>
@property (nonatomic) QRCodeReader* qrCodeReader;
@property (nonatomic, strong) AVCaptureSession *captureSession;
@property (nonatomic, strong) AVCaptureVideoPreviewLayer *videoPreviewPlayer;
@end
@implementation QRCodeReaderImpl
- (void)viewDidLoad {
[super viewDidLoad];
_captureSession = nil;
}
- (void)setQrCodeReader: (QRCodeReader*)value {
_qrCodeReader = value;
}
- (BOOL)startReading {
NSError *error;
AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType: AVMediaTypeVideo];
AVCaptureDeviceInput *deviceInput = [AVCaptureDeviceInput deviceInputWithDevice: captureDevice error: &error];
if(!deviceInput) {
NSLog(@"Error %@", error.localizedDescription);
return NO;
}
_captureSession = [[AVCaptureSession alloc]init];
[_captureSession addInput:deviceInput];
AVCaptureMetadataOutput *capturedMetadataOutput = [[AVCaptureMetadataOutput alloc] init];
[_captureSession addOutput:capturedMetadataOutput];
dispatch_queue_t dispatchQueue;
dispatchQueue = dispatch_queue_create("myQueue", NULL);
[capturedMetadataOutput setMetadataObjectsDelegate: self queue: dispatchQueue];
[capturedMetadataOutput setMetadataObjectTypes: [NSArray arrayWithObject:AVMetadataObjectTypeQRCode]];
_videoPreviewPlayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession: _captureSession];
CGFloat tabBarHeight = 20.0;
QRect cameraRect = _qrCodeReader->cameraSize();
CGRect cameraCGRect = CGRectMake(cameraRect.x(),
cameraRect.y() + tabBarHeight,
cameraRect.width(),
cameraRect.height());
[_videoPreviewPlayer setVideoGravity: AVLayerVideoGravityResizeAspect];
[_videoPreviewPlayer setFrame: cameraCGRect];
CALayer* layer = [UIApplication sharedApplication].keyWindow.layer;
[layer addSublayer: _videoPreviewPlayer];
[_captureSession startRunning];
return YES;
}
- (void)stopReading {
[_captureSession stopRunning];
_captureSession = nil;
[_videoPreviewPlayer removeFromSuperlayer];
}
- (void)captureOutput:(AVCaptureOutput *)output didOutputMetadataObjects:(NSArray<__kindof AVMetadataObject *> *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
if (metadataObjects != nil && metadataObjects.count > 0) {
AVMetadataMachineReadableCodeObject *metadataObject = [metadataObjects objectAtIndex:0];
if ([[metadataObject type] isEqualToString: AVMetadataObjectTypeQRCode]) {
_qrCodeReader->emit codeReaded([metadataObject stringValue].UTF8String);
}
}
}
@end
QRCodeReader::QRCodeReader() {
m_qrCodeReader = [[QRCodeReaderImpl alloc] init];
[m_qrCodeReader setQrCodeReader: this];
}
QRect QRCodeReader::cameraSize() {
return m_cameraSize;
}
void QRCodeReader::setCameraSize(QRect value) {
m_cameraSize = value;
}
void QRCodeReader::startReading() {
[m_qrCodeReader startReading];
}
void QRCodeReader::stopReading() {
[m_qrCodeReader stopReading];
}

View file

@ -157,5 +157,6 @@
<file>images/svg/control_point_black_24dp.svg</file>
<file>images/svg/settings_suggest_black_24dp.svg</file>
<file>ui/qml/Controls/SvgButtonType.qml</file>
<file>ui/qml/Pages/PageQrDecoderIos.qml</file>
</qresource>
</RCC>

View file

@ -24,7 +24,7 @@ enum class Page {Start = 0, NewServer, NewServerProtocols, Vpn,
Wizard, WizardLow, WizardMedium, WizardHigh, WizardVpnMode, ServerConfiguringProgress,
GeneralSettings, AppSettings, NetworkSettings, ServerSettings,
ServerContainers, ServersList, ShareConnection, Sites,
ProtocolSettings, ProtocolShare, QrDecoder, About};
ProtocolSettings, ProtocolShare, QrDecoder, QrDecoderIos, About};
Q_ENUM_NS(Page)
static void declareQmlPageEnum() {

View file

@ -26,7 +26,7 @@ PageBase {
}
Connections {
target: QrDecoderLogic
target: Qt.platform.os != "ios" ? QrDecoderLogic : nil
function onStartDecode() {
console.debug("Starting QR decoder")
loader.sourceComponent = component
@ -51,6 +51,7 @@ PageBase {
Item {
anchors.fill: parent
Camera
{
id:camera
@ -76,7 +77,7 @@ PageBase {
Rectangle {
color: "black"
opacity: 0.5
width: videoOutput.contentRect.width *0.15
width: videoOutput.contentRect.width * 0.15
height: videoOutput.contentRect.height
x: (videoOutput.width - videoOutput.contentRect.width)/2
anchors.verticalCenter: videoOutput.verticalCenter
@ -85,28 +86,28 @@ PageBase {
Rectangle {
color: "black"
opacity: 0.5
width: videoOutput.contentRect.width *0.15
width: videoOutput.contentRect.width * 0.15
height: videoOutput.contentRect.height
x: videoOutput.width/2 + videoOutput.contentRect.width/2 - videoOutput.contentRect.width *0.15
x: videoOutput.width/2 + videoOutput.contentRect.width/2 - videoOutput.contentRect.width * 0.15
anchors.verticalCenter: videoOutput.verticalCenter
}
Rectangle {
color: "black"
opacity: 0.5
width: videoOutput.contentRect.width *0.7
height: videoOutput.contentRect.height *0.15
x: (videoOutput.width - videoOutput.contentRect.width)/2 + videoOutput.contentRect.width *0.15
width: videoOutput.contentRect.width * 0.7
height: videoOutput.contentRect.height * 0.15
x: (videoOutput.width - videoOutput.contentRect.width)/2 + videoOutput.contentRect.width * 0.15
y: (videoOutput.height - videoOutput.contentRect.height)/2
}
Rectangle {
color: "black"
opacity: 0.5
width: videoOutput.contentRect.width *0.7
height: videoOutput.contentRect.height *0.15
x: (videoOutput.width - videoOutput.contentRect.width)/2 + videoOutput.contentRect.width *0.15
y: videoOutput.height/2 + videoOutput.contentRect.height/2 - videoOutput.contentRect.height *0.15
width: videoOutput.contentRect.width * 0.7
height: videoOutput.contentRect.height * 0.15
x: (videoOutput.width - videoOutput.contentRect.width)/2 + videoOutput.contentRect.width * 0.15
y: videoOutput.height/2 + videoOutput.contentRect.height/2 - videoOutput.contentRect.height * 0.15
}
LabelType {

View file

@ -0,0 +1,76 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import PageEnum 1.0
import QRCodeReader 1.0
import "./"
import "../Controls"
import "../Config"
PageBase {
id: root
page: PageEnum.QrDecoderIos
logic: QrDecoderLogic
onDeactivated: {
console.debug("Stopping QR decoder")
loader.sourceComponent = undefined
}
BackButton {
}
Caption {
id: caption
text: qsTr("Import configuration")
}
Connections {
target: Qt.platform.os == "ios" ? QrDecoderLogic : nil
function onStartDecode() {
console.debug("Starting QR decoder")
loader.sourceComponent = component
}
function onStopDecode() {
console.debug("Stopping QR decoder")
loader.sourceComponent = undefined
}
}
Loader {
id: loader
anchors.top: caption.bottom
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
}
Component {
id: component
Item {
anchors.fill: parent
QRCodeReader {
id: qrCodeReader
onCodeReaded: {
QrDecoderLogic.onDetectedQrCode(code)
}
Component.onCompleted: {
qrCodeReader.setCameraSize(Qt.rect(loader.x,
loader.y,
loader.width,
loader.height))
qrCodeReader.startReading()
}
Component.onDestruction: qrCodeReader.stopReading()
}
}
}
}

View file

@ -135,7 +135,11 @@ PageBase {
text: qsTr("Scan QR code")
visible: StartPageLogic.pushButtonConnectVisible
onClicked: {
UiLogic.goToPage(PageEnum.QrDecoder)
if (Qt.platform.os == "ios") {
UiLogic.goToPage(PageEnum.QrDecoderIos)
} else {
UiLogic.goToPage(PageEnum.QrDecoder)
}
}
enabled: StartPageLogic.pushButtonConnectEnabled
}