From bd185ad28bbe9883ef34a27da7d7031d39f5f41e Mon Sep 17 00:00:00 2001 From: dorian Date: Thu, 4 Jul 2019 09:03:39 +0200 Subject: [PATCH] started to implement speed final flowcharts --- android-sources/AndroidManifest.xml | 2 +- resources/qml/Components/DataListView.qml | 2 + resources/qml/Components/SpeedFlowChart.qml | 314 ++++++++++++++++++ resources/qml/Widgets/CalendarWidget.qml | 30 +- resources/qml/Widgets/ResultWidget.qml | 79 ++++- resources/qml/qml.qrc | 1 + .../shared/icons/bluerock/20x20/flowchart.png | Bin 0 -> 369 bytes .../icons/bluerock/20x20@2/flowchart.png | Bin 0 -> 663 bytes .../icons/bluerock/20x20@3/flowchart.png | Bin 0 -> 884 bytes .../icons/bluerock/20x20@4/flowchart.png | Bin 0 -> 1061 bytes resources/shared/shared.qrc | 4 + 11 files changed, 426 insertions(+), 6 deletions(-) create mode 100644 resources/qml/Components/SpeedFlowChart.qml create mode 100644 resources/shared/icons/bluerock/20x20/flowchart.png create mode 100644 resources/shared/icons/bluerock/20x20@2/flowchart.png create mode 100644 resources/shared/icons/bluerock/20x20@3/flowchart.png create mode 100644 resources/shared/icons/bluerock/20x20@4/flowchart.png diff --git a/android-sources/AndroidManifest.xml b/android-sources/AndroidManifest.xml index bec38e0..b7ae0fc 100644 --- a/android-sources/AndroidManifest.xml +++ b/android-sources/AndroidManifest.xml @@ -1,5 +1,5 @@ - + diff --git a/resources/qml/Components/DataListView.qml b/resources/qml/Components/DataListView.qml index 6f5c02b..07d80a4 100644 --- a/resources/qml/Components/DataListView.qml +++ b/resources/qml/Components/DataListView.qml @@ -24,6 +24,8 @@ ListView { property int status: -1 property bool loading: false + property var listData + property var emptyProperties: [] signal refresh() diff --git a/resources/qml/Components/SpeedFlowChart.qml b/resources/qml/Components/SpeedFlowChart.qml new file mode 100644 index 0000000..0e2b6a4 --- /dev/null +++ b/resources/qml/Components/SpeedFlowChart.qml @@ -0,0 +1,314 @@ +import QtQuick 2.10 +import QtQuick.Controls 2.4 +import QtQuick.Controls.Material 2.1 + +ListView { + id: control + + property var flowchartData + property var allFlowchartData + property int rounds + property int tileSize: app.height / 8 * 0.8 + + anchors.fill: parent + anchors.margins: 10 + model: rounds + 2 + + spacing: app.width * 0.1 + + orientation: ListView.LeftToRight + boundsBehavior: ListView.StopAtBounds + + onFlowchartDataChanged: { + prepareData() + } + + function prepareData() { + + // array to store the restructured data + var allData = [] + + for(var round in flowchartData['route_names']){ + if(flowchartData['route_names'].hasOwnProperty(round) && parseInt(round) >= 0){ + console.log(round) + + if(allData.length > 0){ + allData[allData.length-1].push(round) + allData[allData.length-1].push(flowchartData['route_names'][round]) + } + + if(parseInt(round) === 0){ + // this is the first round + + // find pairs (always wors vs. best (1-16; 1-15; ...)) (they are sorted by the rank of the better athlete (1-2-3-4-5-6-7-8) + + var qualificationResults = [] + + for(var x = 0; x < flowchartData['participants'].length; x++){ + qualificationResults.push(flowchartData['participants'][x]) + } + + qualificationResults.sort(function(a, b) { + return parseInt(a["result_rank0"]) - parseInt(b["result_rank0"]); + }); + + var nextRoundPairs = [] + var nextRoundMatches = Math.pow(2, control.model-1) + + for(var i = 0; i < nextRoundMatches; i++){ + nextRoundPairs.push([qualificationResults[i], qualificationResults[nextRoundMatches*2-i-1]]) + } + + // build second round pairs (sorted by the rank of the better athlete and worst vs. best (1-8; 2-7; ... )) + + var sortedFirstRoundPairs = [] + + for(i = 0; i < nextRoundMatches; i += 1){ + sortedFirstRoundPairs.push([nextRoundPairs.shift(), nextRoundPairs.pop()]) + } + + // sort these pairs (containing two pairs of athletes) by the rank of the better athlete (1-4;2-3) + + var finalSortedFirstRoundPairs = [] + + for(i=0; i < nextRoundMatches/4; i++){ + finalSortedFirstRoundPairs.push(sortedFirstRoundPairs[i]) + finalSortedFirstRoundPairs.push(sortedFirstRoundPairs[nextRoundMatches/2-i-1]) + } + + // convert the list of pairs of pairs of athletes back to a single list of pairs of athletes + + var finalFirstRoundPairs = [] + + for(i=0; i < finalSortedFirstRoundPairs.length; i++){ + finalFirstRoundPairs.push(finalSortedFirstRoundPairs[i][0]) + finalFirstRoundPairs.push(finalSortedFirstRoundPairs[i][1]) + } + + // push the first round to all data + + allData.push(finalFirstRoundPairs) + + } + else if(parseInt(round) > 0 ){ + // this is not the first round + + var nextRound = [] + + // only used when the current round is the 1/2 final + var smallFinal = [] + var Final = [] + + for(var i = 0; i < allData[allData.length-1].length-2; i+=1){ + + var thisPair = allData[allData.length-1][i] + var thisWinner + var thisLooser + var thisWinnerIsFirstOfNewPair = i%2 === 0 + + if(thisWinnerIsFirstOfNewPair){ + nextRound.push([]) + } + + //thisPair[0]["result_rank"] = thisPair[0]["result_rank"+round] + //thisPair[1]["result_rank"] = thisPair[1]["result_rank"+round] + + if(parseInt(thisPair[0]["result_rank"+round]) < parseInt(thisPair[1]["result_rank"+round])){ + thisWinner = thisPair[0] + thisLooser = thisPair[1] + } + else { + thisWinner = thisPair[1] + thisLooser = thisPair[0] + } + + console.log(thisWinner['firstname']+" has won in round " + round) + //thisWinner.win = false + //thisLooser.win = true + + if(round - control.rounds === 2){ + // if we are in the 1/2 final + + Final.push(thisWinner) + smallFinal.push(thisLooser) + } + else { + nextRound[nextRound.length-1].push(thisWinner) + } + } + + if(smallFinal.length > 0 && Final.length > 0){ + + // Final + allData.push([Final, parseInt(round)+2, flowchartData['route_names'][String(parseInt(round)+2)] + " / " + flowchartData['route_names'][String(parseInt(round)+1)] ]) + // small Final + allData.push([smallFinal, parseInt(round)+1]) + + break + } + else { + //nextRound.push(round) + //nextRound.push(flowchartData['route_names'][round]) + allData.push(nextRound) + } + } + } + } + control.allFlowchartData = allData + } + + delegate: Column { + id: roundCol + + property int thisIndex: index + property int thisRound: control.allFlowchartData[roundCol.thisIndex][control.allFlowchartData[roundCol.thisIndex].length-2] + property bool thisIsLastRound: thisIndex === control.model - 1 + + width: app.width * 0.5 + height: control.height + + //spacing: app.width * 0.1 + + Label { + id: roundNameLa + width: parent.width + horizontalAlignment: Text.AlignHCenter + font.bold: true + text: control.allFlowchartData[roundCol.thisIndex][control.allFlowchartData[roundCol.thisIndex].length-1] + } + + Repeater { + id: rectRep + model: Math.max( Math.pow(2, control.model-1) * Math.pow(0.5, (index)), 2) + delegate: Item { + id: matchItm + + property bool lowerPart: (index%2 > 0) + + property int thisIndex: index + property var thisMatchData: control.allFlowchartData[ thisIsSemifinal ? roundCol.thisIndex+1 : roundCol.thisIndex][matchItm.thisIndex] + property bool thisIsFinal: roundCol.thisIsLastRound && thisIndex === rectRep.model - 2 + property bool thisIsSemifinal: roundCol.thisIsLastRound && thisIndex === rectRep.model - 1 + + Component.onCompleted: { + if(thisIsSemifinal){ + console.log("this is semi final") + console.log(thisMatchData) + } + console.log(thisMatchData) + } + + height: !roundCol.thisIsLastRound ? (roundCol.height - roundNameLa.height) / rectRep.model - roundCol.spacing : (thisIsFinal ? (roundCol.height - roundNameLa.height) * 0.5 + control.tileSize * 0.5 : (roundCol.height - roundNameLa.height) - (roundCol.height - roundNameLa.height) * 0.5 + control.tileSize * 0.5 ) + width: parent.width + + Canvas { + id: lineCanvas + width: app.width; height: app.height + contextType: "2d" + + visible: !roundCol.thisIsLastRound + + property int targetX: matchItm.width + control.spacing + property int targetY: matchItm.lowerPart ? 0:matchItm.height + + Path { + id: myPath + startX: matchRect.x + matchRect.width * matchRect.scale ; startY: matchRect.y + matchRect.height * 0.5 + + PathCurve { x: lineCanvas.targetX ; y: lineCanvas.targetY } + } + + onPaint: { + context.strokeStyle = Qt.rgba(.4,.6,.8); + context.path = myPath; + context.stroke(); + } + } + + Rectangle { + id: matchRect + + anchors { + centerIn: !matchItm.thisIsFinal ? parent:undefined + bottom: matchItm.thisIsFinal ? parent.bottom:undefined + } + + //anchors.verticalCenterOffset: matchItm.lowerPart ? 10:10 + width: parent.width + height: control.tileSize + //scale: 0.9 + color: "white" + border.color: "lightgrey" + border.width: 1 + radius: height * 0.2 + Material.elevation: 10 + + Grid { + columns: app.landscape() ? 2:0 + rows: app.landscape() ? 0:2 + + anchors.fill: parent + anchors.margins: matchRect.radius * 0.5 + + Repeater { + // for the two athletes + model: 2 + + delegate: Row { + height: app.landscape() ? parent.height:parent.height / 2 + width: app.landscape() ? parent.width / 2 : parent.width + + spacing: app.landscape() ? width * 0.1:height * 0.05 + + Label { + height: parent.height + width: parent.width * 0.2 + + verticalAlignment: Text.AlignVCenter + font.pixelSize: height * 0.6 + fontSizeMode: Text.Fit + minimumPixelSize: 1 + + text: matchItm.thisMatchData[index]['result_rank0'] + } + + Label { + height: parent.height + width: parent.width * 0.5 + + verticalAlignment: Text.AlignVCenter + font.pixelSize: height * 0.6 + fontSizeMode: Text.Fit + minimumPixelSize: 1 + + color: (parseInt(matchItm.thisMatchData[0]["result_rank" + roundCol.thisRound ]) < parseInt(matchItm.thisMatchData[1]["result_rank" + roundCol.thisRound])) === (index === 0 ? true:false) ? "green":"black" + + text: matchItm.thisMatchData[index]['firstname'] + " " + matchItm.thisMatchData[index]['lastname'] + } + + /*Rectangle { + id: hasWonRect + + anchors.verticalCenter: parent.verticalCenter + + height: width + width: parent.width * 0.1 + + scale: 0.7 + + radius: width * 0.5 + + color: "green" + + visible: (parseInt(matchItm.thisMatchData[0]["result_rank" + roundCol.thisRound ]) < parseInt(matchItm.thisMatchData[1]["result_rank" + roundCol.thisRound])) === (index === 0 ? true:false) + }*/ + + } + } + } + } + } + } + } +} + diff --git a/resources/qml/Widgets/CalendarWidget.qml b/resources/qml/Widgets/CalendarWidget.qml index 3fa274e..c82d4c8 100644 --- a/resources/qml/Widgets/CalendarWidget.qml +++ b/resources/qml/Widgets/CalendarWidget.qml @@ -93,6 +93,7 @@ DataListView { //boundsBehavior: Flickable.StopAtBounds model: widgetData["competitions"].length + //listData: widgetData['competitions'] onRefresh: { updateData({}, false) @@ -101,13 +102,14 @@ DataListView { Component.onCompleted: { initFilters() - if(model > 0){ - control.ready = true + if(model){ control.status = 200 + control.ready = true } else { control.ready = false control.status = 901 + return } autoScroll() @@ -128,8 +130,11 @@ DataListView { if(parseInt(control.year) === new Date().getFullYear()){ for(var i = 0; i < compList.length; i ++){ - // get the start date pf the competition + // get the start date of the competition var startDate = Date.fromLocaleString(Qt.locale(), compList[i]["date"], "yyyy-MM-dd") + //control.widgetData["competitions"][i]["month"] = startDate.getMonth() + + //console.log("got date: " + startDate + " from string: " + compList[i]["date"] + " -> month is: " + compList[i]["month"]) // get the duration of the competition var durationString = compList[i]["duration"] === undefined ? "1":compList[i]["duration"] @@ -146,6 +151,8 @@ DataListView { //console.log("moving down!") } } + + //control.widgetData = control.widgetData } else { //console.log("not current year") @@ -367,7 +374,7 @@ DataListView { width: parent.width height: includedByFilter ? compDelCol.height + 10 : 0 - enabled: (thisData["cats"] !== undefined && thisData["cats"].length > 0) || control.widgetData["competitions"][index]["homepage"] !== undefined || getCompInfoUrl(index) !== undefined + enabled: (thisData["cats"] !== undefined && thisData["cats"].length > 0) || competitionDel.thisData["homepage"] !== undefined || getCompInfoUrl(index) !== undefined //visible: includedByFilter opacity: 0 @@ -448,6 +455,10 @@ DataListView { text: name } + Label { + //text: model.month + } + Label { id: dateLa @@ -473,6 +484,17 @@ DataListView { } } + section.property: "month" + section.delegate: ItemDelegate { + id: name + background: Rectangle { + color: "red" + } + + width: parent.width + text: section + } + Dialog { id: filterSelectPu diff --git a/resources/qml/Widgets/ResultWidget.qml b/resources/qml/Widgets/ResultWidget.qml index 6fc1a59..e6caba5 100644 --- a/resources/qml/Widgets/ResultWidget.qml +++ b/resources/qml/Widgets/ResultWidget.qml @@ -18,7 +18,9 @@ import QtQuick 2.9 import QtQuick.Controls 2.4 +import QtQuick.Layouts 1.3 import QtGraphicalEffects 1.0 +import QtQuick.Controls.Material 2.3 import "../Components" @@ -31,7 +33,31 @@ DataListView { property string subTitle: getSubtitle() property bool titleIsPageTitle: true - property Component headerComponent: ToolButton { + property Component headerComponent: RowLayout { + + height: parent.height + width: 100//childrenRect.width + + spacing: 0 + + ToolButton { + id: flowToolBt + + visible: control.widgetData['discipline'] === 'speed' + + onClicked: { + if(speedFlowChartBackgroundRect.state === "hidden"){ + speedFlowChartBackgroundRect.state ="visible" + } + else { + speedFlowChartBackgroundRect.state = "hidden" + } + } + + icon.name: "flowchart" + } + + ToolButton { id: moreToolBt onClicked: { @@ -39,6 +65,7 @@ DataListView { } icon.name: "menu" + } } property var widgetData: currentWidgetData @@ -642,4 +669,54 @@ DataListView { } + Rectangle { + id: speedFlowChartBackgroundRect + + state: "hidden" + + anchors.fill: parent + color: Material.background + + SpeedFlowChart { + anchors.fill: parent + + flowchartData: control.widgetData; + + //participants: control.widgetData['participants'].slice() + //route_names: control.widgetData['route_names'] + + rounds: control.widgetData['route_names'][2].includes("8") ? 2:1 + } + + states: [ + State { + name: "hidden" + PropertyChanges { + target: speedFlowChartBackgroundRect + opacity: 0 + scale: 0.9 + height: 0 + } + }, + + State { + name: "visible" + PropertyChanges { + target: speedFlowChartBackgroundRect + opacity: 1 + scale: 1 + height: parent.height + } + } + ] + + transitions: [ + Transition { + NumberAnimation { + properties: "opacity,scale" + duration: 200 + } + } + ] + } } diff --git a/resources/qml/qml.qrc b/resources/qml/qml.qrc index fe58ac3..9a4cbe3 100644 --- a/resources/qml/qml.qrc +++ b/resources/qml/qml.qrc @@ -17,5 +17,6 @@ Widgets/StartlistWidget.qml Widgets/RankingWidget.qml Pages/AthleteSearchPage.qml + Components/SpeedFlowChart.qml diff --git a/resources/shared/icons/bluerock/20x20/flowchart.png b/resources/shared/icons/bluerock/20x20/flowchart.png new file mode 100644 index 0000000000000000000000000000000000000000..6469b0a1c38b852379dd92e6eeb61a9a09b9b80e GIT binary patch literal 369 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE-VTavfC3&Vd9T(EcfWS|IVfk$L9 z0|Vb-5N14{zaj-F$X?><>&pI^O-e}6T5y8RU!c%GPZ!4!i_>SP7-lgA3bgHiv8bBS z)^*E;J4c*!bl2E;M4eZN)H$*x%qd4lgvD3EHR@o-L&hUJ%>ExrzFBKm7Hnbg;ryBZ z|IBwA+f;4n+7=yjH1Ih%GdH{B$IS2?&4q>^)b^ay+BWUL z?upV;bH!p^e!Y4U&EC#Ar!mX^(YIK2tL-0_WlrAiTbaIcZp`&#G2G{sDohJ*emhxz zz^Qq|+dHfglKV9_9^Uqd(;#@=Y=vtVTig${7uik@U^Y9jKChZ_)*<$*S(r|@ MboFyt=akR{0PAy_TL1t6 literal 0 HcmV?d00001 diff --git a/resources/shared/icons/bluerock/20x20@2/flowchart.png b/resources/shared/icons/bluerock/20x20@2/flowchart.png new file mode 100644 index 0000000000000000000000000000000000000000..c87cc2e22c4b40d70660bc436d1a77f58d0f8944 GIT binary patch literal 663 zcmV;I0%-k-P)VGd000McNliru;|3ZM5iR9JiL3ws0whU9 zK~z}7?U+4F96=bzf9BTn;9^e2KoAU3Qc1uFA&sUvEMlXO+QLr!1Zn&R7QW;g#7ZzA zh(f?z;U$GJMLHp*kPG;hQwtA{n1!{Og@<8ZZs*S3EA|fqGtbQY_rJ5xGtbOIiWJGB zqXisUpx3AG8n{jRCEoxSz?oJqR9{oDS|G3!cpT8z6dts@52ga!L7)}lpNXOu_yagT z}j?uU?^^J&pgEa0P;W%D0_$;i%Z-vP}Kw+dW_Ro@&C4{SJ@;Qqk;-X^BM4;(Ly=*XNGtNwsF_>e;DX=Yav18b00>?yPKA`WZ z;nlzoBPMUPEuyRptcvz`1HLUSEiQ`oQB<-XZ5x;dCIDO5o=4y-XnZrkYjvS=ZLgvT zl&e)$pY#cED(o8(_&$hve-&RpP!aZ>M#;K>U)m8WtNe9W*pEZ})I|>XE#~cugX||^ zuK?YCd()&UHt41_vqT_x x{fWwIK@$5o*I^&3;&?c8O_e0arAUz&?f~B%*gFQE2dw}A002ovPDHLkV1hF~C0PIf literal 0 HcmV?d00001 diff --git a/resources/shared/icons/bluerock/20x20@3/flowchart.png b/resources/shared/icons/bluerock/20x20@3/flowchart.png new file mode 100644 index 0000000000000000000000000000000000000000..98bd45f3cabbbc837c79f12e3ef7c673e798d1b9 GIT binary patch literal 884 zcmV-)1B?8LP)VGd000McNliru;|3ZM5go&wxc~qF0|7}y zK~!ko?U~I>RY4espR1upcJ1SOv04RfA_}6Qg1&Y|5NIih(WXsNwDb?CMaybYn|2n_ zqK%2WHbDl3*#{LFeL{;$GxBDsq}>*dFbwaRGnX^!IW#{wi#z9?`OPzD?#z4UKu}On zP*6~6l$!^Sdf+s$I3{i!xB`r2eNcMpW#as%oB~r#;1F1~@eezyUY_2jDoB z=O{L{z#CQa5vQfVmaNa9y}+nL(lLAe0-Cc5y9bzz0Q(3GM% z-cq*)=&>wjooRzTrKX_N*@r;Ep^YU#uLb(Td;(RgP8W@<5jbvv?Nj?}C3(Ru3-no_ zN$5vG_0gLOz$;)F7&5Lu5uNLa_|L|vMxA^}ZB7H<4F6%(w}MaLqH5SRfw%)KO6YmH z0>5G3rzJ%-nl9$O9(^x5dJZiV@OSke^Q8tgg}nj$etDQud#5kedTuYg4+r1?{GR~3 zE*v@h9;lZckA13e{A}b3Tmq)sbVM0Dz~ z2j6WL-#luUN|1DAyR_dWRDwD?v5=hOnJ-+!6Zv{B{9dZUxTF)ii* z@Y{&_0jy8p+a&l-07tc$-9X8R`3dYuvS>96i^f-GP8(-60K6BH{(}jC52+Pe*B8V0 z8SvVOsR#Di8rI)gcc~M_vbG0y2!rwjcw-E}b6|rJcSLovtnJYsfO|$NE@hHRj%6h9u=<8vIsgaY z033j`0_^&!qS~=6m38$@>ozl=G|Mr2p_HI!v2IXMP*70NLhBzZO_e%kXbFM<0000< KMNUMnLSTZAk&Tf6 literal 0 HcmV?d00001 diff --git a/resources/shared/icons/bluerock/20x20@4/flowchart.png b/resources/shared/icons/bluerock/20x20@4/flowchart.png new file mode 100644 index 0000000000000000000000000000000000000000..dc859de4ad1595cd50313b6b006d75a6b2f1fe13 GIT binary patch literal 1061 zcmV+=1ls$FP)VGd000McNliru;|3ZM5e%sV zB9TZW5{X1vsmKE54VAipxgP@d2N%vuRR0Vn_kpa2vJKmjNK1>izz ziHAJ-^7A=535H~*OiF6An`(-we!0izanEx88ooCTC0Kn+j@ zj9A!T$pvtWfQuF|J^^(x`E~&BEb?6g3d0I-G0+UmB!Dmg9B|2B3-nq*ybTnG5nzi2 zyf45`Lm5@TTMLMH!?rqKwP^HLpv`~6S zX$7!Lt-LzD0uBR1DgK}+^vrQ-vX#- zR^8$Rq96fA!dREYL0AAWDH% zhV(Jb_nUzFAOJQ3TQq4sK$|A50%!;TU?WhiN$ban+_|YF2>gMzg6U@0 zhd&pp`M?8%e@!vAHNddOZWt$Yns$|8zU!-sn~)zF?CX5+ufkAYFR(GjwpjH-o&7;S zhVU^%S_kks=I>G9slooF4*-uF(xN!;ZRRzJ6Iz(j*q`;I2M(csMRml*e!n5ltPiK4 z@0z;C;-;5*Z8t24b85j!sQ9qsZkJ8yKQ%mc%lk)7Z+ig@YVt*J9!7S$OxWXUKj|hn z|7LJrZ(uNC2Mvp2GtL{E{3QG{#u8>pK9=x=xic6U;HqdNU%-t zvb9K76CTro(uCZ`$aR(g6o4WDC;$bZ02B#80hn0;y00000NkvXXu0mjf;r!Yo literal 0 HcmV?d00001 diff --git a/resources/shared/shared.qrc b/resources/shared/shared.qrc index fc0916f..babeb75 100644 --- a/resources/shared/shared.qrc +++ b/resources/shared/shared.qrc @@ -42,5 +42,9 @@ icons/bluerock/20x20@3/year.png icons/bluerock/20x20@4/filter.png icons/bluerock/20x20@4/year.png + icons/bluerock/20x20/flowchart.png + icons/bluerock/20x20@2/flowchart.png + icons/bluerock/20x20@3/flowchart.png + icons/bluerock/20x20@4/flowchart.png