diff --git a/blueROCK.pro b/blueROCK.pro index 1d66de9..305e2c3 100644 --- a/blueROCK.pro +++ b/blueROCK.pro @@ -25,6 +25,7 @@ DEFINES += QT_DEPRECATED_WARNINGS #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ + sources/brathlete.cpp \ sources/brleague.cpp \ sources/appsettings.cpp \ sources/brcalendar.cpp \ @@ -35,6 +36,8 @@ SOURCES += \ sources/brprovider.cpp \ sources/brproviderdr.cpp \ sources/brprovidervl.cpp \ + sources/brresult.cpp \ + sources/brround.cpp \ sources/brseason.cpp \ sources/brserverconnector.cpp \ sources/brwidget.cpp \ @@ -42,6 +45,7 @@ SOURCES += \ HEADERS += \ + headers/brathlete.h \ headers/brleague.h \ headers/appsettings.h \ headers/brcalendar.h \ @@ -52,6 +56,8 @@ HEADERS += \ headers/brprovider.h \ headers/brproviderdr.h \ headers/brprovidervl.h \ + headers/brresult.h \ + headers/brround.h \ headers/brseason.h \ headers/brserverconnector.h \ headers/brwidget.h diff --git a/headers/brathlete.h b/headers/brathlete.h new file mode 100644 index 0000000..6f37c92 --- /dev/null +++ b/headers/brathlete.h @@ -0,0 +1,73 @@ +#ifndef BRATHLETE_H +#define BRATHLETE_H + +#include +#include +#include "brwidget.h" + +class BRAthlete : public BRWidget +{ + Q_OBJECT + Q_PROPERTY(QString firstName READ getFirstName NOTIFY metadataChanged) + Q_PROPERTY(QString lastName READ getLastName NOTIFY metadataChanged) + Q_PROPERTY(QString city READ getCity NOTIFY metadataChanged) + Q_PROPERTY(QString federation READ getFederation NOTIFY metadataChanged) + Q_PROPERTY(QUrl federationUrl READ getFederationUrl NOTIFY metadataChanged) + Q_PROPERTY(int yearOfBirth READ getYearOfBirth NOTIFY metadataChanged) + Q_PROPERTY(BRAthleteGender gender READ getGender NOTIFY metadataChanged) + Q_PROPERTY(QString nation READ getNation NOTIFY metadataChanged) + Q_PROPERTY(int age READ getAge NOTIFY metadataChanged) +public: + friend class BRProvider; + + enum BRAthleteGender { + Unknown = -1, + Male, + Female + }; + + typedef struct { + const BRAthlete* athlete; + + QString firstName; + QString lastName; + QString city; + QString federation; + QUrl federationUrl; + int yearOfBirth; + BRAthleteGender gender; + QString nation; + int age; + } BRAthleteData; + + BRWidget::BRWidgetStatusCode load() override; + + QString getFirstName(); + QString getLastName(); + QString getCity(); + QString getFederation(); + QUrl getFederationUrl(); + int getYearOfBirth(); + BRAthleteGender getGender(); + QString getNation(); + int getAge(); + +private: + BRAthlete(BRProvider* provider, BRWidget::BRFederation federation, int id, BRAthleteData initialData); + void setData(BRAthleteData data); + + QString firstName; + QString lastName; + QString city; + QString federation; + QUrl federationUrl; + int yearOfBirth; + BRAthleteGender gender; + QString nation; + int age; + +signals: + void metadataChanged(); +}; + +#endif // BRATHLETE_H diff --git a/headers/brcategory.h b/headers/brcategory.h index f794c19..8ce4456 100644 --- a/headers/brcategory.h +++ b/headers/brcategory.h @@ -4,32 +4,50 @@ #include #include "brwidget.h" +#include "brround.h" +#include "brathlete.h" + +class BRCompetition; class BRCategory : public BRWidget { Q_OBJECT Q_PROPERTY(QString name READ getName NOTIFY metadataChanged) + Q_PROPERTY(BRRound* currentRound READ getCurrentRound WRITE setCurrentRound NOTIFY currentRoundChanged) + Q_PROPERTY(QList rounds READ getRoundsQML NOTIFY roundsChanged) public: friend class BRProvider; + friend class BRCompetition; typedef struct { const BRCategory* category; QString name; + BRRound* currentRound; + QList rounds; } BRCategoryData; Q_INVOKABLE BRWidget::BRWidgetStatusCode load() override; - + Q_INVOKABLE BRCompetition* getCompetition() const; Q_INVOKABLE QString getName(); + Q_INVOKABLE BRRound* getCurrentRound() const; + Q_INVOKABLE void setCurrentRound(BRRound* round); + Q_INVOKABLE QList getRounds() const; + Q_INVOKABLE QList getRoundsQML(); private: BRCategory(BRProvider* provider, BRWidget::BRFederation federation, int id, BRCategoryData initialData); void setData(BRCategoryData data); - const int id; + BRCompetition* competition; + BRRound* currentRound; + QString name; + QList rounds; signals: void metadataChanged(); + void currentRoundChanged(); + void roundsChanged(); }; diff --git a/headers/brcompetition.h b/headers/brcompetition.h index 07c6eb8..b8e8096 100644 --- a/headers/brcompetition.h +++ b/headers/brcompetition.h @@ -23,6 +23,7 @@ class BRCompetition : public BRWidget Q_PROPERTY(QUrl eventWebsiteUrl READ getEventWebsiteUrl NOTIFY metadataChanged) Q_PROPERTY(QList infosheetUrls READ getInfosheetUrls NOTIFY metadataChanged) Q_PROPERTY(QList categories READ getCategoriesQML NOTIFY categoriesChanged) + Q_PROPERTY(BRCategory* currentCategory READ getCurrentCategory WRITE setCurrentCategory NOTIFY currentCategoryChanged) public: friend class BRProvider; @@ -59,6 +60,8 @@ public: Q_INVOKABLE QUrl getEventWebsiteUrl(); Q_INVOKABLE QList getInfosheetUrls(); Q_INVOKABLE QList getCategoriesQML(); + Q_INVOKABLE BRCategory* getCurrentCategory() const; + Q_INVOKABLE void setCurrentCategory(BRCategory* category); static bool lessThan(BRCompetition* competition1, BRCompetition* competition2); @@ -68,7 +71,6 @@ private: void setLeague(BRLeague* league); // metadata - const int id; QString name; BRDiscipline discipline; QDate startDate; @@ -79,12 +81,14 @@ private: // data QList categories; + BRCategory* currentCategory; void setData(BRCompetitionData data); signals: void metadataChanged(); void categoriesChanged(); + void currentCategoryChanged(); }; diff --git a/headers/brcup.h b/headers/brcup.h index 097dd55..bff86b7 100644 --- a/headers/brcup.h +++ b/headers/brcup.h @@ -31,7 +31,6 @@ private: BRCup(BRProvider* provider, BRWidget::BRFederation federation, int id, BRCupData initialData); void setData(BRCupData data); - const int id; QString name; QList categories; diff --git a/headers/brleague.h b/headers/brleague.h index 419a682..86e3537 100644 --- a/headers/brleague.h +++ b/headers/brleague.h @@ -31,7 +31,6 @@ public: BRWidget::BRWidgetStatusCode load() override; - int getId() const; Q_INVOKABLE QString getName(); Q_INVOKABLE QColor getColor(); Q_INVOKABLE QList getCompetitions(); @@ -42,8 +41,6 @@ private: BRLeague(BRProvider* provider, BRWidget::BRFederation federation, int id, BRLeagueData initialData); void setData(BRLeagueData data); - const int id; - QString name; QColor color; diff --git a/headers/brprovider.h b/headers/brprovider.h index 14477a6..ab13ccf 100644 --- a/headers/brprovider.h +++ b/headers/brprovider.h @@ -12,7 +12,9 @@ #include "brseason.h" #include "brleague.h" #include "brcompetition.h" +#include "brathlete.h" #include "brcup.h" +#include "brresult.h" class BRProvider : public QObject { @@ -25,6 +27,9 @@ public: friend class BRSeason; friend class BRLeague; friend class BRCompetition; + friend class BRCategory; + friend class BRAthlete; + friend class BRRound; protected: QVariantMap serverRequest(QUrl serviceUrl, QList additionalHeaders = {}, QUrlQuery postData = QUrlQuery()); @@ -35,12 +40,16 @@ protected: virtual BRCompetition* getCompetition(BRWidget::BRFederation federation, int id, BRCompetition::BRCompetitionData initialData) final; virtual BRCup* getCup(BRWidget::BRFederation federation, int id, BRCup::BRCupData initialData) final; virtual BRCategory* getCategory(BRWidget::BRFederation federation, int id, BRCategory::BRCategoryData initialData) final; + virtual BRAthlete* getAthlete(BRWidget::BRFederation federation, int id, BRAthlete::BRAthleteData initialData) final; + virtual BRRound* getRound(BRWidget::BRFederation federation, int id, BRRound::BRRoundData initialData) final; + virtual BRResult* getResult(BRWidget::BRFederation federation, int id, BRResult::BRResultData initialData) final; virtual BRWidget::BRWidgetStatusCode getWidgetData(BRCalendar::BRCalendarData* calendarData) = 0; virtual BRWidget::BRWidgetStatusCode getWidgetData(BRSeason::BRSeasonData* seasonData) = 0; virtual BRWidget::BRWidgetStatusCode getWidgetData(BRLeague::BRLeagueData* leagueData) = 0; virtual BRWidget::BRWidgetStatusCode getWidgetData(BRCompetition::BRCompetitionData* competitionData) = 0; - + virtual BRWidget::BRWidgetStatusCode getWidgetData(BRCategory::BRCategoryData* categoryData) = 0; + virtual BRWidget::BRWidgetStatusCode getWidgetData(BRRound::BRRoundData* roundData) = 0; signals: diff --git a/headers/brproviderdr.h b/headers/brproviderdr.h index bbad631..11e101a 100644 --- a/headers/brproviderdr.h +++ b/headers/brproviderdr.h @@ -23,10 +23,16 @@ protected: BRWidget::BRWidgetStatusCode getWidgetData(BRCompetition::BRCompetitionData* competitionData) override; BRCompetition::BRCompetitionData parseCompetitionData(QVariantMap rawData, BRWidget::BRFederation federation); + void parseCompetitionData(BRCompetition::BRCompetitionData* competitionData, QVariantMap rawData, BRWidget::BRFederation federation); BRCup::BRCupData parseCupData(QVariantList categoriesList, QVariantMap rawData, BRWidget::BRFederation federation); + BRWidget::BRWidgetStatusCode getWidgetData(BRCategory::BRCategoryData* categoryData) override; BRCategory::BRCategoryData parseCategoryData(QVariantMap rawData); + void parseCategoryData(BRCategory::BRCategoryData* categoryData, QVariantMap rawData); + + + BRWidget::BRWidgetStatusCode getWidgetData(BRRound::BRRoundData* roundData) override; private: QMap> leagues; diff --git a/headers/brprovidervl.h b/headers/brprovidervl.h index d0cddf2..07b5675 100644 --- a/headers/brprovidervl.h +++ b/headers/brprovidervl.h @@ -25,7 +25,13 @@ protected: BRCup::BRCupData parseCupData(QVariantMap rawData); + BRWidget::BRWidgetStatusCode getWidgetData(BRCategory::BRCategoryData* categoryData) override; BRCategory::BRCategoryData parseCategoryData(QVariantMap rawData); + void parseCategoryData(BRCategory::BRCategoryData* categoryData, QVariantMap rawData); + + BRWidget::BRWidgetStatusCode getWidgetData(BRRound::BRRoundData* roundData) override; + BRRound::BRRoundData parseRoundData(QVariantMap rawData); + void parseRoundData(BRRound::BRRoundData* roundData, QVariantMap rawData); private: QMap> leagues; diff --git a/headers/brresult.h b/headers/brresult.h new file mode 100644 index 0000000..7ca4991 --- /dev/null +++ b/headers/brresult.h @@ -0,0 +1,42 @@ +#ifndef BRRESULT_H +#define BRRESULT_H + +#include + +#include "brwidget.h" + +class BRAthlete; + +class BRResult : public BRWidget +{ + Q_OBJECT + Q_PROPERTY(int rank READ getRank NOTIFY metadataChanged) + Q_PROPERTY(BRAthlete* athlete READ getAthlete NOTIFY metadataChanged) + +public: + friend class BRProvider; + + typedef struct { + const BRResult* result; + + int rank; + BRAthlete* athlete; + } BRResultData; + + BRWidget::BRWidgetStatusCode load() override; + + Q_INVOKABLE int getRank() const; + Q_INVOKABLE BRAthlete* getAthlete() const; + +private: + BRResult(BRProvider* provider, BRWidget::BRFederation federation, int id, BRResultData initialData); + void setData(BRResultData data); + + int rank; + BRAthlete* athlete; + +signals: + void metadataChanged(); +}; + +#endif // BRRESULT_H diff --git a/headers/brround.h b/headers/brround.h new file mode 100644 index 0000000..20e6db9 --- /dev/null +++ b/headers/brround.h @@ -0,0 +1,49 @@ +#ifndef BRROUND_H +#define BRROUND_H + +#include +#include "brwidget.h" +#include "brresult.h" + +class BRCategory; + +class BRRound : public BRWidget +{ + Q_OBJECT + Q_PROPERTY(QString name READ getName NOTIFY metadataChanged) + Q_PROPERTY(QList results READ getResultsQML NOTIFY resultsChanged) + +public: + friend class BRProvider; + friend class BRCategory; + + typedef struct { + const BRRound* round; + + QString name; + QList results; + } BRRoundData; + + BRWidget::BRWidgetStatusCode load() override; + + Q_INVOKABLE BRCategory* getCategory() const; + + Q_INVOKABLE QString getName(); + Q_INVOKABLE QList getResultsQML(); + + +private: + BRRound(BRProvider* provider, BRWidget::BRFederation federation, int id, BRRoundData initialData); + void setData(BRRoundData data); + + BRCategory* category; + + QString name; + QList results; + +signals: + void metadataChanged(); + void resultsChanged(); +}; + +#endif // BRROUND_H diff --git a/headers/brseason.h b/headers/brseason.h index e134698..6efd1f9 100644 --- a/headers/brseason.h +++ b/headers/brseason.h @@ -43,7 +43,6 @@ private: explicit BRSeason(BRProvider* provider, BRWidget::BRFederation federation, int id, BRSeasonData initialData); void setData(BRSeasonData data); - const int id; int year; QString name; bool multiLeagueSupport; diff --git a/headers/brwidget.h b/headers/brwidget.h index 0316962..924e2bb 100644 --- a/headers/brwidget.h +++ b/headers/brwidget.h @@ -21,16 +21,18 @@ public: Success = 200, InternalError = 900, NoProviderError = 901, - NotImplementedError = 902 + NotImplementedError = 902, + OpeationNotSupportedError = 903 }; Q_ENUM(BRWidgetStatusCode) Q_INVOKABLE virtual BRWidget::BRWidgetStatusCode load() = 0; Q_INVOKABLE BRFederation getFederation() const; + Q_INVOKABLE int getId() const; protected: - explicit BRWidget(BRProvider* provider, BRFederation federation); + explicit BRWidget(BRProvider* provider, BRFederation federation, int id); BRProvider* getProvider(); template @@ -46,6 +48,7 @@ protected: private: BRProvider* provider; const BRFederation federation; + const int id; signals: diff --git a/resources/qml/Pages/BRWidgetPage.qml b/resources/qml/Pages/BRWidgetPage.qml index be1bad5..5f0883c 100644 --- a/resources/qml/Pages/BRWidgetPage.qml +++ b/resources/qml/Pages/BRWidgetPage.qml @@ -44,7 +44,9 @@ Page { Component.onCompleted: { + console.log("TRYING TO LOAD") var status = data.load() + console.log(data) if(status !== BRWidget.Success) ready = false else diff --git a/resources/qml/Pages/CalendarPage.qml b/resources/qml/Pages/CalendarPage.qml index 661af46..c4833b6 100644 --- a/resources/qml/Pages/CalendarPage.qml +++ b/resources/qml/Pages/CalendarPage.qml @@ -66,7 +66,12 @@ BRWidgetPage { onSelectionFinished: { if(data.task === "competition"){ - app.openWidget({comp: data.comp, cat: data.cat, type:data.status === 4 ? 'starters':''}) + console.log("OPENING COMP 1") + loadingDl.open() + data.competition.currentCategory = data.category + app.openResults(data.competition) + loadingDl.close() + //app.openWidget({comp: data.comp, cat: data.cat, type:data.status === 4 ? 'starters':''}) } else if(data.task === "season"){ loadingDl.open() @@ -95,7 +100,7 @@ BRWidgetPage { var selectOptions = [] var categories = competition.categories for(var i = 0; i < categories.length; i++){ - selectOptions.push({text: categories[i].name, data:{task: "competition", cat: categories[i], comp: competition, status:categories.status}}) + selectOptions.push({text: categories[i].name, data:{task: "competition", category: categories[i], competition: competition, /*TODO*/ status:categories.status}}) } var infoUrls = competition.infosheetUrls @@ -362,7 +367,7 @@ BRWidgetPage { } onClicked: { - control.openCompetition(thisData) + control.openCompetition(competitionDel.thisData) } ParallelAnimation { diff --git a/resources/qml/Pages/ResultPage.qml b/resources/qml/Pages/ResultPage.qml new file mode 100644 index 0000000..ca2e4a4 --- /dev/null +++ b/resources/qml/Pages/ResultPage.qml @@ -0,0 +1,896 @@ +/* + blueROCK - for digital rock + Copyright (C) 2019 Dorian Zedler + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import QtQuick 2.9 +import QtQuick.Controls 2.5 +import QtQuick.Layouts 1.3 +import QtGraphicalEffects 1.0 +import QtQuick.Controls.Material 2.3 +//import QtLocation 5.13 + +import QtPurchasing 1.12 + +import "../Components" +BRWidgetPage { + id: control + ready: true + title: data.name + titleIsPageTitle: true + subTitle: data.currentCategory.name + " " + qsTr("(Results)") + + headerComponent: RowLayout { + id: headerComponent + + height: parent.height + + spacing: 0 + + ToolButton { + id: flowToolBt + + visible: speedFlowChart.enabled + + enabled: false // TODO control.data.currentCategory.currentRound.getId() === -1 && Object.keys(control.widgetData['route_names']).length > 2 + + onClicked: { + if(speedFlowChartBackgroundRect.state === "hidden"){ + speedFlowChartBackgroundRect.state ="visible" + control.positionViewAtBeginning() + } + else { + speedFlowChartBackgroundRect.state = "hidden" + } + } + + icon.name: "flowchart" + } + + ToolButton { + id: moreToolBt + + Layout.alignment: Layout.Right + + onClicked: { + control.changeCategory() + } + + icon.name: "menu" + } + } + + onLoadingFinished: { + if(resultLv.model.length > 0){ + control.ready = true + control.status = 200 + } + else { + control.ready = false + control.status = 901 + } + + if(!control.ready) + return + } + + onSelectionFinished: { + if(data.task === "category"){ + loadingDl.open() + control.data.currentCategory = data.category + control.data.currentCategory.load() + loadingDl.close() + } + else if(data.task === "season"){ + loadingDl.open() + control.data.currentSeason = data.season + loadingDl.close() + } + else if(data.task === "cup1"){ + control.openCup(data) + } + else if(data.task === "cup2"){ + app.openWidget({cup: data.cup, cat: data.cat}) + } + } + + function changeCategory(){ + var selectOptions = [] + var categories = control.data.categories + for(var i = 0; i < categories.length; i++){ + if(categories[i] === control.data.currentCategory) + continue + selectOptions.push({text: categories[i].name, data:{task: "category", category: categories[i]}}) + } + + selector.appear(selectOptions, qsTr("select cat")) + } + + function changeRound(round) { + loadingDl.open() + round.load() + control.data.currentCategory.currentRound = round + loadingDl.close() + } + + DataListView { + id: resultLv + + anchors.fill: parent + + model: control.data.currentCategory.currentRound.results + + onRefresh: { + control.data.currentCategory.load() + } + + /* TODO onWidgetDataChanged: { + console.log("widget data changed") + + if(control.widgetData['discipline'] === 'speed' && control.widgetData['route_order'] === "-1" && Object.keys(control.widgetData['route_names']).length > 2){ + speedFlowChart.flowchartData = ({}) + speedFlowChart.enabled = true + speedFlowChart.flowchartData = control.widgetData + } + else { + speedFlowChart.enabled = false + speedFlowChart.flowchartData = ({}) + } + }*/ + + Connections { + target: selector + onSelectionFinished: { + if(data.cat !== undefined){ + updateData({cat: data.cat}, true) + } + } + } + + onContentYChanged: { + if(contentY > 0 && speedFlowChartBackgroundRect.state === "visible"){ + resultLv.positionViewAtBeginning() + } + } + + delegate: ItemDelegate { + id: partDel + + property int ind: index + property var thisData: modelData + + enabled: speedFlowChartBackgroundRect.state === "hidden" + + width: parent.width + height: 70 + + text: "" + + opacity: 0 + scale: 0.9 + + onThisDataChanged: { + fadeInPa.start() + } + + onClicked: { + app.openWidget({person:thisData["PerId"]}) + } + + ParallelAnimation { + id: fadeInPa + NumberAnimation { target: partDel; property: "opacity"; from: 0; to: 1.0; duration: 400 } + NumberAnimation { target: partDel; property: "scale"; from: 0.8; to: 1.0; duration: 400 } + } + + Rectangle { + id: partDelBackgroundRect + 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 // TODO - partDelSecondRow.height + + Label { + height: parent.height + width: text === "" ? parent.width * 0.08:parent.width * 0.1 + + fontSizeMode: Text.Fit + font.bold: true + font.pixelSize: height * 0.6//Math.abs( partDelSecondRow.height > 0 ? height * 0.6:height * 0.4 ) + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + + text: partDel.thisData.rank + } + + Label { + height: parent.height + width: parent.width * 0.5 + + fontSizeMode: Text.Fit + font.bold: true + font.pixelSize: height * 0.6//Math.abs( partDelSecondRow.height > 0 ? height * 0.6:height * 0.4 ) + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignLeft + + text: partDel.thisData.athlete.firstName + " " + partDel.thisData.athlete.lastName + (partDel.thisData["start_number"] !== undefined ? (" (" + partDel.thisData["start_number"] + ")"):"") + } + + Label { + height: parent.height + width: parent.width * 0.4 + + fontSizeMode: Text.Fit + font.bold: false + font.pixelSize: height * 0.6 //Math.abs( partDelSecondRow.height > 0 ? height * 0.4:height * 0.3 ) + minimumPixelSize: height * 0.3 < 1 ? 1:height * 0.3 + + elide: "ElideRight" + + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + + text: "(" + partDel.thisData.athlete.federation + ")" + + onLinkActivated: { + Qt.openUrlExternally(link) + } + } + } +/* + Row { + id: partDelSecondRow + + width: parent.width + height: 0 // TODO multiResRow.active || multiGenResRow.active || resultLa.acitve ? parent.height / 2 : 0 + + Row { + id: multiResRow + + property bool active: false // TODO parseInt(widgetData[ "route_order" ]) > -1 && boulderResRep.model > 0 + + height: parent.height + width: active ? parent.width * 0.75:0 + + enabled: parseInt(widgetData[ "route_order" ]) > -1 && boulderResRep.model > 0 + + Repeater { + id: boulderResRep + model: parseInt(widgetData[ "route_num_problems" ]) + + function getDataForIcon(index){ + var resultString = widgetData[ "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) + } + } + else { + resultList = [-1,-1] + } + + 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) + + onResultDataChanged: { + boulderResCv.requestPaint() + } + + 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"); + + // clear all remainings from other routes + context.clearRect(0, 0, width, height); + + 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 + if(resultData[0] !== -1) { + // if there is a result available -> draw background + context.fillStyle = "#b7b7b7"; + } + else { + context.fillStyle = "transparent"; + } + + 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: parseInt(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: parseInt(text) > 0 + + fontSizeMode: Text.Fit + font.pixelSize: height + minimumPixelSize: 1 + + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + + text: boulderResCv.resultData[0] + } + } + + } + + } + + } + + Row { + id: multiGenResRow + + property bool active: false // TODO ((parseInt(widgetData[ "route_order" ]) === -1) && (generalResRep.model > 0)) ? true:false + + height: parent.height + width: active ? parent.width - resultLa.width:0 + + enabled: ((parseInt(widgetData[ "route_order" ]) === -1) && (generalResRep.model > 0)) ? true:false + + Repeater { + id: generalResRep + + property var routes: getRoutes() + model: routes.length + + function getRoutes() { + + var obj = widgetData["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: multiGenResRow.active + + 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: widgetData[ "participants" ][partDel.ind]["result"+(generalResRep.routes[index][0])] === undefined ? "":widgetData[ "participants" ][partDel.ind]["result"+(generalResRep.routes[index][0])] + } + + } + + } + } + + Label { + id: resultLa + + property bool acitve: false // TODO ( boulderResRep.model > 0 || widgetData["discipline"] !== "boulder" ) && parseInt(widgetData[ "route_order" ]) > -1 + + width: enabled ? parent.width * 0.25:0 + height: enabled ? parent.height:0 + + enabled: ( boulderResRep.model > 0 || widgetData["discipline"] !== "boulder" ) && parseInt(widgetData[ "route_order" ]) > -1 + + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + + fontSizeMode: Text.Fit + font.pixelSize: Math.abs( height * 0.6 ) + minimumPixelSize: 1 + + text: widgetData[ "participants" ][partDel.ind]["result"] === undefined ? "":widgetData[ "participants" ][partDel.ind]["result"] + } + } + */ + } + } + + PullRefresher { + target: resultLv + + postRefreshDelay: 0 + + busyIndicator: FancyBusyIndicator {} + refreshPosition: height * 1.3 + + onRefreshRequested: { + resultLv.refresh() + } + } + } + + RectangularGlow { + id: toolBarEffect + glowRadius: 3 + spread: 0.2 + color: "black" + opacity: 0.3 + anchors.fill: routeSelectTb + } + + TabBar { + id: routeSelectTb + + property var tabs: control.data.currentCategory.rounds + property var tabIndexes: [] + + enabled: speedFlowChartBackgroundRect.state === "hidden" + + anchors { + left: parent.left + right: parent.right + bottom: parent.bottom + } + + height: tabs.length > 1 ? 50:0 + width: parent.width + + position: TabBar.Footer + + currentIndex: getIndex(control.data.currentCategory.currentRound) + + function getIndex(round) { + //console.log("getting index for route number: " + routeNumber) + + if(tabs === undefined){ + return + } + + for(var i = 0; i < tabs.length; i++){ + //console.log(tabs[i]) + if(tabs[i] === round){ + //console.log("found index: " + i) + return i + } + } + + + return 0 + } + + Repeater { + id: routeSelectButtonRep + + model: routeSelectTb.tabs + + onModelChanged: { + routeSelectTb.setCurrentIndex(routeSelectTb.getIndex(control.data.currentCategory.currentRound)) + } + + delegate: TabButton { + text: modelData.name + + width: Math.max(150, routeSelectTb.width / routeSelectButtonRep.model) //text.length * font.pixelSize + + onClicked: { + //console.log("changing to index: " + index + " (" + routeSelectTb.tabs[index][0] + ", " + routeSelectTb.tabs[index][1] + ")") + control.changeRound(modelData) + + return; + if(routeSelectTb.getIndex(parseInt(control.widgetData['route_order'])) !== index){ + control.changeRoute(routeSelectTb.tabs[index][0]) + routeSelectTb.setCurrentIndex(routeSelectTb.getIndex(parseInt(control.widgetData['route_order']))) + } + } + } + } + + } + + Rectangle { + id: speedFlowChartBackgroundRect + + state: "hidden" + + anchors { + top: parent.top + bottom: parent.bottom + left: parent.right + } + + width: parent.width + height: parent.height + + color: Material.background + + SpeedFlowChart { + id: speedFlowChart + + anchors.fill: parent + + enabled: false + + flowchartData: ({}) + + onEnabledChanged: { + if(!enabled){ + speedFlowChartBackgroundRect.state = 'hidden' + } + } + + Rectangle { + id: speedFlowChartLockedOverlay + + state: appSettings.read("speedBackendPurchase") === "1" ? "unlocked":"locked" + + anchors.fill: parent + anchors.margins: -20 + + color: "white" + + Connections { + target: speedFlowChartProduct + onPurchaseRestored: { + speedFlowChartLockedOverlay.state = appSettings.read("speedBackendPurchase") === "1" ? "unlocked":"locked" + } + + onPurchaseSucceeded: { + speedFlowChartLockedOverlay.state = appSettings.read("speedBackendPurchase") === "1" ? "unlocked":"locked" + } + + onPurchaseFailed: { + purchaseBt.text = qsTr("Purchase failed") + purchaseBt.enabled = false + buttonTextResetTimer.start() + } + } + + Timer { + id: buttonTextResetTimer + interval: 2000 + running: false + repeat: false + onTriggered: { + purchaseBt.text = (speedFlowChartProduct.status === Product.Registered + ? "Buy now for " + speedFlowChartProduct.price + : qsTr("this item is currently unavailable")) + purchaseBt.enabled = true + } + } + + ColumnLayout { + id: lockedLayout + + anchors { + fill: parent + topMargin: parent.height * 0.05 + bottomMargin: parent.height * 0.1 + rightMargin: parent.width * 0.1 + 20 + leftMargin: parent.width * 0.1 + 20 + } + + //spacing: parent.height * 0.05 + + Image { + id: name + + Layout.alignment: Layout.Center + Layout.preferredHeight: height + Layout.preferredWidth: width + + width: lockedLayout.height * 0.1 + height: width + + mipmap: true + + source: "qrc:/icons/lock.png" + } + + Text { + Layout.fillWidth: true + + height: parent.height * 0.05 + + text: qsTr("This is a premium feature.") + + font.bold: true + font.pixelSize: parent.height * 0.05 + fontSizeMode: Text.Fit + + minimumPixelSize: 1 + + horizontalAlignment: Text.AlignHCenter + + } + + SwipeGallery { + Layout.fillHeight: true + Layout.fillWidth: true + + images: ["qrc:/screenshots/SpeedFlowchartDemo/1.png","qrc:/screenshots/SpeedFlowchartDemo/2.png","qrc:/screenshots/SpeedFlowchartDemo/3.png"] + } + + Button { + id: purchaseBt + Layout.alignment: Layout.Center + enabled: speedFlowChartProduct.status === Product.Registered + text: speedFlowChartProduct.status === Product.Registered + ? "Buy now for " + speedFlowChartProduct.price + : qsTr("this item is currently unavailable") + icon.name: "buy" + //display: AbstractButton.TextBesideIcon + onClicked: speedFlowChartProduct.purchase() + } + + } + + states: [ + State { + name: "unlocked" + PropertyChanges { + target: speedFlowChartLockedOverlay + visible: false + } + }, + State { + name: "locked" + PropertyChanges { + target: speedFlowChartLockedOverlay + visible: true + } + } + ] + } + + } + + states: [ + State { + name: "hidden" + PropertyChanges { + target: speedFlowChartBackgroundRect + opacity: 0 + anchors.leftMargin: 0 + } + }, + + State { + name: "visible" + PropertyChanges { + target: speedFlowChartBackgroundRect + opacity: 1 + anchors.leftMargin: -parent.width + } + } + ] + + transitions: [ + Transition { + NumberAnimation { + properties: "opacity,scale,anchors.leftMargin" + duration: 200 + easing.type: Easing.InOutQuad + } + } + ] + } + + +} diff --git a/resources/qml/main.qml b/resources/qml/main.qml index 2c5327e..47d1fd8 100644 --- a/resources/qml/main.qml +++ b/resources/qml/main.qml @@ -461,6 +461,25 @@ Window { loadingDl.close() } + function openResults(competition) { + loadingDl.open() + + console.log("OPENING COMP 2") + var newPageComp = Qt.createComponent("qrc:/Pages/ResultPage.qml").createObject(null, {"data": competition}) + + console.log("OPENING COMP 3") + app.errorCode = newPageComp.status + + if(newPageComp.ready){ + mainStack.push(newPageComp) + } + else { + delete(newPageComp) + } + + loadingDl.close() + } + function defaultString(string, defaultString){ if(string === undefined || string === null){ return defaultString diff --git a/resources/qml/qml.qrc b/resources/qml/qml.qrc index 076af1f..fdb6266 100644 --- a/resources/qml/qml.qrc +++ b/resources/qml/qml.qrc @@ -21,5 +21,6 @@ Components/SwipeGallery.qml Pages/CalendarPage.qml Pages/BRWidgetPage.qml + Pages/ResultPage.qml diff --git a/sources/brathlete.cpp b/sources/brathlete.cpp new file mode 100644 index 0000000..01a3759 --- /dev/null +++ b/sources/brathlete.cpp @@ -0,0 +1,72 @@ +#include "../headers/brathlete.h" + +BRAthlete::BRAthlete(BRProvider* provider, BRWidget::BRFederation federation, int id, BRAthleteData initialData) : BRWidget(provider, federation, id) +{ + this->setData(initialData); +} + +QString BRAthlete::getFirstName() { + return this->firstName; +} + +QString BRAthlete::getLastName() { + return this->lastName; +} + +QString BRAthlete::getCity() { + return this->city; +} + +QString BRAthlete::getFederation() { + return this->federation; +} + +QUrl BRAthlete::getFederationUrl() { + return this->federationUrl; +} + +int BRAthlete::getYearOfBirth() { + return this->yearOfBirth; +} + +BRAthlete::BRAthleteGender BRAthlete::getGender() { + return this->gender; +} + +QString BRAthlete::getNation() { + return this->nation; +} + +int BRAthlete::getAge() { + return this->age; +} + +void BRAthlete::setData(BRAthleteData data) { + this->firstName = data.firstName; + this->lastName = data.lastName; + this->city = data.city; + this->federation = data.federation; + this->federationUrl = data.federationUrl; + this->yearOfBirth = data.yearOfBirth; + this->gender = data.gender; + this->nation = data.nation; + this->age = data.age; + emit this->metadataChanged(); +} + +BRWidget::BRWidgetStatusCode BRAthlete::load() { + + BRAthleteData newData { + this, + + this->firstName, + this->lastName, + this->city, + this->federation, + this->federationUrl, + this->yearOfBirth, + this->gender, + this->nation, + this->age, + }; +} diff --git a/sources/brcalendar.cpp b/sources/brcalendar.cpp index 5c4f3a6..571fc91 100644 --- a/sources/brcalendar.cpp +++ b/sources/brcalendar.cpp @@ -1,7 +1,7 @@ #include "../headers/brcalendar.h" #include "headers/brprovider.h" -BRCalendar::BRCalendar(BRProvider* provider, BRFederation federation) : BRWidget(provider, federation) +BRCalendar::BRCalendar(BRProvider* provider, BRFederation federation) : BRWidget(provider, federation, -1) { this->currentSeason = nullptr; this->seasons = {}; diff --git a/sources/brcategory.cpp b/sources/brcategory.cpp index 3166c5b..3c6a231 100644 --- a/sources/brcategory.cpp +++ b/sources/brcategory.cpp @@ -1,20 +1,77 @@ #include "../headers/brcategory.h" +#include "headers/brprovider.h" -BRCategory::BRCategory(BRProvider* provider, BRWidget::BRFederation federation, int id, BRCategoryData initialData) : BRWidget(provider, federation), id(id) +BRCategory::BRCategory(BRProvider* provider, BRWidget::BRFederation federation, int id, BRCategoryData initialData) : BRWidget(provider, federation, id) { + this->currentRound = nullptr; this->setData(initialData); } +BRCompetition* BRCategory::getCompetition() const { + return this->competition; +} + QString BRCategory::getName() { return this->name; } +BRRound* BRCategory::getCurrentRound() const { + return this->currentRound; +} + +void BRCategory::setCurrentRound(BRRound* round) { + if(!this->rounds.contains(round)) + return; + + this->currentRound = round; + emit this->currentRoundChanged(); +} + +QList BRCategory::getRounds() const { + return this->rounds; +} + +QList BRCategory::getRoundsQML() { + return this->listToQmlList(this->rounds); +} + void BRCategory::setData(BRCategoryData data) { this->name = data.name; emit this->metadataChanged(); + + if(this->currentRound != data.currentRound) { + this->currentRound = data.currentRound; + emit this->currentRoundChanged(); + } + + if(this->rounds != data.rounds) { + this->rounds.clear(); + this->rounds = data.rounds; + + for(BRRound* round : this->rounds) + round->category = this; + + emit this->roundsChanged(); + } } BRWidget::BRWidgetStatusCode BRCategory::load() { - // TODO + + BRCategoryData newData { + this, + this->name, + this->currentRound, + this->rounds + }; + + qDebug() << "LOADING CATEGORY"; + BRWidget::BRWidgetStatusCode statusCode = this->getProvider()->getWidgetData(&newData); + + if(statusCode != BRWidget::Success) + return statusCode; + + this->setData(newData); + + return BRWidget::Success; } diff --git a/sources/brcompetition.cpp b/sources/brcompetition.cpp index 18d7999..4340689 100644 --- a/sources/brcompetition.cpp +++ b/sources/brcompetition.cpp @@ -1,7 +1,9 @@ #include "headers/brcompetition.h" #include "headers/brleague.h" +#include "headers/brprovider.h" -BRCompetition::BRCompetition(BRProvider* provider, BRWidget::BRFederation federation, int id, BRCompetitionData initialData) : BRWidget(provider, federation), id(id) { +BRCompetition::BRCompetition(BRProvider* provider, BRWidget::BRFederation federation, int id, BRCompetitionData initialData) : BRWidget(provider, federation, id) { + this->currentCategory = nullptr; this->setData(initialData); } @@ -52,8 +54,50 @@ QList BRCompetition::getCategoriesQML() { return this->listToQmlList(this->categories); } -BRWidget::BRWidgetStatusCode BRCompetition::load() { +BRCategory* BRCompetition::getCurrentCategory() const { + return this->currentCategory; +} + +void BRCompetition::setCurrentCategory(BRCategory* category) { + if(!this->categories.contains(category)) + return; + + // try to find the same round in the new category + if(this->currentCategory != nullptr && this->currentCategory->getCurrentRound() != nullptr) { + QString currentRoundName = this->currentCategory->getCurrentRound()->getName(); + + // search round name in new category + for(BRRound* round : category->getRounds()) + if(round->getName() == currentRoundName) + category->setCurrentRound(round); + } + + this->currentCategory = category; + emit this->currentCategoryChanged(); +} + +BRWidget::BRWidgetStatusCode BRCompetition::load() { + BRCompetitionData newData { + this, + this->name, + this->discipline, + this->startDate, + this->endDate, + this->eventWebsiteUrl, + this->infosheetUrls, + + this->categories + }; + + BRWidget::BRWidgetStatusCode statusCode = this->getProvider()->getWidgetData(&newData); + + if(statusCode != BRWidget::Success) + return statusCode; + + this->setData(newData); + + return BRWidget::Success; } void BRCompetition::setData(BRCompetition::BRCompetitionData data) { @@ -68,6 +112,8 @@ void BRCompetition::setData(BRCompetition::BRCompetitionData data) { if(this->categories != data.categories) { this->categories.clear(); this->categories = data.categories; + for(BRCategory* category : this->categories) + category->competition = this; emit this->categoriesChanged(); } diff --git a/sources/brcup.cpp b/sources/brcup.cpp index d321cae..4a0422d 100644 --- a/sources/brcup.cpp +++ b/sources/brcup.cpp @@ -1,6 +1,6 @@ #include "../headers/brcup.h" -BRCup::BRCup(BRProvider* provider, BRWidget::BRFederation federation, int id, BRCupData initialData) : BRWidget(provider, federation), id(id) +BRCup::BRCup(BRProvider* provider, BRWidget::BRFederation federation, int id, BRCupData initialData) : BRWidget(provider, federation, id) { this->categories = {}; this->setData(initialData); diff --git a/sources/brleague.cpp b/sources/brleague.cpp index da8f29b..7a46e0c 100644 --- a/sources/brleague.cpp +++ b/sources/brleague.cpp @@ -1,17 +1,13 @@ #include "headers/brleague.h" #include "headers/brprovider.h" -BRLeague::BRLeague(BRProvider* provider, BRWidget::BRFederation federation, int id, BRLeagueData initialData) : BRWidget(provider, federation), id(id) +BRLeague::BRLeague(BRProvider* provider, BRWidget::BRFederation federation, int id, BRLeagueData initialData) : BRWidget(provider, federation, id) { this->competitions = {}; this->competitions = {}; this->setData(initialData); } -int BRLeague::getId() const { - return this->id; -} - QString BRLeague::getName() { return this->name; } @@ -75,8 +71,6 @@ BRWidget::BRWidgetStatusCode BRLeague::load() { if(statusCode != BRWidget::Success) return statusCode; - qDebug() << "new Data: " << newData.competitions; - this->setData(newData); return statusCode; diff --git a/sources/brprovider.cpp b/sources/brprovider.cpp index ade7aa3..b85db6b 100644 --- a/sources/brprovider.cpp +++ b/sources/brprovider.cpp @@ -30,6 +30,20 @@ BRCategory* BRProvider::getCategory(BRWidget::BRFederation federation, int id, B return new BRCategory(this, federation, id, initialData); } + +BRAthlete* BRProvider::getAthlete(BRWidget::BRFederation federation, int id, BRAthlete::BRAthleteData initialData) { + return new BRAthlete(this, federation, id, initialData); +} + +BRRound* BRProvider::getRound(BRWidget::BRFederation federation, int id, BRRound::BRRoundData initialData) { + return new BRRound(this, federation, id, initialData); +} + + +BRResult* BRProvider::getResult(BRWidget::BRFederation federation, int id, BRResult::BRResultData initialData) { + return new BRResult(this, federation, id, initialData); +} + QVariantMap BRProvider::serverRequest(QUrl serviceUrl, QList additionalHeaders, QUrlQuery postData) { qDebug() << "requesting: " << serviceUrl; diff --git a/sources/brproviderdr.cpp b/sources/brproviderdr.cpp index 2cc51f6..470e901 100644 --- a/sources/brproviderdr.cpp +++ b/sources/brproviderdr.cpp @@ -202,10 +202,21 @@ BRLeague::BRLeagueData BRProviderDr::parseLeagueData(QVariantMap leaguePropertie BRWidget::BRWidgetStatusCode BRProviderDr::getWidgetData(BRCompetition::BRCompetitionData* competitionData) { + if(competitionData->competition->getCurrentCategory() == nullptr) + return BRWidget::NotImplementedError; + return competitionData->competition->getCurrentCategory()->load(); } BRCompetition::BRCompetitionData BRProviderDr::parseCompetitionData(QVariantMap rawData, BRWidget::BRFederation federation) { + BRCompetition::BRCompetitionData data; + + this->parseCompetitionData(&data, rawData, federation); + + return data; +} + +void BRProviderDr::parseCompetitionData(BRCompetition::BRCompetitionData* competitionData, QVariantMap rawData, BRWidget::BRFederation federation) { QMap disciplineTranslations = { {"boulder", BRCompetition::Boulder}, @@ -213,42 +224,63 @@ BRCompetition::BRCompetitionData BRProviderDr::parseCompetitionData(QVariantMap {"speed", BRCompetition::Speed} }; - BRCompetition::BRCompetitionData data; - - data.name = rawData["name"].toString(); + if(rawData.contains("name")) + competitionData->name = rawData["name"].toString(); + else if(rawData.contains("comp_name")) + competitionData->name = rawData["comp_name"].toString(); if(disciplineTranslations.contains(rawData["discipline"].toString())) - data.discipline = disciplineTranslations[rawData["discipline"].toString()]; + competitionData->discipline = disciplineTranslations[rawData["discipline"].toString()]; - data.startDate = QDate::fromString(rawData["date"].toString(), "yyyy-MM-dd"); - data.endDate = QDate::fromString(rawData["date_end"].toString(), "yyyy-MM-dd"); + if(rawData.contains("date")) + competitionData->startDate = QDate::fromString(rawData["date"].toString(), "yyyy-MM-dd"); + if(rawData.contains("date_end")) + competitionData->endDate = QDate::fromString(rawData["date_end"].toString(), "yyyy-MM-dd"); - data.eventWebsiteUrl = rawData["homepage"].toString(); + if(rawData.contains("hompage")) + competitionData->eventWebsiteUrl = rawData["homepage"].toString(); + // load infosheet URLs for(int i = 0; i < 2; i++) { QString infosheetName = QStringList({"info", "info2"})[i]; if(rawData.contains(infosheetName)) { QString url = rawData[infosheetName].toString(); if(federation == BRWidget::DAV) - url = "http://ranking.alpenverein.de/" + QString::number(data.startDate.year()) + "/GER/" + rawData["rkey"].toString() + ".pdf"; + url = "http://ranking.alpenverein.de/" + QString::number(competitionData->startDate.year()) + "/GER/" + rawData["rkey"].toString() + ".pdf"; - data.infosheetUrls.append(url); + competitionData->infosheetUrls.append(url); } } - QVariantList categoriesList = rawData["cats"].toList(); - for(QVariant categoryVar : categoriesList) { - QVariantMap categoryMap = categoryVar.toMap(); - BRCategory* category = this->getCategory(federation, rawData["GrpId"].toInt(), this->parseCategoryData(categoryMap)); - data.categories.append(category); + // load categories + QVariantList categoriesList; + if(rawData.contains("cats")) { + // we are loading calendar data! + QVariantList categoriesList = rawData["cats"].toList(); + competitionData->categories.clear(); + for(QVariant categoryVar : categoriesList) { + BRCategory::BRCategoryData categoryData; + categoryData.name = rawData["name"].toString(); + BRCategory* category = this->getCategory(federation, rawData["GrpId"].toInt(), categoryData); + competitionData->categories.append(category); + } + } + else { + // we are loading result data! + // TODO: clean up!! + if(competitionData->competition->getCurrentCategory()->getId() != rawData["GrpId"].toInt()) + // if the current category does not match the loaded category, there is some error and we cannot proceed! + return; + + // load the category! + } - // TODO load results - return data; } + BRCup::BRCupData BRProviderDr::parseCupData(QVariantList categoriesList, QVariantMap rawData, BRWidget::BRFederation federation) { BRCup::BRCupData data; @@ -262,7 +294,9 @@ BRCup::BRCupData BRProviderDr::parseCupData(QVariantList categoriesList, QVarian QVariantMap categoryMap = categoryVar.toMap(); if(categoryMap["rkey"].toString() == categoryName.toString()) { - BRCategory* category = this->getCategory(federation, rawData["GrpId"].toInt(), this->parseCategoryData(categoryMap)); + BRCategory::BRCategoryData categoryData; + categoryData.name = rawData["name"].toString(); + BRCategory* category = this->getCategory(federation, rawData["GrpId"].toInt(), categoryData); data.categories.append(category); break; } @@ -272,10 +306,40 @@ BRCup::BRCupData BRProviderDr::parseCupData(QVariantList categoriesList, QVarian return data; } +BRWidget::BRWidgetStatusCode BRProviderDr::getWidgetData(BRCategory::BRCategoryData* categoryData) { + // load category data + QString competitionId = QString::number(categoryData->category->getCompetition()->getId()); + QString categoryId = QString::number(categoryData->category->getId()); + QString requestUrl = "https://www.digitalrock.de/egroupware/ranking/json.php?comp=" + competitionId + "&cat=" + categoryId; + QVariantMap ret = this->serverRequest(QUrl(requestUrl)); + + if(ret["status"] != 200){ + // request was a failure + return BRWidget::BRWidgetStatusCode(ret["status"].toInt()); + } + + QVariantMap data = QJsonDocument::fromJson(ret["text"].toString().toUtf8()).toVariant().toMap(); + + this->parseCategoryData(categoryData, data); + + return BRWidget::Success; +} + BRCategory::BRCategoryData BRProviderDr::parseCategoryData(QVariantMap rawData) { - // TODO: status - // TODO: sex BRCategory::BRCategoryData data; - data.name = rawData["name"].toString(); + this->parseCategoryData(&data, rawData); return data; } + +void BRProviderDr::parseCategoryData(BRCategory::BRCategoryData* categoryData, QVariantMap rawData) { + // TODO: status + // TODO: sex + // TODO: load routes + // TODO: athletes + //categoryData->name = rawData["name"].toString(); +} + + +BRWidget::BRWidgetStatusCode BRProviderDr::getWidgetData(BRRound::BRRoundData* roundData) { + +} diff --git a/sources/brprovidervl.cpp b/sources/brprovidervl.cpp index e836d75..885741e 100644 --- a/sources/brprovidervl.cpp +++ b/sources/brprovidervl.cpp @@ -112,9 +112,9 @@ void BRProviderVl::parseLeagueData(BRLeague::BRLeagueData* data, QVariantMap raw for(QVariant competitionVar : competitionsVar) { QVariantMap competitionMap = competitionVar.toMap(); + qDebug() << "- Adding competition: " << competitionMap["event"].toString(); BRCompetition* competition = this->getCompetition(federation, competitionVar.toMap()["event_id"].toInt(), this->parseCompetitionData(competitionMap, federation)); data->competitions.append(competition); - qDebug() << "- Adding competition: " << competition->getName(); } // parse cups @@ -129,8 +129,12 @@ void BRProviderVl::parseLeagueData(BRLeague::BRLeagueData* data, QVariantMap raw BRWidget::BRWidgetStatusCode BRProviderVl::getWidgetData(BRCompetition::BRCompetitionData* competitionData) { + qDebug() << "LOADING COMP 4"; + if(competitionData->competition->getCurrentCategory() == nullptr) + return BRWidget::NotImplementedError; - + qDebug() << "LOADING COMP 5"; + return competitionData->competition->getCurrentCategory()->load(); } BRCompetition::BRCompetitionData BRProviderVl::parseCompetitionData(QVariantMap rawData, BRWidget::BRFederation federation) { @@ -161,7 +165,8 @@ BRCompetition::BRCompetitionData BRProviderVl::parseCompetitionData(QVariantMap QVariantList categoriesList = rawData["d_cats"].toList(); for(QVariant categoryVar : categoriesList) { QVariantMap categoryMap = categoryVar.toMap(); - BRCategory* category = this->getCategory(federation, rawData["id"].toInt(), this->parseCategoryData(categoryMap)); + qDebug() << "-- Adding category: " << categoryMap["name"].toString(); + BRCategory* category = this->getCategory(federation, categoryMap["id"].toInt(), this->parseCategoryData(categoryMap)); data.categories.append(category); } @@ -190,10 +195,147 @@ BRCup::BRCupData BRProviderVl::parseCupData(QVariantMap rawData) { return data; } + +BRWidget::BRWidgetStatusCode BRProviderVl::getWidgetData(BRCategory::BRCategoryData* categoryData) { + return categoryData->category->getCurrentRound()->load(); +} + BRCategory::BRCategoryData BRProviderVl::parseCategoryData(QVariantMap rawData) { // TODO: status // TODO: sex BRCategory::BRCategoryData data; + data.name = rawData["name"].toString(); + data.currentRound = nullptr; + + // load rounds + QVariantList roundsList = rawData["category_rounds"].toList(); + // insert general result + roundsList.insert(0, QVariantMap({{"name", "General result"}, {"category_round_id", -1}})); + for(QVariant roundVar : roundsList) { + QVariantMap roundMap = roundVar.toMap(); + + BRRound::BRRoundData roundData; + roundData.name = roundMap["name"].toString(); + qDebug() << "--- Adding round: " << roundData.name; + BRRound* round = this->getRound(BRWidget::IFSC, roundMap["category_round_id"].toInt(), roundData); + data.rounds.append(round); + } + + data.currentRound = data.rounds[0]; + return data; } + +void BRProviderVl::parseCategoryData(BRCategory::BRCategoryData* categoryData, QVariantMap rawData) { + + // no need to load rounds, they were already loaded when the whole competition was loaded! + + qDebug() << "INITIALLY PARSING CATEGORY"; + // load athletes + QVariantList atheletList = rawData["ranking"].toList(); + QMap tmpAthletes; + + // load general result + BRRound::BRRoundData roundData; + + // TODO status + roundData.name = tr("General result"); + + // parse Ranking + QVariantList resultList = rawData["ranking"].toList(); + for(QVariant resultVar : resultList) { + QVariantMap resultMap = resultVar.toMap(); + + int athleteId = resultMap["athlete_id"].toInt(); + if(!tmpAthletes.contains(athleteId)) + continue; + + qDebug() << "Adding result: rank: " << resultMap["rank"]; + BRResult::BRResultData resultData; + resultData.rank = resultMap["rank"].toInt(); + resultData.athlete = tmpAthletes[athleteId]; + BRResult* result = this->getResult(BRWidget::IFSC, -1, resultData); + roundData.results.append(result); + } + + BRRound* generalResultRound = this->getRound(BRWidget::IFSC, -1, roundData); + qDebug() << "General result round: " << generalResultRound; + categoryData->rounds.insert(0, generalResultRound); + categoryData->currentRound = generalResultRound; +} + + + +BRWidget::BRWidgetStatusCode BRProviderVl::getWidgetData(BRRound::BRRoundData* roundData) { + + // load round data + QString competitionId = QString::number(roundData->round->getCategory()->getCompetition()->getId()); + QString categoryId = QString::number(roundData->round->getCategory()->getId()); + QString roundId = QString::number(roundData->round->getId()); + + QString requestUrl; + + if(roundId == "-1") { + requestUrl = "https://ifsc.results.info/api/v1/events/" + competitionId + "/result/" + categoryId; + } + else { + requestUrl = "https://ifsc.results.info/api/v1/category_rounds/" + roundId + "/results"; + } + + QVariantMap ret = this->serverRequest(QUrl(requestUrl), {{"x-auth-token", "cc7375f680648e7e6171e035e70351eb"}}); + + if(ret["status"] != 200){ + // request was a failure + return BRWidget::BRWidgetStatusCode(ret["status"].toInt()); + } + + QVariantMap data = QJsonDocument::fromJson(ret["text"].toString().toUtf8()).toVariant().toMap(); + + this->parseRoundData(roundData, data); + + return BRWidget::Success; +} + +BRRound::BRRoundData BRProviderVl::parseRoundData(QVariantMap rawData) { + BRRound::BRRoundData data; + this->parseRoundData(&data, rawData); + return data; +} + +void BRProviderVl::parseRoundData(BRRound::BRRoundData* roundData, QVariantMap rawData) { + + // TODO status + + // clear up + for(BRResult* result : roundData->results) + result->deleteLater(); + + roundData->results.clear(); + + // parse RankingQVariantList resultList = rawData["ranking"].toList(); + QVariantList resultList = rawData["ranking"].toList(); + for(QVariant resultVar : resultList) { + QVariantMap resultMap = resultVar.toMap(); + + // load athlete + BRAthlete::BRAthleteData athleteData; + // TODO: start number + athleteData.firstName = resultMap["firstname"].toString(); + athleteData.lastName = resultMap["lastname"].toString(); + athleteData.federation = resultMap["country"].toString(); + athleteData.nation = resultMap["country"].toString(); + qDebug() << "--- Adding athlete: " << athleteData.firstName << " " << athleteData.lastName; + + BRAthlete* athlete = this->getAthlete(BRWidget::IFSC, resultMap["athlete_id"].toInt(), athleteData); + + // load result + qDebug() << "Adding result: rank: " << resultMap["rank"]; + BRResult::BRResultData resultData; + resultData.rank = resultMap["rank"].toInt(); + resultData.athlete = athlete; + BRResult* result = this->getResult(BRWidget::IFSC, -1, resultData); + roundData->results.append(result); + } + +} diff --git a/sources/brresult.cpp b/sources/brresult.cpp new file mode 100644 index 0000000..986e84e --- /dev/null +++ b/sources/brresult.cpp @@ -0,0 +1,27 @@ +#include "headers/brresult.h" + +BRResult::BRResult(BRProvider* provider, BRWidget::BRFederation federation, int id, BRResultData initialData) : BRWidget(provider, federation, id) +{ + this->setData(initialData); +} + + +int BRResult::getRank() const { + return this->rank; +} + +BRAthlete* BRResult::getAthlete() const { + return this->athlete; +} + + +void BRResult::setData(BRResultData data) { + this->rank = data.rank; + this->athlete = data.athlete; + emit this->metadataChanged(); +} + + +BRWidget::BRWidgetStatusCode BRResult::load() { + return BRWidget::OpeationNotSupportedError; +} diff --git a/sources/brround.cpp b/sources/brround.cpp new file mode 100644 index 0000000..1d0eab4 --- /dev/null +++ b/sources/brround.cpp @@ -0,0 +1,47 @@ +#include "../headers/brround.h" +#include "headers/brprovider.h" + +BRRound::BRRound(BRProvider* provider, BRWidget::BRFederation federation, int id, BRRoundData initialData) : BRWidget(provider, federation, id) +{ + this->setData(initialData); +} + +BRCategory* BRRound::getCategory() const { + return this->category; +} + +QString BRRound::getName() { + return this->name; +} + +QList BRRound::getResultsQML() { + return this->listToQmlList(this->results); +} + +BRWidget::BRWidgetStatusCode BRRound::load() { + BRRoundData newData { + this, + this->name, + this->results + }; + + BRWidget::BRWidgetStatusCode statusCode = this->getProvider()->getWidgetData(&newData); + + if(statusCode != BRWidget::Success) + return statusCode; + + this->setData(newData); + + return BRWidget::Success; +} + +void BRRound::setData(BRRoundData data) { + this->name = data.name; + emit this->metadataChanged(); + + if(this->results != data.results) { + this->results.clear(); + this->results = data.results; + emit this->resultsChanged(); + } +} diff --git a/sources/brseason.cpp b/sources/brseason.cpp index 4354c6d..b6bebfc 100644 --- a/sources/brseason.cpp +++ b/sources/brseason.cpp @@ -3,7 +3,7 @@ using namespace std; -BRSeason::BRSeason(BRProvider* provider, BRWidget::BRFederation federation, int id, BRSeasonData initialData) : BRWidget(provider, federation), id(id) +BRSeason::BRSeason(BRProvider* provider, BRWidget::BRFederation federation, int id, BRSeasonData initialData) : BRWidget(provider, federation, id) { connect(this, &BRSeason::leaguesChanged, this, &BRSeason::competitionsChanged); connect(this, &BRSeason::leaguesChanged, this, &BRSeason::cupsChanged); @@ -35,8 +35,6 @@ QList BRSeason::getCompetitionsQML() { std::sort(allCompetitions.begin(), allCompetitions.end(), BRCompetition::lessThan); - qDebug() << "competitions: " << allCompetitions; - return this->listToQmlList(allCompetitions); } diff --git a/sources/brwidget.cpp b/sources/brwidget.cpp index 0b4cc61..758545f 100644 --- a/sources/brwidget.cpp +++ b/sources/brwidget.cpp @@ -2,7 +2,7 @@ #include "headers/brprovider.h" -BRWidget::BRWidget(BRProvider* provider, BRFederation federation) : QObject(provider), provider(provider), federation(federation) +BRWidget::BRWidget(BRProvider* provider, BRFederation federation, int id) : QObject(provider), provider(provider), federation(federation), id(id) { } @@ -13,3 +13,7 @@ BRWidget::BRFederation BRWidget::getFederation() const { BRProvider* BRWidget::getProvider() { return this->provider; } + +int BRWidget::getId() const { + return this->id; +} diff --git a/sources/main.cpp b/sources/main.cpp index 351df81..cfe1455 100644 --- a/sources/main.cpp +++ b/sources/main.cpp @@ -49,6 +49,9 @@ int main(int argc, char *argv[]) qmlRegisterUncreatableType("de.itsblue.blueRock", 2, 0, "BRCompetition", "BRCompetition is not creatable"); qmlRegisterUncreatableType("de.itsblue.blueRock", 2, 0, "BRCup", "BRCup is not creatable"); qmlRegisterUncreatableType("de.itsblue.blueRock", 2, 0, "BRCategory", "BRCategory is not creatable"); + qmlRegisterUncreatableType("de.itsblue.blueRock", 2, 0, "BRRound", "BRRound is not creatable"); + qmlRegisterUncreatableType("de.itsblue.blueRock", 2, 0, "BRAthlete", "BRAthlete is not creatable"); + qmlRegisterUncreatableType("de.itsblue.blueRock", 2, 0, "BRResult", "BRResult is not creatable"); qmlRegisterUncreatableType("de.itsblue.blueRock", 2, 0, "BRWidget", "BRWidget is not creatable"); qRegisterMetaType("BRWidget::BRFederation"); qRegisterMetaType("BRWidget::BRWidgetStatusCode");