added qr code scanner for ios

This commit is contained in:
vladimir.kuznetsov 2023-08-13 11:28:32 +05:00
parent c1c68cf72d
commit 14fa0b4fd3
19 changed files with 128 additions and 69 deletions

View file

@ -7,6 +7,7 @@
#include <QCommandLineParser> #include <QCommandLineParser>
#include <QQmlApplicationEngine> #include <QQmlApplicationEngine>
#include <QQmlContext> #include <QQmlContext>
#include <QThread>
#include "settings.h" #include "settings.h"
#include "vpnconnection.h" #include "vpnconnection.h"

View file

@ -217,8 +217,8 @@ QString ContainerProps::easySetupDescription(DockerContainer container)
{ {
switch (container) { switch (container) {
case DockerContainer::OpenVpn: return tr("I just want to increase the level of privacy"); case DockerContainer::OpenVpn: return tr("I just want to increase the level of privacy");
case DockerContainer::Cloak: return tr("Some foreign sites are blocked, but VPN providers are not blocked"); case DockerContainer::Cloak: return tr("Many foreign websites and VPN providers are blocked");
case DockerContainer::ShadowSocks: return tr("Many foreign websites and VPN providers are blocked"); case DockerContainer::ShadowSocks: return tr("Some foreign sites are blocked, but VPN providers are not blocked");
default: return ""; default: return "";
} }
} }

View file

@ -49,14 +49,15 @@
_videoPreviewPlayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession: _captureSession]; _videoPreviewPlayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession: _captureSession];
CGFloat tabBarHeight = 20.0; CGFloat statusBarHeight = [UIApplication sharedApplication].statusBarFrame.size.height;
QRect cameraRect = _qrCodeReader->cameraSize(); QRect cameraRect = _qrCodeReader->cameraSize();
CGRect cameraCGRect = CGRectMake(cameraRect.x(), CGRect cameraCGRect = CGRectMake(cameraRect.x(),
cameraRect.y() + tabBarHeight, cameraRect.y() + statusBarHeight,
cameraRect.width(), cameraRect.width(),
cameraRect.height()); cameraRect.height());
[_videoPreviewPlayer setVideoGravity: AVLayerVideoGravityResizeAspect]; [_videoPreviewPlayer setVideoGravity: AVLayerVideoGravityResizeAspectFill];
[_videoPreviewPlayer setFrame: cameraCGRect]; [_videoPreviewPlayer setFrame: cameraCGRect];
CALayer* layer = [UIApplication sharedApplication].keyWindow.layer; CALayer* layer = [UIApplication sharedApplication].keyWindow.layer;

View file

@ -42,8 +42,11 @@ namespace
return ConfigTypes::Amnezia; return ConfigTypes::Amnezia;
} }
#ifdef Q_OS_ANDROID #if defined Q_OS_ANDROID
ImportController *mInstance = nullptr; ImportController *mInstance = nullptr;
#endif
#ifdef Q_OS_ANDROID
constexpr auto AndroidCameraActivity = "org.amnezia.vpn.qt.CameraActivity"; constexpr auto AndroidCameraActivity = "org.amnezia.vpn.qt.CameraActivity";
#endif #endif
} // namespace } // namespace
@ -264,17 +267,6 @@ QJsonObject ImportController::extractWireGuardConfig(const QString &data)
} }
#ifdef Q_OS_ANDROID #ifdef Q_OS_ANDROID
void ImportController::startDecodingQr()
{
AndroidController::instance()->startQrReaderActivity();
}
void ImportController::stopDecodingQr()
{
QJniObject::callStaticMethod<void>(AndroidCameraActivity, "stopQrCodeReader", "()V");
emit qrDecodingFinished();
}
void ImportController::onNewQrCodeDataChunk(JNIEnv *env, jobject thiz, jstring data) void ImportController::onNewQrCodeDataChunk(JNIEnv *env, jobject thiz, jstring data)
{ {
Q_UNUSED(thiz); Q_UNUSED(thiz);
@ -296,6 +288,30 @@ void ImportController::onNewQrCodeDataChunk(JNIEnv *env, jobject thiz, jstring d
mInstance->parseQrCodeChunk(parcelBody); mInstance->parseQrCodeChunk(parcelBody);
} }
} }
#endif
#if defined Q_OS_ANDROID || defined Q_OS_IOS
void ImportController::startDecodingQr()
{
m_qrCodeChunks.clear();
m_totalQrCodeChunksCount = 0;
m_receivedQrCodeChunksCount = 0;
#if defined Q_OS_IOS
m_isQrCodeProcessed = true;
#endif
#if defined Q_OS_ANDROID
AndroidController::instance()->startQrReaderActivity();
#endif
}
void ImportController::stopDecodingQr()
{
#if defined Q_OS_ANDROID
QJniObject::callStaticMethod<void>(AndroidCameraActivity, "stopQrCodeReader", "()V");
#endif
emit qrDecodingFinished();
}
void ImportController::parseQrCodeChunk(const QString &code) void ImportController::parseQrCodeChunk(const QString &code)
{ {
@ -333,8 +349,10 @@ void ImportController::parseQrCodeChunk(const QString &code)
bool ok = extractConfigFromQr(data); bool ok = extractConfigFromQr(data);
if (ok) { if (ok) {
m_isQrCodeProcessed = false; m_isQrCodeProcessed = false;
qDebug() << "stopDecodingQr";
stopDecodingQr(); stopDecodingQr();
} else { } else {
qDebug() << "error while extracting data from qr";
m_qrCodeChunks.clear(); m_qrCodeChunks.clear();
m_totalQrCodeChunksCount = 0; m_totalQrCodeChunksCount = 0;
m_receivedQrCodeChunksCount = 0; m_receivedQrCodeChunksCount = 0;
@ -344,8 +362,19 @@ void ImportController::parseQrCodeChunk(const QString &code)
bool ok = extractConfigFromQr(ba); bool ok = extractConfigFromQr(ba);
if (ok) { if (ok) {
m_isQrCodeProcessed = false; m_isQrCodeProcessed = false;
qDebug() << "stopDecodingQr";
stopDecodingQr(); stopDecodingQr();
} }
} }
} }
double ImportController::getQrCodeScanProgressBarValue()
{
return (1.0 / m_totalQrCodeChunksCount) * m_receivedQrCodeChunksCount;
}
QString ImportController::getQrCodeScanProgressString()
{
return tr("Scanned %1 of %2.").arg(m_receivedQrCodeChunksCount).arg(m_totalQrCodeChunksCount);
}
#endif #endif

View file

@ -28,8 +28,12 @@ public slots:
QString getConfig(); QString getConfig();
QString getConfigFileName(); QString getConfigFileName();
#if defined Q_OS_ANDROID #if defined Q_OS_ANDROID || defined Q_OS_IOS
void startDecodingQr(); void startDecodingQr();
void parseQrCodeChunk(const QString &code);
double getQrCodeScanProgressBarValue();
QString getQrCodeScanProgressString();
#endif #endif
signals: signals:
@ -43,10 +47,11 @@ private:
QJsonObject extractOpenVpnConfig(const QString &data); QJsonObject extractOpenVpnConfig(const QString &data);
QJsonObject extractWireGuardConfig(const QString &data); QJsonObject extractWireGuardConfig(const QString &data);
#if defined Q_OS_ANDROID #if defined Q_OS_ANDROID || defined Q_OS_IOS
void stopDecodingQr(); void stopDecodingQr();
#endif
#if defined Q_OS_ANDROID
static void onNewQrCodeDataChunk(JNIEnv *env, jobject thiz, jstring data); static void onNewQrCodeDataChunk(JNIEnv *env, jobject thiz, jstring data);
void parseQrCodeChunk(const QString &code);
#endif #endif
QSharedPointer<ServersModel> m_serversModel; QSharedPointer<ServersModel> m_serversModel;
@ -56,7 +61,7 @@ private:
QJsonObject m_config; QJsonObject m_config;
QString m_configFileName; QString m_configFileName;
#if defined Q_OS_ANDROID #if defined Q_OS_ANDROID || defined Q_OS_IOS
QMap<int, QByteArray> m_qrCodeChunks; QMap<int, QByteArray> m_qrCodeChunks;
bool m_isQrCodeProcessed; bool m_isQrCodeProcessed;
int m_totalQrCodeChunksCount; int m_totalQrCodeChunksCount;

View file

@ -176,7 +176,7 @@ ErrorCode ContainersModel::removeCurrentlyProcessedContainer()
ErrorCode errorCode = serverController.removeContainer(credentials, dockerContainer); ErrorCode errorCode = serverController.removeContainer(credentials, dockerContainer);
if (errorCode == ErrorCode::NoError) { if (errorCode == ErrorCode::NoError) {
beginResetModel(); // todo change to begin remove rows? beginResetModel();
m_settings->removeContainerConfig(m_currentlyProcessedServerIndex, dockerContainer); m_settings->removeContainerConfig(m_currentlyProcessedServerIndex, dockerContainer);
m_containers = m_settings->containers(m_currentlyProcessedServerIndex); m_containers = m_settings->containers(m_currentlyProcessedServerIndex);

View file

@ -79,8 +79,7 @@ QVariant OpenVpnConfigModel::data(const QModelIndex &index, int role) const
void OpenVpnConfigModel::updateModel(const QJsonObject &config) void OpenVpnConfigModel::updateModel(const QJsonObject &config)
{ {
beginResetModel(); beginResetModel();
m_container = m_container = ContainerProps::containerFromString(config.value(config_key::container).toString());
ContainerProps::containerFromString(config.value(config_key::container).toString()); // todo maybe unused
m_fullConfig = config; m_fullConfig = config;
QJsonObject protocolConfig = config.value(config_key::openvpn).toObject(); QJsonObject protocolConfig = config.value(config_key::openvpn).toObject();

View file

@ -157,7 +157,6 @@ bool ServersModel::isDefaultServerHasWriteAccess()
void ServersModel::addServer(const QJsonObject &server) void ServersModel::addServer(const QJsonObject &server)
{ {
// todo beginInsertRows()?
beginResetModel(); beginResetModel();
m_settings->addServer(server); m_settings->addServer(server);
m_servers = m_settings->serversArray(); m_servers = m_settings->serversArray();

View file

@ -13,12 +13,10 @@ import "../Components"
PageType { PageType {
id: root id: root
//todo move to main?
Connections { Connections {
target: InstallController target: InstallController
function onUpdateContainerFinished() { function onUpdateContainerFinished() {
//todo change to notification
PageController.showNotificationMessage(qsTr("Settings updated successfully")) PageController.showNotificationMessage(qsTr("Settings updated successfully"))
} }
} }

View file

@ -19,7 +19,6 @@ PageType {
target: InstallController target: InstallController
function onUpdateContainerFinished() { function onUpdateContainerFinished() {
//todo change to notification
PageController.showNotificationMessage(qsTr("Settings updated successfully")) PageController.showNotificationMessage(qsTr("Settings updated successfully"))
} }
} }

View file

@ -13,12 +13,10 @@ import "../Components"
PageType { PageType {
id: root id: root
//todo move to main?
Connections { Connections {
target: InstallController target: InstallController
function onUpdateContainerFinished() { function onUpdateContainerFinished() {
//todo change to notification
PageController.showNotificationMessage(qsTr("Settings updated successfully")) PageController.showNotificationMessage(qsTr("Settings updated successfully"))
} }
} }

View file

@ -15,12 +15,10 @@ import "../Components"
PageType { PageType {
id: root id: root
//todo move to main?
Connections { Connections {
target: InstallController target: InstallController
function onUpdateContainerFinished() { function onUpdateContainerFinished() {
//todo change to notification
PageController.showNotificationMessage(qsTr("Settings updated successfully")) PageController.showNotificationMessage(qsTr("Settings updated successfully"))
} }
} }

View file

@ -16,12 +16,10 @@ import "../Components"
PageType { PageType {
id: root id: root
//todo move to main?
Connections { Connections {
target: InstallController target: InstallController
function onUpdateContainerFinished() { function onUpdateContainerFinished() {
//todo change to notification
PageController.showNotificationMessage(qsTr("Settings updated successfully")) PageController.showNotificationMessage(qsTr("Settings updated successfully"))
} }
} }

View file

@ -55,16 +55,15 @@ PageType {
anchors.topMargin: 32 anchors.topMargin: 32
ListView { ListView {
// todo change id naming id: protocols
id: container
width: parent.width width: parent.width
height: container.contentItem.height height: protocols.contentItem.height
clip: true clip: true
interactive: false interactive: false
model: ProtocolsModel model: ProtocolsModel
delegate: Item { delegate: Item {
implicitWidth: container.width implicitWidth: protocols.width
implicitHeight: delegateContent.implicitHeight implicitHeight: delegateContent.implicitHeight
ColumnLayout { ColumnLayout {

View file

@ -17,6 +17,7 @@ PageType {
target: ImportController target: ImportController
function onQrDecodingFinished() { function onQrDecodingFinished() {
closePage()
goToPage(PageEnum.PageSetupWizardViewConfig) goToPage(PageEnum.PageSetupWizardViewConfig)
} }
} }
@ -86,7 +87,7 @@ It's okay if a friend passed the code.")
clickedFunction: function() { clickedFunction: function() {
ImportController.startDecodingQr() ImportController.startDecodingQr()
// goToPage(PageEnum.PageSetupWizardQrReader) goToPage(PageEnum.PageSetupWizardQrReader)
} }
} }

View file

@ -68,7 +68,6 @@ PageType {
} }
FlickableType { FlickableType {
id: fl
anchors.fill: parent anchors.fill: parent
contentHeight: content.height contentHeight: content.height
@ -82,7 +81,6 @@ PageType {
spacing: 16 spacing: 16
ListView { ListView {
// todo change id naming
id: container id: container
width: parent.width width: parent.width
height: container.contentItem.height height: container.contentItem.height

View file

@ -233,7 +233,6 @@ PageType {
} }
Component.onCompleted: { Component.onCompleted: {
//todo move to protocols model?
var defaultContainerProto = ContainerProps.defaultProtocol(dockerContainer) var defaultContainerProto = ContainerProps.defaultProtocol(dockerContainer)
if (ProtocolProps.defaultPort(defaultContainerProto) < 0) { if (ProtocolProps.defaultPort(defaultContainerProto) < 0) {

View file

@ -14,39 +14,76 @@ import "../Config"
PageType { PageType {
id: root id: root
ColumnLayout { BackButtonType {
anchors.fill: parent id: backButton
anchors.left: parent.left
anchors.top: parent.top
spacing: 0 anchors.topMargin: 20
}
BackButtonType { ParagraphTextType {
Layout.topMargin: 20 id: header
}
ParagraphTextType { property string progressString
Layout.fillWidth: true
text: qsTr("Point the camera at the QR code and hold for a couple of seconds.") anchors.left: parent.left
} anchors.top: backButton.bottom
anchors.right: parent.right
ProgressBarType { anchors.leftMargin: 16
anchors.rightMargin: 16
} text: qsTr("Point the camera at the QR code and hold for a couple of seconds. ") + progressString
}
Item { ProgressBarType {
Layout.fillHeight: true id: progressBar
Layout.fillWidth: true
QRCodeReader { anchors.left: parent.left
id: qrCodeReader anchors.top: header.bottom
Component.onCompleted: { anchors.right: parent.right
qrCodeReader.setCameraSize(Qt.rect(parent.x,
parent.y, anchors.leftMargin: 16
parent.width, anchors.rightMargin: 16
parent.height)) }
qrCodeReader.startReading()
} Rectangle {
} id: qrCodeRectange
anchors.right: parent.right
anchors.left: parent.left
anchors.bottom: parent.bottom
anchors.top: progressBar.bottom
anchors.topMargin: 34
anchors.leftMargin: 16
anchors.rightMargin: 16
anchors.bottomMargin: 34
color: "transparent"
//radius: 16
QRCodeReader {
id: qrCodeReader
onCodeReaded: function(code) {
ImportController.parseQrCodeChunk(code)
progressBar.value = ImportController.getQrCodeScanProgressBarValue()
header.progressString = ImportController.getQrCodeScanProgressString()
}
Component.onCompleted: {
console.log(qrCodeRectange.x)
console.log(qrCodeRectange.y)
console.log(qrCodeRectange.width)
qrCodeReader.setCameraSize(Qt.rect(qrCodeRectange.x,
qrCodeRectange.y,
qrCodeRectange.width,
qrCodeRectange.height))
qrCodeReader.startReading()
}
Component.onDestruction: qrCodeReader.stopReading()
} }
} }
} }

View file

@ -96,7 +96,7 @@ void VpnConnection::onConnectionStateChanged(Vpn::ConnectionState state)
#endif #endif
#ifdef Q_OS_IOS #ifdef Q_OS_IOS
if (state == VpnProtocol::Connected) { if (state == Vpn::ConnectionState::Connected) {
m_checkTimer.start(); m_checkTimer.start();
} }
else { else {
@ -337,7 +337,7 @@ void VpnConnection::connectToVpn(int serverIndex,
if (!iosVpnProtocol->initialize()) { if (!iosVpnProtocol->initialize()) {
qDebug() << QString("Init failed") ; qDebug() << QString("Init failed") ;
emit VpnProtocol::Error; emit Vpn::ConnectionState::Error;
iosVpnProtocol->deleteLater(); iosVpnProtocol->deleteLater();
return; return;
} }