298 lines
8.1 KiB
QML
298 lines
8.1 KiB
QML
import QtQuick 2.0
|
|
import QtQuick.Controls 2.12
|
|
import QtQuick.Layouts 1.12
|
|
import QZXing 3.1
|
|
import QtMultimedia 5.12
|
|
import QtQuick.Shapes 1.12
|
|
import QtQuick.Controls.Material 2.12
|
|
|
|
import "../Components"
|
|
|
|
Page {
|
|
id: control
|
|
|
|
property string _statusText: ""
|
|
property string _statusColor: Material.primaryTextColor
|
|
property bool _freezeScanning: false
|
|
signal headerComponentChanged()
|
|
|
|
//% "Scan QR-Code"
|
|
title: qsTrId("#scanQrCode")
|
|
|
|
onFocusChanged: focus ? open() : close()
|
|
|
|
function open() {
|
|
_setDefaultStatusText()
|
|
control._freezeScanning = false
|
|
if(serverConn.isCameraPermissionGranted())
|
|
cameraLoader.sourceComponent = cameraComponent
|
|
else
|
|
cameraLoader.sourceComponent = noPermissionComponent
|
|
}
|
|
|
|
function close() {
|
|
cameraLoader.sourceComponent = null
|
|
}
|
|
|
|
function _setDefaultStatusText() {
|
|
//% "Place the Code in the center"
|
|
_statusText = qsTrId("#placeQrCodeInCenter")
|
|
_statusColor = Material.primaryTextColor
|
|
}
|
|
|
|
function _handleTag(tag) {
|
|
if(control._freezeScanning)
|
|
return
|
|
|
|
control._freezeScanning = true
|
|
|
|
//% "Plase wait"
|
|
control._statusText = qsTrId("#pleaseWait") + "..."
|
|
|
|
if(app.openWidgetFromUrl(tag))
|
|
control.close()
|
|
else {
|
|
//% "Invalid QR-Code"
|
|
control._statusText = qsTrId("#invalidQrCode")
|
|
control._statusColor = Material.color(Material.Red)
|
|
statusTextResetTimer.start()
|
|
control._freezeScanning = false
|
|
}
|
|
}
|
|
|
|
function _requestCameraPermission() {
|
|
var permissionGranted = serverConn.requestCameraPermission()
|
|
|
|
if(permissionGranted)
|
|
cameraLoader.sourceComponent = cameraComponent
|
|
}
|
|
|
|
contentItem: Loader {
|
|
id: cameraLoader
|
|
|
|
anchors.fill: parent
|
|
|
|
//asynchronous: true
|
|
sourceComponent: null
|
|
}
|
|
|
|
Component {
|
|
id: cameraComponent
|
|
Item {
|
|
anchors.fill: parent
|
|
|
|
Camera {
|
|
id: camera
|
|
captureMode: Camera.CaptureStillImage
|
|
imageProcessing.whiteBalanceMode: CameraImageProcessing.WhiteBalanceAuto
|
|
|
|
focus {
|
|
focusMode: Camera.FocusContinuous
|
|
focusPointMode: Camera.FocusPointCenter
|
|
}
|
|
}
|
|
|
|
FancyBusyIndicator {
|
|
anchors.centerIn: parent
|
|
}
|
|
|
|
VideoOutput {
|
|
id: videoOutput
|
|
x: 0
|
|
y: 0
|
|
width: parent.width
|
|
height: parent.height
|
|
|
|
fillMode: VideoOutput.PreserveAspectCrop
|
|
|
|
source: camera
|
|
filters: [ zxingFilter ]
|
|
focus : visible // to receive focus and capture key events when visible
|
|
|
|
autoOrientation: true
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
|
|
onClicked: {
|
|
if (camera.lockStatus !== Camera.Unlocked)
|
|
camera.unlock();
|
|
|
|
camera.searchAndLock();
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
anchors {
|
|
top: parent.top
|
|
left: parent.left
|
|
right: app.landscape() ? focusIndicatorRect.left : parent.right
|
|
bottom: app.landscape() ? parent.bottom : focusIndicatorRect.top
|
|
}
|
|
|
|
opacity: focusIndicatorRect.opacity
|
|
color: focusIndicatorRect.border.color
|
|
}
|
|
|
|
Rectangle {
|
|
id: focusIndicatorRect
|
|
anchors.centerIn: parent
|
|
|
|
width: Math.min(parent.height, parent.width)
|
|
height: width
|
|
|
|
border.width: width * 0.1
|
|
border.color: "#000000"
|
|
|
|
opacity: 0.5
|
|
color: "transparent"
|
|
}
|
|
|
|
Rectangle {
|
|
anchors {
|
|
bottom: focusIndicatorRect.bottom
|
|
bottomMargin: height * 0.5
|
|
horizontalCenter: focusIndicatorRect.horizontalCenter
|
|
}
|
|
|
|
width: (focusIndicatorRect.width - focusIndicatorRect.border.width * 2) * 0.8
|
|
height: focusIndicatorRect.border.width
|
|
|
|
radius: height * 0.3
|
|
|
|
color: Material.backgroundColor
|
|
|
|
Material.elevation: 10
|
|
|
|
|
|
Label {
|
|
anchors {
|
|
fill: parent
|
|
margins: height * 0.1
|
|
}
|
|
|
|
color: control._statusColor
|
|
|
|
font.pixelSize: height * 0.5
|
|
fontSizeMode: Text.Fit
|
|
minimumPixelSize: height * 0.2
|
|
|
|
verticalAlignment: Text.AlignVCenter
|
|
horizontalAlignment: Text.AlignHCenter
|
|
|
|
text: control._statusText
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
anchors {
|
|
top: app.landscape() ? parent.top : focusIndicatorRect.bottom
|
|
left: app.landscape() ? focusIndicatorRect.right : parent.left
|
|
right: parent.right
|
|
bottom: parent.bottom
|
|
}
|
|
|
|
opacity: focusIndicatorRect.opacity
|
|
color: focusIndicatorRect.border.color
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: noPermissionComponent
|
|
ColumnLayout {
|
|
//anchors.fill: parent
|
|
//anchors.margins: app.landscape() ? app.height * 0.1 : app.width * 0.1
|
|
|
|
property int columnWidth: control.width * 0.9
|
|
|
|
spacing: height * 0.02
|
|
|
|
Item {
|
|
Layout.fillHeight: true
|
|
}
|
|
|
|
Label {
|
|
id: noPermissionIcon
|
|
|
|
Layout.preferredWidth: parent.columnWidth
|
|
Layout.alignment: Layout.Center
|
|
|
|
font.pixelSize: app.landscape() ? parent.height * 0.25:parent.height * 0.15
|
|
font.family: fa5solid.name
|
|
|
|
horizontalAlignment: Text.AlignHCenter
|
|
|
|
text: "\uf3ed"
|
|
}
|
|
Label {
|
|
id: noPermissionText
|
|
|
|
Layout.preferredWidth: parent.columnWidth
|
|
Layout.alignment: Layout.Center
|
|
|
|
font.bold: true
|
|
font.pixelSize: noPermissionIcon.height * 0.2
|
|
|
|
horizontalAlignment: Text.AlignHCenter
|
|
|
|
wrapMode: Text.Wrap
|
|
|
|
//% "Camera access required"
|
|
text: qsTrId("#cameraPermissionDenied")
|
|
}
|
|
|
|
Label {
|
|
id: noPermissionDetailText
|
|
|
|
Layout.preferredWidth: parent.columnWidth
|
|
Layout.alignment: Layout.Center
|
|
|
|
font.pixelSize: noPermissionText.font.pixelSize * 0.7
|
|
|
|
horizontalAlignment: Text.AlignHCenter
|
|
|
|
wrapMode: Text.Wrap
|
|
|
|
//% "blueROCK needs to access your camera in order to scan QR-Codes. It will never record or store any photos or videos."
|
|
text: qsTrId("#cameraPermissionDeniedDetails")
|
|
}
|
|
|
|
Button {
|
|
id: grantPermissionButton
|
|
|
|
Layout.alignment: Layout.Center
|
|
|
|
//% "Allow access"
|
|
text: qsTrId("#allowAccess")
|
|
|
|
onClicked: control._requestCameraPermission()
|
|
}
|
|
|
|
|
|
Item {
|
|
Layout.fillHeight: true
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
QZXingFilter {
|
|
id: zxingFilter
|
|
|
|
decoder {
|
|
onTagFound: control._handleTag(tag)
|
|
|
|
enabledDecoders: QZXing.DecoderFormat_QR_CODE
|
|
}
|
|
}
|
|
|
|
Timer {
|
|
id: statusTextResetTimer
|
|
running: false
|
|
repeat: false
|
|
interval: 3000
|
|
onTriggered: _setDefaultStatusText()
|
|
}
|
|
}
|