diff --git a/DigitalRockRanking.pro b/DigitalRockRanking.pro
new file mode 100644
index 0000000..a5e1b48
--- /dev/null
+++ b/DigitalRockRanking.pro
@@ -0,0 +1,42 @@
+QT += quick qml quickcontrols2
+CONFIG += c++11
+
+android {
+ QT += androidextras
+ ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android-sources
+}
+
+# The following define makes your compiler emit warnings if you use
+# any Qt feature that has been marked deprecated (the exact warnings
+# depend on your compiler). Refer to the documentation for the
+# deprecated API to know how to port your code away from it.
+DEFINES += QT_DEPRECATED_WARNINGS
+
+# You can also make your code fail to compile if it uses deprecated APIs.
+# In order to do so, uncomment the following line.
+# You can also select to disable deprecated APIs only up to a certain version of Qt.
+#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
+
+SOURCES += \
+ sources/main.cpp \
+ sources/serverconn.cpp
+
+RESOURCES += resources/qml/qml.qrc \
+ resources/shared/shared.qrc
+
+# Additional import path used to resolve QML modules in Qt Creator's code model
+QML_IMPORT_PATH =
+
+# Additional import path used to resolve QML modules just for Qt Quick Designer
+QML_DESIGNER_IMPORT_PATH =
+
+# Default rules for deployment.
+qnx: target.path = /tmp/$${TARGET}/bin
+else: unix:!android: target.path = /opt/$${TARGET}/bin
+!isEmpty(target.path): INSTALLS += target
+
+HEADERS += \
+ headers/serverconn.h
+
+DISTFILES += \
+ android-sources/AndroidManifest.xml
diff --git a/DigitalRockRanking.pro.user b/DigitalRockRanking.pro.user
new file mode 100644
index 0000000..544d316
--- /dev/null
+++ b/DigitalRockRanking.pro.user
@@ -0,0 +1,635 @@
+
+
+
+
+
+ EnvironmentId
+ {73fd4d96-a4f7-426d-9695-506509aacee9}
+
+
+ ProjectExplorer.Project.ActiveTarget
+ 0
+
+
+ ProjectExplorer.Project.EditorSettings
+
+ true
+ false
+ true
+
+ Cpp
+
+ CppGlobal
+
+
+
+ QmlJS
+
+ QmlJSGlobal
+
+
+ 2
+ UTF-8
+ false
+ 4
+ false
+ 80
+ true
+ true
+ 1
+ true
+ false
+ 0
+ true
+ true
+ 0
+ 8
+ true
+ 1
+ true
+ true
+ true
+ false
+
+
+
+ ProjectExplorer.Project.PluginSettings
+
+
+ true
+
+
+
+ ProjectExplorer.Project.Target.0
+
+ Android for armeabi-v7a (Clang Qt 5.11.3 for Android ARMv7)
+ Android for armeabi-v7a (Clang Qt 5.11.3 for Android ARMv7)
+ {0c845c7b-f333-4cf9-be32-0bca6d080fce}
+ 0
+ 0
+ 0
+
+ /home/dorian/builds/build-DigitalRockRanking-Android_for_armeabi_v7a_Clang_Qt_5_11_3_for_Android_ARMv7-Debug
+
+
+ true
+ qmake
+
+ QtProjectManager.QMakeBuildStep
+ true
+
+ false
+ false
+ false
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ false
+
+
+ false
+
+
+ true
+ Copy application data
+
+ Qt4ProjectManager.AndroidPackageInstallationStep
+
+
+ android-28
+
+ true
+ Build Android APK
+
+ QmakeProjectManager.AndroidBuildApkStep
+ false
+ false
+
+ 4
+ Build
+
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ true
+ clean
+
+ false
+
+ 1
+ Clean
+
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ Debug
+ Debug
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 2
+ true
+
+
+ /home/dorian/builds/build-DigitalRockRanking-Android_for_armeabi_v7a_Clang_Qt_5_11_3_for_Android_ARMv7-Release
+
+
+ true
+ qmake
+
+ QtProjectManager.QMakeBuildStep
+ false
+
+ false
+ false
+ true
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ false
+
+
+ false
+
+
+ true
+ Copy application data
+
+ Qt4ProjectManager.AndroidPackageInstallationStep
+
+
+ android-28
+
+ true
+ Build Android APK
+
+ QmakeProjectManager.AndroidBuildApkStep
+ false
+ false
+
+ 4
+ Build
+
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ true
+ clean
+
+ false
+
+ 1
+ Clean
+
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ Release
+ Release
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ true
+
+
+ /home/dorian/builds/build-DigitalRockRanking-Android_for_armeabi_v7a_Clang_Qt_5_11_3_for_Android_ARMv7-Profile
+
+
+ true
+ qmake
+
+ QtProjectManager.QMakeBuildStep
+ true
+
+ false
+ true
+ true
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ false
+
+
+ false
+
+
+ true
+ Copy application data
+
+ Qt4ProjectManager.AndroidPackageInstallationStep
+
+
+ android-28
+
+ true
+ Build Android APK
+
+ QmakeProjectManager.AndroidBuildApkStep
+ false
+ false
+
+ 4
+ Build
+
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ true
+ clean
+
+ false
+
+ 1
+ Clean
+
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ Profile
+ Profile
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ true
+
+ 3
+
+
+
+ true
+ Deploy to Android device
+
+ Qt4ProjectManager.AndroidDeployQtStep
+ false
+
+ 1
+ Deploy
+
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+ Deploy to Android device
+
+ Qt4ProjectManager.AndroidDeployConfiguration2
+
+ 1
+
+ MWS0216A15001488
+ 24
+
+
+ false
+ false
+ 1000
+
+ true
+
+ false
+ false
+ false
+ false
+ true
+ 0.01
+ 10
+ true
+ 1
+ 25
+
+ 1
+ true
+ false
+ true
+ valgrind
+
+ 0
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+
+
+
+
+ 0
+
+ DigitalRockRanking
+ DigitalRockRanking
+ Qt4ProjectManager.AndroidRunConfiguration:/home/dorian/DigitalRockRanking/DigitalRockRanking.pro
+
+ 3768
+ false
+ true
+ false
+ false
+ true
+
+ 1
+
+
+
+ ProjectExplorer.Project.Target.1
+
+ Desktop Qt 5.11.3 GCC 64bit
+ Desktop Qt 5.11.3 GCC 64bit
+ qt.qt5.5113.gcc_64_kit
+ 0
+ 0
+ 0
+
+ /home/dorian/builds/build-DigitalRockRanking-Desktop_Qt_5_11_3_GCC_64bit-Debug
+
+
+ true
+ qmake
+
+ QtProjectManager.QMakeBuildStep
+ true
+
+ false
+ false
+ false
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ false
+
+
+ false
+
+ 2
+ Build
+
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ true
+ clean
+
+ false
+
+ 1
+ Clean
+
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ Debug
+ Debug
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 2
+ true
+
+
+ /home/dorian/builds/build-DigitalRockRanking-Desktop_Qt_5_11_3_GCC_64bit-Release
+
+
+ true
+ qmake
+
+ QtProjectManager.QMakeBuildStep
+ false
+
+ false
+ false
+ true
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ false
+
+
+ false
+
+ 2
+ Build
+
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ true
+ clean
+
+ false
+
+ 1
+ Clean
+
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ Release
+ Release
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ true
+
+
+ /home/dorian/builds/build-DigitalRockRanking-Desktop_Qt_5_11_3_GCC_64bit-Profile
+
+
+ true
+ qmake
+
+ QtProjectManager.QMakeBuildStep
+ true
+
+ false
+ true
+ true
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ false
+
+
+ false
+
+ 2
+ Build
+
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ true
+ clean
+
+ false
+
+ 1
+ Clean
+
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ Profile
+ Profile
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ true
+
+ 3
+
+
+ 0
+ Deploy
+
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+ Deploy Configuration
+
+ ProjectExplorer.DefaultDeployConfiguration
+
+ 1
+
+
+ false
+ false
+ 1000
+
+ true
+
+ false
+ false
+ false
+ false
+ true
+ 0.01
+ 10
+ true
+ 1
+ 25
+
+ 1
+ true
+ false
+ true
+ valgrind
+
+ 0
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+
+ 2
+
+ DigitalRockRanking
+
+ Qt4ProjectManager.Qt4RunConfiguration:/home/dorian/DigitalRockRanking/DigitalRockRanking.pro
+ DigitalRockRanking.pro
+
+ 3768
+ false
+ true
+ true
+ false
+ false
+ true
+
+ /home/dorian/builds/build-DigitalRockRanking-Desktop_Qt_5_11_3_GCC_64bit-Debug
+
+ 1
+
+
+
+ ProjectExplorer.Project.TargetCount
+ 2
+
+
+ ProjectExplorer.Project.Updater.FileVersion
+ 20
+
+
+ Version
+ 20
+
+
diff --git a/Questions.odt b/Questions.odt
new file mode 100644
index 0000000..b4782dd
Binary files /dev/null and b/Questions.odt differ
diff --git a/android-sources/AndroidManifest.xml b/android-sources/AndroidManifest.xml
new file mode 100644
index 0000000..a627afb
--- /dev/null
+++ b/android-sources/AndroidManifest.xml
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android-sources/libs/armeabi-v7a/libcrypto.so b/android-sources/libs/armeabi-v7a/libcrypto.so
new file mode 100644
index 0000000..4448d85
Binary files /dev/null and b/android-sources/libs/armeabi-v7a/libcrypto.so differ
diff --git a/android-sources/libs/armeabi-v7a/libssl.so b/android-sources/libs/armeabi-v7a/libssl.so
new file mode 100644
index 0000000..e8ef374
Binary files /dev/null and b/android-sources/libs/armeabi-v7a/libssl.so differ
diff --git a/android-sources/libs/x86/libcrypto.so b/android-sources/libs/x86/libcrypto.so
new file mode 100644
index 0000000..a2e46cd
Binary files /dev/null and b/android-sources/libs/x86/libcrypto.so differ
diff --git a/android-sources/libs/x86/libssl.so b/android-sources/libs/x86/libssl.so
new file mode 100644
index 0000000..3f3032a
Binary files /dev/null and b/android-sources/libs/x86/libssl.so differ
diff --git a/android-sources/res/drawable-hdpi/icon.png b/android-sources/res/drawable-hdpi/icon.png
new file mode 100644
index 0000000..15f210f
Binary files /dev/null and b/android-sources/res/drawable-hdpi/icon.png differ
diff --git a/android-sources/res/drawable-ldpi/icon.png b/android-sources/res/drawable-ldpi/icon.png
new file mode 100644
index 0000000..15f210f
Binary files /dev/null and b/android-sources/res/drawable-ldpi/icon.png differ
diff --git a/android-sources/res/drawable-mdpi/icon.png b/android-sources/res/drawable-mdpi/icon.png
new file mode 100644
index 0000000..15f210f
Binary files /dev/null and b/android-sources/res/drawable-mdpi/icon.png differ
diff --git a/headers/serverconn.h b/headers/serverconn.h
new file mode 100644
index 0000000..c0ed1c2
--- /dev/null
+++ b/headers/serverconn.h
@@ -0,0 +1,36 @@
+#ifndef SERVERCONN_H
+#define SERVERCONN_H
+
+#include
+#include
+#include
+#include
+#include
+
+class ServerConn : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QVariant foodplan READ getFoodplan NOTIFY foodplanChanged)
+public:
+ explicit ServerConn(QObject *parent = nullptr);
+
+private:
+ QVariantMap senddata(QUrl serviceUrl, QUrlQuery pdata = QUrlQuery());
+
+ // variables
+ QVariant foodplan;
+
+signals:
+ void foodplanChanged();
+
+public slots:
+ void refreshFoodplan();
+
+ QVariant getCalendar(QString nation);
+ QVariant getRanking(int competitionId, int categoryId, bool registrationData = false, const int routeNumber = -2);
+
+ // functions for qml
+ QVariant getFoodplan();
+};
+
+#endif // SERVERCONN_H
diff --git a/resources/qml/Components/AppToolBar.qml b/resources/qml/Components/AppToolBar.qml
new file mode 100644
index 0000000..4aeab97
--- /dev/null
+++ b/resources/qml/Components/AppToolBar.qml
@@ -0,0 +1,94 @@
+import QtQuick 2.6
+import QtQuick.Controls 2.1
+import QtGraphicalEffects 1.0
+import QtQuick.Controls.Material 2.3
+
+Item {
+ id: control
+ height: 50
+ property bool showErrorBar: true
+
+ RectangularGlow {
+ id: toolBarEffect
+ glowRadius: 3
+ spread: 0.2
+ color: "black"
+ opacity: 0.3
+ anchors.fill: toolBar
+ }
+
+ Rectangle {
+ id: toolBar
+ color: "white"
+ anchors.fill: parent
+
+
+// anchors {
+// top: parent.top
+// left: parent.left
+// right: parent.right
+// topMargin: -60
+// }
+
+ Rectangle {
+ id: errorField
+ width: parent.width
+ height: 30
+ enabled: app.is_error & app.state !== "notLoggedIn" & control.showErrorBar
+ anchors.top: parent.bottom
+
+ color: "red"
+ onEnabledChanged: {
+ if(enabled){
+ toolBar.state = 'moveIn'
+ }
+ else {
+ toolBar.state = 'moveOut'
+ }
+ }
+
+ MouseArea { anchors.fill: parent; onClicked: {
+ toolBar.state = 'moveOut'
+
+ console.log("clicked")
+ }
+ }
+
+ Text {
+ anchors {
+ horizontalCenter: parent.horizontalCenter
+ verticalCenter: parent.verticalCenter
+ }
+
+ id: errorText
+ font.family: "Helvetica"
+ color: "White"
+ font.pointSize: 8
+ visible: parent.height !== 0
+ text: ""
+ }
+ }
+
+ states: [
+ State {
+ name: "moveOut"
+ PropertyChanges { target: errorField; height: 0 }
+ },
+ State {
+ name: "moveIn"
+ PropertyChanges { target: errorField; height: 30 }
+ }
+ ]
+
+ transitions: [
+ Transition {
+ to: "moveOut"
+ NumberAnimation { properties: "height"; easing.type: Easing.InOutQuad; duration: 200 }
+ },
+ Transition {
+ to: "moveIn"
+ NumberAnimation { properties: "height"; easing.type: Easing.InOutQuad; duration: 200 }
+ }
+ ]
+ }
+}
diff --git a/resources/qml/Components/DataListView.qml b/resources/qml/Components/DataListView.qml
new file mode 100644
index 0000000..0e9ee28
--- /dev/null
+++ b/resources/qml/Components/DataListView.qml
@@ -0,0 +1,50 @@
+import QtQuick 2.9
+import QtQuick.Controls 2.4
+
+ListView {
+ id: control
+
+ property int status: -1
+
+ signal refresh()
+
+ anchors.margins: 10
+ anchors.rightMargin: 14
+
+ ScrollBar.vertical: ScrollBar {
+ parent: control.parent
+
+ anchors {
+ top: control.top
+ left: control.right
+ margins: 10
+ leftMargin: 3
+ bottom: control.bottom
+ }
+
+ width: 8
+
+ active: true
+ }
+
+ onContentYChanged: {
+ if(contentY < -125){
+ control.refresh()
+ }
+ }
+
+ InfoArea {
+ id: infoArea
+
+ anchors {
+ left: control.left
+ right: control.right
+ top: control.top
+ margins: app.landscape() ? control.width * 0.4:control.width * 0.3
+ topMargin: control.height*( status === 901 ? 0.6:0.5) - height * 0.8
+ }
+
+ excludedCodes: [200, 902]
+ errorCode: control.status
+ }
+}
diff --git a/resources/qml/Components/FancyBusyIndicator.qml b/resources/qml/Components/FancyBusyIndicator.qml
new file mode 100644
index 0000000..32d8421
--- /dev/null
+++ b/resources/qml/Components/FancyBusyIndicator.qml
@@ -0,0 +1,95 @@
+import QtQuick 2.3
+import QtQuick.Controls 2.4
+import QtQuick.Controls.Styles 1.2
+
+BusyIndicator {
+ id: control
+
+ property double animationSpeed: 0.5
+
+ contentItem: Item {
+ implicitWidth: 64
+ implicitHeight: 64
+
+ Item {
+ id: item
+
+ x: parent.width / 2 - 32
+ y: parent.height / 2 - 32
+
+ width: 64
+ height: 64
+
+ opacity: control.running ? 1 : 0
+
+ property int currentHeight: 0
+
+ onCurrentHeightChanged: {
+ }
+
+ Behavior on opacity {
+ OpacityAnimator {
+ duration: 250
+ }
+ }
+
+ SequentialAnimation {
+ loops: Animation.Infinite
+
+ running: true
+
+ NumberAnimation {
+ target: item
+
+ duration: 2000 * 1/control.animationSpeed
+
+ to: 1000
+
+ properties: "currentHeight"
+
+ easing.type: Easing.InOutQuad
+
+ }
+
+ NumberAnimation {
+ target: item
+
+ duration: 2000 * 1/control.animationSpeed
+
+ to: 0
+
+ properties: "currentHeight"
+
+ easing.type: Easing.InOutQuad
+
+ }
+ }
+
+ Row {
+
+ anchors.fill: parent
+
+ spacing: item.width / 9
+
+ Repeater {
+ id: repeater
+ model: 5
+
+ Rectangle {
+
+ property double heightMultiplier: Math.abs( Math.sin(( (item.currentHeight + (index*20))*0.01) * (Math.PI/2) ) )
+
+ anchors.verticalCenter: parent.verticalCenter
+
+ width: item.width / 9
+ height: ( heightMultiplier ) * ( item.height - 1 ) + 1
+
+ radius: width * 0.5
+
+ color: "#21be2b"
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/resources/qml/Components/FancyButton.qml b/resources/qml/Components/FancyButton.qml
new file mode 100644
index 0000000..2ec7623
--- /dev/null
+++ b/resources/qml/Components/FancyButton.qml
@@ -0,0 +1,88 @@
+import QtQuick 2.9
+import QtQuick.Controls 2.4
+import QtGraphicalEffects 1.0
+
+Button {
+ id: control
+
+ property string image
+ property color backgroundColor: "white"
+ property color textColor: "black"
+ property real imageScale: 1
+ property double glowRadius: 0.001
+ property double glowSpread: 0.2
+ property bool glowVisible: true
+ property double glowScale: 0.75
+ property double glowOpacity: 1
+
+ scale: control.pressed ? 0.8:1
+
+ Behavior on scale {
+ PropertyAnimation {
+ duration: 100
+ }
+ }
+
+ Behavior on backgroundColor {
+ ColorAnimation {
+ duration: 200
+ }
+ }
+
+ contentItem: Text {
+ visible: false
+ }
+
+ Text {
+ id: conetntText
+ text: qsTr(control.text)
+ anchors.centerIn: parent
+ font: parent.font
+ color: control.textColor
+ opacity: control.enabled ? 1:0.4
+ }
+
+ background: Item {
+ id: controlBackgroundContainer
+
+ RectangularGlow {
+ id: effect
+ glowRadius: control.glowRadius
+ spread: control.glowSpread
+ color: "black"
+
+ visible: control.glowVisible
+
+ cornerRadius: controlBackground.radius
+ anchors.fill: controlBackground
+ scale: control.glowScale
+ opacity: control.glowOpacity
+ }
+
+ Rectangle {
+ id: controlBackground
+
+ anchors.fill: parent
+
+ radius: height * 0.5
+
+ color: control.backgroundColor
+
+ Image {
+ id: buttonIcon
+ source: control.image
+
+ anchors.centerIn: parent
+ height: parent.height * 0.5
+ width: height
+
+ mipmap: true
+
+ fillMode: Image.PreserveAspectFit
+
+ scale: control.imageScale
+ }
+ }
+ }
+
+}
diff --git a/resources/qml/Components/InfoArea.qml b/resources/qml/Components/InfoArea.qml
new file mode 100644
index 0000000..6f4e646
--- /dev/null
+++ b/resources/qml/Components/InfoArea.qml
@@ -0,0 +1,98 @@
+/*
+ Fannyapp - Application to view the cover plan of the Fanny-Leicht-Gymnasium ins Stuttgart Vaihingen, Germany
+ Copyright (C) 2019 Itsblue Development
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+ */
+
+import QtQuick 2.9
+import QtQuick.Controls 2.4
+
+Item {
+ id: infoArea
+
+ property int alertLevel: app.getErrorInfo(infoArea.errorCode)[0]
+ // 0 - ok
+ // 1 - info
+ // 2 - error
+ property int errorCode: -1
+ property var excludedCodes: []
+
+ visible: !(excludedCodes.indexOf(errorCode) >= 0)
+
+ height: childrenRect.height
+
+ Rectangle {
+
+ radius: height * 0.5
+ width: parent.width
+ height: width
+
+ color: "transparent"
+ border.width: 5
+ border.color: infoArea.alertLevel > 0 ? infoArea.alertLevel > 1 ? "red":"grey" : "green"
+
+ opacity: infoArea.errorCode !== 200 && infoArea.errorCode !== (-1) ? 1:0
+
+ Behavior on opacity {
+ NumberAnimation {
+ duration: 500
+ }
+ }
+
+ Label {
+ anchors.centerIn: parent
+ font.pixelSize: parent.height * 0.8
+ text: infoArea.alertLevel > 1 ? "!":"i"
+ color: infoArea.alertLevel > 0 ? infoArea.alertLevel > 1 ? "red":"grey" : "green"
+ }
+
+ Label {
+ id: errorShortDescription
+ anchors {
+ horizontalCenter: parent.horizontalCenter
+ top: parent.bottom
+ margins: parent.height * 0.1
+ }
+
+ width: app.width * 0.8
+
+ wrapMode: Label.Wrap
+
+ horizontalAlignment: Label.AlignHCenter
+
+ font.pixelSize: errorLongDescription.font.pixelSize * 1.8
+ text: app.getErrorInfo(infoArea.errorCode)[1]
+ }
+
+ Label {
+ id: errorLongDescription
+ anchors {
+ horizontalCenter: parent.horizontalCenter
+ top: errorShortDescription.bottom
+ margins: parent.height * 0.1
+ }
+
+ width: app.width * 0.8
+
+ wrapMode: Label.Wrap
+
+ horizontalAlignment: Label.AlignHCenter
+
+ text: app.getErrorInfo(infoArea.errorCode)[2]
+ }
+ }
+
+}
+
diff --git a/resources/qml/Components/RankingView.qml b/resources/qml/Components/RankingView.qml
new file mode 100644
index 0000000..d0af5ce
--- /dev/null
+++ b/resources/qml/Components/RankingView.qml
@@ -0,0 +1,274 @@
+import QtQuick 2.0
+import QtQuick.Controls 2.4
+
+DataListView {
+ id: control
+
+ property var listData: ({})
+
+ onListDataChanged: {
+ model = listData[ root.listKey ] === undefined ? 0:listData[ root.listKey ].length
+ }
+
+ model: listData[ root.listKey ] === undefined ? 0:listData[ root.listKey ].length
+
+ delegate: ItemDelegate {
+ id: partDel
+
+ property int ind: index
+
+ width: parent.width
+ height: 70
+
+ text: ""
+
+ Rectangle {
+ anchors.fill: parent
+
+ width: partDel.width
+
+ color: partDel.ind % 2 == 0 ? "white":"lightgrey"
+
+ opacity: 0.2
+ }
+
+ Column {
+ id: partDelCol
+
+ anchors.fill: parent
+ anchors.margins: 5
+
+ Row {
+ id: partDelFirstRow
+
+ width: parent.width
+ height: parent.height - partDelSecondRow.height
+
+ Label {
+ height: parent.height
+ width: parent.width * 0.1
+
+ fontSizeMode: Text.Fit
+ font.bold: true
+ font.pixelSize: Math.abs( partDelSecondRow.height > 0 ? height * 0.6:height * 0.4 )
+ verticalAlignment: Text.AlignVCenter
+ horizontalAlignment: Text.AlignHCenter
+
+ text: listData[ "participants" ][index]["result_rank"]
+ }
+
+ Label {
+ height: parent.height
+ width: parent.width * 0.5
+
+ fontSizeMode: Text.Fit
+ font.bold: true
+ font.pixelSize: Math.abs( partDelSecondRow.height > 0 ? height * 0.6:height * 0.4 )
+ verticalAlignment: Text.AlignVCenter
+ horizontalAlignment: Text.AlignLeft
+
+ text: listData[ "participants" ][index]["firstname"] + " " + listData[ "participants" ][index]["lastname"]
+ }
+
+ Label {
+ height: parent.height
+ width: parent.width * 0.4
+
+ fontSizeMode: Text.Fit
+ font.bold: false
+ font.pixelSize: Math.abs( partDelSecondRow.height > 0 ? height * 0.4:height * 0.3 )
+ minimumPixelSize: 0
+ verticalAlignment: Text.AlignVCenter
+ horizontalAlignment: Text.AlignHCenter
+
+ text: "(" + (listData[ "display_athlete" ] === "nation" ? listData[ "participants" ][index]["nation"] : listData[ "participants" ][index]["federation"]) + ")"
+
+ onLinkActivated: {
+ Qt.openUrlExternally(link)
+ }
+ }
+ }
+
+ Row {
+ id: partDelSecondRow
+
+ width: parent.width
+ height: multiResRow.enabled || multiGenResRow.enabled || resultLa.enabled ? parent.height / 2:0
+
+ Row {
+ id: multiResRow
+
+ height: parent.height
+ width: enabled ? parent.width * 0.75:0
+
+ enabled: parseInt(listData[ "route_order" ]) > -1 && boulderResRep.model > 0
+
+ Repeater {
+ id: boulderResRep
+
+ model: parseInt(listData[ "route_num_problems" ])
+
+ delegate: Item {
+ id: boulderResItm
+
+ anchors.verticalCenter: parent.verticalCenter
+
+ width: parent.width / ( boulderResRep.model )
+ height: parent.height
+
+ 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 {
+ anchors.centerIn: parent
+
+ height: parent.height
+ width: parent.width * 0.9
+
+ fontSizeMode: Text.Fit
+ font.pixelSize: Math.abs( height * 0.6 )
+ minimumPixelSize: 0
+ verticalAlignment: Text.AlignVCenter
+ horizontalAlignment: Text.AlignHCenter
+
+ text: listData[ "participants" ][partDel.ind]["boulder"+(index+1)] === undefined ? "":listData[ "participants" ][partDel.ind]["boulder"+(index+1)]
+ }
+
+ }
+
+ }
+
+ }
+
+ Row {
+ id: multiGenResRow
+
+ height: parent.height
+ width: enabled ? parent.width - resultLa.width:0
+
+ enabled: ((parseInt(listData[ "route_order" ]) === -1) && (generalResRep.model > 0)) ? true:false
+
+ Repeater {
+ id: generalResRep
+
+ property var routes: getRoutes()
+ model: routes.length
+
+ function getRoutes() {
+
+ var obj = listData["route_names"]
+ var routes = []
+
+ for(var prop in obj) {
+ // go through the whole array and search for data keys
+ if (obj.hasOwnProperty(prop) && prop > -1) {
+ routes.push([prop, obj[prop]])
+ //console.log("found " + obj[prop] + " at index " + prop)
+ }
+ }
+
+ routes.sort(function(a, b) {
+ return a[0] - b[0];
+ });
+
+ return routes
+ }
+
+ delegate: Item {
+ id: boulderGenResItm
+
+ anchors.verticalCenter: parent.verticalCenter
+
+ width: parent.width / ( generalResRep.model )
+ height: parent.height
+
+ visible: boulderGenResLa.text != ""
+
+ Rectangle {
+
+ anchors {
+ left: parent.left
+ }
+
+ width: 1
+ height: parent.height
+
+ visible: index === 0
+
+ color: "grey"
+ }
+
+ Rectangle {
+ anchors {
+ right: parent.right
+ }
+
+ width: 1
+ height: parent.height
+
+ color: "grey"
+ }
+
+ Label {
+ id: boulderGenResLa
+ anchors.centerIn: parent
+
+ height: parent.height
+ width: parent.width * 0.9
+
+ fontSizeMode: Text.Fit
+ font.pixelSize: Math.abs( height * 0.6 )
+ minimumPixelSize: 0
+ verticalAlignment: Text.AlignVCenter
+ horizontalAlignment: Text.AlignHCenter
+
+ text: listData[ "participants" ][partDel.ind]["result"+(generalResRep.routes[index][0])] === undefined ? "":listData[ "participants" ][partDel.ind]["result"+(generalResRep.routes[index][0])]
+ }
+
+ }
+
+ }
+ }
+
+ Label {
+ id: resultLa
+
+ width: enabled ? parent.width * 0.25:0
+ height: enabled ? parent.height:0
+
+ enabled: ( boulderResRep.model > 0 || listData["discipline"] !== "boulder" ) && parseInt(listData[ "route_order" ]) > -1
+
+ verticalAlignment: Text.AlignVCenter
+ horizontalAlignment: Text.AlignHCenter
+
+ fontSizeMode: Text.Fit
+ font.pixelSize: Math.abs( height * 0.6 )
+ minimumPixelSize: 0
+
+ text: listData[ "participants" ][partDel.ind]["result"] === undefined ? "":listData[ "participants" ][partDel.ind]["result"]
+ }
+ }
+ }
+ }
+}
diff --git a/resources/qml/Components/RegistrationView.qml b/resources/qml/Components/RegistrationView.qml
new file mode 100644
index 0000000..b2aab09
--- /dev/null
+++ b/resources/qml/Components/RegistrationView.qml
@@ -0,0 +1,45 @@
+import QtQuick 2.0
+import QtQuick.Controls 2.4
+
+DataListView {
+ id: control
+
+ property var listData: ({})
+
+ model: listData[ root.listKey ] === undefined ? 0:listData[ root.listKey ].length
+
+ delegate: ItemDelegate {
+ id: partDel
+
+ width: parent.width
+
+ text: control.getText(index)
+ }
+
+ function getText(index){
+
+ // ----------------------------
+ // if we have registration data
+
+ var fedName // federation name
+
+ if(listData["federations"] !== undefined){
+ // not an international competition -> get name of federation
+
+ for(var i = 0; i < listData["federations"].length; i ++ ){
+ //console.log("checking " + i + ": cat: " + parseInt(listData["categorys"][i]["GrpId"]) + " searched cat: " + root.catId)
+ if(listData["federations"][i]["fed_id"] === listData[ root.listKey ][index]["reg_fed_id"]){
+ fedName = listData["federations"][i]["shortcut"]
+ }
+ }
+ }
+ else {
+ // an international competition -> get nation
+
+ fedName = listData[ root.listKey ][index]["nation"]
+ }
+
+ return listData[ "athletes" ][index]["firstname"] + " " + listData[ "athletes" ][index]["lastname"] + " (" + fedName + ")"
+ }
+
+}
diff --git a/resources/qml/Pages/CompetitionCalendarPage.qml b/resources/qml/Pages/CompetitionCalendarPage.qml
new file mode 100644
index 0000000..b761d14
--- /dev/null
+++ b/resources/qml/Pages/CompetitionCalendarPage.qml
@@ -0,0 +1,183 @@
+import QtQuick 2.0
+import QtQuick.Controls 2.4
+import QtQuick.Controls.Material 2.3
+
+import "../Components"
+
+Page {
+ id: root
+
+ title: "calendar"
+
+ property string nation: ""
+ property int status: -1
+
+ Component.onCompleted: {
+ var ret = serverConn.getCalendar(nation)
+
+ if(ret["status"] === 200){
+ root.status = 200
+ calendarList.listData = ret["data"]["competitions"]
+ }
+ else {
+ root.status = ret["status"]
+ calendarList.listData = {}
+ }
+ }
+
+ InfoArea {
+ id: infoArea
+
+ anchors {
+ left: parent.left
+ right: parent.right
+ top: parent.top
+ margins: app.landscape() ? parent.width * 0.4:parent.width * 0.3
+ topMargin: parent.height*( status === 901 ? 0.6:0.5) - height * 0.8
+ }
+
+ excludedCodes: [200, 902]
+ errorCode: root.status
+ }
+
+ ListView {
+ id: calendarList
+
+ property var listData
+
+ anchors.fill: parent
+
+ boundsBehavior: Flickable.StopAtBounds
+
+ model: listData.length
+
+ delegate: ItemDelegate {
+ id: competitionDel
+
+ property string name: calendarList.listData[index]["name"]
+ property string date: calendarList.listData[index]["date_span"]
+ property var cats: calendarList.listData[index]["cats"]
+ property int catId: calendarList.listData[index]["cat_id"]
+
+ width: parent.width
+ height: compDelCol.height + 10
+
+ onClicked: {
+ catSelectPu.appear(index)
+ }
+
+ Rectangle {
+ id: delBackroundRect
+
+ anchors.fill: parent
+
+ opacity: 0.5
+
+ color: app.competitionCategoryColors[catId]
+
+ }
+
+ Column {
+ id: compDelCol
+
+ anchors.centerIn: parent
+
+ width: parent.width * 0.97
+
+ spacing: 10
+
+ Label {
+ id: nameLa
+
+ width: parent.width
+
+ font.bold: true
+
+ wrapMode: Text.WordWrap
+
+ text: name
+ }
+
+ Label {
+ id: dateLa
+
+ color: "grey"
+
+ text: date
+ }
+
+ Label {
+ id: catIdLa
+
+ color: "grey"
+
+ text: catId
+ }
+ }
+
+ Rectangle {
+ id: bottomLineRa
+
+ anchors {
+ bottom: parent.bottom
+ left: parent.left
+ right: parent.right
+ }
+
+ height: 1
+
+ color: "lightgrey"
+
+ }
+ }
+ }
+
+ Dialog {
+ id: catSelectPu
+
+ property int index: -1
+ property var catObj: calendarList.listData[catSelectPu.index] !== undefined ? calendarList.listData[catSelectPu.index]["cats"]:undefined
+
+ x: root.width / 2 - width / 2
+ y: root.height / 2 - height / 2
+
+ width: root.width * 0.8
+ height: root.height * 0.6
+
+ modal: true
+ focus: true
+
+ title: qsTr("select category")
+
+ function appear(index) {
+ catSelectPu.open()
+ catSelectPu.index = index
+ }
+
+ contentItem: ListView {
+ id: catsLv
+
+ width: parent.width
+ height: root.height * 0.6
+
+ model: catSelectPu.catObj !== undefined ? catSelectPu.catObj.length:0
+
+ delegate: Button {
+ id: catBt
+
+ width: parent.width
+
+ flat: true
+
+ text: catSelectPu.catObj[index]["name"]
+
+ onClicked: {
+ catSelectPu.close()
+ app.openResults(calendarList.listData[catSelectPu.index]["WetId"], catSelectPu.catObj[index]["GrpId"], (catSelectPu.catObj[index]["status"] === 4 || catSelectPu.catObj[index]["status"] === undefined))
+ }
+ }
+ }
+
+ }
+
+}
diff --git a/resources/qml/Pages/RankingPage.qml b/resources/qml/Pages/RankingPage.qml
new file mode 100644
index 0000000..ebeb810
--- /dev/null
+++ b/resources/qml/Pages/RankingPage.qml
@@ -0,0 +1,236 @@
+import QtQuick 2.0
+import QtQuick.Controls 2.4
+import QtGraphicalEffects 1.0
+
+import "../Components"
+
+Page {
+ id: root
+
+ title: root.rankingData[compNameKey]
+ property string subTitle: getSubtitle()
+ property bool titleIsPageTitle: true
+
+ property int status: -1
+
+ property bool debug: true
+
+ property int comId: -1
+ property int catId: -1
+ property int routeNumber: -2
+ property bool reg: false
+
+ property var rankingData
+
+ property string listKey: root.reg ? "athletes":"participants"
+ property string compNameKey: root.reg ? "name":"comp_name"
+
+ Component.onCompleted: {
+ root.loadData(root.comId, root.catId, root.reg, root.routeNumber)
+ }
+
+ function loadData(comp, cat, reg, route){
+ loadingDl.open()
+ console.log("[info][QML] getting ranking data of comp: " + comp + " and cat: " + cat + " reg: " + reg)
+ var ret = serverConn.getRanking(comp, cat, reg, route)
+
+ root.status = ret["status"]
+
+ if(parseInt(ret["status"]) === 200){
+ // request was successfull -> prepare data
+ if(root.reg){
+ // if the data i sregistration data, athletes of other cats need to be removed
+
+ var validAthletes = []
+
+ for(var i = 0; i < ret["data"]["athletes"].length; i++){
+ if(parseInt(ret["data"]["athletes"][i]["cat"]) === cat){
+ //console.log("found matching athlete at " + i)
+ validAthletes.push(ret["data"]["athletes"][i])
+ }
+ }
+ ret["data"]["athletes"] = validAthletes
+
+ root.rankingData = ret["data"]
+ }
+ else {
+ root.rankingData = ret["data"]
+ root.routeNumber = root.rankingData["route_order"] === undefined ? -2:root.rankingData["route_order"]
+ }
+ }
+ else {
+ root.rankingData = {}
+ }
+
+
+ if(ret["data"][ root.listKey ] === undefined || ret["data"][ root.listKey ].length < 1){
+ root.status = 901
+ }
+
+ console.log("done! status: " + root.status)
+ loadingDl.close()
+ }
+
+ function getSubtitle() {
+ var titleString
+
+ //console.log("getting title, reg: " + root.reg)
+
+ if(reg){
+ for(var i = 0; i < root.rankingData["categorys"].length; i ++ ){
+ //console.log("checking " + i + ": cat: " + parseInt(root.rankingData["categorys"][i]["GrpId"]) + " searched cat: " + root.catId)
+ if(parseInt(root.rankingData["categorys"][i]["GrpId"]) === root.catId){
+ titleString = root.rankingData["categorys"][i]["name"]
+ }
+ }
+ }
+ else {
+ titleString = root.rankingData["route_name"]
+ }
+
+ return titleString
+
+ }
+
+ Item {
+ id: regItm
+ // item for registration view
+
+ anchors.fill: parent
+
+ visible: root.reg
+
+ RegistrationView {
+ id: regViewRv
+
+ anchors.fill: parent
+
+ status: root.status
+
+ listData: root.reg ? root.rankingData:({})
+
+ }
+ }
+
+ Item {
+ id: rankItm
+ // item for ranking data
+
+ anchors.fill: parent
+
+ visible: !root.reg
+
+ RankingView {
+ id: rankViewRv
+
+ anchors {
+ left: parent.left
+ right: parent.right
+ top: parent.top
+ bottom: routeSelectTb.top
+ }
+
+ height: root.height - routeSelectTb.height
+
+ status: root.status
+
+ listData: root.reg ? ({}):root.rankingData
+
+ onListDataChanged: {
+ console.log("list data changed")
+ }
+ }
+
+ RectangularGlow {
+ id: toolBarEffect
+ glowRadius: 3
+ spread: 0.2
+ color: "black"
+ opacity: 0.3
+ anchors.fill: routeSelectTb
+ }
+
+ TabBar {
+ id: routeSelectTb
+
+ property var tabs: getTabs()
+ property var tabIndexes: []
+
+ anchors {
+ left: parent.left
+ right: parent.right
+ bottom: parent.bottom
+ }
+
+ height: tabs.length > 0 ? 50:0
+
+ position: TabBar.Footer
+
+ Component.onCompleted: {
+ //currentIndex = getIndex(root.routeNumber)
+ setCurrentIndex(getIndex(root.routeNumber))
+ }
+
+ function getTabs() {
+
+ var obj = root.rankingData["route_names"]
+ var buttonData = []
+
+ for(var prop in obj) {
+ // go through the whole array and search for data keys
+ if (obj.hasOwnProperty(prop)) {
+ buttonData.push([prop, obj[prop]])
+ console.log("found " + obj[prop] + " at index " + prop)
+ }
+ }
+
+ buttonData.sort(function(a, b) {
+ return a[0] - b[0];
+ });
+
+ return buttonData
+ }
+
+ function getIndex(routeNumber) {
+ console.log("getting index for route number: " + routeNumber)
+
+ for(var i = 0; i < tabs.length; i++){
+ //console.log(tabs[i])
+ if(parseInt(tabs[i][0]) === routeNumber){
+ console.log("found index: " + i)
+ return i
+ }
+ }
+
+
+ return 0
+ }
+
+ Repeater {
+ id: routeSelectButtonRep
+
+ model: routeSelectTb.tabs.length
+
+ onModelChanged: {
+ routeSelectTb.setCurrentIndex(routeSelectTb.getIndex(root.routeNumber))
+ }
+
+ delegate: TabButton {
+ text: routeSelectTb.tabs[index][1]
+
+ 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] + ")")
+ if(root.routeNumber !== routeSelectTb.tabs[index][0]){
+ root.routeNumber = routeSelectTb.tabs[index][0]
+ root.loadData(root.comId, root.catId, root.reg, root.routeNumber)
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/resources/qml/Pages/StartPage.qml b/resources/qml/Pages/StartPage.qml
new file mode 100644
index 0000000..059c5de
--- /dev/null
+++ b/resources/qml/Pages/StartPage.qml
@@ -0,0 +1,67 @@
+import QtQuick 2.0
+import QtQuick.Controls 2.4
+
+import "../Components"
+
+Page {
+ id: root
+
+ title: "start"
+
+ Grid {
+ id: menuGr
+
+ anchors.centerIn: parent
+
+ rows: app.landscape() ? 1:3
+ columns: app.landscape() ? 3:1
+
+ spacing: app.landscape() ? parent.height * 0.1:parent.width * 0.1
+
+ property int buttonSize: app.landscape() ? parent.width * 0.2:parent.height * 0.2
+
+ FancyButton {
+ id: ifscBt
+
+ height: menuGr.buttonSize
+ width: height
+
+ image: "qrc:/icons/ifsc.png"
+
+ onClicked: {
+ app.openCalendar("")
+ }
+
+ }
+
+ FancyButton {
+ id: davBt
+
+ height: menuGr.buttonSize
+ width: height
+
+ image: "qrc:/icons/dav.png"
+
+ onClicked: {
+ app.openCalendar("GER")
+ }
+
+ }
+
+ FancyButton {
+ id: sacBt
+
+ height: menuGr.buttonSize
+ width: height
+
+ image: "qrc:/icons/sac.png"
+
+ onClicked: {
+ app.openCalendar("SUI")
+ }
+
+ }
+
+ }
+
+}
diff --git a/resources/qml/main.qml b/resources/qml/main.qml
new file mode 100644
index 0000000..bafbf1f
--- /dev/null
+++ b/resources/qml/main.qml
@@ -0,0 +1,351 @@
+import QtQuick 2.9
+import QtQuick.Window 2.2
+import QtQuick.Controls 2.4
+
+import com.itsblue.digitalRockRanking 1.0
+
+import "./Pages"
+import "./Components"
+
+Window {
+ visible: true
+ width: 540
+ height: 960
+ title: qsTr("Digital Rock Ranking")
+
+ Page {
+ id: app
+
+ property var competitionCategoryColors: {
+ "61": "lightgrey",
+ "58": "lightgreen",
+
+ "69": "#B8C8FF",
+ "70": "#F0F0F0",
+ "71": "#D8E8FF",
+ "256": "#D8E8FF"
+ }
+
+ anchors.fill: parent
+
+ Shortcut {
+ sequences: ["Esc", "Back"]
+ enabled: mainStack.depth > 1
+ onActivated: {
+ if(!mainStack.currentItem.locked){
+ mainStack.pop()
+ }
+ }
+ }
+
+ ServerConn {
+ id: serverConn
+
+ Component.onCompleted: {
+ //serverConn.refreshFoodplan()
+ }
+ }
+
+ StackView {
+ id: mainStack
+
+ anchors {
+ top: toolBar.bottom
+ left: parent.left
+ right: parent.right
+ bottom: parent.bottom
+ }
+
+ initialItem: startPgComp
+
+ Component {
+ id: startPgComp
+ StartPage {}
+ }
+
+ popEnter: Transition {
+ XAnimator {
+ from: (mainStack.mirrored ? -1 : 1) * -mainStack.width
+ to: 0
+ duration: 500
+ easing.type: Easing.OutCubic
+ }
+ }
+
+ popExit: Transition {
+ XAnimator {
+ from: 0
+ to: (mainStack.mirrored ? -1 : 1) * mainStack.width
+ duration: 500
+ easing.type: Easing.OutCubic
+ }
+ }
+
+ pushEnter: Transition {
+ XAnimator {
+ from: (mainStack.mirrored ? -1 : 1) * mainStack.width
+ to: 0
+ duration: 500
+ easing.type: Easing.OutCubic
+ }
+ }
+
+ pushExit: Transition {
+ XAnimator {
+ from: 0
+ to: (mainStack.mirrored ? -1 : 1) * -mainStack.width
+ duration: 500
+ easing.type: Easing.OutCubic
+ }
+ }
+ }
+
+ AppToolBar {
+ id: toolBar
+
+ anchors {
+ top: parent.top
+ left: parent.left
+ right: parent.right
+ topMargin: -60
+ }
+
+ height: 50
+
+ Button {
+ id:toolButton
+ enabled: true
+ anchors {
+ left: parent.left
+ verticalCenter: parent.verticalCenter
+ leftMargin: parent.width *0.02
+ }
+ height: parent.height - parent.height * 0.5
+ width: height
+
+ onClicked: {
+ if(!mainStack.currentItem.locked){
+ mainStack.pop()
+ }
+ }
+
+ onPressed: toolButton.scale = 0.9
+ onReleased: toolButton.scale = 1.0
+
+ background: Image {
+ source: "qrc:/icons/backDark.png"
+ height: parent.height
+ width: parent.width
+ fillMode: Image.PreserveAspectFit
+ Behavior on scale {
+ PropertyAnimation {
+ duration: 100
+ }
+ }
+ }
+ }
+
+ Label {
+ id: toolBarTitleLa
+
+
+ anchors {
+ verticalCenter: parent.verticalCenter
+ verticalCenterOffset: -toolBarSubTitleLa.anchors.verticalCenterOffset
+ left: toolButton.right
+ leftMargin: parent.width * 0.02
+ right: parent.right
+ }
+
+ elide: "ElideRight"
+
+ font.bold: true
+
+ color: "black"
+
+ text: getText()
+
+ function getText(){
+ var titleString = "";
+
+ if(!mainStack.currentItem.titleIsPageTitle){
+ for(var i=1; i 1){
+ titleString += " > "
+ }
+
+ titleString += mainStack.get(i).title
+ }
+ }
+ else {
+ titleString = mainStack.currentItem.title
+ }
+
+ return(titleString)
+ }
+ }
+
+ Label {
+ id: toolBarSubTitleLa
+
+ anchors {
+ verticalCenter: parent.verticalCenter
+ verticalCenterOffset: toolBarSubTitleLa.text !== "" ? height/2:0
+ left: toolButton.right
+ leftMargin: parent.width * 0.02
+ right: parent.right
+ }
+
+ elide: "ElideRight"
+
+ font.bold: false
+
+ color: "black"
+
+ text: getText()
+
+ function getText(){
+ var titleString = "";
+
+ if(mainStack.currentItem.subTitle !== undefined){
+ titleString = mainStack.currentItem.subTitle
+ }
+
+ return(titleString)
+ }
+ }
+
+ Behavior on anchors.topMargin {
+ NumberAnimation {
+ duration: 500
+ easing.type: Easing.OutCubic
+ }
+ }
+
+ states: [
+ State {
+ name: "closed"
+ when: mainStack.depth === 1
+ PropertyChanges {
+ target: toolBar
+ anchors.topMargin: -60
+ }
+ },
+ State {
+ name: "open"
+ when: mainStack.depth > 1
+ PropertyChanges {
+ target: toolBar
+ anchors.topMargin: 0
+ }
+ }
+ ]
+ }
+
+ Dialog {
+ id: loadingDl
+
+ x: ( app.width - width ) / 2
+ y: ( app.height - height ) / 2
+
+ modal: true
+ closePolicy: Dialog.NoAutoClose
+
+ contentItem: Column {
+ FancyBusyIndicator {
+ running: true
+ }
+
+ Label {
+
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ font.bold: true
+
+ text: "loading..."
+ }
+ }
+
+ }
+
+ function landscape(){
+ return app.height < app.width
+ }
+
+ function openCalendar(nation){
+ loadingDl.open()
+ mainStack.push(Qt.createComponent("qrc:/Pages/CompetitionCalendarPage.qml").createObject(null, {"nation": nation}))
+ loadingDl.close()
+ }
+
+ function openResults(comp, cat, reg){
+ // comp: (int) competiotion ID
+ // cat: (int) category ID
+ // reg: (bool) false: results; true: registrations
+
+ //loadingDl.open()
+ mainStack.push(Qt.createComponent("qrc:/Pages/RankingPage.qml").createObject(null, {"comId": comp, "catId": cat, "reg": reg}))
+ //loadingDl.close()
+ }
+
+ function getErrorInfo(errorCode) {
+
+ var infoLevel
+ // 0 - ok
+ // 1 - info
+ // 2 - error
+
+ var errorString
+ var errorDescription
+
+ switch(errorCode) {
+ case 0:
+ infoLevel = 2
+ errorString = "No connection to server"
+ errorDescription = "Please check your internet connection and try again."
+ break
+ case 401:
+ infoLevel = 2
+ errorString = "Authentication required"
+ errorDescription = "The server asked for user credentinals, please chack them and try again"
+ break
+ case 500:
+ infoLevel = 2
+ errorString = "Internal server error"
+ errorDescription = "The server was unable to process this request, this is probaply the servers vault. Please try again later."
+ break
+ case 900:
+ infoLevel = 2
+ errorString = "Internal processing error"
+ errorDescription = "The server has sent some data that could ot be processed. Please try again later"
+ break
+ case 901:
+ infoLevel = 1
+ errorString = "No Data"
+ errorDescription = "There is currently no data available. Please try again later."
+ break
+ case 902:
+ infoLevel = 1
+ errorString = "Alte Daten"
+ errorDescription = "Es konnte keine Verbindung zum Server hergestellt werden, aber es sind noch alte Daten gespeichert."
+ break
+ case 903:
+ infoLevel = 1
+ errorString = "Ungültiger Aufruf"
+ errorDescription = "Die aufgerufene Funktion ist momentan nicht verfügbar, bitte versuche es später erneut."
+ break
+ case 904:
+ infoLevel = 2
+ errorString = "Incompatible API"
+ errorDescription = "Please make shure that you are using the latest version of this app and try again."
+ break
+ default:
+ infoLevel = 2
+ errorString = "Unexpected error ("+errorCode+")"
+ errorDescription = "Unexpected error while getting data from the server. Please try again later."
+ }
+
+ return([infoLevel, errorString, errorDescription])
+ }
+ }
+}
diff --git a/resources/qml/qml.qrc b/resources/qml/qml.qrc
new file mode 100644
index 0000000..badc274
--- /dev/null
+++ b/resources/qml/qml.qrc
@@ -0,0 +1,15 @@
+
+
+ main.qml
+ Pages/CompetitionCalendarPage.qml
+ Pages/RankingPage.qml
+ Pages/StartPage.qml
+ Components/FancyButton.qml
+ Components/AppToolBar.qml
+ Components/FancyBusyIndicator.qml
+ Components/InfoArea.qml
+ Components/DataListView.qml
+ Components/RankingView.qml
+ Components/RegistrationView.qml
+
+
diff --git a/resources/shared/icons/back.png b/resources/shared/icons/back.png
new file mode 100644
index 0000000..d1740cd
Binary files /dev/null and b/resources/shared/icons/back.png differ
diff --git a/resources/shared/icons/backDark.png b/resources/shared/icons/backDark.png
new file mode 100644
index 0000000..c55ab31
Binary files /dev/null and b/resources/shared/icons/backDark.png differ
diff --git a/resources/shared/icons/dav.png b/resources/shared/icons/dav.png
new file mode 100644
index 0000000..055d1d2
Binary files /dev/null and b/resources/shared/icons/dav.png differ
diff --git a/resources/shared/icons/dig_rock.klein.jpg b/resources/shared/icons/dig_rock.klein.jpg
new file mode 100644
index 0000000..7170811
Binary files /dev/null and b/resources/shared/icons/dig_rock.klein.jpg differ
diff --git a/resources/shared/icons/dig_rock.klein.png b/resources/shared/icons/dig_rock.klein.png
new file mode 100644
index 0000000..0eb0963
Binary files /dev/null and b/resources/shared/icons/dig_rock.klein.png differ
diff --git a/resources/shared/icons/favicon.png b/resources/shared/icons/favicon.png
new file mode 100644
index 0000000..15f210f
Binary files /dev/null and b/resources/shared/icons/favicon.png differ
diff --git a/resources/shared/icons/favicon.xcf b/resources/shared/icons/favicon.xcf
new file mode 100644
index 0000000..5cdba7f
Binary files /dev/null and b/resources/shared/icons/favicon.xcf differ
diff --git a/resources/shared/icons/ifsc.png b/resources/shared/icons/ifsc.png
new file mode 100644
index 0000000..993f23a
Binary files /dev/null and b/resources/shared/icons/ifsc.png differ
diff --git a/resources/shared/icons/json.php.json b/resources/shared/icons/json.php.json
new file mode 100644
index 0000000..6a8f597
--- /dev/null
+++ b/resources/shared/icons/json.php.json
@@ -0,0 +1 @@
+{"WetId":"8422","GrpId":"11","route_order":"-1","route_name":"Gesamtergebnis m\u00e4nnliche Jugend A","route_result":"16.3.2019, 18:56:58","discipline":"boulder2018","comp_name":"1. Deutscher Jugendcup (B) 2019 - Bexbach","comp_date":"2019-03-16","nation":"GER","display_athlete":"fed_and_parent","route_names":{"0":"Qualifikation","2":"Finale","-1":"General Result"},"participants":[{"PerId":"52991","acl":"63","birthyear":2002,"city":"H\u00f6chberg","fed_id":"565","fed_parent":"460","federation":"W\u00fcrzburg","firstname":"Tim","lastname":"W\u00fcrthner","nation":"GER","parent_fed":"Bayern","result0":"5T6z\u00a06\u00a08","result2":"3T4z\u00a05\u00a014","result_modified":"1552740095","result_rank":1,"result_rank0":"5","result_rank2":"1","rkey":"TWU14M","start_number":"312","start_order":"12","top_tries":6,"tops":5,"url":"https:\/\/www.digitalrock.de\/egroupware\/ranking\/sitemgr\/digitalrock\/pstambl.html#person=52991&cat=11","zone_tries":8,"zones":6},{"PerId":"53096","acl":"63","birthyear":2002,"city":"Hannover","fed_id":"325","fed_parent":"464","fed_url":"http:\/\/alpinclub-hannover.de\/","federation":"AlpinClub Hannover","firstname":"Lasse","lastname":"von Freier","nation":"GER","parent_fed":"Nord","result0":"6T6z\u00a09\u00a07","result2":"3T4z\u00a06\u00a013","result_modified":"1552739015","result_rank":2,"result_rank0":"1","result_rank2":"2","rkey":"LFR14M2","start_number":"317","start_order":"17","top_tries":9,"tops":6,"url":"https:\/\/www.digitalrock.de\/egroupware\/ranking\/sitemgr\/digitalrock\/pstambl.html#person=53096&cat=11","zone_tries":7,"zones":6},{"PerId":"52993","acl":"63","birthyear":2003,"city":"Buxheim","fed_id":"474","fed_parent":"460","fed_url":"http:\/\/www.dav-ingolstadt.de\/","federation":"Ingolstadt","firstname":"Philipp","lastname":"Kuczora","nation":"GER","parent_fed":"Bayern","result0":"5T6z\u00a08\u00a09","result2":"3T4z\u00a08\u00a013","result_modified":"1552739372","result_rank":3,"result_rank0":"6","result_rank2":"3","rkey":"PKU14M","start_number":"308","start_order":"8","top_tries":8,"tops":5,"url":"https:\/\/www.digitalrock.de\/egroupware\/ranking\/sitemgr\/digitalrock\/pstambl.html#person=52993&cat=11","zone_tries":9,"zones":6},{"PerId":"54545","acl":"63","birthyear":2003,"city":"Olching","fed_id":"40","fed_parent":"460","fed_url":"http:\/\/www.alpenverein-muenchen-oberland.de\/","federation":"M\u00fcnchen-Oberland","firstname":"Julius","lastname":"R\u00fcth","nation":"GER","parent_fed":"Bayern","result0":"5T6z\u00a010\u00a010","result2":"2T3z\u00a07\u00a016","result_modified":"1552740798","result_rank":4,"result_rank0":"8","result_rank2":"4","rkey":"JR15M","start_number":"310","start_order":"10","top_tries":10,"tops":5,"url":"https:\/\/www.digitalrock.de\/egroupware\/ranking\/sitemgr\/digitalrock\/pstambl.html#person=54545&cat=11","zone_tries":10,"zones":6},{"PerId":"55798","acl":"63","birthyear":2002,"city":"Saarbr\u00fccken","fed_id":"515","fed_parent":"469","fed_url":"http:\/\/www.dav-saarbruecken.de\/","federation":"ASS Saarbr\u00fccken","firstname":"Nils","lastname":"Siegel","nation":"GER","parent_fed":"Saar","result0":"5T6z\u00a011\u00a08","result2":"2T3z\u00a09\u00a09","result_modified":"1552741078","result_rank":5,"result_rank0":"10","result_rank2":"5","rkey":"NSI16M","start_number":"327","start_order":"26","top_tries":11,"tops":5,"url":"https:\/\/www.digitalrock.de\/egroupware\/ranking\/sitemgr\/digitalrock\/pstambl.html#person=55798&cat=11","zone_tries":8,"zones":6},{"PerId":"53136","acl":"63","birthyear":2002,"city":"Cleebronn","fed_id":"321","fed_parent":"461","fed_url":"http:\/\/www.dav-heilbronn.de\/","federation":"Heilbronn","firstname":"Luca","lastname":"Jung","nation":"GER","parent_fed":"Baden-W.","result0":"6T6z\u00a014\u00a010","result2":"2T3z\u00a09\u00a010","result_modified":"1552740354","result_rank":6,"result_rank0":"3","result_rank2":"6","rkey":"LJU14M","start_number":"302","start_order":"2","top_tries":14,"tops":6,"url":"https:\/\/www.digitalrock.de\/egroupware\/ranking\/sitemgr\/digitalrock\/pstambl.html#person=53136&cat=11","zone_tries":10,"zones":6},{"PerId":"53058","acl":"63","birthyear":2002,"city":"Freising","fed_id":"182","fed_parent":"460","fed_url":"http:\/\/www.dav-freising.de\/","federation":"Freising","firstname":"Jannik","lastname":"Weiser","nation":"GER","parent_fed":"Bayern","result0":"5T6z\u00a010\u00a014","result2":"2T2z\u00a03\u00a03","result_modified":"1552740265","result_rank":7,"result_rank0":"9","result_rank2":"7","rkey":"JWE14M","start_number":"311","start_order":"11","top_tries":10,"tops":5,"url":"https:\/\/www.digitalrock.de\/egroupware\/ranking\/sitemgr\/digitalrock\/pstambl.html#person=53058&cat=11","zone_tries":14,"zones":6},{"PerId":"52967","acl":"63","birthyear":2003,"city":"Landshut","fed_id":"277","fed_parent":"460","fed_url":"http:\/\/www.alpenverein-landshut.de\/","federation":"Landshut","firstname":"Ludwig","lastname":"Breu","nation":"GER","parent_fed":"Bayern","result0":"5T6z\u00a09\u00a011","result2":"2T2z\u00a05\u00a05","result_modified":"1552740942","result_rank":8,"result_rank0":"7","result_rank2":"8","rkey":"LBR14M","start_number":"306","start_order":"6","top_tries":9,"tops":5,"url":"https:\/\/www.digitalrock.de\/egroupware\/ranking\/sitemgr\/digitalrock\/pstambl.html#person=52967&cat=11","zone_tries":11,"zones":6},{"PerId":"56552","acl":"63","birthyear":2002,"city":"Marburg","fed_id":"282","fed_parent":"462","fed_url":"http:\/\/alpenverein-frankfurtmain.de\/","federation":"Frankfurt\/Main","firstname":"Frederik","lastname":"Schmelzer","nation":"GER","parent_fed":"Hessen","result0":"6T6z\u00a016\u00a011","result2":"1T2z\u00a02\u00a03","result_modified":"1552740833","result_rank":9,"result_rank0":"4","result_rank2":"9","rkey":"FSC16M","start_number":"315","start_order":"15","top_tries":16,"tops":6,"url":"https:\/\/www.digitalrock.de\/egroupware\/ranking\/sitemgr\/digitalrock\/pstambl.html#person=56552&cat=11","zone_tries":11,"zones":6},{"PerId":"63689","acl":"63","birthyear":2002,"city":"Namborn","fed_id":"180","fed_parent":"469","fed_url":"http:\/\/www.bergfreunde-saar.de\/","federation":"Bergfreunde Saar","firstname":"Elias","lastname":"Schmitt","nation":"GER","parent_fed":"Saar","result0":"6T6z\u00a010\u00a07","result2":"0T3z\u00a00\u00a010","result_modified":"1552739944","result_rank":10,"result_rank0":"2","result_rank2":"10","rkey":"ESC17M","start_number":"326","start_order":"25","top_tries":10,"tops":6,"url":"https:\/\/www.digitalrock.de\/egroupware\/ranking\/sitemgr\/digitalrock\/pstambl.html#person=63689&cat=11","zone_tries":7,"zones":6},{"PerId":"55692","acl":"63","birthyear":2003,"city":"A\u00dflar-Werdorf","fed_id":"436","fed_parent":"462","fed_url":"http:\/\/www.dav-wetzlar.de\/","federation":"Wetzlar","firstname":"Henri","lastname":"Breuer","nation":"GER","parent_fed":"Hessen","result0":"4T6z\u00a05\u00a08","result_modified":"1552740352","result_rank":11,"result_rank0":"11","rkey":"HBR16M","start_number":"314","start_order":"14","top_tries":5,"tops":4,"url":"https:\/\/www.digitalrock.de\/egroupware\/ranking\/sitemgr\/digitalrock\/pstambl.html#person=55692&cat=11","zone_tries":8,"zones":6},{"PerId":"53054","acl":"63","birthyear":2002,"city":"M\u00fcnchen","fed_id":"40","fed_parent":"460","fed_url":"http:\/\/www.alpenverein-muenchen-oberland.de\/","federation":"M\u00fcnchen-Oberland","firstname":"Luis","lastname":"Funk","nation":"GER","parent_fed":"Bayern","result0":"4T6z\u00a05\u00a010","result_modified":"1552740045","result_rank":12,"result_rank0":"12","rkey":"LFU14M","start_number":"307","start_order":"7","top_tries":5,"tops":4,"url":"https:\/\/www.digitalrock.de\/egroupware\/ranking\/sitemgr\/digitalrock\/pstambl.html#person=53054&cat=11","zone_tries":10,"zones":6},{"PerId":"54374","acl":"63","birthyear":2002,"city":"Oberisling","fed_id":"185","fed_parent":"460","fed_url":"http:\/\/www.alpenverein-regensburg.de\/","federation":"Regensburg","firstname":"Luca","lastname":"Lindig","nation":"GER","parent_fed":"Bayern","result0":"4T6z\u00a011\u00a09","result_modified":"1552741938","result_rank":13,"result_rank0":"13","rkey":"LLI15M","start_number":"309","start_order":"9","top_tries":11,"tops":4,"url":"https:\/\/www.digitalrock.de\/egroupware\/ranking\/sitemgr\/digitalrock\/pstambl.html#person=54374&cat=11","zone_tries":9,"zones":6},{"PerId":"53035","acl":"63","birthyear":2002,"city":"Burgrieden-Rot","fed_id":"658","fed_parent":"460","federation":"SG Ulm, Neu-Ulm, SSV Ulm","firstname":"Linus","lastname":"Bader","nation":"GER","parent_fed":"Bayern","result0":"4T5z\u00a05\u00a05","result_modified":"1552740500","result_rank":14,"result_rank0":"14","rkey":"LBA14M","start_number":"305","start_order":"5","top_tries":5,"tops":4,"url":"https:\/\/www.digitalrock.de\/egroupware\/ranking\/sitemgr\/digitalrock\/pstambl.html#person=53035&cat=11","zone_tries":5,"zones":5},{"PerId":"55683","acl":"63","birthyear":2002,"city":"Herrenberg","fed_id":"339","fed_parent":"461","fed_url":"http:\/\/www.dav-tuebingen.de\/","federation":"T\u00fcbingen","firstname":"David","lastname":"Dongus","nation":"GER","parent_fed":"Baden-W.","result0":"4T5z\u00a010\u00a012","result_modified":"1552740967","result_rank":15,"result_rank0":"15","rkey":"DDO16M","start_number":"301","start_order":"1","top_tries":10,"tops":4,"url":"https:\/\/www.digitalrock.de\/egroupware\/ranking\/sitemgr\/digitalrock\/pstambl.html#person=55683&cat=11","zone_tries":12,"zones":5},{"PerId":"66676","acl":"63","birthyear":2003,"city":"Vallgorguina","fed_id":"173","fed_parent":"465","fed_url":"http:\/\/www.dav-frankenthal.de\/","federation":"Frankenthal","firstname":"Cedric Lluc","lastname":"Milles","nation":"GER","parent_fed":"RL-Pfalz","result0":"4T4z\u00a07\u00a07","result_modified":"1552739722","result_rank":16,"result_rank0":"16","rkey":"CMI17M","start_number":"323","start_order":"22","top_tries":7,"tops":4,"url":"https:\/\/www.digitalrock.de\/egroupware\/ranking\/sitemgr\/digitalrock\/pstambl.html#person=66676&cat=11","zone_tries":7,"zones":4},{"PerId":"63693","acl":"63","birthyear":2003,"city":"St. Wendel","fed_id":"852","fed_parent":"469","fed_url":"http:\/\/www.sbsb-saar.de\/index.php?id=379","federation":"Generation Rocklands","firstname":"Luca","lastname":"Kaul","nation":"GER","parent_fed":"Saar","result0":"3T5z\u00a05\u00a08","result_modified":"1552740715","result_rank":17,"result_rank0":"17","rkey":"LKA17M","start_number":"325","start_order":"24","top_tries":5,"tops":3,"url":"https:\/\/www.digitalrock.de\/egroupware\/ranking\/sitemgr\/digitalrock\/pstambl.html#person=63693&cat=11","zone_tries":8,"zones":5},{"PerId":"55591","acl":"63","birthyear":2002,"city":"Gottmadingen","fed_id":"105","fed_parent":"461","fed_url":"http:\/\/www.dav-konstanz.de\/","federation":"Konstanz","firstname":"Sebastian","lastname":"Lucke","nation":"GER","parent_fed":"Baden-W.","result0":"3T5z\u00a07\u00a011","result_modified":"1552740555","result_rank":18,"result_rank0":"18","rkey":"SLU16M","start_number":"303","start_order":"3","top_tries":7,"tops":3,"url":"https:\/\/www.digitalrock.de\/egroupware\/ranking\/sitemgr\/digitalrock\/pstambl.html#person=55591&cat=11","zone_tries":11,"zones":5},{"PerId":"52155","acl":"63","birthyear":2003,"city":"Dresden","fed_id":"168","fed_parent":"466","fed_url":"http:\/\/www.bergsteigerbund.de\/","federation":"S\u00e4chsischer Bergsteigerbund","firstname":"Albert","lastname":"Sch\u00f6nherr","nation":"GER","parent_fed":"Sachsen","result0":"2T4z\u00a02\u00a06","result_modified":"1552741036","result_rank":19,"result_rank0":"19","rkey":"ASC12M","start_number":"329","start_order":"28","top_tries":2,"tops":2,"url":"https:\/\/www.digitalrock.de\/egroupware\/ranking\/sitemgr\/digitalrock\/pstambl.html#person=52155&cat=11","zone_tries":6,"zones":4},{"PerId":"63321","acl":"63","birthyear":2003,"city":"Zweibr\u00fccken","fed_id":"368","fed_parent":"465","fed_url":"http:\/\/alpenverein-zweibruecken.de\/","federation":"Zweibr\u00fccken","firstname":"Thorben","lastname":"Schulte","nation":"GER","parent_fed":"RL-Pfalz","result0":"2T4z\u00a05\u00a05","result_modified":"1552740228","result_rank":20,"result_rank0":"20","rkey":"TSC17M","start_number":"324","start_order":"23","top_tries":5,"tops":2,"url":"https:\/\/www.digitalrock.de\/egroupware\/ranking\/sitemgr\/digitalrock\/pstambl.html#person=63321&cat=11","zone_tries":5,"zones":4},{"PerId":"56993","acl":"63","birthyear":2003,"city":"Hildesheim","fed_id":"193","fed_parent":"464","fed_url":"http:\/\/www.dav-hildesheim.de\/","federation":"Hildesheim","firstname":"Justus","lastname":"Aselmeier","nation":"GER","parent_fed":"Nord","result0":"2T3z\u00a03\u00a04","result_modified":"1552741051","result_rank":21,"result_rank0":"21","rkey":"JAS16M","start_number":"316","start_order":"16","top_tries":3,"tops":2,"url":"https:\/\/www.digitalrock.de\/egroupware\/ranking\/sitemgr\/digitalrock\/pstambl.html#person=56993&cat=11","zone_tries":4,"zones":3},{"PerId":"51894","acl":"63","birthyear":2003,"city":"Bautzen","fed_id":"168","fed_parent":"466","fed_url":"http:\/\/www.bergsteigerbund.de\/","federation":"S\u00e4chsischer Bergsteigerbund","firstname":"Dominic","lastname":"Horn","nation":"GER","parent_fed":"Sachsen","result0":"2T3z\u00a03\u00a04","result_modified":"1552741003","result_rank":21,"result_rank0":"21","rkey":"DHO12M3","start_number":"328","start_order":"27","top_tries":3,"tops":2,"url":"https:\/\/www.digitalrock.de\/egroupware\/ranking\/sitemgr\/digitalrock\/pstambl.html#person=51894&cat=11","zone_tries":4,"zones":3},{"PerId":"53251","acl":"63","birthyear":2002,"city":"Solingen","fed_id":"135","fed_parent":"463","fed_url":"http:\/\/www.dav-wuppertal.de\/","federation":"Wuppertal","firstname":"Nils","lastname":"Brandenburger","nation":"GER","parent_fed":"NRW","result0":"2T3z\u00a05\u00a06","result_modified":"1552740172","result_rank":23,"result_rank0":"23","rkey":"BNI14M2","start_number":"318","start_order":"18","top_tries":5,"tops":2,"url":"https:\/\/www.digitalrock.de\/egroupware\/ranking\/sitemgr\/digitalrock\/pstambl.html#person=53251&cat=11","zone_tries":6,"zones":3},{"PerId":"69593","acl":"63","birthyear":2003,"city":"K\u00f6ln","fed_id":"170","fed_parent":"463","fed_url":"http:\/\/www.dav-koeln.de\/","federation":"Rheinland-K\u00f6ln","firstname":"Felix","lastname":"Sch\u00e4fer","nation":"GER","parent_fed":"NRW","result0":"1T3z\u00a03\u00a08","result_modified":"1552741233","result_rank":24,"result_rank0":"24","rkey":"FSC18M","start_number":"320","start_order":"20","top_tries":3,"tops":1,"url":"https:\/\/www.digitalrock.de\/egroupware\/ranking\/sitemgr\/digitalrock\/pstambl.html#person=69593&cat=11","zone_tries":8,"zones":3},{"PerId":"54303","acl":"63","birthyear":2003,"city":"Stuttgart","fed_id":"290","fed_parent":"461","fed_url":"http:\/\/www.alpenverein-stuttgart.de\/","federation":"Stuttgart","firstname":"Jona","lastname":"Marx","nation":"GER","parent_fed":"Baden-W.","result0":"0T4z\u00a00\u00a05","result_modified":"1552741259","result_rank":25,"result_rank0":"25","rkey":"JMA15M","start_number":"304","start_order":"4","tops":0,"url":"https:\/\/www.digitalrock.de\/egroupware\/ranking\/sitemgr\/digitalrock\/pstambl.html#person=54303&cat=11","zone_tries":5,"zones":4},{"PerId":"53284","acl":"63","birthyear":2003,"city":"Carlsberg","fed_id":"173","fed_parent":"465","fed_url":"http:\/\/www.dav-frankenthal.de\/","federation":"Frankenthal","firstname":"Eric","lastname":"Grabo","nation":"GER","parent_fed":"RL-Pfalz","result0":"0T3z\u00a00\u00a06","result_modified":"1552740130","result_rank":26,"result_rank0":"26","rkey":"EGR14M","start_number":"321","start_order":"21","tops":0,"url":"https:\/\/www.digitalrock.de\/egroupware\/ranking\/sitemgr\/digitalrock\/pstambl.html#person=53284&cat=11","zone_tries":6,"zones":3},{"PerId":"54274","acl":"63","birthyear":2002,"city":"Berlin","fed_id":"104","fed_parent":"470","fed_url":"http:\/\/www.dav-berlin.de\/","federation":"Berlin","firstname":"Luis","lastname":"Fuchs","nation":"GER","parent_fed":"Berlin","result0":"0T2z\u00a00\u00a04","result_modified":"1552741070","result_rank":27,"result_rank0":"27","rkey":"LFU15M","start_number":"313","start_order":"13","tops":0,"url":"https:\/\/www.digitalrock.de\/egroupware\/ranking\/sitemgr\/digitalrock\/pstambl.html#person=54274&cat=11","zone_tries":4,"zones":2},{"PerId":"54606","acl":"63","birthyear":2003,"city":"Freudenberg","fed_id":"210","fed_parent":"463","fed_url":"http:\/\/www.dav-aachen.de","federation":"Aachen","firstname":"Kalvin","lastname":"Klappert","nation":"GER","parent_fed":"NRW","result0":"0T1z\u00a00\u00a01","result_modified":"1552740876","result_rank":28,"result_rank0":"28","rkey":"KKL15M","start_number":"319","start_order":"19","tops":0,"url":"https:\/\/www.digitalrock.de\/egroupware\/ranking\/sitemgr\/digitalrock\/pstambl.html#person=54606&cat=11","zone_tries":1,"zones":1}],"see_also":[{"name":"Ranking after 1. Deutscher Jugendcup (B) 2019 - Bexbach","url":"https:\/\/www.digitalrock.de\/ranglist.php?type=ranking&cat=11&comp=8422"},{"name":"DAV Jugendcup 2019 after 1. Deutscher Jugendcup (B) 2019 - Bexbach","url":"https:\/\/www.digitalrock.de\/ranglist.php?type=ranking&cat=11&cup=796&comp=8422"}],"categorys":[{"GrpId":"48","route_order":"2","name":"weibliche Jugend A"},{"GrpId":"11","route_order":"2","name":"m\u00e4nnliche Jugend A"},{"GrpId":"49","route_order":"2","name":"weibliche Jugend B"},{"GrpId":"12","route_order":"2","name":"m\u00e4nnliche Jugend B"},{"GrpId":"213","route_order":"0","name":"Coaches"}],"etag":"\"8cd778beaec9d8d190e1a6a74dfd1fc7\"","expires":86400}
\ No newline at end of file
diff --git a/resources/shared/icons/sac.png b/resources/shared/icons/sac.png
new file mode 100644
index 0000000..c16a111
Binary files /dev/null and b/resources/shared/icons/sac.png differ
diff --git a/resources/shared/shared.qrc b/resources/shared/shared.qrc
new file mode 100644
index 0000000..aabd3de
--- /dev/null
+++ b/resources/shared/shared.qrc
@@ -0,0 +1,9 @@
+
+
+ icons/dav.png
+ icons/ifsc.png
+ icons/sac.png
+ icons/back.png
+ icons/backDark.png
+
+
diff --git a/sources/main.cpp b/sources/main.cpp
new file mode 100644
index 0000000..8711658
--- /dev/null
+++ b/sources/main.cpp
@@ -0,0 +1,24 @@
+#include
+#include
+#include
+#include
+
+#include "headers/serverconn.h"
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+
+ QGuiApplication app(argc, argv);
+
+ QQuickStyle::setStyle("Material");
+
+ qmlRegisterType("com.itsblue.digitalRockRanking", 1, 0, "ServerConn");
+
+ QQmlApplicationEngine engine;
+ engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
+ if (engine.rootObjects().isEmpty())
+ return -1;
+
+ return app.exec();
+}
diff --git a/sources/serverconn.cpp b/sources/serverconn.cpp
new file mode 100644
index 0000000..a4e774e
--- /dev/null
+++ b/sources/serverconn.cpp
@@ -0,0 +1,134 @@
+#include "headers/serverconn.h"
+
+ServerConn::ServerConn(QObject *parent) : QObject(parent)
+{
+}
+
+void ServerConn::refreshFoodplan() {
+ QVariant tmpFoodplan;
+
+ QVariantMap ret = this->senddata(QUrl("http://egw.ifsc-climbing.org/egw/ranking/json.php"));
+
+ if(ret["status"] != 200){
+ // request was a failure
+ return;
+ }
+
+ QJsonDocument jsonReply = QJsonDocument::fromJson(ret["text"].toString().toUtf8());
+
+ this->foodplan = jsonReply.toVariant();
+
+ //qDebug() << this->foodplan;
+
+ emit this->foodplanChanged();
+}
+
+QVariant ServerConn::getCalendar(QString nation){
+ QVariantMap ret = this->senddata(QUrl("http://egw.ifsc-climbing.org/egw/ranking/json.php?year=2018&nation=" + nation));
+
+ if(ret["status"] != 200){
+ // request was a failure
+ return QVariantMap({{"status", ret["status"]}, {"data", ""}});
+ }
+
+ QJsonDocument jsonReply = QJsonDocument::fromJson(ret["text"].toString().toUtf8());
+
+ QVariantMap rankingData = {{"status", 200}, {"data", jsonReply.toVariant()}};
+
+ return rankingData;
+}
+
+QVariant ServerConn::getRanking(int competiotionId, int categoryId, bool registrationData, int routeNumber) {
+
+ QString requestUrl = "http://egw.ifsc-climbing.org/egw/ranking/json.php?comp="+ QString::number( competiotionId ) +"&cat="+ QString::number( categoryId ) + (registrationData ? "&type=starters":"") + "&route=" + ((routeNumber == -2) ? "":QString::number(routeNumber));
+
+ qDebug() << requestUrl;
+
+ QVariantMap ret = this->senddata(QUrl(requestUrl));
+
+ if(ret["status"] != 200){
+ // request was a failure
+ return QVariantMap({{"status", ret["status"]}, {"data", ""}});
+ }
+
+ QJsonDocument jsonReply = QJsonDocument::fromJson(ret["text"].toString().toUtf8());
+
+ QVariantMap rankingData = {{"status", 200}, {"data", jsonReply.toVariant()}};
+
+ return rankingData;
+}
+
+// ------------------------
+// --- Helper functions ---
+// ------------------------
+
+QVariantMap ServerConn::senddata(QUrl serviceUrl, QUrlQuery pdata)
+{
+ // 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);
+}
+
+// -------------------------
+// --- Functions for QML ---
+// -------------------------
+
+QVariant ServerConn::getFoodplan() {
+ return this->foodplan;
+}
+