Compare commits

..

46 Commits

Author SHA1 Message Date
Dennis Guse 23f47f10f8 Release v3.7.5 2020-06-14 20:09:27 +02:00
Román Martínez 251fa17487 Merge pull request #271 from OpenTracksApp/all_statistics#112
Aggregated statistics by activity type.
2020-06-14 20:03:29 +02:00
Román bae3373fe9 Aggregated statistics by activity type. Fixes #112. 2020-06-14 19:57:07 +02:00
Dennis Guse 0a685a66e3 Added list of tested Bluetooth LE sensors.
Fixes #202.
2020-06-14 11:58:45 +02:00
Dennis Guse 5ca9ca857a Cleanup. 2020-06-13 23:07:58 +02:00
Dennis Guse d9dfa6d746 Dashboard API: add data transfer as GPX and removed unnecessary IntentChooser. 2020-06-13 17:56:59 +02:00
Dennis Guse 3a5220546e Dashboard API: fallback to "open as KMZ" implemented as proxy activity.
We are not allowed to query for installed packages as of Android R (API 30).
2020-06-13 17:56:59 +02:00
Dennis Guse 047d5c2340 Manifest reordered to fix warning. 2020-06-13 17:56:59 +02:00
Dennis Guse 725c21c0a1 Bugfix: parse URI with trackIds correctly. 2020-06-13 17:56:59 +02:00
Dennis Guse 7939e39fc1 Go for Android R (API level 30). 2020-06-13 17:56:59 +02:00
Dennis Guse a133bd8f9e Bugfix: adaptive icon was too large.
We now use the same as OSMDashboard.
Thanks Peter.
2020-06-13 00:08:00 +02:00
transifex-integration[bot] 1f9790cba8 Translate /src/main/res/values/strings.xml in gl
translation completed for the source file '/src/main/res/values/strings.xml'
on the 'gl' language.
2020-06-10 22:20:23 +02:00
Dennis Guse a3ba1e1490 Cleanup: use lambda instead of runnable. 2020-06-09 23:01:09 +02:00
Dennis Guse accb30152f Translations fixed. 2020-06-09 19:58:23 +02:00
Dennis Guse dc7daa6e8c App icon: be complaint with Android requirements. (#253)
Fixes #121.
2020-06-09 19:37:47 +02:00
Dennis Guse 1d8e788d53 Documentation: add internal data flow. 2020-06-09 19:36:54 +02:00
Dennis Guse 568b908b26 Removed unused strings. 2020-06-09 19:35:57 +02:00
transifex-integration[bot] 3ab63adb34 Translate '/src/main/res/values/strings.xml' in 'de' [manual sync] (#269)
* Translate /src/main/res/values/strings.xml in de

at least 95% translated for the source file '/src/main/res/values/strings.xml'
on the 'de' language.

 Manual sync of partially translated files: untranslated content is included with an empty translation or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2020-06-08 23:42:16 +02:00
transifex-integration[bot] 91692f345e Translate /src/main/res/values/strings.xml in fr
at least 95% translated for the source file '/src/main/res/values/strings.xml'
on the 'fr' language.

 Manual sync of partially translated files: untranslated content is included with an empty translation or source language content depending on file format
2020-06-08 23:32:34 +02:00
transifex-integration[bot] dbdb98a682 Translate /src/main/res/values/strings.xml in eu
at least 95% translated for the source file '/src/main/res/values/strings.xml'
on the 'eu' language.

 Manual sync of partially translated files: untranslated content is included with an empty translation or source language content depending on file format
2020-06-08 23:32:21 +02:00
transifex-integration[bot] df66cd5753 Translate /src/main/res/values/strings.xml in cs
at least 95% translated for the source file '/src/main/res/values/strings.xml'
on the 'cs' language.

 Manual sync of partially translated files: untranslated content is included with an empty translation or source language content depending on file format
2020-06-08 23:31:19 +02:00
transifex-integration[bot] 6e39dd37f8 Translate /src/main/res/values/strings.xml in da
at least 95% translated for the source file '/src/main/res/values/strings.xml'
on the 'da' language.

 Manual sync of partially translated files: untranslated content is included with an empty translation or source language content depending on file format
2020-06-08 23:31:08 +02:00
transifex-integration[bot] 7212f7be94 Translate /src/main/res/values/strings.xml in nl
at least 95% translated for the source file '/src/main/res/values/strings.xml'
on the 'nl' language.

 Manual sync of partially translated files: untranslated content is included with an empty translation or source language content depending on file format
2020-06-08 23:31:00 +02:00
transifex-integration[bot] 77fe494e6c Translate /src/main/res/values/strings.xml in et
at least 95% translated for the source file '/src/main/res/values/strings.xml'
on the 'et' language.

 Manual sync of partially translated files: untranslated content is included with an empty translation or source language content depending on file format
2020-06-08 23:30:55 +02:00
transifex-integration[bot] 2f491e8c10 Translate /src/main/res/values/strings.xml in es
at least 95% translated for the source file '/src/main/res/values/strings.xml'
on the 'es' language.

 Manual sync of partially translated files: untranslated content is included with an empty translation or source language content depending on file format
2020-06-08 23:30:48 +02:00
Dennis Guse f4fe7b1ab3 Import: convert all failed date parsing into SAXExceptions. 2020-06-08 22:51:01 +02:00
Peter Storch 7e444cbf31 Merge pull request #248 from OpenTracksApp/keep_screen_on_dashboard
forward keep screen on while recording preference to dashboard
2020-06-06 23:12:24 +02:00
Dennis Guse ed6ab9c53c Import: be lenient with missing timezone information.
Fixes #249.
2020-06-06 22:58:02 +02:00
Peter Storch f91ca3154c forward show on lockscreen to dashboard 2020-06-05 20:52:00 +02:00
Peter Storch bbfab1b201 forward keep screen on while recording preference to dashboard 2020-06-05 20:17:24 +02:00
Dennis Guse 1f2e3bcf70 Upgrade to Android Gradle plugin 4.0.0 2020-05-30 20:25:36 +02:00
Dennis Guse d1f3791f97 Release v3.7.4 2020-05-27 08:21:37 +02:00
Román 490b95a001 Merge branch 'split_trackdetail#171' 2020-05-25 13:28:36 +02:00
Román 12e6f03098 Recorded/Recording nested layouts converted to constraint layout. Fixes #15. 2020-05-25 13:06:36 +02:00
Román d86f42e2e9 Animation between recording and recorded activities. Update PlantUML with new changes. 2020-05-25 13:06:17 +02:00
Román 360d59d3de Split detail and record to simplify the code. Fixes #171. 2020-05-25 13:06:17 +02:00
Dennis Guse b617420290 Export: do not show progress of exported TrackPoints.
Only the overall number of tracks is shown now (similar to import).
2020-05-24 10:58:43 +02:00
Dennis Guse 53b267150b Export/Import: TrackFileFormat is now selected via settings only. 2020-05-24 10:58:43 +02:00
Dennis Guse 0dfd55ed52 Settings: added default sharing track file format.
Fixes #225.
2020-05-24 10:58:43 +02:00
Román daabd5381d Links in help and about are clickable. Also added scroll in about activity. Fixes #232. 2020-05-22 16:01:33 +02:00
Dennis Guse a842129e37 Bugfix: wheel circumference was not stored in correct preference key. 2020-05-13 21:46:48 +02:00
Dennis Guse e8b9c2bbc3 Release v3.7.3 2020-05-13 21:03:52 +02:00
Dennis Guse e55924dae3 Bugfix: Cadence/Speed computation incorrectly truncated time to long instead of float. 2020-05-13 20:34:16 +02:00
Dennis Guse e3a8143d58 Cleanup. 2020-05-13 20:34:16 +02:00
Dennis Guse 30310bb874 Localization: removed unused translations.
Fixed German labels for speed (were too long on Stats screen).
2020-05-13 20:34:16 +02:00
Dennis Guse 9f377b172d Upgraded to Gradle wrapper 6.3 2020-05-10 15:28:42 +02:00
147 changed files with 4174 additions and 2994 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
+9 -3
View File
@@ -51,13 +51,19 @@ _OpenTracks_ is a sport tracking application that completely respects your priva
__Only required permissions:__
* _ACCESS_FINE_LOCATION_: required to use the GPS.
An overview of Bluetooth LE sensors that are known to work with OpenTracks is in [README_TESTED_SENSORS.md](README_TESTED_SENSORS.md).
_Please note:_
_OpenTracks_ does not contain a _map_ (as this would required Internet access).
To show your tracks on a map, a 3rd party application (e.g., [OsmAnd](https://play.google.com/store/apps/details?id=net.osmand) or [MAPS.ME](https://play.google.com/store/apps/details?id=com.mapswithme.maps.pro)) needs to be installed.
## Custom Dashboards
## Custom Dashboards (incl. Map)
As of v3.3.1 OpenTracks enables to use custom dashboards.
The reference implementation is [OSMDashboard](https://github.com/OpenTracksApp/OSMDashboard), which presents an OpenStreetMap map (showing the current track, incl. updates).
The developer documentation is in [README_API.md](README_API.md).
Alternatively, recorded tracks can be shared as KMZ/GPX to installed applications (e.g., [OsmAnd](https://play.google.com/store/apps/details?id=net.osmand) or [MAPS.ME](https://play.google.com/store/apps/details?id=com.mapswithme.maps.pro)).
However, this is rather slow and does not provide updates while recording.
## Screenshots
<div>
@@ -87,7 +93,7 @@ Rework of _OpenTracks_ included:
* removing calorie estimation and activity estimation,
* removing support for ANT+ and Classic Bluetooth,
* adding support for Bluetooth LE heart rate sensors,
* removing Protobuf (store sensor data in SQLite columns directly), and
* removing Protobuf (store sensosensorr data in SQLite columns directly), and
* removing Android Service API for other apps.
Artwork, logos and user interface remained more or less unchanged.
-3
View File
@@ -7,9 +7,6 @@ Although this might be (mostly) sufficient, it has some limitations.
This include limited configurability (e.g., ordering of shown elements) and the lack of Internet access.
In fact, the later is considered a feature but severely limits the implementation presenting a map (at least in an easy way).
_NOTE:_ for showing a track on a map a workaround was implemented in OpenTracks.
Data could be exported as KMZ and presented in 3rd-party application (e.g., [OsmAnd](https://play.google.com/store/apps/details?id=net.osmand) or [MAPS.ME](https://play.google.com/store/apps/details?id=com.mapswithme.maps.pro)).
For the time being, the OpenTracks Data API can be used to implement mainly custom dashboards.
## Implementation
+20
View File
@@ -0,0 +1,20 @@
# Overview of tested Bluetooth LE sensors
## HRS: Heartrate Service
* Decathlon|Geonaute|Kalenji Dual HRM Belt
* Polar H7
* Polar OH1
Has updatable firmware that requires a user account at polar.com
* Wahoo Tickr (Model: WFBTHR02)
## CSCP: Cycling Cadence and Speed Service
Please note that the according to the specification these sensors _may_ provide speed as well as cadence.
However, often only one value is provided.
### Speed
* Wahoo Speed (Model: WFRPMSPD)
### Cadence
* Wahoo Cadence (Model: WFPODCAD2)
This sensor reports cadence data as speed.
A workaround is in place.
+15 -9
View File
@@ -6,7 +6,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.6.2'
classpath 'com.android.tools.build:gradle:4.0.0'
}
}
@@ -50,25 +50,30 @@ def getVersionName = { ->
}
android {
compileSdkVersion 29
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
compileSdkVersion 30
defaultConfig {
applicationId "de.dennisguse.opentracks"
manifestPlaceholders = [
applicationLogo: "@drawable/ic_logo_color_24dp",
applicationLogo: "@mipmap/ic_launcher",
applicationName: "@string/app_name"
]
versionCode 3381
versionCode 3427
//versionCode getVersionCode() //Useful for debugging.
versionName "v3.7.2"
versionName "v3.7.5"
buildConfigField "String", "VERSION_NAME_FULL", "\"${getVersionName()}\""
minSdkVersion 21
targetSdkVersion 29
targetSdkVersion 30
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
@@ -78,7 +83,7 @@ android {
applicationIdSuffix ".debug"
versionNameSuffix "-debug"
manifestPlaceholders = [
applicationLogo: "@drawable/ic_logo_black_24dp",
applicationLogo: "@mipmap/ic_launcher_debug",
applicationName: "OpenTracks (Debug)"
]
}
@@ -100,8 +105,10 @@ android {
dependencies {
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.preference:preference:1.1.0'
implementation 'androidx.preference:preference:1.1.1'
implementation 'androidx.documentfile:documentfile:1.0.1'
implementation 'com.google.android.material:material:1.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
androidTestImplementation 'androidx.test:core:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
@@ -113,5 +120,4 @@ dependencies {
testImplementation 'androidx.test:core:1.2.0'
testImplementation 'org.mockito:mockito-core:3.0.0'
implementation 'com.google.android.material:material:1.1.0'
}
+23 -12
View File
@@ -9,23 +9,34 @@ from every activity showing a menu.
endlegend
[*] --> TrackListActivity
TrackListActivity --> TrackDetailActivity : Start recording
TrackListActivity --> TrackRecordingActivity : Start recording
TrackListActivity --> SearchListActivity
TrackListActivity --> MarkerListActivity : Show all markers
TrackListActivity --> TrackDetailActivity : Show track
TrackListActivity --> TrackRecordedActivity : Show track
TrackListActivity --> TrackDeleteActivity
SearchListActivity --> MarkerDetailActivity : Search result
SearchListActivity --> TrackDetailActivity : Search result
SearchListActivity --> TrackRecordedActivity : Search result
TrackDetailActivity --> TrackDeleteActivity
TrackDetailActivity --> TrackEditActivity
TrackDetailActivity --> MarkerListActivity
TrackDetailActivity --> MarkerEditActivity : Add marker
TrackDetailActivity --> CameraIntent : Add marker (with photo)
TrackDetailActivity --> ShareFileIntent
TrackDetailActivity --> DashboardIntent : Database cursor
TrackDetailActivity --> TrackOnMapIntent : KMZ
TrackRecordedActivity --> TrackDeleteActivity
TrackRecordedActivity --> TrackEditActivity
TrackRecordedActivity --> MarkerListActivity
TrackRecordedActivity --> MarkerEditActivity : Add marker
TrackRecordedActivity --> CameraIntent : Add marker (with photo)
TrackRecordedActivity --> ShareFileIntent
TrackRecordedActivity --> DashboardIntent : Database cursor
TrackRecordedActivity --> TrackOnMapIntent : KMZ
TrackRecordedActivity --> TrackRecordingActivity
TrackRecordedActivity --> SettingsActivity
TrackRecordedActivity --> TrackListActivity : Back button
TrackRecordingActivity --> TrackOnMapIntent
TrackRecordingActivity --> MarkerEditActivity : Add marker
TrackRecordingActivity --> MarkerListActivity
TrackRecordingActivity --> TrackEditActivity
TrackRecordingActivity --> SettingsActivity
TrackRecordingActivity --> TrackRecordedActivity : Stop recording
TrackRecordingActivity --> TrackListActivity : Back button
MarkerListActivity --> MarkerDetailActivity
@@ -37,4 +48,4 @@ SettingsActivity --> HelpActivity
SettingsActivity --> ExportActivity
SettingsActivity --> ImportActivity
@enduml
@enduml
+18
View File
@@ -0,0 +1,18 @@
@startuml
SensorManager --> ElevationSumManager
LocationManager --> TrackRecordingService
ElevationSumManager --> TrackRecordingService
TrackRecordingService --> TrackRecordingServiceConnection
TrackRecordingService --> Database
Database --> CustomContentProvider
CustomContentProvider --> TrackDataHub
CustomContentProvider --> ShareContentProvider
TrackDataHub --> StatisticsRecordingFragment : TrackPoints, TrackStatistics, Waypoints (push)
TrackDataHub --> StatisticsRecordedFragment : TrackPoints, TrackStatistics, Waypoints (push)
TrackDataHub --> ChartFragment --> ChartView
TrackRecordingServiceConnection --> StatisticsRecordingFragment : Sensor data (heartrate, cadence, elevation gain; pull 1s)
TrackRecordingServiceConnection --> TrackController : Start time (pull, onStart)
@enduml
@@ -0,0 +1,7 @@
v3.7.3: OpenTracks
Bugfix:
- Fixed computation of cadence and speed (via Bluetooth LE sensor)
Developer:
- Removed unused translations
@@ -0,0 +1,12 @@
v3.7.4: OpenTracks
Changes:
- Sharing/export format configurable
Bugfix:
- Wheel diameter not stored correctly (for speed sensor)
- Help: links are clickable
Developer:
- Split TrackDetailActivity
- StatsFragement successor uses ConstraintLayout
@@ -0,0 +1,11 @@
v3.7.5: OpenTracks
Changes:
- Added aggregated statistics summary (from main the screen's menu)
- Dashboard API: pass "show on lock screen"- and "keep screen on"-setting
- Updated translations
- Import: be lenient with ISO8601 date format
- Show track on map: file format can be selected and opening dashboard works on Android R (API 30+)
Bugfix:
- App icon now correctly implemented
Binary file not shown.
+1 -2
View File
@@ -1,6 +1,5 @@
#Sun Apr 12 18:41:12 CEST 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
Vendored
+14 -17
View File
@@ -82,6 +82,7 @@ esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
@@ -129,6 +130,7 @@ fi
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
@@ -154,19 +156,19 @@ if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
i=`expr $i + 1`
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
@@ -175,14 +177,9 @@ save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"
Vendored
+104 -100
View File
@@ -1,100 +1,104 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
@@ -11,7 +11,14 @@ import de.dennisguse.opentracks.io.file.TrackFileFormat;
public class ShareContentProviderTest {
@Test
public void testCreateandParseURI() {
public void testCreateandParseURI_invalid() {
Uri uri = Uri.parse("content://de.dennisguse.opentracks.debug.content/tracks/1");
Assert.assertArrayEquals(new long[]{}, ShareContentProvider.parseURI(uri));
}
@Test
public void testCreateandParseURI_valid() {
long[] trackIds = {1, 3, 5};
Pair<Uri, String> shareURIandMIME = ShareContentProvider.createURI(trackIds, "TrackName", TrackFileFormat.KML_ONLY_TRACK);
@@ -12,7 +12,7 @@ import de.dennisguse.opentracks.util.UintUtils;
public class SensorDataCyclingTest {
@Test
public void compute_cadence() {
public void compute_cadence_1() {
// given
SensorDataCycling.Cadence previous = new SensorDataCycling.Cadence("sensorAddress", "sensorName", 1, 1024); // 1s
SensorDataCycling.Cadence current = new SensorDataCycling.Cadence("sensorAddress", "sensorName", 2, 2048); // 2s
@@ -24,6 +24,19 @@ public class SensorDataCyclingTest {
Assert.assertEquals(60, current.getCadence_rpm(), 0.01);
}
@Test
public void compute_cadence_2() {
// given
SensorDataCycling.Cadence previous = new SensorDataCycling.Cadence("sensorAddress", "sensorName", 1, 6184);
SensorDataCycling.Cadence current = new SensorDataCycling.Cadence("sensorAddress", "sensorName", 2, 8016);
// when
current.compute(previous);
// then
Assert.assertEquals(33.53, current.getCadence_rpm(), 0.01);
}
@Test
public void compute_cadence_sameCount() {
// given
@@ -77,6 +90,19 @@ public class SensorDataCyclingTest {
Assert.assertEquals(60, current.getCadence_rpm(), 0.01);
}
@Test
public void compute_speed() {
// given
SensorDataCycling.Speed previous = new SensorDataCycling.Speed("sensorAddress", "sensorName", 1, 6184);
SensorDataCycling.Speed current = new SensorDataCycling.Speed("sensorAddress", "sensorName", 2, 8016);
// when
current.compute(previous, 2150);
// then
Assert.assertEquals(1.20, current.getSpeed_mps(), 0.01);
}
@Test
public void compute_speed_rollOverCount() {
// given
@@ -97,7 +97,7 @@ public class ExportImportTest {
Track track = contentProviderUtils.getTrack(trackId);
TrackFileFormat trackFileFormat = TrackFileFormat.KML_WITH_TRACKDETAIL;
TrackExporter trackExporter = trackFileFormat.newTrackExporter(context, new Track[]{track}, null);
TrackExporter trackExporter = trackFileFormat.newTrackExporter(context, new Track[]{track});
// when
// 1. export
@@ -169,7 +169,7 @@ public class ExportImportTest {
Track track = contentProviderUtils.getTrack(trackId);
TrackFileFormat trackFileFormat = TrackFileFormat.GPX;
TrackExporter trackExporter = trackFileFormat.newTrackExporter(context, new Track[]{track}, null);
TrackExporter trackExporter = trackFileFormat.newTrackExporter(context, new Track[]{track});
// when
// 1. export
@@ -0,0 +1,62 @@
package de.dennisguse.opentracks.util;
import android.content.Context;
import android.content.SharedPreferences;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.io.file.TrackFileFormat;
@RunWith(AndroidJUnit4.class)
public class PreferencesUtilsTest {
private final Context context = ApplicationProvider.getApplicationContext();
@Test
public void ExportTrackFileFormat_ok() {
// given
SharedPreferences.Editor editor = PreferencesUtils.getSharedPreferences(context).edit();
editor.putString(context.getString(R.string.export_trackfileformat_key), TrackFileFormat.KMZ_WITH_TRACKDETAIL.name());
editor.commit();
// when
TrackFileFormat trackFileFormat = PreferencesUtils.getExportTrackFileFormat(context);
// then
Assert.assertEquals(TrackFileFormat.KMZ_WITH_TRACKDETAIL, trackFileFormat);
}
@Test
public void ExportTrackFileFormat_invalid() {
// given
SharedPreferences.Editor editor = PreferencesUtils.getSharedPreferences(context).edit();
editor.putString(context.getString(R.string.export_trackfileformat_key), "invalid");
editor.commit();
// when
TrackFileFormat trackFileFormat = PreferencesUtils.getExportTrackFileFormat(context);
// then
Assert.assertEquals(TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA, trackFileFormat);
}
@Test
public void ExportTrackFileFormat_noValue() {
// given
SharedPreferences.Editor editor = PreferencesUtils.getSharedPreferences(context).edit();
editor.clear();
editor.commit();
// when
TrackFileFormat trackFileFormat = PreferencesUtils.getExportTrackFileFormat(context);
// then
Assert.assertEquals(TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA, trackFileFormat);
}
}
@@ -128,6 +128,7 @@ public class StringUtilsTest {
*/
@Test
public void testGetTime_timezone() {
assertGetTime("2010-05-04T03:02:01", 2010, 5, 4, 3, 2, 1, 0);
assertGetTime("2010-05-04T03:02:01Z", 2010, 5, 4, 3, 2, 1, 0);
assertGetTime("2010-05-04T03:02:01+00:00", 2010, 5, 4, 3, 2, 1, 0);
assertGetTime("2010-05-04T03:02:01-00:00", 2010, 5, 4, 3, 2, 1, 0);
@@ -0,0 +1,257 @@
package de.dennisguse.opentracks.viewmodels;
import android.content.Context;
import androidx.test.core.app.ApplicationProvider;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.stats.TrackStatistics;
import de.dennisguse.opentracks.util.TrackIconUtils;
@RunWith(JUnit4.class)
public class AggregatedStatisticsTest {
private final Context context = ApplicationProvider.getApplicationContext();
/**
* Create a TrackStatistics object.
*
* @param totalDistance distance in meters.
* @param totalTime total time in milliseconds.
* @return TrackStatistics object.
*/
private static Track createTrack(Context context, long totalDistance, long totalTime, String category) {
TrackStatistics statistics = new TrackStatistics();
statistics.setStartTime_ms(1000L); // Resulting start time
statistics.setStopTime_ms(1000L + totalTime);
statistics.setTotalTime(totalTime);
statistics.setMovingTime(totalTime);
statistics.setTotalDistance(totalDistance);
statistics.setTotalElevationGain(50.0);
statistics.setMaxSpeed(50.0); // Resulting max speed
statistics.setMaxElevation(1250.0);
statistics.setMinElevation(1200.0); // Resulting min elevation
Track track = new Track();
track.setIcon(TrackIconUtils.getIconValue(context, category));
track.setCategory(category);
track.setTrackStatistics(statistics);
return track;
}
@Test
public void testAggregate() {
// given
// 10km in 40 minutes.
long totalDistance = 10000;
long totalTime = 2400000;
String biking = context.getString(R.string.activity_type_biking);
Track track = createTrack(context, totalDistance, totalTime, biking);
// when
AggregatedStatistics aggregatedStatistics = new AggregatedStatistics();
aggregatedStatistics.aggregate(track);
// then
Assert.assertEquals(1, aggregatedStatistics.getCount());
Assert.assertTrue(aggregatedStatistics.get(biking) != null);
Assert.assertEquals(1, aggregatedStatistics.get(biking).getCountTracks());
TrackStatistics statistics2 = aggregatedStatistics.get(biking).getTrackStatistics();
Assert.assertEquals(totalDistance, statistics2.getTotalDistance(), 0);
Assert.assertEquals(totalTime, statistics2.getMovingTime());
}
@Test
public void testAggregate_mountainBiking() {
// given
// 10km in 40 minutes.
long totalDistance = 10000;
long totalTime = 2400000;
String mountainBiking = context.getString(R.string.activity_type_mountain_biking);
Track track = createTrack(context, totalDistance, totalTime, mountainBiking);
// when
AggregatedStatistics aggregatedStatistics = new AggregatedStatistics();
aggregatedStatistics.aggregate(track);
// then
Assert.assertTrue(aggregatedStatistics.get(mountainBiking) != null);
}
@Test
public void testAggregate_trailRunning() {
// given
// 10km in 40 minutes.
long totalDistance = 10000;
long totalTime = 2400000;
String trailRunning = context.getString(R.string.activity_type_trail_running);
Track track = createTrack(context, totalDistance, totalTime, trailRunning);
// when
AggregatedStatistics aggregatedStatistics = new AggregatedStatistics();
aggregatedStatistics.aggregate(track);
// then
Assert.assertTrue(aggregatedStatistics.get(trailRunning) != null);
}
@Test
public void testAggregate_twoBikingTracks() {
// given
// 10km in 40 minutes.
long totalDistance = 10000;
long totalTime = 2400000;
String biking = context.getString(R.string.activity_type_biking);
Track[] tracks = new Track[2];
for (int i = 0; i < 2; i++) {
tracks[i] = createTrack(context, totalDistance, totalTime, biking);
}
// when
AggregatedStatistics aggregatedStatistics = new AggregatedStatistics();
aggregatedStatistics.aggregate(tracks[0]); // biking activity 1.
aggregatedStatistics.aggregate(tracks[1]); // biking activity 2.
// then
Assert.assertEquals(1, aggregatedStatistics.getCount());
Assert.assertTrue(aggregatedStatistics.get(biking) != null);
Assert.assertEquals(2, aggregatedStatistics.get(biking).getCountTracks());
TrackStatistics statistics2 = aggregatedStatistics.get(biking).getTrackStatistics();
Assert.assertEquals(totalDistance * 2, statistics2.getTotalDistance(), 0);
Assert.assertEquals(totalTime * 2L, statistics2.getMovingTime());
}
@Test
public void testAggregate_threeDifferentTracks() {
// given
// 10km in 40 minutes.
long totalDistance = 10000;
String biking = context.getString(R.string.activity_type_biking);
String running = context.getString(R.string.activity_type_running);
String walking = context.getString(R.string.activity_type_walking);
long totalTime = 2400000;
Track[] tracks = new Track[]{
createTrack(context, totalDistance, totalTime, biking),
createTrack(context, totalDistance, totalTime, running),
createTrack(context, totalDistance, totalTime, walking)
};
// when
AggregatedStatistics aggregatedStatistics = new AggregatedStatistics();
aggregatedStatistics.aggregate(tracks[0]); // biking activity 1.
aggregatedStatistics.aggregate(tracks[1]); // biking activity 2.
aggregatedStatistics.aggregate(tracks[2]); // biking activity 3.
// then
Assert.assertEquals(3, aggregatedStatistics.getCount());
Assert.assertTrue(aggregatedStatistics.get(biking) != null);
Assert.assertTrue(aggregatedStatistics.get(running) != null);
Assert.assertTrue(aggregatedStatistics.get(walking) != null);
Assert.assertEquals(1, aggregatedStatistics.get(biking).getCountTracks());
Assert.assertEquals(1, aggregatedStatistics.get(running).getCountTracks());
Assert.assertEquals(1, aggregatedStatistics.get(walking).getCountTracks());
{
TrackStatistics statistics2 = aggregatedStatistics.get(biking).getTrackStatistics();
Assert.assertEquals(totalDistance, statistics2.getTotalDistance(), 0);
Assert.assertEquals(totalTime, statistics2.getMovingTime());
}
{
TrackStatistics statistics2 = aggregatedStatistics.get(running).getTrackStatistics();
Assert.assertEquals(totalDistance, statistics2.getTotalDistance(), 0);
Assert.assertEquals(totalTime, statistics2.getMovingTime());
}
{
TrackStatistics statistics2 = aggregatedStatistics.get(walking).getTrackStatistics();
Assert.assertEquals(totalDistance, statistics2.getTotalDistance(), 0);
Assert.assertEquals(totalTime, statistics2.getMovingTime());
}
}
@Test
public void testAggregate_severalTracksWithSeveralActivities() {
// given
// 10km in 40 minutes.
long totalDistance = 10000;
long totalTime = 2400000;
String biking = context.getString(R.string.activity_type_biking);
String running = context.getString(R.string.activity_type_running);
String walking = context.getString(R.string.activity_type_walking);
String driving = context.getString(R.string.activity_type_driving);
Track[] tracks = new Track[]{
createTrack(context, totalDistance, totalTime, biking),
createTrack(context, totalDistance, totalTime, running),
createTrack(context, totalDistance, totalTime, walking),
createTrack(context, totalDistance, totalTime, biking),
createTrack(context, totalDistance, totalTime, running),
createTrack(context, totalDistance, totalTime, walking),
createTrack(context, totalDistance, totalTime, biking),
createTrack(context, totalDistance, totalTime, biking),
createTrack(context, totalDistance, totalTime, biking),
createTrack(context, totalDistance, totalTime, driving),
};
// when
AggregatedStatistics aggregatedStatistics = new AggregatedStatistics();
for (Track track : tracks) {
aggregatedStatistics.aggregate(track);
}
// then
// 4 sports.
Assert.assertEquals(4, aggregatedStatistics.getCount());
// There is a map for every sport.
Assert.assertTrue(aggregatedStatistics.get(biking) != null);
Assert.assertTrue(aggregatedStatistics.get(running) != null);
Assert.assertTrue(aggregatedStatistics.get(walking) != null);
Assert.assertTrue(aggregatedStatistics.get(driving) != null);
// Number of tracks by sport.
Assert.assertEquals(5, aggregatedStatistics.get(biking).getCountTracks()); // Biking.
Assert.assertEquals(2, aggregatedStatistics.get(running).getCountTracks()); // Running.
Assert.assertEquals(2, aggregatedStatistics.get(walking).getCountTracks()); // Walking.
Assert.assertEquals(1, aggregatedStatistics.get(driving).getCountTracks()); // Driving.
// Biking.
{
TrackStatistics statistics2 = aggregatedStatistics.get(biking).getTrackStatistics();
Assert.assertEquals(totalDistance * 5, statistics2.getTotalDistance(), 0);
Assert.assertEquals(totalTime * 5, statistics2.getMovingTime());
}
// Running.
{
TrackStatistics statistics2 = aggregatedStatistics.get(running).getTrackStatistics();
Assert.assertEquals(totalDistance * 2, statistics2.getTotalDistance(), 0);
Assert.assertEquals(totalTime * 2, statistics2.getMovingTime());
}
// Walking.
{
TrackStatistics statistics2 = aggregatedStatistics.get(walking).getTrackStatistics();
Assert.assertEquals(totalDistance * 2, statistics2.getTotalDistance(), 0);
Assert.assertEquals(totalTime * 2, statistics2.getMovingTime());
}
// Driving.
{
TrackStatistics statistics2 = aggregatedStatistics.get(driving).getTrackStatistics();
Assert.assertEquals(totalDistance, statistics2.getTotalDistance(), 0);
Assert.assertEquals(totalTime, statistics2.getMovingTime());
}
}
}
+32 -8
View File
@@ -16,7 +16,14 @@ limitations under the License.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.dennisguse.opentracks"
android:installLocation="auto">
<!-- Permission to initialize services -->
<supports-screens
android:anyDensity="true"
android:largeScreens="true"
android:normalScreens="true"
android:smallScreens="true"
android:xlargeScreens="true" />
<application
android:name=".Startup"
android:allowBackup="false"
@@ -79,7 +86,11 @@ limitations under the License.
</activity>
<activity
android:name=".TrackDetailActivity"
android:name=".TrackRecordedActivity"
android:screenOrientation="userPortrait" />
<activity
android:name=".TrackRecordingActivity"
android:screenOrientation="userPortrait" />
<activity android:name=".TrackEditActivity" />
@@ -94,12 +105,30 @@ limitations under the License.
android:value=".SearchListActivity" />
</activity>
<activity
android:name=".AggregatedStatisticsActivity"
android:screenOrientation="userPortrait"
android:label="@string/menu_aggregated_statistics"/>
<activity
android:name=".io.file.exporter.ExportActivity"
android:theme="@style/ThemeCustomTransparent" />
<activity android:name=".settings.SettingsActivity" />
<activity android:name=".ShowOnMapProxyActivity$KMZ">
<intent-filter android:label="@string/open_track_as_KMZ">
<action android:name="Intent.OpenTracks-Dashboard" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity android:name=".ShowOnMapProxyActivity$GPX">
<intent-filter android:label="@string/open_track_as_GPX">
<action android:name="Intent.OpenTracks-Dashboard" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<provider
android:name=".content.provider.ShareContentProvider"
android:authorities="${applicationId}.content"
@@ -124,12 +153,7 @@ limitations under the License.
android:icon="@drawable/ic_logo_color_24dp"
android:label="@string/recording_service" />
</application>
<supports-screens
android:anyDensity="true"
android:largeScreens="true"
android:normalScreens="true"
android:smallScreens="true"
android:xlargeScreens="true" />
<!-- Permissions to record locations -->
<uses-feature
android:name="android.hardware.location.gps"
@@ -2,11 +2,13 @@ package de.dennisguse.opentracks;
import android.os.Bundle;
import android.view.Menu;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.Nullable;
import de.dennisguse.opentracks.util.SystemUtils;
import de.dennisguse.opentracks.util.ViewUtils;
public class AboutActivity extends AbstractActivity {
@@ -27,6 +29,8 @@ public class AboutActivity extends AbstractActivity {
TextView textURL = findViewById(R.id.about_app_url);
textURL.setText(getString(R.string.about_url, getString(R.string.app_web_url)));
ViewUtils.makeClickableLinks((ViewGroup) findViewById(android.R.id.content));
}
protected int getLayoutResId() {
@@ -26,7 +26,7 @@ import de.dennisguse.opentracks.util.PreferencesUtils;
/**
* An abstract class for the following common tasks across
* {@link TrackListActivity}, {@link TrackDetailActivity}, and
* {@link TrackListActivity}, {@link TrackRecordedActivity}, and
* {@link SearchListActivity}:
* <p>
* - share track <br>
@@ -0,0 +1,41 @@
package de.dennisguse.opentracks;
import android.os.Bundle;
import android.widget.ListView;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import de.dennisguse.opentracks.adapters.AggregatedStatisticsAdapter;
import de.dennisguse.opentracks.viewmodels.AggregatedStatistics;
import de.dennisguse.opentracks.viewmodels.AggregatedStatisticsModel;
public class AggregatedStatisticsActivity extends AbstractActivity {
private ListView listView;
private AggregatedStatisticsAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
listView = findViewById(R.id.aggregated_stats_list);
final AggregatedStatisticsModel viewModel = new ViewModelProvider(this).get(AggregatedStatisticsModel.class);
viewModel.getAggregatedStats().observe(this, new Observer<AggregatedStatistics>() {
@Override
public void onChanged(AggregatedStatistics aggregatedStatistics) {
if (aggregatedStatistics != null) {
adapter = new AggregatedStatisticsAdapter(getApplicationContext(), aggregatedStatistics);
listView.setAdapter(adapter);
}
adapter.notifyDataSetChanged();
}
});
}
@Override
protected int getLayoutResId() {
return R.layout.aggregated_stats;
}
}
@@ -1,7 +1,20 @@
package de.dennisguse.opentracks;
import android.os.Bundle;
import android.view.ViewGroup;
import androidx.annotation.Nullable;
import de.dennisguse.opentracks.util.ViewUtils;
public class HelpActivity extends AbstractActivity {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ViewUtils.makeClickableLinks((ViewGroup) findViewById(android.R.id.content));
}
@Override
protected int getLayoutResId() {
return R.layout.help;
@@ -109,12 +109,7 @@ public class MarkerDetailActivity extends AbstractActivity implements DeleteMark
@Override
public void onDeleteMarkerDone() {
runOnUiThread(new Runnable() {
@Override
public void run() {
finish();
}
});
runOnUiThread(this::finish);
}
/**
@@ -82,12 +82,7 @@ public class MarkerListActivity extends AbstractActivity implements DeleteMarker
recordingTrackPaused = PreferencesUtils.isRecordingTrackPaused(MarkerListActivity.this);
}
if (key != null) {
runOnUiThread(new Runnable() {
@Override
public void run() {
MarkerListActivity.this.invalidateOptionsMenu();
}
});
runOnUiThread(() -> MarkerListActivity.this.invalidateOptionsMenu());
}
}
};
@@ -153,12 +153,7 @@ public class SearchListActivity extends AbstractListActivity implements DeleteMa
recordingTrackPaused = PreferencesUtils.isRecordingTrackPaused(SearchListActivity.this);
}
if (key != null) {
runOnUiThread(new Runnable() {
@Override
public void run() {
arrayAdapter.notifyDataSetChanged();
}
});
runOnUiThread(() -> arrayAdapter.notifyDataSetChanged());
}
}
};
@@ -214,11 +209,11 @@ public class SearchListActivity extends AbstractListActivity implements DeleteMa
Map<String, Object> item = arrayAdapter.getItem(position);
Long trackId = (Long) item.get(TRACK_ID_FIELD);
Long markerId = (Long) item.get(MARKER_ID_FIELD);
Intent intent = IntentUtils.newIntent(SearchListActivity.this, TrackDetailActivity.class);
Intent intent = IntentUtils.newIntent(SearchListActivity.this, TrackRecordedActivity.class);
if (markerId != null) {
intent = intent.putExtra(TrackDetailActivity.EXTRA_MARKER_ID, markerId);
intent = intent.putExtra(TrackRecordedActivity.EXTRA_MARKER_ID, markerId);
} else {
intent = intent.putExtra(TrackDetailActivity.EXTRA_TRACK_ID, trackId);
intent = intent.putExtra(TrackRecordedActivity.EXTRA_TRACK_ID, trackId);
}
startActivity(intent);
}
@@ -346,12 +341,9 @@ public class SearchListActivity extends AbstractListActivity implements DeleteMa
final List<Map<String, Object>> displayResults = prepareResultsforDisplay(scoredResults);
// Use the UI thread to display the results
runOnUiThread(new Runnable() {
@Override
public void run() {
arrayAdapter.clear();
arrayAdapter.addAll(displayResults);
}
runOnUiThread(() -> {
arrayAdapter.clear();
arrayAdapter.addAll(displayResults);
});
}
@@ -448,12 +440,7 @@ public class SearchListActivity extends AbstractListActivity implements DeleteMa
@Override
public void onDeleteMarkerDone() {
runOnUiThread(new Runnable() {
@Override
public void run() {
handleIntent(getIntent());
}
});
runOnUiThread(() -> handleIntent(getIntent()));
}
@Override
@@ -463,11 +450,6 @@ public class SearchListActivity extends AbstractListActivity implements DeleteMa
@Override
protected void onDeleted() {
runOnUiThread(new Runnable() {
@Override
public void run() {
handleIntent(getIntent());
}
});
runOnUiThread(() -> handleIntent(getIntent()));
}
}
@@ -0,0 +1,69 @@
package de.dennisguse.opentracks;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Pair;
import androidx.appcompat.app.AppCompatActivity;
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
import de.dennisguse.opentracks.content.provider.ShareContentProvider;
import de.dennisguse.opentracks.io.file.TrackFileFormat;
import de.dennisguse.opentracks.util.IntentDashboardUtils;
/**
* Used to convert IntentDashboardUtils.startDashboard-requests into {@link TrackFileFormat}.
*/
public abstract class ShowOnMapProxyActivity extends AppCompatActivity {
private TrackFileFormat trackFileFormat;
protected ShowOnMapProxyActivity(TrackFileFormat trackFileFormat) {
this.trackFileFormat = trackFileFormat;
}
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
long[] trackIds = IntentDashboardUtils.extractTrackIdsFromIntent(getIntent());
showTrackTrackfileFormat(this, trackFileFormat, trackIds);
finish();
}
/**
* Send intent to show tracks on a map (needs an another app) as KMZ.
*
* @param context the context
* @param trackIds the track ids
*/
private static void showTrackTrackfileFormat(Context context, TrackFileFormat trackFileFormat, long[] trackIds) {
if (trackIds.length == 0) {
return;
}
Intent intent = new Intent(android.content.Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(TrackPointsColumns.TRACKID, trackIds[0]);
Pair<Uri, String> uriAndMime = ShareContentProvider.createURI(trackIds, "SharingTrack", trackFileFormat);
intent.setDataAndType(uriAndMime.first, uriAndMime.second);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
context.startActivity(Intent.createChooser(intent, context.getString(R.string.open_track_as_trackfileformat, trackFileFormat.getExtension())));
}
public static class KMZ extends ShowOnMapProxyActivity {
public KMZ() {
super(TrackFileFormat.KMZ_WITH_TRACKDETAIL);
}
}
public static class GPX extends ShowOnMapProxyActivity {
public GPX() {
super(TrackFileFormat.GPX);
}
}
}
@@ -0,0 +1,10 @@
package de.dennisguse.opentracks;
import de.dennisguse.opentracks.content.TrackDataHub;
/**
* Interface for communication between activities that use {@link de.dennisguse.opentracks.content.TrackDataHub} and their fragments that need thi data hub.
*/
public interface TrackActivityDataHubInterface {
TrackDataHub getTrackDataHub();
}
@@ -56,6 +56,7 @@ import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
import de.dennisguse.opentracks.services.TrackRecordingServiceInterface;
import de.dennisguse.opentracks.settings.SettingsActivity;
import de.dennisguse.opentracks.util.ActivityUtils;
import de.dennisguse.opentracks.util.IntentDashboardUtils;
import de.dennisguse.opentracks.util.IntentUtils;
import de.dennisguse.opentracks.util.ListItemUtils;
import de.dennisguse.opentracks.util.PreferencesUtils;
@@ -143,14 +144,11 @@ public class TrackListActivity extends AbstractListActivity implements ConfirmDe
recordingTrackPaused = PreferencesUtils.isRecordingTrackPaused(TrackListActivity.this);
}
if (key != null) {
runOnUiThread(new Runnable() {
@Override
public void run() {
TrackListActivity.this.invalidateOptionsMenu();
LoaderManager.getInstance(TrackListActivity.this).restartLoader(0, null, loaderCallbacks);
boolean isRecording = PreferencesUtils.isRecording(recordingTrackId);
trackController.update(isRecording, recordingTrackPaused);
}
runOnUiThread(() -> {
TrackListActivity.this.invalidateOptionsMenu();
LoaderManager.getInstance(TrackListActivity.this).restartLoader(0, null, loaderCallbacks);
boolean isRecording = PreferencesUtils.isRecording(recordingTrackId);
trackController.update(isRecording, recordingTrackPaused);
});
}
}
@@ -174,15 +172,8 @@ public class TrackListActivity extends AbstractListActivity implements ConfirmDe
private final Runnable bindChangedCallback = new Runnable() {
@Override
public void run() {
/*
* After binding changes (e.g., becomes available), update the total time in trackController.
*/
runOnUiThread(new Runnable() {
@Override
public void run() {
trackController.update(PreferencesUtils.isRecording(recordingTrackId), recordingTrackPaused);
}
});
// After binding changes (e.g., becomes available), update the total time in trackController.
runOnUiThread(() -> trackController.update(PreferencesUtils.isRecording(recordingTrackId), recordingTrackPaused));
if (!startGps) {
return;
@@ -205,8 +196,7 @@ public class TrackListActivity extends AbstractListActivity implements ConfirmDe
if (!PreferencesUtils.isRecording(recordingTrackId)) {
// Not recording -> Recording
updateMenuItems(false, true);
Intent newIntent = IntentUtils.newIntent(TrackListActivity.this, TrackDetailActivity.class)
.putExtra(TrackDetailActivity.EXTRA_RECORDING_REQUEST, true);
Intent newIntent = IntentUtils.newIntent(TrackListActivity.this, TrackRecordingActivity.class);
startActivity(newIntent);
} else if (recordingTrackPaused) {
// Paused -> Resume
@@ -251,9 +241,17 @@ public class TrackListActivity extends AbstractListActivity implements ConfirmDe
listView.setEmptyView(findViewById(R.id.track_list_empty_view));
listView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent newIntent = IntentUtils.newIntent(TrackListActivity.this, TrackDetailActivity.class)
.putExtra(TrackDetailActivity.EXTRA_TRACK_ID, id);
public void onItemClick(AdapterView<?> parent, View view, int position, long trackId) {
Intent newIntent;
if (trackId == recordingTrackId) {
// Is recording -> open record activity.
newIntent = IntentUtils.newIntent(TrackListActivity.this, TrackRecordingActivity.class)
.putExtra(TrackRecordedActivity.EXTRA_TRACK_ID, trackId);
} else {
// Not recording -> open detail activity.
newIntent = IntentUtils.newIntent(TrackListActivity.this, TrackRecordedActivity.class)
.putExtra(TrackRecordedActivity.EXTRA_TRACK_ID, trackId);
}
startActivity(newIntent);
}
});
@@ -397,6 +395,10 @@ public class TrackListActivity extends AbstractListActivity implements ConfirmDe
this.invalidateOptionsMenu();
}
return true;
case R.id.track_list_aggregated_stats:
intent = IntentUtils.newIntent(this, AggregatedStatisticsActivity.class);
startActivity(intent);
return true;
case R.id.track_list_markers:
intent = IntentUtils.newIntent(this, MarkerListActivity.class);
startActivity(intent);
@@ -480,7 +482,7 @@ public class TrackListActivity extends AbstractListActivity implements ConfirmDe
Intent intent;
switch (itemId) {
case R.id.list_context_menu_show_on_map:
IntentUtils.showTrackOnMap(this, trackIds);
IntentDashboardUtils.startDashboard(this, trackIds);
return true;
case R.id.list_context_menu_share:
intent = IntentUtils.newShareFileIntent(this, trackIds);
@@ -0,0 +1,270 @@
/*
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package de.dennisguse.opentracks;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.viewpager.widget.ViewPager;
import com.google.android.material.tabs.TabLayout;
import de.dennisguse.opentracks.content.TrackDataHub;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.data.Waypoint;
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
import de.dennisguse.opentracks.fragments.ChartFragment;
import de.dennisguse.opentracks.fragments.ChooseActivityTypeDialogFragment;
import de.dennisguse.opentracks.fragments.ConfirmDeleteDialogFragment;
import de.dennisguse.opentracks.fragments.StatisticsRecordedFragment;
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
import de.dennisguse.opentracks.settings.SettingsActivity;
import de.dennisguse.opentracks.util.IntentDashboardUtils;
import de.dennisguse.opentracks.util.IntentUtils;
import de.dennisguse.opentracks.util.PreferencesUtils;
import de.dennisguse.opentracks.util.TrackIconUtils;
import de.dennisguse.opentracks.util.TrackUtils;
/**
* An activity to show the track detail, record a new track or resumes an existing one.
*
* @author Leif Hendrik Wilden
* @author Rodrigo Damazio
*/
public class TrackRecordedActivity extends AbstractListActivity implements ChooseActivityTypeDialogFragment.ChooseActivityTypeCaller, ConfirmDeleteDialogFragment.ConfirmDeleteCaller, TrackActivityDataHubInterface {
public static final String EXTRA_TRACK_ID = "track_id";
public static final String EXTRA_MARKER_ID = "marker_id";
private static final String TAG = TrackRecordedActivity.class.getSimpleName();
private static final String CURRENT_TAB_TAG_KEY = "current_tab_tag_key";
// The following are set in onCreate.
private ContentProviderUtils contentProviderUtils;
private TrackDataHub trackDataHub;
private ViewPager pager;
// From intent.
private long trackId;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
contentProviderUtils = new ContentProviderUtils(this);
handleIntent(getIntent());
trackDataHub = new TrackDataHub(this);
FragmentPagerAdapter adapter = new FragmentPagerAdapter(getSupportFragmentManager(), 1) {
@Override
public int getCount() {
return 3;
}
@NonNull
@Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new StatisticsRecordedFragment();
case 1:
return ChartFragment.newInstance(false);
case 2:
return ChartFragment.newInstance(true);
default:
throw new RuntimeException("There isn't Fragment associated with the position: " + position);
}
}
@Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return getString(R.string.track_detail_stats_tab);
case 1:
return getString(R.string.settings_chart_by_time);
case 2:
return getString(R.string.settings_chart_by_distance);
}
return "Unknown Tab";
}
};
pager = findViewById(R.id.track_detail_activity_view_pager);
pager.setAdapter(adapter);
TabLayout tabs = findViewById(R.id.track_detail_activity_tablayout);
tabs.setupWithViewPager(pager);
if (savedInstanceState != null) {
pager.setCurrentItem(savedInstanceState.getInt(CURRENT_TAB_TAG_KEY));
}
}
@Override
protected void onStart() {
super.onStart();
trackDataHub.start();
}
@Override
protected void onResume() {
super.onResume();
// Update UI
this.invalidateOptionsMenu();
if (trackId != -1L) {
trackDataHub.loadTrack(trackId);
}
}
@Override
protected void onStop() {
super.onStop();
trackDataHub.stop();
}
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(CURRENT_TAB_TAG_KEY, pager.getCurrentItem());
}
@Override
protected int getLayoutResId() {
return R.layout.track_detail;
}
@Override
public void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
handleIntent(intent);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.track_detail, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
menu.findItem(R.id.track_detail_markers).setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
menu.findItem(R.id.track_detail_resume_track).setVisible(!PreferencesUtils.isRecording(this));
Track track = contentProviderUtils.getTrack(trackId);
setTitle(track != null ? track.getName() : "");
return super.onPrepareOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
Intent intent;
switch (item.getItemId()) {
case R.id.track_detail_share:
intent = IntentUtils.newShareFileIntent(this, new long[]{trackId});
intent = Intent.createChooser(intent, null);
startActivity(intent);
return true;
case R.id.track_detail_menu_show_on_map:
IntentDashboardUtils.startDashboard(this, trackId);
return true;
case R.id.track_detail_markers:
intent = IntentUtils.newIntent(this, MarkerListActivity.class)
.putExtra(MarkerListActivity.EXTRA_TRACK_ID, trackId);
startActivity(intent);
return true;
case R.id.track_detail_edit:
intent = IntentUtils.newIntent(this, TrackEditActivity.class)
.putExtra(TrackEditActivity.EXTRA_TRACK_ID, trackId);
startActivity(intent);
return true;
case R.id.track_detail_delete:
deleteTracks(new long[]{trackId});
return true;
case R.id.track_detail_resume_track:
Intent newIntent = IntentUtils.newIntent(TrackRecordedActivity.this, TrackRecordingActivity.class)
.putExtra(TrackRecordingActivity.EXTRA_TRACK_ID, trackId);
startActivity(newIntent);
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
finish();
return true;
case R.id.track_detail_settings:
intent = IntentUtils.newIntent(this, SettingsActivity.class);
startActivity(intent);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
protected TrackRecordingServiceConnection getTrackRecordingServiceConnection() {
// Not needed.
return null;
}
@Override
protected void onDeleted() {
runOnUiThread(this::finish);
}
/**
* Gets the {@link TrackDataHub}.
*/
@Override
public TrackDataHub getTrackDataHub() {
return trackDataHub;
}
private void handleIntent(Intent intent) {
trackId = intent.getLongExtra(EXTRA_TRACK_ID, -1L);
long markerId = intent.getLongExtra(EXTRA_MARKER_ID, -1L);
if (markerId != -1L) {
// Use the trackId from the marker
Waypoint waypoint = contentProviderUtils.getWaypoint(markerId);
if (waypoint == null) {
finish();
return;
}
trackId = waypoint.getTrackId();
}
if (trackId == -1L) {
Log.e(TAG, "TrackDetailActivity needs EXTRA_TRACK_ID.");
finish();
}
}
public void chooseActivityType(String category) {
ChooseActivityTypeDialogFragment.showDialog(getSupportFragmentManager(), category);
}
@Override
public void onChooseActivityTypeDone(String iconValue) {
Track track = contentProviderUtils.getTrack(trackId);
String category = getString(TrackIconUtils.getIconActivityType(iconValue));
TrackUtils.updateTrack(this, track, null, category, null, contentProviderUtils);
}
}
@@ -1,19 +1,3 @@
/*
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package de.dennisguse.opentracks;
import android.content.Intent;
@@ -38,15 +22,14 @@ import com.google.android.material.tabs.TabLayout;
import de.dennisguse.opentracks.content.TrackDataHub;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.data.Waypoint;
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
import de.dennisguse.opentracks.fragments.ChartFragment;
import de.dennisguse.opentracks.fragments.ChooseActivityTypeDialogFragment;
import de.dennisguse.opentracks.fragments.ConfirmDeleteDialogFragment;
import de.dennisguse.opentracks.fragments.StatsFragment;
import de.dennisguse.opentracks.fragments.StatisticsRecordingFragment;
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
import de.dennisguse.opentracks.services.TrackRecordingServiceInterface;
import de.dennisguse.opentracks.settings.SettingsActivity;
import de.dennisguse.opentracks.util.IntentDashboardUtils;
import de.dennisguse.opentracks.util.IntentUtils;
import de.dennisguse.opentracks.util.PreferencesUtils;
import de.dennisguse.opentracks.util.TrackIconUtils;
@@ -58,13 +41,11 @@ import de.dennisguse.opentracks.util.TrackUtils;
* @author Leif Hendrik Wilden
* @author Rodrigo Damazio
*/
public class TrackDetailActivity extends AbstractListActivity implements ChooseActivityTypeDialogFragment.ChooseActivityTypeCaller, ConfirmDeleteDialogFragment.ConfirmDeleteCaller {
public class TrackRecordingActivity extends AbstractActivity implements ChooseActivityTypeDialogFragment.ChooseActivityTypeCaller, TrackActivityDataHubInterface {
public static final String EXTRA_TRACK_ID = "track_id";
public static final String EXTRA_MARKER_ID = "marker_id";
public static final String EXTRA_RECORDING_REQUEST = "request_recording";
private static final String TAG = TrackDetailActivity.class.getSimpleName();
private static final String TAG = TrackRecordingActivity.class.getSimpleName();
private static final String CURRENT_TAB_TAG_KEY = "current_tab_tag_key";
@@ -79,8 +60,6 @@ public class TrackDetailActivity extends AbstractListActivity implements ChooseA
// From intent
private long trackId;
private boolean isRecordingRequest = false;
// Preferences
private long recordingTrackId = PreferencesUtils.RECORDING_TRACK_ID_DEFAULT;
private boolean recordingTrackPaused;
@@ -89,12 +68,7 @@ public class TrackDetailActivity extends AbstractListActivity implements ChooseA
@Override
public void run() {
// After binding changes (is available), update the total time in trackController.
runOnUiThread(new Runnable() {
@Override
public void run() {
trackController.update(isRecording(), recordingTrackPaused);
}
});
runOnUiThread(() -> trackController.update(true, recordingTrackPaused));
if (recordingTrackId == -1L) {
TrackRecordingServiceInterface service = trackRecordingServiceConnection.getServiceIfBound();
@@ -102,9 +76,6 @@ public class TrackDetailActivity extends AbstractListActivity implements ChooseA
Log.d(TAG, "could not get TrackRecordingService");
return;
}
if (!isRecordingRequest) {
return;
}
// Starts or resumes a track.
int msg;
@@ -121,12 +92,10 @@ public class TrackDetailActivity extends AbstractListActivity implements ChooseA
}
// A recording track is on.
Toast.makeText(TrackDetailActivity.this, msg, Toast.LENGTH_SHORT).show();
Toast.makeText(TrackRecordingActivity.this, msg, Toast.LENGTH_SHORT).show();
trackDataHub.loadTrack(trackId);
trackController.update(true, false);
trackController.onResume(true, recordingTrackPaused);
isRecordingRequest = false;
}
}
};
@@ -134,43 +103,37 @@ public class TrackDetailActivity extends AbstractListActivity implements ChooseA
private final OnSharedPreferenceChangeListener sharedPreferenceChangeListener = new OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
if (PreferencesUtils.isKey(TrackDetailActivity.this, R.string.recording_track_id_key, key)) {
recordingTrackId = PreferencesUtils.getRecordingTrackId(TrackDetailActivity.this);
if (PreferencesUtils.isKey(TrackRecordingActivity.this, R.string.recording_track_id_key, key)) {
recordingTrackId = PreferencesUtils.getRecordingTrackId(TrackRecordingActivity.this);
setLockscreenPolicy();
setScreenOnPolicy();
}
if (PreferencesUtils.isKey(TrackDetailActivity.this, R.string.recording_track_paused_key, key)) {
recordingTrackPaused = PreferencesUtils.isRecordingTrackPaused(TrackDetailActivity.this);
if (PreferencesUtils.isKey(TrackRecordingActivity.this, R.string.recording_track_paused_key, key)) {
recordingTrackPaused = PreferencesUtils.isRecordingTrackPaused(TrackRecordingActivity.this);
setLockscreenPolicy();
setScreenOnPolicy();
}
if (PreferencesUtils.isKey(TrackDetailActivity.this, R.string.stats_show_on_lockscreen_while_recording_key, key)) {
if (PreferencesUtils.isKey(TrackRecordingActivity.this, R.string.stats_show_on_lockscreen_while_recording_key, key)) {
setLockscreenPolicy();
}
if (PreferencesUtils.isKey(TrackDetailActivity.this, R.string.stats_keep_screen_on_while_recording_key, key)) {
if (PreferencesUtils.isKey(TrackRecordingActivity.this, R.string.stats_keep_screen_on_while_recording_key, key)) {
setScreenOnPolicy();
}
if (key == null) return;
runOnUiThread(new Runnable() {
@Override
public void run() {
TrackDetailActivity.this.invalidateOptionsMenu();
boolean isRecording = isRecording();
trackController.update(isRecording, recordingTrackPaused);
}
runOnUiThread(() -> {
TrackRecordingActivity.this.invalidateOptionsMenu();
trackController.update(true, recordingTrackPaused);
});
}
};
private MenuItem insertMarkerMenuItem;
private MenuItem markerListMenuItem;
private MenuItem shareMenuItem;
private MenuItem resumeMenuItem;
private final OnClickListener recordListener = new OnClickListener() {
@Override
@@ -192,8 +155,13 @@ public class TrackDetailActivity extends AbstractListActivity implements ChooseA
private final OnClickListener stopListener = new OnClickListener() {
@Override
public void onClick(View v) {
trackRecordingServiceConnection.stopRecording(TrackDetailActivity.this, true);
trackRecordingServiceConnection.stopRecording(TrackRecordingActivity.this, true);
Intent newIntent = IntentUtils.newIntent(TrackRecordingActivity.this, TrackRecordedActivity.class)
.putExtra(TrackRecordedActivity.EXTRA_TRACK_ID, trackId);
startActivity(newIntent);
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
updateMenuItems(true);
finish();
}
};
@@ -220,12 +188,14 @@ public class TrackDetailActivity extends AbstractListActivity implements ChooseA
@Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new StatisticsRecordingFragment();
case 1:
return ChartFragment.newInstance(false);
case 2:
return ChartFragment.newInstance(true);
default: //0
return new StatsFragment();
default:
throw new RuntimeException("There isn't Fragment associated with the position: " + position);
}
}
@@ -261,7 +231,7 @@ public class TrackDetailActivity extends AbstractListActivity implements ChooseA
}
private void setLockscreenPolicy() {
boolean showOnLockScreen = PreferencesUtils.shouldShowStatsOnLockscreen(TrackDetailActivity.this)
boolean showOnLockScreen = PreferencesUtils.shouldShowStatsOnLockscreen(TrackRecordingActivity.this)
&& PreferencesUtils.isRecording(this);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
@@ -274,7 +244,7 @@ public class TrackDetailActivity extends AbstractListActivity implements ChooseA
}
private void setScreenOnPolicy() {
boolean keepScreenOn = PreferencesUtils.shouldKeepScreenOn(TrackDetailActivity.this)
boolean keepScreenOn = PreferencesUtils.shouldKeepScreenOn(TrackRecordingActivity.this)
&& PreferencesUtils.isRecording(this);
if (keepScreenOn) {
@@ -304,10 +274,10 @@ public class TrackDetailActivity extends AbstractListActivity implements ChooseA
if (trackId != -1L) {
trackDataHub.loadTrack(trackId);
trackController.onResume(isRecording(), recordingTrackPaused);
} else {
startRecording();
trackController.onResume(true, recordingTrackPaused);
}
startRecording();
}
@Override
@@ -332,7 +302,7 @@ public class TrackDetailActivity extends AbstractListActivity implements ChooseA
@Override
protected int getLayoutResId() {
return R.layout.track_detail;
return R.layout.track_record;
}
@Override
@@ -344,12 +314,10 @@ public class TrackDetailActivity extends AbstractListActivity implements ChooseA
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.track_detail, menu);
getMenuInflater().inflate(R.menu.track_record, menu);
insertMarkerMenuItem = menu.findItem(R.id.track_detail_insert_marker);
shareMenuItem = menu.findItem(R.id.track_detail_share);
markerListMenuItem = menu.findItem(R.id.track_detail_markers);
resumeMenuItem = menu.findItem(R.id.track_detail_resume_track);
return super.onCreateOptionsMenu(menu);
}
@@ -370,13 +338,8 @@ public class TrackDetailActivity extends AbstractListActivity implements ChooseA
.putExtra(MarkerEditActivity.EXTRA_TRACK_ID, trackId);
startActivity(intent);
return true;
case R.id.track_detail_share:
intent = IntentUtils.newShareFileIntent(this, new long[]{trackId});
intent = Intent.createChooser(intent, null);
startActivity(intent);
return true;
case R.id.track_detail_menu_show_on_map:
IntentUtils.showTrackOnMap(this, new long[]{trackId});
IntentDashboardUtils.startDashboard(this, trackId);
return true;
case R.id.track_detail_markers:
intent = IntentUtils.newIntent(this, MarkerListActivity.class)
@@ -388,13 +351,6 @@ public class TrackDetailActivity extends AbstractListActivity implements ChooseA
.putExtra(TrackEditActivity.EXTRA_TRACK_ID, trackId);
startActivity(intent);
return true;
case R.id.track_detail_delete:
deleteTracks(new long[]{trackId});
return true;
case R.id.track_detail_resume_track:
isRecordingRequest = true;
startRecording();
return true;
case R.id.track_detail_settings:
intent = IntentUtils.newIntent(this, SettingsActivity.class);
startActivity(intent);
@@ -404,58 +360,25 @@ public class TrackDetailActivity extends AbstractListActivity implements ChooseA
}
}
@Override
protected TrackRecordingServiceConnection getTrackRecordingServiceConnection() {
return trackRecordingServiceConnection;
}
@Override
protected void onDeleted() {
runOnUiThread(new Runnable() {
@Override
public void run() {
finish();
}
});
}
/**
* Gets the {@link TrackDataHub}.
*/
@Override
public TrackDataHub getTrackDataHub() {
return trackDataHub;
}
private void handleIntent(Intent intent) {
trackId = intent.getLongExtra(EXTRA_TRACK_ID, -1L);
isRecordingRequest = intent.getBooleanExtra(EXTRA_RECORDING_REQUEST, false);
long markerId = intent.getLongExtra(EXTRA_MARKER_ID, -1L);
if (markerId != -1L) {
// Use the trackId from the marker
Waypoint waypoint = contentProviderUtils.getWaypoint(markerId);
if (waypoint == null) {
finish();
return;
}
trackId = waypoint.getTrackId();
if (trackId == -1L) {
finish();
return;
}
}
if (trackId == -1L) {
return;
}
Track track = contentProviderUtils.getTrack(trackId);
if (track == null) {
// Use the last track if markerId is not set
if (markerId == -1L) {
track = contentProviderUtils.getLastTrack();
if (track != null) {
trackId = track.getId();
return;
}
track = contentProviderUtils.getLastTrack();
if (track != null) {
trackId = track.getId();
return;
}
finish();
}
@@ -465,20 +388,9 @@ public class TrackDetailActivity extends AbstractListActivity implements ChooseA
* Updates the menu items.
*/
private void updateMenuItems(boolean isPaused) {
insertMarkerMenuItem.setVisible(isRecording() && !isPaused);
shareMenuItem.setVisible(!isRecording());
markerListMenuItem.setShowAsAction(isRecording() ? MenuItem.SHOW_AS_ACTION_NEVER : MenuItem.SHOW_AS_ACTION_IF_ROOM);
String title;
if (isRecording()) {
title = getString(isPaused ? R.string.generic_paused : R.string.generic_recording);
resumeMenuItem.setVisible(false);
} else {
Track track = contentProviderUtils.getTrack(trackId);
title = track != null ? track.getName() : "";
// Only visible if there aren't other tracks that is recording.
resumeMenuItem.setVisible(recordingTrackId == -1L);
}
setTitle(title);
insertMarkerMenuItem.setVisible(!isPaused);
markerListMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
setTitle(getString(isPaused ? R.string.generic_paused : R.string.generic_recording));
}
public void chooseActivityType(String category) {
@@ -492,10 +404,6 @@ public class TrackDetailActivity extends AbstractListActivity implements ChooseA
TrackUtils.updateTrack(this, track, null, category, null, contentProviderUtils);
}
private boolean isRecording() {
return trackId == recordingTrackId;
}
private void startRecording() {
trackRecordingServiceConnection.startAndBind(this);
@@ -0,0 +1,181 @@
package de.dennisguse.opentracks.adapters;
import android.content.Context;
import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.util.PreferencesUtils;
import de.dennisguse.opentracks.util.StringUtils;
import de.dennisguse.opentracks.util.TrackIconUtils;
import de.dennisguse.opentracks.viewmodels.AggregatedStatistics;
public class AggregatedStatisticsAdapter extends BaseAdapter {
private AggregatedStatistics aggregatedStatistics;
private Context context;
public AggregatedStatisticsAdapter(Context context, AggregatedStatistics aggregatedStatistics) {
this.context = context;
this.aggregatedStatistics = aggregatedStatistics;
}
@Override
public int getCount() {
if (aggregatedStatistics != null) {
return aggregatedStatistics.getCount();
}
return 0;
}
@Override
public AggregatedStatistics.AggregatedStatistic getItem(int position) {
return aggregatedStatistics.getItem(position);
}
@Override
public long getItemId(int position) {
// Not important because data are not database register but cooked data.
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
AggregatedStatistics.AggregatedStatistic aggregatedStats = getItem(position);
ViewHolder viewHolder;
if (isSpeedSport(position)) {
viewHolder = new ViewSpeedHolder();
} else {
viewHolder = new ViewPaceHolder();
}
convertView = LayoutInflater.from(context).inflate(R.layout.aggregated_stats_list_item, parent, false);
viewHolder.setValues(convertView, getIcon(position), getName(position), aggregatedStats);
return convertView;
}
private boolean isSpeedSport(int position) {
String category = aggregatedStatistics.getSportName(position);
return TrackIconUtils.isSpeedIcon(context, category);
}
private int getIcon(int position) {
String iconValue = TrackIconUtils.getIconValue(context, aggregatedStatistics.getSportName(position));
return TrackIconUtils.getIconDrawable(iconValue);
}
private String getName(int position) {
return aggregatedStatistics.getSportName(position);
}
private class ViewHolder {
protected ImageView sportIcon;
protected TextView typeLabel;
protected TextView numTracks;
protected TextView distance;
protected TextView distanceUnit;
protected TextView time;
protected boolean metricsUnits;
public ViewHolder() {
metricsUnits = PreferencesUtils.isMetricUnits(context);
}
public void setValues(View view, int iconDrawable, String name, AggregatedStatistics.AggregatedStatistic aggregatedStats) {
sportIcon = view.findViewById(R.id.aggregated_stats_sport_icon);
typeLabel = view.findViewById(R.id.aggregated_stats_type_label);
numTracks = view.findViewById(R.id.aggregated_stats_num_tracks);
distance = view.findViewById(R.id.aggregated_stats_distance);
distanceUnit = view.findViewById(R.id.aggregated_stats_distance_unit);
time = view.findViewById(R.id.aggregated_stats_time);
sportIcon.setImageResource(iconDrawable);
typeLabel.setText(name);
numTracks.setText(StringUtils.valueInParentheses(String.valueOf(aggregatedStats.getCountTracks())));
Pair<String, String> parts = StringUtils.getDistanceParts(context, aggregatedStats.getTrackStatistics().getTotalDistance(), metricsUnits);
distance.setText(parts.first);
distanceUnit.setText(parts.second);
time.setText(StringUtils.formatElapsedTime(aggregatedStats.getTrackStatistics().getMovingTime()));
}
}
private class ViewSpeedHolder extends ViewHolder {
private TextView avgSpeed;
private TextView avgSpeedUnit;
private TextView avgSpeedLabel;
private TextView maxSpeed;
private TextView maxSpeedUnit;
private TextView maxSpeedLabel;
@Override
public void setValues(View view, int iconDrawable, String name, AggregatedStatistics.AggregatedStatistic aggregatedStats) {
super.setValues(view, iconDrawable, name, aggregatedStats);
avgSpeed = view.findViewById(R.id.aggregated_stats_avg_rate);
avgSpeedUnit = view.findViewById(R.id.aggregated_stats_avg_rate_unit);
avgSpeedLabel = view.findViewById(R.id.aggregated_stats_avg_rate_label);
maxSpeed = view.findViewById(R.id.aggregated_stats_max_rate);
maxSpeedUnit = view.findViewById(R.id.aggregated_stats_max_rate_unit);
maxSpeedLabel = view.findViewById(R.id.aggregated_stats_max_rate_label);
{
Pair<String, String> parts = StringUtils.getSpeedParts(context, aggregatedStats.getTrackStatistics().getAverageMovingSpeed(), metricsUnits, true);
avgSpeed.setText(parts.first);
avgSpeedUnit.setText(parts.second);
avgSpeedLabel.setText(context.getString(R.string.stats_average_moving_speed));
}
{
Pair<String, String> parts = StringUtils.getSpeedParts(context, aggregatedStats.getTrackStatistics().getMaxSpeed(), metricsUnits, true);
maxSpeed.setText(parts.first);
maxSpeedUnit.setText(parts.second);
maxSpeedLabel.setText(context.getString(R.string.stats_max_speed));
}
}
}
private class ViewPaceHolder extends ViewHolder {
private TextView avgPace;
private TextView avgPaceUnit;
private TextView avgPaceLabel;
private TextView maxPace;
private TextView maxPaceUnit;
private TextView maxPaceLabel;
@Override
public void setValues(View view, int iconDrawable, String name, AggregatedStatistics.AggregatedStatistic aggregatedStats) {
super.setValues(view, iconDrawable, name, aggregatedStats);
avgPace = view.findViewById(R.id.aggregated_stats_avg_rate);
avgPaceUnit = view.findViewById(R.id.aggregated_stats_avg_rate_unit);
avgPaceLabel = view.findViewById(R.id.aggregated_stats_avg_rate_label);
maxPace = view.findViewById(R.id.aggregated_stats_max_rate);
maxPaceUnit = view.findViewById(R.id.aggregated_stats_max_rate_unit);
maxPaceLabel = view.findViewById(R.id.aggregated_stats_max_rate_label);
{
Pair<String, String> parts = StringUtils.getSpeedParts(context, aggregatedStats.getTrackStatistics().getAverageMovingSpeed(), metricsUnits, false);
avgPace.setText(parts.first);
avgPaceUnit.setText(parts.second);
avgPaceLabel.setText(R.string.stats_average_moving_pace);
}
{
Pair<String, String> parts = StringUtils.getSpeedParts(context, aggregatedStats.getTrackStatistics().getMaxSpeed(), metricsUnits, false);
maxPace.setText(parts.first);
maxPaceUnit.setText(parts.second);
maxPaceLabel.setText(R.string.stats_fastest_pace);
}
}
}
}
@@ -144,12 +144,9 @@ public class TrackDataHub implements SharedPreferences.OnSharedPreferenceChangeL
PreferencesUtils.register(context, this);
onSharedPreferenceChanged(null, null);
runInHandlerThread(new Runnable() {
@Override
public void run() {
if (started) {
loadDataForAll();
}
runInHandlerThread(() -> {
if (started) {
loadDataForAll();
}
});
}
@@ -178,16 +175,13 @@ public class TrackDataHub implements SharedPreferences.OnSharedPreferenceChangeL
}
public void loadTrack(final long trackId) {
runInHandlerThread(new Runnable() {
@Override
public void run() {
if (trackId == selectedTrackId) {
Log.i(TAG, "Not reloading track " + trackId);
return;
}
selectedTrackId = trackId;
loadDataForAll();
runInHandlerThread(() -> {
if (trackId == selectedTrackId) {
Log.i(TAG, "Not reloading track " + trackId);
return;
}
selectedTrackId = trackId;
loadDataForAll();
});
}
@@ -197,13 +191,10 @@ public class TrackDataHub implements SharedPreferences.OnSharedPreferenceChangeL
* @param trackDataListener the track data listener
*/
public void registerTrackDataListener(final TrackDataListener trackDataListener, final boolean tracksTable, final boolean waypointsTable, final boolean trackPointsTable_SampleIn, final boolean trackPointsTable_SampleOut) {
runInHandlerThread(new Runnable() {
@Override
public void run() {
trackDataManager.registerTrackDataListener(trackDataListener, tracksTable, waypointsTable, trackPointsTable_SampleIn, trackPointsTable_SampleOut);
if (started) {
loadDataForListener(trackDataListener);
}
runInHandlerThread(() -> {
trackDataManager.registerTrackDataListener(trackDataListener, tracksTable, waypointsTable, trackPointsTable_SampleIn, trackPointsTable_SampleOut);
if (started) {
loadDataForListener(trackDataListener);
}
});
}
@@ -214,12 +205,7 @@ public class TrackDataHub implements SharedPreferences.OnSharedPreferenceChangeL
* @param trackDataListener the track data listener
*/
public void unregisterTrackDataListener(final TrackDataListener trackDataListener) {
runInHandlerThread(new Runnable() {
@Override
public void run() {
trackDataManager.unregisterTrackDataListener(trackDataListener);
}
});
runInHandlerThread(() -> trackDataManager.unregisterTrackDataListener(trackDataListener));
}
/**
@@ -238,15 +224,12 @@ public class TrackDataHub implements SharedPreferences.OnSharedPreferenceChangeL
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, final String key) {
runInHandlerThread(new Runnable() {
@Override
public void run() {
if (PreferencesUtils.isKey(context, R.string.recording_track_id_key, key)) {
recordingTrackId = PreferencesUtils.getRecordingTrackId(context);
}
if (PreferencesUtils.isKey(context, R.string.recording_track_paused_key, key)) {
recordingTrackPaused = PreferencesUtils.isRecordingTrackPaused(context);
}
runInHandlerThread(() -> {
if (PreferencesUtils.isKey(context, R.string.recording_track_id_key, key)) {
recordingTrackId = PreferencesUtils.getRecordingTrackId(context);
}
if (PreferencesUtils.isKey(context, R.string.recording_track_paused_key, key)) {
recordingTrackPaused = PreferencesUtils.isRecordingTrackPaused(context);
}
});
}
@@ -289,7 +272,7 @@ public class TrackDataHub implements SharedPreferences.OnSharedPreferenceChangeL
if (isOnlyListener) {
resetSamplingState();
}
Set<TrackDataListener> sampledOutListeners = hasSampledOut ? trackDataListeners : Collections.<TrackDataListener>emptySet();
Set<TrackDataListener> sampledOutListeners = hasSampledOut ? trackDataListeners : Collections.emptySet();
notifyTrackPointsTableUpdate(isOnlyListener, trackDataListeners, sampledOutListeners);
}
@@ -910,5 +910,4 @@ public class ContentProviderUtils {
public static String[] parseTrackIdsFromUri(Uri url) {
return TextUtils.split(url.getLastPathSegment(), ID_SEPARATOR);
}
}
@@ -92,7 +92,7 @@ public class ShareContentProvider extends CustomContentProvider implements ICont
static long[] parseURI(Uri uri) {
List<String> uriPaths = uri.getPathSegments();
if (uriPaths == null || uriPaths.size() < 2) {
if (uriPaths == null || uriPaths.size() < 3) {
Log.d(TAG, "URI does not contain any trackIds.");
return new long[]{};
}
@@ -209,7 +209,7 @@ public class ShareContentProvider extends CustomContentProvider implements ICont
tracks[i] = contentProviderUtils.getTrack(trackIds[i]);
}
final TrackExporter trackExporter = getTrackFileFormat(uri).newTrackExporter(getContext(), tracks, null);
final TrackExporter trackExporter = getTrackFileFormat(uri).newTrackExporter(getContext(), tracks);
PipeDataWriter pipeDataWriter = new PipeDataWriter<String>() {
@Override
@@ -64,13 +64,13 @@ public final class SensorDataCycling {
public void compute(Cadence previous) {
if (hasData() && previous != null && previous.hasData()) {
long timeDiff_ms = UintUtils.diff(crankRevolutionsTime, previous.crankRevolutionsTime, UintUtils.UINT16_MAX) / 1024 * UnitConversions.S_TO_MS;
float timeDiff_ms = UintUtils.diff(crankRevolutionsTime, previous.crankRevolutionsTime, UintUtils.UINT16_MAX) / 1024f * UnitConversions.S_TO_MS;
if (timeDiff_ms <= 0) {
Log.e(TAG, "Timestamps difference is invalid: cannot compute cadence.");
cadence_rpm = INVALID_VALUE_FLOAT;
} else {
long crankDiff = UintUtils.diff(crankRevolutionsCount, previous.crankRevolutionsCount, UintUtils.UINT32_MAX);
float cadence_ms = crankDiff / (float) timeDiff_ms;
float cadence_ms = crankDiff / timeDiff_ms;
cadence_rpm = (float) (cadence_ms / UnitConversions.MS_TO_S / UnitConversions.S_TO_MIN);
}
}
@@ -79,7 +79,7 @@ public final class SensorDataCycling {
@NonNull
@Override
public String toString() {
return "cadence=" + getCadence_rpm() + "_" + getCrankRevolutionsTime();
return "cadence=" + getCadence_rpm() + " time=" + getCrankRevolutionsTime() + " count=" + getCrankRevolutionsCount();
}
@Override
@@ -125,7 +125,7 @@ public final class SensorDataCycling {
public void compute(Speed previous, int wheel_circumference_mm) {
if (hasData() && previous != null && previous.hasData()) {
long timeDiff_ms = UintUtils.diff(wheelRevolutionsTime, previous.wheelRevolutionsTime, UintUtils.UINT16_MAX) / 1024 * UnitConversions.S_TO_MS;
float timeDiff_ms = UintUtils.diff(wheelRevolutionsTime, previous.wheelRevolutionsTime, UintUtils.UINT16_MAX) / 1024f * UnitConversions.S_TO_MS;
if (timeDiff_ms <= 0) {
Log.e(TAG, "Timestamps difference is invalid: cannot compute cadence.");
speed_mps = INVALID_VALUE_FLOAT;
@@ -140,7 +140,7 @@ public final class SensorDataCycling {
@NonNull
@Override
public String toString() {
return "speed=" + getSpeed_mps() + "_" + getWheelRevolutionsTime();
return "speed=" + getSpeed_mps() + " time=" + getWheelRevolutionsTime() + " count=" + getWheelRevolutionsCount();
}
@Override
@@ -4,9 +4,6 @@ import androidx.annotation.NonNull;
import de.dennisguse.opentracks.content.data.TrackPoint;
/**
*
*/
public final class SensorDataSet {
private SensorDataHeartRate heartRate;
@@ -31,10 +28,6 @@ public final class SensorDataSet {
}
public void set(SensorData data) {
if (data == null) {
return;
}
if (data instanceof SensorDataHeartRate) {
this.heartRate = (SensorDataHeartRate) data;
return;
@@ -48,10 +41,6 @@ public final class SensorDataSet {
this.cyclingSpeed = (SensorDataCycling.Speed) data;
return;
}
if (data instanceof SensorDataCycling.CadenceAndSpeed) {
set(((SensorDataCycling.CadenceAndSpeed) data).getCadence());
set(((SensorDataCycling.CadenceAndSpeed) data).getSpeed());
}
throw new UnsupportedOperationException();
}
@@ -32,7 +32,7 @@ import java.util.ArrayList;
import java.util.List;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.TrackDetailActivity;
import de.dennisguse.opentracks.TrackActivityDataHubInterface;
import de.dennisguse.opentracks.chart.ChartPoint;
import de.dennisguse.opentracks.chart.ChartView;
import de.dennisguse.opentracks.content.TrackDataHub;
@@ -90,12 +90,9 @@ public class ChartFragment extends Fragment implements TrackDataListener {
boolean metricUnits = PreferencesUtils.isMetricUnits(getContext());
if (metricUnits != chartView.getMetricUnits()) {
chartView.setMetricUnits(metricUnits);
runOnUiThread(new Runnable() {
@Override
public void run() {
if (isResumed()) {
chartView.requestLayout();
}
runOnUiThread(() -> {
if (isResumed()) {
chartView.requestLayout();
}
});
}
@@ -106,12 +103,9 @@ public class ChartFragment extends Fragment implements TrackDataListener {
chartView.setReportSpeed(reportSpeed);
chartView.applyReportSpeed();
runOnUiThread(new Runnable() {
@Override
public void run() {
if (isResumed()) {
chartView.requestLayout();
}
runOnUiThread(() -> {
if (isResumed()) {
chartView.requestLayout();
}
});
}
@@ -214,12 +208,9 @@ public class ChartFragment extends Fragment implements TrackDataListener {
trackStatisticsUpdater = startTime != -1L ? new TrackStatisticsUpdater(startTime) : null;
pendingPoints.clear();
chartView.reset();
runOnUiThread(new Runnable() {
@Override
public void run() {
if (isResumed()) {
chartView.resetScroll();
}
runOnUiThread(() -> {
if (isResumed()) {
chartView.resetScroll();
}
});
}
@@ -286,7 +277,7 @@ public class ChartFragment extends Fragment implements TrackDataListener {
* Needs to be synchronized because trackDataHub can be accessed by multiple threads.
*/
private synchronized void resumeTrackDataHub() {
trackDataHub = ((TrackDetailActivity) getActivity()).getTrackDataHub();
trackDataHub = ((TrackActivityDataHubInterface) getActivity()).getTrackDataHub();
trackDataHub.registerTrackDataListener(this, true, true, true, true);
}
@@ -80,15 +80,12 @@ public class DeleteMarkerDialogFragment extends DialogFragment {
fragmentActivity, titleId, getString(messageId), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
new Thread(new Runnable() {
@Override
public void run() {
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(fragmentActivity);
for (long markerId : markerIds) {
contentProviderUtils.deleteWaypoint(getContext(), markerId);
}
caller.onDeleteMarkerDone();
new Thread(() -> {
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(fragmentActivity);
for (long markerId : markerIds) {
contentProviderUtils.deleteWaypoint(getContext(), markerId);
}
caller.onDeleteMarkerDone();
}).start();
}
});
@@ -1,126 +0,0 @@
/*
* Copyright 2013 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package de.dennisguse.opentracks.fragments;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.FragmentManager;
import java.util.Locale;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.io.file.TrackFileFormat;
/**
* A DialogFragment to select a file type, gpx, kml, etc.
*
* @author Jimmy Shih
*/
public class FileTypeDialogFragment extends DialogFragment {
private static final String FILE_TYPE_DIALOG_TAG = "fileType";
private static final String KEY_TITLE_ID = "titleId";
private static final String KEY_OPTION_ID = "optionId";
private FileTypeCaller caller;
public static void showDialog(FragmentManager fragmentManager, int titleId, int optionId) {
Bundle bundle = new Bundle();
bundle.putInt(KEY_TITLE_ID, titleId);
bundle.putInt(KEY_OPTION_ID, optionId);
FileTypeDialogFragment fileTypeDialogFragment = new FileTypeDialogFragment();
fileTypeDialogFragment.setArguments(bundle);
fileTypeDialogFragment.show(fragmentManager, FILE_TYPE_DIALOG_TAG);
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
try {
caller = (FileTypeCaller) context;
} catch (ClassCastException e) {
throw new ClassCastException(context + " must implement " + FileTypeCaller.class.getSimpleName());
}
}
@Override
@NonNull
public Dialog onCreateDialog(Bundle savedInstanceState) {
int optionId = getArguments().getInt(KEY_OPTION_ID);
final int titleId = getArguments().getInt(KEY_TITLE_ID);
final TrackFileFormat[] trackFileFormats = {TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA_AND_PICTURES, TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA, TrackFileFormat.KML_WITH_TRACKDETAIL_AND_SENSORDATA, TrackFileFormat.GPX};
String[] choices = new String[trackFileFormats.length];
for (int i = 0; i < choices.length; i++) {
TrackFileFormat trackFileFormat = trackFileFormats[i];
String trackFileFormatUpperCase = trackFileFormat.getExtension().toUpperCase(Locale.US); //ASCII upper case
int photoMessageId = trackFileFormat.includesPhotos() ? R.string.export_with_photos : R.string.export_without_photos;
String trackFileFormatDisplayName = String.format("%s (%s)", trackFileFormatUpperCase, getString(photoMessageId));
choices[i] = getString(optionId, trackFileFormatDisplayName);
}
return new AlertDialog.Builder(getActivity())
.setNegativeButton(R.string.generic_cancel, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
onDismissed();
}
})
.setPositiveButton(R.string.generic_ok, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
int position = ((AlertDialog) dialog).getListView().getCheckedItemPosition();
caller.onFileTypeDone(trackFileFormats[position]);
}
})
.setSingleChoiceItems(choices, 0, null)
.setTitle(titleId)
.create();
}
@Override
public void onCancel(@NonNull DialogInterface dialog) {
onDismissed();
}
private void onDismissed() {
dismiss();
caller.onDismissed();
}
/**
* Interface for caller of this dialog fragment.
*
* @author Jimmy Shih
*/
public interface FileTypeCaller {
/**
* Called when file type selection is done.
*/
void onFileTypeDone(TrackFileFormat trackFileFormat);
void onDismissed();
}
}
@@ -0,0 +1,304 @@
/*
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package de.dennisguse.opentracks.fragments;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Pair;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Spinner;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.TrackRecordedActivity;
import de.dennisguse.opentracks.content.TrackDataHub;
import de.dennisguse.opentracks.content.TrackDataListener;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.data.TrackPoint;
import de.dennisguse.opentracks.content.data.Waypoint;
import de.dennisguse.opentracks.stats.TrackStatistics;
import de.dennisguse.opentracks.util.PreferencesUtils;
import de.dennisguse.opentracks.util.StringUtils;
import de.dennisguse.opentracks.util.TrackIconUtils;
/**
* A fragment to display track statistics to the user.
*
* @author Sandor Dornbush
* @author Rodrigo Damazio
*/
public class StatisticsRecordedFragment extends Fragment implements TrackDataListener {
private TrackStatistics trackStatistics = null;
private String category = "";
private final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
if (PreferencesUtils.isKey(getContext(), R.string.stats_units_key, key) || PreferencesUtils.isKey(getContext(), R.string.stats_rate_key, key)) {
if (isResumed()) {
getActivity().runOnUiThread(() -> {
if (isResumed()) {
updateUI();
}
});
}
}
}
};
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.statistics_recorded, container, false);
}
/* Views */
private TextView totalTimeValueView;
private TextView distanceValue;
private TextView distanceUnit;
private View activityLabel;
private Spinner activitySpinner;
private TextView movingTimeValue;
private TextView speedAvgLabel;
private TextView speedAvgValue;
private TextView speedAvgUnit;
private TextView speedMaxLabel;
private TextView speedMaxValue;
private TextView speedMaxUnit;
private TextView speedMovingLabel;
private TextView speedMovingValue;
private TextView speedMovingUnit;
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
totalTimeValueView = view.findViewById(R.id.stats_total_time_value);
distanceValue = view.findViewById(R.id.stats_distance_value);
distanceUnit = view.findViewById(R.id.stats_distance_unit);
activityLabel = view.findViewById(R.id.stats_activity_type_label);
activitySpinner = view.findViewById(R.id.stats_activity_type_icon);
movingTimeValue = view.findViewById(R.id.stats_moving_time_value);
speedAvgLabel = view.findViewById(R.id.stats_average_speed_label);
speedAvgValue = view.findViewById(R.id.stats_average_speed_value);
speedAvgUnit = view.findViewById(R.id.stats_average_speed_unit);
speedMaxLabel = view.findViewById(R.id.stats_max_speed_label);
speedMaxValue = view.findViewById(R.id.stats_max_speed_value);
speedMaxUnit = view.findViewById(R.id.stats_max_speed_unit);
speedMovingLabel = view.findViewById(R.id.stats_moving_speed_label);
speedMovingValue = view.findViewById(R.id.stats_moving_speed_value);
speedMovingUnit = view.findViewById(R.id.stats_moving_speed_unit);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Spinner activityTypeIcon = getView().findViewById(R.id.stats_activity_type_icon);
activityTypeIcon.setAdapter(TrackIconUtils.getIconSpinnerAdapter(getActivity(), ""));
activityTypeIcon.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
((TrackRecordedActivity) getActivity()).chooseActivityType(category);
}
return true;
}
});
activityTypeIcon.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
((TrackRecordedActivity) getActivity()).chooseActivityType(category);
}
return true;
}
});
}
@Override
public void onResume() {
super.onResume();
PreferencesUtils.register(getContext(), sharedPreferenceChangeListener);
TrackDataHub trackDataHub = ((TrackRecordedActivity) getActivity()).getTrackDataHub();
trackDataHub.registerTrackDataListener(this, true, false, true, true);
}
@Override
public void onPause() {
super.onPause();
PreferencesUtils.unregister(getContext(), sharedPreferenceChangeListener);
TrackDataHub trackDataHub = ((TrackRecordedActivity) getActivity()).getTrackDataHub();
trackDataHub.unregisterTrackDataListener(this);
}
@Override
public void onDestroyView() {
super.onDestroyView();
totalTimeValueView = null;
distanceValue = null;
distanceUnit = null;
activityLabel = null;
activitySpinner = null;
movingTimeValue = null;
speedAvgLabel = null;
speedAvgValue = null;
speedAvgUnit = null;
speedMaxLabel = null;
speedMaxValue = null;
speedMaxUnit = null;
speedMovingLabel = null;
speedMovingValue = null;
speedMovingUnit = null;
}
@Override
public void onTrackUpdated(final Track track) {
if (isResumed()) {
getActivity().runOnUiThread(() -> {
if (isResumed()) {
trackStatistics = track != null ? track.getTrackStatistics() : null;
category = track != null ? track.getCategory() : "";
updateUI();
}
});
}
}
@Override
public void clearTrackPoints() {
// We don't care.
}
@Override
public void onSampledInTrackPoint(TrackPoint trackPoint) {
// We don't care.
}
@Override
public void onSampledOutTrackPoint(TrackPoint trackPoint) {
// We don't care.
}
@Override
public void onNewTrackPointsDone() {
// We don't care.
}
@Override
public void clearWaypoints() {
// We don't care.
}
@Override
public void onNewWaypoint(Waypoint wpt) {
// We don't care.
}
@Override
public void onNewWaypointsDone() {
// We don't care.
}
private void updateUI() {
String trackIconValue = TrackIconUtils.getIconValue(getContext(), category);
boolean metricUnits = PreferencesUtils.isMetricUnits(getContext());
boolean reportSpeed = PreferencesUtils.isReportSpeed(getContext(), category);
// Set total distance
{
double totalDistance = trackStatistics == null ? Double.NaN : trackStatistics.getTotalDistance();
Pair<String, String> parts = StringUtils.getDistanceParts(getContext(), totalDistance, metricUnits);
distanceValue.setText(parts.first);
distanceUnit.setText(parts.second);
}
// Set activity type
{
activityLabel.setVisibility(trackIconValue != null ? View.VISIBLE : View.GONE);
activitySpinner.setVisibility(trackIconValue != null ? View.VISIBLE : View.GONE);
activitySpinner.setEnabled(false);
if (trackIconValue != null) {
TrackIconUtils.setIconSpinner(activitySpinner, trackIconValue);
}
}
// Set time and start datetime
if (trackStatistics != null) {
movingTimeValue.setText(StringUtils.formatElapsedTime(trackStatistics.getMovingTime()));
totalTimeValueView.setText(StringUtils.formatElapsedTime(trackStatistics.getTotalTime()));
}
// Set average speed/pace
{
double speed = trackStatistics != null ? trackStatistics.getAverageSpeed() : Double.NaN;
speedAvgLabel.setText(reportSpeed ? R.string.stats_average_speed : R.string.stats_average_pace);
Pair<String, String> parts = StringUtils.getSpeedParts(getContext(), speed, metricUnits, reportSpeed);
speedAvgValue.setText(parts.first);
speedAvgUnit.setText(parts.second);
}
// Set max speed/pace
{
double speed = trackStatistics == null ? Double.NaN : trackStatistics.getMaxSpeed();
speedMaxLabel.setText(reportSpeed ? R.string.stats_max_speed : R.string.stats_fastest_pace);
Pair<String, String> parts = StringUtils.getSpeedParts(getContext(), speed, metricUnits, reportSpeed);
speedMaxValue.setText(parts.first);
speedMaxUnit.setText(parts.second);
}
// Set moving speed/pace
{
double speed = trackStatistics != null ? trackStatistics.getAverageMovingSpeed() : Double.NaN;
speedMovingLabel.setText(reportSpeed ? R.string.stats_average_moving_speed : R.string.stats_average_moving_pace);
Pair<String, String> parts = StringUtils.getSpeedParts(getContext(), speed, metricUnits, reportSpeed);
speedMovingValue.setText(parts.first);
speedMovingUnit.setText(parts.second);
}
}
}
@@ -1,19 +1,3 @@
/*
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package de.dennisguse.opentracks.fragments;
import android.content.SharedPreferences;
@@ -31,15 +15,18 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.Group;
import androidx.fragment.app.Fragment;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.TrackDetailActivity;
import de.dennisguse.opentracks.TrackRecordingActivity;
import de.dennisguse.opentracks.content.TrackDataHub;
import de.dennisguse.opentracks.content.TrackDataListener;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.data.TrackPoint;
import de.dennisguse.opentracks.content.data.Waypoint;
import de.dennisguse.opentracks.content.sensor.SensorDataCycling;
import de.dennisguse.opentracks.content.sensor.SensorDataHeartRate;
import de.dennisguse.opentracks.content.sensor.SensorDataSet;
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
import de.dennisguse.opentracks.services.TrackRecordingServiceInterface;
@@ -57,9 +44,9 @@ import de.dennisguse.opentracks.util.UnitConversions;
* @author Sandor Dornbush
* @author Rodrigo Damazio
*/
public class StatsFragment extends Fragment implements TrackDataListener {
public class StatisticsRecordingFragment extends Fragment implements TrackDataListener {
private static final String STATS_FRAGMENT_TAG = StatsFragment.class.getSimpleName();
private static final String TAG = StatisticsRecordingFragment.class.getSimpleName();
private static final long UI_UPDATE_INTERVAL = UnitConversions.ONE_SECOND_MS;
@@ -81,12 +68,9 @@ public class StatsFragment extends Fragment implements TrackDataListener {
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
if (PreferencesUtils.isKey(getContext(), R.string.stats_units_key, key) || PreferencesUtils.isKey(getContext(), R.string.stats_rate_key, key)) {
if (isResumed()) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
if (isResumed()) {
updateUI();
}
getActivity().runOnUiThread(() -> {
if (isResumed()) {
updateUI();
}
});
}
@@ -109,14 +93,15 @@ public class StatsFragment extends Fragment implements TrackDataListener {
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.stats, container, false);
return inflater.inflate(R.layout.statistics_recording, container, false);
}
/* Views */
private View heartRateContainer;
private View sensorHorizontalLine;
private Group heartRateGroup;
private TextView heartRateValueView;
private TextView heartRateSensorView;
private View cadenceContainer;
private Group cadenceGroup;
private TextView cadenceValueView;
private TextView cadenceSensorView;
@@ -147,16 +132,13 @@ public class StatsFragment extends Fragment implements TrackDataListener {
private TextView speedMovingLabel;
private TextView speedMovingValue;
private TextView speedMovingUnit;
private View elevationSeparator;
private View elevationContainer;
private View speedContainer;
private Group elevationGroup;
private TextView speedLabel;
private TextView speedValue;
private TextView speedUnit;
private TextView elevationValue;
private TextView elevationUnit;
private View coordinateSeparator;
private View coordinateContainer;
private Group coordinateGroup;
private TextView latitudeValue;
private TextView longitudeValue;
@@ -164,11 +146,13 @@ public class StatsFragment extends Fragment implements TrackDataListener {
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
heartRateContainer = view.findViewById(R.id.stats_sensor_heart_rate_container);
sensorHorizontalLine = view.findViewById(R.id.stats_sensor_horizontal_line);
heartRateGroup = view.findViewById(R.id.stats_sensor_heart_rate_group);
heartRateValueView = view.findViewById(R.id.stats_sensor_heart_rate_value);
heartRateSensorView = view.findViewById(R.id.stats_sensor_heart_rate_sensor_value);
cadenceContainer = view.findViewById(R.id.stats_sensor_cadence_container);
cadenceGroup = view.findViewById(R.id.stats_sensor_cadence_group);
cadenceValueView = view.findViewById(R.id.stats_sensor_cadence_value);
cadenceSensorView = view.findViewById(R.id.stats_sensor_cadence_sensor_value);
@@ -194,10 +178,8 @@ public class StatsFragment extends Fragment implements TrackDataListener {
speedMovingValue = view.findViewById(R.id.stats_moving_speed_value);
speedMovingUnit = view.findViewById(R.id.stats_moving_speed_unit);
elevationSeparator = view.findViewById(R.id.stats_elevation_separator);
elevationContainer = view.findViewById(R.id.stats_elevation_container);
elevationGroup = view.findViewById(R.id.stats_elevation_current_group);
speedContainer = view.findViewById(R.id.stats_speed);
speedLabel = view.findViewById(R.id.stats_speed_label);
speedValue = view.findViewById(R.id.stats_speed_value);
speedUnit = view.findViewById(R.id.stats_speed_unit);
@@ -205,8 +187,7 @@ public class StatsFragment extends Fragment implements TrackDataListener {
elevationValue = view.findViewById(R.id.stats_elevation_current_value);
elevationUnit = view.findViewById(R.id.stats_elevation_current_unit);
coordinateSeparator = view.findViewById(R.id.stats_coordinate_separator);
coordinateContainer = view.findViewById(R.id.stats_coordinate_container);
coordinateGroup = view.findViewById(R.id.stats_coordinate_group);
latitudeValue = view.findViewById(R.id.stats_latitude_value);
longitudeValue = view.findViewById(R.id.stats_longitude_value);
@@ -226,7 +207,7 @@ public class StatsFragment extends Fragment implements TrackDataListener {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
((TrackDetailActivity) getActivity()).chooseActivityType(category);
((TrackRecordingActivity) getActivity()).chooseActivityType(category);
}
return true;
}
@@ -235,7 +216,7 @@ public class StatsFragment extends Fragment implements TrackDataListener {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
((TrackDetailActivity) getActivity()).chooseActivityType(category);
((TrackRecordingActivity) getActivity()).chooseActivityType(category);
}
return true;
}
@@ -275,10 +256,12 @@ public class StatsFragment extends Fragment implements TrackDataListener {
@Override
public void onDestroyView() {
super.onDestroyView();
heartRateContainer = null;
sensorHorizontalLine = null;
heartRateGroup = null;
heartRateValueView = null;
heartRateSensorView = null;
cadenceContainer = null;
cadenceGroup = null;
cadenceValueView = null;
cadenceSensorView = null;
@@ -304,10 +287,8 @@ public class StatsFragment extends Fragment implements TrackDataListener {
speedMovingValue = null;
speedMovingUnit = null;
elevationSeparator = null;
elevationContainer = null;
elevationGroup = null;
speedContainer = null;
speedLabel = null;
speedValue = null;
speedUnit = null;
@@ -315,8 +296,7 @@ public class StatsFragment extends Fragment implements TrackDataListener {
elevationValue = null;
elevationUnit = null;
coordinateSeparator = null;
coordinateContainer = null;
coordinateGroup = null;
latitudeValue = null;
longitudeValue = null;
@@ -325,14 +305,11 @@ public class StatsFragment extends Fragment implements TrackDataListener {
@Override
public void onTrackUpdated(final Track track) {
if (isResumed()) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
if (isResumed()) {
lastTrackStatistics = track != null ? track.getTrackStatistics() : null;
category = track != null ? track.getCategory() : "";
updateUI();
}
getActivity().runOnUiThread(() -> {
if (isResumed()) {
lastTrackStatistics = track != null ? track.getTrackStatistics() : null;
category = track != null ? track.getCategory() : "";
updateUI();
}
});
}
@@ -356,24 +333,21 @@ public class StatsFragment extends Fragment implements TrackDataListener {
@Override
public void onNewTrackPointsDone() {
if (isResumed()) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
if (isResumed()) {
if (!isSelectedTrackRecording() || isSelectedTrackPaused()) {
getActivity().runOnUiThread(() -> {
if (isResumed()) {
if (!isSelectedTrackRecording() || isSelectedTrackPaused()) {
lastTrackPoint = null;
}
if (lastTrackPoint != null) {
boolean hasFix = !LocationUtils.isLocationOld(lastTrackPoint.getLocation());
boolean hasGoodFix = TrackPointUtils.fulfillsAccuracy(lastTrackPoint, recordingGpsAccuracy);
if (!hasFix || !hasGoodFix) {
lastTrackPoint = null;
}
if (lastTrackPoint != null) {
boolean hasFix = !LocationUtils.isLocationOld(lastTrackPoint.getLocation());
boolean hasGoodFix = TrackPointUtils.fulfillsAccuracy(lastTrackPoint, recordingGpsAccuracy);
if (!hasFix || !hasGoodFix) {
lastTrackPoint = null;
}
}
setLocationValues();
}
setLocationValues();
}
});
}
@@ -399,7 +373,7 @@ public class StatsFragment extends Fragment implements TrackDataListener {
* Needs to be synchronized because trackDataHub can be accessed by multiple threads.
*/
private synchronized void resumeTrackDataHub() {
trackDataHub = ((TrackDetailActivity) getActivity()).getTrackDataHub();
trackDataHub = ((TrackRecordingActivity) getActivity()).getTrackDataHub();
trackDataHub.registerTrackDataListener(this, true, false, true, true);
}
@@ -442,65 +416,79 @@ public class StatsFragment extends Fragment implements TrackDataListener {
SensorDataSet sensorDataSet = null;
if (trackRecordingService == null) {
Log.d(STATS_FRAGMENT_TAG, "Cannot get the track recording service.");
Log.d(TAG, "Cannot get the track recording service.");
} else {
sensorDataSet = trackRecordingService.getSensorData();
}
setHeartRateSensorData(sensorDataSet, isSelectedTrackRecording());
setCadenceSensorData(sensorDataSet, isSelectedTrackRecording());
setHeartRateSensorData(sensorDataSet);
setCadenceSensorData(sensorDataSet);
setSpeedSensorData(sensorDataSet, isSelectedTrackRecording());
}
private void setHeartRateSensorData(SensorDataSet sensorDataSet, boolean isRecording) {
private void setHeartRateSensorData(SensorDataSet sensorDataSet) {
int isVisible = View.VISIBLE;
if (!isRecording || PreferencesUtils.isBluetoothHeartRateSensorAddressNone(getContext())) {
isVisible = View.INVISIBLE;
if (PreferencesUtils.isBluetoothHeartRateSensorAddressNone(getContext())) {
isVisible = View.GONE;
}
heartRateContainer.setVisibility(isVisible);
heartRateGroup.setVisibility(isVisible);
setVisibilitySensorHorizontalLine();
if (isRecording) {
String sensorValue = getContext().getString(R.string.value_unknown);
String sensorName = getContext().getString(R.string.value_unknown);
if (sensorDataSet != null && sensorDataSet.getHeartRate() != null) {
sensorName = sensorDataSet.getHeartRate().getSensorName();
if (sensorDataSet.getHeartRate().hasHeartRate_bpm() && sensorDataSet.getHeartRate().isRecent()) {
sensorValue = StringUtils.formatDecimal(sensorDataSet.getHeartRate().getHeartRate_bpm(), 0);
}
String sensorValue = getContext().getString(R.string.value_unknown);
String sensorName = getContext().getString(R.string.value_unknown);
if (sensorDataSet != null && sensorDataSet.getHeartRate() != null) {
SensorDataHeartRate data = sensorDataSet.getHeartRate();
sensorName = data.getSensorName();
if (data.hasHeartRate_bpm() && data.isRecent()) {
sensorValue = StringUtils.formatDecimal(data.getHeartRate_bpm(), 0);
}
heartRateSensorView.setText(sensorName);
heartRateValueView.setText(sensorValue);
}
heartRateSensorView.setText(sensorName);
heartRateValueView.setText(sensorValue);
}
private void setCadenceSensorData(SensorDataSet sensorDataSet, boolean isRecording) {
private void setCadenceSensorData(SensorDataSet sensorDataSet) {
int isVisible = View.VISIBLE;
if (!isRecording || PreferencesUtils.isBluetoothCyclingCadenceSensorAddressNone(getContext())) {
isVisible = View.INVISIBLE;
if (PreferencesUtils.isBluetoothCyclingCadenceSensorAddressNone(getContext())) {
isVisible = View.GONE;
}
cadenceContainer.setVisibility(isVisible);
cadenceGroup.setVisibility(isVisible);
setVisibilitySensorHorizontalLine();
if (isRecording) {
String sensorValue = getContext().getString(R.string.value_unknown);
String sensorName = getContext().getString(R.string.value_unknown);
if (sensorDataSet != null && sensorDataSet.getCyclingCadence() != null) {
sensorName = sensorDataSet.getCyclingCadence().getSensorName();
if (sensorDataSet.getCyclingCadence().hasCadence_rpm() && sensorDataSet.getCyclingCadence().isRecent()) {
sensorValue = StringUtils.formatDecimal(sensorDataSet.getCyclingCadence().getCadence_rpm(), 0);
}
String sensorValue = getContext().getString(R.string.value_unknown);
String sensorName = getContext().getString(R.string.value_unknown);
if (sensorDataSet != null && sensorDataSet.getCyclingCadence() != null) {
SensorDataCycling.Cadence data = sensorDataSet.getCyclingCadence();
sensorName = data.getSensorName();
if (data.hasCadence_rpm() && data.isRecent()) {
sensorValue = StringUtils.formatDecimal(data.getCadence_rpm(), 0);
}
cadenceSensorView.setText(sensorName);
cadenceValueView.setText(sensorValue);
}
cadenceSensorView.setText(sensorName);
cadenceValueView.setText(sensorValue);
}
/**
* If cadence and hear rate groups are invisible then sensor horizontal line hast to be invisible too.
*/
private void setVisibilitySensorHorizontalLine() {
if (cadenceGroup.getVisibility() != View.VISIBLE && heartRateGroup.getVisibility() != View.VISIBLE) {
sensorHorizontalLine.setVisibility(View.GONE);
}
}
private void setSpeedSensorData(SensorDataSet sensorDataSet, boolean isRecording) {
if (isRecording) {
if (sensorDataSet != null && sensorDataSet.getCyclingSpeed() != null) {
if (sensorDataSet.getCyclingSpeed().hasSpeed_mps() && sensorDataSet.getCyclingSpeed().isRecent()) {
setSpeed(sensorDataSet.getCyclingSpeed().getSpeed_mps());
SensorDataCycling.Speed data = sensorDataSet.getCyclingSpeed();
if (data.hasSpeed_mps() && data.isRecent()) {
setSpeed(data.getSpeed_mps());
}
}
}
@@ -574,7 +562,7 @@ public class StatsFragment extends Fragment implements TrackDataListener {
// Make elevation visible?
{
boolean showElevation = PreferencesUtils.isShowStatsElevation(getContext());
elevationSeparator.setVisibility(showElevation ? View.VISIBLE : View.GONE);
elevationGroup.setVisibility(showElevation ? View.VISIBLE : View.GONE);
}
}
@@ -603,18 +591,14 @@ public class StatsFragment extends Fragment implements TrackDataListener {
private void setLocationValues() {
boolean metricUnits = PreferencesUtils.isMetricUnits(getContext());
boolean isRecording = isSelectedTrackRecording();
// Set speed/pace
speedContainer.setVisibility(isRecording ? View.VISIBLE : View.INVISIBLE);
if (isRecording) {
double speed = lastTrackPoint != null && lastTrackPoint.hasSpeed() ? lastTrackPoint.getSpeed() : Double.NaN;
setSpeed(speed);
}
double speed = lastTrackPoint != null && lastTrackPoint.hasSpeed() ? lastTrackPoint.getSpeed() : Double.NaN;
setSpeed(speed);
// Set elevation
boolean showElevation = isRecording && PreferencesUtils.isShowStatsElevation(getContext());
elevationContainer.setVisibility(showElevation ? View.VISIBLE : View.GONE);
boolean showElevation = PreferencesUtils.isShowStatsElevation(getContext());
elevationGroup.setVisibility(showElevation ? View.VISIBLE : View.GONE);
if (showElevation) {
double altitude = lastTrackPoint != null && lastTrackPoint.hasAltitude() ? lastTrackPoint.getAltitude() : Double.NaN;
@@ -625,10 +609,9 @@ public class StatsFragment extends Fragment implements TrackDataListener {
}
// Set coordinate
boolean showCoordinate = isRecording && PreferencesUtils.isStatsShowCoordinate(getContext());
boolean showCoordinate = PreferencesUtils.isStatsShowCoordinate(getContext());
coordinateSeparator.setVisibility(showCoordinate ? View.VISIBLE : View.GONE);
coordinateContainer.setVisibility(showCoordinate ? View.VISIBLE : View.GONE);
coordinateGroup.setVisibility(showCoordinate ? View.VISIBLE : View.GONE);
if (showCoordinate) {
double latitude = lastTrackPoint != null ? lastTrackPoint.getLatitude() : Double.NaN;
String latitudeText = Double.isNaN(latitude) || Double.isInfinite(latitude) ? getContext().getString(R.string.value_unknown) : StringUtils.formatCoordinate(latitude);
@@ -12,7 +12,6 @@ import de.dennisguse.opentracks.io.file.exporter.GpxTrackWriter;
import de.dennisguse.opentracks.io.file.exporter.KmlTrackWriter;
import de.dennisguse.opentracks.io.file.exporter.KmzTrackExporter;
import de.dennisguse.opentracks.io.file.exporter.TrackExporter;
import de.dennisguse.opentracks.io.file.exporter.TrackExporterListener;
import de.dennisguse.opentracks.io.file.exporter.TrackWriter;
/**
@@ -74,8 +73,8 @@ public enum TrackFileFormat {
return new KmlTrackWriter(context, multiple, false, false, exportPhotos);
}
public TrackExporter newTrackExporter(Context context, Track[] tracks, TrackExporterListener trackExporterListener) {
return newKmzTrackExporter(context, this.newTrackWriter(context, tracks.length > 1), tracks, trackExporterListener, exportPhotos);
public TrackExporter newTrackExporter(Context context, Track[] tracks) {
return newKmzTrackExporter(context, this.newTrackWriter(context, tracks.length > 1), tracks, exportPhotos);
}
@Override
@@ -101,8 +100,8 @@ public enum TrackFileFormat {
return new KmlTrackWriter(context, multiple, true, false, exportPhotos);
}
public TrackExporter newTrackExporter(Context context, Track[] tracks, TrackExporterListener trackExporterListener) {
return newKmzTrackExporter(context, this.newTrackWriter(context, tracks.length > 1), tracks, trackExporterListener, exportPhotos);
public TrackExporter newTrackExporter(Context context, Track[] tracks) {
return newKmzTrackExporter(context, this.newTrackWriter(context, tracks.length > 1), tracks, exportPhotos);
}
@Override
@@ -134,8 +133,8 @@ public enum TrackFileFormat {
return MIME_KMZ;
}
public TrackExporter newTrackExporter(Context context, Track[] tracks, TrackExporterListener trackExporterListener) {
return newKmzTrackExporter(context, this.newTrackWriter(context, tracks.length > 1), tracks, trackExporterListener, exportPhotos);
public TrackExporter newTrackExporter(Context context, Track[] tracks) {
return newKmzTrackExporter(context, this.newTrackWriter(context, tracks.length > 1), tracks, exportPhotos);
}
public String getExtension() {
@@ -163,8 +162,8 @@ public enum TrackFileFormat {
return MIME_KMZ;
}
public TrackExporter newTrackExporter(Context context, Track[] tracks, TrackExporterListener trackExporterListener) {
return newKmzTrackExporter(context, newTrackWriter(context, tracks.length > 1), tracks, trackExporterListener, exportPhotos);
public TrackExporter newTrackExporter(Context context, Track[] tracks) {
return newKmzTrackExporter(context, newTrackWriter(context, tracks.length > 1), tracks, exportPhotos);
}
public String getExtension() {
@@ -197,10 +196,10 @@ public enum TrackFileFormat {
private static final String MIME_KML = "application/vnd.google-earth.kml+xml";
private static TrackExporter newKmzTrackExporter(Context context, TrackWriter trackWriter, Track[] tracks, TrackExporterListener trackExporterListener, boolean exportPhotos) {
private static TrackExporter newKmzTrackExporter(Context context, TrackWriter trackWriter, Track[] tracks, boolean exportPhotos) {
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(context);
FileTrackExporter fileTrackExporter = new FileTrackExporter(contentProviderUtils, trackWriter, tracks, trackExporterListener);
FileTrackExporter fileTrackExporter = new FileTrackExporter(contentProviderUtils, trackWriter, tracks);
return new KmzTrackExporter(contentProviderUtils, fileTrackExporter, tracks, exportPhotos);
}
@@ -210,10 +209,10 @@ public enum TrackFileFormat {
*/
public abstract String getMimeType();
public TrackExporter newTrackExporter(Context context, Track[] tracks, TrackExporterListener trackExporterListener) {
public TrackExporter newTrackExporter(Context context, Track[] tracks) {
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(context);
TrackWriter trackWriter = newTrackWriter(context, tracks.length > 1);
return new FileTrackExporter(contentProviderUtils, trackWriter, tracks, trackExporterListener);
return new FileTrackExporter(contentProviderUtils, trackWriter, tracks);
}
/**
@@ -30,17 +30,17 @@ import androidx.documentfile.provider.DocumentFile;
import androidx.fragment.app.FragmentActivity;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.fragments.FileTypeDialogFragment;
import de.dennisguse.opentracks.io.file.TrackFileFormat;
import de.dennisguse.opentracks.util.DialogUtils;
import de.dennisguse.opentracks.util.FileUtils;
import de.dennisguse.opentracks.util.PreferencesUtils;
/**
* An activity for saving tracks to the external storage.
*
* @author Rodrigo Damazio
*/
public class ExportActivity extends FragmentActivity implements FileTypeDialogFragment.FileTypeCaller {
public class ExportActivity extends FragmentActivity {
private static final int DIRECTORY_PICKER_REQUEST_CODE = 6;
@@ -55,8 +55,6 @@ public class ExportActivity extends FragmentActivity implements FileTypeDialogFr
private int processedTrackCount;
private int totalTrackCount;
private Uri directoryUri;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -71,36 +69,24 @@ public class ExportActivity extends FragmentActivity implements FileTypeDialogFr
super.onActivityResult(requestCode, resultCode, resultData);
if (requestCode == DIRECTORY_PICKER_REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK) {
directoryUri = resultData.getData();
fileTypeDialogStart();
Uri directoryUri = resultData.getData();
DocumentFile pickedDirectory = DocumentFile.fromTreeUri(this, directoryUri);
DocumentFile exportDirectory = pickedDirectory.findFile(FileUtils.EXPORT_DIR);
if (exportDirectory == null) {
exportDirectory = pickedDirectory.createDirectory(FileUtils.EXPORT_DIR);
}
TrackFileFormat trackFileFormat = PreferencesUtils.getExportTrackFileFormat(this);
directoryDisplayName = FileUtils.getPath(exportDirectory);
exportAsyncTask = new ExportAsyncTask(this, trackFileFormat, exportDirectory);
exportAsyncTask.execute();
} else {
finish();
}
}
}
private void fileTypeDialogStart() {
FileTypeDialogFragment.showDialog(getSupportFragmentManager(), R.string.export_all_title, R.string.export_all_option);
}
@Override
public void onFileTypeDone(TrackFileFormat trackFileFormat) {
DocumentFile pickedDirectory = DocumentFile.fromTreeUri(this, directoryUri);
DocumentFile exportDirectory = pickedDirectory.findFile(FileUtils.EXPORT_DIR);
if (exportDirectory == null) {
exportDirectory = pickedDirectory.createDirectory(FileUtils.EXPORT_DIR);
}
directoryDisplayName = FileUtils.getPath(exportDirectory);
exportAsyncTask = new ExportAsyncTask(this, trackFileFormat, exportDirectory);
exportAsyncTask.execute();
}
@Override
public void onDismissed() {
finish();
}
@Override
protected Dialog onCreateDialog(int id) {
switch (id) {
@@ -112,7 +98,7 @@ public class ExportActivity extends FragmentActivity implements FileTypeDialogFr
public void onCancel(DialogInterface dialog) {
exportAsyncTask.cancel(true);
dialog.dismiss();
onDismissed();
finish();
}
}, directoryDisplayName);
return progressDialog;
@@ -138,13 +124,13 @@ public class ExportActivity extends FragmentActivity implements FileTypeDialogFr
@Override
public void onCancel(DialogInterface dialog) {
dialog.dismiss();
onDismissed();
finish();
}
}).setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int arg1) {
dialog.dismiss();
onDismissed();
finish();
}
}).setTitle(titleId);
return builder.create();
@@ -16,7 +16,6 @@
package de.dennisguse.opentracks.io.file.exporter;
import android.content.Context;
import android.database.Cursor;
import android.os.AsyncTask;
import android.os.PowerManager.WakeLock;
@@ -45,13 +44,10 @@ class ExportAsyncTask extends AsyncTask<Void, Integer, Boolean> {
private static final String TAG = ExportAsyncTask.class.getSimpleName();
private final TrackFileFormat trackFileFormat;
private final DocumentFile directory;
private final Context context;
private final ContentProviderUtils contentProviderUtils;
private ExportActivity exportActivity;
private WakeLock wakeLock;
private boolean completed = false;
private int processedTrackCount = 0;
private int totalTrackCount = 0;
@@ -66,8 +62,7 @@ class ExportAsyncTask extends AsyncTask<Void, Integer, Boolean> {
this.exportActivity = exportActivity;
this.trackFileFormat = trackFileFormat;
this.directory = directory;
context = exportActivity.getApplicationContext();
contentProviderUtils = new ContentProviderUtils(context);
contentProviderUtils = new ContentProviderUtils(exportActivity);
}
@Override
@@ -99,7 +94,6 @@ class ExportAsyncTask extends AsyncTask<Void, Integer, Boolean> {
@Override
protected void onPostExecute(Boolean result) {
completed = true;
if (exportActivity != null) {
exportActivity.onAsyncTaskCompleted(processedTrackCount, totalTrackCount);
}
@@ -107,7 +101,6 @@ class ExportAsyncTask extends AsyncTask<Void, Integer, Boolean> {
@Override
protected void onCancelled() {
completed = true;
if (exportActivity != null) {
exportActivity.onAsyncTaskCompleted(processedTrackCount, totalTrackCount);
}
@@ -119,17 +112,7 @@ class ExportAsyncTask extends AsyncTask<Void, Integer, Boolean> {
* @param track the track
*/
private Boolean exportTrack(Track track) {
TrackExporterListener trackExporterListener = new TrackExporterListener() {
@Override
public void onProgressUpdate(int number, int max) {
//Update the progress dialog once every 500 points.
if (number % 500 == 0) {
publishProgress(number, max);
}
}
};
TrackExporter trackExporter = trackFileFormat.newTrackExporter(context, new Track[]{track}, trackExporterListener);
TrackExporter trackExporter = trackFileFormat.newTrackExporter(exportActivity, new Track[]{track});
String fileName = track.getId() + "." + trackFileFormat.getExtension();
@@ -139,8 +122,8 @@ class ExportAsyncTask extends AsyncTask<Void, Integer, Boolean> {
file = directory.createFile(trackFileFormat.getMimeType(), fileName);
}
try (OutputStream outputStream = context.getContentResolver().openOutputStream(file.getUri())) {
if (trackExporter.writeTrack(context, outputStream)) {
try (OutputStream outputStream = exportActivity.getContentResolver().openOutputStream(file.getUri())) {
if (trackExporter.writeTrack(exportActivity, outputStream)) {
return true;
} else {
if (!file.delete()) {
@@ -167,6 +150,7 @@ class ExportAsyncTask extends AsyncTask<Void, Integer, Boolean> {
return false;
}
totalTrackCount = cursor.getCount();
for (int i = 0; i < totalTrackCount; i++) {
if (isCancelled()) {
return false;
@@ -44,7 +44,6 @@ public class FileTrackExporter implements TrackExporter {
private final ContentProviderUtils contentProviderUtils;
private final Track[] tracks;
private final TrackWriter trackWriter;
private final TrackExporterListener trackExporterListener;
/**
* Constructor.
@@ -52,13 +51,11 @@ public class FileTrackExporter implements TrackExporter {
* @param contentProviderUtils the content provider utils
* @param trackWriter the track writer
* @param tracks the tracks
* @param trackExporterListener the track export listener
*/
public FileTrackExporter(ContentProviderUtils contentProviderUtils, TrackWriter trackWriter, Track[] tracks, TrackExporterListener trackExporterListener) {
public FileTrackExporter(ContentProviderUtils contentProviderUtils, TrackWriter trackWriter, Track[] tracks) {
this.contentProviderUtils = contentProviderUtils;
this.tracks = tracks;
this.trackWriter = trackWriter;
this.trackExporterListener = trackExporterListener;
}
@Override
@@ -158,9 +155,6 @@ public class FileTrackExporter implements TrackExporter {
// Write the current trackPoint
trackWriter.writeTrackPoint(trackPoint);
if (trackExporterListener != null) {
trackExporterListener.onProgressUpdate(locationNumber, trackPointIterator.getCount());
}
} else {
if (wroteSegment) {
trackWriter.writeCloseSegment();
@@ -1,33 +0,0 @@
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package de.dennisguse.opentracks.io.file.exporter;
/**
* Listener for {@link TrackExporter} progress.
*
* @author Jimmy Shih
*/
public interface TrackExporterListener {
/**
* Called to update progress.
*
* @param number the number of {@link de.dennisguse.opentracks.content.data.TrackPoint}s written
* @param max the maximum number of {@link de.dennisguse.opentracks.content.data.TrackPoint}s in a {@link de.dennisguse.opentracks.content.data.Track}, for calculation of
* completion percentage
*/
void onProgressUpdate(int number, int max);
}
@@ -424,7 +424,7 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
} else {
try {
timeValue = StringUtils.parseTime(time);
} catch (IllegalArgumentException e) {
} catch (Exception e) {
throw new SAXException(createErrorMessage(String.format(Locale.US, "Unable to parse time: %s", time)), e);
}
}
@@ -30,17 +30,17 @@ import androidx.documentfile.provider.DocumentFile;
import androidx.fragment.app.FragmentActivity;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.fragments.FileTypeDialogFragment;
import de.dennisguse.opentracks.io.file.TrackFileFormat;
import de.dennisguse.opentracks.util.DialogUtils;
import de.dennisguse.opentracks.util.FileUtils;
import de.dennisguse.opentracks.util.PreferencesUtils;
/**
* An activity to import files from the external storage.
*
* @author Rodrigo Damazio
*/
public class ImportActivity extends FragmentActivity implements FileTypeDialogFragment.FileTypeCaller {
public class ImportActivity extends FragmentActivity {
private static final int DIRECTORY_PICKER_REQUEST_CODE = 6;
@@ -55,8 +55,6 @@ public class ImportActivity extends FragmentActivity implements FileTypeDialogFr
private int importedTrackCount;
private int totalTrackCount;
private Uri directoryUri;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -72,34 +70,20 @@ public class ImportActivity extends FragmentActivity implements FileTypeDialogFr
super.onActivityResult(requestCode, resultCode, resultData);
if (requestCode == DIRECTORY_PICKER_REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK) {
directoryUri = resultData.getData();
fileTypeDialogStart();
Uri directoryUri = resultData.getData();
DocumentFile pickedDirectory = DocumentFile.fromTreeUri(this, directoryUri);
directoryDisplayName = FileUtils.getPath(pickedDirectory);
TrackFileFormat trackFileFormat = PreferencesUtils.getExportTrackFileFormat(this);
importAsyncTask = new ImportAsyncTask(this, trackFileFormat, pickedDirectory);
importAsyncTask.execute();
} else {
finish();
}
}
}
private void fileTypeDialogStart() {
FileTypeDialogFragment.showDialog(getSupportFragmentManager(), R.string.import_selection_title, R.string.import_selection_option);
}
@Override
public void onFileTypeDone(TrackFileFormat trackFileFormat) {
DocumentFile pickedDirectory = DocumentFile.fromTreeUri(this, directoryUri);
directoryDisplayName = FileUtils.getPath(pickedDirectory);
importAsyncTask = new ImportAsyncTask(this, trackFileFormat, pickedDirectory);
importAsyncTask.execute();
}
@Override
public void onDismissed() {
finish();
}
@Override
protected Dialog onCreateDialog(int id) {
switch (id) {
@@ -110,7 +94,7 @@ public class ImportActivity extends FragmentActivity implements FileTypeDialogFr
public void onCancel(DialogInterface dialog) {
importAsyncTask.cancel(true);
dialog.dismiss();
onDismissed();
finish();
}
}, directoryDisplayName);
return progressDialog;
@@ -140,13 +124,13 @@ public class ImportActivity extends FragmentActivity implements FileTypeDialogFr
@Override
public void onCancel(DialogInterface dialogInterface) {
dialogInterface.dismiss();
onDismissed();
finish();
}
}).setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int which) {
dialogInterface.dismiss();
onDismissed();
finish();
}
}).setTitle(titleId).create();
default:
@@ -41,8 +41,8 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.TrackDetailActivity;
import de.dennisguse.opentracks.TrackListActivity;
import de.dennisguse.opentracks.TrackRecordingActivity;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.data.TrackPoint;
import de.dennisguse.opentracks.content.data.Waypoint;
@@ -150,12 +150,7 @@ public class TrackRecordingService extends Service {
if (locationExecutorService == null || locationExecutorService.isShutdown() || locationExecutorService.isTerminated()) {
return;
}
locationExecutorService.submit(new Runnable() {
@Override
public void run() {
onLocationChangedAsync(location);
}
});
locationExecutorService.submit(() -> onLocationChangedAsync(location));
}
@Override
@@ -743,10 +738,10 @@ public class TrackRecordingService extends Service {
private void showNotification(boolean isGpsStarted) {
if (isRecording()) {
Intent intent = IntentUtils.newIntent(this, TrackDetailActivity.class)
.putExtra(TrackDetailActivity.EXTRA_TRACK_ID, recordingTrackId);
Intent intent = IntentUtils.newIntent(this, TrackRecordingActivity.class)
.putExtra(TrackRecordingActivity.EXTRA_TRACK_ID, recordingTrackId);
PendingIntent pendingIntent = TaskStackBuilder.create(this)
.addParentStack(TrackDetailActivity.class)
.addParentStack(TrackRecordingActivity.class)
.addNextIntent(intent)
.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
@@ -51,12 +51,14 @@ public class TrackRecordingServiceConnection implements ServiceConnection, Death
private TrackRecordingServiceInterface trackRecordingService;
public TrackRecordingServiceConnection() {
callback = null;
}
/**
* Constructor.
*
* @param callback the callback to invoke when the service binding changes
*/
public TrackRecordingServiceConnection(Runnable callback) {
public TrackRecordingServiceConnection(@NonNull Runnable callback) {
this.callback = callback;
}
@@ -23,6 +23,7 @@ import android.content.SharedPreferences;
import android.util.Log;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.content.sensor.SensorData;
import de.dennisguse.opentracks.content.sensor.SensorDataCycling;
import de.dennisguse.opentracks.content.sensor.SensorDataSet;
import de.dennisguse.opentracks.util.BluetoothUtils;
@@ -31,11 +32,11 @@ import de.dennisguse.opentracks.util.UnitConversions;
/**
* Bluetooth LE sensor manager: manages connections to Bluetooth LE sensors.
*
* <p>
* Note: should only be instantiated once.
*
* <p>
* TODO: listen for Bluetooth enabled/disabled events.
*
* <p>
* TODO: In case, a cycling (Cadence and Speed) sensor reports both values, testing is required.
* We establish two GATT separate GATT connections (as if two different sensors were used).
* However, it is not clear if this is allowed.
@@ -148,20 +149,25 @@ public class BluetoothRemoteSensorManager implements BluetoothConnectionManager.
}
@Override
public synchronized void onChanged(de.dennisguse.opentracks.content.sensor.SensorData sensorData) {
public synchronized void onChanged(SensorData sensorData) {
if (sensorData instanceof SensorDataCycling.Cadence) {
if (sensorData.equals(sensorDataSet.getCyclingCadence())) {
SensorDataCycling.Cadence previous = sensorDataSet.getCyclingCadence();
Log.d(TAG, "previous " + previous + "; current" + sensorData);
if (sensorData.equals(previous)) {
Log.d(TAG, "onChanged: cadence data repeated.");
return;
}
((SensorDataCycling.Cadence) sensorData).compute(sensorDataSet.getCyclingCadence());
((SensorDataCycling.Cadence) sensorData).compute(previous);
}
if (sensorData instanceof SensorDataCycling.Speed) {
if (sensorData.equals(sensorDataSet.getCyclingSpeed())) {
SensorDataCycling.Speed previous = sensorDataSet.getCyclingSpeed();
Log.d(TAG, "previous " + previous + "; current" + sensorData);
if (sensorData.equals(previous)) {
Log.d(TAG, "onChanged: speed data repeated.");
return;
}
((SensorDataCycling.Speed) sensorData).compute(sensorDataSet.getCyclingSpeed(), PreferencesUtils.getWheelCircumference(context));
((SensorDataCycling.Speed) sensorData).compute(previous, PreferencesUtils.getWheelCircumference(context));
}
sensorDataSet.set(sensorData);
@@ -11,8 +11,11 @@ import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
import java.util.Locale;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.fragments.ChooseActivityTypeDialogFragment;
import de.dennisguse.opentracks.io.file.TrackFileFormat;
import de.dennisguse.opentracks.settings.bluetooth.BluetoothLeCyclingCadenceAndSpeedPreference;
import de.dennisguse.opentracks.settings.bluetooth.BluetoothLeHeartRatePreference;
import de.dennisguse.opentracks.settings.bluetooth.BluetoothLeSensorPreference;
@@ -57,20 +60,10 @@ public class SettingsActivity extends AppCompatActivity implements ChooseActivit
@Override
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
if (PreferencesUtils.isKey(getActivity(), R.string.recording_track_id_key, key)) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
updateReset();
}
});
getActivity().runOnUiThread(() -> updateReset());
}
if (PreferencesUtils.isKey(getActivity(), R.string.stats_units_key, key)) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
updateUnits();
}
});
getActivity().runOnUiThread(() -> updateUnits());
}
}
};
@@ -89,6 +82,8 @@ public class SettingsActivity extends AppCompatActivity implements ChooseActivit
setPreferencesFromResource(R.xml.settings, rootKey);
}
setExportTrackFileFormatOptions();
}
@Override
@@ -172,5 +167,24 @@ public class SettingsActivity extends AppCompatActivity implements ChooseActivit
HackUtils.invalidatePreference(statsRatePreferences);
}
private void setExportTrackFileFormatOptions() {
final TrackFileFormat[] trackFileFormats = {TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA_AND_PICTURES, TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA, TrackFileFormat.KML_WITH_TRACKDETAIL_AND_SENSORDATA, TrackFileFormat.GPX};
String[] entries = new String[trackFileFormats.length];
String[] entryValues = new String[trackFileFormats.length];
for (int i = 0; i < entries.length; i++) {
TrackFileFormat trackFileFormat = trackFileFormats[i];
String trackFileFormatUpperCase = trackFileFormat.getExtension().toUpperCase(Locale.US); //ASCII upper case
int photoMessageId = trackFileFormat.includesPhotos() ? R.string.export_with_photos : R.string.export_without_photos;
entries[i] = String.format("%s (%s)", trackFileFormatUpperCase, getString(photoMessageId));
entryValues[i] = trackFileFormat.name();
}
ListPreference listPreference = findPreference(getString(R.string.export_trackfileformat_key));
listPreference.setEntries(entries);
listPreference.setEntryValues(entryValues);
}
}
}
@@ -61,13 +61,10 @@ public class BluetoothUtils {
final Object mutex = new Object();
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
adapters.add(BluetoothAdapter.getDefaultAdapter());
synchronized (mutex) {
mutex.notify();
}
handler.post(() -> {
adapters.add(BluetoothAdapter.getDefaultAdapter());
synchronized (mutex) {
mutex.notify();
}
});
@@ -5,6 +5,8 @@ import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import androidx.annotation.NonNull;
import java.util.ArrayList;
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
@@ -21,32 +23,61 @@ public class IntentDashboardUtils {
private static final String ACTION_DASHBOARD_PAYLOAD = ACTION_DASHBOARD + ".Payload";
private static final String EXTRAS_SHOULD_KEEP_SCREEN_ON = "EXTRAS_SHOULD_KEEP_SCREEN_ON";
private static final String EXTRAS_SHOW_WHEN_LOCKED = "EXTRAS_SHOULD_KEEP_SCREEN_ON";
private static int TRACK_URI_INDEX = 0;
private static int TRACKPOINTS_URI_INDEX = 1;
private IntentDashboardUtils() {
}
public static boolean startDashboard(Context context, long[] trackIds) {
ArrayList<Uri> uris = new ArrayList<>();
/**
* Send intent to show tracks on a map (needs an another app) as resource URIs.
*
* @param context the context
* @param trackIds the track ids
*/
public static void startDashboard(Context context, long[] trackIds) {
if (trackIds.length == 0) {
return;
}
String trackIdList = ContentProviderUtils.formatIdListForUri(trackIds);
uris.add(0, Uri.withAppendedPath(TracksColumns.CONTENT_URI, trackIdList));
uris.add(1, Uri.withAppendedPath(TrackPointsColumns.CONTENT_URI_BY_TRACKID, trackIdList));
ArrayList<Uri> uris = new ArrayList<>();
uris.add(TRACK_URI_INDEX, Uri.withAppendedPath(TracksColumns.CONTENT_URI, trackIdList));
uris.add(TRACKPOINTS_URI_INDEX, Uri.withAppendedPath(TrackPointsColumns.CONTENT_URI_BY_TRACKID, trackIdList));
Intent intent = new Intent(ACTION_DASHBOARD);
intent.putParcelableArrayListExtra(ACTION_DASHBOARD_PAYLOAD, uris);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(EXTRAS_SHOULD_KEEP_SCREEN_ON, PreferencesUtils.shouldKeepScreenOn(context));
intent.putExtra(EXTRAS_SHOW_WHEN_LOCKED, PreferencesUtils.shouldShowStatsOnLockscreen(context));
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
ClipData clipData = ClipData.newRawUri(null, uris.get(0));
clipData.addItem(new ClipData.Item(uris.get(1)));
ClipData clipData = ClipData.newRawUri(null, uris.get(TRACK_URI_INDEX));
clipData.addItem(new ClipData.Item(uris.get(TRACKPOINTS_URI_INDEX)));
intent.setClipData(clipData);
if (intent.resolveActivity(context.getPackageManager()) != null) {
context.startActivity(Intent.createChooser(intent, null));
return true;
}
return false;
context.startActivity(intent);
}
public static void startDashboard(Context context, long trackId) {
startDashboard(context, new long[]{trackId});
}
public static long[] extractTrackIdsFromIntent(@NonNull Intent intent) {
final ArrayList<Uri> uris = intent.getParcelableArrayListExtra(ACTION_DASHBOARD_PAYLOAD);
final Uri tracksUri = uris.get(TRACK_URI_INDEX);
String[] trackIdsString = ContentProviderUtils.parseTrackIdsFromUri(tracksUri);
long[] trackIds = new long[trackIdsString.length];
for (int i = 0; i < trackIdsString.length; i++) {
trackIds[i] = Long.parseLong(trackIdsString[i]);
}
return trackIds;
}
}
@@ -16,14 +16,12 @@
package de.dennisguse.opentracks.util;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.provider.MediaStore;
import android.util.Log;
import android.util.Pair;
import android.widget.Toast;
import androidx.core.content.FileProvider;
@@ -35,11 +33,9 @@ import java.util.Date;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.content.DescriptionGenerator;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
import de.dennisguse.opentracks.content.data.Waypoint;
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
import de.dennisguse.opentracks.content.provider.ShareContentProvider;
import de.dennisguse.opentracks.io.file.TrackFileFormat;
/**
* Utilities for creating intents.
@@ -92,9 +88,10 @@ public class IntentUtils {
Track track = contentProviderUtils.getTrack(trackId);
if (track == null) {
Log.e(TAG, "TrackId " + trackId + " could not be resolved.");
continue;
}
Pair<Uri, String> uriAndMime = ShareContentProvider.createURI(new long[]{trackId}, track.getName(), TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA_AND_PICTURES);
Pair<Uri, String> uriAndMime = ShareContentProvider.createURI(new long[]{trackId}, track.getName(), PreferencesUtils.getExportTrackFileFormat(context));
uris.add(uriAndMime.first);
mime = uriAndMime.second;
}
@@ -152,42 +149,11 @@ public class IntentUtils {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(uri));
try {
context.startActivity(intent);
} catch (ActivityNotFoundException e) {
Toast.makeText(context, context.getString(R.string.app_not_installed_show_on_map), Toast.LENGTH_SHORT).show();
}
context.startActivity(Intent.createChooser(intent, null));
}
/**
* Send intent to show tracks on a map (needs an another app).
*
* @param context the context
* @param trackIds the track ids
*/
public static void showTrackOnMap(Context context, long[] trackIds) {
if (trackIds.length == 0) {
return;
}
if (IntentDashboardUtils.startDashboard(context, trackIds)) {
return;
}
Intent intent = new Intent(android.content.Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(TrackPointsColumns.TRACKID, trackIds[0]);
Pair<Uri, String> uriAndMime = ShareContentProvider.createURI(trackIds, "SharingTrack", TrackFileFormat.KMZ_WITH_TRACKDETAIL);
intent.setDataAndType(uriAndMime.first, uriAndMime.second);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
if (intent.resolveActivity(context.getPackageManager()) != null) {
context.startActivity(intent);
} else {
Toast.makeText(context, context.getString(R.string.app_not_installed_show_on_map), Toast.LENGTH_SHORT).show();
}
}
/**
* Sends a take picture request to the camera app.
@@ -24,6 +24,7 @@ import androidx.annotation.VisibleForTesting;
import androidx.preference.PreferenceManager;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.io.file.TrackFileFormat;
/**
* Utilities to access preferences stored in {@link SharedPreferences}.
@@ -320,6 +321,16 @@ public class PreferencesUtils {
return getInt(context, R.string.recording_gps_accuracy_key, RECORDING_GPS_ACCURACY);
}
public static TrackFileFormat getExportTrackFileFormat(Context context) {
final String TRACKFILEFORMAT_NAME_DEFAULT = getString(context, R.string.export_trackfileformat_default, null);
String trackFileFormatName = getString(context, R.string.export_trackfileformat_key, TRACKFILEFORMAT_NAME_DEFAULT);
try {
return TrackFileFormat.valueOf(trackFileFormatName);
} catch (Exception e) {
return TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA;
}
}
public static boolean isRecording(Context context) {
long recordingTrackId = getRecordingTrackId(context);
return isRecording(recordingTrackId);
@@ -20,12 +20,16 @@ import android.location.Location;
import android.os.Build;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.Log;
import android.util.Pair;
import java.text.DecimalFormat;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
import java.util.Date;
@@ -44,6 +48,8 @@ import de.dennisguse.opentracks.R;
*/
public class StringUtils {
private static final String TAG = StringUtils.class.getSimpleName();
private static final String COORDINATE_DEGREE = "\u00B0";
//TODO Remove when upgrading to API level 26+.
@@ -280,22 +286,27 @@ public class StringUtils {
}
/**
* Gets the time, in milliseconds, from an XML date time string as defined at http://www.w3.org/TR/xmlschema-2/#dateTime
* Gets the time, in milliseconds, from an XML date time string (ISO8601) as defined at http://www.w3.org/TR/xmlschema-2/#dateTime
* Let's be lenient: if timezone information is not provided, UTC will be used.
*
* @param xmlDateTime the XML date time string
*/
public static long parseTime(String xmlDateTime) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
try {
TemporalAccessor t = DateTimeFormatter.ISO_DATE_TIME.parse(xmlDateTime);
TemporalAccessor t = DateTimeFormatter.ISO_DATE_TIME.parseBest(xmlDateTime, ZonedDateTime::from, LocalDateTime::from);
if (t instanceof LocalDateTime) {
Log.w(TAG, "Date does not contain timezone information: using UTC.");
t = ((LocalDateTime) t).atZone(ZoneOffset.UTC);
}
return Instant.from(t).toEpochMilli();
} catch (Exception e) {
throw new IllegalArgumentException("Invalid XML dateTime value: " + e);
Log.e(TAG, "Invalid XML dateTime value");
throw e;
}
}
//TODO Remove the following when upgrading to API level 26+.
//ATTENTION: The following code does not require a time zone (+01 or Z); while ISO_DATE_TIME requires this!
// Parse the date time base
ParsePosition position = new ParsePosition(0);
@@ -415,4 +426,8 @@ public class StringUtils {
}
return new Pair<>(value, unit);
}
public static String valueInParentheses(String text) {
return "(" + text + ")";
}
}
@@ -17,7 +17,7 @@ public class UintUtils {
if (a < 0 || b < 0) {
return -1;
}
if (a > UINT_MAX && b > UINT_MAX) {
if (a > UINT_MAX || b > UINT_MAX) {
return -1;
}
@@ -0,0 +1,30 @@
package de.dennisguse.opentracks.util;
import android.text.method.LinkMovementMethod;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
public class ViewUtils {
private ViewUtils() {
}
/**
* Traverses all childs of {@link View} recursively and makes links within {@link TextView}s clickable.
*/
public static void makeClickableLinks(ViewGroup view) {
if (view == null) {
return;
}
for (int i = 0; i < view.getChildCount(); i++) {
final View child = view.getChildAt(i);
if (child instanceof ViewGroup) {
makeClickableLinks((ViewGroup) child);
} else if (child instanceof TextView) {
((TextView) child).setMovementMethod(LinkMovementMethod.getInstance());
}
}
}
}
@@ -0,0 +1,74 @@
package de.dennisguse.opentracks.viewmodels;
import android.content.Context;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.stats.TrackStatistics;
import de.dennisguse.opentracks.util.TrackIconUtils;
public class AggregatedStatistics {
private HashMap<String, AggregatedStatistic> aggregatedStatistics = new HashMap<>();
public void aggregate(List<Track> tracks) {
for (Track track : tracks) {
aggregate(track);
}
}
public void aggregate(Track track) {
String category = track.getCategory();
if (aggregatedStatistics.containsKey(category)) {
aggregatedStatistics.get(category).add(track.getTrackStatistics());
} else {
aggregatedStatistics.put(category, new AggregatedStatistic(track.getTrackStatistics()));
}
}
public int getCount() {
return aggregatedStatistics.size();
}
public String getSportName(int position) {
return getKey(position);
}
public AggregatedStatistic get(String category) {
return aggregatedStatistics.get(category);
}
private String getKey(int position) {
return (new ArrayList<>(aggregatedStatistics.keySet())).get(position);
}
public AggregatedStatistic getItem(int position) {
return (new ArrayList<>(aggregatedStatistics.values())).get(position);
}
public static class AggregatedStatistic {
private TrackStatistics trackStatistics;
private int countTracks;
public AggregatedStatistic(TrackStatistics trackStatistics) {
this.trackStatistics = trackStatistics;
this.countTracks = 1;
}
public TrackStatistics getTrackStatistics() {
return trackStatistics;
}
public int getCountTracks() {
return countTracks;
}
void add(TrackStatistics statistics) {
trackStatistics.merge(statistics);
countTracks++;
}
}
}
@@ -0,0 +1,42 @@
package de.dennisguse.opentracks.viewmodels;
import android.app.Application;
import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import java.util.List;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
public class AggregatedStatisticsModel extends AndroidViewModel {
private MutableLiveData<AggregatedStatistics> aggregatedStats;
public AggregatedStatisticsModel(@NonNull Application application) {
super(application);
}
public LiveData<AggregatedStatistics> getAggregatedStats() {
if (aggregatedStats == null) {
aggregatedStats = new MutableLiveData<>();
loadAggregatedStats();
}
return aggregatedStats;
}
private void loadAggregatedStats() {
new Thread(() -> {
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(getApplication().getApplicationContext());
List<Track> tracks = contentProviderUtils.getAllTracks();
AggregatedStatistics aggregatedStatistics = new AggregatedStatistics();
aggregatedStatistics.aggregate(tracks);
aggregatedStats.postValue(aggregatedStatistics);
}).start();
}
}
@@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="100"
android:viewportHeight="100">
<path
android:fillColor="#000000"
android:pathData="M82.489,12.834C83.196,10.418 82.043,9.556 79.926,10.917L10.087,55.828c-2.117,1.361 -1.795,2.628 0.714,2.815L39.806,60.807c2.51,0.188 5.291,2.267 6.18,4.621l10.282,27.208c0.89,2.354 2.195,2.304 2.902,-0.111z" />
</vector>
@@ -0,0 +1,33 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<group
android:scaleX="0.56"
android:scaleY="0.56"
android:translateX="23.76"
android:translateY="23.76">
<path
android:strokeWidth="1"
android:pathData="M85.133,20.59C85.731,18.546 84.756,17.817 82.965,18.968L23.874,56.967c-1.791,1.152 -1.519,2.224 0.604,2.382L49.019,61.18c2.124,0.159 4.477,1.918 5.229,3.91l8.7,23.021c0.753,1.992 1.857,1.949 2.455,-0.094z"
android:strokeColor="#f69123">
<aapt:attr name="android:fillColor">
<gradient
android:startY="80.33152"
android:startX="38.773293"
android:endY="19.211866"
android:endX="84.4913"
android:type="linear">
<item
android:offset="0"
android:color="#FFFBB22F" />
<item
android:offset="1"
android:color="#FFF58820" />
</gradient>
</aapt:attr>
</path>
</group>
</vector>
@@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M19,3L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM9,17L7,17v-7h2v7zM13,17h-2L11,7h2v10zM17,17h-2v-4h2v4z"/>
</vector>
+78 -65
View File
@@ -6,82 +6,95 @@
<include layout="@layout/toolbar" />
<ImageView
android:id="@+id/imageView"
<ScrollView
android:layout_width="match_parent"
android:layout_height="239dp"
android:contentDescription="@string/app_name"
android:scaleType="fitCenter"
android:src="@drawable/ic_logo_color_24dp" />
android:layout_height="wrap_content">
<TextView
style="@style/TextLarge"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/app_name"
android:textSize="24sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="20dp">
<View style="@style/StatsHorizontalLine" />
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="239dp"
android:contentDescription="@string/app_name"
android:scaleType="fitCenter"
android:src="@drawable/ic_logo_color_24dp" />
<TextView
android:id="@+id/about_text_description"
style="@style/TextMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="12dp" />
<TextView
style="@style/TextLarge"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/app_name"
android:textSize="24sp" />
<View style="@style/StatsHorizontalLine" />
<View style="@style/StatsHorizontalLine" />
<TextView
android:id="@+id/about_text_version_name"
style="@style/TextSmall"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="6dp" />
<TextView
android:id="@+id/about_text_description"
style="@style/TextMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="12dp" />
<TextView
android:id="@+id/about_text_version_code"
style="@style/TextSmall"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="6dp" />
<View style="@style/StatsHorizontalLine" />
<TextView
android:id="@+id/about_app_url"
style="@style/TextSmall"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:autoLink="web"
android:gravity="center"
android:padding="6dp" />
<TextView
android:id="@+id/about_text_version_name"
style="@style/TextSmall"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="6dp" />
<TextView
style="@style/TextSmall"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:autoLink="web"
android:gravity="center"
android:padding="6dp"
android:text="@string/about_history" />
<TextView
android:id="@+id/about_text_version_code"
style="@style/TextSmall"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="6dp" />
<View style="@style/StatsHorizontalLine" />
<TextView
android:id="@+id/about_app_url"
style="@style/TextSmall"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:autoLink="web"
android:gravity="center"
android:padding="6dp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="12dp"
android:text="@string/about_libraries" />
<TextView
style="@style/TextSmall"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="6dp"
android:linksClickable="true"
android:text="@string/about_history" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:autoLink="web"
android:gravity="center"
android:text="@string/third_party_libraries" />
<View style="@style/StatsHorizontalLine" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="12dp"
android:text="@string/about_libraries" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:linksClickable="true"
android:text="@string/third_party_libraries" />
</LinearLayout>
</ScrollView>
</LinearLayout>
+14
View File
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/toolbar" />
<ListView
android:id="@+id/aggregated_stats_list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1.0" />
</LinearLayout>
@@ -0,0 +1,150 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="24dp">
<!-- Guidelines -->
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline1"
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="vertical"
app:layout_constraintGuide_begin="8dp" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline2"
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline3"
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="vertical"
app:layout_constraintGuide_end="8dp" />
<!-- Icon and sport name -->
<ImageView
android:id="@+id/aggregated_stats_sport_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginTop="16dp"
app:layout_constraintLeft_toLeftOf="@id/guideline1"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_activity_bike_24dp" />
<TextView
android:id="@+id/aggregated_stats_type_label"
style="@style/StatsLargeLabel"
android:layout_marginTop="0dp"
android:layout_marginBottom="0dp"
app:layout_constraintBottom_toBottomOf="@+id/aggregated_stats_sport_icon"
app:layout_constraintLeft_toRightOf="@+id/aggregated_stats_sport_icon"
app:layout_constraintTop_toTopOf="@+id/aggregated_stats_sport_icon"
tools:text="@string/activity_type_cycling"
android:layout_marginLeft="16dp" />
<TextView
android:id="@+id/aggregated_stats_num_tracks"
style="@style/StatsLargeLabel"
android:layout_marginTop="0dp"
android:layout_marginBottom="0dp"
app:layout_constraintBottom_toBottomOf="@+id/aggregated_stats_type_label"
app:layout_constraintLeft_toRightOf="@+id/aggregated_stats_type_label"
app:layout_constraintTop_toTopOf="@+id/aggregated_stats_type_label"
tools:text="(1)"
android:layout_marginLeft="4dp" />
<!-- Distance -->
<TextView
android:id="@+id/aggregated_stats_distance"
style="@style/StatsLargeValue"
app:layout_constraintLeft_toLeftOf="@id/guideline1"
app:layout_constraintTop_toBottomOf="@+id/aggregated_stats_sport_icon"
tools:text="100000"
android:layout_marginLeft="16dp"
android:layout_marginTop="16dp" />
<TextView
android:id="@+id/aggregated_stats_distance_unit"
style="@style/StatsUnit"
android:textColor="@android:color/white"
app:layout_constraintBottom_toBottomOf="@+id/aggregated_stats_distance"
app:layout_constraintLeft_toRightOf="@+id/aggregated_stats_distance"
tools:text="km" />
<!-- Time -->
<TextView
android:id="@+id/aggregated_stats_time"
style="@style/StatsLargeValue"
app:layout_constraintRight_toRightOf="@id/guideline3"
app:layout_constraintTop_toBottomOf="@+id/aggregated_stats_sport_icon"
tools:text="00:00:00"
android:layout_marginRight="16dp"
android:layout_marginTop="16dp" />
<!-- Avg. rate -->
<TextView
android:id="@+id/aggregated_stats_avg_rate"
style="@style/StatsSmallValue"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintTop_toBottomOf="@id/aggregated_stats_distance"
app:layout_constraintLeft_toRightOf="@id/guideline1"
app:layout_constraintRight_toLeftOf="@+id/aggregated_stats_avg_rate_unit"
android:layout_marginTop="24dp"
tools:text="30" />
<TextView
android:id="@+id/aggregated_stats_avg_rate_unit"
style="@style/StatsUnit"
android:textColor="@android:color/white"
app:layout_constraintBottom_toBottomOf="@+id/aggregated_stats_avg_rate"
app:layout_constraintLeft_toRightOf="@+id/aggregated_stats_avg_rate"
app:layout_constraintRight_toRightOf="@id/guideline2"
tools:text="km/h" />
<TextView
android:id="@+id/aggregated_stats_avg_rate_label"
style="@style/StatsTinyLabel"
app:layout_constrainedWidth="true"
app:layout_constraintTop_toBottomOf="@+id/aggregated_stats_avg_rate"
app:layout_constraintLeft_toRightOf="@id/guideline1"
app:layout_constraintRight_toRightOf="@id/guideline2"
tools:text="@string/stats_average_moving_speed" />
<!-- Max. rate -->
<TextView
android:id="@+id/aggregated_stats_max_rate"
style="@style/StatsSmallValue"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintTop_toBottomOf="@id/aggregated_stats_time"
app:layout_constraintLeft_toRightOf="@id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/aggregated_stats_max_rate_unit"
android:layout_marginTop="24dp"
tools:text="70" />
<TextView
android:id="@+id/aggregated_stats_max_rate_unit"
style="@style/StatsUnit"
android:textColor="@android:color/white"
app:layout_constraintBottom_toBottomOf="@+id/aggregated_stats_max_rate"
app:layout_constraintLeft_toRightOf="@+id/aggregated_stats_max_rate"
app:layout_constraintRight_toLeftOf="@id/guideline3"
tools:text="km/h" />
<TextView
android:id="@+id/aggregated_stats_max_rate_label"
style="@style/StatsTinyLabel"
app:layout_constrainedWidth="true"
app:layout_constraintTop_toBottomOf="@+id/aggregated_stats_max_rate"
app:layout_constraintLeft_toRightOf="@id/guideline2"
app:layout_constraintRight_toLeftOf="@id/guideline3"
tools:text="@string/stats_max_speed" />
</androidx.constraintlayout.widget.ConstraintLayout>
+213
View File
@@ -0,0 +1,213 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
style="@style/StatsScrollView">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- Guidelines -->
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="vertical"
app:layout_constraintGuide_begin="8dp" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline2"
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline3"
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="vertical"
app:layout_constraintGuide_end="8dp" />
<!-- Distance -->
<TextView
android:id="@+id/stats_distance_label"
style="@style/StatsLargeLabel"
android:text="@string/stats_distance"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/stats_distance_value"
style="@style/StatsLargeValue"
android:value="@string/value_unknown"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/stats_distance_unit"
app:layout_constraintTop_toBottomOf="@+id/stats_distance_label"
tools:text="100" />
<TextView
android:id="@+id/stats_distance_unit"
style="@style/StatsUnit"
app:layout_constraintBottom_toBottomOf="@+id/stats_distance_value"
app:layout_constraintLeft_toRightOf="@+id/stats_distance_value"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
tools:text="km" />
<!-- Activity Type -->
<TextView
android:id="@+id/stats_activity_type_label"
style="@style/StatsLargeLabel"
android:text="@string/track_edit_activity_type_hint"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintTop_toTopOf="parent" />
<Spinner
android:id="@+id/stats_activity_type_icon"
style="@style/StatsLargeValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintBottom_toBottomOf="@+id/stats_distance_value"
app:layout_constraintTop_toTopOf="@+id/stats_distance_value" />
<!-- Total time -->
<TextView
android:id="@+id/stats_total_time_label"
style="@style/StatsLargeLabel"
android:text="@string/stats_total_time"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
app:layout_constraintTop_toBottomOf="@+id/stats_distance_value" />
<TextView
android:id="@+id/stats_total_time_value"
style="@style/StatsLargeValue"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
app:layout_constraintTop_toBottomOf="@+id/stats_total_time_label"
tools:text="00:00:00" />
<!-- Moving time -->
<TextView
android:id="@+id/stats_moving_time_label"
style="@style/StatsLargeLabel"
android:text="@string/stats_moving_time"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintTop_toTopOf="@+id/stats_total_time_label"
app:layout_constraintBottom_toBottomOf="@+id/stats_total_time_label" />
<TextView
android:id="@+id/stats_moving_time_value"
style="@style/StatsLargeValue"
android:value="@string/value_unknown"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@+id/stats_moving_time_label"
tools:text="00:00:00" />
<!-- Horizontal line -->
<View
android:id="@+id/stats_speed_horizontal_line"
style="@style/StatsHorizontalLine"
android:layout_marginBottom="8dp"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@+id/stats_moving_time_value" />
<!-- Average speed/pace -->
<TextView
android:id="@+id/stats_average_speed_label"
style="@style/StatsSmallLabel"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@id/stats_speed_horizontal_line"
tools:text="Avg. Speed" />
<TextView
android:id="@+id/stats_average_speed_value"
style="@style/StatsSmallValue"
android:value="@string/value_unknown"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/stats_average_speed_unit"
app:layout_constraintTop_toBottomOf="@+id/stats_average_speed_label"
tools:text="30.00" />
<TextView
android:id="@+id/stats_average_speed_unit"
style="@style/StatsUnit"
app:layout_constraintBottom_toBottomOf="@+id/stats_average_speed_value"
app:layout_constraintLeft_toRightOf="@+id/stats_average_speed_value"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
tools:text="km/h" />
<!-- Speed max -->
<TextView
android:id="@+id/stats_max_speed_label"
style="@style/StatsSmallLabel"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
app:layout_constraintTop_toBottomOf="@id/stats_average_speed_value"
tools:text="Max. Speed" />
<TextView
android:id="@+id/stats_max_speed_value"
style="@style/StatsSmallValue"
android:value="@string/value_unknown"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/stats_max_speed_unit"
app:layout_constraintTop_toBottomOf="@+id/stats_max_speed_label"
tools:text="30.00" />
<TextView
android:id="@+id/stats_max_speed_unit"
style="@style/StatsUnit"
app:layout_constraintBottom_toBottomOf="@+id/stats_max_speed_value"
app:layout_constraintLeft_toRightOf="@+id/stats_max_speed_value"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
tools:text="km/h" />
<!-- Moving speed max -->
<TextView
android:id="@+id/stats_moving_speed_label"
style="@style/StatsSmallLabel"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@id/stats_average_speed_value"
tools:text="Max. Moving Speed" />
<TextView
android:id="@+id/stats_moving_speed_value"
style="@style/StatsSmallValue"
android:value="@string/value_unknown"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/stats_moving_speed_unit"
app:layout_constraintTop_toBottomOf="@+id/stats_moving_speed_label"
tools:text="30.00" />
<TextView
android:id="@+id/stats_moving_speed_unit"
style="@style/StatsUnit"
app:layout_constraintBottom_toBottomOf="@+id/stats_moving_speed_value"
app:layout_constraintLeft_toRightOf="@+id/stats_moving_speed_value"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
tools:text="km/h" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
@@ -0,0 +1,430 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
style="@style/StatsScrollView">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- Guidelines -->
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="vertical"
app:layout_constraintGuide_begin="8dp" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline2"
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline3"
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="vertical"
app:layout_constraintGuide_end="8dp" />
<!-- Distance -->
<TextView
android:id="@+id/stats_distance_label"
style="@style/StatsLargeLabel"
android:text="@string/stats_distance"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/stats_distance_value"
style="@style/StatsLargeValue"
android:value="@string/value_unknown"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/stats_distance_unit"
app:layout_constraintTop_toBottomOf="@+id/stats_distance_label"
tools:text="100" />
<TextView
android:id="@+id/stats_distance_unit"
style="@style/StatsUnit"
app:layout_constraintBottom_toBottomOf="@+id/stats_distance_value"
app:layout_constraintLeft_toRightOf="@+id/stats_distance_value"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
tools:text="km" />
<!-- Activity Type -->
<TextView
android:id="@+id/stats_activity_type_label"
style="@style/StatsLargeLabel"
android:text="@string/track_edit_activity_type_hint"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintTop_toTopOf="parent" />
<Spinner
android:id="@+id/stats_activity_type_icon"
style="@style/StatsLargeValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintBottom_toBottomOf="@+id/stats_distance_value"
app:layout_constraintTop_toTopOf="@+id/stats_distance_value" />
<!-- Total time -->
<TextView
android:id="@+id/stats_total_time_label"
style="@style/StatsLargeLabel"
android:text="@string/stats_total_time"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
app:layout_constraintTop_toBottomOf="@+id/stats_distance_value" />
<TextView
android:id="@+id/stats_total_time_value"
style="@style/StatsLargeValue"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
app:layout_constraintTop_toBottomOf="@+id/stats_total_time_label"
tools:text="00:00:00" />
<!-- Moving time -->
<TextView
android:id="@+id/stats_moving_time_label"
style="@style/StatsLargeLabel"
android:text="@string/stats_moving_time"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintTop_toTopOf="@+id/stats_total_time_label"
app:layout_constraintBottom_toBottomOf="@+id/stats_total_time_label" />
<TextView
android:id="@+id/stats_moving_time_value"
style="@style/StatsLargeValue"
android:value="@string/value_unknown"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@+id/stats_moving_time_label"
tools:text="00:00:00" />
<!-- Horizontal line -->
<View
android:id="@+id/stats_speed_horizontal_line"
style="@style/StatsHorizontalLine"
android:layout_marginBottom="8dp"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@+id/stats_moving_time_value" />
<!-- Speed/pace -->
<TextView
android:id="@+id/stats_speed_label"
style="@style/StatsSmallLabel"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
app:layout_constraintTop_toBottomOf="@id/stats_speed_horizontal_line"
tools:text="Speed" />
<TextView
android:id="@+id/stats_speed_value"
style="@style/StatsSmallValue"
android:value="@string/value_unknown"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/stats_speed_unit"
app:layout_constraintTop_toBottomOf="@+id/stats_speed_label"
tools:text="30.00" />
<TextView
android:id="@+id/stats_speed_unit"
style="@style/StatsUnit"
app:layout_constraintBottom_toBottomOf="@+id/stats_speed_value"
app:layout_constraintLeft_toRightOf="@+id/stats_speed_value"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
tools:text="km/h" />
<!-- Average speed/pace -->
<TextView
android:id="@+id/stats_average_speed_label"
style="@style/StatsSmallLabel"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@id/stats_speed_horizontal_line"
tools:text="Avg. Speed" />
<TextView
android:id="@+id/stats_average_speed_value"
style="@style/StatsSmallValue"
android:value="@string/value_unknown"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/stats_average_speed_unit"
app:layout_constraintTop_toBottomOf="@+id/stats_average_speed_label"
tools:text="30.00" />
<TextView
android:id="@+id/stats_average_speed_unit"
style="@style/StatsUnit"
app:layout_constraintBottom_toBottomOf="@+id/stats_average_speed_value"
app:layout_constraintLeft_toRightOf="@+id/stats_average_speed_value"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
tools:text="km/h" />
<!-- Speed max -->
<TextView
android:id="@+id/stats_max_speed_label"
style="@style/StatsSmallLabel"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
app:layout_constraintTop_toBottomOf="@id/stats_average_speed_value"
tools:text="Max. Speed" />
<TextView
android:id="@+id/stats_max_speed_value"
style="@style/StatsSmallValue"
android:value="@string/value_unknown"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/stats_max_speed_unit"
app:layout_constraintTop_toBottomOf="@+id/stats_max_speed_label"
tools:text="30.00" />
<TextView
android:id="@+id/stats_max_speed_unit"
style="@style/StatsUnit"
app:layout_constraintBottom_toBottomOf="@+id/stats_max_speed_value"
app:layout_constraintLeft_toRightOf="@+id/stats_max_speed_value"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
tools:text="km/h" />
<!-- Moving speed max -->
<TextView
android:id="@+id/stats_moving_speed_label"
style="@style/StatsSmallLabel"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@id/stats_average_speed_value"
tools:text="Max. Moving Speed" />
<TextView
android:id="@+id/stats_moving_speed_value"
style="@style/StatsSmallValue"
android:value="@string/value_unknown"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/stats_moving_speed_unit"
app:layout_constraintTop_toBottomOf="@+id/stats_moving_speed_label"
tools:text="30.00" />
<TextView
android:id="@+id/stats_moving_speed_unit"
style="@style/StatsUnit"
app:layout_constraintBottom_toBottomOf="@+id/stats_moving_speed_value"
app:layout_constraintLeft_toRightOf="@+id/stats_moving_speed_value"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
tools:text="km/h" />
<!-- Horizontal line -->
<View
android:id="@+id/stats_elevation_horizontal_line"
style="@style/StatsHorizontalLine"
android:layout_marginBottom="8dp"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@+id/stats_moving_speed_value" />
<!-- Current elevation -->
<androidx.constraintlayout.widget.Group
android:id="@+id/stats_elevation_current_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="stats_elevation_current_label,stats_elevation_current_value,stats_elevation_current_unit,stats_elevation_horizontal_line" />
<TextView
android:id="@+id/stats_elevation_current_label"
style="@style/StatsSmallLabel"
android:text="@string/stats_elevation"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@id/stats_elevation_horizontal_line" />
<TextView
android:id="@+id/stats_elevation_current_value"
style="@style/StatsSmallValue"
android:value="@string/value_unknown"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/stats_elevation_current_unit"
app:layout_constraintTop_toBottomOf="@+id/stats_elevation_current_label"
tools:text="100" />
<TextView
android:id="@+id/stats_elevation_current_unit"
style="@style/StatsUnit"
app:layout_constraintBottom_toBottomOf="@+id/stats_elevation_current_value"
app:layout_constraintLeft_toRightOf="@+id/stats_elevation_current_value"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
tools:text="m" />
<!-- Coordinate group -->
<androidx.constraintlayout.widget.Group
android:id="@+id/stats_coordinate_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="stats_latitude_label,stats_latitude_value,stats_longitude_label,stats_longitude_value,stats_coordinate_horizontal_line" />
<!-- Horizontal line -->
<View
android:id="@+id/stats_coordinate_horizontal_line"
style="@style/StatsHorizontalLine"
android:layout_marginBottom="8dp"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@+id/stats_elevation_current_value" />
<!-- Latitude -->
<TextView
android:id="@+id/stats_latitude_label"
style="@style/StatsSmallLabel"
android:text="@string/stats_latitude"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
app:layout_constraintTop_toBottomOf="@id/stats_coordinate_horizontal_line" />
<TextView
android:id="@+id/stats_latitude_value"
style="@style/StatsSmallValue"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
app:layout_constraintTop_toBottomOf="@+id/stats_latitude_label"
tools:text="0.834937848" />
<!-- Longitude -->
<TextView
android:id="@+id/stats_longitude_label"
style="@style/StatsSmallLabel"
android:text="@string/stats_longitude"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@id/stats_coordinate_horizontal_line" />
<TextView
android:id="@+id/stats_longitude_value"
style="@style/StatsSmallValue"
android:value="@string/value_unknown"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@+id/stats_longitude_label"
tools:text="0.834937848" />
<!-- Horizontal line -->
<View
android:id="@+id/stats_sensor_horizontal_line"
style="@style/StatsHorizontalLine"
android:layout_marginBottom="8dp"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@+id/stats_latitude_value" />
<!-- Heart rate -->
<androidx.constraintlayout.widget.Group
android:id="@+id/stats_sensor_heart_rate_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="stats_sensor_heart_rate_label,stats_sensor_heart_rate_sensor_value,stats_sensor_heart_rate_value,stats_sensor_heart_rate_unit" />
<TextView
android:id="@+id/stats_sensor_heart_rate_label"
style="@style/StatsLargeLabel"
android:text="@string/sensor_state_heart_rate"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
app:layout_constraintTop_toBottomOf="@id/stats_sensor_horizontal_line" />
<TextView
android:id="@+id/stats_sensor_heart_rate_sensor_value"
style="@style/StatsTinyValue"
android:text="@string/value_unknown"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
app:layout_constraintTop_toBottomOf="@+id/stats_sensor_heart_rate_label"
tools:text="90" />
<TextView
android:id="@+id/stats_sensor_heart_rate_value"
style="@style/StatsLargeValue"
android:value="@string/value_unknown"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
app:layout_constraintTop_toBottomOf="@+id/stats_sensor_heart_rate_sensor_value"
tools:text="90" />
<TextView
android:id="@+id/stats_sensor_heart_rate_unit"
style="@style/StatsUnit"
android:text="@string/sensor_unit_beats_per_minute"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
app:layout_constraintTop_toBottomOf="@+id/stats_sensor_heart_rate_value" />
<!-- Cadence -->
<androidx.constraintlayout.widget.Group
android:id="@+id/stats_sensor_cadence_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="stats_sensor_cadence_label,stats_sensor_cadence_sensor_value,stats_sensor_cadence_value,stats_sensor_cadence_unit" />
<TextView
android:id="@+id/stats_sensor_cadence_label"
style="@style/StatsLargeLabel"
android:text="@string/sensor_state_cadence"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@id/stats_sensor_horizontal_line" />
<TextView
android:id="@+id/stats_sensor_cadence_sensor_value"
style="@style/StatsTinyValue"
android:text="@string/value_unknown"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@+id/stats_sensor_cadence_label"
tools:text="90" />
<TextView
android:id="@+id/stats_sensor_cadence_value"
style="@style/StatsLargeValue"
android:value="@string/value_unknown"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@+id/stats_sensor_cadence_sensor_value"
tools:text="90" />
<TextView
android:id="@+id/stats_sensor_cadence_unit"
style="@style/StatsUnit"
android:text="@string/sensor_unit_rounds_per_minute"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@+id/stats_sensor_cadence_value" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
-332
View File
@@ -1,332 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!--
Copyright 2010 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/StatsScrollView">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!-- Distance and activity type -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- Distance -->
<LinearLayout style="@style/StatsLargeItemContainer">
<TextView
style="@style/StatsLargeLabel"
android:text="@string/stats_distance" />
<LinearLayout style="@style/StatsLargeValueContainer">
<TextView
android:id="@+id/stats_distance_value"
style="@style/StatsLargeValue"
android:value="@string/value_unknown" />
<TextView
android:id="@+id/stats_distance_unit"
style="@style/StatsUnit" />
</LinearLayout>
</LinearLayout>
<!-- Activity type -->
<include
android:id="@+id/stats_activity_type"
layout="@layout/stats_activity_type" />
</LinearLayout>
<!-- Total time and moving time -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- Total time -->
<LinearLayout style="@style/StatsLargeItemContainer">
<TextView
style="@style/StatsLargeLabel"
android:text="@string/stats_total_time" />
<TextView
android:id="@+id/stats_total_time_value"
style="@style/StatsLargeValue" />
</LinearLayout>
<!-- Moving time -->
<LinearLayout style="@style/StatsLargeItemContainer">
<TextView
style="@style/StatsLargeLabel"
android:text="@string/stats_moving_time" />
<TextView
android:id="@+id/stats_moving_time_value"
style="@style/StatsLargeValue"
android:value="@string/value_unknown" />
</LinearLayout>
</LinearLayout>
<!-- Horizontal line -->
<View style="@style/StatsHorizontalLine" />
<!-- Speed/pace and average -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- Speed/pace -->
<LinearLayout
android:id="@+id/stats_speed"
style="@style/StatsSmallItemContainer">
<TextView
android:id="@+id/stats_speed_label"
style="@style/StatsSmallLabel" />
<LinearLayout style="@style/StatsSmallValueContainer">
<TextView
android:id="@+id/stats_speed_value"
style="@style/StatsSmallValue"
android:value="@string/value_unknown" />
<TextView
android:id="@+id/stats_speed_unit"
style="@style/StatsUnit" />
</LinearLayout>
</LinearLayout>
<!-- Average -->
<LinearLayout style="@style/StatsSmallItemContainer">
<TextView
android:id="@+id/stats_average_speed_label"
style="@style/StatsSmallLabel" />
<LinearLayout style="@style/StatsSmallValueContainer">
<TextView
android:id="@+id/stats_average_speed_value"
style="@style/StatsSmallValue"
android:value="@string/value_unknown" />
<TextView
android:id="@+id/stats_average_speed_unit"
style="@style/StatsUnit" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<!-- Speed max and moving -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- Speed max -->
<LinearLayout style="@style/StatsSmallItemContainer">
<TextView
android:id="@+id/stats_max_speed_label"
style="@style/StatsSmallLabel" />
<LinearLayout style="@style/StatsSmallValueContainer">
<TextView
android:id="@+id/stats_max_speed_value"
style="@style/StatsSmallValue"
android:value="@string/value_unknown" />
<TextView
android:id="@+id/stats_max_speed_unit"
style="@style/StatsUnit" />
</LinearLayout>
</LinearLayout>
<!-- Speed moving -->
<LinearLayout style="@style/StatsSmallItemContainer">
<TextView
android:id="@+id/stats_moving_speed_label"
style="@style/StatsSmallLabel" />
<LinearLayout style="@style/StatsSmallValueContainer">
<TextView
android:id="@+id/stats_moving_speed_value"
style="@style/StatsSmallValue"
android:value="@string/value_unknown" />
<TextView
android:id="@+id/stats_moving_speed_unit"
style="@style/StatsUnit" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<View
android:id="@+id/stats_elevation_separator"
style="@style/StatsHorizontalLine" />
<LinearLayout
android:id="@+id/stats_elevation_container"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout style="@style/StatsSmallGroupContainer">
<!-- This is a placeholder -->
</LinearLayout>
<!-- Elevation -->
<LinearLayout style="@style/StatsSmallGroupContainer">
<TextView
style="@style/StatsSmallLabel"
android:text="@string/stats_elevation" />
<TableLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center">
<!-- Current elevation -->
<LinearLayout
style="@style/StatsSmallValueContainer"
android:layout_gravity="start|bottom">
<TextView
android:id="@+id/stats_elevation_current_value"
style="@style/StatsSmallValue"
android:value="@string/value_unknown" />
<TextView
android:id="@+id/stats_elevation_current_unit"
style="@style/StatsUnit" />
</LinearLayout>
</TableLayout>
</LinearLayout>
</LinearLayout>
<!-- Horizontal line -->
<View
android:id="@+id/stats_coordinate_separator"
style="@style/StatsHorizontalLine" />
<!-- Latitude and longitude -->
<LinearLayout
android:id="@+id/stats_coordinate_container"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout style="@style/StatsSmallItemContainer">
<TextView
style="@style/StatsSmallLabel"
android:text="@string/stats_latitude" />
<TextView
android:id="@+id/stats_latitude_value"
style="@style/StatsSmallValue" />
</LinearLayout>
<LinearLayout style="@style/StatsSmallItemContainer">
<TextView
style="@style/StatsSmallLabel"
android:text="@string/stats_longitude" />
<TextView
android:id="@+id/stats_longitude_value"
style="@style/StatsSmallValue"
android:value="@string/value_unknown" />
</LinearLayout>
</LinearLayout>
<View
android:id="@+id/stats_sensor_separator"
style="@style/StatsHorizontalLine" />
<!-- Sensor data -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/stats_sensor_heart_rate_container"
style="@style/StatsLargeItemContainer">
<TextView
style="@style/StatsLargeLabel"
android:text="@string/sensor_state_heart_rate" />
<TextView
android:id="@+id/stats_sensor_heart_rate_sensor_value"
style="@style/StatsTinyValue"
android:text="@string/value_unknown" />
<LinearLayout style="@style/StatsLargeValueContainer">
<TextView
android:id="@+id/stats_sensor_heart_rate_value"
style="@style/StatsLargeValue"
android:value="@string/value_unknown" />
<TextView
style="@style/StatsUnit"
android:text="@string/sensor_unit_beats_per_minute" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/stats_sensor_cadence_container"
style="@style/StatsLargeItemContainer">
<TextView
style="@style/StatsLargeLabel"
android:text="@string/sensor_state_cadence" />
<TextView
android:id="@+id/stats_sensor_cadence_sensor_value"
style="@style/StatsTinyValue"
android:text="@string/value_unknown" />
<LinearLayout style="@style/StatsLargeValueContainer">
<TextView
android:id="@+id/stats_sensor_cadence_value"
style="@style/StatsLargeValue"
android:value="@string/value_unknown" />
<TextView
style="@style/StatsUnit"
android:text="@string/sensor_unit_rounds_per_minute" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</ScrollView>
-2
View File
@@ -32,6 +32,4 @@ limitations under the License.
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<include layout="@layout/track_controller" />
</LinearLayout>
+23
View File
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/toolbar" />
<com.google.android.material.tabs.TabLayout
android:id="@+id/track_detail_activity_tablayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabIndicatorColor="@color/holo_orange_dark" />
<androidx.viewpager.widget.ViewPager
android:id="@+id/track_detail_activity_view_pager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<include layout="@layout/track_controller" />
</LinearLayout>
-6
View File
@@ -15,12 +15,6 @@ limitations under the License.
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/track_detail_insert_marker"
android:icon="@drawable/ic_marker_add_24dp"
android:orderInCategory="1"
app:showAsAction="ifRoom"
android:title="@string/menu_insert_marker" />
<item
android:id="@+id/track_detail_menu_show_on_map"
android:icon="@drawable/ic_map_24dp"
+5
View File
@@ -28,6 +28,11 @@ limitations under the License.
android:title="@string/menu_start_gps"
android:visible="false"
app:showAsAction="ifRoom" />
<item
android:id="@+id/track_list_aggregated_stats"
android:icon="@drawable/ic_statistics_24dp"
android:title="@string/menu_aggregated_statistics"
app:showAsAction="ifRoom" />
<item
android:id="@+id/track_list_markers"
android:icon="@drawable/ic_marker_show_24dp"
+45
View File
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?><!--
Copyright 2011 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/track_detail_insert_marker"
android:icon="@drawable/ic_marker_add_24dp"
android:orderInCategory="1"
app:showAsAction="ifRoom"
android:title="@string/menu_insert_marker" />
<item
android:id="@+id/track_detail_menu_show_on_map"
android:icon="@drawable/ic_map_24dp"
app:showAsAction="ifRoom"
android:title="@string/menu_show_on_map" />
<item
android:id="@+id/track_detail_markers"
android:icon="@drawable/ic_marker_show_24dp"
android:orderInCategory="5"
app:showAsAction="ifRoom"
android:title="@string/menu_markers" />
<item
android:id="@+id/track_detail_edit"
android:icon="@drawable/ic_edit_24dp"
android:orderInCategory="9"
android:title="@string/menu_edit" />
<item
android:id="@+id/track_detail_settings"
android:icon="@drawable/ic_settings_24dp"
android:orderInCategory="13"
android:title="@string/menu_settings" />
</menu>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_logo_color_108dp" />
</adaptive-icon>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_debug_background" />
<foreground android:drawable="@drawable/ic_logo_color_108dp" />
</adaptive-icon>
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

-31
View File
@@ -133,13 +133,9 @@
<string name="generic_yes">نعم</string>
<string name="gps_location_access">\"الدخول إلى الموقع\"</string>
<string name="gps_disabled">نظام تحديد المواقع العالمي (GPS) غير ممكّن. انقر هنا للانتقال إلى %1$s. اضغط على زر الرجوع للعودة.</string>
<string name="gps_disabled_location_mode">حدد وضع تحديد الموقع بدقة عالية. انقر هنا للانتقال إلى %1$s. اضغط على زر الرجوع للعودة.</string>
<string name="gps_disabled_my_location">لا يمكن تحديد الموقع الحالي. تستطيع تمكين مصادر أكثر للموقع على‏ ‏%1$s‏ ‏وتأكد من أنك في مكان مفتوح. حاول مرة أخرى في وقت لاحق.</string>
<string name="gps_disabled_my_location_location_mode">لا يمكن تحديد الموقع الحالي. يمكنك تحديد‏ ‏وضع تحديد الموقع بدقة عالية على %1$s‏ ‏وتأكد من أنك في مكان مفتوح. حاول مرة أخرى في وقت لاحق.</string>
<string name="gps_not_found">لم يتم العثور على نظام تحديد المواقع (GPS) على الجهاز</string>
<string name="gps_starting">بدء نظام تحديد المواقع العالمي (GPS)</string>
<string name="gps_starting_error">تعذر تشغيل نظام تحديد المواقع العالمي (GPS)</string>
<string name="gps_stopping">جارٍ إيقاف نظام تحديد المواقع العالمي (GPS)</string>
<string name="gps_wait_for_better_signal">في انتظار إشارة أفضل ‏‫لنظام تحديد المواقع العالمي (GPS)‬</string>
<string name="gps_wait_for_signal">في انتظار إشارة نظام تحديد المواقع العالمي (GPS)‬</string>
<string name="image_application">تطبيق</string>
@@ -178,20 +174,13 @@
<string name="marker_list_empty_message">ليس لديك أية علامات</string>
<string name="menu_aggregated_statistics">الإحصاءات المجمعة</string>
<string name="menu_delete">حذف</string>
<string name="menu_delete_all">حذف الكل</string>
<string name="menu_edit">تعديل</string>
<string name="menu_export">تصدير</string>
<string name="menu_export_all">تصدير جميع المسارات</string>
<string name="menu_feedback">تعليقات</string>
<string name="menu_help">مساعدة</string>
<string name="menu_help_feedback">المساعدة والتعليقات</string>
<string name="menu_help_forum">منتدى المساعدة</string>
<string name="menu_import_all">استيراد جميع المسارات</string>
<string name="menu_insert_marker">إدراج مُحدد</string>
<string name="menu_insert_photo">جارٍ إدراج الصورة</string>
<string name="menu_map">الخريطة</string>
<string name="menu_markers">العلامات</string>
<string name="menu_play">تشغيل</string>
<string name="menu_search">بحث</string>
<string name="menu_select_all">تحديد الكل</string>
<string name="menu_sensor_state">حالة المستشعر</string>
@@ -208,19 +197,14 @@
<string name="search_global_description">المسارات والمحددات</string>
<string name="search_list_empty_message">لم يطابق بحثك أي مسارات أو علامات</string>
<string name="search_list_marker_track_location">في المسار ‘%1$s’.</string>
<string name="search_voice_prompt">انطق اسم مسار أو علامة</string>
<string name="sensor_state_battery">مستوى شحن البطارية</string>
<string name="sensor_state_cadence">الإيقاع</string>
<string name="sensor_state_cadence_value">%1$d دورة في الدقيقة</string>
<string name="sensor_state_connected">متصل</string>
<string name="sensor_state_connecting">اتصال</string>
<string name="sensor_state_disconnected">غير متصل</string>
<string name="sensor_state_heart_rate">معدل ضربات القلب</string>
<string name="sensor_state_heart_rate_value">%1$d نبضة في الدقيقة</string>
<string name="sensor_state_last_sensor_time">آخر وقت للمستشعر</string>
<string name="sensor_state_power">الطاقة</string>
<string name="sensor_state_power_value">%1$d واط</string>
<string name="sensor_state_sending">إرسال</string>
<string name="settings_not_while_recording">غير متاح أثناء تسجيل مسار</string>
<string name="settings_show">إظهار</string>
<string name="settings_advanced">خيارات متقدمة</string>
@@ -249,22 +233,13 @@
<string name="settings_reset_confirm_title">إعادة التعيين الآن؟</string>
<string name="settings_reset_done">لقد تمت إعادة جميع الإعدادات إلى القيم الافتراضية</string>
<string name="settings_sensor">المستشعر</string>
<string name="settings_sensor_ant_reset_bike_cadence_sensor">إعادة ضبط إيقاع الدراجة</string>
<string name="settings_sensor_ant_reset_combined_bike_sensor">إعادة ضبط الدراجة المجمعة</string>
<string name="settings_sensor_ant_reset_heart_rate_monitor">إعادة ضبط معدل نبضات القلب</string>
<string name="settings_sensor_ant_reset_speed_distance_monitor">إعادة تعيين لوحة القدم</string>
<string name="settings_sensor_bluetooth">البلوتوث</string>
<string name="settings_sensor_bluetooth_pairing">اقتران البلوتوث</string>
<string name="settings_sensor_bluetooth_pairing_summary">فتح إعدادات بلوتوث في Android لإقران الجهاز</string>
<string name="settings_sensor_bluetooth_sensor">مستشعر بلوتوث</string>
<string name="settings_sensor_connected">تم التوصيل بـ %1$s</string>
<string name="settings_stats_coordinate">خط العرض/خط الطول</string>
<string name="settings_stats_rate_title">المعدل المفضل</string>
<string name="settings_stats_units_imperial">وحدات القياس البريطانية (ميل، قدم)</string>
<string name="settings_stats_units_metric">وحدات القياس المترية (كم، م)</string>
<string name="settings_stats_units_title">الوحدات المفضلة</string>
<string name="share_track_emails_hint">عناوين البريد الإلكتروني</string>
<string name="share_track_picker_title">حدد تطبيقًا</string>
<string name="share_track_share_file">مشاركة ملف مسار</string>
<string name="share_track_share_file_body">أعتقد أنك قد تكون مهتمًا بهذا المسار.\n\nلعرض هذا المسار، استخدام برنامج Google Earth أو غيره من البرامج تصميم الخرائط.\n\n%1$s</string>
<string name="share_track_subject">أريد مشاركة مسار معك</string>
@@ -299,9 +274,6 @@
<string name="track_edit_activity_type_hint">نوع النشاط</string>
<string name="track_edit_new_track_title">مسار جديد</string>
<string name="track_list_empty_message">بدء تسجيل مغامرتك التالية هنا</string>
<string name="track_list_record_error">يتعذر بدء التسجيل. ليس هناك إشارة بنظام تحديد المواقع العالمي (GPS). حاول مرة أخرى.</string>
<string name="track_list_record_success">جارٍ الآن تسجيل مسار جديد</string>
<string name="track_widget_config_title">تهيئة عناصر الأداة</string>
<string name="tracks_few">%1$d‏ مسارات</string>
<string name="tracks_many">%1$d‏ مسارًا</string>
<string name="tracks_one">1 مسار</string>
@@ -327,10 +299,8 @@
<string name="value_integer_feet">%1$d قدم</string>
<string name="value_integer_feet_excellent_gps">%1$d قدم (إشارة نظام تحديد المواقع ممتازة)</string>
<string name="value_integer_feet_recommended">%1$d قدم (موصى به)</string>
<string name="value_integer_kilobyte">%1$d‏ كيلوبايت</string>
<string name="value_integer_kilometer">%1$d كم</string>
<string name="value_integer_kilometer_hour">%1$d‏ كم/ساعة</string>
<string name="value_integer_megabyte">%1$d‏ ميغابايت</string>
<string name="value_integer_meter">%1$d م</string>
<string name="value_integer_meter_excellent_gps">%1$d م (إشارة نظام تحديد المواقع ممتازة)</string>
<string name="value_integer_meter_poor_gps">%1$d م (إشارة نظام تحديد المواقع سيئة)</string>
@@ -340,7 +310,6 @@
<string name="value_integer_minute">%1$d دقيقة</string>
<string name="value_integer_percent">%1$d %%</string>
<string name="value_integer_second">%1$d ث</string>
<string name="value_never">مطلقًا</string>
<string name="value_none">لا شيء</string>
<string name="value_off">إيقاف</string>
<string name="value_smallest">الأصغر</string>
-31
View File
@@ -133,13 +133,9 @@
<string name="generic_yes">Yes</string>
<string name="gps_location_access">\'Location access\'</string>
<string name="gps_disabled">GPS not enabled. Tap here to go to %1$s. Press the back button to return.</string>
<string name="gps_disabled_location_mode">Select high-accuracy location mode. Tap here to go to %1$s. Press the back button to return.</string>
<string name="gps_disabled_my_location">Current location cannot be determined. Enable more location sources at %1$s and make sure the sky is visible. Try again later.</string>
<string name="gps_disabled_my_location_location_mode">Current location cannot be determined. Select the high-accuracy location mode at %1$s and make sure the sky is visible. Try again later.</string>
<string name="gps_not_found">No GPS found on the device</string>
<string name="gps_starting">Starting GPS</string>
<string name="gps_starting_error">Unable to start GPS</string>
<string name="gps_stopping">Stopping GPS</string>
<string name="gps_wait_for_better_signal">Waiting for a better GPS signal</string>
<string name="gps_wait_for_signal">Waiting for GPS signal</string>
<string name="image_application">Application</string>
@@ -178,20 +174,13 @@
<string name="marker_list_empty_message">You don\'t have any markers</string>
<string name="menu_aggregated_statistics">Aggregated stats</string>
<string name="menu_delete">Delete</string>
<string name="menu_delete_all">Delete all</string>
<string name="menu_edit">Edit</string>
<string name="menu_export">Export</string>
<string name="menu_export_all">Export all</string>
<string name="menu_feedback">Feedback</string>
<string name="menu_help">Help</string>
<string name="menu_help_feedback">Help &amp; feedback</string>
<string name="menu_help_forum">Help forum</string>
<string name="menu_import_all">Import all</string>
<string name="menu_insert_marker">Insert marker</string>
<string name="menu_insert_photo">Insert photo</string>
<string name="menu_map">Map</string>
<string name="menu_markers">Markers</string>
<string name="menu_play">Play</string>
<string name="menu_search">Search</string>
<string name="menu_select_all">Select all</string>
<string name="menu_sensor_state">Sensor state</string>
@@ -208,19 +197,14 @@
<string name="search_global_description">Tracks and markers</string>
<string name="search_list_empty_message">No tracks or markers matched your search</string>
<string name="search_list_marker_track_location">In track ‘%1$s’.</string>
<string name="search_voice_prompt">Say the name of a track or marker</string>
<string name="sensor_state_battery">Battery level</string>
<string name="sensor_state_cadence">Cadence</string>
<string name="sensor_state_cadence_value">%1$d rpm</string>
<string name="sensor_state_connected">Connected</string>
<string name="sensor_state_connecting">Connecting</string>
<string name="sensor_state_disconnected">Disconnected</string>
<string name="sensor_state_heart_rate">Heart rate</string>
<string name="sensor_state_heart_rate_value">%1$d bpm</string>
<string name="sensor_state_last_sensor_time">Last sensor time</string>
<string name="sensor_state_power">Power</string>
<string name="sensor_state_power_value">%1$d W</string>
<string name="sensor_state_sending">Sending</string>
<string name="settings_not_while_recording">Not available while recording a track</string>
<string name="settings_show">Show</string>
<string name="settings_advanced">Advanced</string>
@@ -249,22 +233,13 @@
<string name="settings_reset_confirm_title">Reset now?</string>
<string name="settings_reset_done">All settings have been reverted to default values</string>
<string name="settings_sensor">Sensor</string>
<string name="settings_sensor_ant_reset_bike_cadence_sensor">Reset bike cadence</string>
<string name="settings_sensor_ant_reset_combined_bike_sensor">Reset combined bike</string>
<string name="settings_sensor_ant_reset_heart_rate_monitor">Reset heart rate</string>
<string name="settings_sensor_ant_reset_speed_distance_monitor">Reset foot pod</string>
<string name="settings_sensor_bluetooth">Bluetooth</string>
<string name="settings_sensor_bluetooth_pairing">Bluetooth pairing</string>
<string name="settings_sensor_bluetooth_pairing_summary">Open Android\'s Bluetooth settings to pair a sensor</string>
<string name="settings_sensor_bluetooth_sensor">Bluetooth sensor</string>
<string name="settings_sensor_connected">Connected to %1$s</string>
<string name="settings_stats_coordinate">Latitude/Longitude</string>
<string name="settings_stats_rate_title">Preferred rate</string>
<string name="settings_stats_units_imperial">Imperial (miles, ft)</string>
<string name="settings_stats_units_metric">Metric (km, m)</string>
<string name="settings_stats_units_title">Preferred units</string>
<string name="share_track_emails_hint">Email addresses</string>
<string name="share_track_picker_title">Select an application</string>
<string name="share_track_share_file">Share track file</string>
<string name="share_track_share_file_body">I think you might be interested in this track.\n\nTo view this track, use Google Earth or other
mapping software.\n\n%1$s</string>
@@ -300,9 +275,6 @@
<string name="track_edit_activity_type_hint">Activity type</string>
<string name="track_edit_new_track_title">New Track</string>
<string name="track_list_empty_message">Start recording your next adventure here</string>
<string name="track_list_record_error">Unable to start recording. No GPS signal. Try again.</string>
<string name="track_list_record_success">Now recording a new track</string>
<string name="track_widget_config_title">Configure Widget Items</string>
<string name="tracks_few">%1$d tracks</string>
<string name="tracks_many">%1$d tracks</string>
<string name="tracks_one">1 track</string>
@@ -328,10 +300,8 @@
<string name="value_integer_feet">%1$d ft</string>
<string name="value_integer_feet_excellent_gps">%1$d ft (excellent GPS)</string>
<string name="value_integer_feet_recommended">%1$d ft (recommended)</string>
<string name="value_integer_kilobyte">%1$d kB</string>
<string name="value_integer_kilometer">%1$d km</string>
<string name="value_integer_kilometer_hour">%1$d km/h</string>
<string name="value_integer_megabyte">%1$d MB</string>
<string name="value_integer_meter">%1$d m</string>
<string name="value_integer_meter_excellent_gps">%1$d m (excellent GPS)</string>
<string name="value_integer_meter_poor_gps">%1$d m (poor GPS)</string>
@@ -341,7 +311,6 @@
<string name="value_integer_minute">%1$d min</string>
<string name="value_integer_percent">%1$d %%</string>
<string name="value_integer_second">%1$d s</string>
<string name="value_never">Never</string>
<string name="value_none">None</string>
<string name="value_off">Off</string>
<string name="value_smallest">Smallest</string>
-31
View File
@@ -133,13 +133,9 @@
<string name="generic_yes">Sí</string>
<string name="gps_location_access">“Acceso a ubicaciones”</string>
<string name="gps_disabled">El GPS no está habilitado. Puntea aquí para ir a %1$s. Para volver, presiona el botón Atrás.</string>
<string name="gps_disabled_location_mode">Selecciona el modo de ubicación de alta precisión. Toca aquí para acceder a %1$s. Para volver a la pantalla anterior, presiona el botón Atrás.</string>
<string name="gps_disabled_my_location">No se puede determinar la ubicación actual. Habilita más fuentes de ubicación en %1$s y asegúrate de que se pueda ver el cielo. Vuelve a intentarlo más tarde.</string>
<string name="gps_disabled_my_location_location_mode">No se puede determinar la ubicación actual. Selecciona el modo de ubicación de alta precisión en %1$s y asegúrate de que se pueda ver el cielo. Vuelve a intentarlo más tarde.</string>
<string name="gps_not_found">No se encontró ningún GPS en el dispositivo.</string>
<string name="gps_starting">Iniciando GPS</string>
<string name="gps_starting_error">No se puede iniciar el GPS.</string>
<string name="gps_stopping">Deteniendo GPS</string>
<string name="gps_wait_for_better_signal">Esperando una mejor señal de GPS</string>
<string name="gps_wait_for_signal">Esperando señal de GPS</string>
<string name="image_application">Aplicación</string>
@@ -178,21 +174,14 @@
<string name="marker_list_empty_message">No tienes ningún marcador.</string>
<string name="menu_aggregated_statistics">Estadíst. globales</string>
<string name="menu_delete">Eliminar</string>
<string name="menu_delete_all">Eliminar todos</string>
<string name="menu_edit">Editar</string>
<string name="menu_export">Exportar</string>
<string name="menu_export_all">Exportar todo</string>
<string name="menu_feedback">Comentarios</string>
<string name="menu_help">Ayuda</string>
<string name="menu_help_feedback">Ayuda y comentarios</string>
<string name="menu_help_forum">Foro de ayuda</string>
<string name="menu_import_all">Importar todo</string>
<string name="menu_insert_marker">Insertar marcador</string>
<string name="menu_insert_photo">Insertar foto</string>
<string name="menu_insert_gallery_img">Insertar imagen de galería</string>
<string name="menu_map">Mapa</string>
<string name="menu_markers">Marcadores</string>
<string name="menu_play">Reproducir</string>
<string name="menu_search">Buscar</string>
<string name="menu_select_all">Seleccionar todo</string>
<string name="menu_sensor_state">Estado del sensor</string>
@@ -210,19 +199,14 @@
<string name="search_global_description">Recorridos y marcadores</string>
<string name="search_list_empty_message">No hay rutas ni marcadores que coincidan con tu búsqueda.</string>
<string name="search_list_marker_track_location">En el recorrido “%1$s”</string>
<string name="search_voice_prompt">Di el nombre de la ruta o del marcador.</string>
<string name="sensor_state_battery">Nivel de la batería</string>
<string name="sensor_state_cadence">Cadencia</string>
<string name="sensor_state_cadence_value">%1$d rpm</string>
<string name="sensor_state_connected">Conectado</string>
<string name="sensor_state_connecting">Conectándose</string>
<string name="sensor_state_disconnected">Desconectado</string>
<string name="sensor_state_heart_rate">Frecuencia cardíaca</string>
<string name="sensor_state_heart_rate_value">%1$d bpm</string>
<string name="sensor_state_last_sensor_time">Última hora del sensor</string>
<string name="sensor_state_power">Potencia</string>
<string name="sensor_state_power_value">%1$d W</string>
<string name="sensor_state_sending">Enviando</string>
<string name="settings_not_while_recording">No está disponible durante la grabación de un recorrido.</string>
<string name="settings_show">Mostrar</string>
<string name="settings_advanced">Opciones avanzadas</string>
@@ -251,22 +235,13 @@
<string name="settings_reset_confirm_title">¿Restablecer ahora?</string>
<string name="settings_reset_done">Se restablecieron los valores predeterminados de todas las opciones de configuración.</string>
<string name="settings_sensor">Sensor</string>
<string name="settings_sensor_ant_reset_bike_cadence_sensor">Rest. cad. de bicicleta</string>
<string name="settings_sensor_ant_reset_combined_bike_sensor">Rest. bicicleta comb.</string>
<string name="settings_sensor_ant_reset_heart_rate_monitor">Restablecer frecuencia cardíaca</string>
<string name="settings_sensor_ant_reset_speed_distance_monitor">Restablecer podómetro</string>
<string name="settings_sensor_bluetooth">Bluetooth</string>
<string name="settings_sensor_bluetooth_pairing">Vinculación Bluetooth</string>
<string name="settings_sensor_bluetooth_pairing_summary">Se abre la configuración de Bluetooth de Android para vincular un sensor.</string>
<string name="settings_sensor_bluetooth_sensor">Sensor de Bluetooth</string>
<string name="settings_sensor_connected">Conectado a %1$s</string>
<string name="settings_stats_coordinate">Latitud/longitud</string>
<string name="settings_stats_rate_title">Tasa preferida</string>
<string name="settings_stats_units_imperial">Imperiales (millas, pies)</string>
<string name="settings_stats_units_metric">Métricas (km, m)</string>
<string name="settings_stats_units_title">Unidades preferidas</string>
<string name="share_track_emails_hint">Direcciones de correo electrónico</string>
<string name="share_track_picker_title">Seleccione una aplicación</string>
<string name="share_track_share_file">Compartir el archivo del recorrido</string>
<string name="share_track_share_file_body">Creo que este recorrido podría interesarte.\n\nPara ver este recorrido, usa Google Earth u otro software de mapas.\n\n%1$s</string>
<string name="share_track_subject">Me gustaría compartir un recorrido contigo</string>
@@ -302,9 +277,6 @@
<string name="track_edit_activity_type_hint">Tipo de actividad</string>
<string name="track_edit_new_track_title">Nuevo recorrido</string>
<string name="track_list_empty_message">Comienza a grabar aquí tu próxima aventura.</string>
<string name="track_list_record_error">No se puede iniciar la grabación. No se recibe señal de GPS. Vuelve a intentarlo.</string>
<string name="track_list_record_success">Grabando una nueva ruta</string>
<string name="track_widget_config_title">Configurar elementos de widget</string>
<string name="tracks_few">%1$d recorridos</string>
<string name="tracks_many">%1$d recorridos</string>
<string name="tracks_one">1 recorrido</string>
@@ -330,10 +302,8 @@
<string name="value_integer_feet">%1$d pies</string>
<string name="value_integer_feet_excellent_gps">%1$d pies (señal de GPS excelente)</string>
<string name="value_integer_feet_recommended">%1$d pies (recomendado)</string>
<string name="value_integer_kilobyte">%1$d KB</string>
<string name="value_integer_kilometer">%1$d km</string>
<string name="value_integer_kilometer_hour">%1$d km/h</string>
<string name="value_integer_megabyte">%1$d MB</string>
<string name="value_integer_meter">%1$d m</string>
<string name="value_integer_meter_excellent_gps">%1$d m (señal de GPS excelente)</string>
<string name="value_integer_meter_poor_gps">%1$d m (señal de GPS deficiente)</string>
@@ -343,7 +313,6 @@
<string name="value_integer_minute">%1$d min.</string>
<string name="value_integer_percent">%1$d %%</string>
<string name="value_integer_second">%1$d s</string>
<string name="value_never">Nunca</string>
<string name="value_none">Ninguno</string>
<string name="value_off">Desactivado</string>
<string name="value_smallest">Menor</string>
-31
View File
@@ -133,13 +133,9 @@
<string name="generic_yes">Да</string>
<string name="gps_location_access">„Достъп до местоположението“</string>
<string name="gps_disabled">GPS не е активиран. Докоснете тук, за да отидете на %1$s. Натиснете бутона за назад, за да се върнете.</string>
<string name="gps_disabled_location_mode">Изберете режима за висока точност на местоположението. Докоснете тук, за да отидете в/ъв %1$s. Натиснете бутона за назад, за да се върнете.</string>
<string name="gps_disabled_my_location">Текущото местоположение не може да бъде определено. Активирайте още източници на местоположение от %1$s и се уверете, че небето се вижда. Опитайте отново по-късно.</string>
<string name="gps_disabled_my_location_location_mode">Текущото местоположение не може да бъде определено. Изберете режима за висока точност на местоположението от %1$s и се уверете, че небето се вижда. Опитайте отново по-късно.</string>
<string name="gps_not_found">Няма намерен GPS на устройството.</string>
<string name="gps_starting">GPS се включва.</string>
<string name="gps_starting_error">GPS не може да стартира.</string>
<string name="gps_stopping">GPS се изключва.</string>
<string name="gps_wait_for_better_signal">Изчаква се по-добър сигнал за GPS.</string>
<string name="gps_wait_for_signal">Изчаква се сигнал за GPS.</string>
<string name="image_application">Приложение</string>
@@ -179,20 +175,13 @@
<string name="marker_list_empty_message">Нямате маркери.</string>
<string name="menu_aggregated_statistics">Събрани статист. данни</string>
<string name="menu_delete">Изтриване</string>
<string name="menu_delete_all">Изтриване на всички</string>
<string name="menu_edit">Редактиране</string>
<string name="menu_export">Експортиране</string>
<string name="menu_export_all">Експорт. на всички</string>
<string name="menu_feedback">Отзиви</string>
<string name="menu_help">Помощ</string>
<string name="menu_help_feedback">Помощ и отзиви</string>
<string name="menu_help_forum">Помощен форум</string>
<string name="menu_import_all">Импорт. на всички</string>
<string name="menu_insert_marker">Вмъкване на маркер</string>
<string name="menu_insert_photo">Вмъкване на снимка</string>
<string name="menu_map">Карта</string>
<string name="menu_markers">Маркери</string>
<string name="menu_play">Старт</string>
<string name="menu_search">Търсене</string>
<string name="menu_select_all">Избиране на всички</string>
<string name="menu_sensor_state">Състояние на сензора</string>
@@ -209,19 +198,14 @@
<string name="search_global_description">Маршрути и маркери</string>
<string name="search_list_empty_message">Няма маршрути или маркери, отговарящи на търсените от вас.</string>
<string name="search_list_marker_track_location">В маршрут „%1$s“.</string>
<string name="search_voice_prompt">Произнесете името на маршрут или маркер.</string>
<string name="sensor_state_battery">Ниво на батерията</string>
<string name="sensor_state_cadence">Такт</string>
<string name="sensor_state_cadence_value">%1$d об/мин</string>
<string name="sensor_state_connected">Свързано</string>
<string name="sensor_state_connecting">Свързва се</string>
<string name="sensor_state_disconnected">Изключено</string>
<string name="sensor_state_heart_rate">Сърдечен ритъм</string>
<string name="sensor_state_heart_rate_value">%1$d уд/мин</string>
<string name="sensor_state_last_sensor_time">Последно използване на сензора</string>
<string name="sensor_state_power">Захранване</string>
<string name="sensor_state_power_value">%1$d W</string>
<string name="sensor_state_sending">Изпраща се</string>
<string name="settings_not_while_recording">Не е налице при записване на маршрут.</string>
<string name="settings_show">Показване</string>
<string name="settings_advanced">Разширени</string>
@@ -250,22 +234,13 @@
<string name="settings_reset_confirm_title">Да се зададе ли повторно сега?</string>
<string name="settings_reset_done">Всички настройки са възстановени до стойностите по подразбиране.</string>
<string name="settings_sensor">Сензор</string>
<string name="settings_sensor_ant_reset_bike_cadence_sensor">Нулиране на велос. каданс</string>
<string name="settings_sensor_ant_reset_combined_bike_sensor">Нулиране на сензорите</string>
<string name="settings_sensor_ant_reset_heart_rate_monitor">Повторно задаване на пулса</string>
<string name="settings_sensor_ant_reset_speed_distance_monitor">Повторно задаване на крачкомер</string>
<string name="settings_sensor_bluetooth">Bluetooth</string>
<string name="settings_sensor_bluetooth_pairing">Сдвояване чрез Bluetooth</string>
<string name="settings_sensor_bluetooth_pairing_summary">Отваря настройките за Bluetooth на Android, за да се сдвои сензор</string>
<string name="settings_sensor_bluetooth_sensor">Bluetooth сензор</string>
<string name="settings_sensor_connected">Свързан с %1$s</string>
<string name="settings_stats_coordinate">Ширина и дължина</string>
<string name="settings_stats_rate_title">Предпочитана мярка</string>
<string name="settings_stats_units_imperial">Имперски (мил, фт)</string>
<string name="settings_stats_units_metric">Метрични (км, м)</string>
<string name="settings_stats_units_title">Предпочитани единици</string>
<string name="share_track_emails_hint">Имейл адреси</string>
<string name="share_track_picker_title">Избор на приложение</string>
<string name="share_track_share_file">Споделяне на файл с маршрут</string>
<string name="share_track_share_file_body">Мисля, че този маршрут може да Ви заинтересува.\n\nЗа да го видите, използвайте Google Земя или друг
картографски софтуер.\n\n%1$s</string>
@@ -301,9 +276,6 @@
<string name="track_edit_activity_type_hint">Тип дейност</string>
<string name="track_edit_new_track_title">Нов маршрут</string>
<string name="track_list_empty_message">Започнете да записвате следващото си приключение тук.</string>
<string name="track_list_record_error">Записът не може да стартира. Няма сигнал за GPS. Опитайте отново.</string>
<string name="track_list_record_success">В момента се записва нов маршрут.</string>
<string name="track_widget_config_title">Конфигуриране на елементите на приспособления</string>
<string name="tracks_few">%1$d маршрута</string>
<string name="tracks_many">%1$d маршрута</string>
<string name="tracks_one">1 маршрут</string>
@@ -329,10 +301,8 @@
<string name="value_integer_feet">%1$d фт</string>
<string name="value_integer_feet_excellent_gps">%1$d фт (отличен GPS)</string>
<string name="value_integer_feet_recommended">%1$d фт (препоръчително)</string>
<string name="value_integer_kilobyte">%1$d КБ</string>
<string name="value_integer_kilometer">%1$d км</string>
<string name="value_integer_kilometer_hour">%1$d км/ч</string>
<string name="value_integer_megabyte">%1$d МБ</string>
<string name="value_integer_meter">%1$d м</string>
<string name="value_integer_meter_excellent_gps">%1$d м (отличен GPS)</string>
<string name="value_integer_meter_poor_gps">%1$d м (слаб GPS)</string>
@@ -342,7 +312,6 @@
<string name="value_integer_minute">%1$d мин</string>
<string name="value_integer_percent">%1$d %%</string>
<string name="value_integer_second">%1$d сек</string>
<string name="value_never">Никога</string>
<string name="value_none">Никоя</string>
<string name="value_off">Изключено</string>
<string name="value_smallest">Най-малката</string>
-32
View File
@@ -133,15 +133,10 @@
<string name="generic_yes">Sí</string>
<string name="gps_location_access">\"Accés a la ubicació\"</string>
<string name="gps_disabled">El GPS no està activat. Premeu aquí per anar a %1$s. Premeu el botó Enrere per tornar.</string>
<string name="gps_disabled_location_mode">Seleccioneu el mode d\'ubicació d\'alta precisió. Toqueu aquí per anar a %1$s. Premeu el botó de retorn per anar enrere.</string>
<string name="gps_disabled_my_location">No es pot determinar la ubicació actual. Activeu més fonts d\'ubicació a %1$s i assegureu-vos que
es vegi el cel. Torneu-ho a provar més tard.</string>
<string name="gps_disabled_my_location_location_mode">No es pot determinar la ubicació actual. Seleccioneu el mode d\'ubicació d\'alta precisió a %1$s i assegureu-vos que
es vegi el cel. Torneu-ho a provar més tard.</string>
<string name="gps_not_found">No s\'ha trobat el GPS al dispositiu.</string>
<string name="gps_starting">El GPS s\'està iniciant.</string>
<string name="gps_starting_error">El GPS no es pot iniciar.</string>
<string name="gps_stopping">El GPS s\'està aturant.</string>
<string name="gps_wait_for_better_signal">S\'està esperant un senyal GPS de millor qualitat.</string>
<string name="gps_wait_for_signal">S\'està esperant el senyal GPS.</string>
<string name="image_application">Aplicació</string>
@@ -181,20 +176,13 @@ es vegi el cel. Torneu-ho a provar més tard.</string>
<string name="marker_list_empty_message">No teniu cap marcador.</string>
<string name="menu_aggregated_statistics">Estadístiques globals</string>
<string name="menu_delete">Suprimeix</string>
<string name="menu_delete_all">Suprimeix-les totes</string>
<string name="menu_edit">Edita</string>
<string name="menu_export">Exporta</string>
<string name="menu_export_all">Exporta-ho tot</string>
<string name="menu_feedback">Comentaris</string>
<string name="menu_help">ajuda</string>
<string name="menu_help_feedback">Ajuda i comentaris</string>
<string name="menu_help_forum">Fòrum d\'ajuda</string>
<string name="menu_import_all">Importa-ho tot</string>
<string name="menu_insert_marker">Insereix un marcador</string>
<string name="menu_insert_photo">Insereix una foto</string>
<string name="menu_map">Mapa</string>
<string name="menu_markers">Marcadors</string>
<string name="menu_play">Reprodueix</string>
<string name="menu_search">Cerca</string>
<string name="menu_select_all">Selecciona-ho tot</string>
<string name="menu_sensor_state">Estat del sensor</string>
@@ -211,19 +199,14 @@ es vegi el cel. Torneu-ho a provar més tard.</string>
<string name="search_global_description">Pistes i marcadors</string>
<string name="search_list_empty_message">No hi ha cap ruta ni marcador que coincideixi amb els criteris de cerca.</string>
<string name="search_list_marker_track_location">A la ruta \"%1$s\".</string>
<string name="search_voice_prompt">Digueu el nom d\'una ruta o d\'un marcador.</string>
<string name="sensor_state_battery">Nivell de la bateria</string>
<string name="sensor_state_cadence">Cadència</string>
<string name="sensor_state_cadence_value">%1$d rpm</string>
<string name="sensor_state_connected">Connectat</string>
<string name="sensor_state_connecting">S\'està connectant</string>
<string name="sensor_state_disconnected">Desconnectat</string>
<string name="sensor_state_heart_rate">Freqüència cardíaca</string>
<string name="sensor_state_heart_rate_value">%1$d ppm</string>
<string name="sensor_state_last_sensor_time">Darrera hora del sensor</string>
<string name="sensor_state_power">Potència</string>
<string name="sensor_state_power_value">%1$d W</string>
<string name="sensor_state_sending">S\'està enviant</string>
<string name="settings_not_while_recording">No està disponible durant l\'enregistrament d\'una ruta.</string>
<string name="settings_show">Mostra\'n més</string>
<string name="settings_advanced">Avançades</string>
@@ -252,22 +235,13 @@ es vegi el cel. Torneu-ho a provar més tard.</string>
<string name="settings_reset_confirm_title">Voleu restablir-ho ara?</string>
<string name="settings_reset_done">S\'ha recuperat la configuració predeterminada.</string>
<string name="settings_sensor">Sensor</string>
<string name="settings_sensor_ant_reset_bike_cadence_sensor">Restableix cadència bici</string>
<string name="settings_sensor_ant_reset_combined_bike_sensor">Restableix bicicleta combinada</string>
<string name="settings_sensor_ant_reset_heart_rate_monitor">Reinicia el pulsòmetre</string>
<string name="settings_sensor_ant_reset_speed_distance_monitor">Reinicia el podòmetre</string>
<string name="settings_sensor_bluetooth">Bluetooth</string>
<string name="settings_sensor_bluetooth_pairing">Sincronització de Bluetooth</string>
<string name="settings_sensor_bluetooth_pairing_summary">Obre la configuració de Bluetooth d\'Android per a la sincronització d\'un sensor.</string>
<string name="settings_sensor_bluetooth_sensor">Sensor de Bluetooth</string>
<string name="settings_sensor_connected">Connectat a %1$s</string>
<string name="settings_stats_coordinate">Latitud/Longitud:</string>
<string name="settings_stats_rate_title">Mesura preferida</string>
<string name="settings_stats_units_imperial">Sistema anglosaxó (milles, peus)</string>
<string name="settings_stats_units_metric">Sistema mètric (km, m)</string>
<string name="settings_stats_units_title">Unitats preferides</string>
<string name="share_track_emails_hint">Adreces electròniques</string>
<string name="share_track_picker_title">Seleccioneu una aplicació</string>
<string name="share_track_share_file">Comparteix el fitxer de la pista</string>
<string name="share_track_share_file_body">Crec que aquesta ruta et podria interessar.\n\nLa pots veure amb Google Earth o qualsevol altre programari de mapatge.\n\n%1$s</string>
<string name="share_track_subject">Vull compartir una ruta amb tu</string>
@@ -302,9 +276,6 @@ es vegi el cel. Torneu-ho a provar més tard.</string>
<string name="track_edit_activity_type_hint">Tipus d\'activitat</string>
<string name="track_edit_new_track_title">Nova ruta</string>
<string name="track_list_empty_message">Comenceu a enregistrar aquí la vostra pròxima aventura.</string>
<string name="track_list_record_error">No es pot iniciar l\'enregistrament. No hi ha senyal del GPS. Torneu-ho a provar.</string>
<string name="track_list_record_success">S\'està enregistrant una ruta nova</string>
<string name="track_widget_config_title">Configuració d\'elements del widget</string>
<string name="tracks_few">%1$d rutes</string>
<string name="tracks_many">%1$d rutes</string>
<string name="tracks_one">1 ruta</string>
@@ -330,10 +301,8 @@ es vegi el cel. Torneu-ho a provar més tard.</string>
<string name="value_integer_feet">%1$d peus</string>
<string name="value_integer_feet_excellent_gps">%1$d peus (senyal de GPS excel·lent)</string>
<string name="value_integer_feet_recommended">%1$d peus (recomanat)</string>
<string name="value_integer_kilobyte">%1$d KB</string>
<string name="value_integer_kilometer">%1$d km</string>
<string name="value_integer_kilometer_hour">%1$d km/h</string>
<string name="value_integer_megabyte">%1$d MB</string>
<string name="value_integer_meter">%1$d m</string>
<string name="value_integer_meter_excellent_gps">%1$d m (GPS amb bona senyal)</string>
<string name="value_integer_meter_poor_gps">%1$d m (GPS amb poca senyal)</string>
@@ -343,7 +312,6 @@ es vegi el cel. Torneu-ho a provar més tard.</string>
<string name="value_integer_minute">%1$d min</string>
<string name="value_integer_percent">%1$d %%</string>
<string name="value_integer_second">%1$d s</string>
<string name="value_never">Mai</string>
<string name="value_none">Cap</string>
<string name="value_off">Desactivat</string>
<string name="value_smallest">Més petit</string>
+149 -32
View File
@@ -1,5 +1,90 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?><!--
Copyright 2010 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="about_preference_title">O OpenTracks</string>
<string name="about_description"><i> OpenTracks </i> je sportovní sledovací aplikace, která zcela respektuje vaše soukromí.</string>
<string name="about_url">Webová stránka projektu: <a href="%1$s">%1$s</a></string>
<string name="about_version_name">Název verze: %1$s</string>
<string name="about_version_code">Kód verze: %1$d</string>
<string name="about_history">OpenTracks je vidlička <a href="https://code.google.com/archive/p/mytracks/"> <i> MyTracks Google </i> </a> (v roce 2016 ukončena).</string>
<string name="about_libraries">Knihovny</string>
<!-- Help -->
<string name="help_feature_title">OpenTracks má následující funkce:</string>
<string name="help_feature_content">
* vytvářet GPS stopy \ n
* použijte snímač srdeční frekvence (pouze Bluetooth LE) \ n
* hlasová oznámení (podle času nebo vzdálenosti) \ n
* vytvářejte značky (včetně obrázků) \ n
* funguje zcela offline \ n
* zobrazit skladby na mapě (viz níže)</string>
<string name="help_track_map_title">Jak ukázat skladbu na mapě?</string>
<string name="help_track_map_content">
Použijte malou ikonu mapy.\n
a) (živé aktualizace) Nainstalujte <a href="https://github.com/OpenTracksApp/OSMDashboard">OSMDashboard</a>.
Poskytuje online nebo offline mapy prostřednictvím <a href="https://www.openstreetmap.org">OpenStreetMap</a>.\n
Ve skutečnosti je OSMDashboard samostatná aplikace, která má přístup (dočasně) pouze k datům stop, které se bud(ou) zobrazovat.\n
b) Prostřednictvím „normální“ mapové aplikace (např. <a href="http://osmand.net/">OsmAnd</a> a <a href="https://maps.me/">MAPS.ME</a>).
Tyto aplikace musí podporovat formát souboru KMZ (pouze umístění a časová razítka).
Ve skutečnosti musí aplikace podporovat <i>ACTION_VIEW</i> pomocí MIME <i>application/vnd.google-earth.kmz</i>.</string>
<string name="help_storage_pictures_title">Jak ukládá OpenTracks obrázky pořízené jako značky?</string>
<string name="help_storage_pictures_content">Jsou uloženy v interním úložišti aplikace (tj. Přístupné pouze v rámci OpenTracks).</string>
<string name="help_track_export_title">Jak mohu exportovat / sdílet zaznamenané stopy?</string>
<string name="help_track_export_content">
Skladby lze exportovat z Nastavení jako KMZ, KML nebo GPX.
KMZ / KML všechna data; Pouze umístění GPX.
Skladby sdílené pomocí ikony sdílení <i> </i> jsou sdíleny jako KMZ.</string>
<string name="help_data_google_play_services_title">Vyžaduje služba OpenTracks / používá službu Google Play?</string>
<string name="help_recording_title">Jak OpenTracks zaznamenává data?</string>
<string name="help_recording_content">
OpenTracks používá GPS senzor zařízení k nepřetržitému zaznamenávání polohy.
Pokud zařízení GPS hlásí nepřesná data (např. Polohu, rychlost, nadmořskou výšku), OpenTracks s tím nemůže nic udělat.</string>
<string name="help_data_storage_title">Jak OpenTracks ukládá data senzorů?</string>
<string name="help_data_storage_content">
Data senzoru se ukládají na zaznamenané místo.
Pokud jde o snímač srdeční frekvence, znamená to, že na každé místo je uloženo pouze <i> jedno </i> měření srdeční frekvence.
Pokud stojíte v klidu nebo jste uvnitř, nebudou zaznamenána žádná data ze senzorů (ale budou zobrazena).</string>
<string name="help_gps_troubleshooting_title">OpenTracks nezaznamenává místa?</string>
<string name="help_gps_troubleshooting_content">
Co můžete udělat: \ n
a) zkontrolujte, zda je GPS povoleno, \ n
b) zlepšit příjem GPS (např. jít venku), \ n
c) zkontrolujte, zda používáte aplikaci <a href="https://f-droid.org/en/packages/com.android.gpstest.osmdroid/"> GPSTest </a> a \ n
d) deaktivujte úsporu energie. \ n
\ n
Pokud všechno nepomůže, nahláste chybu.</string>
<string name="help_support_title">Jak mohu podporovat OpenTracks?</string>
<string name="help_support_content">
Můžete: \ n
a) šířit slovo o OpenTracks, \ n
b) <a href="https://github.com/OpenTracksApp/OpenTracks/issues"> navrhnout funkce </a>, \ n
c) <a href="https://github.com/OpenTracksApp/OpenTracks/issues"> nahlaste chyby </a>, \ n
d) pomoc při vývoji softwaru, \ n
e) nakupujte v <a href="https://play.google.com/store/apps/details?id=de.dennisguse.opentracks.playstore"> Obchod Google Play </a>, \ n
f) darovat, a \ n
g) udělejte, co si myslíte, že pomůže OpenTracks.</string>
<!-- Activity Type -->
<string name="activity_type_airplane">letadlo</string>
<string name="activity_type_atv">terénní auta</string>
<string name="activity_type_biking">cyklistika</string>
@@ -66,6 +151,8 @@
<string name="activity_type_walking">chůze</string>
<string name="activity_type_water_skiing">vodní lyžování</string>
<string name="activity_type_wind_surfing">windsurfing</string>
<string name="app_not_installed_show_on_map">Nainstalujte prosím aplikaci, která podporuje prezentaci mapových dat.</string>
<!-- Description -->
<string name="description_activity_type">Typ aktivity: %1$s</string>
<string name="description_average_moving_pace_in_minute">Průměrné tempo pohybu: %1$s min/km (%2$s min/míli)</string>
<string name="description_average_moving_speed">Průměrná rychlost přesunu: %1$.2f km/h (%2$.1f mil/h)</string>
@@ -93,6 +180,7 @@
<string name="description_sensor_cadence">Tempo šlapání (ot./min)</string>
<string name="description_sensor_heart_rate">Srdeční frekvence (údery/min)</string>
<string name="description_sensor_power">Výkon (W)</string>
<string name="description_default_speed_or_pace">Podle typu činnosti</string>
<string name="description_speed_imperial">Rychlost (míle/h)</string>
<string name="description_speed_metric">Rychlost (km/h)</string>
<string name="description_time">Doba</string>
@@ -100,19 +188,25 @@
<string name="description_total_time">Celková doba: %1$s</string>
<string name="description_track_point">Bod</string>
<string name="description_track_segment">Segment</string>
<!-- Export -->
<string name="export_all_option">Vše ve formátu %1$s</string>
<string name="export_all_title">Export do externího úložiště</string>
<string name="export_with_photos">s fotkami</string>
<string name="export_without_photos">bez fotografií</string>
<string name="export_error">Trasy byly exportovány do složky %3$s (%1$d z %2$s).</string>
<string name="export_option">jako %1$s do složky %2$s</string>
<string name="export_progress_message">Exportování do složky %1$s…</string>
<string name="export_success">Trasy (celkem %1$s) byly exportovány do složky %2$s.</string>
<string name="export_title">Export do…</string>
<!-- External Storage -->
<!-- Files -->
<string name="files_few">%1$d soubory</string>
<string name="files_many">%1$d souborů</string>
<string name="files_one">1 soubor</string>
<string name="files_other">%1$d souborů</string>
<string name="files_two">2 soubory</string>
<string name="files_zero">0 souborů</string>
<!-- Generic -->
<string name="generic_add">Přidat</string>
<string name="generic_cancel">Zrušit</string>
<string name="generic_delete_all_confirm_title">Smazat vše?</string>
@@ -131,17 +225,15 @@
<string name="generic_success_title">Úspěch</string>
<string name="generic_tracks">Trasy</string>
<string name="generic_yes">Ano</string>
<!-- Gps -->
<string name="gps_location_access">Přístup k poloze</string>
<string name="gps_disabled">Systém GPS není zapnutý. Klepnutím sem přejdete na možnost %1$s. Stisknutím tlačítka Zpět se vrátíte.</string>
<string name="gps_disabled_location_mode">Vyberte režim vysoké přesnosti určování polohy. Klepnutím sem přejdete do části %1$s. Stisknutím tlačítka Zpět se vrátíte.</string>
<string name="gps_disabled_my_location">Aktuální polohu nelze určit. V části %1$s aktivujte další zdroje pro zjišťování polohy a ujistěte se, že vidíte oblohu. Zkuste to znovu později.</string>
<string name="gps_disabled_my_location_location_mode">Aktuální polohu nelze určit. V části %1$s vyberte režim vysoké přesnosti určování polohy a ujistěte se, že vidíte oblohu. Zkuste to znovu později.</string>
<string name="gps_not_found">Zařízení neobsahuje GPS</string>
<string name="gps_starting">Spouštění GPS</string>
<string name="gps_starting_error">GPS nelze spustit</string>
<string name="gps_stopping">Zastavování GPS</string>
<string name="gps_wait_for_better_signal">Čekání na lepší signál GPS</string>
<string name="gps_wait_for_signal">Čekání na signál GPS</string>
<!-- Image -->
<string name="image_application">Aplikace</string>
<string name="image_arrow">Šipka</string>
<string name="image_marker">Značka</string>
@@ -152,6 +244,7 @@
<string name="image_record">Zaznamenat</string>
<string name="image_stop">Ukončit</string>
<string name="image_track">Trasa</string>
<!-- Import -->
<string name="import_error">Trasy byly importovány ze složky %3$s (%1$d z %2$s).</string>
<string name="import_no_directory">Složka %1$s neexistuje.</string>
<string name="import_no_file">Nebyly nalezeny žádné soubory, které by bylo možné importovat. Připojte zařízení k počítači a umístěte soubory, které chcete importovat, do složky %1$s.</string>
@@ -160,9 +253,11 @@
<string name="import_selection_option">Všechny soubory %1$s</string>
<string name="import_selection_title">Import z externího úložiště</string>
<string name="import_success">Trasy (celkem %1$s) byly importovány ze složky %2$s.</string>
<!-- Marker -->
<string name="marker_add_error">Značku nelze vložit. Signál GPS není dostupný. Zkuste to znovu.</string>
<string name="marker_add_success">Značka byla vložena.</string>
<string name="marker_add_canceled">Zrušeno, značky nebyly přidány.</string>
<string name="marker_add_photo_canceled">Zrušeno, nebyla přidána žádná značka</string>
<string name="marker_delete_all_confirm_message">Všechny značky této trasy budou trvale smazány ze zařízení.</string>
<string name="marker_delete_one_confirm_message">Značka bude trvale smazána ze zařízení.</string>
<string name="marker_delete_one_confirm_title">Smazat značku?</string>
@@ -172,26 +267,24 @@
<string name="marker_name_format">Značka %1$d</string>
<string name="marker_split_name_format">Dělicí značka %1$d</string>
<string name="marker_title">%1$d z %2$d</string>
<!-- Marker Detail -->
<string name="marker_detail_statistics_title">Od poslední dělicí značky:</string>
<!-- Marker Edit -->
<string name="marker_edit_marker_type">Typ značky (například vodopád…)</string>
<string name="marker_edit_marker_type_hint">Typ značky</string>
<!-- Marker List -->
<string name="marker_list_empty_message">Nemáte žádné značky.</string>
<!-- Menu -->
<string name="menu_aggregated_statistics">Souhrnná statistika</string>
<string name="menu_delete">Smazat</string>
<string name="menu_delete_all">Smazat vše</string>
<string name="menu_edit">Upravit</string>
<string name="menu_export">Exportovat</string>
<string name="menu_export_all">Exportovat vše</string>
<string name="menu_feedback">Zpětná vazba</string>
<string name="menu_help">Nápověda</string>
<string name="menu_help_feedback">Nápověda a názory</string>
<string name="menu_help_forum">Fórum nápovědy</string>
<string name="menu_import_all">Importovat vše</string>
<string name="menu_insert_marker">Vložit značku</string>
<string name="menu_insert_photo">Vložit fotku</string>
<string name="menu_map">Mapa</string>
<string name="menu_insert_gallery_img">Vložte obrázek galerie</string>
<string name="menu_markers">Značky</string>
<string name="menu_play">Přehrát</string>
<string name="menu_search">Vyhledat</string>
<string name="menu_select_all">Vybrat vše</string>
<string name="menu_sensor_state">Stav senzoru</string>
@@ -203,30 +296,41 @@
<string name="menu_stop_gps">Ukončit GPS</string>
<string name="menu_view_photo">Zobrazit fotku</string>
<string name="menu_voice_frequency">Frekvence oznámení</string>
<string name="menu_resume_track">Obnovit skladbu</string>
<!-- OpenTracks -->
<string name="app_name">OpenTracks</string>
<string name="recording_service">Služba pro záznam</string>
<!-- Permission -->
<string name="permission_gps_failed">OpenTracks vyžaduje povolení k používání GPS.</string>
<!-- Search -->
<string name="search_global_description">Trasy a značky</string>
<string name="search_list_empty_message">Vyhledávacímu dotazu neodpovídají žádné trasy ani značky.</string>
<string name="search_list_marker_track_location">Na trase %1$s</string>
<string name="search_voice_prompt">Vyslovte název trasy nebo značky.</string>
<!-- Sensor State -->
<string name="sensor_state_battery">Stav baterie</string>
<string name="sensor_state_cadence">Frekvence šlapání</string>
<string name="sensor_state_cadence_value">%1$d ot./min</string>
<string name="sensor_state_connected">Připojeno</string>
<string name="sensor_state_connecting">Připojování</string>
<string name="sensor_state_disconnected">Odpojeno</string>
<string name="sensor_state_heart_rate">Srdeční frekvence</string>
<string name="sensor_state_heart_rate_value">%1$d úderů/min</string>
<string name="sensor_state_last_sensor_time">Poslední čas senzoru</string>
<string name="sensor_state_power">Napájení</string>
<string name="sensor_state_power_value">%1$d W</string>
<string name="sensor_state_sending">Odesílání</string>
<string name="sensor_not_known">Senzor %1$s není znám. Zkontrolujte nastavení.</string>
<string name="sensor_could_not_scan">Nelze vyhledat zařízení Bluetooth (chyba %1$i).</string>
<string name="bluetooth_disabled">Aktivujte prosím Bluetooth.</string>
<string name="settings_not_while_recording">Při záznamu trasy není tato funkce dostupná.</string>
<string name="settings_show">Zobrazit</string>
<!-- Settings Advanced -->
<string name="settings_advanced">Pokročilé</string>
<!-- Settings Chart -->
<string name="settings_chart_by_distance">Podle vzdálenosti</string>
<string name="settings_chart_by_time">Podle doby</string>
<string name="settings_chart_x_axis">Osa X</string>
<!-- Settings Recording -->
<string name="settings_recording_show_on_lockscreen_while_recording_title">Zobrazit statistiky na obrazovce uzamčení</string>
<string name="settings_recording_show_on_lockscreen_while_recording_summary">Během nahrávání zobrazte statistiky bez odemknutí zařízení.</string>
<string name="settings_recording_keep_screen_on_while_recording_title">Nechte obrazovku zapnutou</string>
<string name="settings_recording_keep_screen_on_while_recording_summary">Během nahrávání udržujte obrazovku zapnutou.</string>
<string name="settings_recording">Záznam</string>
<string name="settings_recording_auto_resume_track_timeout_always_summary">Po restartu vždy pokračovat v záznamu</string>
<string name="settings_recording_auto_resume_track_timeout_never_summary">Po restartu nikdy nepokračovat v záznamu</string>
@@ -244,30 +348,32 @@
<string name="settings_recording_track_name_date_local_option">Datum (místní)</string>
<string name="settings_recording_track_name_number_option">Číslo</string>
<string name="settings_recording_track_name_title">Výchozí název trasy</string>
<!-- Settings Reset -->
<string name="settings_reset">Resetovat</string>
<string name="settings_reset_confirm_message">Všechna nastavení budou obnovena na výchozí hodnoty.</string>
<string name="settings_reset_confirm_title">Resetovat nyní?</string>
<string name="settings_reset_done">Všechna nastavení byla obnovena na výchozí hodnoty.</string>
<string name="settings_error_initial_values_restored">Litujeme, ale došlo k chybě. Všechna nastavení byla vrácena na výchozí hodnoty.</string>
<!-- Settings Sensor -->
<string name="settings_sensor">Senzor</string>
<string name="settings_sensor_ant_reset_bike_cadence_sensor">Resetovat tempo šlapání</string>
<string name="settings_sensor_ant_reset_combined_bike_sensor">Resetovat údaje o kole</string>
<string name="settings_sensor_ant_reset_heart_rate_monitor">Resetovat tepovou frekvenci</string>
<string name="settings_sensor_ant_reset_speed_distance_monitor">Resetovat krokoměr</string>
<string name="settings_sensor_bluetooth">Bluetooth</string>
<string name="settings_sensor_bluetooth_pairing">Párování zařízení Bluetooth</string>
<string name="settings_sensor_bluetooth_pairing_summary">Otevřete v Androidu nastavení Bluetooth a spárujte senzor.</string>
<string name="settings_sensor_bluetooth_sensor">Senzor Bluetooth</string>
<string name="settings_sensor_connected">Připojeno k senzoru %1$s</string>
<string name="settings_sensor_connecting">Připojeno k senzoru %1$s</string>
<string name="settings_sensor_disconnected">Odpojeno od %1$s</string>
<string name="settings_sensor_wheel_circumference">Velikost kola (ETRTO)</string>
<!-- Settings Stats -->
<string name="settings_stats_coordinate">Zeměpisná šířka/délka</string>
<string name="settings_stats_rate_title">Preferovaná rychlost</string>
<string name="settings_stats_units_imperial">Imperiální jednotky (míle, stopy)</string>
<string name="settings_stats_units_metric">Metrické jednotky (km, m)</string>
<string name="settings_stats_units_title">Preferované jednotky</string>
<string name="share_track_emails_hint">E-mailové adresy</string>
<string name="share_track_picker_title">Zvolte aplikaci</string>
<!-- Share Track -->
<string name="share_track_share_file">Sdílet soubor trasy</string>
<string name="share_track_share_file_body">Možná by vás mohla zajímat tato trasa.\n\nChcete-li ji zobrazit, použijte Google Earth nebo jiný mapový software.\n\n%1$s</string>
<string name="share_track_subject">Chci s vámi sdílet trasu</string>
<!-- Stats -->
<string name="stats_average_moving_pace">Průměrné tempo pohybu</string>
<string name="stats_average_moving_speed">Průměrná rychlost pohybu</string>
<string name="stats_average_pace">Průměrné tempo</string>
@@ -286,28 +392,36 @@
<string name="stats_speed">Rychlost</string>
<string name="stats_distance">Vzdálenost</string>
<string name="stats_total_time">Celková doba</string>
<!-- Track -->
<string name="track_name_format">Trasa %1$d</string>
<string name="track_record_notification">Záznam trasy…</string>
<string name="track_recording_notification_accuracy">Přesnost polohy: %1$s</string>
<string name="track_markers">Značky na trase %1$s</string>
<!-- Track Delete -->
<string name="track_delete_one_confirm_message">Trasa a související značky budou trvale smazány ze zařízení.</string>
<string name="track_delete_one_confirm_title">Smazat trasu?</string>
<string name="track_delete_multiple_confirm_message">Vybrané trasy a jejich značky budou trvale smazány ze zařízení.</string>
<string name="track_delete_progress_message">Mazání…</string>
<!-- Track Detail -->
<string name="track_detail_chart_tab">Graf</string>
<string name="track_detail_stats_tab">Statistika</string>
<string name="track_detail_record_success">Zaznamenávání nové trasy</string>
<string name="track_detail_resume_success">Nyní se obnovuje skladba</string>
<!-- Track Edit -->
<string name="track_edit_activity_type">Typ aktivity (například chůze…)</string>
<string name="track_edit_activity_type_hint">Typ aktivity</string>
<string name="track_edit_new_track_title">Nová trasa</string>
<!-- Track List -->
<string name="track_list_empty_message">Zde zaznamenejte příští výpravu</string>
<string name="track_list_record_error">Záznam nelze spustit. Signál GPS není dostupný. Zkuste to znovu.</string>
<string name="track_list_record_success">Zaznamenávání nové trasy</string>
<string name="track_widget_config_title">Konfigurace widgetů</string>
<!-- Track Widget -->
<!-- Tracks -->
<string name="tracks_few">%1$d trasy</string>
<string name="tracks_many">%1$d tras</string>
<string name="tracks_one">1 trasa</string>
<string name="tracks_other">%1$d tras</string>
<string name="tracks_two">2 trasy</string>
<string name="tracks_zero">0 tras</string>
<!-- Unit -->
<string name="unit_feet">stop</string>
<string name="unit_kilometer">km</string>
<string name="unit_kilometer_per_hour">km/h</string>
@@ -316,6 +430,7 @@
<string name="unit_mile_per_hour">mil/h</string>
<string name="unit_minute_per_kilometer">min/km</string>
<string name="unit_minute_per_mile">min/míle</string>
<!-- Value -->
<string name="value_adapt_accuracy">Přizpůsobit na přesnost</string>
<string name="value_adapt_battery_life">Přizpůsobit výdrži baterie</string>
<string name="value_always">Vždy</string>
@@ -327,10 +442,8 @@
<string name="value_integer_feet">%1$d stop</string>
<string name="value_integer_feet_excellent_gps">%1$d stop (vynikající signál GPS)</string>
<string name="value_integer_feet_recommended">%1$d stop (doporučeno)</string>
<string name="value_integer_kilobyte">%1$d kB</string>
<string name="value_integer_kilometer">%1$d km</string>
<string name="value_integer_kilometer_hour">%1$d km/h</string>
<string name="value_integer_megabyte">%1$d MB</string>
<string name="value_integer_meter">%1$d m</string>
<string name="value_integer_meter_excellent_gps">%1$d m (vynikající signál GPS)</string>
<string name="value_integer_meter_poor_gps">%1$d m (špatný signál GPS)</string>
@@ -340,11 +453,11 @@
<string name="value_integer_minute">%1$d min</string>
<string name="value_integer_percent">%1$d %%</string>
<string name="value_integer_second">%1$d s</string>
<string name="value_never">Nikdy</string>
<string name="value_none">Žádné</string>
<string name="value_off">Vypnuto</string>
<string name="value_smallest">Nejmenší</string>
<string name="value_smallest_recommended">Nejnižší hodnota (doporučeno)</string>
<!-- Voice -->
<string name="voice_hours_few">%1$d hodiny</string>
<string name="voice_hours_many">%1$d hodin</string>
<string name="voice_hours_one">1 hodina</string>
@@ -391,6 +504,7 @@
<string name="voice_total_distance_miles_two">celková vzdálenost 2 míle</string>
<string name="voice_total_distance_miles_zero">celková vzdálenost 0 mil</string>
<string name="voice_total_distance_zero">Celková vzdálenost Mých tras je nulová.</string>
<!-- Waypoint Type -->
<string name="waypoint_type_atm">Bankomat</string>
<string name="waypoint_type_bank">banka</string>
<string name="waypoint_type_bar">bar</string>
@@ -442,4 +556,7 @@
<string name="waypoint_type_waterfall">vodopád</string>
<string name="waypoint_type_water_fountain">kašna</string>
<string name="waypoint_type_waypoint">navigační bod</string>
<!-- Share image -->
<string name="share_image_subject">Chtěl bych s vámi sdílet obrázek</string>
<string name="share_image_body">Myslím, že by vás mohl tento obrázek zajímat.</string>
</resources>
+150 -33
View File
@@ -1,5 +1,91 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?><!--
Copyright 2010 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="about_preference_title">Om OpenTracks</string>
<string name="about_description"><i> OpenTracks </i> er en sportssporingsapplikation, der fuldt ud respekterer dit privatliv.</string>
<string name="about_url">Projektwebside: <a href="%1$s">%1$s</a></string>
<string name="about_version_name">Versionsnavn: %1$s</string>
<string name="about_version_code">Versionskode: %1$d</string>
<string name="about_history">OpenTracks er en gaffel fra <a href="https://code.google.com/archive/p/mytracks/"> <i> Googles MyTracks </i> </a> (afviklet i 2016).</string>
<string name="about_libraries">Biblioteker</string>
<!-- Help -->
<string name="help_feature_title">OpenTracks har følgende funktioner:</string>
<string name="help_feature_content">
* Opret GPS-spor \n
* Brug en pulssensor (kun Bluetooth LE) \n
* stemmemeddelelser (efter tid eller afstand) \n
* Opret markører (inkl. billeder) \n
* fungerer helt offline \n
* vis spor på et kort (se nedenfor)</string>
<string name="help_track_map_title">Hvordan viser man et spor på et kort?</string>
<string name="help_track_map_content">
Brug det lille kortikon. \n
a)
(liveopdateringer) Installer <a href="https://github.com/OpenTracksApp/OSMDashboard">OSMDashboard</a>.
Det giver online eller offline kort via <a href="https://www.openstreetmap.org">OpenStreetMap</a>.\n
Faktisk er OSMDashboard en separat app, der kun kan få adgang til (midlertidigt) adgang til dataene fra spor (e), der skal vises.\n
b) Via et normalt kortprogram (f.eks. <a href="http://osmand.net/">OsmAnd</a> og <a href="https://maps.me/">MAPS.ME</a>).
Disse app skal understøtte KMZ-filformatet (kun placeringer og tidsstempler).
Faktisk skal en app understøtte <i>ACTION_VIEW</i> med MIME <i>application/vnd.google-earth.kmz</i>.</string>
<string name="help_storage_pictures_title">Hvordan gemmer OpenTracks billeder, der blev taget som markører?</string>
<string name="help_storage_pictures_content">Disse gemmes i appens interne lager (dvs. kun tilgængelig inden for OpenTracks).</string>
<string name="help_track_export_title">Hvordan kan jeg eksportere / dele indspillede numre?</string>
<string name="help_track_export_content">
Spor kan eksporteres fra indstillingerne som KMZ, KML eller GPX.
KMZ / KML alle data; GPX kun placeringer.
Spor, der deles via <i>delingsikonet</i> deles som KMZ.</string>
<string name="help_data_google_play_services_title">Kræver/bruger OpenTracks Google Play Service?</string>
<string name="help_recording_title">Hvordan registrerer OpenTracks data?</string>
<string name="help_recording_content">
OpenTracks bruger enhedens GPS-sensor til at registrere placeringen kontinuerligt.
Hvis GPS-enheden rapporterer unøjagtige data (f.eks. Placering, hastighed, højde), kan OpenTracks ikke gøre noget ved det.</string>
<string name="help_data_storage_title">Hvordan gemmer OpenTracks sensordata?</string>
<string name="help_data_storage_content">
Sensordata gemmes pr. Optaget placering.
Med hensyn til en pulssensor betyder det, at der kun er <i> en </i> måling af hjertefrekvensen lagret pr. Placering.
Hvis du står stille eller er indendørs, registreres ingen sensordata (men de vil blive vist).</string>
<string name="help_gps_troubleshooting_title">OpenTracks optager ikke placeringer?</string>
<string name="help_gps_troubleshooting_content">
Hvad du kan gøre:\n
a) Kontroller, om GPS er aktiveret,\n
b) forbedre GPS-modtagelse (f.eks. gå udendørs), \n
c) Kontroller, om du har appen <a href="https://f-droid.org/en/packages/com.android.gpstest.osmdroid/"> GPSTest </a> og \n
d) deaktiver strømbesparelse. \n
\n
Hvis alt ikke hjælper, skal du rapportere en fejl.</string>
<string name="help_support_title">Hvordan kan jeg støtte OpenTracks?</string>
<string name="help_support_content">
Du kan: \n
a) sprede ordet om OpenTracks, \n
b) <a href="https://github.com/OpenTracksApp/OpenTracks/issues"> foreslå funktioner </a>, \n
c) <a href="https://github.com/OpenTracksApp/OpenTracks/issues"> rapportfejl </a>, \n
d) hjælp til softwareudvikling, \n
e) køb i <a href="https://play.google.com/store/apps/details?id=de.dennisguse.opentracks.playstore"> Google Play Store </a>, \n
f) donere, og \n
g) gør hvad du synes hjælper OpenTracks.</string>
<!-- Activity Type -->
<string name="activity_type_airplane">fly</string>
<string name="activity_type_atv">Terrængående køretøj</string>
<string name="activity_type_biking">cykling</string>
@@ -66,6 +152,8 @@
<string name="activity_type_walking">til fods</string>
<string name="activity_type_water_skiing">vandski</string>
<string name="activity_type_wind_surfing">windsurfing</string>
<string name="app_not_installed_show_on_map">Installer venligst en app, der understøtter præsentation af kortdata.</string>
<!-- Description -->
<string name="description_activity_type">Aktivitetstype: %1$s</string>
<string name="description_average_moving_pace_in_minute">Gennemsnitsfart: %1$s min./km (%2$s min./mil)</string>
<string name="description_average_moving_speed">Gennemsnitlig bevægelseshastighed: %1$.2f km/t (%2$.1f mil/t)</string>
@@ -93,6 +181,7 @@
<string name="description_sensor_cadence">Kadence (omdr./min.)</string>
<string name="description_sensor_heart_rate">Puls (slag/min.)</string>
<string name="description_sensor_power">Effekt (W)</string>
<string name="description_default_speed_or_pace">Efter aktivitetstype</string>
<string name="description_speed_imperial">Hastighed (mil/t)</string>
<string name="description_speed_metric">Hastighed (km/t)</string>
<string name="description_time">Tid</string>
@@ -100,19 +189,25 @@
<string name="description_total_time">Samlet tid: %1$s</string>
<string name="description_track_point">Punkt</string>
<string name="description_track_segment">Segment</string>
<!-- Export -->
<string name="export_all_option">Alle som %1$s</string>
<string name="export_all_title">Eksportér til eksternt lager</string>
<string name="export_with_photos">med fotos</string>
<string name="export_without_photos">uden fotos</string>
<string name="export_error">%1$d af %2$s blev eksporteret til %3$s</string>
<string name="export_option">som %1$s til %2$s</string>
<string name="export_progress_message">Eksporterer til %1$s…</string>
<string name="export_success">%1$s blev eksporteret til %2$s</string>
<string name="export_title">Eksportér til…</string>
<!-- External Storage -->
<!-- Files -->
<string name="files_few">%1$d filer</string>
<string name="files_many">%1$d filer</string>
<string name="files_one">1 fil</string>
<string name="files_other">%1$d filer</string>
<string name="files_two">2 filer</string>
<string name="files_zero">0 filer</string>
<!-- Generic -->
<string name="generic_add">Tilføj</string>
<string name="generic_cancel">Annuller</string>
<string name="generic_delete_all_confirm_title">Skal alle slettes?</string>
@@ -131,19 +226,16 @@
<string name="generic_success_title">Gennemført</string>
<string name="generic_tracks">Ruter</string>
<string name="generic_yes">Ja</string>
<!-- Gps -->
<string name="gps_location_access">\"Placeringsadgang\"</string>
<string name="gps_disabled">GPS er ikke aktiveret. Tryk her for at gå til %1$s. Tryk på knappen Tilbage for at vende tilbage.</string>
<string name="gps_disabled_location_mode">Vælg placeringstilstanden Høj nøjagtighed. Tryk her for at gå til %1$s. Tryk på knappen igen for at vende tilbage.</string>
<string name="gps_disabled_my_location">Den aktuelle placering kan ikke bestemmes. Aktivér flere placeringskilder i %1$s, og sørg for, at
himlen er synlig. Prøv igen senere.</string>
<string name="gps_disabled_my_location_location_mode">Den aktuelle placering kan ikke bestemmes. Aktivér flere placeringskilder i %1$s, og sørg
for, at himlen er synlig. Prøv igen senere.</string>
<string name="gps_not_found">Der blev ikke fundet nogen GPS på enheden</string>
<string name="gps_starting">Starter GPS</string>
<string name="gps_starting_error">GPS kunne ikke startes</string>
<string name="gps_stopping">Stopper GPS</string>
<string name="gps_wait_for_better_signal">Venter på et bedre GPS-signal</string>
<string name="gps_wait_for_signal">Venter på GPS-signal</string>
<!-- Image -->
<string name="image_application">Applikation</string>
<string name="image_arrow">Pil</string>
<string name="image_marker">Markør</string>
@@ -154,6 +246,7 @@
<string name="image_record">Registrer</string>
<string name="image_stop">Stop</string>
<string name="image_track">Rute</string>
<!-- Import -->
<string name="import_error">%1$d af %2$s er importeret fra %3$s</string>
<string name="import_no_directory">%1$s findes ikke</string>
<string name="import_no_file">Der var ingen filer at importere. Slut din enhed til din computer, og placer filer, der skal
@@ -163,9 +256,11 @@
<string name="import_selection_option">Alle %1$s</string>
<string name="import_selection_title">Importér fra eksternt lager</string>
<string name="import_success">%1$s er importeret fra %2$s</string>
<!-- Marker -->
<string name="marker_add_error">En markør kan ikke indsættes. Intet GPS-signal. Prøv igen.</string>
<string name="marker_add_success">Der blev indsat en markør</string>
<string name="marker_add_canceled">Annulleret, ingen markør blev tilføjet</string>
<string name="marker_add_photo_canceled">Annulleret, ingen fotomarkering tilføjet</string>
<string name="marker_delete_all_confirm_message">Alle markører for denne rute slettes permanent fra enheden</string>
<string name="marker_delete_one_confirm_message">Markøren slettes permanent fra enheden</string>
<string name="marker_delete_one_confirm_title">Vil du slette markøren?</string>
@@ -175,26 +270,24 @@
<string name="marker_name_format">Markør %1$d</string>
<string name="marker_split_name_format">Deling %1$d</string>
<string name="marker_title">%1$d af %2$d</string>
<!-- Marker Detail -->
<string name="marker_detail_statistics_title">Siden sidste delte markør:</string>
<!-- Marker Edit -->
<string name="marker_edit_marker_type">Markørtype (f.eks. vandfald)</string>
<string name="marker_edit_marker_type_hint">Markørtype</string>
<!-- Marker List -->
<string name="marker_list_empty_message">Du har ingen markører</string>
<!-- Menu -->
<string name="menu_aggregated_statistics">Samlet statistik</string>
<string name="menu_delete">Slet</string>
<string name="menu_delete_all">Slet alle</string>
<string name="menu_edit">Rediger</string>
<string name="menu_export">Eksportér</string>
<string name="menu_export_all">Eksportér alle</string>
<string name="menu_feedback">Feedback</string>
<string name="menu_help">Hjælp</string>
<string name="menu_help_feedback">Hjælp og feedback</string>
<string name="menu_help_forum">Hjælpeforum</string>
<string name="menu_import_all">Importér alle</string>
<string name="menu_insert_marker">Indsæt markør</string>
<string name="menu_insert_photo">Indsæt billede</string>
<string name="menu_map">Kort</string>
<string name="menu_insert_gallery_img">Indsæt galleribillede</string>
<string name="menu_markers">Markører</string>
<string name="menu_play">Afspil</string>
<string name="menu_search">Søg</string>
<string name="menu_select_all">Vælg alle</string>
<string name="menu_sensor_state">Sensortilstand</string>
@@ -206,30 +299,41 @@
<string name="menu_stop_gps">Stop GPS</string>
<string name="menu_view_photo">Se billede</string>
<string name="menu_voice_frequency">Stemmefrekvens</string>
<string name="menu_resume_track">Genoptag sporet</string>
<!-- OpenTracks -->
<string name="app_name">OpenTracks</string>
<string name="recording_service">Registreringstjeneste</string>
<!-- Permission -->
<string name="permission_gps_failed">OpenTracks kræver tilladelse til at bruge GPS.</string>
<!-- Search -->
<string name="search_global_description">Ruter og markører</string>
<string name="search_list_empty_message">Ingen ruter eller markører matchede din søgning</string>
<string name="search_list_marker_track_location">I ruten \"%1$s\".</string>
<string name="search_voice_prompt">Sig navnet på en rute eller markør</string>
<!-- Sensor State -->
<string name="sensor_state_battery">Batteriniveau</string>
<string name="sensor_state_cadence">Kadence</string>
<string name="sensor_state_cadence_value">%1$d omdr/min</string>
<string name="sensor_state_connected">Tilsluttet</string>
<string name="sensor_state_connecting">Opretter forbindelse</string>
<string name="sensor_state_disconnected">Afbrudt</string>
<string name="sensor_state_heart_rate">Puls</string>
<string name="sensor_state_heart_rate_value">%1$d slag per minut</string>
<string name="sensor_state_last_sensor_time">Sidste sensortid</string>
<string name="sensor_state_power">Strøm</string>
<string name="sensor_state_power_value">%1$d W</string>
<string name="sensor_state_sending">Sender</string>
<string name="sensor_not_known">Sensor %1$s er ukendt. Kontroller indstillingerne.</string>
<string name="sensor_could_not_scan">Kunne ikke scanne efter Bluetooth-enheder (fejl %1$i).</string>
<string name="bluetooth_disabled">Aktivér Bluetooth.</string>
<string name="settings_not_while_recording">Ikke tilgængelig ved registrering af rute</string>
<string name="settings_show">Vis</string>
<!-- Settings Advanced -->
<string name="settings_advanced">Avanceret</string>
<!-- Settings Chart -->
<string name="settings_chart_by_distance">Efter afstand</string>
<string name="settings_chart_by_time">Efter tid</string>
<string name="settings_chart_x_axis">X-akse</string>
<!-- Settings Recording -->
<string name="settings_recording_show_on_lockscreen_while_recording_title">Vis statistik på låseskærm</string>
<string name="settings_recording_show_on_lockscreen_while_recording_summary">Vis statistik, mens du optager, uden at låse enheden op.</string>
<string name="settings_recording_keep_screen_on_while_recording_title">Hold skærmen tændt</string>
<string name="settings_recording_keep_screen_on_while_recording_summary">Hold skærmen tændt, mens du optager.</string>
<string name="settings_recording">Registrering</string>
<string name="settings_recording_auto_resume_track_timeout_always_summary">Genoptag altid en registrering efter en genstart</string>
<string name="settings_recording_auto_resume_track_timeout_never_summary">Genoptag altid en registrering efter en genstart</string>
@@ -247,31 +351,33 @@
<string name="settings_recording_track_name_date_local_option">Dato (lokal)</string>
<string name="settings_recording_track_name_number_option">Nummer</string>
<string name="settings_recording_track_name_title">Standardnavn på spor</string>
<!-- Settings Reset -->
<string name="settings_reset">Nulstil</string>
<string name="settings_reset_confirm_message">Alle indstillinger vil blive ændret til standardværdierne..</string>
<string name="settings_reset_confirm_title">Vil du nulstille nu?</string>
<string name="settings_reset_done">Alle indstillinger er blevet gendannet til standardværdierne</string>
<string name="settings_error_initial_values_restored">Beklager, men der opstod en fejl. Alle indstillinger er vendt tilbage til standardværdierne.</string>
<!-- Settings Sensor -->
<string name="settings_sensor">Sensor</string>
<string name="settings_sensor_ant_reset_bike_cadence_sensor">Nulstil cykelkadence</string>
<string name="settings_sensor_ant_reset_combined_bike_sensor">Nulstil kombineret cykel</string>
<string name="settings_sensor_ant_reset_heart_rate_monitor">Nulstil puls</string>
<string name="settings_sensor_ant_reset_speed_distance_monitor">Nulstil fodsensor</string>
<string name="settings_sensor_bluetooth">Bluetooth</string>
<string name="settings_sensor_bluetooth_pairing">Bluetooth-parring</string>
<string name="settings_sensor_bluetooth_pairing_summary">Åbn indstillinger for Bluetooth i Android for at parre en sensor</string>
<string name="settings_sensor_bluetooth_sensor">Bluetooth-sensor</string>
<string name="settings_sensor_connected">Tilsluttet %1$s</string>
<string name="settings_sensor_connecting">Tilsluttet %1$s</string>
<string name="settings_sensor_disconnected">Frakoblet %1$s</string>
<string name="settings_sensor_wheel_circumference">Hjulstørrelse (ETRTO)</string>
<!-- Settings Stats -->
<string name="settings_stats_coordinate">Breddegrad/længdegrad</string>
<string name="settings_stats_rate_title">Foretrukkenfartenhed</string>
<string name="settings_stats_units_imperial">Britisk (mil, ft)</string>
<string name="settings_stats_units_metric">Metrisk (km, m)</string>
<string name="settings_stats_units_title">Foretrukne enheder</string>
<string name="share_track_emails_hint">E-mailadresser</string>
<string name="share_track_picker_title">Vælg en applikation</string>
<!-- Share Track -->
<string name="share_track_share_file">Del rutefil</string>
<string name="share_track_share_file_body">Du kunne måske være interesseret i denne rute.\n\nDu kan bruge Google Earth eller anden
kortlægningssoftware til at se ruten.\n\n%1$s</string>
<string name="share_track_subject">Jeg vil gerne dele en rute med dig</string>
<!-- Stats -->
<string name="stats_average_moving_pace">Gns. bevægelsestempo</string>
<string name="stats_average_moving_speed">Gns. bevægelseshastighed</string>
<string name="stats_average_pace">Gns. tempo</string>
@@ -290,28 +396,36 @@
<string name="stats_speed">Hastighed</string>
<string name="stats_distance">Afstand</string>
<string name="stats_total_time">Samlet tid</string>
<!-- Track -->
<string name="track_name_format">Rute %1$d</string>
<string name="track_record_notification">Registrerer din rute…</string>
<string name="track_recording_notification_accuracy">Placeringsnøjagtighed: %1$s</string>
<string name="track_markers">Markører på %1$s</string>
<!-- Track Delete -->
<string name="track_delete_one_confirm_message">Ruten og de tilhørende markører slettes permanent fra enheden.</string>
<string name="track_delete_one_confirm_title">Vil du slette ruten?</string>
<string name="track_delete_multiple_confirm_message">De valgte ruter og tilhørende markører slettes permanent fra enheden.</string>
<string name="track_delete_progress_message">Sletter…</string>
<!-- Track Detail -->
<string name="track_detail_chart_tab">Diagram</string>
<string name="track_detail_stats_tab">Statistik</string>
<string name="track_detail_record_success">Registrerer en ny rute</string>
<string name="track_detail_resume_success">Genoptager nu sporet</string>
<!-- Track Edit -->
<string name="track_edit_activity_type">Aktivitetstype (f.eks. vandretur)</string>
<string name="track_edit_activity_type_hint">Aktivitetstype</string>
<string name="track_edit_new_track_title">Ny rute</string>
<!-- Track List -->
<string name="track_list_empty_message">Her kan du gå i gang med at registrere dit næste eventyr</string>
<string name="track_list_record_error">Registreringen kan ikke startes. Intet GPS-signal. Prøv igen.</string>
<string name="track_list_record_success">Registrerer en ny rute</string>
<string name="track_widget_config_title">Konfigurer widget-elementer</string>
<!-- Track Widget -->
<!-- Tracks -->
<string name="tracks_few">%1$d ruter</string>
<string name="tracks_many">%1$d ruter</string>
<string name="tracks_one">1 rute</string>
<string name="tracks_other">%1$d ruter</string>
<string name="tracks_two">2 ruter</string>
<string name="tracks_zero">0 ruter</string>
<!-- Unit -->
<string name="unit_feet">fod</string>
<string name="unit_kilometer">km</string>
<string name="unit_kilometer_per_hour">km/t</string>
@@ -320,6 +434,7 @@
<string name="unit_mile_per_hour">mil/t</string>
<string name="unit_minute_per_kilometer">min./km</string>
<string name="unit_minute_per_mile">min./mil</string>
<!-- Value -->
<string name="value_adapt_accuracy">Juster nøjagtighed</string>
<string name="value_adapt_battery_life">Tilpas til batterilevetid</string>
<string name="value_always">Altid</string>
@@ -331,10 +446,8 @@
<string name="value_integer_feet">%1$d fod</string>
<string name="value_integer_feet_excellent_gps">%1$d fod (fremragende GPS)</string>
<string name="value_integer_feet_recommended">%1$d fod (anbefales)</string>
<string name="value_integer_kilobyte">%1$d kB</string>
<string name="value_integer_kilometer">%1$d km</string>
<string name="value_integer_kilometer_hour">%1$d km/t</string>
<string name="value_integer_megabyte">%1$d MB</string>
<string name="value_integer_meter">%1$d m</string>
<string name="value_integer_meter_excellent_gps">%1$d m (fremragende GPS)</string>
<string name="value_integer_meter_poor_gps">%1$d m (dårlig GPS)</string>
@@ -344,11 +457,11 @@
<string name="value_integer_minute">%1$d min.</string>
<string name="value_integer_percent">%1$d %%</string>
<string name="value_integer_second">%1$d sek.</string>
<string name="value_never">Aldrig</string>
<string name="value_none">Ingen</string>
<string name="value_off">Fra</string>
<string name="value_smallest">Mindste</string>
<string name="value_smallest_recommended">Mindst (anbefalet)</string>
<!-- Voice -->
<string name="voice_hours_few">%1$d timer</string>
<string name="voice_hours_many">%1$d timer</string>
<string name="voice_hours_one">1 time</string>
@@ -395,6 +508,7 @@
<string name="voice_total_distance_miles_two">afstand i alt 2 mil</string>
<string name="voice_total_distance_miles_zero">afstand i alt 0 mil</string>
<string name="voice_total_distance_zero">Afstand i alt i OpenTracks er nul.</string>
<!-- Waypoint Type -->
<string name="waypoint_type_atm">Pengeautomat</string>
<string name="waypoint_type_bank">bank</string>
<string name="waypoint_type_bar">bar</string>
@@ -446,4 +560,7 @@
<string name="waypoint_type_waterfall">vandfald</string>
<string name="waypoint_type_water_fountain">springvand</string>
<string name="waypoint_type_waypoint">vejpunkt</string>
<!-- Share image -->
<string name="share_image_subject">Jeg vil gerne dele et billede med dig</string>
<string name="share_image_body">Jeg tror, du måske er interesseret i dette billede.</string>
</resources>
+8 -38
View File
@@ -36,7 +36,7 @@ limitations under the License.
Verwende das kleine Kartensymbol.\n
a)
(Live-Aktualisierungen) Installiere <a href="https://github.com/OpenTracksApp/OSMDashboard">OSMDashboard</a>.
OSMDashboard stellt Online- oder Offline-Karten über <a href="https://www.openstreetmap.org">OpenStreetmap</a>.\n zur Verfügung.
OSMDashboard stellt Online- oder Offline-Karten über <a href="https://www.openstreetmap.org">OpenStreetMap</a>.\n zur Verfügung.
Eigentlich ist OSMDashboard eine separate App, die nur (vorübergehend) auf die Daten der anzuzeigenden Strecke(n) zugreifen kann.
\n
@@ -232,13 +232,9 @@ g) das tun, was Deiner Meinung nach OpenTracks hilft.</string>
<!-- Gps -->
<string name="gps_location_access">\"Standortzugriff\"</string>
<string name="gps_disabled">GPS ist nicht aktiviert. Tippen Sie hier, um zu %1$s wechseln. Drücken Sie \"Zurück\", um zurückzugehen.</string>
<string name="gps_disabled_location_mode">Wählen Sie den Standortmodus für hohe Genauigkeit aus. Tippen Sie hier, um \"%1$s\" zu öffnen. Tippen Sie auf \"Zurück\", um zu dieser Ansicht zurückzukehren.</string>
<string name="gps_disabled_my_location">Der aktuelle Standort kann nicht ermittelt werden. Aktivieren Sie mehr Standortquellen unter \"%1$s\" und vergewissern Sie sich, dass der Himmel sichtbar ist. Bitte versuchen Sie es später erneut.</string>
<string name="gps_disabled_my_location_location_mode">Der aktuelle Standort kann nicht ermittelt werden. Aktivieren Sie den Standortmodus für hohe Genauigkeit unter \"%1$s\" und vergewissern Sie sich, dass der Himmel sichtbar ist. Bitte versuchen Sie es später erneut.</string>
<string name="gps_not_found">Das Gerät sendet kein GPS-Signal.</string>
<string name="gps_starting">GPS wird gestartet.</string>
<string name="gps_starting_error">GPS kann nicht gestartet werden.</string>
<string name="gps_stopping">GPS wird beendet.</string>
<string name="gps_wait_for_better_signal">Warten auf besseres GPS-Signal</string>
<string name="gps_wait_for_signal">Warten auf GPS-Signal</string>
<!-- Image -->
@@ -286,21 +282,14 @@ g) das tun, was Deiner Meinung nach OpenTracks hilft.</string>
<!-- Menu -->
<string name="menu_aggregated_statistics">Gesammelte Statistiken</string>
<string name="menu_delete">Löschen</string>
<string name="menu_delete_all">Alle löschen</string>
<string name="menu_edit">Bearbeiten</string>
<string name="menu_export">Exportieren</string>
<string name="menu_export_all">Alle exportieren</string>
<string name="menu_feedback">Feedback</string>
<string name="menu_help">Hilfe</string>
<string name="menu_help_feedback">Hilfe &amp; Feedback</string>
<string name="menu_help_forum">Hilfeforum</string>
<string name="menu_import_all">Alle importieren</string>
<string name="menu_insert_marker">Markierung einfügen</string>
<string name="menu_insert_photo">Foto einfügen</string>
<string name="menu_insert_gallery_img">Galerie Bild einfügen</string>
<string name="menu_map">Karte</string>
<string name="menu_markers">Markierungen</string>
<string name="menu_play">Wiedergeben</string>
<string name="menu_search">Suche</string>
<string name="menu_select_all">Alle auswählen</string>
<string name="menu_sensor_state">Sensorstatus</string>
@@ -322,27 +311,23 @@ g) das tun, was Deiner Meinung nach OpenTracks hilft.</string>
<string name="search_global_description">Tracks und Markierungen</string>
<string name="search_list_empty_message">Keine Tracks oder Markierungen gefunden, die Ihrer Suchanfrage entsprechen</string>
<string name="search_list_marker_track_location">Im Track \"%1$s\".</string>
<string name="search_voice_prompt">Sprechen Sie den Namen eines Tracks oder einer Markierung.</string>
<!-- Sensor State -->
<string name="sensor_state_battery">Akkustatus</string>
<string name="sensor_state_cadence">Trittfrequenz</string>
<string name="sensor_state_cadence_value">%1$d Umdrehungen pro Minute</string>
<string name="sensor_state_connected">Verbunden</string>
<string name="sensor_state_connecting">Verbindung wird hergestellt…</string>
<string name="sensor_state_disconnected">Nicht verbunden</string>
<string name="sensor_state_heart_rate">Herzfrequenz</string>
<string name="sensor_state_heart_rate_value">%1$d Schläge pro Minute</string>
<string name="sensor_state_last_sensor_time">Letzte Sensorzeit</string>
<string name="sensor_state_power">Leistung</string>
<string name="sensor_state_power_value">%1$d W</string>
<string name="sensor_state_sending">Wird gesendet</string>
<string name="sensor_not_known">Sensor %1$s ist unbekannt. Bitte überprüfe die Einstellungen.</string>
<string name="sensor_could_not_scan">Konnte nicht nach Bluetooth-Geräten scannen (Fehler %1$i).</string>
<string name="bluetooth_disabled">Bitte Bluetooth aktivieren.</string><!-- Settings -->
<string name="bluetooth_disabled">Bitte Bluetooth aktivieren.</string>
<string name="settings_not_while_recording">Während der Aufzeichnung eines Tracks nicht verfügbar</string>
<string name="settings_show">Anzeigen</string>
<!-- Settings Advanced -->
<string name="settings_advanced">Erweitert</string>
<string name="settings_default_trackfileformat">Dateiformat für export/teilen</string>
<!-- Settings Chart -->
<string name="settings_chart_by_distance">Nach Strecke</string>
<string name="settings_chart_by_time">Nach Zeit</string>
@@ -377,16 +362,9 @@ g) das tun, was Deiner Meinung nach OpenTracks hilft.</string>
<string name="settings_error_initial_values_restored">Entschuldigung, es ist ein Fehler aufgetreten. Alle Einstellungen wurden auf die Standardwerte zurückgesetzt.</string>
<!-- Settings Sensor -->
<string name="settings_sensor">Sensor</string>
<string name="settings_sensor_ant_reset_bike_cadence_sensor">Trittfrequenz zurücksetzen</string>
<string name="settings_sensor_ant_reset_combined_bike_sensor">Radsensoren zurücksetzen</string>
<string name="settings_sensor_ant_reset_heart_rate_monitor">Herzfrequenz zurücksetzen</string>
<string name="settings_sensor_ant_reset_speed_distance_monitor">Laufsensor zurücksetzen</string>
<string name="settings_sensor_bluetooth">Bluetooth</string>
<string name="settings_sensor_bluetooth_pairing">Bluetooth-Pairing</string>
<string name="settings_sensor_bluetooth_pairing_summary">Die Bluetooth-Einstellungen von Android öffnen, um ein Sensor-Pairing vorzunehmen</string>
<string name="settings_sensor_bluetooth_sensor">Bluetooth-Sensor</string>
<string name="settings_sensor_connecting">Verbunden mit %1$s</string>
<string name="settings_sensor_connected">Verbunden mit %1$s</string>
<string name="settings_sensor_disconnected">Verbindung getrennt von %1$s</string>
<string name="settings_sensor_wheel_circumference">Reifengröße (ETRTO)</string>
@@ -398,16 +376,14 @@ g) das tun, was Deiner Meinung nach OpenTracks hilft.</string>
<string name="settings_stats_units_metric">Metrisch (km, m)</string>
<string name="settings_stats_units_title">Bevorzugte Einheiten</string>
<!-- Share Track -->
<string name="share_track_emails_hint">E-Mail-Adressen</string>
<string name="share_track_picker_title">App auswählen</string>
<string name="share_track_share_file">Track-Datei teilen</string>
<string name="share_track_share_file_body">Dieser Track könnte dich interessieren.\n\nDu kannst ihn dir mit Google Earth oder einer anderen Kartierungssoftware ansehen.\n\n%1$s</string>
<string name="share_track_subject">Ich möchte einen Track mit dir teilen</string>
<!-- Stats -->
<string name="stats_average_moving_pace">Durchschnittl. Bewegungstempo</string>
<string name="stats_average_moving_speed">Durchschnittl. Bewegungsgeschwindigkeit</string>
<string name="stats_average_pace">Durchschnittstempo</string>
<string name="stats_average_speed">Durchschnittsgeschwindigkeit</string>
<string name="stats_average_moving_pace">Durchschnitt\n(Bewegung)</string>
<string name="stats_average_moving_speed">Durchschnitt\n(Bewegung)</string>
<string name="stats_average_pace">Durchschnitt</string>
<string name="stats_average_speed">Durchschnitt</string>
<string name="stats_elevation">Höhe</string>
<string name="stats_fastest_pace">Schnellstes Tempo</string>
<string name="stats_gain">Anstieg</string>
@@ -415,7 +391,7 @@ g) das tun, was Deiner Meinung nach OpenTracks hilft.</string>
<string name="stats_latitude">Breitengrad</string>
<string name="stats_longitude">Längengrad</string>
<string name="stats_max">Max.</string>
<string name="stats_max_speed">Höchstgeschwin-digkeit</string>
<string name="stats_max_speed">Max.</string>
<string name="stats_min">Min.</string>
<string name="stats_moving_time">Bewegungszeit</string>
<string name="stats_pace">Tempo</string>
@@ -443,10 +419,7 @@ g) das tun, was Deiner Meinung nach OpenTracks hilft.</string>
<string name="track_edit_new_track_title">Neuer Track</string>
<!-- Track List -->
<string name="track_list_empty_message">Zeichnen Sie Ihr nächstes Abenteuer hier auf.</string>
<string name="track_list_record_error">Die Aufzeichnung kann nicht gestartet werden, da kein GPS-Signal verfügbar ist. Bitte versuchen Sie es erneut.</string>
<string name="track_list_record_success">Neuer Track wird aufgezeichnet</string>
<!-- Track Widget -->
<string name="track_widget_config_title">Widget-Elemente konfigurieren</string>
<!-- Tracks -->
<string name="tracks_few">%1$d Tracks</string>
<string name="tracks_many">%1$d Tracks</string>
@@ -475,10 +448,8 @@ g) das tun, was Deiner Meinung nach OpenTracks hilft.</string>
<string name="value_integer_feet">%1$d Fuß</string>
<string name="value_integer_feet_excellent_gps">%1$d Fuß (ausgezeichnetes GPS-Signal)</string>
<string name="value_integer_feet_recommended">%1$d Fuß (empfohlen)</string>
<string name="value_integer_kilobyte">%1$d KB</string>
<string name="value_integer_kilometer">%1$d km</string>
<string name="value_integer_kilometer_hour">%1$d km/h</string>
<string name="value_integer_megabyte">%1$d MB</string>
<string name="value_integer_meter">%1$d m</string>
<string name="value_integer_meter_excellent_gps">%1$d m (ausgezeichnetes GPS-Signal)</string>
<string name="value_integer_meter_poor_gps">%1$d m (schlechtes GPS-Signal)</string>
@@ -488,7 +459,6 @@ g) das tun, was Deiner Meinung nach OpenTracks hilft.</string>
<string name="value_integer_minute">%1$d min</string>
<string name="value_integer_percent">%1$d %%</string>
<string name="value_integer_second">%1$d s</string>
<string name="value_never">Nie</string>
<string name="value_none">Keine</string>
<string name="value_off">Aus</string>
<string name="value_smallest">Kleinster</string>
-31
View File
@@ -133,13 +133,9 @@
<string name="generic_yes">Ναι</string>
<string name="gps_location_access">\'Πρόσβαση τοποθεσίας\'</string>
<string name="gps_disabled">Το GPS δεν είναι ενεργοποιημένο. Πατήστε εδώ για να μεταβείτε στο %1$s. Πατήστε το κουμπί \"Πίσω\" για να επιστρέψετε.</string>
<string name="gps_disabled_location_mode">Επιλέξτε τη λειτουργία θέσης υψηλής ακρίβειας. Πατήστε εδώ για να μεταβείτε στο μενού %1$s . Πατήστε το κουμπί Πίσω για να επιστρέψετε.</string>
<string name="gps_disabled_my_location">Η τρέχουσα τοποθεσία δεν μπορεί να προσδιοριστεί. Ενεργοποιήστε περισσότερες πηγές εντοπισμού στο μενού %1$s και βεβαιωθείτε ότι ο ουρανός είναι καθαρός. Δοκιμάστε ξανά αργότερα.</string>
<string name="gps_disabled_my_location_location_mode">Η τρέχουσα θέση δεν μπορεί να προσδιοριστεί. Επιλέξτε τη λειτουργία θέσης υψηλής ακρίβειας στο μενού %1$s και βεβαιωθείτε ότι ο ουρανός είναι καθαρός. Δοκιμάστε ξανά αργότερα.</string>
<string name="gps_not_found">Δε βρέθηκε GPS στη συσκευή</string>
<string name="gps_starting">Εκκίνηση GPS</string>
<string name="gps_starting_error">Δεν είναι δυνατή η εκκίνηση του GPS</string>
<string name="gps_stopping">Διακοπή λειτουργίας GPS</string>
<string name="gps_wait_for_better_signal">Αναμονή για καλύτερο σήμα GPS</string>
<string name="gps_wait_for_signal">Αναμονή για σήμα GPS</string>
<string name="image_application">Εφαρμογή</string>
@@ -179,20 +175,13 @@
<string name="marker_list_empty_message">Δεν έχετε κανένα δείκτη</string>
<string name="menu_aggregated_statistics">Στατιστικά</string>
<string name="menu_delete">Διαγραφή</string>
<string name="menu_delete_all">Διαγραφή όλων</string>
<string name="menu_edit">Επεξεργασία</string>
<string name="menu_export">Εξαγωγή</string>
<string name="menu_export_all">Εξαγωγή όλων</string>
<string name="menu_feedback">Σχόλια</string>
<string name="menu_help">Bοήθεια</string>
<string name="menu_help_feedback">Βοήθεια και σχόλια</string>
<string name="menu_help_forum">Φόρουμ βοήθειας</string>
<string name="menu_import_all">Εισαγωγή όλων</string>
<string name="menu_insert_marker">Εισαγωγή σήμανσης</string>
<string name="menu_insert_photo">Εισαγωγή φωτογραφίας</string>
<string name="menu_map">Χάρτης</string>
<string name="menu_markers">Δείκτες</string>
<string name="menu_play">Αναπαραγωγή</string>
<string name="menu_search">Αναζήτηση</string>
<string name="menu_select_all">Επιλογή όλων</string>
<string name="menu_sensor_state">Κατάσταση αισθητήρα</string>
@@ -209,19 +198,14 @@
<string name="search_global_description">Ίχνη και σημάνσεις</string>
<string name="search_list_empty_message">Δεν υπάρχουν διαδρομές ή δείκτες που να ταιριάζουν στην αναζήτησή σας</string>
<string name="search_list_marker_track_location">Στο ίχνος \"%1$s\".</string>
<string name="search_voice_prompt">Εκφωνείστε το όνομα μιας διαδρομής ή δείκτη</string>
<string name="sensor_state_battery">Στάθμη μπαταρίας</string>
<string name="sensor_state_cadence">Ρυθμός</string>
<string name="sensor_state_cadence_value">%1$d rpm</string>
<string name="sensor_state_connected">Συνδέθηκε</string>
<string name="sensor_state_connecting">Σύνδεση</string>
<string name="sensor_state_disconnected">Αποσυνδεδεμένος</string>
<string name="sensor_state_heart_rate">Καρδιακοί παλμοί</string>
<string name="sensor_state_heart_rate_value">%1$d bpm</string>
<string name="sensor_state_last_sensor_time">Χρόνος τελευταίου αισθητήρα</string>
<string name="sensor_state_power">Ισχύς</string>
<string name="sensor_state_power_value">%1$d W</string>
<string name="sensor_state_sending">Αποστολή</string>
<string name="settings_not_while_recording">Η επιλογή δεν είναι διαθέσιμη κατά την εγγραφή ίχνους</string>
<string name="settings_show">Εμφάνιση</string>
<string name="settings_advanced">Προηγμένες</string>
@@ -250,22 +234,13 @@
<string name="settings_reset_confirm_title">Επαναφορά τώρα;</string>
<string name="settings_reset_done">Όλες οι ρυθμίσεις έχουν επανέλθει στις προεπιλεγμένες τιμές</string>
<string name="settings_sensor">Αισθητήρας</string>
<string name="settings_sensor_ant_reset_bike_cadence_sensor">Επαναφορά ρυθμού ποδηλασίας</string>
<string name="settings_sensor_ant_reset_combined_bike_sensor">Επαναφορά συνδυασμού ποδηλασίας</string>
<string name="settings_sensor_ant_reset_heart_rate_monitor">Επαναφορά καρδιακού ρυθμού</string>
<string name="settings_sensor_ant_reset_speed_distance_monitor">Επαναφορά μετρητή ταχύτητας</string>
<string name="settings_sensor_bluetooth">Bluetooth</string>
<string name="settings_sensor_bluetooth_pairing">Ζεύξη Bluetooth</string>
<string name="settings_sensor_bluetooth_pairing_summary">Άνοιγμα των ρυθμίσεων Bluetooth του Android για ζεύξη με αισθητήρα</string>
<string name="settings_sensor_bluetooth_sensor">Αισθητήρας Bluetooth</string>
<string name="settings_sensor_connected">Έγινε σύνδεση με %1$s</string>
<string name="settings_stats_coordinate">Πλάτος/Μήκος</string>
<string name="settings_stats_rate_title">Προτιμώμενος ρυθμός</string>
<string name="settings_stats_units_imperial">Αγγλοσαξονικό (μίλια, πόδια)</string>
<string name="settings_stats_units_metric">Μετρικό (χλμ, μέτρα)</string>
<string name="settings_stats_units_title">Προτιμώμενες μονάδες</string>
<string name="share_track_emails_hint">Διευθύνσεις ηλεκτρονικού ταχυδρομείου</string>
<string name="share_track_picker_title">Επιλογή εφαρμογής</string>
<string name="share_track_share_file">Κοινή χρήση αρχείου ίχνους</string>
<string name="share_track_share_file_body">Νομίζω ότι μπορεί να σε ενδιαφέρει αυτό το ίχνος.\n\nΓια να δεις αυτό το ίχνος, χρησιμοποίησε το Google Earth ή άλλο λογισμικό χαρτογράφησης.\n\n%1$s</string>
<string name="share_track_subject">Θα ήθελα να μοιραστώ μία διαδρομή μαζί σου</string>
@@ -300,9 +275,6 @@
<string name="track_edit_activity_type_hint">Τύπος δραστηριότητας</string>
<string name="track_edit_new_track_title">Νέο ίχνος</string>
<string name="track_list_empty_message">Ξεκινήστε την εγγραφή της επόμενης περιπέτειάς σας εδώ</string>
<string name="track_list_record_error">Δεν είναι δυνατή η έναρξη της εγγραφής. Δεν υπάρχει σήμα GPS. Δοκιμάστε ξανά.</string>
<string name="track_list_record_success">Εγγραφή νέας διαδρομής σε εξέλιξη</string>
<string name="track_widget_config_title">Διαμόρφωση στοιχείων γραφικού στοιχείου</string>
<string name="tracks_few">%1$d ίχνη</string>
<string name="tracks_many">%1$d ίχνη</string>
<string name="tracks_one">1 ίχνος</string>
@@ -328,10 +300,8 @@
<string name="value_integer_feet">%1$d πόδια</string>
<string name="value_integer_feet_excellent_gps">%1$d πόδια (τέλειο σήμα GPS)</string>
<string name="value_integer_feet_recommended">%1$d ft (συνιστάται)</string>
<string name="value_integer_kilobyte">%1$d kB</string>
<string name="value_integer_kilometer">%1$d χιλιόμετρα</string>
<string name="value_integer_kilometer_hour">%1$d χλμ/ώρα</string>
<string name="value_integer_megabyte">%1$d MB</string>
<string name="value_integer_meter">%1$d μέτρα</string>
<string name="value_integer_meter_excellent_gps">%1$d μέτρα (τέλειο σήμα GPS)</string>
<string name="value_integer_meter_poor_gps">%1$d μέτρα (χαμηλό σήμα GPS)</string>
@@ -341,7 +311,6 @@
<string name="value_integer_minute">%1$d λεπ.</string>
<string name="value_integer_percent">%1$d %%</string>
<string name="value_integer_second">%1$d δευτ</string>
<string name="value_never">Ποτέ</string>
<string name="value_none">Καμία</string>
<string name="value_off">Απενεργοποιημένο</string>
<string name="value_smallest">Μικρότερη</string>
+144 -32
View File
@@ -1,5 +1,94 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?><!--
Copyright 2010 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="about_preference_title">Acerca de OpenTracks</string>
<string name="about_description"><i>OpenTracks</i> es una aplicación de seguimiento deportivo que respeta completamente su privacidad.</string>
<string name="about_url">Página web del proyecto: <a href="%1$s">%1$s</a></string>
<string name="about_version_name">Nombre de la versión: %1$s</string>
<string name="about_version_code">Código de la versión: %1$d</string>
<string name="about_history">OpenTracks es una bifurcación de <a href="https://code.google.com/archive/p/mytracks/"><i>MyTracks </i></a> de Google (descontinuado en 2016).</string>
<string name="about_libraries">Bibliotecas</string>
<!-- Help -->
<string name="help_feature_title">OpenTracks tiene las siguientes características:</string>
<string name="help_feature_content">
* crear un seguimiento GPS *
* usa un sensor de ritmo cardíaco (sólo Bluetooth LE) *
* anuncios de voz (por tiempo o distancia)*
* crear marcadores (incluyendo imágenes) *
* funciona completamente fuera de línea *
* mostrar las pistas en un mapa (ver abajo)</string>
<string name="help_track_map_title">¿Cómo mostrar una pista en un mapa?</string>
<string name="help_track_map_content">
Usa el icono del mapa pequeño.
a)
(actualizaciones en vivo) Instalar <a href="https://github.com/OpenTracksApp/OSMDashboard">OSMDashboard</a>.
Proporciona mapas en línea o fuera de línea a través de <a href="https://www.openstreetmap.org">OpenStreetMap</a>.\n
En realidad, OSMDashboard es una aplicación independiente que sólo puede acceder (temporalmente) a los datos de las pist(as) que se van a mostrar.
\n
b)
A través de una aplicación de mapas normal (por ejemplo, <a href="http://osmand.net/">OsmAnd</a> y <a href="https://maps.me/">MAPS.ME</a>).
Estas aplicaciones necesitan soportar el formato de archivo KMZ (sólo las ubicaciones y las marcas de tiempo).
De hecho, una aplicación necesita soportar <i>ACTION_VIEW</i> con MIME <i>application/vnd.google-earth.kmz</i>.</string>
<string name="help_storage_pictures_title">¿Cómo almacena OpenTracks las fotos que fueron tomadas como marcadores?</string>
<string name="help_storage_pictures_content">Estos se almacenan en el almacenamiento interno de la aplicación (es decir, sólo accesible dentro de OpenTracks).</string>
<string name="help_track_export_title">¿Cómo puedo exportar/compartir las pistas grabadas?</string>
<string name="help_track_export_content">
Las pistas pueden ser exportadas desde los ajustes como KMZ, KML o GPX.
KMZ/KML todos los datos; GPX sólo las ubicaciones.
Las pistas compartidas a través del <i> icono de compartir </i> se comparten como KMZ.</string>
<string name="help_data_google_play_services_title">¿Requiere OpenTracks usar el servicio de Google Play?</string>
<string name="help_recording_title">¿Cómo registra OpenTracks los datos?</string>
<string name="help_recording_content">
OpenTracks utiliza el sensor GPS del dispositivo para registrar la ubicación de forma continua.
Si el dispositivo GPS reporta datos inexactos (por ejemplo, ubicación, velocidad, elevación), OpenTracks no puede hacer nada al respecto.</string>
<string name="help_data_storage_title">¿Cómo almacena OpenTracks los datos de los sensores?</string>
<string name="help_data_storage_content">
Los datos de los sensores se almacenan por cada ubicación registrada.
En términos de un sensor de frecuencia cardíaca, esto significa que sólo <i>uno</i> la medición de la frecuencia cardíaca se almacena por ubicación.
Si está parado o en el interior, no se registrarán los datos del sensor (pero se mostrarán).</string>
<string name="help_gps_troubleshooting_title">OpenTracks no está grabando las localizaciones?</string>
<string name="help_gps_troubleshooting_content">
Lo que puedes hacer...
a) Comprobar si el GPS está activado.
b) mejorar la recepción del GPS (por ejemplo, ir al exterior),\n
c) comprueba si con <a href="https://f-droid.org/en/packages/com.android.gpstest.osmdroid/">GPSTest</a> app, y\n
d) desactivar el ahorro de energía.
\n
Si todo no ayuda, por favor informe de un error.</string>
<string name="help_support_title">¿Cómo puedo apoyar OpenTracks?</string>
<string name="help_support_content">
Puedes...
a) difundir la palabra sobre OpenTracks,...
b) <a href="https://github.com/OpenTracksApp/OpenTracks/issues">proponer características</a>,\n
c) <a href="https://github.com/OpenTracksApp/OpenTracks/issues">report bugs</a>,\n
d) ayudar en el desarrollo de software,\n
e) comprar en <a href="https://play.google.com/store/apps/details?id=de.dennisguse.opentracks.playstore">Google Play Store</a>,\n
f) donar, y
g) haz lo que creas que ayude a OpenTracks.</string>
<!-- Activity Type -->
<string name="activity_type_airplane">avión</string>
<string name="activity_type_atv">vehículos todoterreno</string>
<string name="activity_type_biking">ciclismo</string>
@@ -66,6 +155,8 @@
<string name="activity_type_walking">recorrido a pie</string>
<string name="activity_type_water_skiing">esquí acuático</string>
<string name="activity_type_wind_surfing">windsurf</string>
<string name="app_not_installed_show_on_map">Por favor, instale una aplicación que soporte la presentación de datos de mapas.</string>
<!-- Description -->
<string name="description_activity_type">Tipo de actividad: %1$s</string>
<string name="description_average_moving_pace_in_minute">Ritmo de movimiento medio: %1$s min/km (%2$s min/mi)</string>
<string name="description_average_moving_speed">Velocidad de movimiento media: %1$.2f km/h (%2$.1f mi/h)</string>
@@ -93,6 +184,7 @@
<string name="description_sensor_cadence">Cadencia (rpm)</string>
<string name="description_sensor_heart_rate">Frecuencia cardíaca (bpm)</string>
<string name="description_sensor_power">Potencia (W)</string>
<string name="description_default_speed_or_pace">Por la clase de actividad</string>
<string name="description_speed_imperial">Velocidad (mi/h)</string>
<string name="description_speed_metric">Velocidad (km / h)</string>
<string name="description_time">Tiempo</string>
@@ -100,6 +192,7 @@
<string name="description_total_time">Tiempo total: %1$s</string>
<string name="description_track_point">Punto</string>
<string name="description_track_segment">Segmento</string>
<!-- Export -->
<string name="export_all_option">Todo como %1$s</string>
<string name="export_all_title">Exportar a unidad de almacenamiento externa</string>
<string name="export_with_photos">con fotos</string>
@@ -109,12 +202,15 @@
<string name="export_progress_message">Exportando a %1$s…</string>
<string name="export_success">Se exportaron %1$s a %2$s</string>
<string name="export_title">Exportar a…</string>
<!-- External Storage -->
<!-- Files -->
<string name="files_few">%1$d archivos</string>
<string name="files_many">%1$d archivos</string>
<string name="files_one">1 archivo</string>
<string name="files_other">%1$d archivos</string>
<string name="files_two">2 archivos</string>
<string name="files_zero">0 archivos</string>
<!-- Generic -->
<string name="generic_add">Añadir</string>
<string name="generic_cancel">Cancelar</string>
<string name="generic_delete_all_confirm_title">¿Eliminar todo?</string>
@@ -133,17 +229,15 @@
<string name="generic_success_title">Correcto</string>
<string name="generic_tracks">Rutas</string>
<string name="generic_yes">Sí</string>
<!-- Gps -->
<string name="gps_location_access">\"Acceso a la ubicación\"</string>
<string name="gps_disabled">El GPS no está habilitado. Toca aquí para ir a %1$s. Pulsa el botón Atrás para volver.</string>
<string name="gps_disabled_location_mode">Selecciona el modo de ubicación de alta precisión. Toca aquí para acceder a %1$s. Para volver a la pantalla anterior, pulsa el botón atrás.</string>
<string name="gps_disabled_my_location">No se puede determinar la ubicación actual. Habilita más fuentes de ubicación en %1$s y asegúrate de que se pueda ver el cielo. Vuelve a intentarlo más tarde.</string>
<string name="gps_disabled_my_location_location_mode">No se puede determinar la ubicación actual. Selecciona el modo de ubicación de alta precisión en %1$s y asegúrate de que se pueda ver el cielo. Vuelve a intentarlo más tarde.</string>
<string name="gps_not_found">No se ha encontrado ningún GPS en el dispositivo</string>
<string name="gps_starting">Iniciando GPS</string>
<string name="gps_starting_error">No se ha podido iniciar el GPS</string>
<string name="gps_stopping">Deteniendo GPS</string>
<string name="gps_wait_for_better_signal">Esperando una mejor señal de GPS</string>
<string name="gps_wait_for_signal">Esperando señal de GPS</string>
<!-- Image -->
<string name="image_application">Aplicación</string>
<string name="image_arrow">Flecha</string>
<string name="image_marker">Marcador</string>
@@ -154,6 +248,7 @@
<string name="image_record">Grabar</string>
<string name="image_stop">Detener</string>
<string name="image_track">Ruta</string>
<!-- Import -->
<string name="import_error">Se importaron %1$d de %2$s desde %3$s</string>
<string name="import_no_directory">%1$s no existe</string>
<string name="import_no_file">No hay archivos que importar. Conecta tu dispositivo al ordenador y coloca los archivos que quieras
@@ -163,6 +258,7 @@
<string name="import_selection_option">Todos los archivos %1$s</string>
<string name="import_selection_title">Importar desde la unidad de almacenamiento externa</string>
<string name="import_success">Se importaron %1$s desde %2$s</string>
<!-- Marker -->
<string name="marker_add_error">No se puede insertar el marcador. No se recibe señal de GPS. Inténtalo de nuevo.</string>
<string name="marker_add_success">Se ha insertado un marcador</string>
<string name="marker_add_canceled">Cancelado, no se ha añadido ningún marcador</string>
@@ -176,27 +272,24 @@
<string name="marker_name_format">Marcador %1$d</string>
<string name="marker_split_name_format">Dividir %1$d</string>
<string name="marker_title">%1$d de %2$d</string>
<!-- Marker Detail -->
<string name="marker_detail_statistics_title">Desde el último marcador de división:</string>
<!-- Marker Edit -->
<string name="marker_edit_marker_type">Tipo de marcador (p. ej., cascada…)</string>
<string name="marker_edit_marker_type_hint">Tipo de marcador</string>
<!-- Marker List -->
<string name="marker_list_empty_message">No tienes ningún marcador</string>
<!-- Menu -->
<string name="menu_aggregated_statistics">Estadísticas globales</string>
<string name="menu_delete">Eliminar</string>
<string name="menu_delete_all">Eliminar todo</string>
<string name="menu_edit">Editar</string>
<string name="menu_export">Exportar</string>
<string name="menu_export_all">Exportar todo</string>
<string name="menu_feedback">Enviar comentarios</string>
<string name="menu_help">Ayuda</string>
<string name="menu_help_feedback">Ayuda y opiniones</string>
<string name="menu_help_forum">Foro de ayuda</string>
<string name="menu_import_all">Importar todo</string>
<string name="menu_insert_marker">Insertar marcador</string>
<string name="menu_insert_photo">Insertar foto</string>
<string name="menu_insert_gallery_img">Insertar imagen de galería</string>
<string name="menu_map">Mapa</string>
<string name="menu_markers">Marcadores</string>
<string name="menu_play">Reproducir</string>
<string name="menu_search">Buscar</string>
<string name="menu_select_all">Seleccionar todo</string>
<string name="menu_sensor_state">Estado de los sensores</string>
@@ -209,30 +302,40 @@
<string name="menu_view_photo">Ver foto</string>
<string name="menu_voice_frequency">Frecuencia de voz</string>
<string name="menu_resume_track">Reanudar ruta</string>
<!-- OpenTracks -->
<string name="app_name">OpenTracks</string>
<string name="recording_service">Servicio de grabación</string>
<!-- Permission -->
<string name="permission_gps_failed">OpenTracks requiere permiso para usar el GPS.</string>
<!-- Search -->
<string name="search_global_description">Recorridos y marcadores</string>
<string name="search_list_empty_message">No hay rutas ni marcadores que coincidan con tu búsqueda</string>
<string name="search_list_marker_track_location">En la ruta \"%1$s\"</string>
<string name="search_voice_prompt">Di el nombre de la ruta o del marcador</string>
<!-- Sensor State -->
<string name="sensor_state_battery">Nivel de batería</string>
<string name="sensor_state_cadence">Cadencia</string>
<string name="sensor_state_cadence_value">%1$d rpm</string>
<string name="sensor_state_connected">Conectado</string>
<string name="sensor_state_connecting">Conectando</string>
<string name="sensor_state_disconnected">Desconectado</string>
<string name="sensor_state_heart_rate">Frecuencia cardíaca</string>
<string name="sensor_state_heart_rate_value">%1$d bpm</string>
<string name="sensor_state_last_sensor_time">Último envío de datos del sensor</string>
<string name="sensor_state_power">Potencia</string>
<string name="sensor_state_power_value">%1$d W</string>
<string name="sensor_state_sending">Enviando</string>
<string name="sensor_not_known">Sensor %1$s es desconocido. Por favor, compruebe la configuración.</string>
<string name="sensor_could_not_scan">No se pudieron buscar dispositivos Bluetooth (error %1$i).</string>
<string name="bluetooth_disabled">Por favor, activa el Bluetooth.</string>
<string name="settings_not_while_recording">No disponible mientras se graba una ruta</string>
<string name="settings_show">Mostrar</string>
<!-- Settings Advanced -->
<string name="settings_advanced">Avanzado</string>
<!-- Settings Chart -->
<string name="settings_chart_by_distance">Por distancia</string>
<string name="settings_chart_by_time">Por tiempo</string>
<string name="settings_chart_x_axis">Eje X</string>
<!-- Settings Recording -->
<string name="settings_recording_show_on_lockscreen_while_recording_title">Mostrar las estadísticas en la pantalla de bloqueo</string>
<string name="settings_recording_show_on_lockscreen_while_recording_summary">Mientras graba, muestre las estadísticas sin desbloquear el dispositivo.</string>
<string name="settings_recording_keep_screen_on_while_recording_title">Mantén la pantalla encendida</string>
<string name="settings_recording_keep_screen_on_while_recording_summary">Mientras graba, mantenga la pantalla encendida.</string>
<string name="settings_recording">Grabación</string>
<string name="settings_recording_auto_resume_track_timeout_always_summary">Reanudar siempre una grabación después de reiniciar</string>
<string name="settings_recording_auto_resume_track_timeout_never_summary">No reanudar nunca una grabación después de reiniciar</string>
@@ -250,30 +353,32 @@
<string name="settings_recording_track_name_date_local_option">Fecha (local)</string>
<string name="settings_recording_track_name_number_option">Número</string>
<string name="settings_recording_track_name_title">Nombre de la ruta</string>
<!-- Settings Reset -->
<string name="settings_reset">Restablecer</string>
<string name="settings_reset_confirm_message">Todos los ajustes volverán a los valores predeterminados.</string>
<string name="settings_reset_confirm_title">¿Restablecer ahora?</string>
<string name="settings_reset_done">Se han restablecido los valores predeterminados de todas las opciones de configuración</string>
<string name="settings_error_initial_values_restored">Lo siento, pero ha habido un error. Todos los ajustes se han vuelto a los valores predeterminados.</string>
<!-- Settings Sensor -->
<string name="settings_sensor">Sensor</string>
<string name="settings_sensor_ant_reset_bike_cadence_sensor">Restablecer cadencia de bicicleta</string>
<string name="settings_sensor_ant_reset_combined_bike_sensor">Restablecer bicicleta combinada</string>
<string name="settings_sensor_ant_reset_heart_rate_monitor">Restablecer pulso</string>
<string name="settings_sensor_ant_reset_speed_distance_monitor">Restablecer podómetro</string>
<string name="settings_sensor_bluetooth">Bluetooth</string>
<string name="settings_sensor_bluetooth_pairing">Sincronización de Bluetooth</string>
<string name="settings_sensor_bluetooth_pairing_summary">Esta opción permite abrir los ajustes de Bluetooth de Android para sincronizar un sensor.</string>
<string name="settings_sensor_bluetooth_sensor">Sensor Bluetooth</string>
<string name="settings_sensor_connected">Conectado a %1$s</string>
<string name="settings_sensor_connecting">Conectado a %1$s</string>
<string name="settings_sensor_disconnected">Desconectado de %1$s</string>
<string name="settings_sensor_wheel_circumference">Tamaño de la rueda (ETRTO)</string>
<!-- Settings Stats -->
<string name="settings_stats_coordinate">Latitud/Longitud</string>
<string name="settings_stats_rate_title">Ritmo preferido</string>
<string name="settings_stats_units_imperial">Imperiales (millas, pies)</string>
<string name="settings_stats_units_metric">Métricas (km, m)</string>
<string name="settings_stats_units_title">Unidades preferidas</string>
<string name="share_track_emails_hint">Direcciones de correo electrónico</string>
<string name="share_track_picker_title">Selecciona una aplicación</string>
<!-- Share Track -->
<string name="share_track_share_file">Compartir el archivo de la ruta</string>
<string name="share_track_share_file_body">Creo que esta ruta te podría interesar.\n\nPara ver esta ruta, usa Google Earth u otro software de mapas.\n\n%1$s</string>
<string name="share_track_subject">Me gustaría compartir una ruta contigo</string>
<!-- Stats -->
<string name="stats_average_moving_pace">Ritmo de movimiento medio</string>
<string name="stats_average_moving_speed">Velocidad de movimiento media</string>
<string name="stats_average_pace">Ritmo medio</string>
@@ -292,29 +397,36 @@
<string name="stats_speed">Velocidad</string>
<string name="stats_distance">Distancia</string>
<string name="stats_total_time">Tiempo total</string>
<!-- Track -->
<string name="track_name_format">Ruta %1$d</string>
<string name="track_record_notification">Grabando tu ruta…</string>
<string name="track_recording_notification_accuracy">Precisión de la localización: %1$s</string>
<string name="track_markers">Marcadores de %1$s</string>
<!-- Track Delete -->
<string name="track_delete_one_confirm_message">La ruta y sus marcadores se eliminarán de forma permanente del dispositivo.</string>
<string name="track_delete_one_confirm_title">¿Eliminar ruta?</string>
<string name="track_delete_multiple_confirm_message">Las rutas seleccionadas y sus marcadores se eliminarán de forma permanente del dispositivo.</string>
<string name="track_delete_progress_message">Eliminando…</string>
<!-- Track Detail -->
<string name="track_detail_chart_tab">Gráfico</string>
<string name="track_detail_stats_tab">Estadísticas</string>
<string name="track_detail_record_success">Grabando una nueva ruta</string>
<string name="track_detail_resume_success">Ahora reanudando la pista</string>
<!-- Track Edit -->
<string name="track_edit_activity_type">Tipo de actividad (p. ej., senderismo…)</string>
<string name="track_edit_activity_type_hint">Tipo de actividad</string>
<string name="track_edit_new_track_title">Nueva pista</string>
<!-- Track List -->
<string name="track_list_empty_message">Empieza a grabar aquí tu próxima aventura</string>
<string name="track_list_record_error">No se puede iniciar la grabación. No se recibe señal de GPS. Inténtalo de nuevo.</string>
<string name="track_list_record_success">Grabando una nueva ruta</string>
<string name="track_widget_config_title">Configurar elementos de widget</string>
<!-- Track Widget -->
<!-- Tracks -->
<string name="tracks_few">%1$d rutas</string>
<string name="tracks_many">%1$d rutas</string>
<string name="tracks_one">1 ruta</string>
<string name="tracks_other">%1$d rutas</string>
<string name="tracks_two">2 rutas</string>
<string name="tracks_zero">0 ruta</string>
<!-- Unit -->
<string name="unit_feet">pies</string>
<string name="unit_kilometer">km</string>
<string name="unit_kilometer_per_hour">km/h</string>
@@ -323,6 +435,7 @@
<string name="unit_mile_per_hour">millas/h</string>
<string name="unit_minute_per_kilometer">min/km</string>
<string name="unit_minute_per_mile">min/milla</string>
<!-- Value -->
<string name="value_adapt_accuracy">Adaptar para obtener valores exactos</string>
<string name="value_adapt_battery_life">Adaptar a la duración de la batería</string>
<string name="value_always">Siempre</string>
@@ -334,10 +447,8 @@
<string name="value_integer_feet">%1$d pies</string>
<string name="value_integer_feet_excellent_gps">%1$d pies (señal de GPS excelente)</string>
<string name="value_integer_feet_recommended">%1$d pies (recomendado)</string>
<string name="value_integer_kilobyte">%1$d KB</string>
<string name="value_integer_kilometer">%1$d km</string>
<string name="value_integer_kilometer_hour">%1$d km/h</string>
<string name="value_integer_megabyte">%1$d MB</string>
<string name="value_integer_meter">%1$d m</string>
<string name="value_integer_meter_excellent_gps">%1$d m (señal de GPS excelente)</string>
<string name="value_integer_meter_poor_gps">%1$d m (señal de GPS débil)</string>
@@ -347,11 +458,11 @@
<string name="value_integer_minute">%1$d min</string>
<string name="value_integer_percent">%1$d %%</string>
<string name="value_integer_second">%1$d s</string>
<string name="value_never">Nunca</string>
<string name="value_none">Ninguna</string>
<string name="value_off">No</string>
<string name="value_smallest">Menor</string>
<string name="value_smallest_recommended">Mínimo (recomendado)</string>
<!-- Voice -->
<string name="voice_hours_few">%1$d horas</string>
<string name="voice_hours_many">%1$d horas</string>
<string name="voice_hours_one">1 hora</string>
@@ -398,6 +509,7 @@
<string name="voice_total_distance_miles_two">distancia total de 2 millas</string>
<string name="voice_total_distance_miles_zero">distancia total de 0 millas</string>
<string name="voice_total_distance_zero">La distancia total de OpenTracks es igual a cero.</string>
<!-- Waypoint Type -->
<string name="waypoint_type_atm">cajero automático</string>
<string name="waypoint_type_bank">banco</string>
<string name="waypoint_type_bar">bar</string>

Some files were not shown because too many files have changed in this diff Show More