split profile dialog up into multiple files

This commit is contained in:
Dorian Zedler 2019-06-08 11:14:18 +02:00
parent a3f0f13ff3
commit 9bb64027b4
10 changed files with 869 additions and 743 deletions

Binary file not shown.

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
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
}
}
}
}

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
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: {
}
}
}

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
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"
}
}
}
}
}

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
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
}
}
}
}

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
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
}
}
}

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
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"
}
}
}
}

View file

@ -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

View file

@ -1,7 +1,6 @@
<RCC>
<qresource prefix="/">
<file>main.qml</file>
<file>ProfilesDialog.qml</file>
<file>SettingsDialog.qml</file>
<file>components/ProgressCircle.qml</file>
<file>components/ConnectionDelegate.qml</file>
@ -16,5 +15,10 @@
<file>components/SmoothSliderDelegate.qml</file>
<file>components/RemoteDataListView.qml</file>
<file>components/FancyBusyIndicator.qml</file>
<file>ProfilesDialog/ProfilesDialog.qml</file>
<file>ProfilesDialog/ProfilesStack.qml</file>
<file>ProfilesDialog/ProfileListPage.qml</file>
<file>ProfilesDialog/AddProfilePage.qml</file>
<file>ProfilesDialog/ResultListPage.qml</file>
</qresource>
</RCC>

View file

@ -459,7 +459,7 @@ QVariant ClimbingRace::getAthletes() {
QVariantMap tmpAthletes = reply["data"].toMap();
qDebug() << tmpAthletes;
//qDebug() << tmpAthletes;
return tmpAthletes;
}