diff --git a/SettingsDialog.qml b/SettingsDialog.qml
new file mode 100644
index 0000000..8a60145
--- /dev/null
+++ b/SettingsDialog.qml
@@ -0,0 +1,90 @@
+import QtQuick 2.9
+import QtMultimedia 5.8
+import QtQuick.Window 2.2
+import QtQuick.Controls 2.2
+
+Dialog {
+
+ x: startButt.x
+ y: startButt.y
+ width: startButt.width
+ height: startButt.height
+ modal: false
+ enabled: false
+
+ enter: Transition {
+ NumberAnimation { properties: "scale"; from: 0; to: 1; duration: 500; easing.type: Easing.InCubic }
+ }
+
+ exit: Transition {
+ NumberAnimation { properties: "scale"; from: 1; to: 0; duration: 500; easing.type: Easing.OutCubic }
+ }
+
+
+ background: Rectangle {
+ radius: width * 0.5
+ color: "white"
+ border.color: "grey"
+ border.width: 1
+ Label {
+ text: "Options"
+ font.pixelSize: headlineUnderline.width * 0.1
+ anchors {
+ horizontalCenter: parent.horizontalCenter
+ top: parent.top
+ topMargin: headlineUnderline.anchors.topMargin / 2 - height / 2
+ }
+ }
+
+ Rectangle {
+ id: headlineUnderline
+ height: 1
+ width: parent.width
+ color: "grey"
+ 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))
+ }
+ }
+ }
+ Column {
+ anchors.fill: parent
+
+ ItemDelegate {
+ id: connect_del
+ anchors.fill: parent
+ text: "connect"
+ onClicked: {
+ var i;
+ if(i === 100){
+ i = 0
+ running = false
+ }
+
+ var theUrl = "http://192.168.4.1";
+ var xmlHttp = null;
+
+ xmlHttp = new XMLHttpRequest();
+ xmlHttp.open( "GET", theUrl, false );
+ xmlHttp.setRequestHeader("Content-type", "text/plain;charset=UTF-8");
+ xmlHttp.send( null );
+ var response = xmlHttp.responseText
+ var response_status = xmlHttp.status
+ connect_del.text = response
+ var res = response.split("
");
+ var time_now = new Date().getTime()
+ console.log(time_now)
+ console.log(res[1])
+ console.log(time_now-res[0])
+ root.buzzer_offset = time_now-res[0]
+ root.last_button_pressed = res[1]
+ console.log("buzzer_offset: "+root.buzzer_offset)
+ connect_del.text = response
+ }
+ }
+ }
+}
diff --git a/buzzerconn.cpp b/buzzerconn.cpp
new file mode 100644
index 0000000..e95acf2
--- /dev/null
+++ b/buzzerconn.cpp
@@ -0,0 +1,94 @@
+#include "buzzerconn.h"
+
+BuzzerConn::BuzzerConn(QObject *parent) : QObject(parent)
+{
+ this->networkManager = new QNetworkAccessManager();
+ connect();
+}
+
+bool BuzzerConn::connect()
+{
+ QList times = gettimes();
+
+ if(times[0] == 200.0){
+ this->connected = true;
+ calcoffset();
+ calcoffset();
+ calcoffset();
+ return(true);
+ }
+ else{
+ return(false);
+ }
+}
+
+void BuzzerConn::calcoffset()
+{
+ QList times = gettimes();
+ QDateTime * date = new QDateTime;
+ double offset = date->currentMSecsSinceEpoch() - times[2];
+ this->latest_offsets.append(offset);
+ double mem = 0;
+ for(int i=0;ioffset = mem / double(latest_offsets.length());
+}
+
+QList BuzzerConn::gettimes()
+{
+ QList times;
+ ReturnData_t ret = senddata(QUrl("http://192.168.4.1"));
+ times.append(double(ret.status_code));
+
+ if(ret.status_code == 200){
+ qDebug()<");
+ times.append(times_cache[0].toDouble());
+ times.append(times_cache[1].toDouble());
+
+ return(times);
+ }
+ else{
+ return(times);
+ }
+}
+
+ReturnData_t BuzzerConn::senddata(QUrl serviceUrl)
+{
+
+ ReturnData_t ret; //this is a custom type to store the returned data
+ // Call the webservice
+
+ QNetworkRequest request(serviceUrl);
+ request.setHeader(QNetworkRequest::ContentTypeHeader,
+ "application/x-www-form-urlencoded");
+
+ //set ssl configuration
+ //send a POST request with the given url and data to the server
+ QUrlQuery pdata;
+ QNetworkReply* reply;
+
+ reply = this->networkManager->post(request, pdata.toString(QUrl::FullyEncoded).toUtf8());
+
+ //wait until the request has finished
+ QEventLoop loop;
+ loop.connect(this->networkManager, SIGNAL(finished(QNetworkReply*)), SLOT(quit()));
+ loop.exec();
+
+ //get the status code
+ QVariant status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
+
+ ret.status_code = status_code.toInt();
+ if(ret.status_code == 0){ //if tehstatus code is zero, the connecion to the server was not possible
+ ret.status_code = 444;
+ }
+ //get the full text response
+ ret.text = QString::fromUtf8(reply->readAll());
+
+ //return the data
+ return(ret);
+}
diff --git a/buzzerconn.h b/buzzerconn.h
new file mode 100644
index 0000000..1bb22e0
--- /dev/null
+++ b/buzzerconn.h
@@ -0,0 +1,39 @@
+#ifndef BUZZERCONN_H
+#define BUZZERCONN_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+typedef struct strReturnData{
+ int status_code;
+ QString text;
+}ReturnData_t;
+
+class BuzzerConn : public QObject
+{
+ Q_OBJECT
+public:
+ explicit BuzzerConn(QObject *parent = nullptr);
+ double offset;
+ QList latest_offsets;
+ bool connected;
+
+private:
+ QNetworkAccessManager *networkManager;
+
+signals:
+
+public slots:
+ ReturnData_t senddata(QUrl serviceUrl);
+ QList gettimes();
+ bool connect();
+ void calcoffset();
+};
+
+#endif // BUZZERCONN_H
diff --git a/main.cpp b/main.cpp
index 259b549..0478a4a 100644
--- a/main.cpp
+++ b/main.cpp
@@ -6,11 +6,34 @@
#include
#include
#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
#ifdef Q_OS_ANDROID
#include
#endif
#include "sqlstoragemodel.h"
#include "sqlprofilemodel.h"
+#include "buzzerconn.h"
static void connectToDatabase()
{
@@ -44,11 +67,15 @@ int main(int argc, char *argv[])
QGuiApplication app(argc, argv);
- QAndroidJniObject jactivity=QtAndroid::androidActivity();
- if(jactivity.isValid())
- jactivity.callMethod("setVolumeControlStream","(I)V",3);
+ #ifdef Q_OS_ANDROID
+ //set the standard volume to media
+ QAndroidJniObject jactivity=QtAndroid::androidActivity();
+ if(jactivity.isValid())
+ jactivity.callMethod("setVolumeControlStream","(I)V",3);
+ #endif
connectToDatabase();
+ BuzzerConn * pBuzzerConn = new BuzzerConn;
//setup the sql storage model as a qml model
qmlRegisterType("com.itsblue.speedclimbingstopwatch", 1, 0, "SqlProfileModel");
@@ -59,5 +86,7 @@ int main(int argc, char *argv[])
if (engine.rootObjects().isEmpty())
return -1;
+ engine.rootContext()->setContextProperty("_cppBuzzerConn", pBuzzerConn);
+
return app.exec();
}
diff --git a/main.qml b/main.qml
index 39d2886..11cf8cc 100644
--- a/main.qml
+++ b/main.qml
@@ -23,6 +23,10 @@ Window {
property double stoppedTime: 0
property double currTime: new Date().getTime()
+ property double buzzer_offset
+ property double last_button_pressed
+
+
state: "IDLE"
Timer {
@@ -32,6 +36,33 @@ Window {
interval: 1
onTriggered: {
root.currTime = new Date().getTime()
+
+ }
+ }
+
+ Timer {
+ id: running_refresh_timer
+ running: root.state === "RUNNING"
+ repeat: true
+ interval: 1
+
+ onTriggered: {
+ var theUrl = "http://192.168.4.1";
+ var xmlHttp = null;
+
+ xmlHttp = new XMLHttpRequest();
+ xmlHttp.open( "GET", theUrl, false );
+ xmlHttp.send( null );
+ var response = xmlHttp.responseText
+ var res = response.split("
");
+ startButt.text = res[0]
+ if(res[1]>root.last_button_pressed){
+ root.last_button_pressed = res[1]
+ root.stoppedTime = (root.last_button_pressed + root.buzzer_offset) - root.startTime
+ console.log("STOPPED: "+root.stoppedTime)
+ time.text = ( root.stoppedTime / 1000 ).toFixed(3) + " sec"
+ root.state = "STOPPED"
+ }
}
}
@@ -86,96 +117,100 @@ Window {
/*----------------------
Start button
----------------------*/
- Rectangle {
- id: startButt
+ Button {
+ id : startButt
- property string text: "start"
+ text: "start"
property int size: root.landscape() ? parent.width * 0.5:parent.height * 0.5
anchors {
bottom: parent.bottom
- bottomMargin: parent.height * 0.5 - height * 0.5
+ bottomMargin: root.height * 0.5 - height * 0.5
right: parent.right
- rightMargin: parent.width * 0.5 - width * 0.5
+ rightMargin: root.width * 0.5 - width * 0.5
+ }
+ contentItem: Text {
+ //make text disappear
}
-
height: root.landscape() ? size > parent.height * 0.9 ? parent.height * 0.9:size : size
width: root.landscape() ? size : size > parent.width * 0.9 ? parent.width * 0.9:size
- color: "white"
- border.color: "grey"
- border.width: 1
- radius: width / 2
-
- Label {
- id: startButt_text
- text: parent.text
- anchors.centerIn: parent
- font.pixelSize: parent.height * 0.16
- font.family: "Helvetica"
- }
- MouseArea {
- enabled: startButt.enabled
- anchors.fill: parent
- onPressed: parent.color = "lightgrey"
- onReleased: parent.color = "white"
- onClicked: {
- switch(root.state) {
- case "":
- root.state = "IDLE"
- case "IDLE":
- root.state = "STARTING"
- startSound.play()
- break
- case "RUNNING":
- root.stoppedTime = new Date().getTime() - root.startTime
- time.text = ( root.stoppedTime / 1000 ).toFixed(3) + " sec"
- root.state = "STOPPED"
- break
- case "STOPPED":
- root.state = "IDLE"
- break
- }
+ onPressedChanged: {
+ if(pressed){
+ background.color = "lightgrey"
+ }
+ else {
+ background.color = "white"
}
}
+
+ background: Rectangle {
+ color: "white"
+ border.color: "grey"
+ border.width: 1
+ radius: width / 2
+ Label {
+ id: startButt_text
+ text: startButt.text
+ anchors.centerIn: parent
+ font.pixelSize: parent.height * 0.16
+ font.family: "Helvetica"
+ }
+ }
+
+ onClicked: {
+ switch(root.state) {
+ case "":
+ root.state = "IDLE"
+ case "IDLE":
+ root.state = "STARTING"
+ startSound.play()
+ break
+ case "RUNNING":
+ root.stoppedTime = new Date().getTime() - root.startTime
+ time.text = ( root.stoppedTime / 1000 ).toFixed(3) + " sec"
+ root.state = "STOPPED"
+ break
+ case "STOPPED":
+ root.state = "IDLE"
+ break
+ }
+ }
+
}
/*----------------------
Cancel button
----------------------*/
- Rectangle {
+ RoundButton {
id: cancelButt
- property string text: "cancel"
+ text: "cancel"
anchors {
right: startButt.right
bottom: startButt.bottom
}
+ contentItem: Text {
+ //make text disappear
+ }
height: startButt.height * 0.3
scale: 0
width: height
- color: "white"
- border.color: "grey"
- border.width: 1
- radius: width / 2
- Label {
- id: cancelButt_text
- text: parent.text
- anchors.centerIn: parent
- font.pixelSize: parent.height * 0.16
- font.family: "Helvetica"
- }
- MouseArea {
- enabled: startSound.playing
- anchors.fill: parent
- onPressed: parent.color = "lightgrey"
- onReleased: parent.color = "white"
- onClicked: {
- startSound.stop()
- root.stoppedTime = 0
- time.text = "false start"
- root.state = "STOPPED"
+ enabled: startSound.playing
+ onPressedChanged: {
+ if(pressed){
+ background.color = "lightgrey"
}
+ else {
+ background.color = "white"
+ }
+ }
+
+ onClicked: {
+ startSound.stop()
+ root.stoppedTime = 0
+ time.text = "false start"
+ root.state = "STOPPED"
}
Behavior on scale {
@@ -183,8 +218,29 @@ Window {
duration: 200
}
}
+ background: Rectangle {
+ color: "white"
+ border.color: "grey"
+ border.width: 1
+ radius: width / 2
+ Label {
+ id: cancelButt_text
+ text: cancelButt.text
+ anchors.centerIn: parent
+ font.pixelSize: parent.height * 0.16
+ font.family: "Helvetica"
+ }
+ }
}
+ /*------
+ Popups
+ ------*/
+ SettingsDialog{
+ id:settingsDialog
+ }
+
+
/*-------------------
lower line and menu
-------------------*/
@@ -208,10 +264,9 @@ Window {
leftMargin: root.landscape() ? parent.width * 0.05:0
}
- Rectangle {
+ RoundButton {
id: settingsButt
- property string text: "cancel"
anchors {
//center
verticalCenter: root.landscape() ? undefined:parent.verticalCenter
@@ -223,45 +278,52 @@ Window {
topMargin: root.landscape() ? (parent.height - (height * 2)) / 3:undefined
//align in portrait mode
leftMargin: root.landscape() ? undefined:(parent.width - width * 2) / 3
-
-
}
+
height: root.landscape() ? parent.width * 0.7:parent.height * 0.7
width: height
- color: "white"
- border.color: "grey"
- border.width: 1
- radius: width / 2
-
- Image {
- id: settungsButt_Image
- source: "qrc:/graphics/icons/settings.png"
- anchors.centerIn: parent
- height: parent.height * 0.7
- width: parent.width * 0.7
- mipmap: true
- }
-
- MouseArea {
- enabled: root.state === "IDLE"
- anchors.fill: parent
- onPressed: parent.color = "lightgrey"
- onReleased: parent.color = "white"
- onClicked: {
+ onPressedChanged: {
+ if(pressed){
+ background.color = "lightgrey"
+ }
+ else {
+ background.color = "white"
}
}
- Behavior on scale {
- PropertyAnimation {
- duration: 200
+ onClicked: {
+ if(settingsDialog.enabled === false){
+ settingsDialog.open()
+ settingsDialog.enabled = true
+ }
+ else {
+ settingsDialog.enabled = false
+ settingsDialog.close()
+ }
+ }
+
+ background: Rectangle {
+ color: "white"
+ border.color: "grey"
+ border.width: 1
+ radius: width / 2
+
+
+ Image {
+ id: settungsButt_Image
+ source: "qrc:/graphics/icons/settings.png"
+ anchors.centerIn: parent
+ height: parent.height * 0.7
+ width: parent.width * 0.7
+ mipmap: true
}
}
}
- Rectangle {
+
+ RoundButton {
id: profilesButt
- property string text: "cancel"
anchors {
verticalCenter: root.landscape() ? undefined:parent.verticalCenter
horizontalCenter: root.landscape() ? parent.horizontalCenter:undefined
@@ -270,39 +332,45 @@ Window {
topMargin: root.landscape() ? (parent.height - (height * 2)) / 3:undefined
leftMargin: root.landscape() ? undefined:(parent.width - width * 2) / 3
}
+
height: root.landscape() ? parent.width * 0.7:parent.height * 0.7
-
width: height
- color: "white"
- border.color: "grey"
- border.width: 1
- radius: width / 2
- Image {
- id: profilesButt_Image
- source: "qrc:/graphics/icons/user.png"
- anchors.centerIn: parent
- height: parent.height * 0.5
- width: parent.width * 0.5
- mipmap: true
- }
-
- MouseArea {
- enabled: root.state === "IDLE"
- anchors.fill: parent
- onPressed: parent.color = "lightgrey"
- onReleased: parent.color = "white"
- onClicked: {
+ onPressedChanged: {
+ if(pressed){
+ background.color = "lightgrey"
+ }
+ else {
+ background.color = "white"
}
}
- Behavior on scale {
- PropertyAnimation {
- duration: 200
+ onClicked: {
+ var theUrl = "http://192.168.4.1";
+ var xmlHttp = null;
+
+ xmlHttp = new XMLHttpRequest();
+ xmlHttp.open( "GET", theUrl, false );
+ xmlHttp.send( null );
+ console.log(xmlHttp.responseText)
+ }
+
+ background: Rectangle {
+ color: "white"
+ border.color: "grey"
+ border.width: 1
+ radius: width / 2
+
+ Image {
+ id: profilesButt_Image
+ source: "qrc:/graphics/icons/user.png"
+ anchors.centerIn: parent
+ height: parent.height * 0.5
+ width: parent.width * 0.5
+ mipmap: true
}
}
}
-
}
diff --git a/qml.qrc b/qml.qrc
index 11e786b..8272b66 100644
--- a/qml.qrc
+++ b/qml.qrc
@@ -2,5 +2,6 @@
main.qml
FadeAnimation.qml
+ SettingsDialog.qml
diff --git a/speedclimbing_stopwatch.pro b/speedclimbing_stopwatch.pro
index 061ba3d..51c0fef 100644
--- a/speedclimbing_stopwatch.pro
+++ b/speedclimbing_stopwatch.pro
@@ -21,7 +21,8 @@ TARGET = speedclimbing_stw
SOURCES += \
main.cpp \
sqlstoragemodel.cpp \
- sqlprofilemodel.cpp
+ sqlprofilemodel.cpp \
+ buzzerconn.cpp
RESOURCES += qml.qrc \
shared.qrc
@@ -50,4 +51,5 @@ android {
HEADERS += \
sqlstoragemodel.h \
- sqlprofilemodel.h
+ sqlprofilemodel.h \
+ buzzerconn.h
diff --git a/sqlstoragemodel.h b/sqlstoragemodel.h
index cc5eede..d756a92 100644
--- a/sqlstoragemodel.h
+++ b/sqlstoragemodel.h
@@ -6,6 +6,7 @@
class SqlStorageModel : public QObject
{
Q_OBJECT
+
public:
explicit SqlStorageModel(QObject *parent = nullptr);