Compare commits

...

57 commits
v0.6.0 ... main

Author SHA1 Message Date
Dorian Zedler bf617ba72c
Chore: don't show 0.000 in speed results
All checks were successful
continuous-integration/drone/push Build is passing
2023-07-15 10:15:15 +02:00
Dorian Zedler 5694d61c4b
Feat: show route_quota 2023-07-15 10:11:26 +02:00
Dorian Zedler cd0500c40b
Feat: show both results in speed quali 2023-07-05 16:27:15 +02:00
Dorian Zedler 12185337b9
Merge branch 'main' of ssh://itsblue.dev/blueROCK/app 2023-05-14 22:56:33 +02:00
Dorian Zedler fe453cd5ac
Fix: fix for new Android API 2023-05-14 22:55:49 +02:00
Dorian Zedler 6644d16a92 Chore: update qt-andrioid version
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2023-02-06 08:57:07 +01:00
Dorian Zedler f42d8fb8d7
Chore: update changelog
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2022-10-20 06:42:18 +02:00
Dorian Zedler e6569694e4
Chore: update permissions 2022-10-20 06:41:37 +02:00
Dorian Zedler 38dbbb3b32 Merge pull request 'Fix: release CI' (#38) from fix/release-ci into main
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone/tag Build is passing
continuous-integration/drone Build is passing
Reviewed-on: #38
2022-08-14 18:08:56 +02:00
Dorian Zedler ce7fc3d367 Fix: release CI
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone/pr Build was killed
2022-08-14 18:08:42 +02:00
Dorian Zedler 8e4e135f9c Merge pull request 'release: 0.7.0' (#37) from release/0.7.0 into main
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone/tag Build is passing
Reviewed-on: #37
2022-08-14 17:55:44 +02:00
Dorian Zedler c13d108cff
Chore: update release date
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone/pr Build was killed
2022-08-14 17:55:26 +02:00
Dorian Zedler 367807b90d
Chore: prepare release 0.7.0
Some checks are pending
continuous-integration/drone/push Build is running
continuous-integration/drone/pr Build is running
2022-08-14 17:53:56 +02:00
Dorian Zedler 6ca5b81f6d
Fix: Font size on Android 2022-08-14 17:53:35 +02:00
Dorian Zedler 05bce5e97d Merge pull request 'Chore: refactor speed flowchart (fixes #26)' (#36) from fix/speed-flowchart into main
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: #36
2022-08-14 17:50:58 +02:00
Dorian Zedler a238a68638
Chore: remove log
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2022-08-14 17:46:19 +02:00
Dorian Zedler 6d7009b183
Chore: refactor speed flowchart (fixes #26)
Some checks are pending
continuous-integration/drone/push Build is running
continuous-integration/drone/pr Build is running
2022-08-14 17:43:38 +02:00
Dorian Zedler 0ca2725bf3 Merge pull request 'Fix: send file on android api 30 (fixes #32)' (#33) from fix/share-on-android-api-30 into main
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #33
2022-08-11 12:49:41 +02:00
Dorian Zedler 447c1135dd
Fix: send file on android api 30 (fixes #32)
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2022-08-11 12:44:39 +02:00
Dorian Zedler 38bdf15f40 Merge pull request 'Feat: add start numbers to speed flowchart (fixes #30)' (#31) from feat/startnumbers-in-speed-tree into main
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #31
2022-08-11 12:15:17 +02:00
Dorian Zedler 0920ee6f77
Fix: don't go to comp on start
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2022-08-11 08:51:05 +02:00
Dorian Zedler a1ea8a4c65
Fix: don't unlock speed flowchart
Some checks reported errors
continuous-integration/drone/push Build is running
continuous-integration/drone/pr Build was killed
2022-08-11 08:49:37 +02:00
Dorian Zedler 21c479cd55
Feat: add start numbers to speed flowchart (fixes #30)
Some checks reported errors
continuous-integration/drone/push Build is running
continuous-integration/drone/pr Build was killed
2022-08-11 08:47:22 +02:00
Dorian Zedler 766da23e26
Merge branch 'main' of ssh://itsblue.dev/blueROCK/app
All checks were successful
continuous-integration/drone/push Build is passing
2022-08-10 09:32:35 +02:00
Dorian Zedler 496d66a521
Chore: update screenshots 2022-08-10 09:32:11 +02:00
Dorian Zedler 43d98bd43e Update '.drone.yml'
All checks were successful
continuous-integration/drone/push Build is passing
2022-08-08 23:48:26 +02:00
Dorian Zedler 30471725d0 Update '.drone.yml'
Some checks are pending
continuous-integration/drone/push Build is running
2022-08-08 23:48:09 +02:00
Dorian Zedler 88ebde27f2
Chore: update version and changelog
All checks were successful
continuous-integration/drone/push Build is passing
2022-08-06 22:00:37 +02:00
Dorian Zedler 4bf2e2b3b3
Merge branch 'master' of ssh://itsblue.dev/blueROCK/app
Some checks are pending
continuous-integration/drone/push Build is running
2022-08-06 21:56:17 +02:00
Dorian Zedler d234474233
Chore: remove app.bluerock.dev from domains 2022-08-06 21:55:59 +02:00
Dorian Zedler 78659fe769 Update '.drone.yml'
All checks were successful
continuous-integration/drone/push Build is passing
2022-08-03 12:52:55 +02:00
Dorian Zedler 99f49e0798
Merge branch 'master' of ssh://itsblue.dev/blueROCK/app
Some checks reported errors
continuous-integration/drone/push Build was killed
2022-08-03 12:52:08 +02:00
Dorian Zedler 455c4044c2
Merge branch 'getcommit' 2022-08-03 12:51:57 +02:00
Dorian Zedler ce67df3416
Chore: update openssl lib path 2022-08-03 12:50:15 +02:00
Dorian Zedler 53460b2091
Add fastlane and ressources 2022-08-01 14:30:57 +02:00
Dorian Zedler 2f3f0488da Update '.drone.yml'
All checks were successful
continuous-integration/drone/push Build is passing
2022-08-01 12:00:43 +02:00
Dorian Zedler a026912929 Update '.drone.yml'
All checks were successful
continuous-integration/drone/push Build is passing
2022-07-30 14:35:59 +02:00
Dorian Zedler 551c6ffb6d Update '.drone.yml'
All checks were successful
continuous-integration/drone/push Build is passing
2022-07-30 14:22:04 +02:00
Dorian Zedler 55a5aac4e1 Update '.drone.yml'
Some checks reported errors
continuous-integration/drone/push Build was killed
2022-07-30 13:52:34 +02:00
Dorian Zedler 21b88575fb Update '.drone.yml'
All checks were successful
continuous-integration/drone/push Build is passing
2022-07-29 14:40:16 +02:00
Dorian Zedler fb17ec52cd Update '.drone.yml'
All checks were successful
continuous-integration/drone/push Build is passing
2022-07-29 14:35:31 +02:00
Dorian Zedler 6b91988ac5 Update '.drone.yml'
All checks were successful
continuous-integration/drone/push Build is passing
2022-07-29 14:30:09 +02:00
Dorian Zedler 75d7212fd9 Update '.drone.yml'
Some checks reported errors
continuous-integration/drone/push Build encountered an error
2022-07-29 14:29:52 +02:00
Dorian Zedler 3a735e2cf4 Update '.drone.yml'
Some checks reported errors
continuous-integration/drone/push Build encountered an error
2022-07-29 14:29:01 +02:00
Dorian Zedler c92362f07a Update '.drone.yml'
Some checks reported errors
continuous-integration/drone/push Build encountered an error
2022-07-29 14:26:45 +02:00
Dorian Zedler 3492e6c511 Update '.drone.yml'
All checks were successful
continuous-integration/drone/push Build is passing
2022-07-29 14:19:01 +02:00
Dorian Zedler 5cfad624a3 Update '.drone.yml'
Some checks failed
continuous-integration/drone/push Build is failing
2022-07-29 14:09:49 +02:00
Dorian Zedler dabb2473b3
Feat: Add fastlande stuff 2022-07-29 09:23:41 +02:00
Dorian Zedler d33748a06d Update '.drone.yml'
Some checks failed
continuous-integration/drone/push Build is failing
2022-07-29 09:06:39 +02:00
Dorian Zedler 1cd7ad6649 Update '.drone.yml'
Some checks failed
continuous-integration/drone/push Build is failing
2022-07-29 08:49:02 +02:00
Dorian Zedler d881b203fa Add '.drone.yml'
Some checks reported errors
continuous-integration/drone Build encountered an error
2022-07-29 08:48:09 +02:00
Dorian Zedler 175c2ea264
Merge branch 'version/0.5.1' 2021-10-20 21:41:28 +02:00
Dorian Zedler 484fb8d7a9
Bump version 2021-10-20 21:35:47 +02:00
Dorian Zedler 7fbf90b215
Add privacy policy link 2021-10-20 20:21:45 +02:00
Dorian Zedler a2e6cdccb9
Version 0.5.1 2021-07-06 09:17:05 +02:00
Dorian Zedler f1d6915c52 Merge branch 'fix/in-appPurchase' into 'master'
Fix in-app purchase

Closes #25

See merge request dorian/blueROCK!2
2021-07-06 07:12:44 +00:00
Dorian Zedler f422aecb77
Fix in-app purchase 2021-07-06 09:11:15 +02:00
43 changed files with 1215 additions and 619 deletions

30
.drone.yml Normal file
View file

@ -0,0 +1,30 @@
kind: pipeline
name: default
steps:
- name: submodules
image: alpine/git
commands:
- git submodule update --init --recursive
- name: build app
image: itsblue.dev/plugins/qt-android:5.15.5-4
settings:
qmake_arguments: "CONFIG+=release"
androiddeployqt_arguments: "--android-platform android-31 --aab"
android_keystore_data:
from_secret: android-release-keystore
android_keystore_alias: "bmca"
android_keystore_store_pass:
from_secret: android-release-keystore-password
- name: release
image: plugins/gitea-release
settings:
base_url: https://itsblue.dev
api_key:
from_secret: gitea-token
files:
- outputs/apk/release/android-build-release-signed.apk
- outputs/bundle/release/android-build-release.aab
when:
event: tag

3
.gitignore vendored
View file

@ -1,2 +1,5 @@
*.pro.user* *.pro.user*
*.DS_Store *.DS_Store
.bundle
vendor
outputs

View file

@ -3,8 +3,38 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
# [0.8.0] - 2023-06-05
### Added
- Show both results in speed quali
# [0.6.0] - UNRELEASED # [0.7.3] - 2023-05-02
### Removed
- Im-App purchase on android
# [0.7.1] - 2022-08-22
### Fixed
- remove unused ACCESS_FINE_LOCATION permission
- missing openssl libraries which lead to an error in the https connection
# [0.7.0] - 2022-08-14
### Added
- Startnumbers in speed flowchart
### Fixed
- Sharing the poster on Android
- Rendering the speed flowchart when starting at 1/2-Final
### Changed
- The qualification rank is now smaller and grayed out in the speed flowchart
### Removed
- URL handler for app.bluerock.dev, it is not needed
# [0.6.1] - 2021-10-20
### Added
- Privacy policy link to comply with google play policies
# [0.6.0] - 2021-08-07
### Changed ### Changed
- The subtitle in results and startlists is now the route name instead of the category name - The subtitle in results and startlists is now the route name instead of the category name
@ -19,6 +49,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
### Fixed ### Fixed
- Rare issue with missing background in boulder result rect - Rare issue with missing background in boulder result rect
# [0.5.1] - 2021-07-06
### Fixed
- In-app purchase
# [0.05] - 2021-06-07 # [0.05] - 2021-06-07
### Changed ### Changed
- the boulder result rect doesn't have a background if there is no result now - the boulder result rect doesn't have a background if there is no result now

3
Gemfile Normal file
View file

@ -0,0 +1,3 @@
source "https://rubygems.org"
gem "fastlane"

218
Gemfile.lock Normal file
View file

@ -0,0 +1,218 @@
GEM
remote: https://rubygems.org/
specs:
CFPropertyList (3.0.5)
rexml
addressable (2.8.0)
public_suffix (>= 2.0.2, < 5.0)
artifactory (3.0.15)
atomos (0.1.3)
aws-eventstream (1.2.0)
aws-partitions (1.612.0)
aws-sdk-core (3.131.5)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.525.0)
aws-sigv4 (~> 1.1)
jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.58.0)
aws-sdk-core (~> 3, >= 3.127.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.114.0)
aws-sdk-core (~> 3, >= 3.127.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.4)
aws-sigv4 (1.5.1)
aws-eventstream (~> 1, >= 1.0.2)
babosa (1.0.4)
claide (1.1.0)
colored (1.2)
colored2 (3.1.2)
commander (4.6.0)
highline (~> 2.0.0)
declarative (0.0.20)
digest-crc (0.6.4)
rake (>= 12.0.0, < 14.0.0)
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
dotenv (2.8.1)
emoji_regex (3.2.3)
excon (0.92.4)
faraday (1.10.0)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)
faraday-excon (~> 1.1)
faraday-httpclient (~> 1.0)
faraday-multipart (~> 1.0)
faraday-net_http (~> 1.0)
faraday-net_http_persistent (~> 1.0)
faraday-patron (~> 1.0)
faraday-rack (~> 1.0)
faraday-retry (~> 1.0)
ruby2_keywords (>= 0.0.4)
faraday-cookie_jar (0.0.7)
faraday (>= 0.8.0)
http-cookie (~> 1.0.0)
faraday-em_http (1.0.0)
faraday-em_synchrony (1.0.0)
faraday-excon (1.1.0)
faraday-httpclient (1.0.1)
faraday-multipart (1.0.4)
multipart-post (~> 2)
faraday-net_http (1.0.1)
faraday-net_http_persistent (1.2.0)
faraday-patron (1.0.0)
faraday-rack (1.0.0)
faraday-retry (1.0.3)
faraday_middleware (1.2.0)
faraday (~> 1.0)
fastimage (2.2.6)
fastlane (2.208.0)
CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.8, < 3.0.0)
artifactory (~> 3.0)
aws-sdk-s3 (~> 1.0)
babosa (>= 1.0.3, < 2.0.0)
bundler (>= 1.12.0, < 3.0.0)
colored
commander (~> 4.6)
dotenv (>= 2.1.1, < 3.0.0)
emoji_regex (>= 0.1, < 4.0)
excon (>= 0.71.0, < 1.0.0)
faraday (~> 1.0)
faraday-cookie_jar (~> 0.0.6)
faraday_middleware (~> 1.0)
fastimage (>= 2.1.0, < 3.0.0)
gh_inspector (>= 1.1.2, < 2.0.0)
google-apis-androidpublisher_v3 (~> 0.3)
google-apis-playcustomapp_v1 (~> 0.1)
google-cloud-storage (~> 1.31)
highline (~> 2.0)
json (< 3.0.0)
jwt (>= 2.1.0, < 3)
mini_magick (>= 4.9.4, < 5.0.0)
multipart-post (~> 2.0.0)
naturally (~> 2.2)
optparse (~> 0.1.1)
plist (>= 3.1.0, < 4.0.0)
rubyzip (>= 2.0.0, < 3.0.0)
security (= 0.1.3)
simctl (~> 1.6.3)
terminal-notifier (>= 2.0.0, < 3.0.0)
terminal-table (>= 1.4.5, < 2.0.0)
tty-screen (>= 0.6.3, < 1.0.0)
tty-spinner (>= 0.8.0, < 1.0.0)
word_wrap (~> 1.0.0)
xcodeproj (>= 1.13.0, < 2.0.0)
xcpretty (~> 0.3.0)
xcpretty-travis-formatter (>= 0.0.3)
gh_inspector (1.1.3)
google-apis-androidpublisher_v3 (0.25.0)
google-apis-core (>= 0.7, < 2.a)
google-apis-core (0.7.0)
addressable (~> 2.5, >= 2.5.1)
googleauth (>= 0.16.2, < 2.a)
httpclient (>= 2.8.1, < 3.a)
mini_mime (~> 1.0)
representable (~> 3.0)
retriable (>= 2.0, < 4.a)
rexml
webrick
google-apis-iamcredentials_v1 (0.13.0)
google-apis-core (>= 0.7, < 2.a)
google-apis-playcustomapp_v1 (0.10.0)
google-apis-core (>= 0.7, < 2.a)
google-apis-storage_v1 (0.18.0)
google-apis-core (>= 0.7, < 2.a)
google-cloud-core (1.6.0)
google-cloud-env (~> 1.0)
google-cloud-errors (~> 1.0)
google-cloud-env (1.6.0)
faraday (>= 0.17.3, < 3.0)
google-cloud-errors (1.2.0)
google-cloud-storage (1.37.0)
addressable (~> 2.8)
digest-crc (~> 0.4)
google-apis-iamcredentials_v1 (~> 0.1)
google-apis-storage_v1 (~> 0.1)
google-cloud-core (~> 1.6)
googleauth (>= 0.16.2, < 2.a)
mini_mime (~> 1.0)
googleauth (1.2.0)
faraday (>= 0.17.3, < 3.a)
jwt (>= 1.4, < 3.0)
memoist (~> 0.16)
multi_json (~> 1.11)
os (>= 0.9, < 2.0)
signet (>= 0.16, < 2.a)
highline (2.0.3)
http-cookie (1.0.5)
domain_name (~> 0.5)
httpclient (2.8.3)
jmespath (1.6.1)
json (2.6.2)
jwt (2.4.1)
memoist (0.16.2)
mini_magick (4.11.0)
mini_mime (1.1.2)
multi_json (1.15.0)
multipart-post (2.0.0)
nanaimo (0.3.0)
naturally (2.2.1)
optparse (0.1.1)
os (1.1.4)
plist (3.6.0)
public_suffix (4.0.7)
rake (13.0.6)
representable (3.2.0)
declarative (< 0.1.0)
trailblazer-option (>= 0.1.1, < 0.2.0)
uber (< 0.2.0)
retriable (3.1.2)
rexml (3.2.5)
rouge (2.0.7)
ruby2_keywords (0.0.5)
rubyzip (2.3.2)
security (0.1.3)
signet (0.17.0)
addressable (~> 2.8)
faraday (>= 0.17.5, < 3.a)
jwt (>= 1.5, < 3.0)
multi_json (~> 1.10)
simctl (1.6.8)
CFPropertyList
naturally
terminal-notifier (2.0.0)
terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1)
trailblazer-option (0.1.2)
tty-cursor (0.7.1)
tty-screen (0.8.1)
tty-spinner (0.9.3)
tty-cursor (~> 0.7)
uber (0.1.0)
unf (0.1.4)
unf_ext
unf_ext (0.0.8.2)
unicode-display_width (1.8.0)
webrick (1.7.0)
word_wrap (1.0.0)
xcodeproj (1.22.0)
CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0)
colored2 (~> 3.1)
nanaimo (~> 0.3.0)
rexml (~> 3.2.4)
xcpretty (0.3.0)
rouge (~> 2.0.7)
xcpretty-travis-formatter (1.0.1)
xcpretty (~> 0.2, >= 0.0.7)
PLATFORMS
x86_64-linux
DEPENDENCIES
fastlane
BUNDLED WITH
2.3.19

View file

@ -2,7 +2,7 @@
<manifest package="com.itsblue.blueROCK" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="-- %%INSERT_VERSION_NAME%% --" android:versionCode="-- %%INSERT_VERSION_CODE%% --" android:installLocation="auto"> <manifest package="com.itsblue.blueROCK" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="-- %%INSERT_VERSION_NAME%% --" android:versionCode="-- %%INSERT_VERSION_CODE%% --" android:installLocation="auto">
<!-- The following comment will be replaced upon deployment with default permissions based on the dependencies of the application. <!-- The following comment will be replaced upon deployment with default permissions based on the dependencies of the application.
Remove the comment if you do not require these default permissions. --> Remove the comment if you do not require these default permissions. -->
<!-- %%INSERT_PERMISSIONS -->
<!-- The following comment will be replaced upon deployment with default features based on the dependencies of the application. <!-- The following comment will be replaced upon deployment with default features based on the dependencies of the application.
Remove the comment if you do not require these default features. --> Remove the comment if you do not require these default features. -->
@ -10,7 +10,7 @@
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/> <supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
<application android:hardwareAccelerated="true" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="-- %%INSERT_APP_NAME%% --" android:extractNativeLibs="true" android:icon="@drawable/icon"> <application android:hardwareAccelerated="true" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="-- %%INSERT_APP_NAME%% --" android:extractNativeLibs="true" android:icon="@drawable/icon">
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density" android:name="de.itsblue.blueROCK.MainActivity" android:label="-- %%INSERT_APP_NAME%% --" android:screenOrientation="unspecified" android:launchMode="singleInstance"> <activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density" android:name="de.itsblue.blueROCK.MainActivity" android:label="-- %%INSERT_APP_NAME%% --" android:screenOrientation="unspecified" android:launchMode="singleInstance" android:exported="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.LAUNCHER"/>
@ -75,8 +75,6 @@
<category android:name="android.intent.category.BROWSABLE"/> <category android:name="android.intent.category.BROWSABLE"/>
<!-- Accepts URIs that begin with "https://l.bluerock.dev/” --> <!-- Accepts URIs that begin with "https://l.bluerock.dev/” -->
<data android:scheme="https" android:host="l.bluerock.dev" android:pathPattern=".*"/> <data android:scheme="https" android:host="l.bluerock.dev" android:pathPattern=".*"/>
<!-- Accepts URIs that begin with "https://app.bluerock.dev” -->
<data android:scheme="https" android:host="app.bluerock.dev" android:pathPattern=".*"/>
</intent-filter> </intent-filter>
</activity> </activity>
<!-- For adding service(s) please check: https://wiki.qt.io/AndroidServices --> <!-- For adding service(s) please check: https://wiki.qt.io/AndroidServices -->
@ -87,4 +85,9 @@
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="29"/> <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="29"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.CAMERA"/>
</manifest> </manifest>

View file

@ -260,9 +260,9 @@ public class QShareUtils
sendIntent.setType(mimeType); sendIntent.setType(mimeType);
sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
sendIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
return createCustomChooserAndStartActivity(sendIntent, title, requestId, uri); QtNative.activity().startActivity(Intent.createChooser(sendIntent, null));
return true;
} }
public static boolean viewFile(String filePath, String title, String mimeType, int requestId) { public static boolean viewFile(String filePath, String title, String mimeType, int requestId) {

View file

@ -1,7 +1,7 @@
QT += quick qml quickcontrols2 purchasing QT += quick qml quickcontrols2
CONFIG += c++11 CONFIG += c++11
VERSION = 0.6.0 VERSION = 0.8.0
TARGET = blueROCK TARGET = blueROCK
# The following define makes your compiler emit warnings if you use # The following define makes your compiler emit warnings if you use
@ -89,13 +89,15 @@ android {
ANDROID_VERSION_NAME = $$VERSION ANDROID_VERSION_NAME = $$VERSION
ANDROID_VERSION_CODE = $$droidVersionCode($$ANDROID_VERSION_NAME) ANDROID_VERSION_CODE = $$droidVersionCode($$ANDROID_VERSION_NAME)
ANDROID_TARGET_SDK_VERSION = 29 ANDROID_TARGET_SDK_VERSION = 31
include(/home/dorian/Android/Sdk/android_openssl/openssl.pri) ANDROID_HOME = $$(ANDROID_HOME)
include($$ANDROID_HOME/android_openssl/openssl.pri)
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
} }
ios { ios {
QT += purchasing
OBJECTIVE_SOURCES += sources/shareUtils/ios/iosshareutils.mm \ OBJECTIVE_SOURCES += sources/shareUtils/ios/iosshareutils.mm \
sources/iospermissionutils.mm \ sources/iospermissionutils.mm \
sources/shareUtils/ios/docviewcontroller.mm sources/shareUtils/ios/docviewcontroller.mm

2
fastlane/Appfile.android Normal file
View file

@ -0,0 +1,2 @@
json_key_file("") # Path to the json secret file - Follow https://docs.fastlane.tools/actions/supply/#setup to get one
package_name("com.itsblue.speedclimbing_stopwatch") # e.g. com.krausefx.app

38
fastlane/Fastfile Normal file
View file

@ -0,0 +1,38 @@
# This file contains the fastlane.tools configuration
# You can find the documentation at https://docs.fastlane.tools
#
# For a list of all available actions, check out
#
# https://docs.fastlane.tools/actions
#
# For a list of all available plugins, check out
#
# https://docs.fastlane.tools/plugins/available-plugins
#
# Uncomment the line if you want fastlane to automatically update itself
# update_fastlane
default_platform(:android)
platform :android do
desc "Runs all the tests"
lane :test do
gradle(task: "test")
end
desc "Submit a new Beta Build to Crashlytics Beta"
lane :beta do
gradle(task: "clean assembleRelease")
crashlytics
# sh "your_script.sh"
# You can also use other beta testing services here
end
desc "Deploy a new version to the Google Play"
lane :deploy do
gradle(task: "clean assembleRelease")
upload_to_play_store
end
end

View file

@ -4,8 +4,7 @@
<dict> <dict>
<key>com.apple.developer.associated-domains</key> <key>com.apple.developer.associated-domains</key>
<array> <array>
<string>applinks:l.bluerock.dev</string> <string>applinks:l.bluerock.dev</string>
<string>applinks:app.bluerock.dev</string>
</array> </array>
</dict> </dict>
</plist> </plist>

2
qzxing

@ -1 +1 @@
Subproject commit cfc728583b867e157bd27e8b7c239c05a081e562 Subproject commit 6ea2b31e26db9d43db027ba207f5c73dc9d759fc

View file

@ -0,0 +1,262 @@
import QtQuick 2.10
import QtQuick.Controls 2.15
import QtQuick.Controls.Material 2.15
Row {
id: multiResRow
property bool active: parseInt(widgetData[ "route_order" ]) > -1 && boulderResRep.model > 0
height: parent.height
width: active ? parent.width * 0.75:0
enabled: parseInt(widgetData[ "route_order" ]) > -1 && boulderResRep.model > 0
Repeater {
id: boulderResRep
model: parseInt(widgetData[ "route_num_problems" ])
function getDataForIcon(index){
// TODO: clean
var resultString = widgetData[ "participants" ][partDel.thisIndex]["boulder"+(index+1)]
var numTrys = widgetData[ "participants" ][partDel.thisIndex]["try"+(index+1)]
var resultList = []
if (resultString !== undefined) {
resultString = resultString.replace("t", "")
resultString = resultString.replace("z", "")
resultString = resultString.replace("b", "")
resultList = resultString.split(" ")
while (resultList.length < 2){
resultList.unshift(0)
}
}
else {
resultList = [-1,-1]
}
if (numTrys !== undefined) {
resultList.push(numTrys)
}
else {
resultList.push(-1)
}
return resultList
}
delegate: Item {
id: boulderResItm
anchors.verticalCenter: parent.verticalCenter
width: parent.width / ( boulderResRep.model )
height: parent.height
Canvas {
id: boulderResCv
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
width: height
onPaint: {
var width = 24//boulderResCv.width * 0.9
var height = width
var radius = width * 0.3
var offsetX = width * 0.05
var offsetY = height * 0.05
//console.log("drawing result rect with width: " + width + " and height: " + height)
var context = getContext("2d");
// clear all remainings from other routes
context.clearRect(0, 0, width, height);
context.beginPath();
context.moveTo(0 + offsetX + radius, 0 + offsetY);
// top line
context.lineTo(width - radius + offsetX, 0 + offsetY);
// top right corner
context.arc(width-radius + offsetX, radius + offsetY, radius, 1.5 * Math.PI, 0);
// right line
context.lineTo(width + offsetX, height - radius + offsetY);
// bottom right corner
context.arc(width-radius + offsetX, height - radius + offsetY, radius, 0, 0.5 * Math.PI);
// bottom line
context.lineTo(0 + radius + offsetX, height + offsetY);
// bottom left corner
context.arc(radius + offsetY, height - radius + offsetY, radius, 0.5 * Math.PI, Math.PI);
// left line
context.lineTo(0 + offsetX, radius + offsetY);
// top left corner
context.arc(radius + offsetX, radius + offsetY, radius, Math.PI, 1.5 * Math.PI);
// fill
if(resultData[0] !== -1 || resultData[2] !== -1) {
// if there is a result available -> draw background
context.fillStyle = "#b7b7b7";
}
else {
context.fillStyle = "transparent";
}
context.fill();
// outline
context.lineWidth = 1;
context.strokeStyle = Material.primaryTextColor;
context.stroke();
if(resultData[1] > 0){
// the first triangle
context.beginPath();
// top right corner
context.arc(width-radius + offsetX, radius + offsetY, radius, 1.75 * Math.PI, 0);
// right line
context.lineTo(width + offsetX, height - radius + offsetY);
// bottom right corner
context.arc(width-radius + offsetX, height - radius + offsetY, radius, 0, 0.5 * Math.PI);
// bottom line
context.lineTo(0 + radius + offsetX, height + offsetY);
// bottom left corner
context.arc(radius + offsetX, height - radius + offsetY, radius, 0.5 * Math.PI, 0.75 * Math.PI);
context.closePath();
context.fillStyle = "#44ed38";
context.fill();
// outline
context.lineWidth = 1;
context.strokeStyle = Material.primaryTextColor;
context.stroke();
if(resultData[0] > 0){
// the second triangle
context.beginPath();
// bottom left corner
context.arc(radius + offsetX, height - radius + offsetY, radius, 0.75 * Math.PI, 1 * Math.PI);
// left line
context.lineTo(0 + offsetX, radius + offsetY);
// top left corner
context.arc(radius + offsetX, radius + offsetY, radius, Math.PI, 1.5 * Math.PI);
// top line
context.lineTo(width - radius + offsetX, 0 + offsetY);
// top right corner
context.arc(width-radius + offsetX, radius + offsetY, radius, 1.5 * Math.PI, 1.75 * Math.PI);
context.closePath();
context.fillStyle = "#44ed38";
context.fill();
// outline
context.lineWidth = 1;
context.strokeStyle = Material.primaryTextColor;
context.stroke();
}
}
}
Label {
id: boulderResTrysLa
anchors.centerIn: parent
height: parent.height / 2
width: parent.width / 2
visible: !boulderResZoneLa.visible && boulderResCv.resultData[2] > 0
fontSizeMode: Text.Fit
font.pixelSize: height
minimumPixelSize: 1
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
color: "#dd000000"
text: boulderResCv.resultData[2]
}
Label {
id: boulderResZoneLa
anchors {
right: parent.right
bottom: parent.bottom
margins: boulderResCv.height * 0.05
}
height: parent.height / 2
width: parent.width / 2
visible: parseInt(text) > 0
fontSizeMode: Text.Fit
font.pixelSize: height
minimumPixelSize: 1
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
color: "#dd000000"
text: boulderResCv.resultData[1]
}
Label {
id: boulderResTopLa
anchors {
left: parent.left
top: parent.top
margins: boulderResCv.height * 0.05
}
height: parent.height / 2
width: parent.width / 2
visible: parseInt(text) > 0
fontSizeMode: Text.Fit
font.pixelSize: height
minimumPixelSize: 1
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
color: "#dd000000"
text: boulderResCv.resultData[0]
}
}
}
}
}

View file

@ -0,0 +1,97 @@
import QtQuick 2.10
import QtQuick.Controls 2.15
import QtQuick.Controls.Material 2.15
Row {
id: multiGenResRow
property bool active: (parseInt(widgetData[ "route_order" ]) === -1) && (generalResRep.model > 0)
height: parent.height
width: active ? parent.width - resultLa.width:0
enabled: active
Repeater {
id: generalResRep
property var routes: getRoutes()
model: routes.length
function getRoutes() {
var obj = widgetData["route_names"]
var routes = []
for(var prop in obj) {
// go through the whole array and search for data keys
if (obj.hasOwnProperty(prop) && prop > -1) {
routes.push([prop, obj[prop]])
//console.log("found " + obj[prop] + " at index " + prop)
}
}
routes.sort(function(a, b) {
return a[0] - b[0];
});
return routes
}
delegate: Item {
id: boulderGenResItm
anchors.verticalCenter: parent.verticalCenter
width: parent.width / ( generalResRep.model )
height: parent.height
visible: multiGenResRow.active
Rectangle {
anchors {
left: parent.left
}
width: 1
height: parent.height
visible: index === 0
color: Material.primaryTextColor
}
Rectangle {
anchors {
right: parent.right
}
width: 1
height: parent.height
color: Material.primaryTextColor
}
Label {
id: boulderGenResLa
anchors.centerIn: parent
height: parent.height
width: parent.width * 0.9
fontSizeMode: Text.Fit
font.pixelSize: Math.abs( height * 0.6 )
minimumPixelSize: 1
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text: widgetData["participants"][partDel.thisIndex]["result"+(generalResRep.routes[index][0])] === undefined ?
"":
widgetData[ "participants" ][partDel.thisIndex]["result"+(generalResRep.routes[index][0])]
}
}
}
}

View file

@ -33,6 +33,19 @@ ColoredItemDelegate {
NumberAnimation { target: partDel; property: "scale"; from: 0.8; to: 1.0; duration: 400 } NumberAnimation { target: partDel; property: "scale"; from: 0.8; to: 1.0; duration: 400 }
} }
Rectangle {
visible: widgetData["route_quota"] !== null && parseInt(widgetData["route_quota"]) - 1 === thisIndex
anchors {
left: parent.left
right: parent.right
verticalCenter: parent.bottom
}
height: 3
color: Material.primaryTextColor
}
GridLayout { GridLayout {
id: partDelCol id: partDelCol
@ -107,370 +120,29 @@ ColoredItemDelegate {
Layout.preferredWidth: partDelCol.showSideBySide ? parent.width * 0.5 : parent.width Layout.preferredWidth: partDelCol.showSideBySide ? parent.width * 0.5 : parent.width
Layout.preferredHeight: partDelCol.showSideBySide ? parent.height : parent.height * 0.5 Layout.preferredHeight: partDelCol.showSideBySide ? parent.height : parent.height * 0.5
visible: multiResRow.active || multiGenResRow.active || resultLa.acitve visible: boulderResRow.active || generalResRow.active || speedQualificationResRow.active || resultLa.active
Row {
id: multiResRow
property bool active: parseInt(widgetData[ "route_order" ]) > -1 && boulderResRep.model > 0
height: parent.height
width: active ? parent.width * 0.75:0
enabled: parseInt(widgetData[ "route_order" ]) > -1 && boulderResRep.model > 0
Repeater {
id: boulderResRep
model: parseInt(widgetData[ "route_num_problems" ])
function getDataForIcon(index){
// TODO: clean
var resultString = widgetData[ "participants" ][partDel.thisIndex]["boulder"+(index+1)]
var numTrys = widgetData[ "participants" ][partDel.thisIndex]["try"+(index+1)]
var resultList = []
if (resultString !== undefined) {
resultString = resultString.replace("t", "")
resultString = resultString.replace("z", "")
resultString = resultString.replace("b", "")
resultList = resultString.split(" ")
while (resultList.length < 2){
resultList.unshift(0)
}
}
else {
resultList = [-1,-1]
}
if (numTrys !== undefined) {
resultList.push(numTrys)
}
else {
resultList.push(-1)
}
return resultList
}
delegate: Item {
id: boulderResItm
anchors.verticalCenter: parent.verticalCenter
width: parent.width / ( boulderResRep.model )
height: parent.height
Canvas {
id: boulderResCv
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
width: height
onPaint: {
var width = 24//boulderResCv.width * 0.9
var height = width
var radius = width * 0.3
var offsetX = width * 0.05
var offsetY = height * 0.05
//console.log("drawing result rect with width: " + width + " and height: " + height)
var context = getContext("2d");
// clear all remainings from other routes
context.clearRect(0, 0, width, height);
context.beginPath();
context.moveTo(0 + offsetX + radius, 0 + offsetY);
// top line
context.lineTo(width - radius + offsetX, 0 + offsetY);
// top right corner
context.arc(width-radius + offsetX, radius + offsetY, radius, 1.5 * Math.PI, 0);
// right line
context.lineTo(width + offsetX, height - radius + offsetY);
// bottom right corner
context.arc(width-radius + offsetX, height - radius + offsetY, radius, 0, 0.5 * Math.PI);
// bottom line
context.lineTo(0 + radius + offsetX, height + offsetY);
// bottom left corner
context.arc(radius + offsetY, height - radius + offsetY, radius, 0.5 * Math.PI, Math.PI);
// left line
context.lineTo(0 + offsetX, radius + offsetY);
// top left corner
context.arc(radius + offsetX, radius + offsetY, radius, Math.PI, 1.5 * Math.PI);
// fill
if(resultData[0] !== -1 || resultData[2] !== -1) {
// if there is a result available -> draw background
context.fillStyle = "#b7b7b7";
}
else {
context.fillStyle = "transparent";
}
context.fill();
// outline
context.lineWidth = 1;
context.strokeStyle = Material.primaryTextColor;
context.stroke();
if(resultData[1] > 0){
// the first triangle
context.beginPath();
// top right corner
context.arc(width-radius + offsetX, radius + offsetY, radius, 1.75 * Math.PI, 0);
// right line
context.lineTo(width + offsetX, height - radius + offsetY);
// bottom right corner
context.arc(width-radius + offsetX, height - radius + offsetY, radius, 0, 0.5 * Math.PI);
// bottom line
context.lineTo(0 + radius + offsetX, height + offsetY);
// bottom left corner
context.arc(radius + offsetX, height - radius + offsetY, radius, 0.5 * Math.PI, 0.75 * Math.PI);
context.closePath();
context.fillStyle = "#44ed38";
context.fill();
// outline
context.lineWidth = 1;
context.strokeStyle = Material.primaryTextColor;
context.stroke();
if(resultData[0] > 0){
// the second triangle
context.beginPath();
// bottom left corner
context.arc(radius + offsetX, height - radius + offsetY, radius, 0.75 * Math.PI, 1 * Math.PI);
// left line
context.lineTo(0 + offsetX, radius + offsetY);
// top left corner
context.arc(radius + offsetX, radius + offsetY, radius, Math.PI, 1.5 * Math.PI);
// top line
context.lineTo(width - radius + offsetX, 0 + offsetY);
// top right corner
context.arc(width-radius + offsetX, radius + offsetY, radius, 1.5 * Math.PI, 1.75 * Math.PI);
context.closePath();
context.fillStyle = "#44ed38";
context.fill();
// outline
context.lineWidth = 1;
context.strokeStyle = Material.primaryTextColor;
context.stroke();
}
}
}
Label {
id: boulderResTrysLa
anchors.centerIn: parent
height: parent.height / 2
width: parent.width / 2
visible: !boulderResZoneLa.visible && boulderResCv.resultData[2] > 0
fontSizeMode: Text.Fit
font.pixelSize: height
minimumPixelSize: 1
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
color: "#dd000000"
text: boulderResCv.resultData[2]
}
Label {
id: boulderResZoneLa
anchors {
right: parent.right
bottom: parent.bottom
margins: boulderResCv.height * 0.05
}
height: parent.height / 2
width: parent.width / 2
visible: parseInt(text) > 0
fontSizeMode: Text.Fit
font.pixelSize: height
minimumPixelSize: 1
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
color: "#dd000000"
text: boulderResCv.resultData[1]
}
Label {
id: boulderResTopLa
anchors {
left: parent.left
top: parent.top
margins: boulderResCv.height * 0.05
}
height: parent.height / 2
width: parent.width / 2
visible: parseInt(text) > 0
fontSizeMode: Text.Fit
font.pixelSize: height
minimumPixelSize: 1
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
color: "#dd000000"
text: boulderResCv.resultData[0]
}
}
}
}
BoulderResultRow {
id: boulderResRow
} }
Row { GeneralResultRow {
id: multiGenResRow id: generalResRow
}
property bool active: ((parseInt(widgetData[ "route_order" ]) === -1) && (generalResRep.model > 0)) ? true:false SpeedQualificationResultRow {
id: speedQualificationResRow
height: parent.height
width: active ? parent.width - resultLa.width:0
enabled: ((parseInt(widgetData[ "route_order" ]) === -1) && (generalResRep.model > 0)) ? true:false
Repeater {
id: generalResRep
property var routes: getRoutes()
model: routes.length
function getRoutes() {
var obj = widgetData["route_names"]
var routes = []
for(var prop in obj) {
// go through the whole array and search for data keys
if (obj.hasOwnProperty(prop) && prop > -1) {
routes.push([prop, obj[prop]])
//console.log("found " + obj[prop] + " at index " + prop)
}
}
routes.sort(function(a, b) {
return a[0] - b[0];
});
return routes
}
delegate: Item {
id: boulderGenResItm
anchors.verticalCenter: parent.verticalCenter
width: parent.width / ( generalResRep.model )
height: parent.height
visible: multiGenResRow.active
Rectangle {
anchors {
left: parent.left
}
width: 1
height: parent.height
visible: index === 0
color: Material.primaryTextColor
}
Rectangle {
anchors {
right: parent.right
}
width: 1
height: parent.height
color: Material.primaryTextColor
}
Label {
id: boulderGenResLa
anchors.centerIn: parent
height: parent.height
width: parent.width * 0.9
fontSizeMode: Text.Fit
font.pixelSize: Math.abs( height * 0.6 )
minimumPixelSize: 1
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text: widgetData["participants"][partDel.thisIndex]["result"+(generalResRep.routes[index][0])] === undefined ?
"":
widgetData[ "participants" ][partDel.thisIndex]["result"+(generalResRep.routes[index][0])]
}
}
}
} }
Label { Label {
id: resultLa id: resultLa
property bool acitve: ( boulderResRep.model > 0 || widgetData["discipline"] !== "boulder" ) && parseInt(widgetData[ "route_order" ]) > -1 property bool active: ( parseInt(widgetData[ "route_num_problems" ]) > 0 || widgetData["discipline"] !== "boulder" ) && parseInt(widgetData[ "route_order" ]) > -1 && !speedQualificationResRow.active
width: enabled ? parent.width * 0.25:0 width: enabled ? parent.width * 0.25:0
height: enabled ? parent.height:0 height: enabled ? parent.height:0
enabled: ( boulderResRep.model > 0 || widgetData["discipline"] !== "boulder" ) && parseInt(widgetData[ "route_order" ]) > -1 enabled: active
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter

View file

@ -1,7 +1,7 @@
import QtQuick 2.12 import QtQuick 2.12
import QtQuick.Controls 2.12 import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12 import QtQuick.Layouts 1.12
import QZXing 3.1 import QZXing 3.3
import QtGraphicalEffects 1.0 import QtGraphicalEffects 1.0
Dialog { Dialog {

View file

@ -0,0 +1,289 @@
.pragma library
/**
* Function to extract results from PartiipantFromApi
* @param {ParticipantFromApi} fromApi
* @return {Result[]}
*/
function _extractResults(fromApi) {
const results = Array(7);
const existingResults = Object.keys(fromApi).filter(key =>
key.match(/result[0-9]/),
);
for (const result of existingResults) {
let roundNumber = 0;
const match = result.match(/result([0-9])/);
if (match !== undefined && match !== null) {
roundNumber = parseInt(match[1]);
}
if (roundNumber < 0) {
continue;
}
results[roundNumber] = {
rank: parseInt(fromApi[`result_rank${roundNumber}`] as string),
result: fromApi[`result${roundNumber}`] as string,
};
}
return results;
}
/**
* Function to clean up participants from the api
* @param {ParticipantFromApi} fromApi
* @return {Participant}
*/
function participantFromApiParticipant(
fromApi,
) {
const results = _extractResults(fromApi);
return {
id: fromApi.PerId,
firstName: fromApi.firstname,
lastName: fromApi.lastname,
results: results,
overallRank: fromApi.result_rank,
startNumber: parseInt(fromApi.start_number),
};
}
/**
*
* @param {number} roundNumber
* @param {RouteNames} routeNames
* @return {string | undefined}
*/
function getRoundName(
roundNumber,
routeNames,
) {
if (roundNumber < 2 || roundNumber > 6) return undefined;
return routeNames[roundNumber];
}
/**
*
* @param {string} name
* @return {number}
*/
function getRoundRank(name) {
const match = name.match(/1\/([842])/);
if (match === undefined || match === null || match.length !== 2) {
return 2;
}
return parseInt(match[1]);
}
/**
*
* @param {SpeedRoundPair} pair
* @param {number} roundIndex
*/
function computeWinnerOfPair(pair, roundIndex) {
if (
!(pair.laneA && pair.laneA.participant.results[roundIndex] && pair.laneA.participant.results[roundIndex].rank) ||
!(pair.laneB && pair.laneB.participant.results[roundIndex] && pair.laneB.participant.results[roundIndex].rank)
)
return;
pair.laneA.result = pair.laneA.participant.results[roundIndex];
pair.laneB.result = pair.laneB.participant.results[roundIndex];
if (pair.winner === undefined) {
pair.winner =
pair.laneA.participant.results[roundIndex].rank >
pair.laneB.participant.results[roundIndex].rank
? 'B'
: 'A';
}
}
/**
*
* @param {SpeedRoundPair} pair
* @param {number} roundNumber
* @return {Participant | undefined}
*/
function getWinnerOfPair(
pair,
roundNumber,
) {
computeWinnerOfPair(pair, roundNumber);
return {
['A']: pair.laneA ? pair.laneA.participant : undefined,
['B']: pair.laneB ? pair.laneB.participant : undefined,
['']: undefined,
}[pair.winner ? pair.winner:''];
}
/**
*
* @param {SpeedRoundPair} pair
* @param {number} roundNumber
* @return {Participant | undefined}
*/
function getLooserOfPair(
pair,
roundNumber,
) {
computeWinnerOfPair(pair, roundNumber);
return {
['A']: pair.laneB ? pair.laneB.participant : undefined,
['B']: pair.laneA ? pair.laneA.participant : undefined,
['']: undefined,
}[pair.winner ? pair.winner:''];
}
/**
*
* @param {number} roundIndex index of the new round
* @param {string} roundName name of the new round
* @param {SpeedRound} previousRound
* @param {number} roundRank
* @param {boolean} takeLooser
* @return {SpeedRound}
*/
function computeRoundFromPreviousRound(
roundIndex,
roundName,
previousRound,
roundRank,
takeLooser = false,
) {
const getAdvancingParticipant = takeLooser
? getLooserOfPair
: getWinnerOfPair;
const nextRoundPairs = new Array(roundRank / 2).fill(0).map((_, i) => {
const laneAParticipant = getAdvancingParticipant(
previousRound.pairs[i * 2],
previousRound.roundIndex,
);
const laneBParticipant = getAdvancingParticipant(
previousRound.pairs[i * 2 + 1],
previousRound.roundIndex,
);
return {
laneA:
laneAParticipant === undefined
? undefined
: {
participant: laneAParticipant,
},
laneB:
laneBParticipant === undefined
? undefined
: {
participant: laneBParticipant,
},
};
});
return {
pairs: nextRoundPairs,
roundIndex: roundIndex,
roundName: roundName,
};
}
/**
*
* @param {SpeedCompetitionCategoryResult} result The result to process
* @return {SpeedFlowchartResult}
*/
function convertResultsToSpeedFlowchartResult(
result,
) {
const rounds = [];
const convertedParticipants = result.participants
.map(fromApi => participantFromApiParticipant(fromApi))
// sort by qualification result
.sort((a, b) => a.results[0].rank - b.results[0].rank);
const roundIndices = Object.keys(result.route_names)
.map(number => parseInt(number))
.filter(number => number > 0);
// process first round
const firstRoundName = getRoundName(roundIndices[0], result.route_names);
const tmpRoundName = getRoundName(roundIndices[0], result.route_names);
const firstRoundRank = getRoundRank(
tmpRoundName ? tmpRoundName:'',
);
const getOpponent = (ofRank) => {
return convertedParticipants[firstRoundRank * 2 - 1 - ofRank];
};
// Should be:
// 0, 1, 2, 3, 4, 5, 6, 7
// - 1,16, 8, 9, 4,13, 5,12, 2,15, 7,10, 3,14, 6,11
// - 1, 8, 4, 5, 2, 7, 3, 6 for firstRoundNumber=8
// - 1, 4, 2, 3 for firstRoundNumber=4
// - 1, 2 for firstRoundNumber=2
// TODO: come up with a proper alogorithm maybe
const ranksOfLaneAInOrder = [
[1, 2],
[1, 4, 2, 3],
[1, 8, 4, 5, 2, 7, 3, 6],
][Math.floor(firstRoundRank / 4)];
const firstRoundPairs = ranksOfLaneAInOrder.map(rank => {
return {
laneA: { participant: convertedParticipants[rank - 1] },
laneB: { participant: getOpponent(rank - 1) },
};
});
const firstRound = {
pairs: firstRoundPairs,
roundIndex: roundIndices[0],
roundName: firstRoundName,
};
rounds.push(firstRound);
// compute following rounds
let roundIndex = roundIndices[1];
for (let roundRank = firstRoundRank; roundRank > 2; roundRank /= 2) {
rounds.push(
computeRoundFromPreviousRound(
roundIndex,
result.route_names[roundIndex] ? result.route_names[roundIndex]:'',
rounds[rounds.length - 1],
roundRank,
),
);
roundIndex++;
}
// compute final and semi final
const semifinalRoundIndex = roundIndex++;
const semifinal = computeRoundFromPreviousRound(
semifinalRoundIndex,
result.route_names[semifinalRoundIndex] ? result.route_names[semifinalRoundIndex]:'',
rounds[rounds.length - 1],
2,
true,
);
computeWinnerOfPair(semifinal.pairs[0], semifinalRoundIndex);
rounds.push(semifinal);
const finalRoundIndex = roundIndex;
const final = computeRoundFromPreviousRound(
finalRoundIndex,
result.route_names[finalRoundIndex] ? result.route_names[finalRoundIndex]:'',
rounds[rounds.length - 2],
2,
);
computeWinnerOfPair(final.pairs[0], finalRoundIndex);
rounds.push(final);
return {
rounds: rounds,
};
}

View file

@ -22,6 +22,8 @@ import QtQuick.Layouts 1.3
import QtQuick.Controls.Material 2.1 import QtQuick.Controls.Material 2.1
import QtGraphicalEffects 1.0 import QtGraphicalEffects 1.0
import "SpeedFlowChart.js" as SpeedFlowChart
Item { Item {
id: control id: control
@ -32,8 +34,6 @@ Item {
property int refreshes: 0 property int refreshes: 0
property int roundRefreshes: 1 property int roundRefreshes: 1
property int roundCount: 0
onFlowchartDataChanged: { onFlowchartDataChanged: {
prepareData() prepareData()
} }
@ -42,187 +42,26 @@ Item {
if(!control.enabled || control.flowchartData === undefined || control.flowchartData['route_names'] === undefined) if(!control.enabled || control.flowchartData === undefined || control.flowchartData['route_names'] === undefined)
return return
/*refreshes += 1
if(refreshes > 2){ var flowchartResult = SpeedFlowChart.convertResultsToSpeedFlowchartResult(control.flowchartData)
roundRefreshes += 1 const l = flowchartResult.rounds.length;
} const dummy = { dummy: true };
flowchartResult.rounds[l - 2].pairs = [
console.log("refreshes: " + refreshes + " rounds: " + roundRefreshes) dummy,
...flowchartResult.rounds[l - 1].pairs,
// create competition like data (just testing) ...flowchartResult.rounds[l - 2].pairs,
for(var part in flowchartData['participants']){ ];
if(flowchartData['participants'].hasOwnProperty(part)){ flowchartResult.rounds[l - 2].roundName = `${
flowchartResult.rounds[l - 1].roundName
for(var r = 2 + roundRefreshes; r < 7; r++){ } / ${flowchartResult.rounds[l - 2].roundName}`;
delete flowchartData['participants'][part]["result"+r] flowchartResult.rounds.pop();
delete flowchartData['participants'][part]["result_rank"+r] control.allFlowchartData = flowchartResult
}
if(parseInt(flowchartData['participants'][part]["result_rank0"]) > 14 + refreshes) {
delete flowchartData['participants'][part]["result_rank2"]
}
}
}
delete flowchartData['route_names'][2]
delete flowchartData['route_names'][3]
delete flowchartData['route_names'][4]
delete flowchartData['route_names'][5]
delete flowchartData['route_names'][6]
*/
//flowchartData['route_names'] = flowchartData['route_names'].slice(0,)
// array to store the restructured data
var allData = []
control.allFlowchartData = []
control.rounds = Object.keys(control.flowchartData['route_names']).length > 2 ? control.flowchartData['route_names']["2"].includes("8") ? 2:1 : 0
//console.log(JSON.stringify(flowchartData['route_names']))
for(var round in flowchartData['route_names']){
if(flowchartData['route_names'].hasOwnProperty(round) && parseInt(round) >= 0){
//console.log(round)
if(parseInt(round) === 0){
// this is the first round
// find pairs (always wors vs. best (1-16; 1-15; ...)) (they are sorted by the rank of the better athlete (1-2-3-4-5-6-7-8)
var qualificationResults = []
for(var x = 0; x < flowchartData['participants'].length; x++){
qualificationResults.push(flowchartData['participants'][x])
}
qualificationResults.sort(function(a, b) {
return parseInt(a["result_rank0"]) - parseInt(b["result_rank0"]);
});
var nextRoundPairs = []
var totalMatches = (parseInt(Object.keys(control.flowchartData['route_names']).length > 2 ? control.flowchartData['route_names']["2"].includes("8") ? 2:1 : 0) + 2)
var nextRoundMatches = Math.pow(2, totalMatches-1)
for(var i = 0; i < nextRoundMatches; i++){
nextRoundPairs.push([qualificationResults[i], qualificationResults[nextRoundMatches*2-i-1]])
}
// build second round pairs (sorted by the rank of the better athlete and worst vs. best (1-8; 2-7; ... ))
var sortedFirstRoundPairs = []
for(i = 0; i < nextRoundMatches; i += 1){
sortedFirstRoundPairs.push([nextRoundPairs.shift(), nextRoundPairs.pop()])
}
// sort these pairs (containing two pairs of athletes) by the rank of the better athlete (1-4;2-3)
var finalSortedFirstRoundPairs = []
for(i=0; i < nextRoundMatches/4; i++){
finalSortedFirstRoundPairs.push(sortedFirstRoundPairs[i])
finalSortedFirstRoundPairs.push(sortedFirstRoundPairs[nextRoundMatches/2-i-1])
}
// convert the list of pairs of pairs of athletes back to a single list of pairs of athletes
var finalFirstRoundPairs = []
for(i=0; i < finalSortedFirstRoundPairs.length; i++){
finalFirstRoundPairs.push(finalSortedFirstRoundPairs[i][0])
finalFirstRoundPairs.push(finalSortedFirstRoundPairs[i][1])
}
// push the first round to all data
finalFirstRoundPairs.push(2)
finalFirstRoundPairs.push(flowchartData['route_names'][2])
allData.push(finalFirstRoundPairs)
}
else if(parseInt(round) > 0 ){
// this is not the first round
var nextRound = []
// only used when the current round is the 1/2 final
var smallFinal = []
var Final = []
for(var i = 0; i < allData[allData.length-1].length-2; i+=1){
var thisPair = allData[allData.length-1][i]
var thisWinner
var thisLooser
var thisWinnerIsFirstOfNewPair = i%2 === 0
if(thisPair[0] === undefined || thisPair[1] === undefined){
continue
}
if(thisWinnerIsFirstOfNewPair){
nextRound.push([])
}
//thisPair[0]["result_rank"] = thisPair[0]["result_rank"+round]
//thisPair[1]["result_rank"] = thisPair[1]["result_rank"+round]
if(parseInt(thisPair[0]["result_rank"+round]) < parseInt(thisPair[1]["result_rank"+round])){
thisWinner = thisPair[0]
thisLooser = thisPair[1]
}
else if(parseInt(thisPair[0]["result_rank"+round]) > parseInt(thisPair[1]["result_rank"+round])) {
thisWinner = thisPair[1]
thisLooser = thisPair[0]
}
else {
// no result yet!!
//console.log("got no winner yet, rank 0: " + thisPair[0]["result_rank"+round] + " rank 1: " + thisPair[1]["result_rank"+round])
continue
}
//console.log(thisWinner['firstname']+" has won in round " + round)
if(round - control.rounds === 2){
// if we are in the 1/2 final
Final.push(thisWinner)
smallFinal.push(thisLooser)
}
else {
nextRound[nextRound.length-1].push(thisWinner)
}
}
if(smallFinal.length > 0 && Final.length > 0){
// Final
allData.push([Final, parseInt(round)+2, flowchartData['route_names'][String(parseInt(round)+2)] + " / " + flowchartData['route_names'][String(parseInt(round)+1)] ])
// small Final
allData.push([smallFinal, parseInt(round)+1])
//break
}
else {
nextRound.push(parseInt(round) + 1 )
nextRound.push(flowchartData['route_names'][parseInt(round) + 1])
allData.push(nextRound)
}
}
}
}
control.allFlowchartData = allData
control.roundCount = (parseInt(Object.keys(control.flowchartData['route_names']).length > 2 ? control.flowchartData['route_names']["2"].includes("8") ? 2:1 : 0) + 2)
//console.log(JSON.stringify(allData))
} }
ListView { ListView {
id: roundListView id: roundListView
property int columnWidth: height * 0.3 property int columnWidth: height * 0.4
property int columnHeight: height property int columnHeight: height
anchors { anchors {
@ -238,19 +77,18 @@ Item {
orientation: ListView.LeftToRight orientation: ListView.LeftToRight
boundsBehavior: ListView.StopAtBounds boundsBehavior: ListView.StopAtBounds
model: control.roundCount model: control.allFlowchartData.rounds.length
delegate: Item { delegate: Item {
id: roundItem id: roundItem
property int thisIndex: index property int thisIndex: index
property int thisRound: thisRoundIsValid ? control.allFlowchartData[roundItem.thisIndex][control.allFlowchartData[roundItem.thisIndex].length-2]:-1 property var thisData: control.allFlowchartData.rounds[thisIndex]
property bool thisRoundIsValid: control.allFlowchartData !== undefined
&& control.allFlowchartData[roundItem.thisIndex] !== undefined
&& control.allFlowchartData[roundItem.thisIndex].length > 2
property bool thisIsLastRound: thisIndex === control.roundCount - 1 property bool thisRoundIsValid: true
property bool thisIsSemiFinal: thisIndex === control.roundCount - 2 && rectRep.model === 2
property bool thisIsLastRound: thisIndex === roundListView.model - 1
property bool thisIsSemiFinal: thisIndex === roundListView.model - 2
property int tileSize: (roundItem.height / 8 - roundNameLa.height) * 1.45 property int tileSize: (roundItem.height / 8 - roundNameLa.height) * 1.45
@ -272,50 +110,26 @@ Item {
font.pixelSize: height * 0.6 font.pixelSize: height * 0.6
minimumPixelSize: 1 minimumPixelSize: 1
font.bold: true font.bold: true
text: roundItem.thisRoundIsValid text: roundItem.thisData.roundName ?
&& control.allFlowchartData[roundItem.thisIndex][control.allFlowchartData[roundItem.thisIndex].length-1] !== undefined ? roundItem.thisData.roundName :
control.allFlowchartData[roundItem.thisIndex][control.allFlowchartData[roundItem.thisIndex].length-1] :
"-" "-"
} }
Repeater { Repeater {
id: rectRep id: rectRep
model: Math.max( Math.pow(2, control.roundCount-1) * Math.pow(0.5, (roundItem.thisIndex)), 2) model: roundItem.thisData.pairs.length
delegate: Item { delegate: Item {
id: matchItm id: matchItm
property bool lowerPart: (index%2 > 0) property bool lowerPart: (index%2 > 0)
property var thisData: roundItem.thisData.pairs[index]
property var matchData: roundItem.thisRoundIsValid ?
control.allFlowchartData[
thisIsSmallFinal ?
roundItem.thisIndex+1 :
roundItem.thisIndex
][ thisIsSmallFinal ? 0:matchItm.thisIndex]:
undefined
property int thisIndex: index property int thisIndex: index
property int thisRound: parseInt(roundItem.thisRound) - (thisIsSmallFinal ? 1:0)
property var thisMatchData: thisMatchDataIsValid ? matchData:[]
property bool thisMatchDataIsValid: (matchData !== undefined && matchData !== null && typeof matchData === "object" && matchData.length > 0)
property bool thisMatchIsOver: thisMatchDataIsValid && thisMatchData[0]['result_rank'+thisRound] !== undefined && thisMatchData[1]['result_rank'+thisRound] !== undefined
property bool thisIsFinal: roundItem.thisIsLastRound && thisIndex === rectRep.model - 2
property bool thisIsSmallFinal: roundItem.thisIsLastRound && thisIndex === rectRep.model - 1
property int winnerIndex: thisMatchIsOver ? (parseInt(thisMatchData[0]['result_rank'+thisRound]) < parseInt(thisMatchData[1]['result_rank'+thisRound]) ? 0:1) : -1
height: !roundItem.thisIsLastRound ?
(roundItem.height - roundNameLa.height) / rectRep.model - roundCol.spacing :
(thisIsFinal ?
(roundItem.height - roundNameLa.height) * 0.5 + roundItem.tileSize * 0.5 :
(roundItem.height - roundNameLa.height) - (roundItem.height - roundNameLa.height) * 0.5 + roundItem.tileSize * 0.5
)
height: (roundItem.height - roundNameLa.height) / rectRep.model - roundCol.spacing
width: roundItem.width width: roundItem.width
onMatchDataChanged: { onThisDataChanged: {
fadeInPa.start() fadeInPa.start()
} }
@ -365,6 +179,7 @@ Item {
RectangularGlow { RectangularGlow {
id: effect id: effect
visible: matchRect.visible
anchors.fill: matchRect anchors.fill: matchRect
glowRadius: 0 glowRadius: 0
spread: 0 spread: 0
@ -381,13 +196,12 @@ Item {
bottom: matchItm.thisIsFinal ? parent.bottom:undefined bottom: matchItm.thisIsFinal ? parent.bottom:undefined
} }
//anchors.verticalCenterOffset: matchItm.lowerPart ? 10:10 visible: !matchItm.thisData.dummy
width: parent.width width: parent.width
height: roundItem.tileSize height: roundItem.tileSize
//scale: 0.9
color: Material.dialogColor color: Material.dialogColor
border.color: "lightgrey"
border.width: 0
radius: height * 0.2 radius: height * 0.2
Column { Column {
@ -401,6 +215,13 @@ Item {
model: 2 model: 2
delegate: RowLayout { delegate: RowLayout {
id: laneRow
property var thisData: index === 0 ? matchItm.thisData.laneA : matchItm.thisData.laneB
property var participant: thisData ? thisData.participant : undefined
property var result: thisData ? thisData.result : undefined
property var lane: index === 0 ? "A":"B"
property bool isWinner: matchItm.thisData.winner === laneRow.lane
height: parent.height / 2 - parent.spacing height: parent.height / 2 - parent.spacing
width: parent.width width: parent.width
@ -409,53 +230,90 @@ Item {
Label { Label {
Layout.preferredHeight: parent.height Layout.preferredHeight: parent.height
Layout.preferredWidth: parent.width * 0.15 Layout.preferredWidth: parent.width * 0.08
height: parent.height
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignLeft horizontalAlignment: Text.AlignLeft
font.pixelSize: height * 0.7 font.pixelSize: height * 0.4
fontSizeMode: Text.Fit font.bold: true
minimumPixelSize: 1 opacity: 0.7
text: matchItm.thisMatchData[index] !== undefined ? text: laneRow.participant ?
( (
parseInt(matchItm.thisMatchData[index]['result_rank0']) < 10 ? laneRow.participant.results[0].rank < 10 ?
matchItm.thisMatchData[index]['result_rank0'] + " ": laneRow.participant.results[0].rank + " ":
matchItm.thisMatchData[index]['result_rank0'] laneRow.participant.results[0].rank
): ):
"" ""
} }
Label { Label {
Layout.preferredHeight: parent.height Layout.preferredHeight: parent.height
Layout.fillWidth: true Layout.maximumWidth: parent.width * 0.6
height: parent.height height: parent.height
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignLeft horizontalAlignment: Text.AlignLeft
font.pixelSize: height * 0.5 font.pixelSize: height * 0.5
font.bold: matchItm.winnerIndex === index font.bold: laneRow.isWinner
elide: "ElideRight" elide: "ElideRight"
color: matchItm.winnerIndex === index ? Material.color(Material.Green):Material.primaryTextColor color: laneRow.isWinner ? Material.color(Material.Green):Material.primaryTextColor
text: matchItm.thisMatchData[index] !== undefined ? matchItm.thisMatchData[index]['firstname'] + " " + matchItm.thisMatchData[index]['lastname'] :"-" text: laneRow.participant ? laneRow.participant.firstName + " " + laneRow.participant.lastName :"-"
}
Rectangle {
Layout.preferredHeight: parent.height * 0.8
Layout.preferredWidth: parent.width * 0.13
visible: laneRow.participant && laneRow.participant.startNumber ? true:false
radius: height / 2
border.width: parent.height * 0.03
border.color: Material.frameColor
color: "transparent"
Label {
anchors.fill: parent
padding: parent.parent.height * 0.1
leftPadding: padding * 2
rightPadding: leftPadding
font.pixelSize: parent.height * 0.5
font.bold: true
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text: laneRow.participant ? laneRow.participant.startNumber:""
}
}
Item {
Layout.fillHeight: true
Layout.fillWidth: true
} }
Label { Label {
Layout.preferredHeight: parent.height Layout.preferredHeight: parent.height
Layout.preferredWidth: parent.width * 0.15
height: parent.height height: parent.height
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignRight
font.pixelSize: height * 0.5 font.pixelSize: height * 0.5
font.bold: laneRow.isWinner
text: matchItm.thisMatchData[index] !== undefined && matchItm.thisMatchData[index]['result'+matchItm.thisRound] !== undefined ? color: laneRow.isWinner ? Material.color(Material.Green):Material.primaryTextColor
( parseFloat(matchItm.thisMatchData[index]['result'+matchItm.thisRound]) ?
(parseFloat(matchItm.thisMatchData[index]['result'+matchItm.thisRound]).toFixed(2)) text: laneRow.result ? laneRow.result.result : ""
: matchItm.thisMatchData[index]['result'+matchItm.thisRound] )
: "-"
} }
} }
} }
@ -478,7 +336,7 @@ Item {
id: blueRockBadgeComponent id: blueRockBadgeComponent
BlueRockBadge { BlueRockBadge {
width: roundItem.width width: roundItem.width * 0.8
height: width * 0.25 height: width * 0.25
} }
} }

View file

@ -9,7 +9,7 @@ Rectangle {
// always unlock in debug mode // always unlock in debug mode
//property bool unlocked: QT_DEBUG || appSettings.read("speedBackendPurchase") === "1" //property bool unlocked: QT_DEBUG || appSettings.read("speedBackendPurchase") === "1"
property bool unlocked: appSettings.read("speedBackendPurchase") === "1" property bool unlocked: Qt.platform.os !== "iso" || appSettings.read("speedBackendPurchase") === "1"
Component.onCompleted: { Component.onCompleted: {
console.warn("unlocked:", appSettings.read("speedBackendPurchase")) console.warn("unlocked:", appSettings.read("speedBackendPurchase"))

View file

@ -0,0 +1,79 @@
import QtQuick 2.10
import QtQuick.Controls 2.15
import QtQuick.Controls.Material 2.15
Row {
id: control
property bool active: (parseInt(widgetData[ "route_order" ]) === 0) && (widgetData["discipline"] === "speed") && (thisData["result_l"] !== undefined || thisData["result_r"] !== undefined)
property var thisData: widgetData["participants"][partDel.thisIndex]
height: parent.height
width: active ? parent.width - resultLa.width:0
enabled: active
Repeater {
id: generalResRep
model: 2
delegate: Item {
id: boulderGenResItm
anchors.verticalCenter: parent.verticalCenter
width: parent.width / ( generalResRep.model )
height: parent.height
visible: control.active
Rectangle {
anchors {
left: parent.left
}
width: 1
height: parent.height
visible: index === 0
color: Material.primaryTextColor
}
Rectangle {
anchors {
right: parent.right
}
width: 1
height: parent.height
color: Material.primaryTextColor
}
Label {
id: boulderGenResLa
property string thisKey: "result_"+(["l", "r"][index])
anchors.centerIn: parent
height: parent.height
width: parent.width * 0.9
fontSizeMode: Text.Fit
font.pixelSize: Math.abs( height * 0.6 )
minimumPixelSize: 1
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
font.bold: thisData["result_l"] !== undefined && thisData["result_r"] !== undefined && thisData[thisKey] === thisData["result"]
text: (control.thisData[thisKey] !== undefined && parseInt(control.thisData[thisKey]) > 0) ? control.thisData[thisKey] : ""
}
}
}
}

View file

@ -1,7 +1,7 @@
import QtQuick 2.0 import QtQuick 2.0
import QtQuick.Controls 2.12 import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12 import QtQuick.Layouts 1.12
import QZXing 3.1 import QZXing 3.3
import QtMultimedia 5.12 import QtMultimedia 5.12
import QtQuick.Shapes 1.12 import QtQuick.Shapes 1.12
import QtQuick.Controls.Material 2.12 import QtQuick.Controls.Material 2.12

View file

@ -170,7 +170,8 @@ Page {
DisclaimerDialog { DisclaimerDialog {
id: aboutBluerockDisclaimerDialog id: aboutBluerockDisclaimerDialog
Material.theme: root.Material.theme Material.theme: root.Material.theme
title: "blueROCK v" + APP_VERSION + "<br>By <a href=\"https://itsblue.de\">Itsblue Development</a>" //% "privacy policy"
title: "blueROCK v" + APP_VERSION + "<br>By <a href=\"https://itsblue.de\">Itsblue Development</a>, <a href=\"https://itsblue.de/apps/bluerock/privacypolicy.html\">" + qsTrId("#privacyPolicy") + "</a>"
//% "This app was built using the <a href='https://qt.io'>Qt Framework</a> licensed under the <a href='https://www.gnu.org/licenses/lgpl-3.0.en.html'>GNU lgplV3 license</a>.<br><br>This app is open source and licensed under the <a href='https://www.gnu.org/licenses/agpl-3.0.en.html'>GNU agplV3 license</a>, the source code can be found <a href='https://itsblue.dev/blueROCK/app'>here</a>.<br><br>Resultservice and rankings provided by <a href='http://www.digitalROCK.de'>digital ROCK</a>." //% "This app was built using the <a href='https://qt.io'>Qt Framework</a> licensed under the <a href='https://www.gnu.org/licenses/lgpl-3.0.en.html'>GNU lgplV3 license</a>.<br><br>This app is open source and licensed under the <a href='https://www.gnu.org/licenses/agpl-3.0.en.html'>GNU agplV3 license</a>, the source code can be found <a href='https://itsblue.dev/blueROCK/app'>here</a>.<br><br>Resultservice and rankings provided by <a href='http://www.digitalROCK.de'>digital ROCK</a>."
content: qsTrId("#aboutBluerockDisclaimer") content: qsTrId("#aboutBluerockDisclaimer")
} }

View file

@ -190,17 +190,6 @@ Window {
Material.theme: appSettings.read("darkTheme") === "true" ? Material.Dark:Material.Light Material.theme: appSettings.read("darkTheme") === "true" ? Material.Dark:Material.Light
Component.onCompleted: {
//loadingDl.open()
//app.openAthlete() // dorian: 53139 , rustam: 6933 , helen: 53300
//openWidget({nation:'GER'})
//mainStack.push("Pages/AthleteSearchPage.qml")
//openWidget({comp: 11651, cat: 26})
//openWidget({person: 6623})
//console.log(JSON.stringify(serverConn.getParamsFromUrl("")))
//openWidgetFromUrl("https://l.bluerock.dev/?comp=11501&cat=GER_M")
}
FontLoader { FontLoader {
id: fa5solid id: fa5solid
source: "qrc:/fonts/fa5solid.otf" source: "qrc:/fonts/fa5solid.otf"

View file

@ -31,5 +31,9 @@
<file>Components/SharePopup.qml</file> <file>Components/SharePopup.qml</file>
<file>Pages/QrCodeScanPage.qml</file> <file>Pages/QrCodeScanPage.qml</file>
<file>Components/MovingLabel.qml</file> <file>Components/MovingLabel.qml</file>
<file>Components/SpeedFlowChart.js</file>
<file>Components/BoulderResultRow.qml</file>
<file>Components/GeneralResultRow.qml</file>
<file>Components/SpeedQualificationResultRow.qml</file>
</qresource> </qresource>
</RCC> </RCC>

BIN
resources/shared/badge.xcf Normal file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 257 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 227 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 265 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 212 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 217 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

View file

@ -127,8 +127,13 @@
<source>Unfortunately, the IFSC has restricted the access to their data and &lt;b&gt;is not willing to share results with blueROCK anymore&lt;/b&gt;. Because of this, blueROCK is no longer able to access and display IFSC results.&lt;br&gt;&lt;br&gt;You can find current IFSC results &lt;a href=&quot;https://ifsc.results.info&quot;&gt;over here&lt;/a&gt; and on &lt;a href=&quot;https://ifsc-climbing.org&quot;&gt;their website&lt;/a&gt;.</source> <source>Unfortunately, the IFSC has restricted the access to their data and &lt;b&gt;is not willing to share results with blueROCK anymore&lt;/b&gt;. Because of this, blueROCK is no longer able to access and display IFSC results.&lt;br&gt;&lt;br&gt;You can find current IFSC results &lt;a href=&quot;https://ifsc.results.info&quot;&gt;over here&lt;/a&gt; and on &lt;a href=&quot;https://ifsc-climbing.org&quot;&gt;their website&lt;/a&gt;.</source>
<translation>Leider hat die IFSC den Zugang zu ihren Ergebnissen eingeschränkt &lt;b&gt;und ist nicht mehr bereit, Ergebnisse mit blueROCK zu teilen&lt;/b&gt;. Daher ist blueROCK nicht länger in der Lage auf IFSC Ergebnisse zuzugriefen und diese anzuzeigen.&lt;br&gt;&lt;br&gt;Aktuelle IFSC Ergebnisse finden sich &lt;a href=&quot;https://ifsc.results.info&quot;&gt;hier&lt;/a&gt; und auf der &lt;a href=&quot;https://ifsc-climbing.org&quot;&gt;IFSC Webseite&lt;/a&gt;.</translation> <translation>Leider hat die IFSC den Zugang zu ihren Ergebnissen eingeschränkt &lt;b&gt;und ist nicht mehr bereit, Ergebnisse mit blueROCK zu teilen&lt;/b&gt;. Daher ist blueROCK nicht länger in der Lage auf IFSC Ergebnisse zuzugriefen und diese anzuzeigen.&lt;br&gt;&lt;br&gt;Aktuelle IFSC Ergebnisse finden sich &lt;a href=&quot;https://ifsc.results.info&quot;&gt;hier&lt;/a&gt; und auf der &lt;a href=&quot;https://ifsc-climbing.org&quot;&gt;IFSC Webseite&lt;/a&gt;.</translation>
</message> </message>
<message id="#privacyPolicy">
<location filename="../qml/Pages/StartPage.qml" line="174"/>
<source>privacy policy</source>
<translation>Datenschutzerklärung</translation>
</message>
<message id="#aboutBluerockDisclaimer"> <message id="#aboutBluerockDisclaimer">
<location filename="../qml/Pages/StartPage.qml" line="175"/> <location filename="../qml/Pages/StartPage.qml" line="176"/>
<source>This app was built using the &lt;a href=&apos;https://qt.io&apos;&gt;Qt Framework&lt;/a&gt; licensed under the &lt;a href=&apos;https://www.gnu.org/licenses/lgpl-3.0.en.html&apos;&gt;GNU lgplV3 license&lt;/a&gt;.&lt;br&gt;&lt;br&gt;This app is open source and licensed under the &lt;a href=&apos;https://www.gnu.org/licenses/agpl-3.0.en.html&apos;&gt;GNU agplV3 license&lt;/a&gt;, the source code can be found &lt;a href=&apos;https://itsblue.dev/blueROCK/app&apos;&gt;here&lt;/a&gt;.&lt;br&gt;&lt;br&gt;Resultservice and rankings provided by &lt;a href=&apos;http://www.digitalROCK.de&apos;&gt;digital ROCK&lt;/a&gt;.</source> <source>This app was built using the &lt;a href=&apos;https://qt.io&apos;&gt;Qt Framework&lt;/a&gt; licensed under the &lt;a href=&apos;https://www.gnu.org/licenses/lgpl-3.0.en.html&apos;&gt;GNU lgplV3 license&lt;/a&gt;.&lt;br&gt;&lt;br&gt;This app is open source and licensed under the &lt;a href=&apos;https://www.gnu.org/licenses/agpl-3.0.en.html&apos;&gt;GNU agplV3 license&lt;/a&gt;, the source code can be found &lt;a href=&apos;https://itsblue.dev/blueROCK/app&apos;&gt;here&lt;/a&gt;.&lt;br&gt;&lt;br&gt;Resultservice and rankings provided by &lt;a href=&apos;http://www.digitalROCK.de&apos;&gt;digital ROCK&lt;/a&gt;.</source>
<oldsource>This app was built using the &lt;a href=&apos;https://qt.io&apos;&gt;Qt Framework&lt;/a&gt; licensed under the &lt;a href=&apos;https://www.gnu.org/licenses/lgpl-3.0.en.html&apos;&gt;GNU lgplV3 license&lt;/a&gt;.&lt;br&gt;&lt;br&gt;This app is open source and licensed under the &lt;a href=&apos;https://www.gnu.org/licenses/agpl-3.0.en.html&apos;&gt;GNU agplV3 license&lt;/a&gt;, the source code can be found &lt;a href=&apos;https://itsblue.dev/dorian/blueROCK/&apos;&gt;here&lt;/a&gt;.&lt;br&gt;&lt;br&gt;Resultservice and rankings provided by &lt;a href=&apos;http://www.digitalROCK.de&apos;&gt;digital ROCK&lt;/a&gt;.</oldsource> <oldsource>This app was built using the &lt;a href=&apos;https://qt.io&apos;&gt;Qt Framework&lt;/a&gt; licensed under the &lt;a href=&apos;https://www.gnu.org/licenses/lgpl-3.0.en.html&apos;&gt;GNU lgplV3 license&lt;/a&gt;.&lt;br&gt;&lt;br&gt;This app is open source and licensed under the &lt;a href=&apos;https://www.gnu.org/licenses/agpl-3.0.en.html&apos;&gt;GNU agplV3 license&lt;/a&gt;, the source code can be found &lt;a href=&apos;https://itsblue.dev/dorian/blueROCK/&apos;&gt;here&lt;/a&gt;.&lt;br&gt;&lt;br&gt;Resultservice and rankings provided by &lt;a href=&apos;http://www.digitalROCK.de&apos;&gt;digital ROCK&lt;/a&gt;.</oldsource>
<translation>Diese App wurde unter Verwendung des &lt;a href=&apos;https://qt.io&apos;&gt;Qt Frameworks&lt;/a&gt; unter der &lt;a href=&apos;https://www.gnu.org/licenses/lgpl-3.0.en.html&apos;&gt;GNU lgplV3 Lizenz&lt;/a&gt; erstellt.&lt;br&gt;&lt;br&gt;Diese App ist Open-source und lizensiert unter der &lt;a href=&apos;https://www.gnu.org/licenses/agpl-3.0.en.html&apos;&gt;GNU agplV3 Lizenz&lt;/a&gt;. Der Sourcecode findet sich &lt;a href=&apos;https://itsblue.dev/blueROCK/app&apos;&gt;hier&lt;/a&gt;.&lt;br&gt;&lt;br&gt;Die Ergebnisse und Ranglisten werden von &lt;a href=&apos;http://www.digitalROCK.de&apos;&gt;digital ROCK&lt;/a&gt; zur Verfügung gestellt.</translation> <translation>Diese App wurde unter Verwendung des &lt;a href=&apos;https://qt.io&apos;&gt;Qt Frameworks&lt;/a&gt; unter der &lt;a href=&apos;https://www.gnu.org/licenses/lgpl-3.0.en.html&apos;&gt;GNU lgplV3 Lizenz&lt;/a&gt; erstellt.&lt;br&gt;&lt;br&gt;Diese App ist Open-source und lizensiert unter der &lt;a href=&apos;https://www.gnu.org/licenses/agpl-3.0.en.html&apos;&gt;GNU agplV3 Lizenz&lt;/a&gt;. Der Sourcecode findet sich &lt;a href=&apos;https://itsblue.dev/blueROCK/app&apos;&gt;hier&lt;/a&gt;.&lt;br&gt;&lt;br&gt;Die Ergebnisse und Ranglisten werden von &lt;a href=&apos;http://www.digitalROCK.de&apos;&gt;digital ROCK&lt;/a&gt; zur Verfügung gestellt.</translation>

Binary file not shown.

View file

@ -123,8 +123,13 @@
<source>Unfortunately, the IFSC has restricted the access to their data and &lt;b&gt;is not willing to share results with blueROCK anymore&lt;/b&gt;. Because of this, blueROCK is no longer able to access and display IFSC results.&lt;br&gt;&lt;br&gt;You can find current IFSC results &lt;a href=&quot;https://ifsc.results.info&quot;&gt;over here&lt;/a&gt; and on &lt;a href=&quot;https://ifsc-climbing.org&quot;&gt;their website&lt;/a&gt;.</source> <source>Unfortunately, the IFSC has restricted the access to their data and &lt;b&gt;is not willing to share results with blueROCK anymore&lt;/b&gt;. Because of this, blueROCK is no longer able to access and display IFSC results.&lt;br&gt;&lt;br&gt;You can find current IFSC results &lt;a href=&quot;https://ifsc.results.info&quot;&gt;over here&lt;/a&gt; and on &lt;a href=&quot;https://ifsc-climbing.org&quot;&gt;their website&lt;/a&gt;.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message id="#privacyPolicy">
<location filename="../qml/Pages/StartPage.qml" line="174"/>
<source>privacy policy</source>
<translation type="unfinished"></translation>
</message>
<message id="#aboutBluerockDisclaimer"> <message id="#aboutBluerockDisclaimer">
<location filename="../qml/Pages/StartPage.qml" line="175"/> <location filename="../qml/Pages/StartPage.qml" line="176"/>
<source>This app was built using the &lt;a href=&apos;https://qt.io&apos;&gt;Qt Framework&lt;/a&gt; licensed under the &lt;a href=&apos;https://www.gnu.org/licenses/lgpl-3.0.en.html&apos;&gt;GNU lgplV3 license&lt;/a&gt;.&lt;br&gt;&lt;br&gt;This app is open source and licensed under the &lt;a href=&apos;https://www.gnu.org/licenses/agpl-3.0.en.html&apos;&gt;GNU agplV3 license&lt;/a&gt;, the source code can be found &lt;a href=&apos;https://itsblue.dev/blueROCK/app&apos;&gt;here&lt;/a&gt;.&lt;br&gt;&lt;br&gt;Resultservice and rankings provided by &lt;a href=&apos;http://www.digitalROCK.de&apos;&gt;digital ROCK&lt;/a&gt;.</source> <source>This app was built using the &lt;a href=&apos;https://qt.io&apos;&gt;Qt Framework&lt;/a&gt; licensed under the &lt;a href=&apos;https://www.gnu.org/licenses/lgpl-3.0.en.html&apos;&gt;GNU lgplV3 license&lt;/a&gt;.&lt;br&gt;&lt;br&gt;This app is open source and licensed under the &lt;a href=&apos;https://www.gnu.org/licenses/agpl-3.0.en.html&apos;&gt;GNU agplV3 license&lt;/a&gt;, the source code can be found &lt;a href=&apos;https://itsblue.dev/blueROCK/app&apos;&gt;here&lt;/a&gt;.&lt;br&gt;&lt;br&gt;Resultservice and rankings provided by &lt;a href=&apos;http://www.digitalROCK.de&apos;&gt;digital ROCK&lt;/a&gt;.</source>
<oldsource>This app was built using the &lt;a href=&apos;https://qt.io&apos;&gt;Qt Framework&lt;/a&gt; licensed under the &lt;a href=&apos;https://www.gnu.org/licenses/lgpl-3.0.en.html&apos;&gt;GNU lgplV3 license&lt;/a&gt;.&lt;br&gt;&lt;br&gt;This app is open source and licensed under the &lt;a href=&apos;https://www.gnu.org/licenses/agpl-3.0.en.html&apos;&gt;GNU agplV3 license&lt;/a&gt;, the source code can be found &lt;a href=&apos;https://itsblue.dev/dorian/blueROCK/&apos;&gt;here&lt;/a&gt;.&lt;br&gt;&lt;br&gt;Resultservice and rankings provided by &lt;a href=&apos;http://www.digitalROCK.de&apos;&gt;digital ROCK&lt;/a&gt;.</oldsource> <oldsource>This app was built using the &lt;a href=&apos;https://qt.io&apos;&gt;Qt Framework&lt;/a&gt; licensed under the &lt;a href=&apos;https://www.gnu.org/licenses/lgpl-3.0.en.html&apos;&gt;GNU lgplV3 license&lt;/a&gt;.&lt;br&gt;&lt;br&gt;This app is open source and licensed under the &lt;a href=&apos;https://www.gnu.org/licenses/agpl-3.0.en.html&apos;&gt;GNU agplV3 license&lt;/a&gt;, the source code can be found &lt;a href=&apos;https://itsblue.dev/dorian/blueROCK/&apos;&gt;here&lt;/a&gt;.&lt;br&gt;&lt;br&gt;Resultservice and rankings provided by &lt;a href=&apos;http://www.digitalROCK.de&apos;&gt;digital ROCK&lt;/a&gt;.</oldsource>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>

View file

@ -33,6 +33,9 @@ int main(int argc, char *argv[])
QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
QGuiApplication app(argc, argv); QGuiApplication app(argc, argv);
QFont f = app.font();
f.setPixelSize(16);
app.setFont(f);
// translation // translation
QString localeName = QLocale::system().bcp47Name(); QString localeName = QLocale::system().bcp47Name();