diff --git a/android_release.keystore b/android_release.keystore deleted file mode 100644 index f330509..0000000 Binary files a/android_release.keystore and /dev/null differ 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; }