From 9bb64027b4e5d4be4b2e3f6be0198b403521589a Mon Sep 17 00:00:00 2001 From: dorian Date: Sat, 8 Jun 2019 11:14:18 +0200 Subject: [PATCH] split profile dialog up into multiple files --- android_release.keystore | Bin 2245 -> 0 bytes qml/ProfilesDialog.qml | 741 ------------------------- qml/ProfilesDialog/AddProfilePage.qml | 67 +++ qml/ProfilesDialog/ProfileListPage.qml | 237 ++++++++ qml/ProfilesDialog/ProfilesDialog.qml | 263 +++++++++ qml/ProfilesDialog/ProfilesStack.qml | 175 ++++++ qml/ProfilesDialog/ResultListPage.qml | 120 ++++ qml/main.qml | 1 + qml/qml.qrc | 6 +- sources/climbingrace.cpp | 2 +- 10 files changed, 869 insertions(+), 743 deletions(-) delete mode 100644 android_release.keystore delete mode 100644 qml/ProfilesDialog.qml create mode 100644 qml/ProfilesDialog/AddProfilePage.qml create mode 100644 qml/ProfilesDialog/ProfileListPage.qml create mode 100644 qml/ProfilesDialog/ProfilesDialog.qml create mode 100644 qml/ProfilesDialog/ProfilesStack.qml create mode 100644 qml/ProfilesDialog/ResultListPage.qml diff --git a/android_release.keystore b/android_release.keystore deleted file mode 100644 index f330509c9c8219c8b73a01a0144a15dead4e99d0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2245 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 Q!*N+Tw4hzeHR58%U-^IAB>(^b diff --git a/qml/ProfilesDialog.qml b/qml/ProfilesDialog.qml deleted file mode 100644 index 2cef0ea..0000000 --- a/qml/ProfilesDialog.qml +++ /dev/null @@ -1,741 +0,0 @@ -/* - Speed Climbing Stopwatch - Simple Stopwatch for Climbers - Copyright (C) 2018 Itsblue Development - Dorian Zeder - - 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, version 3 of the License. - - 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 QtMultimedia 5.8 -import QtQuick.Window 2.2 -import QtQuick.Controls 2.4 -import QtQuick.Layouts 1.3 -import QtGraphicalEffects 1.0 -import com.itsblue.speedclimbingstopwatch 1.0 -import "./components" - - -Popup { - id: root - - modal: true - dim: false - - opacity: 0 - - enter: Transition { - NumberAnimation { properties: "opacity"; to: 1; duration: 300; easing.type: Easing.InOutQuad } - NumberAnimation { properties: "scale"; from: 0.9; to: 1; duration: 300; easing.type: Easing.InOutQuad } - } - - exit: Transition { - NumberAnimation { properties: "opacity"; to: 0; duration: 300; easing.type: Easing.InOutQuad } - NumberAnimation { properties: "scale"; from: 1; to: 0.9; duration: 300; easing.type: Easing.InOutQuad } - } - - background: Item { - RectangularGlow { - id: backgroundEffect - glowRadius: 7 - spread: 0.02 - color: "black" - opacity: 0.18 - anchors.fill: backgroundRect - cornerRadius: backgroundRect.radius - scale: 1 - } - - Rectangle { - id: backgroundRect - anchors.fill: parent - radius: width * 0.1 - color: appTheme.style.viewColor - } - } - - StackView { - id: profiles_stack - property int text_pixelSize: headlineUnderline.width * 0.08 - //initialItem: profileListComp - width: headlineUnderline.width - - anchors { - top: topContainerItm.bottom - left: parent.left - leftMargin: ( parent.width - headlineUnderline.width ) / 2 - topMargin: headlineUnderline.anchors.topMargin * 1.2 - bottom: parent.bottom - bottomMargin: topContainerItm.height * 0.3 - } - - Behavior on opacity { - NumberAnimation {duration: 200} - } - - Component.onCompleted: { - profiles_stack.init() - } - - Connections { - target: root - onOpened: { - profiles_stack.init() - } - } - - onCurrentItemChanged: { - currentItem.opened() - } - - function init() { - if(profiles_stack.depth === 0){ - profiles_stack.openAthletes() - } - else { - profiles_stack.currentItem.opened() - } - } - - function openAthletes() { - var athsComp = profileListComp.createObject(null, {}) - profiles_stack.push(athsComp) - } - - function openResults( userName ){ - var resComp = resultViewComp.createObject(null, {"userName": userName}) - profiles_stack.push(resComp) - } - - /*-----List of all profiles-----*/ - Component { - id: profileListComp - - RemoteDataListView { - id: profileList - - property int currentAthlete: -1 - property string title: "profiles" - property string secondButt: "add" - - signal opened() - - onOpened: { - profileList.loadData() - } - - //anchors.fill: parent - //anchors.topMargin: topContainerItm.height * 0.1 - - loadData: function () { - status = 905 - //listData = {} - var retData = speedBackend.getAthletes() - - if(retData === undefined){ - status = 500 - return - } - - listData = retData["allAthletes"] - currentAthlete = retData["activeAthlete"] - status = listData.lenght !== false ? 200:0 - } - - delegate: SwipeDelegate { - id: swipeDelegate - - property bool active: profileList.currentAthlete === profileList.listData[index]["id"] - - text: profileList.listData[index]["fullName"] - width: profileList.width - (swipeDelegate.x) - height: profileList.height / 5 - - font.pixelSize: profiles_stack.text_pixelSize - - function remove() { - removeAnim.start() - } - - onClicked: { - profiles_stack.openResults(profileList.listData[index]["userName"]) - } - - contentItem: Text { - visible: false - } - - Text { - - anchors { - verticalCenter: parent.verticalCenter - left: parent.left - leftMargin: swipeDelegate.width * 0.05 - right: parent.right - rightMargin: swipeDelegate.rightPadding - } - - text: swipeDelegate.text - color: appTheme.style.textColor - - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignLeft - - fontSizeMode: Text.Fit - - font.pixelSize: swipeDelegate.height * 0.4 - - minimumPixelSize: 1 - } - - background: Rectangle { - color: pressed ? appTheme.style.delegatePressedColor : appTheme.style.delegateBackgroundColor - - Behavior on color { - - ColorAnimation { - duration: 200 - } - } - } - - CheckBox { - id: control - - anchors { - verticalCenter: parent.verticalCenter - right: parent.right - rightMargin: 7 - } - - height: parent.height * 0.6 - - checked: swipeDelegate.active - - onCheckedChanged: { - if(checked && !swipeDelegate.active && speedBackend.selectAthlete(profileList.listData[index]["userName"])){ - profileList.loadData() - } - } - - indicator: Rectangle { - implicitWidth: 26 - implicitHeight: 26 - - height: parent.height - width: height - - x: control.leftPadding - y: parent.height / 2 - height / 2 - - radius: width * 0.2 - border.color: control.down ? "#17a81a" : "#21be2b" - color: control.down ? appTheme.style.delegatePressedColor : appTheme.style.delegateBackgroundColor - - Rectangle { - width: parent.width * 0.65 - height: width - anchors.centerIn: parent - radius: control.checked ? width * 0.2:0 - color: control.down ? "#17a81a" : "#21be2b" - opacity: control.checked ? 1:0 - scale: control.checked ? 0.9:0 - - Behavior on color { - ColorAnimation { - duration: 200 - } - } - - Behavior on radius { - NumberAnimation { - duration: 200 - } - } - - Behavior on opacity { - NumberAnimation { - duration: 200 - } - } - - Behavior on scale { - NumberAnimation { - duration: 200 - } - } - } - } - } - - Rectangle { - color: "grey" - height: 1 - width: parent.width * 0.9 - visible: index > 0 - anchors { - horizontalCenter: parent.horizontalCenter - top: parent.top - } - } - - NumberAnimation { - id: removeAnim - target: swipeDelegate - property: "height" - to: 0 - easing.type: Easing.InOutQuad - onStopped: profileModel.model.remove(index) - } - - swipe.transition: Transition { - SmoothedAnimation { velocity: 3; easing.type: Easing.InOutCubic } - } - - swipe.left: Row { - anchors.left: parent.left - height: parent.height - - Label { - id: deleteLabel - text: qsTr("Delete") - color: appTheme.style.textColor - verticalAlignment: Label.AlignVCenter - padding: 12 - height: parent.height - - SwipeDelegate.onClicked: { - profileList.status = 905 - if(speedBackend.deleteAthlete(profileList.listData[index]["userName"])){ - profileList.loadData() - return - } - profileList.status = 200 - } - - background: Rectangle { - color: deleteLabel.SwipeDelegate.pressed ? Qt.darker("tomato", 1.1) : "tomato" - } - } - } - } - } - - } - - /*-----Option to add a profile-----*/ - Component { - id: addProfileComp - Column { - property string title: "add profile" - property string secondButt: "ok" - property string newProfileName: "" - - Connections { - target: head_add - - enabled: true - - onClicked: { - if(speedBackend.createAthlete(userNameTf.text, fullNameTf.text)){ - profiles_stack.get(profiles_stack.depth - 2 ).opened() - profiles_stack.pop() - } - } - } - - TextField { - id: fullNameTf - width: parent.width - placeholderText: "full name" - onTextChanged: { - parent.newProfileName = text - } - Keys.onReturnPressed: { - } - } - TextField { - id: userNameTf - width: parent.width - placeholderText: "username" - onTextChanged: { - parent.newProfileName = text - } - Keys.onReturnPressed: { - } - } - } - } - - // --- Result View --- - Component { - id: resultViewComp - RemoteDataListView { - id: resultView - - property string userName - property string title: userName - property string secondButt: "none" - - signal opened() - - anchors.margins: 10 - - clip: true - - onOpened: { - loadData() - } - - loadData: function () { - status = 905 - listData = {} - listData = speedBackend.getResults(userName) - status = listData.lenght !== false ? 200:0 - } - - delegate: SmoothItemDelegate { - id: resultDel - - width: parent.width - height: resultView.height / 4 - - backgroundRect.radius: 0 - - function getDateText(){ - var date = new Date(listData[index]["timestamp"]*1000).toLocaleString(Qt.locale(), "dddd, dd.MMM HH:mm") - return date - } - - Rectangle { - color: "grey" - height: 1 - width: parent.width * 0.9 - visible: index > 0 - anchors { - horizontalCenter: parent.horizontalCenter - top: parent.top - } - } - - Column { - anchors.fill: parent - anchors.leftMargin: parent.width * 0.05 - - Label { - id: dateLa - - height: parent.height / parent.children.length - - font.pixelSize: height * 0.8 - fontSizeMode: Text.Fit - - color: appTheme.style.textColor - - text: resultDel.getDateText() - } - - Label { - id: resultLa - - height: parent.height / parent.children.length - - font.pixelSize: height * 0.8 - fontSizeMode: Text.Fit - - color: appTheme.style.textColor - - text: qsTr("result: ") + (listData[index]["result"] / 1000).toFixed(3) + " s" - } - - Label { - id: reactionTimeLa - - height: parent.height / parent.children.length - - font.pixelSize: height * 0.8 - fontSizeMode: Text.Fit - - color: appTheme.style.textColor - - text: qsTr("reaction time: ") + listData[index]["reactionTime"].toFixed(0) + " ms" - } - } - } - } - } - - /*-----Custom animations-----*/ - property int animationDuration: 200 - pushEnter: Transition { - NumberAnimation { - property: "opacity" - from: 0 - to: 1 - duration: profiles_stack.animationDuration - easing.type: Easing.InOutQuad - } - - /*NumberAnimation { - property: "x" - from: width * 0.1 - to: 0 - duration: 300 - }*/ - - NumberAnimation { - property: "scale" - from: 1.1 - to: 1 - duration: profiles_stack.animationDuration - } - } - pushExit: Transition { - NumberAnimation { - property: "opacity" - from: 1 - to: 0 - duration: profiles_stack.animationDuration - easing.type: Easing.InOutQuad - } - - /*NumberAnimation { - property: "x" - to: -width * 0.1 - from: 0 - duration: 300 - }*/ - - NumberAnimation { - property: "scale" - from: 1 - to: 0.9 - duration: profiles_stack.animationDuration - } - } - - popExit: Transition { - NumberAnimation { - property: "opacity" - from: 1 - to: 0 - duration: profiles_stack.animationDuration - easing.type: Easing.InOutQuad - } - - /*NumberAnimation { - property: "x" - to: width * 0.1 - from: 0 - duration: 300 - }*/ - - NumberAnimation { - property: "scale" - from: 1 - to: 1.1 - duration: profiles_stack.animationDuration - } - } - popEnter: Transition { - NumberAnimation { - property: "opacity" - from: 0 - to: 1 - duration: profiles_stack.animationDuration - easing.type: Easing.InOutQuad - } - - /*NumberAnimation { - property: "x" - from: -width * 0.1 - to: 0 - duration: 300 - }*/ - - NumberAnimation { - property: "scale" - from: 0.9 - to: 1 - duration: profiles_stack.animationDuration - } - } - } - - Item { - id: topContainerItm - - anchors { - top: parent.top - horizontalCenter: parent.horizontalCenter - } - - height: parent.height * 0.15 - width: backgroundRect.width - - RectangularGlow { - id: headerUnderlineEffect - glowRadius: 7 - spread: 0.02 - color: "black" - opacity: 0.18 - anchors.fill: headlineUnderline - scale: 1 - } - - Rectangle { - id: headlineUnderline - height: 1 - width: parent.width - color: "grey" - anchors { - bottom: parent.bottom - left: parent.left - right: parent.right - } - } - - Canvas { - - id: headerBackground - - anchors.fill: parent - - property color color: appTheme.style.viewColor - - onPaint: { - var ctx = getContext("2d"); - - var topMargin = backgroundRect.radius - - - ctx.beginPath(); - ctx.fillStyle = headerBackground.color - ctx.moveTo(width, topMargin); - // - //ctx.lineTo(width, topMargin); - ctx.lineTo(width, height); - ctx.lineTo(0, height); - ctx.lineTo(0, topMargin) - - ctx.arc(topMargin, topMargin, topMargin, 1 * Math.PI, 1.5*Math.PI, false); - ctx.lineTo(width-topMargin, 0) - ctx.arc(width-topMargin, topMargin, topMargin, 1.5*Math.PI, 0, false) - ctx.fill(); - } - } - - Label { - id: head_text - - anchors { - centerIn: parent - } - - width: parent.width * 0.8 - height: parent.height * 0.8 - - fontSizeMode: Text.Fit - font.pixelSize: headlineUnderline.width * 0.1 - minimumPixelSize: 0 - - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - - color: appTheme.style.textColor - - text: profiles_stack.currentItem.title - - } - - } - - FancyButton { - id: head_back - - anchors { - left: parent.left - leftMargin: -height * 0.3 - top:parent.top - topMargin: anchors.leftMargin - } - - height: topContainerItm.height * 0.8 - width: height - - glowOpacity: Math.pow( root.opacity, 100 ) - - backgroundColor: appTheme.style.buttonColor - - image: appTheme.style.backIcon - - onClicked: profiles_stack.depth > 1 ? profiles_stack.pop():root.close() - - } - - FancyButton { - id: head_add - - anchors { - right: parent.right - rightMargin: -height * 0.3 - top:parent.top - topMargin: anchors.rightMargin - } - - height: topContainerItm.height * 0.8 - width: height - - opacity: root.opacity < 1 ? root.opacity : ["ok", "add"].indexOf(profiles_stack.currentItem.secondButt) >= 0 ? 1:0 - - glowOpacity: opacity < 1 ? Math.pow( opacity, 100 ) : Math.pow( opacity, 100 ) - - backgroundColor: appTheme.style.buttonColor - - image: appTheme.style.confirmIcon - imageScale: profiles_stack.currentItem.secondButt === "ok" ? 1:0 - - Label { - anchors { - top: parent.top - topMargin: parent.height/2 - height*0.55 - left: parent.left - leftMargin: parent.width/2 - width/2 - } - opacity: profiles_stack.currentItem.secondButt === "add" ? 1:0 - - color: appTheme.style.textColor - - text: "+" - font.pixelSize: parent.height * 0.8 - } - - onClicked: { - switch(profiles_stack.currentItem.secondButt){ - case "add": - profiles_stack.push(addProfileComp) - break - case "ok": - //speedBackend.createAthlete(fullNameTf.text, userNameTf.text) - } - - } - - Behavior on opacity { - enabled: root.opacity === 1 - NumberAnimation { - duration: 200 - } - } - } - -} diff --git a/qml/ProfilesDialog/AddProfilePage.qml b/qml/ProfilesDialog/AddProfilePage.qml new file mode 100644 index 0000000..0617d96 --- /dev/null +++ b/qml/ProfilesDialog/AddProfilePage.qml @@ -0,0 +1,67 @@ +/* + Speed Climbing Stopwatch - Simple Stopwatch for Climbers + Copyright (C) 2018 - 2019 Itsblue Development - Dorian Zeder + + 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, version 3 of the License. + + 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 QtMultimedia 5.8 +import QtQuick.Window 2.2 +import QtQuick.Controls 2.4 +import QtQuick.Layouts 1.3 +import QtGraphicalEffects 1.0 +import com.itsblue.speedclimbingstopwatch 1.0 + +import "../components" + +Column { + property string title: "add profile" + property string secondButt: "ok" + property string newProfileName: "" + + Connections { + target: head_add + + enabled: true + + onClicked: { + if(speedBackend.createAthlete(userNameTf.text, fullNameTf.text)){ + profilesStack.get(profilesStack.depth - 2 ).opened() + profilesStack.pop() + } + } + } + + TextField { + id: fullNameTf + width: parent.width + placeholderText: "full name" + onTextChanged: { + parent.newProfileName = text + } + Keys.onReturnPressed: { + } + } + TextField { + id: userNameTf + width: parent.width + placeholderText: "username" + onTextChanged: { + parent.newProfileName = text + } + Keys.onReturnPressed: { + } + } +} + diff --git a/qml/ProfilesDialog/ProfileListPage.qml b/qml/ProfilesDialog/ProfileListPage.qml new file mode 100644 index 0000000..ae81eb8 --- /dev/null +++ b/qml/ProfilesDialog/ProfileListPage.qml @@ -0,0 +1,237 @@ +/* + Speed Climbing Stopwatch - Simple Stopwatch for Climbers + Copyright (C) 2018 - 2019 Itsblue Development - Dorian Zeder + + 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, version 3 of the License. + + 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 QtMultimedia 5.8 +import QtQuick.Window 2.2 +import QtQuick.Controls 2.4 +import QtQuick.Layouts 1.3 +import QtGraphicalEffects 1.0 +import com.itsblue.speedclimbingstopwatch 1.0 + +import "../components" + + +RemoteDataListView { + id: profileList + + property int currentAthlete: -1 + property string title: "profiles" + property string secondButt: "add" + + signal opened() + + onOpened: { + profileList.loadData() + } + + //anchors.fill: parent + //anchors.topMargin: topContainerItm.height * 0.1 + + loadData: function () { + status = 905 + //listData = {} + var retData = speedBackend.getAthletes() + + if(retData === undefined){ + status = 500 + return + } + + listData = retData["allAthletes"] + currentAthlete = retData["activeAthlete"] + status = listData.lenght !== false ? 200:0 + } + + delegate: SwipeDelegate { + id: swipeDelegate + + property bool active: profileList.currentAthlete === profileList.listData[index]["id"] + + text: profileList.listData[index]["fullName"] + width: profileList.width - (swipeDelegate.x) + height: profileList.height / 5 + + font.pixelSize: profilesStack.text_pixelSize + + function remove() { + removeAnim.start() + } + + onClicked: { + profilesStack.openResults(profileList.listData[index]["userName"]) + } + + contentItem: Text { + visible: false + } + + Text { + + anchors { + verticalCenter: parent.verticalCenter + left: parent.left + leftMargin: swipeDelegate.width * 0.05 + right: parent.right + rightMargin: swipeDelegate.rightPadding + } + + text: swipeDelegate.text + color: appTheme.style.textColor + + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignLeft + + fontSizeMode: Text.Fit + + font.pixelSize: swipeDelegate.height * 0.4 + + minimumPixelSize: 1 + } + + background: Rectangle { + color: pressed ? appTheme.style.delegatePressedColor : appTheme.style.delegateBackgroundColor + + Behavior on color { + + ColorAnimation { + duration: 200 + } + } + } + + CheckBox { + id: control + + anchors { + verticalCenter: parent.verticalCenter + right: parent.right + rightMargin: 7 + } + + height: parent.height * 0.6 + + checked: swipeDelegate.active + + onCheckedChanged: { + if(checked && !swipeDelegate.active && speedBackend.selectAthlete(profileList.listData[index]["userName"])){ + profileList.loadData() + } + } + + indicator: Rectangle { + implicitWidth: 26 + implicitHeight: 26 + + height: parent.height + width: height + + x: control.leftPadding + y: parent.height / 2 - height / 2 + + radius: width * 0.2 + border.color: control.down ? "#17a81a" : "#21be2b" + color: control.down ? appTheme.style.delegatePressedColor : appTheme.style.delegateBackgroundColor + + Rectangle { + width: parent.width * 0.65 + height: width + anchors.centerIn: parent + radius: control.checked ? width * 0.2:0 + color: control.down ? "#17a81a" : "#21be2b" + opacity: control.checked ? 1:0 + scale: control.checked ? 0.9:0 + + Behavior on color { + ColorAnimation { + duration: 200 + } + } + + Behavior on radius { + NumberAnimation { + duration: 200 + } + } + + Behavior on opacity { + NumberAnimation { + duration: 200 + } + } + + Behavior on scale { + NumberAnimation { + duration: 200 + } + } + } + } + } + + Rectangle { + color: "grey" + height: 1 + width: parent.width * 0.9 + visible: index > 0 + anchors { + horizontalCenter: parent.horizontalCenter + top: parent.top + } + } + + NumberAnimation { + id: removeAnim + target: swipeDelegate + property: "height" + to: 0 + easing.type: Easing.InOutQuad + onStopped: profileModel.model.remove(index) + } + + swipe.transition: Transition { + SmoothedAnimation { velocity: 3; easing.type: Easing.InOutCubic } + } + + swipe.left: Row { + anchors.left: parent.left + height: parent.height + + Label { + id: deleteLabel + text: qsTr("Delete") + color: appTheme.style.textColor + verticalAlignment: Label.AlignVCenter + padding: 12 + height: parent.height + + SwipeDelegate.onClicked: { + profileList.status = 905 + if(speedBackend.deleteAthlete(profileList.listData[index]["userName"])){ + profileList.loadData() + return + } + profileList.status = 200 + } + + background: Rectangle { + color: deleteLabel.SwipeDelegate.pressed ? Qt.darker("tomato", 1.1) : "tomato" + } + } + } + } +} diff --git a/qml/ProfilesDialog/ProfilesDialog.qml b/qml/ProfilesDialog/ProfilesDialog.qml new file mode 100644 index 0000000..3c652c3 --- /dev/null +++ b/qml/ProfilesDialog/ProfilesDialog.qml @@ -0,0 +1,263 @@ +/* + Speed Climbing Stopwatch - Simple Stopwatch for Climbers + Copyright (C) 2018 Itsblue Development - Dorian Zeder + + 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, version 3 of the License. + + 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 QtMultimedia 5.8 +import QtQuick.Window 2.2 +import QtQuick.Controls 2.4 +import QtQuick.Layouts 1.3 +import QtGraphicalEffects 1.0 +import com.itsblue.speedclimbingstopwatch 1.0 +import "../components" + + +Popup { + id: root + + modal: true + dim: false + + opacity: 0 + + enter: Transition { + NumberAnimation { properties: "opacity"; to: 1; duration: 300; easing.type: Easing.InOutQuad } + NumberAnimation { properties: "scale"; from: 0.9; to: 1; duration: 300; easing.type: Easing.InOutQuad } + } + + exit: Transition { + NumberAnimation { properties: "opacity"; to: 0; duration: 300; easing.type: Easing.InOutQuad } + NumberAnimation { properties: "scale"; from: 1; to: 0.9; duration: 300; easing.type: Easing.InOutQuad } + } + + background: Item { + RectangularGlow { + id: backgroundEffect + glowRadius: 7 + spread: 0.02 + color: "black" + opacity: 0.18 + anchors.fill: backgroundRect + cornerRadius: backgroundRect.radius + scale: 1 + } + + Rectangle { + id: backgroundRect + anchors.fill: parent + radius: width * 0.1 + color: appTheme.style.viewColor + } + } + + ProfilesStack { + id: profilesStack + + width: headlineUnderline.width + + anchors { + top: topContainerItm.bottom + left: parent.left + leftMargin: ( parent.width - width ) / 2 + topMargin: headlineUnderline.anchors.topMargin * 1.2 + bottom: parent.bottom + bottomMargin: topContainerItm.height * 0.3 + } + + Behavior on opacity { + NumberAnimation {duration: 200} + } + + Component.onCompleted: { + profilesStack.init() + } + + Connections { + target: root + onOpened: { + profilesStack.init() + } + } + } + + Item { + id: topContainerItm + + anchors { + top: parent.top + horizontalCenter: parent.horizontalCenter + } + + height: parent.height * 0.15 + width: backgroundRect.width + + RectangularGlow { + id: headerUnderlineEffect + glowRadius: 7 + spread: 0.02 + color: "black" + opacity: 0.18 + anchors.fill: headlineUnderline + scale: 1 + } + + Rectangle { + id: headlineUnderline + height: 1 + width: parent.width + color: "grey" + anchors { + bottom: parent.bottom + left: parent.left + right: parent.right + } + } + + Canvas { + + id: headerBackground + + anchors.fill: parent + + property color color: appTheme.style.viewColor + + onPaint: { + var ctx = getContext("2d"); + + var topMargin = backgroundRect.radius + + + ctx.beginPath(); + ctx.fillStyle = headerBackground.color + ctx.moveTo(width, topMargin); + // + //ctx.lineTo(width, topMargin); + ctx.lineTo(width, height); + ctx.lineTo(0, height); + ctx.lineTo(0, topMargin) + + ctx.arc(topMargin, topMargin, topMargin, 1 * Math.PI, 1.5*Math.PI, false); + ctx.lineTo(width-topMargin, 0) + ctx.arc(width-topMargin, topMargin, topMargin, 1.5*Math.PI, 0, false) + ctx.fill(); + } + } + + Label { + id: head_text + + anchors { + centerIn: parent + } + + width: parent.width * 0.8 + height: parent.height * 0.8 + + fontSizeMode: Text.Fit + font.pixelSize: headlineUnderline.width * 0.1 + minimumPixelSize: 0 + + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + + color: appTheme.style.textColor + + text: profilesStack.currentItem.title + + } + + } + + FancyButton { + id: head_back + + anchors { + left: parent.left + leftMargin: -height * 0.3 + top:parent.top + topMargin: anchors.leftMargin + } + + height: topContainerItm.height * 0.8 + width: height + + glowOpacity: Math.pow( root.opacity, 100 ) + + backgroundColor: appTheme.style.buttonColor + + image: appTheme.style.backIcon + + onClicked: profilesStack.depth > 1 ? profilesStack.pop():root.close() + + } + + FancyButton { + id: head_add + + anchors { + right: parent.right + rightMargin: -height * 0.3 + top:parent.top + topMargin: anchors.rightMargin + } + + height: topContainerItm.height * 0.8 + width: height + + opacity: root.opacity < 1 ? root.opacity : ["ok", "add"].indexOf(profilesStack.currentItem.secondButt) >= 0 ? 1:0 + + glowOpacity: opacity < 1 ? Math.pow( opacity, 100 ) : Math.pow( opacity, 100 ) + + backgroundColor: appTheme.style.buttonColor + + image: appTheme.style.confirmIcon + imageScale: profilesStack.currentItem.secondButt === "ok" ? 1:0 + + Label { + anchors { + top: parent.top + topMargin: parent.height/2 - height*0.55 + left: parent.left + leftMargin: parent.width/2 - width/2 + } + opacity: profilesStack.currentItem.secondButt === "add" ? 1:0 + + color: appTheme.style.textColor + + text: "+" + font.pixelSize: parent.height * 0.8 + } + + onClicked: { + switch(profilesStack.currentItem.secondButt){ + case "add": + profilesStack.push(addProfileComp) + break + case "ok": + //speedBackend.createAthlete(fullNameTf.text, userNameTf.text) + } + + } + + Behavior on opacity { + enabled: root.opacity === 1 + NumberAnimation { + duration: 200 + } + } + } + +} diff --git a/qml/ProfilesDialog/ProfilesStack.qml b/qml/ProfilesDialog/ProfilesStack.qml new file mode 100644 index 0000000..6cb9ae1 --- /dev/null +++ b/qml/ProfilesDialog/ProfilesStack.qml @@ -0,0 +1,175 @@ +/* + Speed Climbing Stopwatch - Simple Stopwatch for Climbers + Copyright (C) 2018 - 2019 Itsblue Development - Dorian Zeder + + 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, version 3 of the License. + + 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 QtMultimedia 5.8 +import QtQuick.Window 2.2 +import QtQuick.Controls 2.4 +import QtQuick.Layouts 1.3 +import QtGraphicalEffects 1.0 +import com.itsblue.speedclimbingstopwatch 1.0 + +import "../components" + +StackView { + id: profilesStack + property int text_pixelSize: width * 0.08 + //initialItem: profileListComp + + onCurrentItemChanged: { + currentItem.opened() + } + + function init() { + if(profilesStack.depth === 0){ + profilesStack.openAthletes() + } + else { + profilesStack.currentItem.opened() + } + } + + function openAthletes() { + var athsComp = profileListComp.createObject(null, {}) + profilesStack.push(athsComp) + } + + function openResults( userName ){ + var resComp = resultViewComp.createObject(null, {"userName": userName}) + profilesStack.push(resComp) + } + + /*-----List of all profiles-----*/ + Component { + id: profileListComp + + ProfileListPage { + + } + } + + /*-----Option to add a profile-----*/ + Component { + id: addProfileComp + + AddProfilePage { + + } + } + + // --- Result View --- + Component { + id: resultViewComp + ResultListPage {} + } + + /*-----Custom animations-----*/ + property int animationDuration: 200 + pushEnter: Transition { + NumberAnimation { + property: "opacity" + from: 0 + to: 1 + duration: profilesStack.animationDuration + easing.type: Easing.InOutQuad + } + + /*NumberAnimation { + property: "x" + from: width * 0.1 + to: 0 + duration: 300 + }*/ + + NumberAnimation { + property: "scale" + from: 1.1 + to: 1 + duration: profilesStack.animationDuration + } + } + pushExit: Transition { + NumberAnimation { + property: "opacity" + from: 1 + to: 0 + duration: profilesStack.animationDuration + easing.type: Easing.InOutQuad + } + + /*NumberAnimation { + property: "x" + to: -width * 0.1 + from: 0 + duration: 300 + }*/ + + NumberAnimation { + property: "scale" + from: 1 + to: 0.9 + duration: profilesStack.animationDuration + } + } + + popExit: Transition { + NumberAnimation { + property: "opacity" + from: 1 + to: 0 + duration: profilesStack.animationDuration + easing.type: Easing.InOutQuad + } + + /*NumberAnimation { + property: "x" + to: width * 0.1 + from: 0 + duration: 300 + }*/ + + NumberAnimation { + property: "scale" + from: 1 + to: 1.1 + duration: profilesStack.animationDuration + } + } + popEnter: Transition { + NumberAnimation { + property: "opacity" + from: 0 + to: 1 + duration: profilesStack.animationDuration + easing.type: Easing.InOutQuad + } + + /*NumberAnimation { + property: "x" + from: -width * 0.1 + to: 0 + duration: 300 + }*/ + + NumberAnimation { + property: "scale" + from: 0.9 + to: 1 + duration: profilesStack.animationDuration + } + } +} diff --git a/qml/ProfilesDialog/ResultListPage.qml b/qml/ProfilesDialog/ResultListPage.qml new file mode 100644 index 0000000..a11ed7f --- /dev/null +++ b/qml/ProfilesDialog/ResultListPage.qml @@ -0,0 +1,120 @@ +/* + Speed Climbing Stopwatch - Simple Stopwatch for Climbers + Copyright (C) 2018 - 2019 Itsblue Development - Dorian Zeder + + 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, version 3 of the License. + + 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 QtMultimedia 5.8 +import QtQuick.Window 2.2 +import QtQuick.Controls 2.4 +import QtQuick.Layouts 1.3 +import QtGraphicalEffects 1.0 +import com.itsblue.speedclimbingstopwatch 1.0 +import "../components" + +RemoteDataListView { + id: resultView + + property string userName + property string title: userName + property string secondButt: "none" + + signal opened() + + anchors.margins: 10 + + clip: true + + onOpened: { + loadData() + } + + loadData: function () { + status = 905 + listData = {} + listData = speedBackend.getResults(userName) + status = listData.lenght !== false ? 200:0 + } + + delegate: SmoothItemDelegate { + id: resultDel + + width: parent.width + height: resultView.height / 4 + + backgroundRect.radius: 0 + + function getDateText(){ + var date = new Date(listData[index]["timestamp"]*1000).toLocaleString(Qt.locale(), "dddd, dd.MMM HH:mm") + return date + } + + Rectangle { + color: "grey" + height: 1 + width: parent.width * 0.9 + visible: index > 0 + anchors { + horizontalCenter: parent.horizontalCenter + top: parent.top + } + } + + Column { + anchors.fill: parent + anchors.leftMargin: parent.width * 0.05 + + Label { + id: dateLa + + height: parent.height / parent.children.length + + font.pixelSize: height * 0.8 + fontSizeMode: Text.Fit + + color: appTheme.style.textColor + + text: resultDel.getDateText() + } + + Label { + id: resultLa + + height: parent.height / parent.children.length + + font.pixelSize: height * 0.8 + fontSizeMode: Text.Fit + + color: appTheme.style.textColor + + text: qsTr("result: ") + (listData[index]["result"] / 1000).toFixed(3) + " s" + } + + Label { + id: reactionTimeLa + + height: parent.height / parent.children.length + + font.pixelSize: height * 0.8 + fontSizeMode: Text.Fit + + color: appTheme.style.textColor + + text: qsTr("reaction time: ") + listData[index]["reactionTime"].toFixed(0) + " ms" + } + } + } +} + diff --git a/qml/main.qml b/qml/main.qml index 4b85415..9e01649 100644 --- a/qml/main.qml +++ b/qml/main.qml @@ -22,6 +22,7 @@ import QtQuick.Controls 2.2 import QtGraphicalEffects 1.0 import "." import "./components" +import "./ProfilesDialog" //import QtQuick.Layouts 1.11 import com.itsblue.speedclimbingstopwatch 2.0 diff --git a/qml/qml.qrc b/qml/qml.qrc index 1043b1e..db55f87 100644 --- a/qml/qml.qrc +++ b/qml/qml.qrc @@ -1,7 +1,6 @@ main.qml - ProfilesDialog.qml SettingsDialog.qml components/ProgressCircle.qml components/ConnectionDelegate.qml @@ -16,5 +15,10 @@ components/SmoothSliderDelegate.qml components/RemoteDataListView.qml components/FancyBusyIndicator.qml + ProfilesDialog/ProfilesDialog.qml + ProfilesDialog/ProfilesStack.qml + ProfilesDialog/ProfileListPage.qml + ProfilesDialog/AddProfilePage.qml + ProfilesDialog/ResultListPage.qml diff --git a/sources/climbingrace.cpp b/sources/climbingrace.cpp index f827496..a3b174f 100644 --- a/sources/climbingrace.cpp +++ b/sources/climbingrace.cpp @@ -459,7 +459,7 @@ QVariant ClimbingRace::getAthletes() { QVariantMap tmpAthletes = reply["data"].toMap(); - qDebug() << tmpAthletes; + //qDebug() << tmpAthletes; return tmpAthletes; }