reaction-trainer/qml/main.qml

386 lines
10 KiB
QML
Raw Normal View History

2019-04-06 20:16:16 +02:00
/*
Speed climbing reaction timer
Copyright (C) 2019 Itsblue Development | Dorian Zedler
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, either version 3 of the License, or
(at your option) any later version.
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 <http://www.gnu.org/licenses/>.
*/
2019-04-06 20:09:40 +02:00
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.4
import QtMultimedia 5.0
import QtGraphicalEffects 1.0
import QtQuick.Controls.Styles 1.4
import com.itsblue.SpeedClimbingStartTrainer 2.0
import "./Components"
Window {
visible: true
width: 640
height: 480
title: qsTr("Speed climbing reaction trainer")
2019-04-06 20:09:40 +02:00
Page {
id: app
state: "IDLE"
anchors.fill: parent
property double startTime: -1
property double stopTime: -1
property double reactionTime: 0
property int highscore: settings.read("highscore")
AppSettings {
id: settings
}
AppTheme {
id: theme
}
Item {
id: soundsItm
SoundEffect {
id: readySe
source: "qrc:/sounds/ready_1.wav"
muted: app.state === "WAITING"
onPlayingChanged: {
if(!playing && app.state === "RUNNING"){
startSe.play()
}
}
}
SoundEffect {
id: startSe
source: "qrc:/sounds/IFSC_STARTSIGNAL_SINE.wav"
2019-04-06 20:09:40 +02:00
muted: app.state === "WAITING"
onPlayingChanged: {
if(!playing){
app.startTime = new Date().getTime()
console.log("offset: ", new Date().getTime() - app.startTime)
if(app.state === "WAITING"){
app.reactionTime = app.stopTime - app.startTime
app.state = "STOPPED"
}
}
}
}
SoundEffect {
id: failedSe
source: "qrc:/sounds/IFSC frequenzy conform false start sound.wav"
2019-04-06 20:09:40 +02:00
}
}
Rectangle {
anchors.fill: parent
color: theme.style.backgroundColor
Behavior on color {
ColorAnimation {
duration: 200
}
}
}
Item {
id: topContainerItm
anchors {
top: parent.top
left: parent.left
right: app.landscape() ? startBt.left:parent.right
bottom: app.landscape() ? parent.bottom:startBt.top
bottomMargin: app.landscape() ? undefined:parent.height * 0.1
rightMargin: app.landscape() ? parent.width * 0.05:0
}
Text {
id: topLa
anchors.centerIn: parent
width: parent.width * 0.8
text: ""
color: theme.style.textColor
fontSizeMode: Text.Fit
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
font.pixelSize: app.landscape() ? parent.width * 0.1 : parent.height * 0.4
minimumPixelSize: 0
Behavior on text {
FadeAnimation{
target: topLa
}
}
}
Text {
id: highscoreLa
anchors {
top: topLa.bottom
horizontalCenter: parent.horizontalCenter
}
width: topLa.width * 0.5
height: topLa.height
visible: text !== "highscore: -1"
text: ""
color: theme.style.textColor
fontSizeMode: Text.Fit
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
font.pixelSize: app.landscape() ? parent.width * 0.1 : parent.height * 0.4
minimumPixelSize: 0
Behavior on text {
FadeAnimation{
target: highscoreLa
}
}
}
Switch {
anchors {
top: topLa.bottom
horizontalCenter: parent.horizontalCenter
horizontalCenterOffset: width * 0.1
}
checked: settings.read("theme") === "1"
scale: 0.8
opacity: app.state === "IDLE" ? 1:0
onCheckedChanged: {
if(checked){
settings.write("theme", 1)
}
else {
settings.write("theme", 0)
}
theme.refreshTheme()
}
indicator: Rectangle {
property bool checked: parent.checked
property bool down: parent.down
height: parent.height
width: height * 2
radius: height * 0.5
color: parent.checked ? "#17a81a" : "transparent"
border.color: parent.checked ? "#17a81a" : "#cccccc"
Behavior on color{
ColorAnimation{
duration: 200
}
}
Rectangle {
x: parent.checked ? parent.width - width : 0
width: parent.height
height: parent.height
radius: height * 0.5
color: parent.down ? theme.style.buttonPressedColor:theme.style.backgroundColor //"#cccccc" : "#ffffff"
border.color: parent.checked ? (parent.down ? "#17a81a" : "#21be2b") : "#999999"
Behavior on x{
NumberAnimation {
property: "x"
duration: 200
easing.type: Easing.InOutQuad
}
}
}
}
Behavior on opacity {
NumberAnimation {
duration: 200
}
}
}
}
FancyButton {
id: startBt
text: "start"
property int size: app.landscape() ? parent.width * 0.5:parent.height * 0.5
backgroundColor: theme.style.buttonColor
textColor: theme.style.textColor
anchors {
bottom: parent.bottom
right: parent.right
bottomMargin: app.landscape() ? parent.height * 0.5 - startBt.height * 0.5:parent.height * 0.1
rightMargin: app.landscape() ? parent.width * 0.05:parent.width * 0.5 - startBt.width * 0.5
}
font.pixelSize: height * 0.15
height: app.landscape() ? (size > parent.height * 0.9 ? parent.height * 0.9:size) : (size > parent.width * 0.9 ? parent.width * 0.9:size)
width: height
onPressed: {
app.start()
}
onReleased: {
app.stop()
}
}
function landscape() {
return app.height < app.width
}
function start() {
if(app.state !== "IDLE"){
app.reset()
return
}
app.state = "RUNNING"
readySe.play()
}
function stop() {
app.stopTime = new Date().getTime()
if(app.state !== "RUNNING"){
return
}
if(startSe.playing){
app.state = "WAITING"
failedSe.play()
}
else if(readySe.playing){
app.state = "IDLE"
}
else {
app.state = "STOPPED"
app.reactionTime = app.stopTime - app.startTime
app.refreshHighscore()
}
}
function refreshHighscore(){
if(app.reactionTime > 0 && ( app.reactionTime < parseInt(settings.read("highscore")) || settings.read("highscore") === "-1" )){
settings.write("highscore", app.reactionTime)
app.highscore = app.reactionTime
}
}
function reset() {
app.state = "IDLE"
}
states: [
State {
name: "IDLE"
PropertyChanges {
target: topLa
text: "Hold down start to start"
}
},
State {
name: "RUNNING"
PropertyChanges {
target: topLa
text: "release to stop"
}
},
State {
name: "STOPPED"
PropertyChanges {
target: topLa
text: "Your reaction time: " + app.reactionTime
}
PropertyChanges {
target: startBt
text: "reset"
}
PropertyChanges {
target: highscoreLa
text: "highscore: " + app.highscore
}
},
State {
name: "WAITING"
PropertyChanges {
target: topLa
text: "please wait..."
}
PropertyChanges {
target: startBt
enabled: false
text: "waiting..."
}
}
]
}
}