/* Speed Climbing Stopwatch - Simple Stopwatch for Climbers Copyright (C) 2018 Itsblue Development - Dorian Zeder This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, version 3 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ import QtQuick 2.9 import QtMultimedia 5.8 import QtQuick.Window 2.2 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import QtGraphicalEffects 1.0 import QtQuick.Controls.Styles 1.4 import "./components" Popup { id: root modal: true dim: false opacity: 0 enter: Transition { NumberAnimation { properties: "opacity"; to: 1; duration: 300; easing.type: Easing.InOutQuad } NumberAnimation { properties: "scale"; from: 0.9; to: 1; duration: 300; easing.type: Easing.InOutQuad } } exit: Transition { NumberAnimation { properties: "opacity"; to: 0; duration: 300; easing.type: Easing.InOutQuad } NumberAnimation { properties: "scale"; from: 1; to: 0.9; duration: 300; easing.type: Easing.InOutQuad } } background: Rectangle { radius: width * 0.5 color: appTheme.style.viewColor border.color: appTheme.style.lineColor border.width: 0 Behavior on color { ColorAnimation { duration: 200 } } RectangularGlow { id: headerUnderlineEffect glowRadius: 7 spread: 0.02 color: "black" opacity: 0.18 anchors.fill: headlineUnderline scale: 1 } Canvas { id: headerBackground anchors { left: parent.left right: parent.right top: parent.top bottom: headlineUnderline.bottom } height: header.height width: header.width property color color: appTheme.style.viewColor Behavior on color { ColorAnimation { duration: 200 } } onColorChanged: { requestPaint() } onPaint: { var ctx = getContext("2d"); ctx.reset(); var centreX = root.width / 2; var centreY = root.height / 2; ctx.beginPath(); ctx.fillStyle = headerBackground.color ctx.moveTo(centreX, centreY); ctx.arc(centreX, centreY, root.width / 2, 1 * Math.PI, 2*Math.PI, false); //ctx.lineTo(centreX, centreY); ctx.fill(); } } Item { id: header anchors { left: parent.left right: parent.right top: parent.top bottom: headlineUnderline.bottom } Label { id: head_text anchors { centerIn: parent } width: headlineUnderline.width * 0.4 height: parent.height fontSizeMode: Text.Fit verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter text: options_stack.currentItem.title font.pixelSize: headlineUnderline.width * 0.1 color: enabled ? appTheme.style.textColor:appTheme.style.disabledTextColor } } Rectangle { id: headlineUnderline height: 1 width: parent.width color: appTheme.style.lineColor visible: false anchors { top: parent.top left: parent.left right: parent.right topMargin: parent.height * 0.15 rightMargin: parent.radius - Math.sqrt(Math.pow(parent.radius,2)-Math.pow(parent.radius-anchors.topMargin,2)) leftMargin: parent.radius - Math.sqrt(Math.pow(parent.radius,2)-Math.pow(parent.radius-anchors.topMargin,2)) } } FancyButton { id: head_back anchors { left: parent.left leftMargin: parent.width * 0.17 top:parent.top topMargin: parent.height * 0.01 } height: parent.height * 0.13 width: height //opacity: root.closePolicy === Popup.NoAutoClose ? 0:1 enabled: opacity > 0 glowOpacity: Math.pow( root.opacity, 100 ) image: appTheme.style.backIcon onClicked: { options_stack.depth > 1 ? options_stack.pop():root.close() } Behavior on opacity { NumberAnimation { duration: 200 } } } } StackView { id: options_stack property int delegateHeight: height * 0.2 property int rowSpacing: height * 0.01 initialItem: settings width: headlineUnderline.width enabled: opacity !== 0 //disable when not visible anchors { top: parent.top left: parent.left leftMargin: ( parent.width - headlineUnderline.width ) / 2 topMargin: headlineUnderline.anchors.topMargin * 0.95 bottom: parent.bottom } Behavior on opacity { NumberAnimation {duration: 200} } /*-----start page of the settings-----*/ Component { id: settings Column { id: settings_col property string title: qsTr("options") spacing: options_stack.rowSpacing /*----Connect to external devices----*/ NextPageDelegate { id: connect_del height: options_stack.delegateHeight text: qsTr("base station") onClicked: { options_stack.push(connect) } } /*----Automated Start----*/ NextPageDelegate { id: autostart_del height: options_stack.delegateHeight text: qsTr("start sequence") onClicked: { options_stack.push(autostart) } } /*----Style Settings----*/ SmoothSwitchDelegate { id: styleDel text: qsTr("dark mode") width: parent.width height: options_stack.delegateHeight checked: speedBackend.readSetting("theme") === "Dark" onCheckedChanged: { speedBackend.writeSetting("theme", checked ? "Dark":"Light") appTheme.refreshTheme() } } } } /*-----Page to setup automatc start sequence-----*/ Component { id: autostart Column { id: autostart_col spacing: options_stack.rowSpacing property string title: "autostart" function updateSetting(key, val, del){ speedBackend.writeSetting(key, val) } function loadSetting(key, del){ return speedBackend.readSetting(key) } SmoothSwitchDelegate { id: ready_del width: parent.width height: options_stack.delegateHeight text: qsTr("say 'ready'") checked: parent.loadSetting("ready_en", ready_del) === "true" onCheckedChanged: { parent.updateSetting("ready_en",checked, ready_del) } } InputDelegate { id: ready_delay_del width: parent.width height: options_stack.delegateHeight enabled: ready_del.checked text: qsTr("delay (ms)") inputHint: qsTr("time") inputMethodHints: Qt.ImhFormattedNumbersOnly inputText: autostart_col.loadSetting("ready_delay", ready_del) onInputFinished: { autostart_col.updateSetting("ready_delay", inputText, ready_delay_del) } } SmoothSwitchDelegate { id: at_marks_del width: parent.width height: options_stack.delegateHeight text: qsTr("say 'at your marks'") checked: autostart_col.loadSetting("at_marks_en", ready_del) === "true" onCheckedChanged: { parent.updateSetting("at_marks_en",at_marks_del.checked, at_marks_del) } } InputDelegate { id: at_marks_delay_del width: parent.width height: options_stack.delegateHeight text: qsTr("delay (ms)") inputHint: qsTr("time") inputMethodHints: Qt.ImhFormattedNumbersOnly enabled: at_marks_del.checked inputText: autostart_col.loadSetting("at_marks_delay", at_marks_delay_del) onInputFinished: { autostart_col.updateSetting("at_marks_delay", inputText, at_marks_delay_del) } } } } /*-----Page to connect to the base station -----*/ Component { id: connect Column { id: connectCol property string title: qsTr("base station") spacing: options_stack.rowSpacing property bool baseConnected: speedBackend.baseStationState === "connected" opacity: 0 ConnectionDelegate { id: connectToBaseDel text: status.status === "connected" ? qsTr("disconnect"): status.status === "disconnected" ? qsTr("connect"):qsTr("connecting...") status: { "status": speedBackend.baseStationState, "progress": 100 } connect: speedBackend.connectBaseStation disconnect: speedBackend.disconnectBaseStation type: "baseStation" width: parent.width height: options_stack.delegateHeight } Loader { id: baseStationOptionsLd property alias parentComp: connectCol property alias baseConnected: connectCol.baseConnected onBaseConnectedChanged: { disappearAnim.start() } Component.onCompleted: { baseStationOptionsLd.sourceComponent = connectCol.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 = connectCol.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) speedBackend.reloadBaseStationIpAdress() } width: parent.width height: options_stack.delegateHeight visible: height > 5 Behavior on height { NumberAnimation { duration: 400 easing.type: Easing.Linear } } } SmoothItemDelegate { id: baseStationHelpDel width: parent.width height: options_stack.delegateHeight text: qsTr("what is this for?") onClicked: { Qt.openUrlExternally("https://itsblue.de/index.php/speed-climbing?ref=ScStwApp") } } } } Component { id: baseStationConnectedOptionsComp Column { id: baseStationConnectedOptions width: parentComp.width opacity: 0 // opacity and scale are adjusted by baseStationOptionsLd scale: 0.95 SmoothSliderDelegate { id: baseStationVolumeDel text: qsTr("volume") width: parent.width height: options_stack.delegateHeight sliderValue: 0 onSliderFinished: { speedBackend.writeSetting("soundVolume", sliderValue) } Component.onCompleted: { var val = speedBackend.readSetting("soundVolume") console.log(val) if(val !== "false"){ sliderValue = parseFloat(val) } } Behavior on height { NumberAnimation { duration: 400 easing.type: Easing.Linear } } } NextPageDelegate { id: baseStationConnectionsDel text: qsTr("connected extensions") width: parent.width height: options_stack.delegateHeight visible: height > 5 onClicked: { options_stack.push(baseStationConnections) } Behavior on height { NumberAnimation { duration: 400 easing.type: Easing.Linear } } } } } } } /*-----Page to view devices that core connected to the pase startion-----*/ Component{ id: baseStationConnections ListView { id: baseStationConnections_list property string title: qsTr("connections") spacing: options_stack.rowSpacing boundsBehavior: Flickable.StopAtBounds model: speedBackend.baseStationConnections.length delegate: ConnectionDelegate { opacity: 1 width: parent.width height: options_stack.delegateHeight text: speedBackend.baseStationConnections[index]["name"] status: {'status': speedBackend.baseStationConnections[index]["state"], 'progress': speedBackend.baseStationConnections[index]["progress"]} } } } /*-----Custom animations-----*/ pushEnter: Transition { NumberAnimation { property: "opacity" from: 0 to: 1 duration: 300 easing.type: Easing.InOutQuad } NumberAnimation { property: "x" from: width * 0.1 to: 0 duration: 300 } } pushExit: Transition { NumberAnimation { property: "opacity" from: 1 to: 0 duration: 300 easing.type: Easing.InOutQuad } NumberAnimation { property: "x" to: -width * 0.1 from: 0 duration: 300 } } popExit: Transition { NumberAnimation { property: "opacity" from: 1 to: 0 duration: 300 easing.type: Easing.InOutQuad } NumberAnimation { property: "x" to: width * 0.1 from: 0 duration: 300 } } popEnter: Transition { NumberAnimation { property: "opacity" from: 0 to: 1 duration: 300 easing.type: Easing.InOutQuad } NumberAnimation { property: "x" from: -width * 0.1 to: 0 duration: 300 } } } }