diff --git a/android-sources/AndroidManifest.xml b/android-sources/AndroidManifest.xml index a627afb..8edc7fe 100644 --- a/android-sources/AndroidManifest.xml +++ b/android-sources/AndroidManifest.xml @@ -1,7 +1,7 @@ - - - + + + @@ -11,7 +11,7 @@ - + diff --git a/android-sources/res/drawable-hdpi/icon.png b/android-sources/res/drawable-hdpi/icon.png index 4908bc2..fa868e0 100644 Binary files a/android-sources/res/drawable-hdpi/icon.png and b/android-sources/res/drawable-hdpi/icon.png differ diff --git a/android-sources/res/drawable-ldpi/icon.png b/android-sources/res/drawable-ldpi/icon.png index 4908bc2..fa868e0 100644 Binary files a/android-sources/res/drawable-ldpi/icon.png and b/android-sources/res/drawable-ldpi/icon.png differ diff --git a/android-sources/res/drawable-mdpi/icon.png b/android-sources/res/drawable-mdpi/icon.png index 4908bc2..fa868e0 100644 Binary files a/android-sources/res/drawable-mdpi/icon.png and b/android-sources/res/drawable-mdpi/icon.png differ diff --git a/DigitalRockRanking.pro b/blueROCK.pro similarity index 100% rename from DigitalRockRanking.pro rename to blueROCK.pro diff --git a/headers/serverconn.h b/headers/serverconn.h index 56810c2..2c69943 100644 --- a/headers/serverconn.h +++ b/headers/serverconn.h @@ -27,7 +27,7 @@ public slots: void refreshFoodplan(); QVariant getCalendar(QString nation, int year); - QVariant getRanking(int competitionId, int categoryId, bool registrationData = false, const int routeNumber = -2); + QVariant getRanking(int competitionId, int categoryId, bool registrationData = false, bool rankingData = false, const int routeNumber = -2); // functions for qml QVariant getFoodplan(); diff --git a/resources/qml/Components/AppToolBar.qml b/resources/qml/Components/AppToolBar.qml index ba9b2d1..19902f1 100644 --- a/resources/qml/Components/AppToolBar.qml +++ b/resources/qml/Components/AppToolBar.qml @@ -28,7 +28,6 @@ Item { property int errorCode: app.errorCode onErrorCodeChanged: { - console.log("new error code: " + errorCode) if(!([-1, 200, 905].indexOf(app.errorCode) >= 0) && control.showErrorBar){ animateErrorBar.start() } diff --git a/resources/qml/Components/RankingView.qml b/resources/qml/Components/RankingView.qml index aa8020e..bed8068 100644 --- a/resources/qml/Components/RankingView.qml +++ b/resources/qml/Components/RankingView.qml @@ -1,10 +1,11 @@ -import QtQuick 2.0 +import QtQuick 2.9 import QtQuick.Controls 2.4 DataListView { id: control property var listData: ({}) + signal closeAll() onListDataChanged: { model = listData[ root.listKey ] === undefined ? 0:listData[ root.listKey ].length @@ -17,11 +18,32 @@ DataListView { property int ind: index + state: "closed" + width: parent.width height: 70 text: "" + onClicked: { + if(state === "closed"){ + // close all other delegates + control.closeAll() + + state = "opened" + } + else { + state = "closed" + } + } + + Connections { + target: control + onCloseAll: { + partDel.state = "closed" + } + } + Rectangle { anchors.fill: parent @@ -35,8 +57,14 @@ DataListView { Column { id: partDelCol - anchors.fill: parent - anchors.margins: 5 + anchors { + top: parent.top + left: parent.left + right: parent.right + margins: 5 + } + + height: 70 - 2 * anchors.margins Row { id: partDelFirstRow @@ -45,19 +73,25 @@ DataListView { height: parent.height - partDelSecondRow.height Label { + id: resultRankLa + height: parent.height width: parent.width * 0.1 + enabled: text !== "" + fontSizeMode: Text.Fit font.bold: true font.pixelSize: Math.abs( partDelSecondRow.height > 0 ? height * 0.6:height * 0.4 ) verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter - text: listData[ "participants" ][index]["result_rank"] + text: listData[ "participants" ][index]["result_rank"] === undefined ? "":listData[ "participants" ][index]["result_rank"] } Label { + id: nameLa + height: parent.height width: parent.width * 0.5 @@ -66,11 +100,14 @@ DataListView { font.pixelSize: Math.abs( partDelSecondRow.height > 0 ? height * 0.6:height * 0.4 ) verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignLeft + minimumPixelSize: 1 text: listData[ "participants" ][index]["firstname"] + " " + listData[ "participants" ][index]["lastname"] } Label { + id: fedLa + height: parent.height width: parent.width * 0.4 @@ -96,319 +133,160 @@ DataListView { id: partDelSecondRow width: parent.width - height: multiResRow.enabled || multiGenResRow.enabled || resultLa.enabled ? parent.height / 2:0 + height: pointsLa.enabled ? parent.height / 2:0 - Row { - id: multiResRow + Item { + id: spacer height: parent.height - width: enabled ? parent.width * 0.75:0 - - enabled: parseInt(listData[ "route_order" ]) > -1 && boulderResRep.model > 0 - - Repeater { - id: boulderResRep - - model: parseInt(listData[ "route_num_problems" ]) - - function getDataForIcon(index){ - var resultString = listData[ "participants" ][partDel.ind]["boulder"+(index+1)] - - var resultList = [] - - if( resultString !== undefined){ - resultString = resultString.replace("t", "") - resultString = resultString.replace("z", "") - resultString = resultString.replace("b", "") - resultList = resultString.split(" ") - } - - - while (resultList.length < 2){ - resultList.unshift(0) - } - - return resultList - } - - delegate: Item { - id: boulderResItm - - anchors.verticalCenter: parent.verticalCenter - - width: parent.width / ( boulderResRep.model ) - height: parent.height - - Canvas { - id: boulderResCv - - property var resultData: boulderResRep.getDataForIcon(index) - - anchors.centerIn: parent - - height: parent.height > parent.width ? parent.width * 0.9:parent.height * 0.9 - width: height - - onPaint: { - var width = boulderResCv.width * 0.9 - var height = boulderResCv.height * 0.9 - - var radius = width * 0.3 - - var offsetX = width * 0.05 - var offsetY = height * 0.05 - - var context = getContext("2d"); - - context.beginPath(); - - context.moveTo(0 + offsetX + radius, 0 + offsetY); - - // top line - context.lineTo(width - radius + offsetX, 0 + offsetY); - // top right corner - context.arc(width-radius + offsetX, radius + offsetY, radius, 1.5 * Math.PI, 0); - // right line - context.lineTo(width + offsetX, height - radius + offsetY); - // bottom right corner - context.arc(width-radius + offsetX, height - radius + offsetY, radius, 0, 0.5 * Math.PI); - // bottom line - context.lineTo(0 + radius + offsetX, height + offsetY); - // bottom left corner - context.arc(radius + offsetY, height - radius + offsetY, radius, 0.5 * Math.PI, Math.PI); - // left line - context.lineTo(0 + offsetX, radius + offsetY); - // top left corner - context.arc(radius + offsetX, radius + offsetY, radius, Math.PI, 1.5 * Math.PI); - - // fill - context.fillStyle = "#b7b7b7"; - context.fill(); - - // outline - context.lineWidth = 1; - context.strokeStyle = '#424242'; - context.stroke(); - - if(resultData[1] > 0){ - - // the first triangle - context.beginPath(); - - // top right corner - context.arc(width-radius + offsetX, radius + offsetY, radius, 1.75 * Math.PI, 0); - - // right line - context.lineTo(width + offsetX, height - radius + offsetY); - - // bottom right corner - context.arc(width-radius + offsetX, height - radius + offsetY, radius, 0, 0.5 * Math.PI); - - // bottom line - context.lineTo(0 + radius + offsetX, height + offsetY); - // bottom left corner - context.arc(radius + offsetX, height - radius + offsetY, radius, 0.5 * Math.PI, 0.75 * Math.PI); - context.closePath(); - - context.fillStyle = "#44ed38"; - context.fill(); - - // outline - context.lineWidth = 1; - context.strokeStyle = '#424242'; - context.stroke(); - - - if(resultData[0] > 0){ - // the second triangle - context.beginPath(); - // bottom left corner - context.arc(radius + offsetX, height - radius + offsetY, radius, 0.75 * Math.PI, 1 * Math.PI); - // left line - context.lineTo(0 + offsetX, radius + offsetY); - // top left corner - context.arc(radius + offsetX, radius + offsetY, radius, Math.PI, 1.5 * Math.PI); - // top line - context.lineTo(width - radius + offsetX, 0 + offsetY); - // top right corner - context.arc(width-radius + offsetX, radius + offsetY, radius, 1.5 * Math.PI, 1.75 * Math.PI); - - context.closePath(); - - context.fillStyle = "#44ed38"; - context.fill(); - - // outline - context.lineWidth = 1; - context.strokeStyle = '#424242'; - context.stroke(); - } - } - } - - Label { - id: boulderResZoneLa - - anchors { - right: parent.right - bottom: parent.bottom - margins: boulderResCv.height * 0.05 - } - - height: parent.height / 2 - width: parent.width / 2 - - visible: text !== "0" - - fontSizeMode: Text.Fit - font.pixelSize: height - minimumPixelSize: 0 - - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - - text: boulderResCv.resultData[1] - } - - Label { - id: boulderResTopLa - - anchors { - left: parent.left - top: parent.top - margins: boulderResCv.height * 0.05 - } - - height: parent.height / 2 - width: parent.width / 2 - - visible: text !== "0" - - fontSizeMode: Text.Fit - font.pixelSize: height - minimumPixelSize: 0 - - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - - text: boulderResCv.resultData[0] - } - } - - } - - } - - } - - Row { - id: multiGenResRow - - height: parent.height - width: enabled ? parent.width - resultLa.width:0 - - enabled: ((parseInt(listData[ "route_order" ]) === -1) && (generalResRep.model > 0)) ? true:false - - Repeater { - id: generalResRep - - property var routes: getRoutes() - model: routes.length - - function getRoutes() { - - var obj = listData["route_names"] - var routes = [] - - for(var prop in obj) { - // go through the whole array and search for data keys - if (obj.hasOwnProperty(prop) && prop > -1) { - routes.push([prop, obj[prop]]) - //console.log("found " + obj[prop] + " at index " + prop) - } - } - - routes.sort(function(a, b) { - return a[0] - b[0]; - }); - - return routes - } - - delegate: Item { - id: boulderGenResItm - - anchors.verticalCenter: parent.verticalCenter - - width: parent.width / ( generalResRep.model ) - height: parent.height - - visible: boulderGenResLa.text != "" - - Rectangle { - - anchors { - left: parent.left - } - - width: 1 - height: parent.height - - visible: index === 0 - - color: "grey" - } - - Rectangle { - anchors { - right: parent.right - } - - width: 1 - height: parent.height - - color: "grey" - } - - Label { - id: boulderGenResLa - anchors.centerIn: parent - - height: parent.height - width: parent.width * 0.9 - - fontSizeMode: Text.Fit - font.pixelSize: Math.abs( height * 0.6 ) - minimumPixelSize: 0 - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - - text: listData[ "participants" ][partDel.ind]["result"+(generalResRep.routes[index][0])] === undefined ? "":listData[ "participants" ][partDel.ind]["result"+(generalResRep.routes[index][0])] - } - - } - - } + width: resultRankLa.width } Label { - id: resultLa + id: pointsLa width: enabled ? parent.width * 0.25:0 height: enabled ? parent.height:0 - enabled: ( boulderResRep.model > 0 || listData["discipline"] !== "boulder" ) && parseInt(listData[ "route_order" ]) > -1 - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter + horizontalAlignment: Text.AlignLeft fontSizeMode: Text.Fit font.pixelSize: Math.abs( height * 0.6 ) - minimumPixelSize: 0 + minimumPixelSize: 1 - text: listData[ "participants" ][partDel.ind]["result"] === undefined ? "":listData[ "participants" ][partDel.ind]["result"] + text: listData[ "participants" ][partDel.ind]["points"] === undefined ? "":"points: "+listData[ "participants" ][partDel.ind]["points"] } } } + + Column { + id: detailResultsCol + + anchors { + top: partDelCol.bottom + left: parent.left + right: parent.right + margins: 5 + } + + height: enabled ? ( 20 + spacing ) * detailResultRowRep.model:0 + + Repeater { + id: detailResultRowRep + + property var compResults: getCompResults() + + model: compResults.length + + function getCompResults() { + + var obj = control.listData["route_names"] + var resultData = [] + + for(var prop in obj) { + // go through the whole array and search for data keys + if (obj.hasOwnProperty(prop) && control.listData["participants"][partDel.ind]["result" + prop.replace(" ", "")] !== undefined ) { + resultData.unshift([prop, obj[prop].replace("\n", " - ")]) + //console.log("found " + obj[prop] + " at index " + prop) + } + } + + return resultData + } + + delegate: Row { + width: parent.width + height: detailResultsCol.height / detailResultRowRep.model - detailResultsCol.spacing + + visible: height > 0 + + Item { + id: spacer_ + + height: parent.height + width: parent.width * 0.15 + } + + Label { + + height: parent.height + width: parent.width / 2 + + fontSizeMode: Text.Fit + font.bold: true + font.pixelSize: Math.abs( partDelSecondRow.height > 0 ? height * 0.6:height * 0.4 ) + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignLeft + minimumPixelSize: 1 + + text: detailResultRowRep.compResults[index][1] + } + + Label { + id: detailResultListLa + + height: parent.height + width: parent.width * 0.35 + + fontSizeMode: Text.Fit + font.pixelSize: Math.abs( partDelSecondRow.height > 0 ? height * 0.6:height * 0.4 ) + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignLeft + minimumPixelSize: 1 + + text: control.listData["participants"][partDel.ind]["result"+detailResultRowRep.compResults[index][0].replace(" ", "")] === undefined ? "":control.listData["participants"][partDel.ind]["result"+detailResultRowRep.compResults[index][0].replace(" ", "")].replace("\n", " ") + } + + Behavior on height { + NumberAnimation { + duration: 200 + } + } + + } + + } + + } + + states: [ + State { + name: "closed" + PropertyChanges { + target: partDel + height: 70 + } + + PropertyChanges { + target: detailResultsCol + enabled: false + } + }, + State { + name: "opened" + PropertyChanges { + target: partDel + height: 70 + detailResultsCol.height + } + + PropertyChanges { + target: detailResultsCol + enabled: true + } + } + ] + + transitions: [ + Transition { + from: "*" + to: "*" + NumberAnimation { + properties: "height" + duration: 200 + } + } + ] + } } diff --git a/resources/qml/Components/RegistrationView.qml b/resources/qml/Components/RegistrationView.qml index e69921f..649f7ef 100644 --- a/resources/qml/Components/RegistrationView.qml +++ b/resources/qml/Components/RegistrationView.qml @@ -57,5 +57,4 @@ DataListView { return listData[ "athletes" ][index]["firstname"] + " " + listData[ "athletes" ][index]["lastname"] + " (" + fedName + ")" } - } diff --git a/resources/qml/Components/ResultView.qml b/resources/qml/Components/ResultView.qml new file mode 100644 index 0000000..8ed2bc3 --- /dev/null +++ b/resources/qml/Components/ResultView.qml @@ -0,0 +1,417 @@ +import QtQuick 2.9 +import QtQuick.Controls 2.4 + +DataListView { + id: control + + property var listData: ({}) + + onListDataChanged: { + model = listData[ root.listKey ] === undefined ? 0:listData[ root.listKey ].length + } + + model: listData[ root.listKey ] === undefined ? 0:listData[ root.listKey ].length + + delegate: ItemDelegate { + id: partDel + + property int ind: index + + width: parent.width + height: 70 + + text: "" + + Rectangle { + anchors.fill: parent + + width: partDel.width + + color: partDel.ind % 2 == 0 ? "white":"lightgrey" + + opacity: 0.2 + } + + Column { + id: partDelCol + + anchors.fill: parent + anchors.margins: 5 + + Row { + id: partDelFirstRow + + width: parent.width + height: parent.height - partDelSecondRow.height + + Label { + height: parent.height + width: parent.width * 0.1 + + fontSizeMode: Text.Fit + font.bold: true + font.pixelSize: Math.abs( partDelSecondRow.height > 0 ? height * 0.6:height * 0.4 ) + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + + text: listData[ "participants" ][index]["result_rank"] + } + + Label { + height: parent.height + width: parent.width * 0.5 + + fontSizeMode: Text.Fit + font.bold: true + font.pixelSize: Math.abs( partDelSecondRow.height > 0 ? height * 0.6:height * 0.4 ) + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignLeft + + text: listData[ "participants" ][index]["firstname"] + " " + listData[ "participants" ][index]["lastname"] + } + + Label { + height: parent.height + width: parent.width * 0.4 + + fontSizeMode: Text.Fit + font.bold: false + font.pixelSize: Math.abs( partDelSecondRow.height > 0 ? height * 0.4:height * 0.3 ) + minimumPixelSize: height * 0.3 + + elide: "ElideRight" + + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + + text: "(" + (listData[ "display_athlete" ] === "nation" ? listData[ "participants" ][index]["nation"] : listData[ "participants" ][index]["federation"]) + ")" + + onLinkActivated: { + Qt.openUrlExternally(link) + } + } + } + + Row { + id: partDelSecondRow + + width: parent.width + height: multiResRow.enabled || multiGenResRow.enabled || resultLa.enabled ? parent.height / 2:0 + + Row { + id: multiResRow + + height: parent.height + width: enabled ? parent.width * 0.75:0 + + enabled: parseInt(listData[ "route_order" ]) > -1 && boulderResRep.model > 0 + + Repeater { + id: boulderResRep + + model: parseInt(listData[ "route_num_problems" ]) + + function getDataForIcon(index){ + var resultString = listData[ "participants" ][partDel.ind]["boulder"+(index+1)] + + var resultList = [] + + if( resultString !== undefined){ + resultString = resultString.replace("t", "") + resultString = resultString.replace("z", "") + resultString = resultString.replace("b", "") + resultList = resultString.split(" ") + } + + + while (resultList.length < 2){ + resultList.unshift(0) + } + + return resultList + } + + delegate: Item { + id: boulderResItm + + anchors.verticalCenter: parent.verticalCenter + + width: parent.width / ( boulderResRep.model ) + height: parent.height + + Canvas { + id: boulderResCv + + property var resultData: boulderResRep.getDataForIcon(index) + + anchors.centerIn: parent + + height: parent.height > parent.width ? parent.width * 0.9:parent.height * 0.9 + width: height + + onPaint: { + var width = 24//boulderResCv.width * 0.9 + var height = width + + var radius = width * 0.3 + + var offsetX = width * 0.05 + var offsetY = height * 0.05 + + console.log("drawing result rect with width: " + width + " and height: " + height) + + var context = getContext("2d"); + + context.beginPath(); + + context.moveTo(0 + offsetX + radius, 0 + offsetY); + + // top line + context.lineTo(width - radius + offsetX, 0 + offsetY); + // top right corner + context.arc(width-radius + offsetX, radius + offsetY, radius, 1.5 * Math.PI, 0); + // right line + context.lineTo(width + offsetX, height - radius + offsetY); + // bottom right corner + context.arc(width-radius + offsetX, height - radius + offsetY, radius, 0, 0.5 * Math.PI); + // bottom line + context.lineTo(0 + radius + offsetX, height + offsetY); + // bottom left corner + context.arc(radius + offsetY, height - radius + offsetY, radius, 0.5 * Math.PI, Math.PI); + // left line + context.lineTo(0 + offsetX, radius + offsetY); + // top left corner + context.arc(radius + offsetX, radius + offsetY, radius, Math.PI, 1.5 * Math.PI); + + // fill + context.fillStyle = "#b7b7b7"; + context.fill(); + + // outline + context.lineWidth = 1; + context.strokeStyle = '#424242'; + context.stroke(); + + if(resultData[1] > 0){ + + // the first triangle + context.beginPath(); + + // top right corner + context.arc(width-radius + offsetX, radius + offsetY, radius, 1.75 * Math.PI, 0); + + // right line + context.lineTo(width + offsetX, height - radius + offsetY); + + // bottom right corner + context.arc(width-radius + offsetX, height - radius + offsetY, radius, 0, 0.5 * Math.PI); + + // bottom line + context.lineTo(0 + radius + offsetX, height + offsetY); + // bottom left corner + context.arc(radius + offsetX, height - radius + offsetY, radius, 0.5 * Math.PI, 0.75 * Math.PI); + context.closePath(); + + context.fillStyle = "#44ed38"; + context.fill(); + + // outline + context.lineWidth = 1; + context.strokeStyle = '#424242'; + context.stroke(); + + + if(resultData[0] > 0){ + // the second triangle + context.beginPath(); + // bottom left corner + context.arc(radius + offsetX, height - radius + offsetY, radius, 0.75 * Math.PI, 1 * Math.PI); + // left line + context.lineTo(0 + offsetX, radius + offsetY); + // top left corner + context.arc(radius + offsetX, radius + offsetY, radius, Math.PI, 1.5 * Math.PI); + // top line + context.lineTo(width - radius + offsetX, 0 + offsetY); + // top right corner + context.arc(width-radius + offsetX, radius + offsetY, radius, 1.5 * Math.PI, 1.75 * Math.PI); + + context.closePath(); + + context.fillStyle = "#44ed38"; + context.fill(); + + // outline + context.lineWidth = 1; + context.strokeStyle = '#424242'; + context.stroke(); + } + } + + } + + Label { + id: boulderResZoneLa + + anchors { + right: parent.right + bottom: parent.bottom + margins: boulderResCv.height * 0.05 + } + + height: parent.height / 2 + width: parent.width / 2 + + visible: text !== "0" + + fontSizeMode: Text.Fit + font.pixelSize: height + minimumPixelSize: 1 + + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + + text: boulderResCv.resultData[1] + } + + Label { + id: boulderResTopLa + + anchors { + left: parent.left + top: parent.top + margins: boulderResCv.height * 0.05 + } + + height: parent.height / 2 + width: parent.width / 2 + + visible: text !== "0" + + fontSizeMode: Text.Fit + font.pixelSize: height + minimumPixelSize: 1 + + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + + text: boulderResCv.resultData[0] + } + } + + } + + } + + } + + Row { + id: multiGenResRow + + height: parent.height + width: enabled ? parent.width - resultLa.width:0 + + enabled: ((parseInt(listData[ "route_order" ]) === -1) && (generalResRep.model > 0)) ? true:false + + Repeater { + id: generalResRep + + property var routes: getRoutes() + model: routes.length + + function getRoutes() { + + var obj = listData["route_names"] + var routes = [] + + for(var prop in obj) { + // go through the whole array and search for data keys + if (obj.hasOwnProperty(prop) && prop > -1) { + routes.push([prop, obj[prop]]) + //console.log("found " + obj[prop] + " at index " + prop) + } + } + + routes.sort(function(a, b) { + return a[0] - b[0]; + }); + + return routes + } + + delegate: Item { + id: boulderGenResItm + + anchors.verticalCenter: parent.verticalCenter + + width: parent.width / ( generalResRep.model ) + height: parent.height + + visible: boulderGenResLa.text != "" + + Rectangle { + + anchors { + left: parent.left + } + + width: 1 + height: parent.height + + visible: index === 0 + + color: "grey" + } + + Rectangle { + anchors { + right: parent.right + } + + width: 1 + height: parent.height + + color: "grey" + } + + Label { + id: boulderGenResLa + anchors.centerIn: parent + + height: parent.height + width: parent.width * 0.9 + + fontSizeMode: Text.Fit + font.pixelSize: Math.abs( height * 0.6 ) + minimumPixelSize: 1 + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + + text: listData[ "participants" ][partDel.ind]["result"+(generalResRep.routes[index][0])] === undefined ? "":listData[ "participants" ][partDel.ind]["result"+(generalResRep.routes[index][0])] + } + + } + + } + } + + Label { + id: resultLa + + width: enabled ? parent.width * 0.25:0 + height: enabled ? parent.height:0 + + enabled: ( boulderResRep.model > 0 || listData["discipline"] !== "boulder" ) && parseInt(listData[ "route_order" ]) > -1 + + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + + fontSizeMode: Text.Fit + font.pixelSize: Math.abs( height * 0.6 ) + minimumPixelSize: 1 + + text: listData[ "participants" ][partDel.ind]["result"] === undefined ? "":listData[ "participants" ][partDel.ind]["result"] + } + } + } + } +} diff --git a/resources/qml/Components/StartlistView.qml b/resources/qml/Components/StartlistView.qml index 9a7b22b..c080e09 100644 --- a/resources/qml/Components/StartlistView.qml +++ b/resources/qml/Components/StartlistView.qml @@ -36,20 +36,21 @@ DataListView { Label { height: parent.height - width: parent.width * 0.4 + width: parent.width * 0.5 fontSizeMode: Text.Fit font.bold: true - font.pixelSize: Math.abs( height * 0.6 ) + font.pixelSize: Math.abs( height * 0.45 ) verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignLeft + minimumPixelSize: 1 text: listData[ "participants" ][index]["firstname"] + " " + listData[ "participants" ][index]["lastname"] } Label { height: parent.height - width: parent.width * 0.5 + width: parent.width * 0.3 fontSizeMode: Text.Fit font.bold: false diff --git a/resources/qml/Pages/CompetitionCalendarPage.qml b/resources/qml/Pages/CompetitionCalendarPage.qml index 015a004..d5189da 100644 --- a/resources/qml/Pages/CompetitionCalendarPage.qml +++ b/resources/qml/Pages/CompetitionCalendarPage.qml @@ -1,4 +1,4 @@ -import QtQuick 2.0 +import QtQuick 2.9 import QtQuick.Controls 2.4 import QtQuick.Controls.Material 2.3 @@ -16,49 +16,91 @@ Page { Row { anchors.fill: parent - anchors.rightMargin: parent.width * 0.05 + anchors.rightMargin: 5 - spacing: anchors.rightMargin + spacing: width * 0.05 Label { anchors.verticalCenter: parent.verticalCenter - width: parent.width - toolButton.width - parent.spacing + width: parent.width * 0.4 height: parent.height * 0.6 fontSizeMode: Text.Fit font.pixelSize: height verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignRight - minimumPixelSize: 0 + horizontalAlignment: Text.AlignHCenter + minimumPixelSize: 1 text: root.year } Button { - id:toolButton + id:yearToolBt anchors { verticalCenter: parent.verticalCenter } height: parent.height * 0.5 - width: height + width: parent.width * 0.25 onClicked: { yearSelectPu.open() } - onPressed: toolButton.scale = 0.9 - onReleased: toolButton.scale = 1.0 + onPressed: yearToolBt.scale = 0.9 + onReleased: yearToolBt.scale = 1.0 background: Image { + + anchors.centerIn: parent + source: "qrc:/icons/calendar.png" - height: parent.height + height: parent.height > parent.width ? parent.width : parent.height width: height + mipmap: true + + fillMode: Image.PreserveAspectFit + Behavior on scale { + PropertyAnimation { + duration: 100 + } + } + } + } + + Button { + id: cupToolBt + + anchors { + verticalCenter: parent.verticalCenter + } + + height: parent.height * 0.5 + width: parent.width * 0.25 + + onClicked: { + cupSelectPu.open() + } + + onPressed: cupToolBt.scale = 0.9 + onReleased: cupToolBt.scale = 1.0 + + background: Image { + + anchors.centerIn: parent + + source: "qrc:/icons/cup.png" + + height: parent.height > parent.width ? parent.width : parent.height + width: height + + mipmap: true + fillMode: Image.PreserveAspectFit Behavior on scale { PropertyAnimation { @@ -93,6 +135,9 @@ Page { root.status = 200 root.calendarData = ret["data"] calendarList.listData = ret["data"]["competitions"] + + + } else if (root.calendarData !== undefined ){ // there is still old data available @@ -112,6 +157,7 @@ Page { loadingDl.close() app.errorCode = root.status + return true } @@ -132,6 +178,34 @@ Page { root.loadData(root.nation, root.year) } + onModelChanged: { + autoScroll() + } + + function autoScroll() { + if(parseInt(root.year) === new Date().getFullYear()){ + for(var i = 0; i < listData.length; i ++){ + // get the start date pf the competition + var startDate = Date.fromLocaleString(Qt.locale(), calendarList.listData[i]["date"], "yyyy-MM-dd") + + // get the duration of the competition + var durationString = calendarList.listData[i]["duration"] === undefined ? "1":calendarList.listData[i]["duration"] + var days = parseInt(durationString.replace(/\D/g,'')) + // calculate the end date of the competition + var endDate = new Date(startDate.valueOf()) + endDate.setDate(endDate.getDate() + days); + + //console.log(calendarList.listData[i]["date"] + ": " + startDate + " to " + endDate) + + if(endDate.getTime() < new Date().getTime()){ + // end date is already over -> move the list view up! + calendarList.positionViewAtIndex(i, ListView.Top) + //console.log("moving down!") + } + } + } + } + delegate: ItemDelegate { id: competitionDel @@ -139,12 +213,15 @@ Page { property string date: calendarList.listData[index]["date_span"] property var cats: calendarList.listData[index]["cats"] property int catId: calendarList.listData[index]["cat_id"] + property bool over width: parent.width height: compDelCol.height + 10 + enabled: calendarList.listData[index]["cats"] !== undefined && calendarList.listData[index]["cats"].length > 0 + onClicked: { - catSelectPu.appear(index) + catSelectPu.appear(index, false) } Rectangle { @@ -155,7 +232,6 @@ Page { opacity: 0.5 color: app.competitionCategoryColors[catId] - } Column { @@ -217,48 +293,125 @@ Page { id: catSelectPu property int index: -1 - property var catObj: calendarList.listData[catSelectPu.index] !== undefined ? calendarList.listData[catSelectPu.index]["cats"]:undefined + property bool cupCat: false + property var catObj: undefined - x: root.width / 2 - width / 2 - y: root.height / 2 - height / 2 + x: 0 //root.width / 2 - width / 2 + y: root.height - height //root.height / 2 - height / 2 - width: root.width * 0.8 - height: root.height * 0.6 + width: root.width + height: catsLv.height //root.height * 0.6 modal: true focus: true title: qsTr("select category") - function appear(index) { - catSelectPu.open() + function appear(index, cupCat) { + catSelectPu.cupCat = cupCat catSelectPu.index = index + + if(cupCat){ + catSelectPu.catObj = root.calendarData["cups"][index]["cats"] + } + else { + catSelectPu.catObj = calendarList.listData[index]["cats"] + } + + catSelectPu.open() + } - contentItem: ListView { + function getText(index){ + // ---------------------------- + // get the text + // returns list with [catId, catName] + + if(catSelectPu.cupCat){ + var catName // category name + var catId // category id + + for(var i = 0; i < root.calendarData["cats"].length; i ++ ){ + //console.log("checking " + i + ": cat: " + parseInt(listData["categorys"][i]["GrpId"]) + " searched cat: " + root.catId) + if(root.calendarData["cats"][i]["rkey"] === root.calendarData["cups"][catSelectPu.index]["cats"][index] && root.calendarData["cats"][i]["sex"] !== undefined){ + catName = root.calendarData["cats"][i]["name"] + catId = root.calendarData["cats"][i]["GrpId"] + } + } + + return [catId, catName] + } + else { + return [catSelectPu.catObj[index]["GrpId"], catSelectPu.catObj[index]["name"]] + } + + + } + + ListView { id: catsLv + property int delegateHeight: 50 + + anchors { + top: parent.top + left: parent.left + right: parent.right + } + width: parent.width - height: root.height * 0.6 + height: root.height * 0.6 < ( (delegateHeight + spacing) * model ) ? root.height * 0.6 : (delegateHeight + spacing) * model + 75 model: catSelectPu.catObj !== undefined ? catSelectPu.catObj.length:0 + ScrollIndicator.vertical: ScrollIndicator { + parent: catsLv.parent + anchors { + top: catsLv.top + left: catsLv.right + margins: 10 + leftMargin: 3 + bottom: catsLv.bottom + } + + } + delegate: Button { id: catBt + property var catData: catSelectPu.getText(index) + width: parent.width + height: text !== "" ? catsLv.delegateHeight:0 flat: true - text: catSelectPu.catObj[index]["name"] + text: catData[1] onClicked: { catSelectPu.close() - app.openResults(calendarList.listData[catSelectPu.index]["WetId"], catSelectPu.catObj[index]["GrpId"], catSelectPu.catObj[index]["status"] ) + app.openResults( catSelectPu.cupCat ? root.calendarData["cups"][catSelectPu.index]["SerId"]:calendarList.listData[catSelectPu.index]["WetId"], catData[0], catSelectPu.cupCat ? -1:catSelectPu.catObj[index]["status"] ) } } } + enter: Transition { + NumberAnimation { property: "opacity"; from: 0.0; to: 1.0 } + NumberAnimation { + property: "y" + from: root.height - catSelectPu.height * 0.7 + to: root.height - catSelectPu.height + } + } + + exit: Transition { + NumberAnimation { property: "opacity"; from: 1.0; to: 0.0 } + NumberAnimation { + property: "y" + from: root.height - catSelectPu.height + to: root.height - catSelectPu.height * 0.7 + } + } } Dialog { @@ -266,10 +419,10 @@ Page { property var yearList: root.calendarData["years"] - x: root.width / 2 - width / 2 - y: root.height / 2 - height / 2 + x: 0 //root.width / 2 - width / 2 + y: root.height - height //root.height / 2 - height / 2 - width: root.width * 0.8 + width: root.width height: root.height * 0.6 modal: true @@ -285,6 +438,20 @@ Page { model: yearSelectPu.yearList !== undefined ? yearSelectPu.yearList.length:0 + clip: true + + ScrollIndicator.vertical: ScrollIndicator { + parent: yearsLv.parent + anchors { + top: yearsLv.top + left: yearsLv.right + margins: 10 + leftMargin: 3 + bottom: yearsLv.bottom + } + + } + delegate: Button { id: yearBt @@ -302,6 +469,111 @@ Page { } } + enter: Transition { + NumberAnimation { property: "opacity"; from: 0.0; to: 1.0 } + NumberAnimation { + property: "y" + from: root.height - yearSelectPu.height * 0.7 + to: root.height - yearSelectPu.height + } + } + + exit: Transition { + NumberAnimation { property: "opacity"; from: 1.0; to: 0.0 } + NumberAnimation { + property: "y" + from: root.height - yearSelectPu.height + to: root.height - yearSelectPu.height * 0.7 + } + } + } + + Dialog { + id: cupSelectPu + + property var cupList: getCupList() + + function getCupList() { + if(root.nation === "") { + root.calendarData["cups"].unshift({"SerId":"","rkey":"","name":"Worldranking","modified":"2018-10-24 16:11:12","modifier":"","year":"","num_comps":"","cats":["ICC-COA","ICC-HD","ICC-MED","ICC_F","ICC_FB","ICC_FS","ICC_M","ICC_MB","ICC_MS"]}) + } + return root.calendarData["cups"] + } + + x: 0 //root.width / 2 - width / 2 + y: root.height - height //root.height / 2 - height / 2 + + width: root.width + height: cupsLv.height //root.height * 0.6 + + modal: true + focus: true + + title: qsTr("select cup") + + ListView { + id: cupsLv + + property int delegateHeight: 50 + + anchors { + top: parent.top + left: parent.left + right: parent.right + } + + width: parent.width + height: root.height * 0.6 < ( (delegateHeight + spacing) * model ) ? root.height * 0.6 : (delegateHeight + spacing) * model + 75 + + model: cupSelectPu.cupList !== undefined ? cupSelectPu.cupList.length:0 + + ScrollIndicator.vertical: ScrollIndicator { + parent: cupsLv.parent + anchors { + top: cupsLv.top + left: cupsLv.right + margins: 10 + leftMargin: 3 + bottom: cupsLv.bottom + } + + } + + delegate: Button { + id: cupBt + + width: parent.width + height: cupsLv.delegateHeight + + flat: true + + text: cupSelectPu.cupList[index]["name"] + + onClicked: { + cupSelectPu.close() + catSelectPu.appear(index, true) + } + } + } + + enter: Transition { + NumberAnimation { property: "opacity"; from: 0.0; to: 1.0 } + NumberAnimation { + property: "y" + from: root.height - cupSelectPu.height * 0.7 + to: root.height - cupSelectPu.height + } + } + + exit: Transition { + NumberAnimation { property: "opacity"; from: 1.0; to: 0.0 } + NumberAnimation { + property: "y" + from: root.height - cupSelectPu.height + to: root.height - cupSelectPu.height * 0.7 + } + } + } } diff --git a/resources/qml/Pages/RankingPage.qml b/resources/qml/Pages/RankingPage.qml index 45edd26..e20f800 100644 --- a/resources/qml/Pages/RankingPage.qml +++ b/resources/qml/Pages/RankingPage.qml @@ -1,4 +1,4 @@ -import QtQuick 2.0 +import QtQuick 2.9 import QtQuick.Controls 2.4 import QtGraphicalEffects 1.0 @@ -21,6 +21,7 @@ Page { property int catStatus: undefined property int routeNumber: -2 + property bool rak: catStatus === -1 // ranking (cup) data property bool reg: catStatus === 4 || catStatus === undefined // registration data property bool res: catStatus === 0 || catStatus === 1 // result data property bool stl: catStatus === 2 || catStatus === 3 // startlist data @@ -31,21 +32,21 @@ Page { property string compNameKey: root.reg ? "name":"comp_name" Component.onCompleted: { - root.loadData(root.comId, root.catId, root.reg, root.routeNumber) + root.loadData(root.comId, root.catId, root.reg, root.rak, root.routeNumber) } - function loadData(comp, cat, reg, route){ + function loadData(comp, cat, reg, rak, route){ loadingDl.open() root.status = 905 - console.log("[info][QML] getting ranking data of comp: " + comp + " and cat: " + cat + " reg: " + reg) - var ret = serverConn.getRanking(comp, cat, reg, route) + console.log("[info][QML] getting ranking data of comp: " + comp + " , cat: " + cat + " and status: " + root.catStatus) + var ret = serverConn.getRanking(comp, cat, reg, rak, route) root.status = ret["status"] if(parseInt(ret["status"]) === 200){ // request was successfull -> prepare data if(root.reg){ - // if the data i sregistration data, athletes of other cats need to be removed + // if the data is registration data, athletes of other cats need to be removed var validAthletes = [] @@ -59,6 +60,10 @@ Page { root.rankingData = ret["data"] } + else if(root.rak){ + root.rankingData = ret["data"] + root.routeNumber = root.rankingData["route_order"] === undefined ? -2:root.rankingData["route_order"] + } else { root.rankingData = ret["data"] root.routeNumber = root.rankingData["route_order"] === undefined ? -2:root.rankingData["route_order"] @@ -77,11 +82,11 @@ Page { } if((ret["data"][ root.listKey ] === undefined || ret["data"][ root.listKey ].length < 1) && ( root.status === 200 || root.status === 404 ) ){ - root.status = 901 - root.ready = false - loadingDl.close() - return false - } + root.status = 901 + root.ready = false + loadingDl.close() + return false + } console.log("done! status: " + root.status) root.ready = true @@ -117,6 +122,9 @@ Page { else if(root.stl) { addition = "(Startlist) " } + else if(root.rak) { + addition = "(Ranking) " + } return addition + titleString @@ -140,7 +148,7 @@ Page { listData: root.reg ? root.rankingData:({}) onRefresh: { - root.loadData(root.comId, root.catId, root.reg, root.routeNumber) + root.loadData(root.comId, root.catId, root.reg, root.rak, root.routeNumber) } } } @@ -153,7 +161,7 @@ Page { visible: root.res - RankingView { + ResultView { id: rankViewRv anchors { @@ -167,10 +175,10 @@ Page { status: root.status - listData: root.reg ? ({}):root.rankingData + listData: root.res ? root.rankingData:({}) onRefresh: { - root.loadData(root.comId, root.catId, root.reg, root.routeNumber) + root.loadData(root.comId, root.catId, root.reg, root.rak, root.routeNumber) } } @@ -259,7 +267,7 @@ Page { console.log("changing to index: " + index + " (" + routeSelectTb.tabs[index][0] + ", " + routeSelectTb.tabs[index][1] + ")") if(root.routeNumber !== routeSelectTb.tabs[index][0]){ root.routeNumber = routeSelectTb.tabs[index][0] - root.loadData(root.comId, root.catId, root.reg, root.routeNumber) + root.loadData(root.comId, root.catId, root.reg, root.rak, root.routeNumber) } } } @@ -285,7 +293,30 @@ Page { listData: root.stl ? root.rankingData:({}) onRefresh: { - root.loadData(root.comId, root.catId, root.reg, root.routeNumber) + root.loadData(root.comId, root.catId, root.reg, root.rak, root.routeNumber) + } + } + } + + Item { + id: rankinglItm + // item for startlist data + + anchors.fill: parent + + visible: root.rak + + RankingView { + id: rankingRv + + anchors.fill: parent + + status: root.status + + listData: root.rak ? root.rankingData:({}) + + onRefresh: { + root.loadData(root.comId, root.catId, root.reg, root.rak, root.routeNumber) } } } diff --git a/resources/qml/main.qml b/resources/qml/main.qml index ba5c306..a72fe3f 100644 --- a/resources/qml/main.qml +++ b/resources/qml/main.qml @@ -11,7 +11,7 @@ Window { visible: true width: 540 height: 960 - title: qsTr("Digital Rock Ranking") + title: qsTr("blueROCK") Page { id: app @@ -234,7 +234,7 @@ Window { id: extraComponentLoader height: parent.height - width: status === Loader.Ready ? parent.width * 0.35 - toolButton.width - 3 * parent.spacing:0 + width: status === Loader.Ready ? parent.width * 0.4 - toolButton.width - 3 * parent.spacing:0 anchors { top: parent.top diff --git a/resources/qml/qml.qrc b/resources/qml/qml.qrc index d6a5861..eeaaff2 100644 --- a/resources/qml/qml.qrc +++ b/resources/qml/qml.qrc @@ -9,8 +9,9 @@ Components/FancyBusyIndicator.qml Components/InfoArea.qml Components/DataListView.qml - Components/RankingView.qml + Components/ResultView.qml Components/RegistrationView.qml Components/StartlistView.qml + Components/RankingView.qml diff --git a/resources/shared/icons/cup.png b/resources/shared/icons/cup.png new file mode 100644 index 0000000..3713be3 Binary files /dev/null and b/resources/shared/icons/cup.png differ diff --git a/resources/shared/shared.qrc b/resources/shared/shared.qrc index 8439a11..59effc4 100644 --- a/resources/shared/shared.qrc +++ b/resources/shared/shared.qrc @@ -6,5 +6,6 @@ icons/back.png icons/backDark.png icons/calendar.png + icons/cup.png diff --git a/sources/serverconn.cpp b/sources/serverconn.cpp index d2128f8..e08d83f 100644 --- a/sources/serverconn.cpp +++ b/sources/serverconn.cpp @@ -38,9 +38,9 @@ QVariant ServerConn::getCalendar(QString nation, int year){ return rankingData; } -QVariant ServerConn::getRanking(int competiotionId, int categoryId, bool registrationData, int routeNumber) { +QVariant ServerConn::getRanking(int competiotionId, int categoryId, bool registrationData, bool rankingData, int routeNumber) { - QString requestUrl = "http://egw.ifsc-climbing.org/egw/ranking/json.php?comp="+ QString::number( competiotionId ) +"&cat="+ QString::number( categoryId ) + (registrationData ? "&type=starters":"") + "&route=" + ((routeNumber == -2) ? "":QString::number(routeNumber)); + QString requestUrl = "http://egw.ifsc-climbing.org/egw/ranking/json.php?" + QString(rankingData ? "cup":"comp") + "=" + QString::number( competiotionId ) + "&cat=" + QString::number( categoryId ) + (registrationData ? "&type=starters":"") + "&route=" + ((routeNumber == -2) ? "":QString::number(routeNumber)); qDebug() << requestUrl; @@ -53,9 +53,9 @@ QVariant ServerConn::getRanking(int competiotionId, int categoryId, bool registr QJsonDocument jsonReply = QJsonDocument::fromJson(ret["text"].toString().toUtf8()); - QVariantMap rankingData = {{"status", 200}, {"data", jsonReply.toVariant()}}; + QVariantMap data = {{"status", 200}, {"data", jsonReply.toVariant()}}; - return rankingData; + return data; } // ------------------------