269 lines
7.6 KiB
QML
269 lines
7.6 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
|
|
|
|
|
|
Dialog {
|
|
id: control
|
|
|
|
property string _statusText: ""
|
|
property string _statusColor: Material.primaryTextColor
|
|
property bool _freezeScanning: false
|
|
|
|
parent: Overlay.overlay
|
|
|
|
x: (parent.width - width) * 0.5
|
|
y: (parent.height - height) * 0.5
|
|
|
|
height: app.height * 0.8
|
|
width: app.width * 0.8
|
|
|
|
modal: true
|
|
//% "Scan QR-Code"
|
|
title: qsTrId("#scanQrCode")
|
|
|
|
standardButtons: Dialog.Cancel
|
|
|
|
onOpened: {
|
|
setDefaultStatusText()
|
|
control._freezeScanning = false
|
|
if(serverConn.isCameraPermissionGranted())
|
|
cameraLoader.sourceComponent = cameraComponent
|
|
else
|
|
cameraLoader.sourceComponent = noPermissionComponent
|
|
}
|
|
|
|
onClosed: cameraLoader.sourceComponent = null
|
|
|
|
function setDefaultStatusText() {
|
|
//% "Place the Code in the center"
|
|
_statusText = qsTrId("#placeQrCodeInCenter")
|
|
_statusColor = Material.primaryTextColor
|
|
}
|
|
|
|
contentItem: Loader {
|
|
id: cameraLoader
|
|
|
|
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
|
|
}
|
|
}
|
|
|
|
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.3
|
|
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
|
|
Item {
|
|
anchors.fill: parent
|
|
|
|
Label {
|
|
id: noPermissionIcon
|
|
anchors {
|
|
top: parent.top
|
|
topMargin: parent.height * 0
|
|
horizontalCenter: parent.horizontalCenter
|
|
}
|
|
font.pixelSize: parent.height * 0.3
|
|
font.family: fa5solid.name
|
|
text: "\uf3ed"
|
|
}
|
|
Label {
|
|
id: noPermissionText
|
|
anchors {
|
|
top: noPermissionIcon.bottom
|
|
topMargin: noPermissionIcon.height * 0.15
|
|
horizontalCenter: parent.horizontalCenter
|
|
}
|
|
|
|
width: parent.width * 0.9
|
|
|
|
font.bold: true
|
|
font.pixelSize: noPermissionIcon.height * 0.15
|
|
|
|
horizontalAlignment: Text.AlignHCenter
|
|
|
|
wrapMode: Text.Wrap
|
|
|
|
//% "Camera permission denied!"
|
|
text: qsTrId("#cameraPermissionDenied")
|
|
}
|
|
|
|
Label {
|
|
id: noPermissionDetailText
|
|
anchors {
|
|
top: noPermissionText.bottom
|
|
topMargin: noPermissionText.height * 0.15
|
|
horizontalCenter: parent.horizontalCenter
|
|
}
|
|
|
|
width: parent.width * 0.9
|
|
|
|
font.pixelSize: noPermissionText.font.pixelSize * 0.7
|
|
|
|
horizontalAlignment: Text.AlignHCenter
|
|
|
|
wrapMode: Text.Wrap
|
|
|
|
//% "This app requires access to your camera in order to scan QR-Codes. It will never record or store any photos or videos."
|
|
text: qsTrId("#cameraPermissionDeniedDetails")
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
QZXingFilter {
|
|
id: zxingFilter
|
|
|
|
decoder {
|
|
onTagFound: {
|
|
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
|
|
}
|
|
}
|
|
|
|
enabledDecoders: QZXing.DecoderFormat_QR_CODE
|
|
}
|
|
}
|
|
|
|
Timer {
|
|
id: statusTextResetTimer
|
|
running: false
|
|
repeat: false
|
|
interval: 3000
|
|
onTriggered: setDefaultStatusText()
|
|
}
|
|
}
|