app/resources/qml/main.qml

650 lines
20 KiB
QML

/*
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 <http://www.gnu.org/licenses/>.
*/
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("blueROCK")
Page {
id: app
property int errorCode: -1
property var competitionCategoryColors: {
"61": "lightgrey",
"58": "lightgreen",
"69": "#B8C8FF",
"70": "#F0F0F0",
"71": "#D8E8FF",
"256": "#D8E8FF"
}
property var compCats: {
'int' : {
'label' : 'International',
'nation' : '',
'wettk_reg' : '^[0-9]{2,2}[_^E]{1}[^YJ]{1,1}.*',
'serie_reg' : '^[0-9]{2,2}_(WC|TR){1,1}.*',
'rang_title': 'CUWR continuously updated WORLDRANKING',
'bgcolor' : '#B8C8FF',
'nat_team_ranking' : '',
'cat_id' : [68,69,70,86,259]
},
'youth' : {
'label' : 'Int. Jugend',
'nation' : '',
'wettk_reg' : '^[0-9]{2,2}(EYC|_J|_Y){1,1}.*',
'serie_reg' : '^[0-9]{2,2}_EYC',
'rang_title': '',
'bgcolor' : '#D8E8FF',
'cat_id' : [71,258]
},
'masters' : {
'label' : 'Masters',
'nation' : '',
'wettk_reg' : '^[0-9]{2,2}_[^PWERASL]{1}.*',
// 'serie_reg' : '^[0-9]{2,2}_(WC|TR){1,1}.*',
// 'rang_title': 'CUWR continuously updated WORLDRANKING',
'bgcolor' : '#F0F0F0',
'cat_id' : [70]
},
'para' : {
'label' : 'Paraclimbing',
'nation' : '',
'wettk_reg' : '^[0-9]{2,2}_PE.*',
'bgcolor' : '#F0F0F0',
'cat_id' : [256,259]
},
'ger_boulder' : {
'label' : 'Bouldern',
'nation' : 'GER',
'wettk_reg' : '^[0-9]{2,2}_B+.*',
'serie_reg' : '^[0-9]{2,2}_BC',
'bgcolor' : '#FFDBA8',
'cat_id' : [59]
},
'ger' : {
'label' : 'Lead',
'nation' : 'GER',
'wettk_reg' : '^[0-9]{2,2}[_J]{1,1}[^WLJ]+.*',
'serie_reg' : '^[0-9]{2,2}_DC',
'bgcolor' : '#A8F0A8',
'cat_id' : [57]
},
'ger_speed' : {
'label' : 'Speed',
'nation' : 'GER',
'wettk_reg' : '^[0-9]{2,2}[_J]{1,1}[^WLJ]+.*',
'serie_reg' : '',
'rang_title': '',
'bgcolor' : '#A8F0A8',
'cat_id' : [60]
},
'ger_jugend' : {
'label' : 'Jugend',
'nation' : 'GER',
'wettk_reg' : '^[0-9]{2,2}[_J]{1,1}[^WL]+.*',
'serie_reg' : '^[0-9]{2,2}_JC',
// 'rang_title': 'Deutsche Jugend RANGLISTE',
'bgcolor' : '#D8FFD8',
'cat_id' : [57,58]
},
'ger_state' : {
'label' : 'Landesmeisterschaft',
'nation' : 'GER',
'wettk_reg' : '^[0-9]{2,2}[_J]{1,1}LM.*',
'serie_reg' : '^[0-9]{2,2}[_J]{1,1}LM.*',
'rang_title': '',
'bgcolor' : '#F0F0F0',
'cat_id' : [61,56]
},
'sui' : {
'label' : 'Erwachsene',
'nation' : 'SUI',
'wettk_reg' : '^[0-9]{2,2}_[^R].*',
'serie_reg' : '.*',
'rang_title': 'SWISS RANKING',
'bgcolor' : '#A8F0A8',
'cat_id' : [62,63]
},
'sui_jugend' : {
'label' : 'Jugend',
'nation' : 'SUI',
'wettk_reg' : '^[0-9]{2,2}_[^R].*',
'serie_reg' : '.*',
'rang_title': 'SWISS RANKING',
'bgcolor' : '#D8FFD8',
'cat_id' : [65]
},
'sui_local' : {
'label' : 'RegioCups',
'nation' : 'SUI',
'wettk_reg' : '^[0-9]{2,2}_RG_.*',
'rang_title': '',
'bgcolor' : '#F0F0F0',
'cat_id' : [64]
},
'sui_ice' : {
'label' : 'Iceclimbing',
'nation' : 'SUI',
'wettk_reg' : '^[0-9]{2,2}_RC_.*',
'rang_title': '',
'bgcolor' : '#F0F0F0',
'cat_id' : [84]
}
}
anchors.fill: parent
Component.onCompleted: {
//app.openAthlete(53139) // dorian: 53139 , rustam: 6933 , helen: 53300
}
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
//enabled: !loadingDl.opened
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: -height
}
height: 50
showErrorBar: true
Row {
anchors.fill: parent
spacing: width * 0.02
Item {
id: spacer
width: 1
height: parent.height
}
Button {
id:toolButton
anchors {
verticalCenter: parent.verticalCenter
}
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: height
fillMode: Image.PreserveAspectFit
Behavior on scale {
PropertyAnimation {
duration: 100
}
}
}
}
Column {
anchors.verticalCenter: parent.verticalCenter
height: childrenRect.height
width: parent.width - extraComponentLoader.width - toolButton.width - 3 * parent.spacing
Label {
id: toolBarTitleLa
width: parent.width
scale: 1
elide: "ElideRight"
font.bold: true
verticalAlignment: Text.AlignVCenter
color: "black"
text: getText()
function getText(){
var titleString = "";
if(!mainStack.currentItem.titleIsPageTitle){
for(var i=1; i<mainStack.depth; i++){
if(i > 1){
titleString += " > "
}
titleString += mainStack.get(i).title
}
}
else {
titleString = mainStack.currentItem.title
}
return(titleString)
}
Behavior on text {
FadeAnimation {
target: toolBarTitleLa
}
}
}
Label {
id: toolBarSubTitleLa
width: parent.width
height: text !== "" ? undefined:0
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 text {
FadeAnimation {
target: toolBarSubTitleLa
}
}
}
}
Loader {
id: extraComponentLoader
height: parent.height
width: status === Loader.Ready ? parent.width * 0.4 - toolButton.width - 3 * parent.spacing:0
anchors {
top: parent.top
bottom: parent.bottom
}
//sourceComponent: mainStack.currentItem.headerComponent
Connections {
target: mainStack
onCurrentItemChanged: {
disappearNa.start()
}
}
ParallelAnimation {
id: appearNa
NumberAnimation {
target: extraComponentLoader
property: "opacity"
from: 0
to: 1
duration: 150
}
NumberAnimation {
target: extraComponentLoader
property: "scale"
from: 0.9
to: 1
duration: 150
}
}
ParallelAnimation {
id: disappearNa
NumberAnimation {
target: extraComponentLoader
property: "opacity"
from: 1
to: 0
duration: 150
}
NumberAnimation {
target: extraComponentLoader
property: "scale"
from: 1
to: 0.9
duration: 150
}
onRunningChanged: {
if(!running){
extraComponentLoader.sourceComponent = mainStack.currentItem.headerComponent
appearNa.start()
}
}
}
}
}
Behavior on anchors.topMargin {
NumberAnimation {
duration: 500
easing.type: Easing.OutCubic
}
}
states: [
State {
name: "closed"
when: mainStack.depth === 1
PropertyChanges {
target: toolBar
anchors.topMargin: -height
}
},
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()
var calComp = Qt.createComponent("qrc:/Pages/CompetitionCalendarPage.qml").createObject(null, {"nation": nation})
app.errorCode = calComp.status
if(calComp.ready){
mainStack.push(calComp)
}
else {
delete(calComp)
}
loadingDl.close()
}
function openResults(comp, cat, status){
// comp: (int) competiotion ID
// cat: (int) category ID
// reg: (int) 0: result imported into ranking; 1: result-service result available; 2: result-service startlist available; 3: old non result-server startlist (no longer used); 4: starters / registration data
loadingDl.open()
var rankComp = Qt.createComponent("qrc:/Pages/RankingPage.qml").createObject(null, {"comId": comp, "catId": cat, "catStatus": status})
app.errorCode = rankComp.status
if(rankComp.ready){
mainStack.push(rankComp)
}
else {
delete(rankComp)
}
loadingDl.close()
}
function openAthlete(perId) {
loadingDl.open()
var athleteComp = Qt.createComponent("qrc:/Pages/AthleteProfilePage.qml").createObject(null, {"perId": perId})
app.errorCode = athleteComp.status
if(athleteComp.ready){
mainStack.push(athleteComp)
}
else {
delete(athleteComp)
}
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 200:
infoLevel = 0
errorString = "Success"
errorDescription = "The request was successfull"
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 = "Cached (old) data"
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
case 905:
infoLevel = 1
errorString = "Loading..."
errorDescription = "Please wait while we're loading some data"
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])
}
}
}