diff --git a/client/client.pro b/client/client.pro index 1cc9dbd2..c972acc8 100644 --- a/client/client.pro +++ b/client/client.pro @@ -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 diff --git a/client/main.cpp b/client/main.cpp index 9cdab7eb..b1419f18 100644 --- a/client/main.cpp +++ b/client/main.cpp @@ -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", 1, 0, "PageType"); + qmlRegisterType("QRCodeReader", 1, 0, "QRCodeReader"); QScopedPointer containerProps(new ContainerProps); qmlRegisterSingletonInstance("ContainerProps", 1, 0, "ContainerProps", containerProps.get()); diff --git a/client/platforms/ios/QRCodeReader.cpp b/client/platforms/ios/QRCodeReader.cpp new file mode 100644 index 00000000..c422a0e7 --- /dev/null +++ b/client/platforms/ios/QRCodeReader.cpp @@ -0,0 +1,14 @@ +#include "QRCodeReader.h" + +QRCodeReader::QRCodeReader() +{ + +} + +QRect QRCodeReader::cameraSize() { + return QRect(); +} + +void QRCodeReader::startReading() {} +void QRCodeReader::stopReading() {} +void QRCodeReader::setCameraSize(QRect) {}; diff --git a/client/platforms/ios/QRCodeReader.h b/client/platforms/ios/QRCodeReader.h new file mode 100644 index 00000000..bc8c9925 --- /dev/null +++ b/client/platforms/ios/QRCodeReader.h @@ -0,0 +1,28 @@ +#ifndef QRCODEREADER_H +#define QRCODEREADER_H + +#include +#include + +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 diff --git a/client/platforms/ios/QRCodeReader.mm b/client/platforms/ios/QRCodeReader.mm new file mode 100644 index 00000000..85f71ba6 --- /dev/null +++ b/client/platforms/ios/QRCodeReader.mm @@ -0,0 +1,109 @@ +#include "QRCodeReader.h" + +#import +#import + +@interface QRCodeReaderImpl : UIViewController +@end + +@interface QRCodeReaderImpl () +@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]; +} diff --git a/client/resources.qrc b/client/resources.qrc index cb7877ff..db61db33 100644 --- a/client/resources.qrc +++ b/client/resources.qrc @@ -157,5 +157,6 @@ images/svg/control_point_black_24dp.svg images/svg/settings_suggest_black_24dp.svg ui/qml/Controls/SvgButtonType.qml + ui/qml/Pages/PageQrDecoderIos.qml diff --git a/client/ui/pages.h b/client/ui/pages.h index b111679a..d74c64a6 100644 --- a/client/ui/pages.h +++ b/client/ui/pages.h @@ -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() { diff --git a/client/ui/qml/Pages/PageQrDecoder.qml b/client/ui/qml/Pages/PageQrDecoder.qml index 6506b7fa..f432b742 100644 --- a/client/ui/qml/Pages/PageQrDecoder.qml +++ b/client/ui/qml/Pages/PageQrDecoder.qml @@ -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 { diff --git a/client/ui/qml/Pages/PageQrDecoderIos.qml b/client/ui/qml/Pages/PageQrDecoderIos.qml new file mode 100644 index 00000000..7dd077dd --- /dev/null +++ b/client/ui/qml/Pages/PageQrDecoderIos.qml @@ -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() + } + + } + + } + + +} diff --git a/client/ui/qml/Pages/PageStart.qml b/client/ui/qml/Pages/PageStart.qml index 26fc5e5f..3ff11a86 100644 --- a/client/ui/qml/Pages/PageStart.qml +++ b/client/ui/qml/Pages/PageStart.qml @@ -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 }