diff --git a/headers/baseconn.h b/headers/baseconn.h index e3ead24..8c96b9e 100644 --- a/headers/baseconn.h +++ b/headers/baseconn.h @@ -96,8 +96,12 @@ public slots: void gotError(QAbstractSocket::SocketError err); + // --- socket communication handling --- + Q_INVOKABLE QVariantMap sendCommand(int header, QJsonValue data = ""); + // --- helper functions --- + Q_INVOKABLE int writeRemoteSetting(QString key, QString value); Q_INVOKABLE bool refreshConnections(); @@ -116,6 +120,10 @@ public slots: private slots: void readyRead(); + void processSocketMessage(QString message); + + void socketReplyRecieved(QString reply); + void socketStateChanged(QAbstractSocket::SocketState socketState); }; extern BaseConn * pGlobalBaseConn; diff --git a/qml/ProfilesDialog.qml b/qml/ProfilesDialog.qml index fc675be..3dba153 100644 --- a/qml/ProfilesDialog.qml +++ b/qml/ProfilesDialog.qml @@ -131,7 +131,7 @@ Popup { loadData: function () { status = 905 - listData = {} + //listData = {} var retData = speedBackend.getAthletes() if(retData === undefined){ @@ -151,8 +151,7 @@ Popup { text: profileList.listData[index]["fullName"] width: profileList.width - (swipeDelegate.x) - - + height: profileList.height / 5 font.pixelSize: profiles_stack.text_pixelSize @@ -164,8 +163,35 @@ Popup { profiles_stack.openResults(profileList.listData[index]["userName"]) } + contentItem: Text { + visible: false + } + + Text { + + anchors { + verticalCenter: parent.verticalCenter + left: parent.left + leftMargin: swipeDelegate.width * 0.05 + right: parent.right + rightMargin: swipeDelegate.rightPadding + } + + text: swipeDelegate.text + color: appTheme.style.textColor + + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignLeft + + fontSizeMode: Text.Fit + + font.pixelSize: swipeDelegate.height * 0.4 + + minimumPixelSize: 1 + } + background: Rectangle { - color: Qt.darker( pressed ? Qt.darker("white", 1.1):"white", swipeDelegate.active ? 1.1:0 ) + color: pressed ? appTheme.style.delegatePressedColor : appTheme.style.delegateBackgroundColor Behavior on color { @@ -205,6 +231,7 @@ Popup { 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 @@ -273,7 +300,7 @@ Popup { Label { id: deleteLabel text: qsTr("Delete") - color: "white" + color: appTheme.style.textColor verticalAlignment: Label.AlignVCenter padding: 12 height: parent.height @@ -353,6 +380,7 @@ Popup { signal opened() + onOpened: { loadData() } @@ -364,14 +392,18 @@ Popup { status = listData.lenght !== false ? 200:0 } - delegate: ItemDelegate { + delegate: SmoothItemDelegate { id: resultDel width: parent.width + height: resultView.height / 4 - font.pixelSize: profiles_stack.text_pixelSize + backgroundRect.radius: 0 - text: "result: " + (listData[index]["result"] / 1000).toFixed(3) + " sec \nreaction time: " + listData[index]["reactionTime"].toFixed(0) + " ms" + function getDateText(){ + var date = new Date(listData[index]["timestamp"]*1000).toLocaleString(Qt.locale(), "dddd, dd.MMM HH:mm") + return date + } Rectangle { color: "grey" @@ -384,18 +416,47 @@ Popup { } } - Label { - anchors.top: parent.top - anchors.left: parent.left + Column { + anchors.fill: parent + anchors.leftMargin: parent.width * 0.05 - font.pixelSize: 10 + Label { + id: dateLa - text: " " + getText() + height: parent.height / parent.children.length - function getText(){ - var date = new Date(listData[index]["timestamp"]*1000).toLocaleDateString(Qt.locale("de_DE")) - return date - console.log(date) + font.pixelSize: height * 0.8 + fontSizeMode: Text.Fit + + color: appTheme.style.textColor + + text: resultDel.getDateText() + } + + Label { + id: resultLa + + height: parent.height / parent.children.length + + font.pixelSize: height * 0.8 + fontSizeMode: Text.Fit + + color: appTheme.style.textColor + + text: qsTr("result: ") + (listData[index]["result"] / 1000).toFixed(3) + " s" + } + + Label { + id: reactionTimeLa + + height: parent.height / parent.children.length + + font.pixelSize: height * 0.8 + fontSizeMode: Text.Fit + + color: appTheme.style.textColor + + text: qsTr("reaction time: ") + listData[index]["reactionTime"].toFixed(0) + " ms" } } } @@ -548,6 +609,8 @@ Popup { verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter + color: appTheme.style.textColor + text: profiles_stack.currentItem.title } @@ -611,6 +674,9 @@ Popup { leftMargin: parent.width/2 - width/2 } opacity: profiles_stack.currentItem.secondButt === "add" ? 1:0 + + color: appTheme.style.textColor + text: "+" font.pixelSize: parent.height } diff --git a/qml/SettingsDialog.qml b/qml/SettingsDialog.qml index 4487de4..b71938f 100644 --- a/qml/SettingsDialog.qml +++ b/qml/SettingsDialog.qml @@ -192,7 +192,6 @@ Popup { glowOpacity: Math.pow( root.opacity, 100 ) - backgroundColor: appTheme.style.buttonColor image: appTheme.style.backIcon onClicked: { diff --git a/qml/components/FancyButton.qml b/qml/components/FancyButton.qml index c5f5f7b..28dd8a3 100644 --- a/qml/components/FancyButton.qml +++ b/qml/components/FancyButton.qml @@ -6,7 +6,7 @@ Button { id: control property string image - property color backgroundColor: "white" + property color backgroundColor: appTheme.style.buttonColor property real imageScale: 1 property double glowRadius: 0.001 property double glowSpread: 0.2 @@ -16,7 +16,7 @@ Button { - scale: control.pressed ? 0.8:1 + //scale: control.pressed ? 0.8:1 Behavior on scale { PropertyAnimation { @@ -24,12 +24,6 @@ Button { } } - Behavior on backgroundColor { - ColorAnimation { - duration: 200 - } - } - background: Item { id: controlBackgroundContainer @@ -48,13 +42,19 @@ Button { } Rectangle { - id: controlBackground + id: controlBackground anchors.fill: parent radius: height * 0.5 - color: control.backgroundColor + color: control.down ? Qt.darker(control.backgroundColor, 1.2) : control.backgroundColor + + Behavior on color { + ColorAnimation { + duration: 200 + } + } Image { id: buttonIcon diff --git a/qml/components/RemoteDataListView.qml b/qml/components/RemoteDataListView.qml index e8bc730..e184bab 100644 --- a/qml/components/RemoteDataListView.qml +++ b/qml/components/RemoteDataListView.qml @@ -1,4 +1,4 @@ -import QtQuick 2.9 +import QtQuick 2.10 import QtQuick.Controls 2.4 Item { @@ -7,6 +7,7 @@ Item { property var loadData property var listData: ({}) property Component delegate + property alias view: listView property int status: -1 @@ -23,11 +24,12 @@ Item { anchors.fill: parent + boundsBehavior: Flickable.DragOverBounds + boundsMovement: Flickable.StopAtBounds + //enabled: status === 200 || status === 902 //opacity: enabled ? 1:0 - boundsBehavior: ListView.StopAtBounds - ScrollBar.vertical: ScrollBar { parent: listView.parent diff --git a/qml/components/SmoothItemDelegate.qml b/qml/components/SmoothItemDelegate.qml index a1547de..c3627d0 100644 --- a/qml/components/SmoothItemDelegate.qml +++ b/qml/components/SmoothItemDelegate.qml @@ -4,8 +4,8 @@ import QtQuick.Controls 2.2 ItemDelegate { id: control text: "" - font.pixelSize: options_stack.text_pixelSize property color textColor: appTheme.style.textColor + property alias backgroundRect: backgroundRect opacity: enabled ? 1 : 0.2 @@ -26,16 +26,20 @@ ItemDelegate { text: control.text color: appTheme.style.textColor + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignLeft + fontSizeMode: Text.Fit font.pixelSize: control.height * 0.4 - minimumPixelSize: 0 + minimumPixelSize: 1 } width: parent.width background: Rectangle { + id: backgroundRect color: control.down ? appTheme.style.delegatePressedColor : appTheme.style.delegateBackgroundColor radius: height * 0.3 diff --git a/sources/baseconn.cpp b/sources/baseconn.cpp index effe924..7dd55d2 100644 --- a/sources/baseconn.cpp +++ b/sources/baseconn.cpp @@ -122,6 +122,10 @@ void BaseConn::gotError(QAbstractSocket::SocketError err) qDebug() << "got socket error: " << strError; } +// ------------------------------------- +// --- socket communication handling --- +// ------------------------------------- + QVariantMap BaseConn::sendCommand(int header, QJsonValue data){ if(this->state != "connected"){ return {{"status", 910}, {"data", "not connected"}}; @@ -178,8 +182,6 @@ QVariantMap BaseConn::sendCommand(int header, QJsonValue data){ // stop the timer as the connection has been established timer.stop(); - timer.deleteLater(); - return {{"status", reply.value("header").toInt()}, {"data", reply.value("data").toVariant()}}; } @@ -189,17 +191,64 @@ void BaseConn::readyRead() { //qDebug() << "ready to ready " << socket->bytesAvailable() << " bytes" ; QString reply = socket->readAll(); - if(!reply.endsWith("")){ - this->readBuffer += reply; + //qWarning() << "socket read: " << reply; + + processSocketMessage(reply); +} + +void BaseConn::processSocketMessage(QString message){ + QString startKey = ""; + QString endKey = ""; + + //qWarning() << "... processing message now ... : " << message; + + if(message == ""){ return; } - else { + + if((message.startsWith(startKey) && message.endsWith(endKey)) && (message.count(startKey) == 1 && message.count(endKey) == 1)){ + // non-split message ( e.g.: 123456789 + } + else if(!message.contains(endKey) && (!this->readBuffer.isEmpty() || message.startsWith(startKey))){ + // begin of a split message ( e.g.: 123 ) + // or middle of a split message ( e.g.: 456 ) + //qWarning() << "this is a begin or middle of split a message"; + this->readBuffer += message; + return; + } + else if(!message.contains(startKey) && message.endsWith(endKey)) { + // end of a split message ( e.g.: 789 ) + if(!this->readBuffer.isEmpty()){ - reply = readBuffer + reply; + message = readBuffer + message; readBuffer.clear(); } } + else if((message.count(startKey) > 1 || message.count(endKey) > 1) || (message.contains(endKey) && !message.endsWith(endKey) && message.contains(startKey) && !message.startsWith(startKey))) { + // multiple messages in one packet ( e.g.: 123456789987654321 ) + // or multiple message fragments in one message ( e.g.: 56789987654321 or 5678998765 ) + //qDebug() << "detected multiple messages"; + int startOfSecondMessage = message.lastIndexOf(startKey); + // process first part of message + QString firstMessage = message.left(startOfSecondMessage); + this->processSocketMessage(firstMessage); + // process second part of message + QString secondMessage = message.right(message.length() - startOfSecondMessage); + this->processSocketMessage(secondMessage); + + return; + } + else { + // invalid message + return; + } + + //qWarning() << "... done processing, message: " << message; + this->socketReplyRecieved(message); +} + +void BaseConn::socketReplyRecieved(QString reply) { reply.replace("", ""); reply.replace("", ""); @@ -216,7 +265,9 @@ void BaseConn::readyRead() { for(int i = 0; i < this->waitingRequests.length(); i++){ if(this->waitingRequests[i].id == id){ this->waitingRequests[i].reply = replyObj; - this->waitingRequests[i].loop->quit(); + if(this->waitingRequests[i].loop != nullptr){ + this->waitingRequests[i].loop->quit(); + } return; } } @@ -224,9 +275,12 @@ void BaseConn::readyRead() { latestReadReply = reply; emit gotUnexpectedReply(reply); - } +// ------------------------ +// --- helper functions --- +// ------------------------ + int BaseConn::writeRemoteSetting(QString key, QString value) { QJsonArray requestData; requestData.append(key); @@ -257,6 +311,7 @@ void BaseConn::socketStateChanged(QAbstractSocket::SocketState socketState) { switch (socketState) { case QAbstractSocket::UnconnectedState: { + this->deInit(); this->setState("disconnected"); break; }