- added nice animations for tool bar
- started to implement athlete view - fixed minor bug in boulder result view that made symbol and text mismath - fixed performance issues in ranking view
This commit is contained in:
parent
626fb58fe8
commit
efbae668ab
12 changed files with 528 additions and 47 deletions
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<manifest package="com.itsblue.blueROCK" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="0.01b" android:versionCode="1" android:installLocation="auto">
|
||||
<manifest package="com.itsblue.blueROCKtest" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="0.01b" android:versionCode="1" android:installLocation="auto">
|
||||
<application android:hardwareAccelerated="true" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="blueROCK" android:icon="@drawable/icon">
|
||||
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation" android:name="org.qtproject.qt5.android.bindings.QtActivity" android:label="blueROCK (for digitalROCK)" android:screenOrientation="unspecified" android:launchMode="singleTop">
|
||||
<intent-filter>
|
||||
|
|
|
@ -40,6 +40,7 @@ public slots:
|
|||
|
||||
QVariant getCalendar(QString nation, int year);
|
||||
QVariant getRanking(int competitionId, int categoryId, bool registrationData = false, bool rankingData = false, const int routeNumber = -2);
|
||||
QVariant getAthlete(int perId);
|
||||
|
||||
};
|
||||
|
||||
|
|
70
resources/qml/Components/FadeAnimation.qml
Normal file
70
resources/qml/Components/FadeAnimation.qml
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
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.0
|
||||
|
||||
SequentialAnimation {
|
||||
id: root
|
||||
property QtObject target
|
||||
property string fadeProperty: "scale"
|
||||
property int fadeDuration: 150
|
||||
property int fadeDuration_in: fadeDuration
|
||||
property int fadeDuration_out: fadeDuration
|
||||
property alias outValue: outAnimation.to
|
||||
property alias inValue: inAnimation.to
|
||||
property alias outEasingType: outAnimation.easing.type
|
||||
property alias inEasingType: inAnimation.easing.type
|
||||
property string easingType: "Quad"
|
||||
ParallelAnimation {
|
||||
NumberAnimation { // in the default case, fade scale to 0
|
||||
id: outAnimation
|
||||
target: root.target
|
||||
property: "scale"
|
||||
duration: root.fadeDuration_in
|
||||
to: 0.9
|
||||
easing.type: Easing["In"+root.easingType]
|
||||
}
|
||||
NumberAnimation { // in the default case, fade scale to 0
|
||||
id: outAnimation2
|
||||
target: root.target
|
||||
property: "opacity"
|
||||
duration: root.fadeDuration_in
|
||||
to: 0
|
||||
easing.type: Easing["In"+root.easingType]
|
||||
}
|
||||
}
|
||||
PropertyAction { } // actually change the property targeted by the Behavior between the 2 other animations
|
||||
ParallelAnimation {
|
||||
NumberAnimation { // in the default case, fade scale back to 1
|
||||
id: inAnimation
|
||||
target: root.target
|
||||
property: root.fadeProperty
|
||||
duration: root.fadeDuration_out
|
||||
to: 1
|
||||
easing.type: Easing["Out"+root.easingType]
|
||||
}
|
||||
NumberAnimation { // in the default case, fade scale to 0
|
||||
id: inAnimation2
|
||||
target: root.target
|
||||
property: "opacity"
|
||||
duration: root.fadeDuration_in
|
||||
to: 1
|
||||
easing.type: Easing["In"+root.easingType]
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -49,6 +49,10 @@ DataListView {
|
|||
fadeInPa.start()
|
||||
}
|
||||
|
||||
onPressAndHold: {
|
||||
app.openAthlete(thisData["PerId"])
|
||||
}
|
||||
|
||||
ParallelAnimation {
|
||||
id: fadeInPa
|
||||
NumberAnimation { target: partDel; property: "opacity"; from: 0; to: 1.0; duration: 400 }
|
||||
|
@ -192,8 +196,8 @@ DataListView {
|
|||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
id: detailResultsCol
|
||||
Item {
|
||||
id: detailResultsItm
|
||||
|
||||
anchors {
|
||||
top: partDelCol.bottom
|
||||
|
@ -202,7 +206,88 @@ DataListView {
|
|||
margins: 5
|
||||
}
|
||||
|
||||
height: enabled ? ( 20 + spacing ) * detailResultRowRep.model:0
|
||||
height: detailResultsLd.status === Loader.Ready && detailResultsLd.enabled ? ( 20 + detailResultsLd.item.spacing ) * detailResultsLd.item.model:0
|
||||
|
||||
Loader {
|
||||
id: detailResultsLd
|
||||
|
||||
property alias partDel: partDel
|
||||
property alias partDelSecondRow: partDelSecondRow
|
||||
|
||||
onEnabledChanged: {
|
||||
if(enabled){
|
||||
sourceComponent = detailResultsComp
|
||||
}
|
||||
else {
|
||||
hideDelayPa.start()
|
||||
}
|
||||
}
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
height: parent.height
|
||||
|
||||
PauseAnimation {
|
||||
id: hideDelayPa
|
||||
|
||||
duration: 200
|
||||
|
||||
onRunningChanged: {
|
||||
if(!running && !detailResultsLd.enabled){
|
||||
detailResultsLd.sourceComponent = undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "closed"
|
||||
PropertyChanges {
|
||||
target: partDel
|
||||
height: 70
|
||||
}
|
||||
|
||||
PropertyChanges {
|
||||
target: detailResultsLd
|
||||
enabled: false
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "opened"
|
||||
PropertyChanges {
|
||||
target: partDel
|
||||
height: 70 + detailResultsLd.height
|
||||
}
|
||||
|
||||
PropertyChanges {
|
||||
target: detailResultsLd
|
||||
enabled: true
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
transitions: [
|
||||
Transition {
|
||||
from: "*"
|
||||
to: "*"
|
||||
NumberAnimation {
|
||||
properties: "height"
|
||||
duration: 200
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
}
|
||||
|
||||
Component {
|
||||
id: detailResultsComp
|
||||
Column {
|
||||
id: detailResultsCol
|
||||
|
||||
property alias model: detailResultRowRep.model
|
||||
|
||||
Repeater {
|
||||
id: detailResultRowRep
|
||||
|
@ -228,8 +313,8 @@ DataListView {
|
|||
}
|
||||
|
||||
delegate: Row {
|
||||
width: parent.width
|
||||
height: detailResultsCol.height / detailResultRowRep.model - detailResultsCol.spacing
|
||||
width: parent.width
|
||||
|
||||
visible: height > 0
|
||||
|
||||
|
@ -282,43 +367,5 @@ DataListView {
|
|||
|
||||
}
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "closed"
|
||||
PropertyChanges {
|
||||
target: partDel
|
||||
height: 70
|
||||
}
|
||||
|
||||
PropertyChanges {
|
||||
target: detailResultsCol
|
||||
enabled: false
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "opened"
|
||||
PropertyChanges {
|
||||
target: partDel
|
||||
height: 70 + detailResultsCol.height
|
||||
}
|
||||
|
||||
PropertyChanges {
|
||||
target: detailResultsCol
|
||||
enabled: true
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
transitions: [
|
||||
Transition {
|
||||
from: "*"
|
||||
to: "*"
|
||||
NumberAnimation {
|
||||
properties: "height"
|
||||
duration: 200
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,6 +42,10 @@ DataListView {
|
|||
fadeInPa.start()
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
app.openAthlete(thisData["PerId"])
|
||||
}
|
||||
|
||||
ParallelAnimation {
|
||||
id: fadeInPa
|
||||
NumberAnimation { target: partDel; property: "opacity"; from: 0; to: 1.0; duration: 400 }
|
||||
|
|
|
@ -48,6 +48,10 @@ DataListView {
|
|||
fadeInPa.start()
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
app.openAthlete(thisData["PerId"])
|
||||
}
|
||||
|
||||
ParallelAnimation {
|
||||
id: fadeInPa
|
||||
NumberAnimation { target: partDel; property: "opacity"; from: 0; to: 1.0; duration: 400 }
|
||||
|
@ -177,6 +181,10 @@ DataListView {
|
|||
|
||||
property var resultData: boulderResRep.getDataForIcon(index)
|
||||
|
||||
onResultDataChanged: {
|
||||
boulderResCv.requestPaint()
|
||||
}
|
||||
|
||||
anchors.centerIn: parent
|
||||
|
||||
height: parent.height > parent.width ? parent.width * 0.9:parent.height * 0.9
|
||||
|
|
|
@ -40,6 +40,10 @@ DataListView {
|
|||
fadeInPa.start()
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
app.openAthlete(thisData["PerId"])
|
||||
}
|
||||
|
||||
ParallelAnimation {
|
||||
id: fadeInPa
|
||||
NumberAnimation { target: partDel; property: "opacity"; from: 0; to: 1.0; duration: 400 }
|
||||
|
|
222
resources/qml/Pages/AthleteProfilePage.qml
Normal file
222
resources/qml/Pages/AthleteProfilePage.qml
Normal file
|
@ -0,0 +1,222 @@
|
|||
import QtQuick 2.9
|
||||
import QtQuick.Controls 2.4
|
||||
import QtQuick.Controls.Material 2.3
|
||||
|
||||
import "../Components"
|
||||
|
||||
Page {
|
||||
id: root
|
||||
|
||||
title: perData["firstname"] + " " + perData["lastname"]
|
||||
property bool titleIsPageTitle: true
|
||||
property bool ready
|
||||
property int status: -1
|
||||
|
||||
property int perId: -1
|
||||
|
||||
property var perData: ({})
|
||||
|
||||
Component.onCompleted: {
|
||||
if(root.loadData(root.perId)){
|
||||
root.ready = true
|
||||
}
|
||||
}
|
||||
|
||||
function loadData(perId) {
|
||||
console.log("loading athlete: ", perId)
|
||||
|
||||
root.status = 905
|
||||
|
||||
var ret = serverConn.getAthlete(perId)
|
||||
|
||||
root.status = ret["status"]
|
||||
|
||||
if(ret["status"] === 200){
|
||||
root.perData = ret["data"]
|
||||
return true
|
||||
}
|
||||
else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
ScrollView {
|
||||
id: mainSv
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: 10
|
||||
anchors.rightMargin: 14
|
||||
|
||||
contentWidth: parent.width - anchors.leftMargin - anchors.rightMargin
|
||||
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
|
||||
anchors {
|
||||
top: mainSv.top
|
||||
left: mainSv.right
|
||||
margins: 10
|
||||
leftMargin: 3
|
||||
bottom: mainSv.bottom
|
||||
}
|
||||
|
||||
width: 8
|
||||
|
||||
active: true
|
||||
}
|
||||
|
||||
Column {
|
||||
id: mainCol
|
||||
|
||||
width: parent.width
|
||||
|
||||
Row {
|
||||
height: root.height * 0.3
|
||||
width: parent.width
|
||||
|
||||
Image {
|
||||
id: photo
|
||||
|
||||
property bool ready: false
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
height: parent.height * 0.9
|
||||
width: status === Image.Null || status === Image.Error ? 0:parent.width * 0.5
|
||||
|
||||
fillMode: Image.PreserveAspectFit
|
||||
|
||||
source: perData["photo"] === undefined ? "":perData["photo"].replace("https", "http").replace("www.digitalrock.de", "egw.ifsc-climbing.org")
|
||||
asynchronous: true
|
||||
|
||||
FancyBusyIndicator {
|
||||
height: width
|
||||
anchors.centerIn: parent
|
||||
opacity: photo.status === Image.Loading
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
height: parent.height * 0.9
|
||||
width: parent.width - photo.width
|
||||
|
||||
Label {
|
||||
|
||||
height: parent.height * 0.2
|
||||
width: parent.width
|
||||
|
||||
font.pixelSize: height * 0.6
|
||||
font.bold: true
|
||||
minimumPixelSize: 1
|
||||
|
||||
fontSizeMode: Text.Fit
|
||||
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
|
||||
text: perData["firstname"] + " " + perData["lastname"]
|
||||
}
|
||||
|
||||
Label {
|
||||
height: parent.height * 0.2
|
||||
width: parent.width
|
||||
|
||||
font.pixelSize: height * 0.6
|
||||
font.bold: false
|
||||
minimumPixelSize: 1
|
||||
|
||||
fontSizeMode: Text.Fit
|
||||
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
|
||||
text: perData["nation"]
|
||||
}
|
||||
|
||||
Label {
|
||||
height: parent.height * 0.15
|
||||
width: parent.width
|
||||
|
||||
font.pixelSize: height * 0.6
|
||||
font.bold: false
|
||||
minimumPixelSize: 1
|
||||
|
||||
fontSizeMode: Text.Fit
|
||||
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
|
||||
text: "<html><a href='" + perData["fed_url"] + "'>" + perData["federation"] + "</a>"
|
||||
|
||||
onLinkActivated: {
|
||||
Qt.openUrlExternally(link)
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
height: parent.height * 0.15
|
||||
width: parent.width
|
||||
|
||||
font.pixelSize: height * 0.6
|
||||
font.bold: false
|
||||
minimumPixelSize: 1
|
||||
|
||||
fontSizeMode: Text.Fit
|
||||
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
|
||||
text: qsTr("age") + ": " + perData["age"]
|
||||
}
|
||||
|
||||
Label {
|
||||
height: parent.height * 0.15
|
||||
width: parent.width
|
||||
|
||||
font.pixelSize: height * 0.6
|
||||
font.bold: false
|
||||
minimumPixelSize: 1
|
||||
|
||||
fontSizeMode: Text.Fit
|
||||
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
|
||||
text: qsTr("year of birth") + ": " + perData["birthdate"]
|
||||
}
|
||||
|
||||
Label {
|
||||
height: parent.height * 0.15
|
||||
width: parent.width
|
||||
|
||||
font.pixelSize: height * 0.6
|
||||
font.bold: false
|
||||
minimumPixelSize: 1
|
||||
|
||||
fontSizeMode: Text.Fit
|
||||
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
|
||||
text: qsTr("city") + ": " + perData["city"]
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Label {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
width: parent.width
|
||||
|
||||
wrapMode: Label.Wrap
|
||||
|
||||
text: perData["freetext"]
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -492,7 +492,9 @@ Page {
|
|||
onClicked: {
|
||||
yearSelectPu.close()
|
||||
root.year = yearSelectPu.yearList[index]
|
||||
loadingDl.open()
|
||||
root.loadData(root.nation, root.year)
|
||||
loadingDl.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,6 +48,10 @@ Window {
|
|||
|
||||
anchors.fill: parent
|
||||
|
||||
Component.onCompleted: {
|
||||
//app.openAthlete(53139) // dorian: 53139 , rustam: 6933 , helen: 53300
|
||||
}
|
||||
|
||||
Shortcut {
|
||||
sequences: ["Esc", "Back"]
|
||||
enabled: mainStack.depth > 1
|
||||
|
@ -194,6 +198,8 @@ Window {
|
|||
|
||||
width: parent.width
|
||||
|
||||
scale: 1
|
||||
|
||||
elide: "ElideRight"
|
||||
|
||||
font.bold: true
|
||||
|
@ -221,6 +227,12 @@ Window {
|
|||
|
||||
return(titleString)
|
||||
}
|
||||
|
||||
Behavior on text {
|
||||
FadeAnimation {
|
||||
target: toolBarTitleLa
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
|
@ -246,6 +258,12 @@ Window {
|
|||
|
||||
return(titleString)
|
||||
}
|
||||
|
||||
Behavior on text {
|
||||
FadeAnimation {
|
||||
target: toolBarSubTitleLa
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -261,7 +279,75 @@ Window {
|
|||
bottom: parent.bottom
|
||||
}
|
||||
|
||||
sourceComponent: mainStack.currentItem.headerComponent
|
||||
//sourceComponent: mainStack.currentItem.headerComponent
|
||||
|
||||
Connections {
|
||||
target: mainStack
|
||||
onCurrentItemChanged: {
|
||||
disappearNa.start()
|
||||
}
|
||||
}
|
||||
|
||||
ParallelAnimation {
|
||||
id: appearNa
|
||||
|
||||
NumberAnimation {
|
||||
|
||||
target: extraComponentLoader
|
||||
property: "opacity"
|
||||
|
||||
from: 0
|
||||
to: 1
|
||||
|
||||
duration: 150
|
||||
}
|
||||
|
||||
NumberAnimation {
|
||||
|
||||
target: extraComponentLoader
|
||||
property: "scale"
|
||||
|
||||
from: 0.9
|
||||
to: 1
|
||||
|
||||
duration: 150
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ParallelAnimation {
|
||||
id: disappearNa
|
||||
|
||||
NumberAnimation {
|
||||
|
||||
target: extraComponentLoader
|
||||
property: "opacity"
|
||||
|
||||
from: 1
|
||||
to: 0
|
||||
|
||||
duration: 150
|
||||
}
|
||||
|
||||
NumberAnimation {
|
||||
|
||||
target: extraComponentLoader
|
||||
property: "scale"
|
||||
|
||||
from: 1
|
||||
to: 0.9
|
||||
|
||||
duration: 150
|
||||
}
|
||||
|
||||
onRunningChanged: {
|
||||
if(!running){
|
||||
extraComponentLoader.sourceComponent = mainStack.currentItem.headerComponent
|
||||
appearNa.start()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -359,6 +445,22 @@ Window {
|
|||
loadingDl.close()
|
||||
}
|
||||
|
||||
function openAthlete(perId) {
|
||||
loadingDl.open()
|
||||
|
||||
var athleteComp = Qt.createComponent("qrc:/Pages/AthleteProfilePage.qml").createObject(null, {"perId": perId})
|
||||
app.errorCode = athleteComp.status
|
||||
|
||||
if(athleteComp.ready){
|
||||
mainStack.push(athleteComp)
|
||||
}
|
||||
else {
|
||||
delete(athleteComp)
|
||||
}
|
||||
|
||||
loadingDl.close()
|
||||
}
|
||||
|
||||
function getErrorInfo(errorCode) {
|
||||
|
||||
var infoLevel
|
||||
|
|
|
@ -14,5 +14,7 @@
|
|||
<file>Components/StartlistView.qml</file>
|
||||
<file>Components/RankingView.qml</file>
|
||||
<file>Components/PullRefresher.qml</file>
|
||||
<file>Pages/AthleteProfilePage.qml</file>
|
||||
<file>Components/FadeAnimation.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
@ -57,6 +57,25 @@ QVariant ServerConn::getRanking(int competiotionId, int categoryId, bool registr
|
|||
return data;
|
||||
}
|
||||
|
||||
QVariant ServerConn::getAthlete(int perId){
|
||||
QString requestUrl = "http://egw.ifsc-climbing.org/egw/ranking/json.php?person=" + QString::number(perId);
|
||||
|
||||
qDebug() << requestUrl;
|
||||
|
||||
QVariantMap ret = this->senddata(QUrl(requestUrl));
|
||||
|
||||
if(ret["status"] != 200){
|
||||
// request was a failure
|
||||
return QVariantMap({{"status", ret["status"]}, {"data", ""}});
|
||||
}
|
||||
|
||||
QJsonDocument jsonReply = QJsonDocument::fromJson(ret["text"].toString().toUtf8());
|
||||
|
||||
QVariantMap data = {{"status", 200}, {"data", jsonReply.toVariant()}};
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
// ------------------------
|
||||
// --- Helper functions ---
|
||||
// ------------------------
|
||||
|
@ -73,9 +92,9 @@ QVariantMap ServerConn::senddata(QUrl serviceUrl, QUrlQuery pdata)
|
|||
request.setHeader(QNetworkRequest::ContentTypeHeader,
|
||||
"application/x-www-form-urlencoded");
|
||||
|
||||
QSslConfiguration config = QSslConfiguration::defaultConfiguration();
|
||||
config.setProtocol(QSsl::TlsV1_2);
|
||||
request.setSslConfiguration(config);
|
||||
//QSslConfiguration config = QSslConfiguration::defaultConfiguration();
|
||||
//config.setProtocol(QSsl::TlsV1_2);
|
||||
//request.setSslConfiguration(config);
|
||||
|
||||
//send a POST request with the given url and data to the server
|
||||
|
||||
|
|
Loading…
Reference in a new issue