692 lines
20 KiB
QML
692 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 QtQuick.Layouts 1.3
|
|
import QtQuick.Controls.Material 2.12
|
|
import QtPurchasing 1.12
|
|
|
|
import de.itsblue.blueROCK 1.0
|
|
|
|
import "./Pages"
|
|
import "./Components"
|
|
|
|
import "./Widgets"
|
|
|
|
Window {
|
|
visible: true
|
|
width: 540
|
|
height: 960
|
|
title: "blueROCK"
|
|
|
|
Page {
|
|
id: app
|
|
|
|
property int errorCode: -1
|
|
|
|
property var colorShade: Material.theme === Material.Light ? Material.Shade300 : Material.Shade700
|
|
property color nationalAdultsColor: Material.color(Material.Green, colorShade)
|
|
property color nationalYouthColor: Material.color(Material.LightGreen, colorShade)
|
|
property color federalColor: Material.color(Material.Grey, colorShade)
|
|
|
|
// comp cats source:
|
|
// - https://github.com/ralfbecker/ranking/blob/master/sitemgr/digitalrock/dav_calendar.php
|
|
// - https://github.com/ralfbecker/ranking/blob/master/sitemgr/digitalrock/sac_calendar.php
|
|
|
|
property var compCats: {
|
|
// --- ICC ---
|
|
|
|
/*'int' : {
|
|
'label' : 'International',
|
|
'nation' : 'ICC',
|
|
'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,86]//[68,69,70,86,259]
|
|
},*/
|
|
'worldcup': {
|
|
'label' : 'World Cups',
|
|
'nation' : 'ICC',
|
|
'bgcolor' : '#B8C8FF',
|
|
'sort_rank': 1,
|
|
'cat_id' : [69]
|
|
},
|
|
'youth' : {
|
|
'label' : 'Youth Events',
|
|
'nation' : 'ICC',
|
|
'wettk_reg' : '^[0-9]{2,2}(EYC|_J|_Y){1,1}.*',
|
|
'serie_reg' : '^[0-9]{2,2}_EYC',
|
|
'rang_title': '',
|
|
'bgcolor' : '#D8E8FF',
|
|
'sort_rank': 2,
|
|
'cat_id' : [71,258]
|
|
},
|
|
'cont': {
|
|
'label' : 'Continental Events',
|
|
'nation' : 'ICC',
|
|
'bgcolor' : '#B8C8FF',
|
|
'sort_rank': 3,
|
|
'cat_id' : [262]
|
|
},
|
|
'masters' : {
|
|
'label' : 'Masters and Promo Events',
|
|
'nation' : 'ICC',
|
|
'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',
|
|
'sort_rank': 4,
|
|
'cat_id' : [70]
|
|
},
|
|
'para' : {
|
|
'label' : 'Paraclimbing Events',
|
|
'nation' : 'ICC',
|
|
'wettk_reg' : '^[0-9]{2,2}_PE.*',
|
|
'bgcolor' : '#F0F0F0',
|
|
'sort_rank': 5,
|
|
'cat_id' : [256,259]
|
|
},
|
|
'games': {
|
|
'label': 'Games',
|
|
'nation': 'ICC',
|
|
'bgcolor' : '#B8C8FF',
|
|
'sort_rank': 6,
|
|
'cat_id': [68,86]
|
|
},
|
|
|
|
// --- GER ---
|
|
|
|
'ger_meisterschaft' : {
|
|
'label' : 'Deutsche Meisterschaft',
|
|
'nation' : 'GER',
|
|
'bgcolor' : app.nationalAdultsColor,//'#A8F0A8',
|
|
'sort_rank': 1,
|
|
'cat_id' : [57, 59, 60]
|
|
},
|
|
|
|
'ger_jugend' : {
|
|
'label' : 'Deutscher Jugendcup',
|
|
'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' : app.nationalYouthColor,//'#D8FFD8',
|
|
'sort_rank': 2,
|
|
'cat_id' : [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' : app.federalColor, //'#F0F0F0',
|
|
'sort_rank': 3,
|
|
'cat_id' : [61,56]
|
|
},
|
|
|
|
// --- SUI ---
|
|
|
|
'sui' : {
|
|
'label' : 'Erwachsene',
|
|
'nation' : 'SUI',
|
|
'wettk_reg' : '^[0-9]{2,2}_[^R].*',
|
|
'serie_reg' : '.*',
|
|
'rang_title': 'SWISS RANKING',
|
|
'bgcolor' : app.nationalAdultsColor, //'#A8F0A8',
|
|
'sort_rank': 1,
|
|
'cat_id' : [62,63]
|
|
},
|
|
'sui_jugend' : {
|
|
'label' : 'Jugend',
|
|
'nation' : 'SUI',
|
|
'wettk_reg' : '^[0-9]{2,2}_[^R].*',
|
|
'serie_reg' : '.*',
|
|
'rang_title': 'SWISS RANKING',
|
|
'bgcolor' : app.nationalYouthColor, //'#D8FFD8',
|
|
'sort_rank': 2,
|
|
'cat_id' : [65]
|
|
},
|
|
'sui_local' : {
|
|
'label' : 'RegioCups',
|
|
'nation' : 'SUI',
|
|
'wettk_reg' : '^[0-9]{2,2}_RG_.*',
|
|
'rang_title': '',
|
|
'bgcolor' : app.federalColor, //'#F0F0F0',
|
|
'sort_rank': 3,
|
|
'cat_id' : [64]
|
|
},
|
|
'sui_ice' : {
|
|
'label' : 'Iceclimbing',
|
|
'nation' : 'SUI',
|
|
'wparams["valid"]ettk_reg' : '^[0-9]{2,2}_RC_.*',
|
|
'rang_title': '',
|
|
'bgcolor' : app.federalColor, //'#F0F0F0',
|
|
'sort_rank': 4,
|
|
'cat_id' : [84]
|
|
}
|
|
}
|
|
|
|
anchors.fill: parent
|
|
|
|
Material.theme: appSettings.read("darkTheme") === "true" ? Material.Dark:Material.Light
|
|
|
|
Component.onCompleted: {
|
|
//loadingDl.open()
|
|
//app.openAthlete() // dorian: 53139 , rustam: 6933 , helen: 53300
|
|
//openWidget({nation:'GER'})
|
|
//mainStack.push("Pages/AthleteSearchPage.qml")
|
|
//openWidget({comp: 11651, cat: 26})
|
|
//openWidget({person: 6623})
|
|
//console.log(JSON.stringify(serverConn.getParamsFromUrl("")))
|
|
//openWidgetFromUrl("https://l.bluerock.dev/?comp=11601&type=starters")
|
|
}
|
|
|
|
FontLoader {
|
|
id: fa5solid
|
|
source: "qrc:/fonts/fa5solid.otf"
|
|
}
|
|
|
|
FontLoader {
|
|
id: fa5regular
|
|
source: "qrc:/fonts/fa5regular.otf"
|
|
}
|
|
|
|
Shortcut {
|
|
sequences: ["Esc", "Back"]
|
|
enabled: mainStack.depth > 1
|
|
onActivated: app.goBack()
|
|
}
|
|
|
|
BlueRockBackend {
|
|
id: serverConn
|
|
|
|
onOpenedViaUrl: {
|
|
app.openWidgetFromUrl(url)
|
|
}
|
|
}
|
|
|
|
AppSettings {
|
|
id: appSettings
|
|
}
|
|
|
|
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: -height
|
|
}
|
|
|
|
height: 50
|
|
|
|
showErrorBar: true
|
|
|
|
RowLayout {
|
|
|
|
anchors.fill: parent
|
|
|
|
spacing: width * 0.02
|
|
|
|
ToolButton {
|
|
id:toolButton
|
|
|
|
height: parent.height
|
|
|
|
onClicked: app.goBack()
|
|
|
|
text: "\uf053"
|
|
font.family: fa5solid.name
|
|
}
|
|
|
|
Column {
|
|
|
|
Layout.fillWidth: true
|
|
|
|
height: childrenRect.height
|
|
width: parent.width - extraComponentLoader.width - toolButton.width - 3 * parent.spacing
|
|
|
|
MovingLabel {
|
|
id: toolBarTitleLa
|
|
|
|
syncWithLabel: toolBarSubTitleLa
|
|
width: parent.width
|
|
scale: 1
|
|
|
|
font.bold: true
|
|
verticalAlignment: Text.AlignVCenter
|
|
|
|
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
|
|
}
|
|
}
|
|
}
|
|
|
|
MovingLabel {
|
|
id: toolBarSubTitleLa
|
|
|
|
visible: text !== ""
|
|
|
|
syncWithLabel: toolBarTitleLa
|
|
width: parent.width
|
|
|
|
font.bold: false
|
|
|
|
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
|
|
|
|
property int maximumWidth: parent.width * 0.4 - toolButton.width - 3
|
|
|
|
height: parent.height
|
|
|
|
onItemChanged: {
|
|
if(item === null) {
|
|
extraComponentLoader.Layout.preferredWidth = 0
|
|
return
|
|
}
|
|
|
|
extraComponentLoader.item.width = extraComponentLoader.item.implicitWidth
|
|
extraComponentLoader.Layout.preferredWidth = extraComponentLoader.item.width
|
|
widthChangedCon.target = extraComponentLoader.item
|
|
}
|
|
|
|
Connections {
|
|
target: mainStack
|
|
function onCurrentItemChanged() {
|
|
secondCon.target = mainStack.currentItem
|
|
disappearNa.start()
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
id: secondCon
|
|
target: null
|
|
function onHeaderComponentChanged() {
|
|
disappearNa.start()
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
id: widthChangedCon
|
|
function onImplicitWidthChanged() {
|
|
extraComponentLoader.item.width = extraComponentLoader.item.implicitWidth
|
|
extraComponentLoader.Layout.preferredWidth = extraComponentLoader.item.implicitWidth
|
|
}
|
|
}
|
|
|
|
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
|
|
}
|
|
}
|
|
]
|
|
}
|
|
|
|
Popup {
|
|
id: loadingDl
|
|
|
|
x: ( app.width - width ) / 2
|
|
y: ( app.height - height ) / 2
|
|
|
|
modal: true
|
|
closePolicy: Dialog.NoAutoClose
|
|
|
|
contentItem: Column {
|
|
|
|
spacing: 50
|
|
|
|
FancyBusyIndicator {
|
|
running: true
|
|
}
|
|
|
|
Label {
|
|
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
|
|
font.bold: true
|
|
color: "white"
|
|
|
|
//% "Loading"
|
|
text: qsTrId("#loading") + "..."
|
|
}
|
|
}
|
|
|
|
background: Rectangle {
|
|
color: "transparent"
|
|
}
|
|
|
|
|
|
}
|
|
|
|
Store {
|
|
id: inAppProductStore
|
|
|
|
Product {
|
|
id: speedFlowChartProduct
|
|
identifier: "speed_flowchart"
|
|
//identifier: "android.test.purchased"
|
|
//identifier: "android.test.canceled"
|
|
//identifier: "android.test.refunded"
|
|
|
|
type: Product.Unlockable
|
|
|
|
onPurchaseRestored: {
|
|
appSettings.write("speedBackendPurchase", 1)
|
|
}
|
|
|
|
onPurchaseSucceeded: {
|
|
appSettings.write("speedBackendPurchase", 1)
|
|
}
|
|
|
|
onPurchaseFailed: {
|
|
appSettings.write("speedBackendPurchase", 0)
|
|
}
|
|
}
|
|
}
|
|
|
|
function landscape() {
|
|
return app.height < app.width
|
|
}
|
|
|
|
function toggleDarkMode() {
|
|
var dark = app.Material.theme === Material.Light
|
|
|
|
app.Material.theme = dark ? Material.Dark : Material.Light
|
|
appSettings.write("darkTheme", dark)
|
|
}
|
|
|
|
function largeScreen() {
|
|
return Math.min(app.width, app.height) > 750
|
|
}
|
|
|
|
function openWidget(params) {
|
|
loadingDl.open()
|
|
|
|
console.log("Opening widget: ", JSON.stringify(params))
|
|
|
|
var result = false
|
|
|
|
if(Object.keys(params).length) {
|
|
var calComp = Qt.createComponent("qrc:/Pages/WidgetPage.qml").createObject(null, {"params": params})
|
|
app.errorCode = calComp.status
|
|
|
|
if(calComp.ready) {
|
|
mainStack.push(calComp)
|
|
result = true
|
|
}
|
|
else {
|
|
delete(calComp)
|
|
}
|
|
}
|
|
|
|
loadingDl.close()
|
|
return result
|
|
}
|
|
|
|
function openWidgetFromUrl(url) {
|
|
var result = serverConn.getParamsFromUrl(url)
|
|
|
|
if(result["valid"]) {
|
|
openWidget(result["params"])
|
|
return app.errorCode !== 906
|
|
}
|
|
|
|
return result["valid"]
|
|
}
|
|
|
|
function defaultString(string, defaultString) {
|
|
if(string === undefined || string === null) {
|
|
return defaultString
|
|
}
|
|
else {
|
|
return string
|
|
}
|
|
}
|
|
|
|
function goBack() {
|
|
if(!mainStack.currentItem.hasOwnProperty('onBackRequested') || mainStack.currentItem.onBackRequested())
|
|
mainStack.pop()
|
|
}
|
|
|
|
function getErrorInfo(errorCode) {
|
|
|
|
var infoLevel
|
|
// 0 - ok
|
|
// 1 - info
|
|
// 2 - error
|
|
|
|
var errorString
|
|
|
|
switch(errorCode) {
|
|
case 0:
|
|
infoLevel = 2
|
|
//% "No connection to server"
|
|
errorString = qsTrId("#noConnectionError")
|
|
break
|
|
case 404:
|
|
infoLevel = 2
|
|
//% "Not found"
|
|
errorString = qsTrId("#notFoundError")
|
|
break
|
|
case 901:
|
|
infoLevel = 1
|
|
//% "No Data"
|
|
errorString = qsTrId("#noDataError")
|
|
break
|
|
case 906:
|
|
infoLevel = 2
|
|
//% "Invalid Request"
|
|
errorString = qsTrId("#invalidRequestError")
|
|
errorDescription = "Invalid Request"
|
|
break
|
|
default:
|
|
infoLevel = 2
|
|
//% "Unexpected error"
|
|
errorString = qsTrId("#unexpectedError") + " ("+errorCode+")"
|
|
}
|
|
|
|
return([infoLevel, errorString])
|
|
}
|
|
|
|
}
|
|
}
|