import QtQuick 2.9 import QtMultimedia 5.8 import QtQuick.Window 2.2 import QtQuick.Controls 2.12 import QtQuick.Layouts 1.3 import QtGraphicalEffects 1.0 import QtQuick.Controls.Styles 1.4 import QtQuick.Templates 2.12 as T import com.itsblue.speedclimbingstopwatch 2.0 import "../components" Column { id: control property string title: qsTr("base station") property bool baseConnected: speedBackend.scStwClient.state === ScStwClient.CONNECTED property var parentObj opacity: 0 function doFirmwareUpdate() { doFirmwareUpdateTimer.start() } Timer { id: doFirmwareUpdateTimer interval: 10 repeat: false running: false onTriggered: { busyDl.open() var ret = speedBackend.scStwClient.updateFirmware() busyDl.displayMessageAndClose(ret ? "OK":"error", ret ? "#6bd43b":"#e03b2f" ) } } ConnectionDelegate { id: connectToBaseDel function clientStateToString(state) { switch(state) { case ScStwClient.DISCONNECTED: return "disconnected" case ScStwClient.CONNECTING: return "connecting" case ScStwClient.INITIALISING: return "connecting" case ScStwClient.CONNECTED: return "connected" } } text: status.status === "connected" ? qsTr("disconnect"): status.status === "disconnected" ? qsTr("connect"):qsTr("connecting...") status: { "status": clientStateToString(speedBackend.scStwClient.state), "progress": 100 } connect: speedBackend.scStwClient.connectToHost disconnect: speedBackend.scStwClient.closeConnection type: "baseStation" width: parent.width height: parentObj.delegateHeight } Loader { id: baseStationOptionsLd property alias parentComp: control property alias baseConnected: control.baseConnected onBaseConnectedChanged: { disappearAnim.start() } Component.onCompleted: { baseStationOptionsLd.sourceComponent = control.baseConnected ? baseStationConnectedOptionsComp : baseStationDisconnectedOptionsComp item.opacity = 1 item.scale = 1 } sourceComponent: null ParallelAnimation { id: disappearAnim NumberAnimation { property: "opacity" to: 0 duration: 100 target: baseStationOptionsLd.item } NumberAnimation { property: "scale" to: 0.95 duration: 100 target: baseStationOptionsLd.item } onRunningChanged: { if(!running) { baseStationOptionsLd.sourceComponent = control.baseConnected ? baseStationConnectedOptionsComp : baseStationDisconnectedOptionsComp appearAnim.start() } } } ParallelAnimation { id: appearAnim NumberAnimation { property: "opacity" from: 0 to: 1 duration: 100 target: baseStationOptionsLd.item } NumberAnimation { property: "scale" from: 0.95 to: 1 duration: 100 target: baseStationOptionsLd.item } } } Component { id: baseStationDisconnectedOptionsComp Column { id: baseStationDisconnectedOptions width: parentComp.width opacity: 0 // opacity and scale are adjusted by baseStationOptionsLd scale: 0.95 InputDelegate { id: baseStationIpDel text: qsTr("IP") inputHint: "IP" inputText: speedBackend.readSetting("baseStationIpAdress") inputTextFieldWidth: width * 0.7 onInputTextChanged: { speedBackend.writeSetting("baseStationIpAdress", inputText) } width: parent.width height: parentObj.delegateHeight visible: height > 5 Behavior on height { NumberAnimation { duration: 400 easing.type: Easing.Linear } } } SmoothItemDelegate { id: baseStationHelpDel width: parent.width height: parentObj.delegateHeight text: qsTr("what is this for?") onClicked: { Qt.openUrlExternally("https://itsblue.de/index.php/speed-climbing?ref=ScStwApp") } } } } Component { id: baseStationConnectedOptionsComp ScrollView{ id: flickable contentHeight: baseStationConnectedOptions.childrenRect.height contentWidth: -1 width: parentComp.width height: control.height - baseStationOptionsLd.y clip: true opacity: 0 // opacity and scale are adjusted by baseStationOptionsLd scale: 0.95 ScrollBar.horizontal.policy: ScrollBar.AlwaysOff ScrollBar.vertical: ScrollBar { parent: flickable.parent anchors.top: flickable.top anchors.left: flickable.right anchors.bottom: flickable.bottom policy: ScrollBar.AlwaysOn interactive: false } Column { id: baseStationConnectedOptions width: parentComp.width SmoothSliderDelegate { id: baseStationVolumeDel text: qsTr("volume") width: parent.width height: parentObj.delegateHeight sliderValue: 0 onSliderFinished: { enabled = false speedBackend.writeSetting("SoundVolume", sliderValue) enabled = true } Component.onCompleted: { var val = speedBackend.readSetting("SoundVolume") if(val !== "false"){ sliderValue = parseFloat(val) } } } NextPageDelegate { id: baseStationConnectionsDel text: qsTr("connected extensions") width: parent.width height: parentObj.delegateHeight visible: height > 5 onClicked: { parentObj.push(baseStationConnections) } } SmoothItemDelegate { id: connectUsbExtensionsDel width: parent.width height: parentObj.delegateHeight text: "pair extensions" onClicked: { busyDl.open() var ret = speedBackend.scStwClient.pairConnectedUsbExtensions() busyDl.displayMessageAndClose(ret === 200 ? "OK":"error", ret === 200 ? "#6bd43b":"#e03b2f" ) } } SmoothItemDelegate { id: baseStationUpdateDel // 0: hidden 1: update firmware 2: sync time property int mode: speedBackend.scStwClient.isFirmwareUpToDate() ? (Math.abs(parseInt(speedBackend.scStwClient.getTimeOffset())) > 10000 ? 2:0) :1 width: parent.width height: mode > 0 ? parentObj.delegateHeight:0 visible: height > 5 text: mode === 2 ? qsTr("sync time"):qsTr("update firmware") onClicked: { if(mode === 1) { control.doFirmwareUpdate() } else if(mode === 2){ busyDl.open() var ret = speedBackend.scStwClient.updateTime() busyDl.displayMessageAndClose(ret ? "OK":"error", ret ? "#6bd43b":"#e03b2f" ) } } } Rectangle { anchors.left: parent.left width: parent.width height: 1 color: appTheme.style.lineColor } Item { anchors.left: parent.left width: parent.width height: parentObj.delegateHeight * 0.5 Label { anchors { top: parent.top left: parent.left } width: parent.width * 0.5 height: parent.height * 0.5 verticalAlignment: Text.AlignTop horizontalAlignment: Text.AlignLeft fontSizeMode: Text.Fit font.pixelSize: height minimumPixelSize: 1 color: appTheme.style.lineColor text: "version: " + speedBackend.scStwClient.getFirmwareVersion() } Label { property var date: new Date(new Date().getTime() + parseInt(speedBackend.scStwClient.getTimeOffset())) anchors { top: parent.top right: parent.right } width: parent.width * 0.5 height: parent.height verticalAlignment: Text.AlignTop horizontalAlignment: Text.AlignRight fontSizeMode: Text.Fit minimumPixelSize: 1 font.pixelSize: height color: appTheme.style.lineColor text: date.toLocaleDateString() + "\n" + date.toLocaleTimeString() } } } } } Popup { id: busyDl property string message: "" property color messageColor: "transparent" x: Math.round((parent.width - width) / 2) y: Math.round((parent.height - height) / 2) width: app.width height: app.height modal: true dim: true closePolicy: Dialog.NoAutoClose function displayMessageAndClose(message, messageColor) { busyDl.message = message busyDl.messageColor = messageColor closeDelayTimer.start() } Timer { id: closeDelayTimer interval: 1000 repeat: false running: false onTriggered: { busyDl.close() busyDl.message = "" busyDl.messageColor = "transparent" } } background: Item { FancyBusyIndicator { anchors.centerIn: parent opacity: busyDl.message === "" ? 1:0 lineColor: "white" Behavior on opacity { NumberAnimation { duration: 150 } } } Label { anchors.centerIn: parent width: parent.width * 0.5 height: parent.height * 0.5 opacity: busyDl.message === "" ? 0:1 color: busyDl.messageColor text: busyDl.message fontSizeMode: Text.Fit font.pixelSize: height minimumPixelSize: 1 font.bold: true verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter Behavior on opacity { NumberAnimation { duration: 150 } } } } T.Overlay.modal: Rectangle { id: modalRect color: "#80404040" Behavior on opacity { NumberAnimation { duration: 150 } } } } }