- added ability to view results of athlete

- improved design of athlete view and stack push / pop animations
This commit is contained in:
Dorian Zedler 2019-05-03 22:54:32 +02:00
parent 6b819d3298
commit 33ae172038
7 changed files with 400 additions and 46 deletions

View file

@ -101,6 +101,7 @@ public slots:
Q_INVOKABLE bool createAthlete( QString userName, QString fullName ); Q_INVOKABLE bool createAthlete( QString userName, QString fullName );
Q_INVOKABLE bool deleteAthlete( QString userName ); Q_INVOKABLE bool deleteAthlete( QString userName );
Q_INVOKABLE bool selectAthlete( QString userName ); Q_INVOKABLE bool selectAthlete( QString userName );
Q_INVOKABLE QVariant getResults( QString userName );
Q_INVOKABLE bool reloadBaseStationIpAdress(); Q_INVOKABLE bool reloadBaseStationIpAdress();
}; };

View file

@ -68,7 +68,7 @@ Popup {
StackView { StackView {
id: profiles_stack id: profiles_stack
property int text_pixelSize: headlineUnderline.width * 0.08 property int text_pixelSize: headlineUnderline.width * 0.08
initialItem: profileListComp //initialItem: profileListComp
width: headlineUnderline.width width: headlineUnderline.width
anchors { anchors {
@ -84,44 +84,48 @@ Popup {
NumberAnimation {duration: 200} NumberAnimation {duration: 200}
} }
Connections {
target: root
onOpened: {
profiles_stack.openAthletes()
}
}
onCurrentItemChanged: {
currentItem.opened()
}
function openAthletes() {
var athsComp = profileListComp.createObject(null, {})
profiles_stack.push(athsComp)
}
function openResults( userName ){
var resComp = resultViewComp.createObject(null, {"userName": userName})
profiles_stack.push(resComp)
}
/*-----List of all profiles-----*/ /*-----List of all profiles-----*/
Component { Component {
id: profileListComp id: profileListComp
RemoteDataListView {
ListView {
id: profileList id: profileList
property string title: "profiles" property string title: "profiles"
property string secondButt: "add" property string secondButt: "add"
property var listData: speedBackend.getAthletes()
function loadData() { signal opened()
profileList.enabled = false
listData = speedBackend.getAthletes()
profileList.enabled = true
}
model: listData.length
Connections {
target: root
onOpened: { onOpened: {
profileList.loadData() loadData()
}
} }
Label { loadData: function () {
opacity: profileList.count <= 0 ? 1:0 status = 905
text: "add a profile by clicking +" listData = {}
anchors.centerIn: parent listData = speedBackend.getAthletes()
font.pixelSize: parent.width*0.06 status = listData.lenght !== false ? 200:0
Behavior on opacity {
NumberAnimation {
duration: 200
easing.type: Easing.InOutQuad
}
}
} }
delegate: SwipeDelegate { delegate: SwipeDelegate {
@ -141,14 +145,53 @@ Popup {
} }
onClicked: { onClicked: {
if(speedBackend.selectAthlete(profileList.listData[index]["userName"])){ profiles_stack.openResults(profileList.listData[index]["userName"])
profileList.loadData()
}
} }
background: Rectangle { background: Rectangle {
color: Qt.darker( pressed ? Qt.darker("white", 1.1):"white", swipeDelegate.active ? 1.1:0 ) color: Qt.darker( pressed ? Qt.darker("white", 1.1):"white", swipeDelegate.active ? 1.1:0 )
}
CheckBox {
id: control
anchors {
verticalCenter: parent.verticalCenter
right: parent.right
}
height: parent.height * 0.6
checked: swipeDelegate.active
onCheckedChanged: {
if(checked && !swipeDelegate.active && speedBackend.selectAthlete(profileList.listData[index]["userName"])){
profileList.loadData()
}
}
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.down ? "#17a81a" : "#21be2b"
Rectangle {
width: parent.width * 0.65
height: width
anchors.centerIn: parent
radius: width * 0.2
color: control.down ? "#17a81a" : "#21be2b"
visible: control.checked
}
}
} }
Rectangle { Rectangle {
@ -188,9 +231,12 @@ Popup {
height: parent.height height: parent.height
SwipeDelegate.onClicked: { SwipeDelegate.onClicked: {
profileList.status = 905
if(speedBackend.deleteAthlete(profileList.listData[index]["userName"])){ if(speedBackend.deleteAthlete(profileList.listData[index]["userName"])){
profileList.loadData() profileList.loadData()
return
} }
profileList.status = 200
} }
background: Rectangle { background: Rectangle {
@ -199,10 +245,7 @@ Popup {
} }
} }
} }
ScrollIndicator.vertical: ScrollIndicator { }
} }
} }
/*-----Option to add a profile-----*/ /*-----Option to add a profile-----*/
@ -220,6 +263,7 @@ Popup {
onClicked: { onClicked: {
if(speedBackend.createAthlete(userNameTf.text, fullNameTf.text)){ if(speedBackend.createAthlete(userNameTf.text, fullNameTf.text)){
profiles_stack.get(profiles_stack.depth - 2 ).loadData()
profiles_stack.pop() profiles_stack.pop()
} }
} }
@ -248,25 +292,99 @@ Popup {
} }
} }
/*-----Custom animations-----*/ // --- Result View ---
Component {
id: resultViewComp
RemoteDataListView {
id: resultView
property string userName
property string title: userName
property string secondButt: "none"
signal opened()
onOpened: {
loadData()
}
loadData: function () {
status = 905
listData = {}
listData = speedBackend.getResults(userName)
status = listData.lenght !== false ? 200:0
}
delegate: ItemDelegate {
id: resultDel
width: parent.width
font.pixelSize: profiles_stack.text_pixelSize
text: "result: " + (listData[index]["result"] / 1000).toFixed(3) + " sec \nreaction time: " + listData[index]["reactionTime"].toFixed(0) + " ms"
Rectangle {
color: "grey"
height: 1
width: parent.width * 0.9
visible: index > 0
anchors {
horizontalCenter: parent.horizontalCenter
top: parent.top
}
}
Label {
anchors.top: parent.top
anchors.left: parent.left
font.pixelSize: 10
text: " " + getText()
function getText(){
var date = new Date(listData[index]["timestamp"]*1000).toLocaleDateString(Qt.locale("de_DE"))
return date
console.log(date)
}
}
}
}
}
/*-----Custom animations-----*/
pushEnter: Transition { pushEnter: Transition {
NumberAnimation { NumberAnimation {
property: "opacity" property: "opacity"
from: 0 from: 0
to: 1 to: 1
duration: 200 duration: 300
easing.type: Easing.InOutQuad easing.type: Easing.InOutQuad
} }
NumberAnimation {
property: "x"
from: width * 0.1
to: 0
duration: 300
}
} }
pushExit: Transition { pushExit: Transition {
NumberAnimation { NumberAnimation {
property: "opacity" property: "opacity"
from: 1 from: 1
to: 0 to: 0
duration: 200 duration: 300
easing.type: Easing.InOutQuad easing.type: Easing.InOutQuad
} }
NumberAnimation {
property: "x"
to: -width * 0.1
from: 0
duration: 300
}
} }
popExit: Transition { popExit: Transition {
@ -274,18 +392,30 @@ Popup {
property: "opacity" property: "opacity"
from: 1 from: 1
to: 0 to: 0
duration: 200 duration: 300
easing.type: Easing.InOutQuad easing.type: Easing.InOutQuad
} }
NumberAnimation {
property: "x"
to: width * 0.1
from: 0
duration: 300
}
} }
popEnter: Transition { popEnter: Transition {
NumberAnimation { NumberAnimation {
property: "opacity" property: "opacity"
from: 0 from: 0
to: 1 to: 1
duration: 200 duration: 300
easing.type: Easing.InOutQuad easing.type: Easing.InOutQuad
} }
NumberAnimation {
property: "x"
from: -width * 0.1
to: 0
duration: 300
}
} }
} }
@ -333,14 +463,21 @@ Popup {
onPaint: { onPaint: {
var ctx = getContext("2d"); var ctx = getContext("2d");
var topMargin = backgroundRect.radius
ctx.beginPath(); ctx.beginPath();
ctx.fillStyle = headerBackground.color ctx.fillStyle = headerBackground.color
ctx.moveTo(0, 0); ctx.moveTo(width, topMargin);
//ctx.arc(centreX, centreY, root.width / 2, 1 * Math.PI, 2*Math.PI, false); //
ctx.lineTo(width, 0); //ctx.lineTo(width, topMargin);
ctx.lineTo(width, height); ctx.lineTo(width, height);
ctx.lineTo(0, height); ctx.lineTo(0, height);
ctx.lineTo(0, 0); ctx.lineTo(0, topMargin)
ctx.arc(topMargin, topMargin, topMargin, 1 * Math.PI, 1.5*Math.PI, false);
ctx.lineTo(width-topMargin, 0)
ctx.arc(width-topMargin, topMargin, topMargin, 1.5*Math.PI, 0, false)
ctx.fill(); ctx.fill();
} }
} }
@ -408,6 +545,8 @@ Popup {
height: parent.height * 0.1 height: parent.height * 0.1
width:height width:height
opacity: profiles_stack.currentItem.secondButt !== "none" ? 1:0
glowOpacity: Math.pow( root.opacity, 100 ) glowOpacity: Math.pow( root.opacity, 100 )
backgroundColor: appTheme.style.buttonColor backgroundColor: appTheme.style.buttonColor

View file

@ -520,6 +520,13 @@ Popup {
duration: 300 duration: 300
easing.type: Easing.InOutQuad easing.type: Easing.InOutQuad
} }
NumberAnimation {
property: "x"
from: width * 0.1
to: 0
duration: 300
}
} }
pushExit: Transition { pushExit: Transition {
NumberAnimation { NumberAnimation {
@ -529,6 +536,13 @@ Popup {
duration: 300 duration: 300
easing.type: Easing.InOutQuad easing.type: Easing.InOutQuad
} }
NumberAnimation {
property: "x"
to: -width * 0.1
from: 0
duration: 300
}
} }
popExit: Transition { popExit: Transition {
@ -539,6 +553,12 @@ Popup {
duration: 300 duration: 300
easing.type: Easing.InOutQuad easing.type: Easing.InOutQuad
} }
NumberAnimation {
property: "x"
to: width * 0.1
from: 0
duration: 300
}
} }
popEnter: Transition { popEnter: Transition {
NumberAnimation { NumberAnimation {
@ -548,6 +568,12 @@ Popup {
duration: 300 duration: 300
easing.type: Easing.InOutQuad easing.type: Easing.InOutQuad
} }
NumberAnimation {
property: "x"
from: -width * 0.1
to: 0
duration: 300
}
} }
} }

View file

@ -0,0 +1,95 @@
import QtQuick 2.3
import QtQuick.Controls 2.4
import QtQuick.Controls.Styles 1.2
BusyIndicator {
id: control
property double animationSpeed: 0.5
contentItem: Item {
implicitWidth: 64
implicitHeight: 64
Item {
id: item
x: parent.width / 2 - 32
y: parent.height / 2 - 32
width: 64
height: 64
opacity: control.running ? 1 : 0
property int currentHeight: 0
onCurrentHeightChanged: {
}
Behavior on opacity {
OpacityAnimator {
duration: 250
}
}
SequentialAnimation {
loops: Animation.Infinite
running: true
NumberAnimation {
target: item
duration: 2000 * 1/control.animationSpeed
to: 1000
properties: "currentHeight"
easing.type: Easing.InOutQuad
}
NumberAnimation {
target: item
duration: 2000 * 1/control.animationSpeed
to: 0
properties: "currentHeight"
easing.type: Easing.InOutQuad
}
}
Row {
anchors.fill: parent
spacing: item.width / 9
Repeater {
id: repeater
model: 5
Rectangle {
property double heightMultiplier: Math.abs( Math.sin(( (item.currentHeight + (index*20))*0.01) * (Math.PI/2) ) )
anchors.verticalCenter: parent.verticalCenter
width: item.width / 9
height: ( heightMultiplier ) * ( item.height - 1 ) + 1
radius: width * 0.5
color: "#21be2b"
}
}
}
}
}
}

View file

@ -0,0 +1,77 @@
import QtQuick 2.9
import QtQuick.Controls 2.4
Item {
id: control
property var loadData
property var listData: ({})
property Component delegate
property int status: -1
signal refresh()
Component.onCompleted: {
}
ListView {
id: listView
model: control.listData.length
anchors.fill: parent
enabled: status === 200 || status === 902
opacity: enabled ? 1:0
ScrollBar.vertical: ScrollBar {
parent: listView.parent
anchors {
top: listView.top
left: listView.right
margins: 10
leftMargin: 3
bottom: listView.bottom
}
width: 8
visible: listView.model > 0
active: true
}
delegate: control.delegate
onContentYChanged: {
/*
if(contentY < -listView.height * 0.3 && control.status !== 905){
contentY = 0
control.refresh()
}*/
}
Behavior on opacity {
NumberAnimation {
duration: 200
}
}
Behavior on contentY {
NumberAnimation {
duration: 200
}
}
}
FancyBusyIndicator {
anchors.centerIn: parent
opacity: listView.opacity === 1 ? 0:1
}
}

View file

@ -14,5 +14,7 @@
<file>components/SmoothSwitchDelegate.qml</file> <file>components/SmoothSwitchDelegate.qml</file>
<file>components/InputDelegate.qml</file> <file>components/InputDelegate.qml</file>
<file>components/SmoothSliderDelegate.qml</file> <file>components/SmoothSliderDelegate.qml</file>
<file>components/RemoteDataListView.qml</file>
<file>components/FancyBusyIndicator.qml</file>
</qresource> </qresource>
</RCC> </RCC>

View file

@ -459,7 +459,7 @@ QVariant ClimbingRace::getAthletes() {
QVariantList tmpAthletes = reply["data"].toList(); QVariantList tmpAthletes = reply["data"].toList();
qDebug() << tmpAthletes; //qDebug() << tmpAthletes;
return tmpAthletes; return tmpAthletes;
} }
@ -503,7 +503,7 @@ bool ClimbingRace::selectAthlete( QString userName){
if(reply["status"] != 200){ if(reply["status"] != 200){
//handle Error!! //handle Error!!
qDebug() << "+ --- error deleting athlete: " << reply["status"]; qDebug() << "+ --- error selecting athlete: " << reply["status"];
return false; return false;
} }
@ -511,7 +511,21 @@ bool ClimbingRace::selectAthlete( QString userName){
} }
QVariant ClimbingRace::getResults( QString userName ){
QVariantMap reply = this->baseConn->sendCommand(4004, userName);
if(reply["status"] != 200){
//handle Error!!
qDebug() << "+ --- error getting results: " << reply["status"];
return false;
}
QVariantList tmpAthletes = reply["data"].toList();
//qDebug() << tmpAthletes;
return tmpAthletes;
}
// ------------------------- // -------------------------
// --- functions for qml --- // --- functions for qml ---