/* blueROCK - for digital rock Copyright (C) 2019 Dorian Zedler This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ import QtQuick 2.9 import QtQuick.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" Window { visible: true width: 540 height: 960 title: qsTr("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: { // --- 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', 'wettk_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}) } 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 Component.onCompleted: { //var params = serverConn.getParamsFromUrl("https://www.digitalrock.de/egroupware/ranking/sitemgr/digitalrock/eliste.html#!comp=11471&cat=GER_F_A") //app.openWidget(params) } } 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 Label { id: toolBarTitleLa width: parent.width scale: 1 elide: "ElideRight" font.bold: true verticalAlignment: Text.AlignVCenter 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) } Behavior on text { FadeAnimation { target: toolBarTitleLa } } } Label { id: toolBarSubTitleLa width: parent.width height: text !== "" ? undefined:0 elide: "ElideRight" 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" text: "loading..." } } background: Rectangle { color: "transparent" } } Store { id: inAppProductStore Product { id: speedFlowChartProduct //identifier: "speed_flowchart" identifier: QT_DEBUG ? "android.test.purchased":"speed_flowchart" //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() var calComp = Qt.createComponent("qrc:/Pages/WidgetPage.qml").createObject(null, {"params": params}) app.errorCode = calComp.status if(calComp.ready) { mainStack.push(calComp) } else { delete(calComp) } loadingDl.close() } 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 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 fault. Please try again later." break case 900: infoLevel = 2 errorString = "Internal error" errorDescription = "Something went wron internally, this is probaply an inssue in the program code" 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]) } } }