/* 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" 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 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]) } } }