diff --git a/NewStructure.md b/NewStructure.md new file mode 100644 index 0000000..6991f6f --- /dev/null +++ b/NewStructure.md @@ -0,0 +1,27 @@ +# Layer 1: +- Server Conector -> gets data as QVariant +- One class: BRServerConnector +- URL has to be given as string + +# Layer 2: +- Translation layer +- classes: + - BRController + - BRProvider + - BRProvderDr + + +# Layer 3 +- Consisten data layer +- classes: + - BRWidget -> gets a provider, has an int load() function + - BRCalendar + - BRCompetition + - BRCategory + - BRResult + - BRBoulderResult + - BRLeadResult + - BRSpeedResult +# layer 4 +- QML +- Will call functions from Layer 2 and get Objects from Layer 3 diff --git a/blueROCK.pro b/blueROCK.pro index e69c9c3..df09f3f 100644 --- a/blueROCK.pro +++ b/blueROCK.pro @@ -26,8 +26,29 @@ DEFINES += QT_DEPRECATED_WARNINGS SOURCES += \ sources/appsettings.cpp \ - sources/main.cpp \ - sources/serverconn.cpp + sources/brcalendar.cpp \ + sources/brcategory.cpp \ + sources/brcompetition.cpp \ + sources/brcontroller.cpp \ + sources/brcup.cpp \ + sources/brprovider.cpp \ + sources/brproviderdr.cpp \ + sources/brserverconnector.cpp \ + sources/brwidget.cpp \ + sources/main.cpp + + +HEADERS += \ + headers/appsettings.h \ + headers/brcalendar.h \ + headers/brcategory.h \ + headers/brcompetition.h \ + headers/brcontroller.h \ + headers/brcup.h \ + headers/brprovider.h \ + headers/brproviderdr.h \ + headers/brserverconnector.h \ + headers/brwidget.h RESOURCES += resources/qml/qml.qrc \ resources/shared/shared.qrc \ @@ -46,10 +67,6 @@ qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target -HEADERS += \ - headers/appsettings.h \ - headers/serverconn.h - DISTFILES += \ CHANGELOG.md \ android-sources/AndroidManifest.xml \ diff --git a/headers/brcalendar.h b/headers/brcalendar.h new file mode 100644 index 0000000..9880dd5 --- /dev/null +++ b/headers/brcalendar.h @@ -0,0 +1,40 @@ +#ifndef BRCALENDAR_H +#define BRCALENDAR_H + +#include + +#include "brcompetition.h" +#include "brwidget.h" +#include "brcategory.h" +#include "brcup.h" + +class BRProvider; + +class BRCalendar : public BRWidget +{ + Q_OBJECT +public: + friend class BRProvider; + friend class BRProviderDr; + + BRWidget::BRWidgetStatusCode load() override; + + Q_INVOKABLE int getYear(); + int getLeague(); + QList getCompetitions(); + QList getCompetitionsQML(); + +private: + explicit BRCalendar(BRProvider* provider, BRFederation federation, int year, int league); + + int year; + int league; + QList competitions; + QList categories; + QList cups; + +signals: + +}; + +#endif // BRCALENDAR_H diff --git a/headers/brcategory.h b/headers/brcategory.h new file mode 100644 index 0000000..4b76732 --- /dev/null +++ b/headers/brcategory.h @@ -0,0 +1,16 @@ +#ifndef BRCATEGORY_H +#define BRCATEGORY_H + +#include + +class BRCategory : public QObject +{ + Q_OBJECT +public: + explicit BRCategory(QObject *parent = nullptr); + +signals: + +}; + +#endif // BRCATEGORY_H diff --git a/headers/brcompetition.h b/headers/brcompetition.h new file mode 100644 index 0000000..ffb9b34 --- /dev/null +++ b/headers/brcompetition.h @@ -0,0 +1,40 @@ +#ifndef BRCOMPETITION_H +#define BRCOMPETITION_H + +#include +#include +#include "brwidget.h" +#include "brcategory.h" + +class BRCompetition : public BRWidget +{ + Q_OBJECT +public: + friend class BRProvider; + friend class BRProviderDr; + + Q_INVOKABLE QString getName(); + + BRWidget::BRWidgetStatusCode load() override; +private: + explicit BRCompetition(BRProvider* provider, BRWidget::BRFederation federation, int id); + + enum BRDiscipline { + Boulder, + Lead, + Speed + }; + + int id; + QString name; + BRDiscipline discipline; + QDate startDate; + QDate endDate; + + QList categories; + +signals: + +}; + +#endif // BRCOMPETITION_H diff --git a/headers/brcontroller.h b/headers/brcontroller.h new file mode 100644 index 0000000..2e0681e --- /dev/null +++ b/headers/brcontroller.h @@ -0,0 +1,26 @@ +#ifndef BRCONTROLLER_H +#define BRCONTROLLER_H + +#include + +#include "brproviderdr.h" +#include "brwidget.h" + +class BRCalendar; + +class BRController : public QObject +{ + Q_OBJECT +public: + explicit BRController(QObject *parent = nullptr); + + Q_INVOKABLE BRCalendar* getCalendar(BRWidget::BRFederation federation, int year, int league = 0); + +private: + BRProvider* providerDr; + +signals: + +}; + +#endif // BRCONTROLLER_H diff --git a/headers/brcup.h b/headers/brcup.h new file mode 100644 index 0000000..ccd9632 --- /dev/null +++ b/headers/brcup.h @@ -0,0 +1,14 @@ +#ifndef BRCUP_H +#define BRCUP_H + +#include +#include "brwidget.h" + +class BRCup : public BRWidget +{ + Q_OBJECT +public: + BRCup(BRProvider* provider, BRWidget::BRFederation federation); +}; + +#endif // BRCUP_H diff --git a/headers/brprovider.h b/headers/brprovider.h new file mode 100644 index 0000000..9bf7a5c --- /dev/null +++ b/headers/brprovider.h @@ -0,0 +1,34 @@ +#ifndef BRPROVIDER_H +#define BRPROVIDER_H + +#include +#include +#include +#include +#include + +#include "brwidget.h" +#include "brcalendar.h" +#include "brcompetition.h" +#include "brcategory.h" +#include "brcup.h" + +class BRProvider : public QObject +{ + Q_OBJECT +public: + explicit BRProvider(QObject *parent = nullptr); + + friend class BRCalendar; + + BRCalendar* getCalendar(BRWidget::BRFederation federation, int year, int league); +protected: + QVariantMap serverRequest(QUrl serviceUrl, QUrlQuery pdata = QUrlQuery()); + + virtual BRWidget::BRWidgetStatusCode loadCalendarData(BRCalendar* calendar) = 0; + +signals: + +}; + +#endif // BRCONTROLLER_H diff --git a/headers/brproviderdr.h b/headers/brproviderdr.h new file mode 100644 index 0000000..2eb8bdc --- /dev/null +++ b/headers/brproviderdr.h @@ -0,0 +1,25 @@ +#ifndef BRPROVIDERDR_H +#define BRPROVIDERDR_H + +#include + +#include "brprovider.h" +#include "brcalendar.h" +#include "brcompetition.h" + +class BRProviderDr : public BRProvider +{ + Q_OBJECT +public: + explicit BRProviderDr(QObject *parent = nullptr); + +protected: + BRWidget::BRWidgetStatusCode loadCalendarData(BRCalendar* calendar); + + BRWidget::BRWidgetStatusCode loadCompetitionData(BRCompetition* competition, QVariantMap data); + +private: + +}; + +#endif // BRPROVIDERDR_H diff --git a/headers/brserverconnector.h b/headers/brserverconnector.h index 2630af3..82b2c37 100644 --- a/headers/brserverconnector.h +++ b/headers/brserverconnector.h @@ -25,11 +25,11 @@ #include #include -class ServerConn : public QObject +class BRServerConnector : public QObject { Q_OBJECT public: - explicit ServerConn(QObject *parent = nullptr); + explicit BRServerConnector(QObject *parent = nullptr); private: QVariantMap senddata(QUrl serviceUrl, QUrlQuery pdata = QUrlQuery()); diff --git a/headers/brwidget.h b/headers/brwidget.h new file mode 100644 index 0000000..81ae8aa --- /dev/null +++ b/headers/brwidget.h @@ -0,0 +1,42 @@ +#ifndef BRWIDGET_H +#define BRWIDGET_H + +#include + +class BRProvider; + +class BRWidget : public QObject +{ + Q_OBJECT +public: + + enum BRFederation { + IFSC, + DAV, + SAC + }; + Q_ENUM(BRFederation) + + enum BRWidgetStatusCode { + Success = 200, + NoProviderError = 510 + }; + Q_ENUM(BRWidgetStatusCode) + + explicit BRWidget(BRProvider* provider, BRFederation federation); + + Q_INVOKABLE virtual BRWidget::BRWidgetStatusCode load() = 0; + BRFederation getFederation(); + +protected: + BRProvider* getProvider(); + +private: + BRProvider* provider; + BRFederation federation; + +signals: + +}; + +#endif // BRWIDGET_H diff --git a/resources/qml/Pages/BRWidgetPage.qml b/resources/qml/Pages/BRWidgetPage.qml new file mode 100644 index 0000000..e69293a --- /dev/null +++ b/resources/qml/Pages/BRWidgetPage.qml @@ -0,0 +1,388 @@ +/* + 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.4 +//import QtGraphicalEffects 1.0 +//import QtQuick.Templates 2.04 as T +//import QtQuick.Controls.impl 2.04 +import QtQuick.Controls.Material 2.3 +import de.itsblue.blueRock 2.0 + +import "../Components" + +Page { + id: root + + property BRWidget data + property Component headerComponent + + property string subTitle + property bool titleIsPageTitle: true + + property int status: -1 + property bool ready: false + + + Component.onCompleted: { + data.load() + } + + function loadData(params) { + // params is an object and can contain: { + // comp: competitionId, + // person: personId, + // cat: categoryId, + // nation: nationString ('', 'GER', 'SUI') + // route: (int) round + // type: ('','starters', 'nat_team_ranking', 'sektionenwertung', 'regionalzentren'), + //} + + var ret = serverConn.getWidgetData(params) + + root.status = ret["status"] + + if(ret["status"] === 200){ + root.widgetData = ret["data"] + root.widgetType = checkWidgetType(params, root.widgetData) + if(widgetLd.load()){ + root.ready = true + } + else { + //root.status = 901 + root.ready = false + } + } + else if(ret["status"] === 404 && [WidgetPage.WidgetType.Registration, WidgetPage.WidgetType.Startlist, WidgetPage.WidgetType.Result].includes(root.widgetType) && root.params["route"] !== "") { + // if we get a 404 and have startlist, results or registration, the route was not found -> remove route and try again + root.params["route"] = "" + loadData(root.params) + return + } + else { + root.ready = false + } + + app.errorCode = root.status + + } + + function updateData(params, openLoadingDl) { + if(openLoadingDl) + loadingDl.open() + + // update all the given values + Object.assign(root.params, params) + + loadData(root.params) + + console.log("ready: " + root.ready + ": " + root.status) + + if(openLoadingDl) + loadingDl.close() + + } + + function checkWidgetType(params, widgetData){ + var widgetType + + function hasParam(object, key, value){ + if(object[key] !== undefined){ + if(value !== undefined){ + return object[key] === value + } + return true + } + return false + } + + // check the type of the requested widget + + if(hasParam(params, 'person')){ + // person profile + widgetType = WidgetPage.WidgetType.Profile + } + + else if(hasParam(params, 'nation')){ + // competition calendar + widgetType = WidgetPage.WidgetType.Competitions + } + + else if(hasParam(params, 'comp') && hasParam(params, 'type', 'starters')){ + // registration + widgetType = WidgetPage.WidgetType.Registration + } + else if(hasParam(params, 'type', 'startlist') || (widgetData.participants !== undefined && widgetData.participants[0] && !widgetData.participants[0].result_rank && widgetData.discipline !== 'ranking')){ + // startlist + widgetType = WidgetPage.WidgetType.Startlist + } + else if(hasParam(params, 'comp') && hasParam(params, 'cat')){ + // results + widgetType = WidgetPage.WidgetType.Result + } + + else if( hasParam(params, 'cat') && hasParam(params, 'cup') && !hasParam(params, 'comp')){ + // ranking data + widgetType = WidgetPage.WidgetType.Ranking + } + else if(hasParam(params, 'type', 'nat_team_ranking') || hasParam(params, 'type', 'sektionenwertung') || hasParam(params, 'type', 'regionalzentren')){ + // aggregated + widgetType = WidgetPage.WidgetType.Aggregated + } + + return widgetType + } + + Loader { + id: widgetLd + + property alias selector: selectorPu + property var updateData: root.updateData + property alias params: root.params + property alias currentWidgetData: root.widgetData + property bool isTopElement: mainStack.currentItem === root + + property var oldWidgetType: NaN + + anchors.fill: parent + + source: "" + + function load() { + if(root.widgetType !== oldWidgetType){ + oldWidgetType = root.widgetType + var calComp = Qt.createComponent(getFile(root.widgetType))//.createObject(null, {widgetData: root.widgetData, parent: widgetLd}) + + widgetLd.sourceComponent = calComp + //widgetLd.item.widgetData = root.widgetData + } + root.status = widgetLd.item.status + + if(widgetLd.item.ready){ + return true + } + else { + root.status = widgetLd.item.status === undefined ? 900:widgetLd.item.status + delete(widgetLd.sourceComponent) + return false + } + + + // + } + + function getFile(widgetType) { + var path = "qrc:/Widgets/" + switch(widgetType){ + case WidgetPage.WidgetType.Competitions: + path += "CalendarWidget" + break + case WidgetPage.WidgetType.Profile: + path += "ProfileWidget" + break + case WidgetPage.WidgetType.Registration: + path += "RegistrationWidget" + break + case WidgetPage.WidgetType.Startlist: + path += "StartlistWidget" + break + case WidgetPage.WidgetType.Result: + path += "ResultWidget" + break + case WidgetPage.WidgetType.Ranking: + path += "RankingWidget" + break + + } + + path += ".qml" + return path + } + + function getItemProperty(key, defaultValue) { + if(widgetLd.item !== null && widgetLd.item.hasOwnProperty(key)) { + return key + } + else { + return defaultValue + } + } + + } + + Dialog { + id: selectorPu + + property var dataObj + property string subTitle: "" + + signal selectionFinished(int index, var data) + + x: 0 //root.width / 2 - width / 2 + y: root.height - selectorPu.height * 0.7//root.height - height //root.height / 2 - height / 2 + + opacity: 0 + + width: root.width + height: selectorLv.implicitHeight + + modal: true + focus: true + + title: "" + + header: Column { + id: selectorPuHeaderCol + + width: parent.width + + Label { + id: headerLa + + visible: selectorPu.title + + width: parent.width + + elide: "ElideRight" + padding: 24 + bottomPadding: 0 + font.bold: true + font.pixelSize: 16 + background: Rectangle { + radius: 2 + color: selectorPu.Material.dialogColor + clip: true + } + + text: selectorPu.title + + onLinkActivated: { + Qt.openUrlExternally(link) + } + + } + Label { + id: headerSubLa + + visible: selectorPu.subTitle + + width: parent.width + + elide: "ElideRight" + padding: 24 + topPadding: 5 + bottomPadding: 0 + font.bold: true + font.pixelSize: 16 + background: Rectangle { + radius: 2 + color: selectorPu.Material.dialogColor + clip: true + } + + text: selectorPu.subTitle + + onLinkActivated: { + Qt.openUrlExternally(link) + } + + } + } + + function appear(dataObj, title, subTitle) { + if(dataObj.length > 0){ + selectorPu.dataObj = dataObj + } + else { + selectorPu.dataObj = undefined + } + selectorPu.title = title + selectorPu.subTitle = subTitle === undefined ? "":subTitle + selectorPu.open() + + } + + ListView { + id: selectorLv + + property int delegateHeight: 50 + + anchors.fill: parent + + implicitWidth: parent.width + implicitHeight: root.height * 0.7 < ( (delegateHeight + spacing) * model ) ? root.height * 0.7 : (delegateHeight + spacing) * model + 100 + + model: selectorPu.dataObj !== undefined ? selectorPu.dataObj.length:0 + + ScrollIndicator.vertical: ScrollIndicator { + parent: selectorLv.parent + anchors { + top: selectorLv.top + left: selectorLv.right + margins: 10 + leftMargin: 3 + bottom: selectorLv.bottom + } + + } + + delegate: Button { + id: catBt + + width: parent.width + height: text !== "" ? selectorLv.delegateHeight:0 + + flat: true + + text: selectorPu.dataObj[index].text + + onClicked: { + selectorPu.close() + selectorPu.selectionFinished(index, selectorPu.dataObj[index].data) + } + } + } + + enter: Transition { + NumberAnimation { + property: "opacity"; + //from: 0.0; + to: 1.0 + } + NumberAnimation { + property: "y" + //from: root.height - selectorPu.height * 0.7 + to: root.height - selectorPu.height + } + } + + exit: Transition { + NumberAnimation { + property: "opacity"; + //from: 1.0; + to: 0.0 + } + NumberAnimation { + property: "y" + //from: root.height - selectorPu.height + to: root.height - selectorPu.height * 0.7 + } + } + } + +} diff --git a/resources/qml/Pages/CalendarPage.qml b/resources/qml/Pages/CalendarPage.qml new file mode 100644 index 0000000..277ee9d --- /dev/null +++ b/resources/qml/Pages/CalendarPage.qml @@ -0,0 +1,758 @@ +/* + 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.4 +import QtQuick.Layouts 1.3 +import de.itsblue.blueRock 2.0 + +import "../Components" + + +BRWidgetPage { + id: control + + title: "New Calendar"//(params.nation === "ICC" ? "IFSC":params.nation === "GER" ? "DAV":"SAC") + " " + qsTr("calendar") + " " + control.year + headerComponent: RowLayout { + + height: parent.height + //width: 10//childrenRect.width + + spacing: 0 + + ToolButton { + id:yearToolBt + + onClicked: { + control.changeYear() + } + + icon.name: "year" + } + + ToolButton { + id: filterToolBt + + onClicked: { + var obj = app.compCats + var compCats = new Array + + for(var prop in obj) { + // go through the whole array and search for data keys + if (obj.hasOwnProperty(prop) && obj[prop]["nation"] === params.nation) { + //console.log("found cat: " + obj[prop]['label']) + + compCats.push( {"text": obj[prop]['label'], "data": obj[prop]} ) + } + } + + compCats.push( {"text": qsTr("Pinned"), "data": {"sort_rank":0, "cat_id":[-1]}} ) + + compCats.sort(function(a, b) { + return a['data']['sort_rank'] - b['data']['sort_rank']; + }); + + filterSelectPu.appear(compCats, qsTr("Select Filters"), "") + } + + icon.name: "filter" + } + + ToolButton { + id: cupToolBt + + onClicked: { + control.openCup() + } + + icon.name: "cup" + } + } + + DataListView { + anchors.fill: parent + + //boundsBehavior: Flickable.StopAtBounds + + model: widgetData["competitions"].length + //listData: widgetData['competitions'] + + onRefresh: { + updateData({}, false) + } + + Component.onCompleted: { + //initFilters() + //initFavorites() + + if(model){ + control.status = 200 + control.ready = true + } + else { + control.ready = false + control.status = 901 + return + } + + autoScroll() + } + /* + onWidgetDataChanged: { + // if the IFSC Calendar is open -> add the worldranking + if(params.nation === "ICC"){ + control.widgetData['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"]}) + } + } +*/ + function autoScroll() { + // function to scroll to the next competition that is not already over + var compList = control.widgetData["competitions"] + + //console.log("scrolling") + + if(parseInt(control.year) === new Date().getFullYear()){ + for(var i = 0; i < compList.length; i ++){ + // 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"] + 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(compList[i]["date"] + ": " + startDate + " to " + endDate) + + if(endDate.getTime() < new Date().getTime()){ + // end date is already over -> move the list view down! + control.positionViewAtIndex(i, ListView.Top) + //console.log("moving down!") + } + } + + //control.widgetData = control.widgetData + } + else { + //console.log("not current year") + } + } + + function getCompCatData(compCatId) { + var obj = app.compCats + + for(var prop in obj) { + // go through the whole array and search for data keys + if (obj.hasOwnProperty(prop) && obj[prop]["cat_id"].indexOf(compCatId) >= 0) { + //console.log("found cat: " + obj[prop]['label']) + return obj[prop] + } + } + } + + function openComp(compIndex){ + var cats = control.widgetData["competitions"][compIndex]["cats"] + + cats.sort(function(a, b) { + return parseInt(a["GrpId"]) - parseInt(b["GrpId"]); + }); + + var selectOptions = [] + + for(var prop in cats){ + if (cats.hasOwnProperty(prop)) { + selectOptions.push({text: cats[prop]["name"], data:{cat: cats[prop]["GrpId"], comp: control.widgetData["competitions"][compIndex]["WetId"], status:cats[prop]["status"]}}) + } + } + + var infoUrls = getCompInfoUrls(compIndex) + var infosheet = ""; + if(infoUrls.length >= 1) + infosheet += ("" + qsTr('infosheet') + "") + if(infoUrls.length === 2) + infosheet += (", " + qsTr('further infos') + "") + + console.log("Infosheet: " + infosheet) + + var eventWebsite = control.widgetData["competitions"][compIndex]["homepage"] !== undefined ? ("" + qsTr('Event Website') + ""):"" + + selector.appear(selectOptions, control.widgetData["competitions"][compIndex]['name'], eventWebsite + ((eventWebsite !== "" && infosheet !== "") ? ", ":"") + infosheet ) + } + + function changeYear(){ + var years = control.widgetData["years"] + + var selectOptions = [] + + for(var prop in years){ + if (years.hasOwnProperty(prop)) { + selectOptions.push({text: years[prop], data:{year: years[prop]}}) + } + } + + selector.appear(selectOptions, qsTr("select year")) + } + + function openCup(state, data) { + var cups = control.widgetData["cups"] + + var prop + var selectOptions = [] + var selectTitle = "" + + if(state === undefined){ + // opened for the first time -> select cup + selectTitle = qsTr("select cup") + + cups.sort(function(a, b) { + return parseInt(b["SerId"]) - parseInt(a["SerId"]); + }); + + for(prop in cups){ + if (cups.hasOwnProperty(prop)) { + selectOptions.push({text: cups[prop]["name"], data:{cup: cups[prop]["SerId"]}}) + } + } + } + else if(state === 1){ + // opened for the second time -> select cat + var cup + + // find the selected cup + for(prop in cups){ + if (cups.hasOwnProperty(prop) && cups[prop]['SerId'] === data.cup) { + cup = cups[prop] + } + } + + if(cup === undefined){ + // cup was not found + return + } + + selectTitle = cup['name'] + ": " + qsTr("select category") + + // build a list with all cat in the cup out of the cat keys (rkey) given in the cup.cats + for(prop in cup['cats']){ + if (cup['cats'].hasOwnProperty(prop)) { + + // search the rkey in the cat list + for(var i = 0; i < control.widgetData["cats"].length; i ++ ){ + if(control.widgetData["cats"][i]["rkey"] === cup["cats"][prop] && control.widgetData["cats"][i]["sex"] !== undefined){ + // found it -> append it to the select list + var catName = control.widgetData["cats"][i]["name"] // name of cat + var catId = control.widgetData["cats"][i]["GrpId"] // id of cat + selectOptions.push({text: catName, data:{cup: data.cup, cat: catId}}) + } + } + } + } + } + + selector.appear(selectOptions, selectTitle) + + } + + function getCompInfoUrls(compIndex) { + + var urls = []; + + if(control.widgetData["competitions"][compIndex].hasOwnProperty("info")) { + if(params.nation === "GER") + urls.push("http://ranking.alpenverein.de/" + control.year + "/GER/" + control.widgetData["competitions"][compIndex]['rkey'] + ".pdf") + else + urls.push(control.widgetData["competitions"][compIndex]['info']) + } + + if(control.widgetData["competitions"][compIndex].hasOwnProperty("info2")) { + if(params.nation === "GER") + urls.push("http://ranking.alpenverein.de/" + control.year + "/GER/i" + control.widgetData["competitions"][compIndex]['rkey'] + ".pdf") + else + urls.push(control.widgetData["competitions"][compIndex]['info2']) + } + + return urls; + } + + function filterCats(display, cats) { + //console.log("filtering cats: " + cats + " displaying: " + display) + for(var i = 0; i < cats.length; i ++){ + if(control.displayedCompCats.indexOf(cats[i]) >= 0 && !display){ + control.displayedCompCats.splice(control.displayedCompCats.indexOf(cats[i]), 1) + } + else if(control.displayedCompCats.indexOf(cats[i]) == -1 && display){ + control.displayedCompCats.push(cats[i]) + + } + } + // trigger 'changed' signal + control.displayedCompCats = control.displayedCompCats + appSettings.write("displayedCompCats"+params.nation, JSON.stringify(displayedCompCats)) + //console.log("new JSON string is: " + JSON.stringify(displayedCompCats)) + //console.log("displayed cats is now: " + control.displayedCompCats) + } + + function initFilters() { + if(appSettings.read("displayedCompCats"+params.nation) !== "false"){ + //console.log(appSettings.read("displayedCompCats"+params.nation)) + control.displayedCompCats = JSON.parse(appSettings.read("displayedCompCats"+params.nation)) + } + if(control.displayedCompCats.length === 0){ + var obj = app.compCats + var compCats = new Array + + for(var prop in obj) { + // go through the whole array and search for data keys + if (obj.hasOwnProperty(prop) && obj[prop]["nation"] === params.nation) { + //console.log("found cat: " + obj[prop]['label']) + filterCats(true, obj[prop]['cat_id']) + } + } + } + // trigger 'changed' signal + control.displayedCompCats = control.displayedCompCats + //console.log(control.displayedCompCats) + } + + function editFavorites(favorite, compId) { + if(control.compFavorites.indexOf(compId) >= 0 && !favorite) { + control.compFavorites.splice( control.compFavorites.indexOf(compId), 1) + } + else if(control.compFavorites.indexOf(compId) < 0 && favorite) { + control.compFavorites.push(compId) + } + + appSettings.write("compFavorites", JSON.stringify(control.compFavorites)) + // trigger 'changed' signal + control.compFavorites = control.compFavorites + } + + function initFavorites() { + if(appSettings.read("compFavorites") !== "false"){ + //console.log(appSettings.read("displayedCompCats"+params.nation)) + control.compFavorites = JSON.parse(appSettings.read("compFavorites")) + } + else { + control.compFavorites = [] + appSettings.write("compFavorites", JSON.stringify(control.compFavorites)) + } + + // trigger 'changed' signal + control.compFavorites = control.compFavorites + console.log(control.compFavorites) + } + + Connections { + target: parent.selector + onSelectionFinished: { + if(data.comp !== undefined){ + //console.log(data.status) + app.openWidget({comp: data.comp, cat: data.cat, type:data.status === 4 ? 'starters':''}) + } + else if(data.year !== undefined){ + updateData({year: data.year}, true) + control.year = data.year + } + else if(data.cup !== undefined && data.cat === undefined){ + control.openCup(1,data) + } + else if(data.cup !== undefined && data.cat !== undefined){ + app.openWidget({cup: data.cup, cat: data.cat}) + } + } + } + + header: Item { + id: topSpacerItm + width: parent.width + height: 10 + } + + footer: Item { + id: bottomSpacerItm + width: parent.width + height: 10 + } + + delegate: ItemDelegate { + id: competitionDel + + property bool over + property var thisData: control.widgetData["competitions"][index] + + property string name: thisData["name"] + property string date: thisData["date_span"] + property var cats: thisData["cats"] + property int catId: thisData["cat_id"] === undefined ? 0:thisData["cat_id"] + + property bool thisIsFavored: control.compFavorites.indexOf(parseInt(thisData['WetId'])) >= 0 + property bool includedByFavorites: control.displayedCompCats.indexOf(-1) >= 0 && thisIsFavored + property bool includedByFilter: control.displayedCompCats.indexOf(parseInt(thisData['cat_id'])) >= 0 + property bool thisIsVisible: includedByFavorites || includedByFilter + + function updateVisibility() { + competitionDel.includedByFilter = control.displayedCompCats.indexOf(parseInt(competitionDel.thisData['cat_id'])) >= 0 + competitionDel.thisIsFavored = control.compFavorites.indexOf(parseInt(thisData['WetId'])) >= 0 + competitionDel.includedByFavorites = control.displayedCompCats.indexOf(-1) >= 0 && thisIsFavored + } + + width: parent.width + height: thisIsVisible ? compDelCol.height + 10 : 0 + + enabled: ((thisData["cats"] !== undefined && thisData["cats"].length > 0) || competitionDel.thisData["homepage"] !== undefined || getCompInfoUrls(index).length > 0) && height > 0 + //visible: includedByFilter + + opacity: 0 + scale: 0.9 + + /*Connections { + target: control + onDisplayedCompCatsChanged: { + competitionDel.updateVisibility() + } + + onCompFavoritesChanged: { + competitionDel.updateVisibility() + } + }*/ + + onThisDataChanged: { + if(thisIsVisible){ + fadeInPa.start() + } + } + + onThisIsVisibleChanged: { + if(thisIsVisible){ + fadeInPa.start() + } + else { + fadeOutPa.start() + } + } + + Behavior on height { + NumberAnimation { + duration: 400 + } + } + + onClicked: { + control.openComp(index) + } + + ParallelAnimation { + id: fadeInPa + NumberAnimation { target: competitionDel; property: "opacity"; from: 0; to: 1.0; duration: 400 } + NumberAnimation { target: competitionDel; property: "scale"; from: 0.8; to: 1.0; duration: 400 } + } + + ParallelAnimation { + id: fadeOutPa + NumberAnimation { target: competitionDel; property: "opacity"; from: 1; to: 0; duration: 400 } + NumberAnimation { target: competitionDel; property: "scale"; from: 1; to: 0.8; duration: 400 } + } + + Rectangle { + id: delBackroundRect + + anchors.fill: parent + + opacity: 0.5 + + color: control.getCompCatData(catId) === undefined ? "white":control.getCompCatData(catId)["bgcolor"] + } + + Column { + id: compDelCol + + anchors.centerIn: parent + + width: parent.width * 0.97 + + spacing: 10 + + RowLayout { + width: parent.width + Label { + id: nameLa + + width: parent.width + + font.bold: true + + wrapMode: Text.WordWrap + + text: name + + Layout.fillWidth: true + } + + ToolButton { + id: bookmarkTb + icon.name: competitionDel.thisIsFavored ? "pinFilled":"pin" + onClicked: { + control.editFavorites(!competitionDel.thisIsFavored, parseInt(thisData['WetId'])) + } + + Layout.alignment: Layout.Right + + Behavior on icon.name { + SequentialAnimation { + NumberAnimation { + property: "scale" + target: bookmarkTb + duration: 75 + to: 0.8 + } + NumberAnimation { + property: "scale" + target: bookmarkTb + duration: 75 + to: 1 + } + } + } + } + } + + Label { + id: dateLa + + color: "grey" + + text: date + } + } + + Rectangle { + id: bottomLineRa + + anchors { + bottom: parent.bottom + left: parent.left + right: parent.right + } + + height: 1 + + color: "lightgrey" + + } + } + + section.property: "month" + section.delegate: ItemDelegate { + id: name + background: Rectangle { + color: "red" + } + + width: parent.width + text: section + } + + Dialog { + id: filterSelectPu + + property var dataObj + property string subTitle: "" + + signal selectionFinished(int index, var data) + + x: 0 - control.anchors.leftMargin //root.width / 2 - width / 2 + y: root.height - filterSelectPu.height * 0.7//root.height - height //root.height / 2 - height / 2 + + opacity: 0 + + width: control.width + control.anchors.leftMargin + control.anchors.rightMargin + height: selectorLv.implicitHeight + + modal: true + focus: true + + title: "" + + function appear(dataObj, title, subTitle) { + if(dataObj.length > 0){ + filterSelectPu.dataObj = dataObj + filterSelectPu.title = title + filterSelectPu.subTitle = subTitle === undefined ? "":subTitle + filterSelectPu.open() + } + } + + header: Column { + id: filterSelectPuHeaderCol + + width: parent.width + + Label { + id: headerLa + + visible: filterSelectPu.title + + width: parent.width + + elide: "ElideRight" + padding: 24 + bottomPadding: 0 + font.bold: true + font.pixelSize: 16 + background: Rectangle { + radius: 2 + //color: filterSelectPu.Material.dialogColor + clip: true + } + + text: filterSelectPu.title + + onLinkActivated: { + Qt.openUrlExternally(link) + } + + } + Label { + id: headerSubLa + + visible: filterSelectPu.subTitle + + width: parent.width + + elide: "ElideRight" + padding: 24 + topPadding: 5 + bottomPadding: 0 + font.bold: true + font.pixelSize: 16 + background: Rectangle { + radius: 2 + //color: filterSelectPu.Material.dialogColor + clip: true + } + + text: filterSelectPu.subTitle + + onLinkActivated: { + Qt.openUrlExternally(link) + } + + } + } + + ListView { + id: selectorLv + + property int delegateHeight: 50 + + anchors.fill: parent + + implicitWidth: parent.width + implicitHeight: root.height * 0.7 < ( (delegateHeight + spacing) * model ) ? root.height * 0.7 : (delegateHeight + spacing) * model + 100 + + model: filterSelectPu.dataObj !== undefined ? filterSelectPu.dataObj.length:0 + + ScrollIndicator.vertical: ScrollIndicator { + parent: selectorLv.parent + anchors { + top: selectorLv.top + left: selectorLv.right + margins: 10 + leftMargin: 3 + bottom: selectorLv.bottom + } + + } + + delegate: CheckDelegate { + id: catBt + + width: parent.width + height: text !== "" ? selectorLv.delegateHeight:0 + + //flat: true + + text: filterSelectPu.dataObj[index].text + + Component.onCompleted: { + checked = getCheckedState() + } + + Connections { + target: control + onDisplayedCompCatsChanged: { + //console.log("filters changed") + //competitionDel.visible = control.displayedCompCats.indexOf(parseInt(competitionDel.thisData['cat_id'])) >= 0 + checked = getCheckedState() + } + } + + function getCheckedState() { + for(var i = 0; i < filterSelectPu.dataObj[index].data.cat_id.length; i ++){ + + //console.log("checking cat " + filterSelectPu.dataObj[index].data.label ) + if(control.displayedCompCats.indexOf(filterSelectPu.dataObj[index].data.cat_id[i] ) >= 0){ + return true + } + } + return false + } + + + onClicked: { + control.filterCats(checked, filterSelectPu.dataObj[index].data.cat_id) + if(control.displayedCompCats.length == 0){ + control.filterCats(true, filterSelectPu.dataObj[index].data.cat_id) + checked = true + } + } + } + } + + enter: Transition { + NumberAnimation { + property: "opacity"; + //from: 0.0; + to: 1.0 + } + NumberAnimation { + property: "y" + //from: root.height - filterSelectPu.height * 0.7 + to: root.height - filterSelectPu.height + } + } + + exit: Transition { + NumberAnimation { + property: "opacity"; + //from: 1.0; + to: 0.0 + } + NumberAnimation { + property: "y" + //from: root.height - filterSelectPu.height + to: root.height - filterSelectPu.height * 0.7 + } + } + } + } +} diff --git a/resources/qml/Pages/StartPage.qml b/resources/qml/Pages/StartPage.qml index 58779c4..29268a6 100644 --- a/resources/qml/Pages/StartPage.qml +++ b/resources/qml/Pages/StartPage.qml @@ -18,6 +18,7 @@ import QtQuick 2.0 import QtQuick.Controls 2.4 +import de.itsblue.blueRock 2.0 import "../Components" @@ -75,7 +76,7 @@ Page { image: "qrc:/icons/dav.png" onClicked: { - app.openWidget({nation:"GER"}) + app.openCalendar(BRWidget.DAV, 2020, -1) } } diff --git a/resources/qml/main.qml b/resources/qml/main.qml index fb2902a..610127f 100644 --- a/resources/qml/main.qml +++ b/resources/qml/main.qml @@ -23,6 +23,7 @@ import QtQuick.Layouts 1.3 import QtPurchasing 1.12 import com.itsblue.digitalRockRanking 1.0 +import de.itsblue.blueRock 2.0 import "./Pages" import "./Components" @@ -224,6 +225,10 @@ Window { } } + BRController { + id: brController + } + ServerConn { id: serverConn } @@ -608,6 +613,22 @@ Window { loadingDl.close() } + function openCalendar(federation, year, season) { + loadingDl.open() + var newPageComp = Qt.createComponent("qrc:/Pages/CalendarPage.qml").createObject(null, {"data": brController.getCalendar(BRWidget.DAV, year, season)}) + + app.errorCode = newPageComp.status + + if(calComp.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 7084d45..076af1f 100644 --- a/resources/qml/qml.qrc +++ b/resources/qml/qml.qrc @@ -19,5 +19,7 @@ Pages/AthleteSearchPage.qml Components/SpeedFlowChart.qml Components/SwipeGallery.qml + Pages/CalendarPage.qml + Pages/BRWidgetPage.qml diff --git a/sources/brcalendar.cpp b/sources/brcalendar.cpp new file mode 100644 index 0000000..2e7f237 --- /dev/null +++ b/sources/brcalendar.cpp @@ -0,0 +1,44 @@ +#include "../headers/brcalendar.h" +#include "headers/brprovider.h" + +BRCalendar::BRCalendar(BRProvider* provider, BRFederation federation, int year, int league) : BRWidget(provider, federation) +{ + this->year = year; + this->league = league; +} + + +int BRCalendar::getYear() { + return this->year; +} + +int BRCalendar::getLeague() { + return this->league; +} + +QList BRCalendar::getCompetitions() { + return this->competitions; +} + +QList BRCalendar::getCompetitionsQML() { + QList tmpCompetitions; + + for(BRCompetition* competition : this->competitions) + tmpCompetitions.append(competition); + + return tmpCompetitions; +} + +BRWidget::BRWidgetStatusCode BRCalendar::load() { + if(this->getProvider() == nullptr) + return BRWidget::NoProviderError; + + // reload all comp data using our providers + this->competitions.clear(); + this->categories.clear(); + this->cups.clear(); + + // TODO: handle changes dynamically + + return this->getProvider()->loadCalendarData(this); +} diff --git a/sources/brcategory.cpp b/sources/brcategory.cpp new file mode 100644 index 0000000..45c4927 --- /dev/null +++ b/sources/brcategory.cpp @@ -0,0 +1,6 @@ +#include "../headers/brcategory.h" + +BRCategory::BRCategory(QObject *parent) : QObject(parent) +{ + +} diff --git a/sources/brcompetition.cpp b/sources/brcompetition.cpp new file mode 100644 index 0000000..42c08da --- /dev/null +++ b/sources/brcompetition.cpp @@ -0,0 +1,14 @@ +#include "../headers/brcompetition.h" + +BRCompetition::BRCompetition(BRProvider* provider, BRWidget::BRFederation federation, int id) : BRWidget(provider, federation) +{ + this->id = id; +} + +QString BRCompetition::getName() { + return this->name; +} + +BRWidget::BRWidgetStatusCode BRCompetition::load() { + +} diff --git a/sources/brcontroller.cpp b/sources/brcontroller.cpp new file mode 100644 index 0000000..ad274ac --- /dev/null +++ b/sources/brcontroller.cpp @@ -0,0 +1,11 @@ +#include "../headers/brcontroller.h" + +BRController::BRController(QObject *parent) : QObject(parent) +{ + this->providerDr = new BRProviderDr(this); +} + + +BRCalendar* BRController::getCalendar(BRWidget::BRFederation federation, int year, int league) { + return this->providerDr->getCalendar(federation, year, -1); +} diff --git a/sources/brcup.cpp b/sources/brcup.cpp new file mode 100644 index 0000000..4ead14b --- /dev/null +++ b/sources/brcup.cpp @@ -0,0 +1,6 @@ +#include "../headers/brcup.h" + +BRCup::BRCup(BRProvider* provider, BRFederation federation) : BRWidget(provider, federation) +{ + +} diff --git a/sources/brprovider.cpp b/sources/brprovider.cpp new file mode 100644 index 0000000..27e46f0 --- /dev/null +++ b/sources/brprovider.cpp @@ -0,0 +1,74 @@ +#include "../headers/brprovider.h" + +BRProvider::BRProvider(QObject *parent) : QObject(parent) +{ + +} + +BRCalendar* BRProvider::getCalendar(BRWidget::BRFederation federation, int year, int league) { + return new BRCalendar(this, federation, year, league); +} + +QVariantMap BRProvider::serverRequest(QUrl serviceUrl, QUrlQuery pdata) +{ + qDebug() << "requesting: " << serviceUrl; + + // create network manager + QNetworkAccessManager * networkManager = new QNetworkAccessManager(); + + QVariantMap ret; //this is a custom type to store the return-data + + // Create network request + QNetworkRequest request(serviceUrl); + request.setHeader(QNetworkRequest::ContentTypeHeader, + "application/x-www-form-urlencoded"); + + //QSslConfiguration config = QSslConfiguration::defaultConfiguration(); + //config.setProtocol(QSsl::TlsV1_2); + //request.setSslConfiguration(config); + + //send a POST request with the given url and data to the server + + QNetworkReply *reply; + + if(pdata.isEmpty()){ + // if no post data is given -> send a GET request + reply = networkManager->get(request); + } + else { + // if post data is given -> send POST request + reply = networkManager->post(request, pdata.toString(QUrl::FullyEncoded).toUtf8()); + } + + // loop to wait until the request has finished before processing the data + QEventLoop loop; + // timer to cancel the request after 3 seconds + QTimer timer; + timer.setSingleShot(true); + + // quit the loop when the request finised + loop.connect(networkManager, SIGNAL(finished(QNetworkReply*)), SLOT(quit())); + // or the timer timed out + loop.connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit())); + // start the timer + timer.start(10000); + // start the loop + loop.exec(); + + //get the status code + QVariant status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); + + ret.insert("status", status_code.toInt()); + + //get the full text response + ret.insert("text", QString::fromUtf8(reply->readAll())); + + // delete the reply object + delete reply; + + // delete the newtwork access manager object + delete networkManager; + + //return the data + return(ret); +} diff --git a/sources/brproviderdr.cpp b/sources/brproviderdr.cpp new file mode 100644 index 0000000..2a53a96 --- /dev/null +++ b/sources/brproviderdr.cpp @@ -0,0 +1,59 @@ +#include "../headers/brproviderdr.h" + +BRProviderDr::BRProviderDr(QObject *parent) : BRProvider(parent) +{ + +} + +BRWidget::BRWidgetStatusCode BRProviderDr::loadCalendarData(BRCalendar* calendar) +{ + // load some data + QString nationStr = calendar->getFederation() == BRWidget::SAC ? "SUI":"GER"; + QVariantMap ret = this->serverRequest(QUrl("https://www.digitalrock.de/egroupware/ranking/json.php?nation=" + nationStr)); + + if(ret["status"] != 200){ + // request was a failure + return BRWidget::BRWidgetStatusCode(ret["status"].toInt()); + } + + QVariantMap data = QJsonDocument::fromJson(ret["text"].toString().toUtf8()).toVariant().toMap(); + + // parse competitions + QVariantList competitions = data["competitions"].toList(); + QList tmpCompetitions; + + for(QVariant competitionVar : competitions) { + BRCompetition* competition = new BRCompetition(this, calendar->getFederation(), competitionVar.toMap()["WetId"].toInt()); + this->loadCompetitionData(competition, competitionVar.toMap()); + tmpCompetitions.append(competition); + } + + if(calendar->competitions != tmpCompetitions) + calendar->competitions = tmpCompetitions; + + return BRWidget::Success; +} + + +BRWidget::BRWidgetStatusCode BRProviderDr::loadCompetitionData(BRCompetition* competition, QVariantMap data) { + + // load basic properties + competition->name = data["name"].toString(); + + QMap disciplineTranslations = { + {"boulder", BRCompetition::Boulder}, + {"lead", BRCompetition::Lead}, + {"speed", BRCompetition::Speed} + }; + + if(disciplineTranslations.contains(data["discipline"].toString())) + competition->discipline = disciplineTranslations[data["discipline"].toString()]; + + competition->startDate = QDate::fromString(data["date"].toString()); + competition->endDate = QDate::fromString(data["date_end"].toString()); + + // TODO load categories + //competition->categories.clear(); + + // TODO load results +} diff --git a/sources/brserverconnector.cpp b/sources/brserverconnector.cpp index 6747562..0f73ca5 100644 --- a/sources/brserverconnector.cpp +++ b/sources/brserverconnector.cpp @@ -16,13 +16,13 @@ along with this program. If not, see . */ -#include "headers/serverconn.h" +#include "headers/brserverconnector.h" -ServerConn::ServerConn(QObject *parent) : QObject(parent) +BRServerConnector::BRServerConnector(QObject *parent) : QObject(parent) { } -QVariant ServerConn::getWidgetData(QVariantMap params){ +QVariant BRServerConnector::getWidgetData(QVariantMap params){ QString requestUrl; if(params["nation"].toString() == "ICC"){ requestUrl = "https://ifsc-egw.wavecdn.net/egw/ranking/json.php?"; @@ -65,7 +65,7 @@ QVariant ServerConn::getWidgetData(QVariantMap params){ // --- Helper functions --- // ------------------------ -QVariantMap ServerConn::senddata(QUrl serviceUrl, QUrlQuery pdata) +QVariantMap BRServerConnector::senddata(QUrl serviceUrl, QUrlQuery pdata) { // create network manager QNetworkAccessManager * networkManager = new QNetworkAccessManager(); diff --git a/sources/brwidget.cpp b/sources/brwidget.cpp new file mode 100644 index 0000000..235f5c4 --- /dev/null +++ b/sources/brwidget.cpp @@ -0,0 +1,17 @@ +#include "../headers/brwidget.h" + +#include "headers/brprovider.h" + +BRWidget::BRWidget(BRProvider* provider, BRFederation federation) : QObject(provider) +{ + this->provider = provider; + this->federation = federation; +} + +BRWidget::BRFederation BRWidget::getFederation() { + return this->federation; +} + +BRProvider* BRWidget::getProvider() { + return this->provider; +} diff --git a/sources/main.cpp b/sources/main.cpp index df5e095..f60f1ea 100644 --- a/sources/main.cpp +++ b/sources/main.cpp @@ -23,8 +23,9 @@ #include #include -#include "headers/serverconn.h" +#include "headers/brserverconnector.h" #include "headers/appsettings.h" +#include "headers/brcontroller.h" int main(int argc, char *argv[]) { @@ -38,9 +39,15 @@ int main(int argc, char *argv[]) QIcon::setFallbackSearchPaths(QIcon::fallbackSearchPaths() << ":/resources/shared/icons"); QIcon::setThemeName("bluerock"); - qmlRegisterType("com.itsblue.digitalRockRanking", 1, 0, "ServerConn"); + qmlRegisterType("com.itsblue.digitalRockRanking", 1, 0, "ServerConn"); qmlRegisterType("com.itsblue.digitalRockRanking", 1, 0, "AppSettings"); + qmlRegisterType("de.itsblue.blueRock", 2, 0, "BRController"); + qmlRegisterUncreatableType("de.itsblue.blueRock", 2, 0, "BRCalendar", "BRCalendar is not creatable"); + qmlRegisterUncreatableType("de.itsblue.blueRock", 2, 0, "BRWidget", "BRWidget is not creatable"); + qRegisterMetaType("BRWidget::BRFederation"); + //qmlRegisterType("de.itsblue.blueRock", 2, 0, "BRController"); + QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); if (engine.rootObjects().isEmpty())