- 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:
Dorian Zedler 2019-05-12 21:33:22 +02:00
parent 626fb58fe8
commit efbae668ab
12 changed files with 528 additions and 47 deletions

View file

@ -1,5 +1,5 @@
<?xml version="1.0"?> <?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"> <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"> <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> <intent-filter>

View file

@ -40,6 +40,7 @@ public slots:
QVariant getCalendar(QString nation, int year); QVariant getCalendar(QString nation, int year);
QVariant getRanking(int competitionId, int categoryId, bool registrationData = false, bool rankingData = false, const int routeNumber = -2); QVariant getRanking(int competitionId, int categoryId, bool registrationData = false, bool rankingData = false, const int routeNumber = -2);
QVariant getAthlete(int perId);
}; };

View 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]
}
}
}

View file

@ -49,6 +49,10 @@ DataListView {
fadeInPa.start() fadeInPa.start()
} }
onPressAndHold: {
app.openAthlete(thisData["PerId"])
}
ParallelAnimation { ParallelAnimation {
id: fadeInPa id: fadeInPa
NumberAnimation { target: partDel; property: "opacity"; from: 0; to: 1.0; duration: 400 } NumberAnimation { target: partDel; property: "opacity"; from: 0; to: 1.0; duration: 400 }
@ -192,8 +196,8 @@ DataListView {
} }
} }
Column { Item {
id: detailResultsCol id: detailResultsItm
anchors { anchors {
top: partDelCol.bottom top: partDelCol.bottom
@ -202,7 +206,88 @@ DataListView {
margins: 5 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 { Repeater {
id: detailResultRowRep id: detailResultRowRep
@ -228,8 +313,8 @@ DataListView {
} }
delegate: Row { delegate: Row {
width: parent.width
height: detailResultsCol.height / detailResultRowRep.model - detailResultsCol.spacing height: detailResultsCol.height / detailResultRowRep.model - detailResultsCol.spacing
width: parent.width
visible: height > 0 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
}
}
]
} }
} }

View file

@ -42,6 +42,10 @@ DataListView {
fadeInPa.start() fadeInPa.start()
} }
onClicked: {
app.openAthlete(thisData["PerId"])
}
ParallelAnimation { ParallelAnimation {
id: fadeInPa id: fadeInPa
NumberAnimation { target: partDel; property: "opacity"; from: 0; to: 1.0; duration: 400 } NumberAnimation { target: partDel; property: "opacity"; from: 0; to: 1.0; duration: 400 }

View file

@ -48,6 +48,10 @@ DataListView {
fadeInPa.start() fadeInPa.start()
} }
onClicked: {
app.openAthlete(thisData["PerId"])
}
ParallelAnimation { ParallelAnimation {
id: fadeInPa id: fadeInPa
NumberAnimation { target: partDel; property: "opacity"; from: 0; to: 1.0; duration: 400 } NumberAnimation { target: partDel; property: "opacity"; from: 0; to: 1.0; duration: 400 }
@ -177,6 +181,10 @@ DataListView {
property var resultData: boulderResRep.getDataForIcon(index) property var resultData: boulderResRep.getDataForIcon(index)
onResultDataChanged: {
boulderResCv.requestPaint()
}
anchors.centerIn: parent anchors.centerIn: parent
height: parent.height > parent.width ? parent.width * 0.9:parent.height * 0.9 height: parent.height > parent.width ? parent.width * 0.9:parent.height * 0.9

View file

@ -40,6 +40,10 @@ DataListView {
fadeInPa.start() fadeInPa.start()
} }
onClicked: {
app.openAthlete(thisData["PerId"])
}
ParallelAnimation { ParallelAnimation {
id: fadeInPa id: fadeInPa
NumberAnimation { target: partDel; property: "opacity"; from: 0; to: 1.0; duration: 400 } NumberAnimation { target: partDel; property: "opacity"; from: 0; to: 1.0; duration: 400 }

View 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"]
}
}
}
}

View file

@ -492,7 +492,9 @@ Page {
onClicked: { onClicked: {
yearSelectPu.close() yearSelectPu.close()
root.year = yearSelectPu.yearList[index] root.year = yearSelectPu.yearList[index]
loadingDl.open()
root.loadData(root.nation, root.year) root.loadData(root.nation, root.year)
loadingDl.close()
} }
} }
} }

View file

@ -48,6 +48,10 @@ Window {
anchors.fill: parent anchors.fill: parent
Component.onCompleted: {
//app.openAthlete(53139) // dorian: 53139 , rustam: 6933 , helen: 53300
}
Shortcut { Shortcut {
sequences: ["Esc", "Back"] sequences: ["Esc", "Back"]
enabled: mainStack.depth > 1 enabled: mainStack.depth > 1
@ -194,6 +198,8 @@ Window {
width: parent.width width: parent.width
scale: 1
elide: "ElideRight" elide: "ElideRight"
font.bold: true font.bold: true
@ -221,6 +227,12 @@ Window {
return(titleString) return(titleString)
} }
Behavior on text {
FadeAnimation {
target: toolBarTitleLa
}
}
} }
Label { Label {
@ -246,6 +258,12 @@ Window {
return(titleString) return(titleString)
} }
Behavior on text {
FadeAnimation {
target: toolBarSubTitleLa
}
}
} }
} }
@ -261,7 +279,75 @@ Window {
bottom: parent.bottom 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() 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) { function getErrorInfo(errorCode) {
var infoLevel var infoLevel

View file

@ -14,5 +14,7 @@
<file>Components/StartlistView.qml</file> <file>Components/StartlistView.qml</file>
<file>Components/RankingView.qml</file> <file>Components/RankingView.qml</file>
<file>Components/PullRefresher.qml</file> <file>Components/PullRefresher.qml</file>
<file>Pages/AthleteProfilePage.qml</file>
<file>Components/FadeAnimation.qml</file>
</qresource> </qresource>
</RCC> </RCC>

View file

@ -57,6 +57,25 @@ QVariant ServerConn::getRanking(int competiotionId, int categoryId, bool registr
return data; 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 --- // --- Helper functions ---
// ------------------------ // ------------------------
@ -73,9 +92,9 @@ QVariantMap ServerConn::senddata(QUrl serviceUrl, QUrlQuery pdata)
request.setHeader(QNetworkRequest::ContentTypeHeader, request.setHeader(QNetworkRequest::ContentTypeHeader,
"application/x-www-form-urlencoded"); "application/x-www-form-urlencoded");
QSslConfiguration config = QSslConfiguration::defaultConfiguration(); //QSslConfiguration config = QSslConfiguration::defaultConfiguration();
config.setProtocol(QSsl::TlsV1_2); //config.setProtocol(QSsl::TlsV1_2);
request.setSslConfiguration(config); //request.setSslConfiguration(config);
//send a POST request with the given url and data to the server //send a POST request with the given url and data to the server