Merge pull request #77 from amnezia-vpn/qr-code-native-ios
Qr code reader native for iOS
This commit is contained in:
commit
240e55029b
10 changed files with 260 additions and 19 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
14
client/platforms/ios/QRCodeReader.cpp
Normal file
14
client/platforms/ios/QRCodeReader.cpp
Normal 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) {};
|
||||
28
client/platforms/ios/QRCodeReader.h
Normal file
28
client/platforms/ios/QRCodeReader.h
Normal 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
|
||||
109
client/platforms/ios/QRCodeReader.mm
Normal file
109
client/platforms/ios/QRCodeReader.mm
Normal 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];
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
76
client/ui/qml/Pages/PageQrDecoderIos.qml
Normal file
76
client/ui/qml/Pages/PageQrDecoderIos.qml
Normal 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()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue