Commit fb453d40 authored by Dorian Zedler's avatar Dorian Zedler

- athlete and time storage now supports multiple timers

- some design improvements
- removed translations
parent 499cd247
......@@ -100,7 +100,7 @@ public slots:
Q_INVOKABLE QVariant getAthletes();
Q_INVOKABLE bool createAthlete( QString userName, QString fullName );
Q_INVOKABLE bool deleteAthlete( QString userName );
Q_INVOKABLE bool selectAthlete( QString userName );
Q_INVOKABLE bool selectAthlete( QString userName, int timerId );
Q_INVOKABLE QVariant getResults( QString userName );
Q_INVOKABLE bool reloadBaseStationIpAdress();
......
/*
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 <https://www.gnu.org/licenses/>.
*/
import QtQuick 2.9
import QtMultimedia 5.8
import QtQuick.Window 2.2
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import com.itsblue.speedclimbingstopwatch 2.0
Popup {
id: root
x: startButt.x
y: startButt.y
width: startButt.width
height: startButt.height
modal: true
enter: Transition {
NumberAnimation { properties: "scale"; from: 0; to: 1; duration: 300; easing.type: Easing.Linear }
}
exit: Transition {
NumberAnimation { properties: "scale"; from: 1; to: 0; duration: 300; easing.type: Easing.Linear }
}
background: Rectangle {
radius: width * 0.5
color: appTheme.style.viewColor
border.color: appTheme.style.lineColor
border.width: 1
Label {
id: head_text
text: "error"
font.pixelSize: headlineUnderline.width * 0.1
color: enabled ? appTheme.style.textColor:appTheme.style.disabledTextColor
anchors {
horizontalCenter: parent.horizontalCenter
top: parent.top
topMargin: headlineUnderline.anchors.topMargin / 2 - height / 2
}
}
Rectangle {
id: headlineUnderline
height: 1
width: parent.width
color: appTheme.style.lineColor
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))
}
}
Image {
id: errorIcon
source: "qrc:/graphics/icons/error.png"
anchors.centerIn: parent
height: parent.height * 0.5
width: height
}
}
}
......@@ -60,7 +60,7 @@ RemoteDataListView {
delegate: SwipeDelegate {
id: swipeDelegate
property bool active: profileList.currentAthlete === profileList.listData[index]["id"]
property int thisIndex: index
text: profileList.listData[index]["fullName"]
width: profileList.width - (swipeDelegate.x)
......@@ -86,8 +86,8 @@ RemoteDataListView {
verticalCenter: parent.verticalCenter
left: parent.left
leftMargin: swipeDelegate.width * 0.05
right: parent.right
rightMargin: swipeDelegate.rightPadding
right: athleteSelectBoxRow.left
rightMargin: leftMargin
}
text: swipeDelegate.text
......@@ -114,73 +114,92 @@ RemoteDataListView {
}
}
CheckBox {
id: control
Row {
id: athleteSelectBoxRow
anchors {
verticalCenter: parent.verticalCenter
right: parent.right
rightMargin: 7
}
height: parent.height * 0.6
height: parent.height
width: childrenRect.width
checked: swipeDelegate.active
Repeater {
id: athleteSelectBoxRep
onCheckedChanged: {
if(checked && !swipeDelegate.active && speedBackend.selectAthlete(profileList.listData[index]["userName"])){
profileList.loadData()
}
}
model: speedBackend.timers.length
indicator: Rectangle {
implicitWidth: 26
implicitHeight: 26
delegate: CheckBox {
id: control
height: parent.height
width: height
x: control.leftPadding
y: parent.height / 2 - height / 2
radius: width * 0.2
border.color: control.down ? "#17a81a" : "#21be2b"
color: control.down ? appTheme.style.delegatePressedColor : appTheme.style.delegateBackgroundColor
Rectangle {
width: parent.width * 0.65
height: width
anchors.centerIn: parent
radius: control.checked ? width * 0.2:0
color: control.down ? "#17a81a" : "#21be2b"
opacity: control.checked ? 1:0
scale: control.checked ? 0.9:0
Behavior on color {
ColorAnimation {
duration: 200
}
}
property bool active: speedBackend.timers[index]["id"] === profileList.listData[swipeDelegate.thisIndex]["active"]
Behavior on radius {
NumberAnimation {
duration: 200
}
}
anchors.verticalCenter: parent.verticalCenter
height: parent.height * 0.6
Behavior on opacity {
NumberAnimation {
duration: 200
enabled: speedBackend.timers[index]["state"] !== "DISABLED"
checked: control.active
onCheckedChanged: {
if(checked && !control.active && speedBackend.selectAthlete(profileList.listData[swipeDelegate.thisIndex]["userName"], speedBackend.timers[index]["id"])){
profileList.loadData()
}
}
Behavior on scale {
NumberAnimation {
duration: 200
indicator: Rectangle {
implicitWidth: 26
implicitHeight: 26
height: parent.height
width: height
x: control.leftPadding
y: parent.height / 2 - height / 2
radius: width * 0.2
border.color: control.enabled ? control.down ? "#17a81a" : "#21be2b" : "grey"
color: control.down ? appTheme.style.delegatePressedColor : appTheme.style.delegateBackgroundColor
Rectangle {
width: parent.width * 0.65
height: width
anchors.centerIn: parent
radius: control.checked ? width * 0.2:0
color: control.enabled ? control.down ? "#17a81a" : "#21be2b" : "grey"
opacity: control.checked ? 1:0
scale: control.checked ? 0.9:0
Behavior on color {
ColorAnimation {
duration: 200
}
}
Behavior on radius {
NumberAnimation {
duration: 200
}
}
Behavior on opacity {
NumberAnimation {
duration: 200
}
}
Behavior on scale {
NumberAnimation {
duration: 200
}
}
}
}
}
}
}
Rectangle {
......
......@@ -26,7 +26,7 @@ SmoothItemDelegate {
onStatusChanged: {
if(oldState !== status.status) {
if(status.status === "disconnected" && oldState === "connecting") {
statusIndicator.color_override = "red"
statusIndicator.color_override = appTheme.style.errorColor
shortDelay.start()
}
oldState = status.status
......@@ -57,11 +57,11 @@ SmoothItemDelegate {
id: statusIndicator
property string color_override: ""
anchors.fill: parent
color: color_override === "" ? status.status === "connected" ? "#c1ff32":"transparent":color_override
color: color_override === "" ? status.status === "connected" ? appTheme.style.successColor:"transparent":color_override
opacity: status.status === "connecting" ? 0:1
radius: height * 0.5
border.color: "grey"
border.width: height * 0.1
border.color: appTheme.style.lineColor
border.width: 1
Behavior on color {
ColorAnimation {
......@@ -81,11 +81,11 @@ SmoothItemDelegate {
id: prog
anchors.fill: parent
opacity: status.status === "connecting" ? 1:0
lineWidth: height * 0.1
lineWidth: 1
arcBegin: 0
arcEnd: 360 * ( status.progress / 100 )
colorCircle: "grey"
colorCircle: appTheme.style.lineColor
onColorCircleChanged: prog.repaint()
onArcEndChanged: prog.repaint()
......
This diff is collapsed.
......@@ -7,7 +7,6 @@
<file>components/FadeAnimation.qml</file>
<file>components/ConnectionIcon.qml</file>
<file>components/NextPageDelegate.qml</file>
<file>ErrorDialog.qml</file>
<file>components/FancyButton.qml</file>
<file>components/SmoothItemDelegate.qml</file>
<file>components/SmoothSwitchDelegate.qml</file>
......
......@@ -15,8 +15,6 @@
<file>sounds/at_marks_2.wav</file>
<file>graphics/icons/buzzer_black.png</file>
<file>graphics/icons/ok_black.png</file>
<file>translations/de_DE.qm</file>
<file>translations/de_DE.ts</file>
<file>graphics/icons/settings_black.png</file>
<file>graphics/icons/startpad_black.png</file>
<file>sounds/false.wav</file>
......
......@@ -25,8 +25,8 @@ AppTheme::AppTheme(QObject *parent) : QObject(parent)
{"sliderColor", "#6ccaf2"},
{"errorColor", "#ba3f62"},
{"infoColor", "#3fba62"},
{"successColor", "#6bd43b"},
{"errorColor", "#e03b2f"},
{"lineColor", "grey"},
......@@ -63,8 +63,8 @@ AppTheme::AppTheme(QObject *parent) : QObject(parent)
{"sliderColor", "#6ccaf2"},
{"errorColor", "#ba3f62"},
{"infoColor", "#3fba62"},
{"successColor", "#60de26"},
{"errorColor", "#ff0000"},
{"lineColor", "grey"},
......
......@@ -394,7 +394,7 @@ void ClimbingRace::refreshTimerText() {
QVariantList newTimerTextList;
foreach(SpeedTimer * timer, this->speedTimers){
QVariantMap timerMap = {{"text",timer->getText()}, {"reacttime", timer->reactionTime}, {"state", timer->getState()}};
QVariantMap timerMap = {{"text",timer->getText()}, {"reacttime", timer->reactionTime}, {"state", timer->getState()}, {"id", this->speedTimers.indexOf(timer)}};
newTimerTextList.append(timerMap);
}
......@@ -526,9 +526,9 @@ bool ClimbingRace::deleteAthlete( QString userName ){
}
bool ClimbingRace::selectAthlete( QString userName){
bool ClimbingRace::selectAthlete( QString userName, int timerId ){
QVariant requestData = QVariantMap({{"userName", userName}});
QVariant requestData = QVariantMap({{"userName", userName}, {"timerId", timerId}});
QVariantMap reply = this->baseConn->sendCommand(4000, requestData.toJsonValue());
......
......@@ -115,26 +115,16 @@ int main(int argc, char *argv[])
qmlRegisterType<SqlProfileModel>("com.itsblue.speedclimbingstopwatch", 1, 0, "SqlProfileModel");
qmlRegisterType<SqlStorageModel>("com.itsblue.speedclimbingstopwatch", 1, 0, "SqlStorageModel");
//setup the startpad and buzzer conn qml objects
//qmlRegisterType<BuzzerConn>("com.itsblue.speedclimbingstopwatch", 1, 0, "BuzzerConn");
//qmlRegisterType<BuzzerConn>("com.itsblue.speedclimbingstopwatch", 1, 0, "StartpadConn");
//qmlRegisterType<BaseConn>("com.itsblue.speedclimbingstopwatch", 1, 0, "BaseStationConn");
//qmlRegisterType<SpeedTimerQmlAdapter>("com.itsblue.speedclimbingstopwatch", 1, 0, "SpeedTimerBackend");
// setup speed backend and App themes
qmlRegisterType<ClimbingRace>("com.itsblue.speedclimbingstopwatch", 2, 0, "SpeedBackend");
qmlRegisterType<AppTheme>("com.itsblue.speedclimbingstopwatch", 2, 0, "AppTheme");
//setup translation engine
//to the language of the system
//if the system language is not found the language is set to english
QTranslator translator;
translator.load(":/translations/"+QLocale::system().name()+".qm");
app.installTranslator(&translator);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
QQmlContext *context = engine.rootContext();
// stup app settings
context->setContextProperty("_cppAppSettings", pAppSettings);
if (engine.rootObjects().isEmpty())
......
......@@ -96,21 +96,21 @@ void SpeedTimer::setState(timerState newState){
QString SpeedTimer::getState(){
switch(state){
case IDLE:
return("IDLE");
return "IDLE";
case STARTING:
return("STARTING");
return "STARTING";
case WAITING:
return ("WAITING");
return "WAITING";
case RUNNING:
return("RUNNING");
return "RUNNING";
case WON:
return "WON";
case LOST:
return "LOST";
case FAILED:
return("FAILED");
return "FAILED";
case CANCELLED:
return("CANCELLED");
return "CANCELLED";
case DISABLED:
return "DISABLED";
}
......@@ -134,13 +134,13 @@ QString SpeedTimer::getText() {
QString newText;
switch (this->state) {
case SpeedTimer::IDLE:
newText = tr("Click Start to start");
newText = "0.000 sec";
break;
case SpeedTimer::STARTING:
newText = "0.000 sec";
break;
case SpeedTimer::WAITING:
newText = tr("Please wait...");
newText = "Please wait...";
break;
case SpeedTimer::RUNNING:
newText = QString::number( this->getCurrTime() / 1000.0, 'f', 3 ) + " sec";
......@@ -152,10 +152,10 @@ QString SpeedTimer::getText() {
newText = QString::number( this->stoppedTime / 1000.0, 'f', 3 ) + " sec";
break;
case SpeedTimer::FAILED:
newText = tr("False Start");
newText = "False Start";
break;
case SpeedTimer::CANCELLED:
newText = tr("Cancelled");
newText = "Cancelled";
break;
case SpeedTimer::DISABLED:
newText = "---";
......
......@@ -43,8 +43,6 @@ RESOURCES += \
shared.qrc \
qml/qml.qrc
TRANSLATIONS = translations/de_DE.ts
# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =
......@@ -63,8 +61,7 @@ else: unix:!android: target.path = /home/pi/$${TARGET}/bin
DISTFILES += \
android-sources/AndroidManifest.xml \
CHANGELOG \
android-sources/src/MainActivity.java \
translations/german_de.ts
android-sources/src/MainActivity.java
android {
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android-sources
......
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="de_DE" sourcelanguage="en">
<context>
<name>InputDelegate</name>
<message>
<source>delay (ms)</source>
<translation type="vanished">Verzögerung (ms)</translation>
</message>
</context>
<context>
<name>SettingsDialog</name>
<message>
<location filename="../qml/SettingsDialog.qml" line="236"/>
<source>Options</source>
<translation>Optionen</translation>
</message>
<message>
<source>connected to buzzer</source>
<translation type="vanished">Mit Buzzer verbunden</translation>
</message>
<message>
<source>connect to buzzer</source>
<translation type="vanished">Mit Buzzer verbinden</translation>
</message>
<message>
<location filename="../qml/SettingsDialog.qml" line="387"/>
<source>connecting...</source>
<translation>verbinde...</translation>
</message>
<message>
<source>success!</source>
<translation type="vanished">Erfolg</translation>
</message>
<message>
<source>error!</source>
<translation type="vanished">Fehler</translation>
</message>
<message>
<location filename="../qml/SettingsDialog.qml" line="245"/>
<location filename="../qml/SettingsDialog.qml" line="379"/>
<source>Base Station</source>
<translation>Base Station</translation>
</message>
<message>
<location filename="../qml/SettingsDialog.qml" line="257"/>
<source>start sequence</source>
<translation>Start Ablauf</translation>
</message>
<message>
<location filename="../qml/SettingsDialog.qml" line="267"/>
<source>dark mode</source>
<translation>dunkler Modus</translation>
</message>
<message>
<location filename="../qml/SettingsDialog.qml" line="310"/>
<source>say &apos;ready&apos;</source>
<translation>sage &apos;ready&apos;</translation>
</message>
<message>
<location filename="../qml/SettingsDialog.qml" line="327"/>
<location filename="../qml/SettingsDialog.qml" line="359"/>
<source>delay (ms)</source>
<translation>Verzögerung (ms)</translation>
</message>
<message>
<location filename="../qml/SettingsDialog.qml" line="328"/>
<location filename="../qml/SettingsDialog.qml" line="360"/>
<source>time</source>
<translation>Zeit</translation>
</message>
<message>
<location filename="../qml/SettingsDialog.qml" line="344"/>
<source>say &apos;at your marks&apos;</source>
<translation>sage &apos;at your marks&apos;</translation>
</message>
<message>
<location filename="../qml/SettingsDialog.qml" line="387"/>
<source>disconnect</source>
<translation>trennen</translation>
</message>
<message>
<location filename="../qml/SettingsDialog.qml" line="387"/>
<source>connect</source>
<translation>verbinden</translation>
</message>
<message>
<location filename="../qml/SettingsDialog.qml" line="403"/>
<source>IP-Adress</source>
<translation>IP-Adresse</translation>
</message>
<message>
<location filename="../qml/SettingsDialog.qml" line="429"/>
<source>volume</source>
<translation>Lautstärke</translation>
</message>
<message>
<location filename="../qml/SettingsDialog.qml" line="465"/>
<source>connected extensions</source>
<translation>verbundene Erweiterungen</translation>
</message>
<message>
<location filename="../qml/SettingsDialog.qml" line="492"/>
<source>connections</source>
<translation>Verbindungen</translation>
</message>
<message>
<source>say
&apos;at your marks&apos;</source>
<translation type="vanished">sage
&apos;at your marks&apos;</translation>
</message>
</context>
<context>
<name>SpeedTimer</name>
<message>
<location filename="../sources/speedtimer.cpp" line="130"/>
<source>Click Start to start</source>
<translation>Tippe start zum Starten</translation>
</message>
<message>
<location filename="../sources/speedtimer.cpp" line="136"/>
<source>Please wait...</source>
<translation>Bitte warten...</translation>
</message>
<message>
<location filename="../sources/speedtimer.cpp" line="145"/>
<source>False Start</source>
<translation>Fehlstart</translation>
</message>
<message>
<location filename="../sources/speedtimer.cpp" line="148"/>
<source>Cancelled</source>
<translation>Abgebrochen</translation>
</message>
</context>
<context>
<name>main</name>
<message>
<location filename="../qml/main.qml" line="33"/>
<source>Speedclimbing stw</source>
<translation></translation>
</message>
<message>
<source>Click start to start</source>
<translation type="vanished">Tippe start zum Starten</translation>
</message>
<message>
<location filename="../qml/main.qml" line="222"/>
<source>reaction time (ms): </source>
<translation>Reaktionszeit (ms): </translation>
</message>
<message>
<location filename="../qml/main.qml" line="349"/>
<location filename="../qml/main.qml" line="629"/>
<source>start</source>
<translation>start</translation>
</message>
<message>
<location filename="../qml/main.qml" line="426"/>
<source>cancel</source>
<translation>Abbruch</translation>
</message>
<message>
<location filename="../qml/main.qml" line="636"/>
<source>Click Start to start</source>
<translation type="unfinished">Tippe start zum Starten</translation>
</message>
<message>
<location filename="../qml/main.qml" line="644"/>
<source>waiting...</source>
<translation>warte...</translation>
</message>
<message>
<location filename="../qml/main.qml" line="652"/>
<source>please wait...</source>
<translation>Bitte warten...</translation>
</message>
<message>
<location filename="../qml/main.qml" line="658"/>
<location filename="../qml/main.qml" line="666"/>
<source>starting...</source>
<translation>starte...</translation>
</message>
<message>
<source>false start</source>
<translation type="vanished">Fehlstart</translation>
</message>
<message>
<location filename="../qml/main.qml" line="686"/>
<source>reset</source>
<translation>reset</translation>
</message>
</context>
</TS>
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
<context>
<name>SettingsDialog</name>
<message>
<location filename="../qml/SettingsDialog.qml" line="275"/>
<source>say &apos;ready&apos;</source>
<translation>fertig</translation>
</message>
<message>
<location filename="../qml/SettingsDialog.qml" line="316"/>
<source>say
&apos;at your marks&apos;</source>
<translation type="unfinished">auf die Plätze</translation>
</message>
</context>
<context>
<name>main</name>
<message>
<location filename="../qml/main.qml" line="30"/>
<source>Speedclimbing stw</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/main.qml" line="195"/>
<location filename="../qml/main.qml" line="540"/>
<source>Click start to start</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/main.qml" line="246"/>
<location filename="../qml/main.qml" line="549"/>
<source>start</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/main.qml" line="346"/>
<source>cancel</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/main.qml" line="559"/>
<source>starting...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/main.qml" line=<