Merge pull request #358 from jat255/max_speed_preference
Add user preference for filtering of GPX speed data
This commit is contained in:
commit
a74c03d14a
2
fittrackee/dist/index.html
vendored
2
fittrackee/dist/index.html
vendored
@ -1 +1 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><!--[if IE]><link rel="icon" href="/favicon.ico"><![endif]--><link rel="stylesheet" href="/static/css/fork-awesome.min.css"/><link rel="stylesheet" href="/static/css/leaflet.css"/><title>FitTrackee</title><script defer="defer" src="/static/js/chunk-vendors.a33476ea.js"></script><script defer="defer" src="/static/js/app.464dd65e.js"></script><link href="/static/css/app.fa4567f8.css" rel="stylesheet"><link rel="icon" type="image/png" sizes="32x32" href="/img/icons/favicon-32x32.png"><link rel="icon" type="image/png" sizes="16x16" href="/img/icons/favicon-16x16.png"><link rel="manifest" href="/manifest.json"><meta name="theme-color" content="#4DBA87"><meta name="apple-mobile-web-app-capable" content="no"><meta name="apple-mobile-web-app-status-bar-style" content="default"><meta name="apple-mobile-web-app-title" content="fittrackee_client"><link rel="apple-touch-icon" href="/img/icons/apple-touch-icon-152x152.png"><link rel="mask-icon" href="/img/icons/safari-pinned-tab.svg" color="#4DBA87"><meta name="msapplication-TileImage" content="/img/icons/msapplication-icon-144x144.png"><meta name="msapplication-TileColor" content="#000000"></head><body><noscript><strong>We're sorry but FitTrackee doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><!--[if IE]><link rel="icon" href="/favicon.ico"><![endif]--><link rel="stylesheet" href="/static/css/fork-awesome.min.css"/><link rel="stylesheet" href="/static/css/leaflet.css"/><title>FitTrackee</title><script defer="defer" src="/static/js/chunk-vendors.a33476ea.js"></script><script defer="defer" src="/static/js/app.f72ca9c7.js"></script><link href="/static/css/app.3193986e.css" rel="stylesheet"><link rel="icon" type="image/png" sizes="32x32" href="/img/icons/favicon-32x32.png"><link rel="icon" type="image/png" sizes="16x16" href="/img/icons/favicon-16x16.png"><link rel="manifest" href="/manifest.json"><meta name="theme-color" content="#4DBA87"><meta name="apple-mobile-web-app-capable" content="no"><meta name="apple-mobile-web-app-status-bar-style" content="default"><meta name="apple-mobile-web-app-title" content="fittrackee_client"><link rel="apple-touch-icon" href="/img/icons/apple-touch-icon-152x152.png"><link rel="mask-icon" href="/img/icons/safari-pinned-tab.svg" color="#4DBA87"><meta name="msapplication-TileImage" content="/img/icons/msapplication-icon-144x144.png"><meta name="msapplication-TileColor" content="#000000"></head><body><noscript><strong>We're sorry but FitTrackee doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
|
2
fittrackee/dist/service-worker.js
vendored
2
fittrackee/dist/service-worker.js
vendored
File diff suppressed because one or more lines are too long
2
fittrackee/dist/service-worker.js.map
vendored
2
fittrackee/dist/service-worker.js.map
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
fittrackee/dist/static/js/app.464dd65e.js
vendored
2
fittrackee/dist/static/js/app.464dd65e.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
fittrackee/dist/static/js/app.f72ca9c7.js
vendored
Normal file
2
fittrackee/dist/static/js/app.f72ca9c7.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
fittrackee/dist/static/js/app.f72ca9c7.js.map
vendored
Normal file
1
fittrackee/dist/static/js/app.f72ca9c7.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,34 @@
|
||||
"""Add user prefrence for gpx speed calculation
|
||||
|
||||
Revision ID: eff1c16c43eb
|
||||
Revises: db58d195c5bf
|
||||
Create Date: 2023-05-14 22:12:56.244291
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'eff1c16c43eb'
|
||||
down_revision = 'db58d195c5bf'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('users', schema=None) as batch_op:
|
||||
batch_op.add_column(sa.Column('use_raw_gpx_speed', sa.Boolean(), nullable=True))
|
||||
op.execute("UPDATE users SET use_raw_gpx_speed = false")
|
||||
op.alter_column('users', 'use_raw_gpx_speed', nullable=False)
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('users', schema=None) as batch_op:
|
||||
batch_op.drop_column('use_raw_gpx_speed')
|
||||
|
||||
# ### end Alembic commands ###
|
18
fittrackee/tests/fixtures/fixtures_users.py
vendored
18
fittrackee/tests/fixtures/fixtures_users.py
vendored
@ -59,6 +59,24 @@ def user_1_full() -> User:
|
||||
return user
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def user_1_raw_speed() -> User:
|
||||
user = User(username='test', email='test@test.com', password='12345678')
|
||||
user.first_name = 'John'
|
||||
user.last_name = 'Doe'
|
||||
user.bio = 'just a random guy'
|
||||
user.location = 'somewhere'
|
||||
user.language = 'en'
|
||||
user.timezone = 'America/New_York'
|
||||
user.birth_date = datetime.datetime.strptime('01/01/1980', '%d/%m/%Y')
|
||||
user.is_active = True
|
||||
user.use_raw_gpx_speed = True
|
||||
user.accepted_policy = datetime.datetime.utcnow()
|
||||
db.session.add(user)
|
||||
db.session.commit()
|
||||
return user
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def user_1_paris() -> User:
|
||||
user = User(username='test', email='test@test.com', password='12345678')
|
||||
|
@ -1459,6 +1459,7 @@ class TestUserPreferencesUpdate(ApiTestCaseMixin):
|
||||
imperial_units=True,
|
||||
display_ascent=False,
|
||||
start_elevation_at_zero=False,
|
||||
use_raw_gpx_speed=True,
|
||||
date_format='yyyy-MM-dd',
|
||||
)
|
||||
),
|
||||
@ -1471,6 +1472,7 @@ class TestUserPreferencesUpdate(ApiTestCaseMixin):
|
||||
assert data['message'] == 'user preferences updated'
|
||||
assert data['data']['display_ascent'] is False
|
||||
assert data['data']['start_elevation_at_zero'] is False
|
||||
assert data['data']['use_raw_gpx_speed'] is True
|
||||
assert data['data']['imperial_units'] is True
|
||||
assert data['data']['language'] == expected_language
|
||||
assert data['data']['timezone'] == 'America/New_York'
|
||||
|
@ -54,7 +54,7 @@ class TestStoppedSpeedThreshold:
|
||||
)
|
||||
|
||||
assert gpx_track_segment_mock.call_args_list[0] == call(
|
||||
stopped_speed_threshold=expected_threshold
|
||||
stopped_speed_threshold=expected_threshold, raw=False
|
||||
)
|
||||
gpx_track_segment_mock.assert_called_with(
|
||||
expected_threshold, # stopped_speed_threshold
|
||||
@ -88,7 +88,7 @@ class TestStoppedSpeedThreshold:
|
||||
)
|
||||
|
||||
assert gpx_track_segment_mock.call_args_list[0] == call(
|
||||
stopped_speed_threshold=expected_threshold
|
||||
stopped_speed_threshold=expected_threshold, raw=False
|
||||
)
|
||||
gpx_track_segment_mock.assert_called_with(
|
||||
expected_threshold, # stopped_speed_threshold
|
||||
@ -98,6 +98,43 @@ class TestStoppedSpeedThreshold:
|
||||
)
|
||||
|
||||
|
||||
class TestUseRawGpxSpeed:
|
||||
@pytest.mark.parametrize('input_use_raw_gpx_speed', [True, False])
|
||||
def test_it_calls_get_moving_data_with_user_use_raw_gpx_speed_preference(
|
||||
self,
|
||||
app: Flask,
|
||||
user_1: User,
|
||||
gpx_file_storage: FileStorage,
|
||||
sport_1_cycling: Sport,
|
||||
input_use_raw_gpx_speed: bool,
|
||||
) -> None:
|
||||
user_1.use_raw_gpx_speed = input_use_raw_gpx_speed
|
||||
with patch(
|
||||
'fittrackee.workouts.utils.workouts.get_new_file_path',
|
||||
return_value='/tmp/fitTrackee/uploads/test.png',
|
||||
), patch(
|
||||
'gpxpy.gpx.GPXTrackSegment.get_moving_data',
|
||||
return_value=moving_data,
|
||||
) as gpx_track_segment_mock:
|
||||
process_files(
|
||||
auth_user=user_1,
|
||||
folders=folders,
|
||||
workout_data={'sport_id': sport_1_cycling.id},
|
||||
workout_file=gpx_file_storage,
|
||||
)
|
||||
|
||||
assert gpx_track_segment_mock.call_args_list[0] == call(
|
||||
stopped_speed_threshold=sport_1_cycling.stopped_speed_threshold,
|
||||
raw=input_use_raw_gpx_speed,
|
||||
)
|
||||
gpx_track_segment_mock.assert_called_with(
|
||||
sport_1_cycling.stopped_speed_threshold, # stopped_speed_threshold
|
||||
False, # raw
|
||||
IGNORE_TOP_SPEED_PERCENTILES, # speed_extreemes_percentiles
|
||||
True, # ignore_nonstandard_distances
|
||||
)
|
||||
|
||||
|
||||
class TestGetGpxInfoStopTime:
|
||||
def test_stop_time_equals_to_0_when_gpx_file_contains_one_segment(
|
||||
self, gpx_file: str
|
||||
|
@ -279,6 +279,37 @@ class TestPostWorkoutWithGpx(ApiTestCaseMixin, CallArgsMixin):
|
||||
assert 'just a workout' == data['data']['workouts'][0]['title']
|
||||
assert_workout_data_with_gpx(data)
|
||||
|
||||
def test_it_adds_a_workout_with_gpx_file_raw_speed(
|
||||
self,
|
||||
app: Flask,
|
||||
user_1_raw_speed: User,
|
||||
sport_1_cycling: Sport,
|
||||
gpx_file: str,
|
||||
) -> None:
|
||||
client, auth_token = self.get_test_client_and_auth_token(
|
||||
app, user_1_raw_speed.email
|
||||
)
|
||||
|
||||
response = client.post(
|
||||
'/api/workouts',
|
||||
data=dict(
|
||||
file=(BytesIO(str.encode(gpx_file)), 'example.gpx'),
|
||||
data='{"sport_id": 1}',
|
||||
),
|
||||
headers=dict(
|
||||
content_type='multipart/form-data',
|
||||
Authorization=f'Bearer {auth_token}',
|
||||
),
|
||||
)
|
||||
|
||||
data = json.loads(response.data.decode())
|
||||
assert response.status_code == 201
|
||||
assert 'created' in data['status']
|
||||
assert len(data['data']['workouts']) == 1
|
||||
# max speed should be slightly higher than that tested in
|
||||
# assert_workout_data_with_gpx
|
||||
assert data['data']['workouts'][0]['max_speed'] == pytest.approx(5.25)
|
||||
|
||||
def test_it_returns_ha_record_when_a_workout_without_gpx_exists(
|
||||
self,
|
||||
app: Flask,
|
||||
|
@ -879,6 +879,7 @@ def edit_user_preferences(auth_user: User) -> Union[Dict, HttpResponse]:
|
||||
"total_ascent": 720.35,
|
||||
"total_distance": 67.895,
|
||||
"total_duration": "6:50:27",
|
||||
"use_raw_gpx_speed": true,
|
||||
"username": "sam"
|
||||
"weekm": true,
|
||||
},
|
||||
@ -892,6 +893,7 @@ def edit_user_preferences(auth_user: User) -> Union[Dict, HttpResponse]:
|
||||
:<json string language: language preferences
|
||||
:<json boolean start_elevation_at_zero: do elevation plots start at zero?
|
||||
:<json string timezone: user time zone
|
||||
:<json boolean use_raw_gpx_speed: Use unfiltered gpx to calculate speeds
|
||||
:<json boolean weekm: does week start on Monday?
|
||||
|
||||
:reqheader Authorization: OAuth 2.0 Bearer Token
|
||||
@ -915,6 +917,7 @@ def edit_user_preferences(auth_user: User) -> Union[Dict, HttpResponse]:
|
||||
'language',
|
||||
'start_elevation_at_zero',
|
||||
'timezone',
|
||||
'use_raw_gpx_speed',
|
||||
'weekm',
|
||||
}
|
||||
if not post_data or not post_data.keys() >= user_mandatory_data:
|
||||
@ -925,6 +928,7 @@ def edit_user_preferences(auth_user: User) -> Union[Dict, HttpResponse]:
|
||||
imperial_units = post_data.get('imperial_units')
|
||||
language = get_language(post_data.get('language'))
|
||||
start_elevation_at_zero = post_data.get('start_elevation_at_zero')
|
||||
use_raw_gpx_speed = post_data.get('use_raw_gpx_speed')
|
||||
timezone = post_data.get('timezone')
|
||||
weekm = post_data.get('weekm')
|
||||
|
||||
@ -935,6 +939,7 @@ def edit_user_preferences(auth_user: User) -> Union[Dict, HttpResponse]:
|
||||
auth_user.language = language
|
||||
auth_user.start_elevation_at_zero = start_elevation_at_zero
|
||||
auth_user.timezone = timezone
|
||||
auth_user.use_raw_gpx_speed = use_raw_gpx_speed
|
||||
auth_user.weekm = weekm
|
||||
db.session.commit()
|
||||
|
||||
|
@ -62,6 +62,7 @@ class User(BaseModel):
|
||||
start_elevation_at_zero = db.Column(
|
||||
db.Boolean, default=True, nullable=False
|
||||
)
|
||||
use_raw_gpx_speed = db.Column(db.Boolean, default=False, nullable=False)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f'<User {self.username!r}>'
|
||||
@ -216,6 +217,7 @@ class User(BaseModel):
|
||||
'language': self.language,
|
||||
'start_elevation_at_zero': self.start_elevation_at_zero,
|
||||
'timezone': self.timezone,
|
||||
'use_raw_gpx_speed': self.use_raw_gpx_speed,
|
||||
'weekm': self.weekm,
|
||||
},
|
||||
}
|
||||
|
@ -73,6 +73,7 @@ def get_gpx_info(
|
||||
stopped_speed_threshold: float,
|
||||
update_map_data: Optional[bool] = True,
|
||||
update_weather_data: Optional[bool] = True,
|
||||
use_raw_gpx_speed: bool = False,
|
||||
) -> Tuple:
|
||||
"""
|
||||
Parse and return gpx, map and weather data from gpx file
|
||||
@ -128,7 +129,8 @@ def get_gpx_info(
|
||||
if update_map_data:
|
||||
map_data.append([point.longitude, point.latitude])
|
||||
moving_data = segment.get_moving_data(
|
||||
stopped_speed_threshold=stopped_speed_threshold
|
||||
stopped_speed_threshold=stopped_speed_threshold,
|
||||
raw=use_raw_gpx_speed,
|
||||
)
|
||||
if moving_data:
|
||||
calculated_max_speed = moving_data.max_speed
|
||||
|
@ -299,10 +299,12 @@ def process_one_gpx_file(
|
||||
absolute_gpx_filepath = None
|
||||
absolute_map_filepath = None
|
||||
try:
|
||||
gpx_data, map_data, weather_data = get_gpx_info(
|
||||
params['file_path'], stopped_speed_threshold
|
||||
)
|
||||
auth_user = params['auth_user']
|
||||
gpx_data, map_data, weather_data = get_gpx_info(
|
||||
gpx_file=params['file_path'],
|
||||
stopped_speed_threshold=stopped_speed_threshold,
|
||||
use_raw_gpx_speed=auth_user.use_raw_gpx_speed,
|
||||
)
|
||||
workout_date, _ = get_workout_datetime(
|
||||
workout_date=gpx_data['start'],
|
||||
date_str_format=None if gpx_data else '%Y-%m-%d %H:%M',
|
||||
|
@ -20,7 +20,31 @@
|
||||
<dt>{{ $t('user.PROFILE.ASCENT_DATA') }}:</dt>
|
||||
<dd>{{ $t(`common.${display_ascent}`) }}</dd>
|
||||
<dt>{{ $t('user.PROFILE.ELEVATION_CHART_START.LABEL') }}:</dt>
|
||||
<dd>{{ $t(`user.PROFILE.ELEVATION_CHART_START.${user.start_elevation_at_zero ? 'ZERO' : 'MIN_ALT'}`) }}</dd>
|
||||
<dd>
|
||||
{{
|
||||
$t(
|
||||
`user.PROFILE.ELEVATION_CHART_START.${
|
||||
user.start_elevation_at_zero ? 'ZERO' : 'MIN_ALT'
|
||||
}`
|
||||
)
|
||||
}}
|
||||
</dd>
|
||||
<dt>{{ $t('user.PROFILE.USE_RAW_GPX_SPEED.LABEL') }}:</dt>
|
||||
<dd>
|
||||
{{
|
||||
$t(
|
||||
`user.PROFILE.USE_RAW_GPX_SPEED.${
|
||||
user.use_raw_gpx_speed ? 'RAW_SPEED' : 'FILTERED_SPEED'
|
||||
}`
|
||||
)
|
||||
}}
|
||||
</dd>
|
||||
<div class="info-box raw-speed-help">
|
||||
<span>
|
||||
<i class="fa fa-info-circle" aria-hidden="true" />
|
||||
{{ $t('user.PROFILE.USE_RAW_GPX_SPEED.HELP') }}
|
||||
</span>
|
||||
</div>
|
||||
</dl>
|
||||
<div class="profile-buttons">
|
||||
<button @click="$router.push('/profile/edit/preferences')">
|
||||
|
@ -104,7 +104,10 @@
|
||||
{{ $t('user.PROFILE.ELEVATION_CHART_START.LABEL') }}
|
||||
</span>
|
||||
<div class="checkboxes">
|
||||
<label v-for="status in startElevationAtZeroData" :key="status.label">
|
||||
<label
|
||||
v-for="status in startElevationAtZeroData"
|
||||
:key="status.label"
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
:id="status.label"
|
||||
@ -119,6 +122,32 @@
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-items form-checkboxes">
|
||||
<span class="checkboxes-label">
|
||||
{{ $t('user.PROFILE.USE_RAW_GPX_SPEED.LABEL') }}
|
||||
</span>
|
||||
<div class="checkboxes">
|
||||
<label v-for="status in useRawGpxSpeed" :key="status.label">
|
||||
<input
|
||||
type="radio"
|
||||
:id="status.label"
|
||||
:name="status.label"
|
||||
:checked="status.value === userForm.use_raw_gpx_speed"
|
||||
:disabled="loading"
|
||||
@input="updateUseRawGpxSpeed(status.value)"
|
||||
/>
|
||||
<span class="checkbox-label">
|
||||
{{ $t(`user.PROFILE.USE_RAW_GPX_SPEED.${status.label}`) }}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="info-box raw-speed-help">
|
||||
<span>
|
||||
<i class="fa fa-info-circle" aria-hidden="true" />
|
||||
{{ $t('user.PROFILE.USE_RAW_GPX_SPEED.HELP') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-buttons">
|
||||
<button class="confirm" type="submit">
|
||||
{{ $t('buttons.SUBMIT') }}
|
||||
@ -193,12 +222,22 @@
|
||||
const startElevationAtZeroData = [
|
||||
{
|
||||
label: 'ZERO',
|
||||
value: true
|
||||
value: true,
|
||||
},
|
||||
{
|
||||
label: 'MIN_ALT',
|
||||
value: false
|
||||
}
|
||||
value: false,
|
||||
},
|
||||
]
|
||||
const useRawGpxSpeed = [
|
||||
{
|
||||
label: 'FILTERED_SPEED',
|
||||
value: false,
|
||||
},
|
||||
{
|
||||
label: 'RAW_SPEED',
|
||||
value: true,
|
||||
},
|
||||
]
|
||||
const loading = computed(
|
||||
() => store.getters[AUTH_USER_STORE.GETTERS.USER_LOADING]
|
||||
@ -222,7 +261,12 @@
|
||||
|
||||
function updateUserForm(user: IAuthUserProfile) {
|
||||
userForm.display_ascent = user.display_ascent
|
||||
userForm.start_elevation_at_zero = user.start_elevation_at_zero ? user.start_elevation_at_zero : false
|
||||
userForm.start_elevation_at_zero = user.start_elevation_at_zero
|
||||
? user.start_elevation_at_zero
|
||||
: false
|
||||
userForm.use_raw_gpx_speed = user.use_raw_gpx_speed
|
||||
? user.use_raw_gpx_speed
|
||||
: false
|
||||
userForm.imperial_units = user.imperial_units ? user.imperial_units : false
|
||||
userForm.language = user.language ? user.language : 'en'
|
||||
userForm.timezone = user.timezone ? user.timezone : 'Europe/Paris'
|
||||
@ -238,6 +282,9 @@
|
||||
function updateStartElevationAtZero(value: boolean) {
|
||||
userForm.start_elevation_at_zero = value
|
||||
}
|
||||
function updateUseRawGpxSpeed(value: boolean) {
|
||||
userForm.use_raw_gpx_speed = value
|
||||
}
|
||||
function updateAscentDisplay(value: boolean) {
|
||||
userForm.display_ascent = value
|
||||
}
|
||||
|
@ -116,6 +116,11 @@
|
||||
"IMPERIAL": "Imperiales System (ft, mi, mph, °F)",
|
||||
"LABEL": "Einheiten für die Distanz",
|
||||
"METRIC": "Metrisches System (m, km, m/s, °C)"
|
||||
},
|
||||
"USE_RAW_GPX_SPEED": {
|
||||
"FILTERED_SPEED": "Gefiltert",
|
||||
"LABEL": "Höchstgeschwindigkeitsstrategie",
|
||||
"RAW_SPEED": "Rau"
|
||||
}
|
||||
},
|
||||
"READ_AND_ACCEPT_PRIVACY_POLICY": "Ich habe die {0} gelesen und stimme ihr zu.",
|
||||
|
@ -68,12 +68,12 @@
|
||||
"EDIT": "Edit profile",
|
||||
"EDIT_PREFERENCES": "Edit preferences",
|
||||
"EDIT_SPORTS_PREFERENCES": "Edit sports preferences",
|
||||
"ERRORED_EMAIL_UPDATE": "Please {0} to change your email address again or contact the administrator",
|
||||
"ELEVATION_CHART_START": {
|
||||
"LABEL": "Elevation chart starts at",
|
||||
"ZERO": "Zero",
|
||||
"MIN_ALT": "Minimum altitude"
|
||||
"MIN_ALT": "Minimum altitude",
|
||||
"ZERO": "Zero"
|
||||
},
|
||||
"ERRORED_EMAIL_UPDATE": "Please {0} to change your email address again or contact the administrator",
|
||||
"FIRST_DAY_OF_WEEK": "First day of week",
|
||||
"FIRST_NAME": "First name",
|
||||
"LANGUAGE": "Language",
|
||||
@ -116,6 +116,12 @@
|
||||
"IMPERIAL": "Imperial system (ft, mi, mph, °F)",
|
||||
"LABEL": "Units for distance",
|
||||
"METRIC": "Metric system (m, km, m/s, °C)"
|
||||
},
|
||||
"USE_RAW_GPX_SPEED": {
|
||||
"FILTERED_SPEED": "Filtered",
|
||||
"HELP": "If filtered, it excludes extreme values (which may be GPS errors) when calculating the maximum speed.",
|
||||
"LABEL": "GPX max speed strategy",
|
||||
"RAW_SPEED": "Raw"
|
||||
}
|
||||
},
|
||||
"READ_AND_ACCEPT_PRIVACY_POLICY": "I have read and agree to the {0}.",
|
||||
|
@ -116,6 +116,11 @@
|
||||
"IMPERIAL": "Sistema Imperial (ft, mi, mph, ºF)",
|
||||
"LABEL": "Unidades de distancia",
|
||||
"METRIC": "Sistema Métrico (m, km, m/s, ºC)"
|
||||
},
|
||||
"USE_RAW_GPX_SPEED": {
|
||||
"FILTERED_SPEED": "Filtrado",
|
||||
"LABEL": "Estrategia de velocidad máxima",
|
||||
"RAW_SPEED": "Crudo"
|
||||
}
|
||||
},
|
||||
"READ_AND_ACCEPT_PRIVACY_POLICY": "He leído y aceptado la {0}.",
|
||||
|
@ -70,8 +70,8 @@
|
||||
"EDIT_SPORTS_PREFERENCES": "Modifier les préférences des sports",
|
||||
"ELEVATION_CHART_START": {
|
||||
"LABEL": "Début de l'axe pour le graphe affichant l'altitude",
|
||||
"ZERO": "0",
|
||||
"MIN_ALT": "Altitude minimale"
|
||||
"MIN_ALT": "Altitude minimale",
|
||||
"ZERO": "0"
|
||||
},
|
||||
"ERRORED_EMAIL_UPDATE": "Veuillez vous {0} pour changer de nouveau votre adresse électronique ou contacter l'administrateur",
|
||||
"FIRST_DAY_OF_WEEK": "Premier jour de la semaine",
|
||||
@ -116,6 +116,12 @@
|
||||
"IMPERIAL": "Système impérial (ft, mi, mph, °F)",
|
||||
"LABEL": "Unités pour les distances",
|
||||
"METRIC": "Système métrique (m, km, m/s, °C)"
|
||||
},
|
||||
"USE_RAW_GPX_SPEED": {
|
||||
"FILTERED_SPEED": "Filtré",
|
||||
"HELP": "Si filtré, les valeurs extrêmes (qui peuvent être des erreurs GPS) sont exclues lors du calcul de la vitesse maximale.",
|
||||
"LABEL": "Stratégie de vitesse maximale",
|
||||
"RAW_SPEED": "Brut"
|
||||
}
|
||||
},
|
||||
"READ_AND_ACCEPT_PRIVACY_POLICY": "J'ai lu et accepte la {0}.",
|
||||
|
@ -116,6 +116,11 @@
|
||||
"IMPERIAL": "Sistema Imperial (ft, mi, mph, ºF)",
|
||||
"LABEL": "Unidades de distancia",
|
||||
"METRIC": "Sistema Métrico (m, km, m/s, ºC)"
|
||||
},
|
||||
"USE_RAW_GPX_SPEED": {
|
||||
"FILTERED_SPEED": "Filtrado",
|
||||
"LABEL": "Estratexia de velocidade máxima",
|
||||
"RAW_SPEED": "Cru"
|
||||
}
|
||||
},
|
||||
"READ_AND_ACCEPT_PRIVACY_POLICY": "Lin e acepto a {0}.",
|
||||
|
@ -97,6 +97,11 @@
|
||||
"IMPERIAL": "Sistema imperiale (ft, mi, mph, °F)",
|
||||
"LABEL": "Unità per la distanza",
|
||||
"METRIC": "Sistema metrico (m, km, m/s, °C)"
|
||||
},
|
||||
"USE_RAW_GPX_SPEED": {
|
||||
"FILTERED_SPEED": "Filtrato",
|
||||
"LABEL": "Strategia di massima velocità",
|
||||
"RAW_SPEED": "Greggio"
|
||||
}
|
||||
},
|
||||
"REGISTER": "Registra",
|
||||
|
@ -47,7 +47,12 @@
|
||||
"TABS": {
|
||||
"PROFILE": "profil"
|
||||
},
|
||||
"TIMEZONE": "Tidssone"
|
||||
"TIMEZONE": "Tidssone",
|
||||
"USE_RAW_GPX_SPEED": {
|
||||
"FILTERED_SPEED": "Filtrert",
|
||||
"LABEL": "Maks hastighet strategi",
|
||||
"RAW_SPEED": "Rå"
|
||||
}
|
||||
},
|
||||
"RESET_PASSWORD": "Tilbakestill passordet ditt",
|
||||
"SHOW_PASSWORD": "vis passord",
|
||||
|
@ -116,6 +116,11 @@
|
||||
"IMPERIAL": "Imperialistisch systeem (ft, mi, mph, °F)",
|
||||
"LABEL": "Eenheid voor afstand",
|
||||
"METRIC": "Metrisch systeem (m, km, m/s, °C)"
|
||||
},
|
||||
"USE_RAW_GPX_SPEED": {
|
||||
"FILTERED_SPEED": "Gefilterd",
|
||||
"LABEL": "Strategie voor maximale snelheid",
|
||||
"RAW_SPEED": "Rauw"
|
||||
}
|
||||
},
|
||||
"READ_AND_ACCEPT_PRIVACY_POLICY": "Ik heb het {0} gelezen en goedgekeurd.",
|
||||
|
@ -29,6 +29,7 @@ export interface IAuthUserProfile extends IUserProfile {
|
||||
display_ascent: boolean
|
||||
imperial_units: boolean
|
||||
start_elevation_at_zero: boolean
|
||||
use_raw_gpx_speed: boolean
|
||||
language: string | null
|
||||
timezone: string
|
||||
date_format: string
|
||||
@ -65,6 +66,7 @@ export interface IAdminUserPayload {
|
||||
export interface IUserPreferencesPayload {
|
||||
display_ascent: boolean
|
||||
start_elevation_at_zero: boolean
|
||||
use_raw_gpx_speed: boolean
|
||||
imperial_units: boolean
|
||||
language: string
|
||||
timezone: string
|
||||
|
Loading…
Reference in New Issue
Block a user